Commit b8338b91bd7fbaefc51f20c4f809619c62b2dd30

Authored by hitier
2 parents 02130a91 92adc966

Import Irap CSV

@@ -24,6 +24,11 @@ or major refactoring improvments. @@ -24,6 +24,11 @@ or major refactoring improvments.
24 24
25 ## Unreleased 25 ## Unreleased
26 26
  27 +## [0.3.pre-5] - 2021-04-30 - Import Irap CSV
  28 +### New
  29 +Db models
  30 +Csv reading and feeding
  31 +
27 ## [0.3.pre-4] - 2021-04-26 - Export chart 32 ## [0.3.pre-4] - 2021-04-26 - Export chart
28 ### New 33 ### New
29 Export chart as png 34 Export chart as png
1 -0.3.pre-4 1 +0.3.pre-5
app/commands/commands.py
1 import csv 1 import csv
2 import os 2 import os
3 import sys 3 import sys
  4 +
4 import click 5 import click
5 import random 6 import random
6 7
7 from flask import current_app 8 from flask import current_app
8 -from sqlalchemy.exc import OperationalError, IntegrityError  
9 -from sqlalchemy.orm.exc import NoResultFound 9 +from sqlalchemy.exc import IntegrityError
10 from sqlalchemy.sql import func 10 from sqlalchemy.sql import func
11 -from sqlalchemy.ext.automap import automap_base  
12 -from sqlalchemy.orm import Session  
13 -from sqlalchemy import create_engine  
14 11
15 -from app.models import db, Agent, Service, Project, Capacity, Period, Charge 12 +from app.models import db, Agent, Service, Project, Capacity, Period, Charge, AgentStatus, Company, AgentBap, \
  13 + AgentGrade, Category, Label, ProjectLabel
  14 +# TODO: rename to methods and add get_roles()
16 from app.auth.models import User, _nameToRole, _roleToName 15 from app.auth.models import User, _nameToRole, _roleToName
17 16
18 from . import bp 17 from . import bp
@@ -57,38 +56,129 @@ def feed_from_irap(csv_file_name): @@ -57,38 +56,129 @@ def feed_from_irap(csv_file_name):
57 with open(csv_file_name, newline='') as csvfile: 56 with open(csv_file_name, newline='') as csvfile:
58 csvreader = csv.DictReader(csvfile, delimiter=',', quotechar='"') 57 csvreader = csv.DictReader(csvfile, delimiter=',', quotechar='"')
59 for row in csvreader: 58 for row in csvreader:
60 - # print('\n'.join(row.keys()))  
61 - # break  
62 # Remove any leading/trailing spaces 59 # Remove any leading/trailing spaces
63 row = {k: v.strip() for k, v in row.items()} 60 row = {k: v.strip() for k, v in row.items()}
64 rows.append(row) 61 rows.append(row)
65 62
66 firstname_key = 'NOM' 63 firstname_key = 'NOM'
67 - secondname_key = 'prénom' 64 + secondname_key = 'PRÉNOM'
  65 + status_key = 'STATUT'
  66 + virtual_key = 'VIRTUEL'
  67 + company_key = 'SOCIÉTÉ'
  68 + bap_key = 'BAP'
  69 + grade_key = 'GRADE CORPS'
68 project_key = 'PROJETS' 70 project_key = 'PROJETS'
69 - service_key = 'Groupe métier'  
70 - # typology_title = 'TYPOLOGIE'  
71 - # thematic_title = 'thématique' 71 + service_key = 'GROUPE MÉTIER'
  72 + categorie_keys = ['TYPOLOGIE', 'THÉMATIQUE']
72 73
73 # Get the columns values 74 # Get the columns values
74 # 75 #
75 - projects = [r[project_key] for r in rows]  
76 - projects = sorted(set(projects))  
77 - agents = [(r[firstname_key], r[secondname_key].strip()) for r in rows]  
78 - agents = sorted(set(agents))  
79 - services = [r[service_key] for r in rows]  
80 - services = sorted(set(services))  
81 -  
82 - # thematics = [r[thematic_title] for r in rows]  
83 - # thematics = sorted(set(thematics))  
84 - # typologies = [r[typology_title] for r in rows]  
85 - # typologies = sorted(set(typologies))  
86 -  
87 - # Feed agents from column 76 + agents = []
  77 + services = []
  78 + baps = []
  79 + grades = []
  80 + companies = []
  81 + statuses = []
  82 +
  83 + # build a category dict of lists
  84 + # key being the category name,
  85 + # list being filled with corresponding labels
  86 + categories = {k: [] for k in categorie_keys}
  87 +
88 # 88 #
89 - for a in agents:  
90 - n_a = Agent(firstname=a[0], secondname=a[1])  
91 - db.session.add(n_a) 89 + categorized_projects = {}
  90 +
  91 + for r in rows:
  92 + services.append(r[service_key])
  93 + baps.append(r[bap_key])
  94 + grades.append(r[grade_key])
  95 + companies.append(r[company_key])
  96 + statuses.append(r[status_key])
  97 +
  98 + # categorized_projects
  99 + project = r[project_key]
  100 + categorized_projects[project] = []
  101 +
  102 + # fill in the category-labels dict
  103 + for k in categorie_keys:
  104 + categories[k].append(r[k])
  105 + categorized_projects[project].append(r[k])
  106 +
  107 + # build agents list of dicts
  108 + agents.append({
  109 + 'firstname': r[firstname_key],
  110 + 'secondname': r[secondname_key],
  111 + 'status': r[status_key],
  112 + 'virtual': r[virtual_key],
  113 + 'company': r[company_key],
  114 + 'bap': r[bap_key],
  115 + 'grade': r[grade_key]})
  116 +
  117 + # Uppercase the small tables
  118 + #
  119 + baps = [x.upper() for x in baps]
  120 + grades = [x.upper() for x in grades]
  121 + statuses = [x.upper() for x in statuses]
  122 +
  123 + # Now, sort the lists
  124 + #
  125 + # 1- first remove empty string with filter()
  126 + # 2- then keep only uniq item with set()
  127 + # 3- at last alpha sort with sorted()
  128 + #
  129 + services = sorted(set(filter(None, services)))
  130 + baps = sorted(set(filter(None, baps)))
  131 + grades = sorted(set(filter(None, grades)))
  132 + companies = sorted(set(filter(None, companies)))
  133 + statuses = sorted(set(filter(None, statuses)))
  134 +
  135 + # Do the same for the projects, that are keys of categorized_projects
  136 + #
  137 + projects = sorted(set(categorized_projects.keys()))
  138 +
  139 + # Do the same for the category labels stored as a dict
  140 + #
  141 + # k is category name
  142 + # v is labels list for that category
  143 + for k in categorie_keys:
  144 + labels = sorted(set(filter(None, categories[k])))
  145 + categories[k] = labels
  146 +
  147 + # At least, as agents is a list of dicts, sorting is a bit tricky
  148 + #
  149 + # the first one liner will store the last agent's line only
  150 + # then we alpha sort on the name
  151 + # on both, the discrimination is based on the name couple: (firstname, secondname)
  152 + #
  153 + agents = list({(a['firstname'], a['secondname']): a for a in agents}.values())
  154 + agents = sorted(agents, key=lambda a: (a['firstname'], a['secondname']))
  155 +
  156 + # Feed baps from column
  157 + #
  158 + for b in baps:
  159 + n_b = AgentBap(name=b)
  160 + db.session.add(n_b)
  161 + db.session.commit()
  162 +
  163 + # Feed grades from column
  164 + #
  165 + for g in grades:
  166 + n_g = AgentGrade(name=g)
  167 + db.session.add(n_g)
  168 + db.session.commit()
  169 +
  170 + # Feed companies from column
  171 + #
  172 + for c in companies:
  173 + n_c = Company(name=c)
  174 + db.session.add(n_c)
  175 + db.session.commit()
  176 +
  177 + # Feed statuses from column
  178 + #
  179 + for s in statuses:
  180 + n_s = AgentStatus(name=s)
  181 + db.session.add(n_s)
92 db.session.commit() 182 db.session.commit()
93 183
94 # Feed projects from column 184 # Feed projects from column
@@ -107,7 +197,8 @@ def feed_from_irap(csv_file_name): @@ -107,7 +197,8 @@ def feed_from_irap(csv_file_name):
107 197
108 # Feed periods names 198 # Feed periods names
109 # Todo: are statically built, 199 # Todo: are statically built,
110 - # should come from year column name. 200 + # should come from year column name.
  201 + # also see later
111 # 202 #
112 for p in range(2011, 2030): 203 for p in range(2011, 2030):
113 n_p = Period(name=f"{p}") 204 n_p = Period(name=f"{p}")
@@ -115,9 +206,65 @@ def feed_from_irap(csv_file_name): @@ -115,9 +206,65 @@ def feed_from_irap(csv_file_name):
115 db.session.commit() 206 db.session.commit()
116 207
117 # Add one default capacity 208 # Add one default capacity
118 - db.session.add(Capacity(name="Travailleur")) 209 + #
  210 + db.session.add(Capacity(name="Agent"))
  211 + db.session.commit()
  212 +
  213 + # Feed categories and labels
  214 + #
  215 + for c, l in categories.items():
  216 + current_app.logger.debug("Adding category " + c)
  217 + n_c = Category(name=c)
  218 + db.session.add(n_c)
  219 + # db.session.commit()
  220 + for label in l:
  221 + current_app.logger.debug("Adding label {} for id {}".format(label, n_c.id))
  222 + n_l = Label(name=label, category=n_c)
  223 + db.session.add(n_l)
  224 + db.session.commit()
  225 +
  226 + # Feed project's labels
  227 + #
  228 + for p, labels in categorized_projects.items():
  229 + n_p = Project.query.filter(Project.name == p).one()
  230 + for l in labels:
  231 + n_l = Label.query.filter(Label.name == l).one()
  232 + n_c = n_l.category
  233 + n_pl = ProjectLabel(project=n_p, category=n_c, label=n_l)
  234 + db.session.add(n_pl)
119 db.session.commit() 235 db.session.commit()
120 236
  237 + # Feed agents from agents list previously filled
  238 + #
  239 + for a in agents:
  240 + status = AgentStatus.query.filter(AgentStatus.name == a['status']).one_or_none()
  241 + if status is None and a['status']:
  242 + status = AgentStatus(name=a['status'])
  243 + company = Company.query.filter(Company.name == a['company']).one_or_none()
  244 + if company is None and a['company']:
  245 + company = Company(name=a['company'])
  246 + bap = AgentBap.query.filter(AgentBap.name == a['bap']).one_or_none()
  247 + if bap is None and a['bap']:
  248 + bap = AgentBap(name=a['bap'])
  249 + grade = AgentGrade.query.filter(AgentGrade.name == a['grade']).one_or_none()
  250 + if grade is None and a['grade']:
  251 + grade = AgentBap(name=a['grade'])
  252 + virtual = 1 if a['virtual'] else 0
  253 + permanent = 1 if a['status'] == 'PERM' else 0
  254 + n_a = Agent(firstname=a['firstname'],
  255 + secondname=a['secondname'],
  256 + status_id=status.id if status else None,
  257 + company_id=company.id if company else None,
  258 + bap_id=bap.id if bap else None,
  259 + grade_id=grade.id if grade else None,
  260 + virtual=virtual,
  261 + permanent=permanent)
  262 + db.session.add(n_a)
  263 + db.session.commit()
  264 +
  265 + # Feed agents from agents list previously filled
  266 + #
  267 +
121 # Now feed the charges. 268 # Now feed the charges.
122 # 269 #
123 # At least one for each csv row 270 # At least one for each csv row
@@ -128,6 +275,7 @@ def feed_from_irap(csv_file_name): @@ -128,6 +275,7 @@ def feed_from_irap(csv_file_name):
128 a = Agent.query.filter(Agent.firstname == r[firstname_key], Agent.secondname == r[secondname_key]).one() 275 a = Agent.query.filter(Agent.firstname == r[firstname_key], Agent.secondname == r[secondname_key]).one()
129 s = Service.query.filter(Service.name == r[service_key]).one() 276 s = Service.query.filter(Service.name == r[service_key]).one()
130 c = Capacity.query.first() 277 c = Capacity.query.first()
  278 + # TODO: period names should come from db request
131 for period_name in range(2011, 2030): 279 for period_name in range(2011, 2030):
132 t = Period.query.filter(Period.name == period_name).one() 280 t = Period.query.filter(Period.name == period_name).one()
133 charge = r[f"{period_name}"] 281 charge = r[f"{period_name}"]
@@ -323,8 +471,8 @@ def feed_random_charges(agent): @@ -323,8 +471,8 @@ def feed_random_charges(agent):
323 def user_add(email, name, login, password, role): 471 def user_add(email, name, login, password, role):
324 """ Add a new user in db.""" 472 """ Add a new user in db."""
325 user = User.query.filter(User.name == name).one_or_none() 473 user = User.query.filter(User.name == name).one_or_none()
326 - if (user):  
327 - current_app.logger.error(f"user already exists {name}") 474 + if user:
  475 + current_app.logger.warn(f"user already exists {name}")
328 return 476 return
329 user = User(email=email, name=name, login=login, password=password, role=role) 477 user = User(email=email, name=name, login=login, password=password, role=role)
330 db.session.add(user) 478 db.session.add(user)
@@ -351,12 +499,12 @@ def user_update(user_id, name, role, email, password): @@ -351,12 +499,12 @@ def user_update(user_id, name, role, email, password):
351 user.set_role(role) 499 user.set_role(role)
352 print(f"User --{user.name}-- role updated to {_roleToName[user.role]}") 500 print(f"User --{user.name}-- role updated to {_roleToName[user.role]}")
353 if email: 501 if email:
354 - user.email=email 502 + user.email = email
355 print(f"User --{user.name}-- email updated to {user.email}") 503 print(f"User --{user.name}-- email updated to {user.email}")
356 if password: 504 if password:
357 print(f"User --{user.name}-- password updated") 505 print(f"User --{user.name}-- password updated")
358 user.set_password(password) 506 user.set_password(password)
359 - if not ( name or role or email or password): 507 + if not (name or role or email or password):
360 print(f"No update for user --{user.name}--") 508 print(f"No update for user --{user.name}--")
361 db.session.commit() 509 db.session.commit()
362 510
1 from flask_sqlalchemy import SQLAlchemy 1 from flask_sqlalchemy import SQLAlchemy
  2 +from sqlalchemy.orm import relationship
2 3
3 db = SQLAlchemy() 4 db = SQLAlchemy()
4 5
5 6
6 -class Agent(db.Model): 7 +#
  8 +# Categorized projects
  9 +#
  10 +
  11 +class Project(db.Model):
7 id = db.Column(db.Integer, primary_key=True) 12 id = db.Column(db.Integer, primary_key=True)
8 - firstname = db.Column(db.String(100))  
9 - secondname = db.Column(db.String(100)) 13 + name = db.Column(db.String)
  14 + labels = relationship("ProjectLabel", back_populates="project")
10 15
11 16
12 -class Project(db.Model): 17 +class Category(db.Model):
13 id = db.Column(db.Integer, primary_key=True) 18 id = db.Column(db.Integer, primary_key=True)
14 - name = db.Column(db.String(100), unique=True) 19 + name = db.Column(db.String)
  20 + labels = relationship("Label", back_populates="category")
  21 + projects = relationship("ProjectLabel", back_populates="category")
15 22
16 23
17 -class Service(db.Model): 24 +class Label(db.Model):
18 id = db.Column(db.Integer, primary_key=True) 25 id = db.Column(db.Integer, primary_key=True)
19 - name = db.Column(db.String(100), unique=True)  
20 - abbr = db.Column(db.String(50), unique=True) 26 + name = db.Column(db.String, unique=True)
  27 + category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
  28 + category = relationship("Category", back_populates="labels")
  29 + projects = relationship("ProjectLabel", back_populates="label")
  30 +
  31 +
  32 +class ProjectLabel(db.Model):
  33 + project_id = db.Column(db.Integer, db.ForeignKey('project.id'), primary_key=True)
  34 + category_id = db.Column(db.Integer, db.ForeignKey('category.id'), primary_key=True)
  35 + label_id = db.Column(db.Integer, db.ForeignKey('label.id'))
  36 +
  37 + project = relationship("Project", back_populates="labels")
  38 + category = relationship("Category", back_populates="projects")
  39 + label = relationship("Label", back_populates="projects")
  40 +
  41 +
  42 +#
  43 +# Agents
  44 +#
  45 +
  46 +class AgentBap(db.Model):
  47 + id = db.Column(db.Integer, primary_key=True)
  48 + name = db.Column(db.String(16))
21 49
22 50
23 -class Function(db.Model): 51 +class AgentGrade(db.Model):
  52 + id = db.Column(db.Integer, primary_key=True)
  53 + name = db.Column(db.String(16))
  54 +
  55 +
  56 +class AgentStatus(db.Model):
  57 + id = db.Column(db.Integer, primary_key=True)
  58 + name = db.Column(db.String(16))
  59 +
  60 +
  61 +class Company(db.Model):
  62 + id = db.Column(db.Integer, primary_key=True)
  63 + name = db.Column(db.String(16))
  64 +
  65 +
  66 +class Agent(db.Model):
  67 + id = db.Column(db.Integer, primary_key=True)
  68 + firstname = db.Column(db.String(100))
  69 + secondname = db.Column(db.String(100))
  70 + company_id = db.Column(db.Integer, db.ForeignKey('company.id'))
  71 + grade_id = db.Column(db.Integer, db.ForeignKey('agent_grade.id'))
  72 + status_id = db.Column(db.Integer, db.ForeignKey('agent_status.id'))
  73 + bap_id = db.Column(db.Integer, db.ForeignKey('agent_bap.id'))
  74 + virtual = db.Column(db.Integer) # integer boolean
  75 + permanent = db.Column(db.Integer) # integer boolean
  76 +
  77 +
  78 +class Service(db.Model):
24 id = db.Column(db.Integer, primary_key=True) 79 id = db.Column(db.Integer, primary_key=True)
25 name = db.Column(db.String(100), unique=True) 80 name = db.Column(db.String(100), unique=True)
  81 + abbr = db.Column(db.String(50), unique=True)
26 82
27 83
28 class Capacity(db.Model): 84 class Capacity(db.Model):
tests/backend_tests.py
  1 +import os
  2 +import sys
1 import unittest 3 import unittest
  4 +from shutil import copyfile
2 5
3 from pdc_config import TestConfig 6 from pdc_config import TestConfig
4 from app import create_app, db_mgr, db 7 from app import create_app, db_mgr, db
@@ -7,18 +10,29 @@ from app.auth.models import User @@ -7,18 +10,29 @@ from app.auth.models import User
7 10
8 class BaseTestCase(unittest.TestCase): 11 class BaseTestCase(unittest.TestCase):
9 def setUp(self): 12 def setUp(self):
10 - # configure data base 13 + # initialise app
11 self.app = create_app(TestConfig) 14 self.app = create_app(TestConfig)
  15 +
  16 + # copy resource demo db to test file
  17 + appdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)
  18 + sqlite_file_name = os.path.abspath(os.path.join(appdir, 'resources', 'lesia-btp.sqlite'))
  19 + if not os.path.isdir(self.app.instance_path):
  20 + os.mkdir(self.app.instance_path)
  21 + self.db_path = os.path.join(self.app.instance_path, 'test.db')
  22 + copyfile(sqlite_file_name, self.db_path)
  23 +
  24 + # force db path to newly create file
  25 + self.app.config.update(
  26 + SQLALCHEMY_DATABASE_URI='sqlite:///' + self.db_path
  27 + )
  28 +
  29 + # update flask context
12 self.app_context = self.app.app_context() 30 self.app_context = self.app.app_context()
13 self.app_context.push() 31 self.app_context.push()
14 - # TODO: shall we always copy db from resources sqlite file ?  
15 - # that would allow us to run all tests in sqlite:memory:  
16 - # db.create_all()  
17 - # admin = User(email='admin@nowhere.org', name='admin', login='admin', password='admin', role='admin')  
18 - # db.session.add(admin)  
19 - # db.session.commit()  
20 32
21 def tearDown(self): 33 def tearDown(self):
  34 + if os.path.isfile(self.db_path):
  35 + os.remove(self.db_path)
22 self.app_context.pop() 36 self.app_context.pop()
23 37
24 def test_always_true(self): 38 def test_always_true(self):
@@ -46,45 +60,3 @@ class DbMgrTestCase(BaseTestCase): @@ -46,45 +60,3 @@ class DbMgrTestCase(BaseTestCase):
46 # Waiting for 17 periods + headers line 60 # Waiting for 17 periods + headers line
47 self.assertEqual(18, len(stacked_charges)) 61 self.assertEqual(18, len(stacked_charges))
48 62
49 -  
50 -class AuthModelTestCase(BaseTestCase):  
51 -  
52 - def skip_if_no_sqlitememory(self):  
53 - if 'memory' not in self.app.config['SQLALCHEMY_DATABASE_URI']:  
54 - self.skipTest("Needs in memory sqlite")  
55 -  
56 - def get_admin(self):  
57 - return User.query.filter(User.name == 'admin').one()  
58 -  
59 - def setUp(self):  
60 - BaseTestCase.setUp(self)  
61 - self.skip_if_no_sqlitememory()  
62 - db.create_all()  
63 - admin = User(email='admin@nowhere.org', name='admin', login='admin', role='admin')  
64 - db.session.add(admin)  
65 - db.session.commit()  
66 -  
67 - def test_in_memory(self):  
68 - self.app.logger.info("In memory Sqlite DB for tests")  
69 - self.assertTrue(True)  
70 -  
71 - def test_setrole(self):  
72 - admin = self.get_admin()  
73 - admin.set_role("ADMIN")  
74 - db.session.commit()  
75 - admin = self.get_admin()  
76 - self.assertTrue(admin is not None)  
77 - self.assertTrue(admin.has_role("ADMIN"))  
78 - self.assertFalse(admin.has_role("SERVICE"))  
79 -  
80 - def test_setrole_valueerror(self):  
81 - admin = self.get_admin()  
82 - with self.assertRaises(ValueError) as ve:  
83 - admin.set_role("NOSUCHROLE")  
84 -  
85 - def test_setcheckpassword(self):  
86 - admin = self.get_admin()  
87 - admin.set_password("hahaha")  
88 - db.session.commit()  
89 - admin2 = self.get_admin()  
90 - self.assertTrue(admin2.check_password("hahaha"))  
tests/cli_tests.py 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +import unittest
  2 +
  3 +from app import create_app, db, User
  4 +from app.commands.commands import feed_from_irap, show_roles, user_add, user_show_all
  5 +from pdc_config import TestConfig
  6 +
  7 +from app.commands import bp as cli_bp
  8 +
  9 +
  10 +class CliBaseTestCase(unittest.TestCase):
  11 +
  12 + def setUp(self):
  13 + # Get rid of a strange 'ValueError: I/O operation' when app.logger outputs
  14 + TestConfig.PDC_LOGS_LEVEL = 'ERROR'
  15 + # Force sqlite in memory db
  16 + TestConfig.SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
  17 + # Create and register app
  18 + self.app = create_app(TestConfig)
  19 + self.app.register_blueprint(cli_bp)
  20 + self.app_context = self.app.app_context()
  21 + self.app_context.push()
  22 + db.create_all()
  23 +
  24 + def tearDown(self):
  25 + pass
  26 +
  27 + def test_hello3(self):
  28 + runner = self.app.test_cli_runner()
  29 + result = runner.invoke(user_show_all)
  30 + print("\n")
  31 + print(result.output)
  32 +
  33 + def test_hello2(self):
  34 + runner = self.app.test_cli_runner()
  35 + result = runner.invoke(show_roles)
  36 + print(result.output)
  37 +
  38 + def test_add_user(self):
  39 + runner = self.app.test_cli_runner()
  40 +
  41 + all_users = User.query.all()
  42 + self.assertEqual(0, len(all_users))
  43 + # invoke the command directly
  44 + arguments = ['geo@ici.fr', 'Joseph Hitier', 'joh', 'passwd', 'PUBLIC']
  45 + result = runner.invoke(user_add, arguments)
  46 + print(result.output)
  47 + all_users = User.query.all()
  48 + print(len(all_users))
  49 + # self.assertEqual(1, len(all_users))
tests/common_db_feed.py 0 → 100644
@@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
  1 +from app.models import Category, db, Label, Project, ProjectLabel
  2 +
  3 +categorized_labels = {'pole': ['Spatial', 'Sol'], 'domaine': ['soleil-terre', 'atmosphere', 'r&t', 'géologie']}
  4 +projects_categories = {'ChemCam': {'pole': 'Spatial', 'domaine': 'géologie'},
  5 + 'Pilot': {'pole': 'Spatial', 'domaine': 'atmosphere'},
  6 + 'Ambre': {'pole': 'Spatial', 'domaine': 'soleil-terre'}}
  7 +
  8 +
  9 +def feed_projects():
  10 + for c_name, labels in categorized_labels.items():
  11 + n_c = Category(name=c_name)
  12 + db.session.add(n_c)
  13 + for l_name in labels:
  14 + n_l = Label(name=l_name, category=n_c)
  15 + db.session.add(n_l)
  16 +
  17 + db.session.commit()
  18 +
  19 + project_names = projects_categories.keys()
  20 +
  21 + for p_name in set(project_names):
  22 + n_p = Project(name=p_name)
  23 + db.session.add(n_p)
  24 + db.session.commit()
  25 +
  26 + for p, categories in projects_categories.items():
  27 + n_p = db.session.query(Project).filter(Project.name == p).one()
  28 + for c_name, l_name in categories.items():
  29 + n_c = db.session.query(Category).filter(Category.name == c_name).one()
  30 + n_l = db.session.query(Label).filter(Label.name == l_name).one()
  31 + n_pc = ProjectLabel(project=n_p, category=n_c, label=n_l)
  32 + db.session.add(n_pc)
  33 +
  34 + db.session.commit()
  35 +
  36 +
  37 +def show_categories():
  38 + for c in db.session.query(Category).all():
  39 + print(c.name + ": ", ",".join([l.name for l in c.categorized_labels]))
tests/db_tests.py 0 → 100644
@@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
  1 +import unittest
  2 +
  3 +from app import create_app, db, User
  4 +from app.models import Project
  5 +from pdc_config import TestConfig
  6 +from tests.common_db_feed import feed_projects
  7 +
  8 +
  9 +class DbBaseTestCase(unittest.TestCase):
  10 + def setUp(self):
  11 + self.app = create_app(TestConfig)
  12 + # force db uri to sqlite memory
  13 + self.app.config.update(
  14 + SQLALCHEMY_DATABASE_URI='sqlite:///:memory:'
  15 + )
  16 + self.app_context = self.app.app_context()
  17 + self.app_context.push()
  18 + db.create_all()
  19 + feed_projects()
  20 +
  21 + def tearDown(self):
  22 + db.session.remove()
  23 + db.drop_all()
  24 + self.app_context.pop()
  25 +
  26 + def test_first(self):
  27 + projects = Project.query.all()
  28 + self.assertEqual(3, len(projects))
  29 +
  30 +
  31 +class AuthModelTestCase(DbBaseTestCase):
  32 +
  33 + def skip_if_no_sqlitememory(self):
  34 + if 'memory' not in self.app.config['SQLALCHEMY_DATABASE_URI']:
  35 + self.skipTest("Needs in memory sqlite")
  36 +
  37 + def get_admin(self):
  38 + return User.query.filter(User.name == 'admin').one()
  39 +
  40 + def setUp(self):
  41 + DbBaseTestCase.setUp(self)
  42 + self.skip_if_no_sqlitememory()
  43 + db.create_all()
  44 + admin = User(email='admin@nowhere.org', name='admin', login='admin', role='admin')
  45 + db.session.add(admin)
  46 + db.session.commit()
  47 +
  48 + def test_in_memory(self):
  49 + self.app.logger.info("In memory Sqlite DB for tests")
  50 + self.assertTrue(True)
  51 +
  52 + def test_setrole(self):
  53 + admin = self.get_admin()
  54 + admin.set_role("ADMIN")
  55 + db.session.commit()
  56 + admin = self.get_admin()
  57 + self.assertTrue(admin is not None)
  58 + self.assertTrue(admin.has_role("ADMIN"))
  59 + self.assertFalse(admin.has_role("SERVICE"))
  60 +
  61 + def test_setrole_valueerror(self):
  62 + admin = self.get_admin()
  63 + with self.assertRaises(ValueError) as ve:
  64 + admin.set_role("NOSUCHROLE")
  65 +
  66 + def test_setcheckpassword(self):
  67 + admin = self.get_admin()
  68 + admin.set_password("hahaha")
  69 + db.session.commit()
  70 + admin2 = self.get_admin()
  71 + self.assertTrue(admin2.check_password("hahaha"))