Commit 0011bed0cf4dd584f00e88ce1a9cdbfb178d8c87

Authored by hitier
2 parents e20cd5d4 74c7dad5

Update category/label data model

app/commands/commands.py
@@ -10,7 +10,7 @@ from sqlalchemy.exc import IntegrityError @@ -10,7 +10,7 @@ from sqlalchemy.exc import IntegrityError
10 from sqlalchemy.sql import func 10 from sqlalchemy.sql import func
11 11
12 from app.models import db, Agent, Service, Project, Capacity, Period, Charge, AgentStatus, Company, AgentBap, \ 12 from app.models import db, Agent, Service, Project, Capacity, Period, Charge, AgentStatus, Company, AgentBap, \
13 - AgentGrade, Category, Label, ProjectLabel 13 + AgentGrade, Category, Label, ProjectLabel, CategoryLabel
14 # TODO: rename to methods and add get_roles() 14 # TODO: rename to methods and add get_roles()
15 from app.auth.models import User, _nameToRole, _roleToName 15 from app.auth.models import User, _nameToRole, _roleToName
16 16
@@ -79,15 +79,22 @@ def feed_from_irap(csv_file_name): @@ -79,15 +79,22 @@ def feed_from_irap(csv_file_name):
79 grades = [] 79 grades = []
80 companies = [] 80 companies = []
81 statuses = [] 81 statuses = []
  82 + labels = []
82 83
83 - # build a category dict of lists 84 + # Build a category dict of lists
84 # key being the category name, 85 # key being the category name,
85 # list being filled with corresponding labels 86 # list being filled with corresponding labels
86 - categories = {k: [] for k in categorie_keys} 87 + categorie_labels = {k: [] for k in categorie_keys}
87 88
  89 + # Projects' labels is a dict of lists
  90 + # indexed by project name
  91 + # containing labels for that project
88 # 92 #
89 - categorized_projects = {} 93 + project_labels = {}
90 94
  95 + #
  96 + # Parse the rows and fill in various lists
  97 + #
91 for r in rows: 98 for r in rows:
92 services.append(r[service_key]) 99 services.append(r[service_key])
93 baps.append(r[bap_key]) 100 baps.append(r[bap_key])
@@ -95,16 +102,20 @@ def feed_from_irap(csv_file_name): @@ -95,16 +102,20 @@ def feed_from_irap(csv_file_name):
95 companies.append(r[company_key]) 102 companies.append(r[company_key])
96 statuses.append(r[status_key]) 103 statuses.append(r[status_key])
97 104
98 - # categorized_projects  
99 - project = r[project_key]  
100 - categorized_projects[project] = [] 105 + # the projet and its labels
  106 + project_name = r[project_key]
  107 + project_labels[project_name] = []
101 108
102 - # fill in the category-labels dict 109 + # now fill in both
  110 + # the labels list,
  111 + # the category-labels dict,
  112 + # and the project-labels dict
103 for k in categorie_keys: 113 for k in categorie_keys:
104 - categories[k].append(r[k])  
105 - categorized_projects[project].append(r[k]) 114 + labels.append(r[k])
  115 + categorie_labels[k].append(r[k])
  116 + project_labels[project_name].append(r[k])
106 117
107 - # build agents list of dicts 118 + # create the agents list of dicts
108 agents.append({ 119 agents.append({
109 'firstname': r[firstname_key], 120 'firstname': r[firstname_key],
110 'secondname': r[secondname_key], 121 'secondname': r[secondname_key],
@@ -124,25 +135,25 @@ def feed_from_irap(csv_file_name): @@ -124,25 +135,25 @@ def feed_from_irap(csv_file_name):
124 # 135 #
125 # 1- first remove empty string with filter() 136 # 1- first remove empty string with filter()
126 # 2- then keep only uniq item with set() 137 # 2- then keep only uniq item with set()
127 - # 3- at last alpha sort with sorted() 138 + # 3- at last alpha sort with sorted()
128 # 139 #
129 services = sorted(set(filter(None, services))) 140 services = sorted(set(filter(None, services)))
130 baps = sorted(set(filter(None, baps))) 141 baps = sorted(set(filter(None, baps)))
131 grades = sorted(set(filter(None, grades))) 142 grades = sorted(set(filter(None, grades)))
132 companies = sorted(set(filter(None, companies))) 143 companies = sorted(set(filter(None, companies)))
133 statuses = sorted(set(filter(None, statuses))) 144 statuses = sorted(set(filter(None, statuses)))
  145 + labels = sorted(set(filter(None, labels)))
134 146
135 - # Do the same for the projects, that are keys of categorized_projects 147 + # Do the same for the projects, that are keys of project_labels
136 # 148 #
137 - projects = sorted(set(categorized_projects.keys())) 149 + projects = sorted(set(project_labels.keys()))
138 150
139 - # Do the same for the category labels stored as a dict 151 + # Do the same for the labels inside each category
  152 + # c is the category name containing the labels list
140 # 153 #
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 154 + for c in categorie_keys:
  155 + c_labels = sorted(set(filter(None, categorie_labels[c])))
  156 + categorie_labels[c] = c_labels
146 157
147 # At least, as agents is a list of dicts, sorting is a bit tricky 158 # At least, as agents is a list of dicts, sorting is a bit tricky
148 # 159 #
@@ -153,6 +164,12 @@ def feed_from_irap(csv_file_name): @@ -153,6 +164,12 @@ def feed_from_irap(csv_file_name):
153 agents = list({(a['firstname'], a['secondname']): a for a in agents}.values()) 164 agents = list({(a['firstname'], a['secondname']): a for a in agents}.values())
154 agents = sorted(agents, key=lambda a: (a['firstname'], a['secondname'])) 165 agents = sorted(agents, key=lambda a: (a['firstname'], a['secondname']))
155 166
  167 + #
  168 + # We are done with collecting data
  169 + #
  170 + # Now we write to database
  171 + #
  172 +
156 # Feed baps from column 173 # Feed baps from column
157 # 174 #
158 for b in baps: 175 for b in baps:
@@ -188,6 +205,20 @@ def feed_from_irap(csv_file_name): @@ -188,6 +205,20 @@ def feed_from_irap(csv_file_name):
188 db.session.add(n_p) 205 db.session.add(n_p)
189 db.session.commit() 206 db.session.commit()
190 207
  208 + # Feed labels from column
  209 + #
  210 + for _l in labels:
  211 + n_l = Label(name=_l)
  212 + db.session.add(n_l)
  213 + db.session.commit()
  214 +
  215 + # Feed categories from initial list
  216 + #
  217 + for _c in categorie_keys:
  218 + n_c = Category(name=_c)
  219 + db.session.add(n_c)
  220 + db.session.commit()
  221 +
191 # Feed services from column 222 # Feed services from column
192 # 223 #
193 for s in services: 224 for s in services:
@@ -212,25 +243,25 @@ def feed_from_irap(csv_file_name): @@ -212,25 +243,25 @@ def feed_from_irap(csv_file_name):
212 243
213 # Feed categories and labels 244 # Feed categories and labels
214 # 245 #
215 - for c, l in categories.items():  
216 - current_app.logger.debug("Adding category " + c)  
217 - n_c = Category(name=c.capitalize())  
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) 246 + for category, labels in categorie_labels.items():
  247 + print(category)
  248 + n_c = Category.query.filter_by(name=category).one()
  249 + for label in labels:
  250 + print(label)
  251 + n_l = Label.query.filter(Label.name == label).one()
  252 + current_app.logger.debug(f"Adding label {label} to category {category}")
  253 + n_cl = CategoryLabel(label=n_l, category=n_c)
  254 + db.session.add(n_cl)
224 db.session.commit() 255 db.session.commit()
225 256
226 # Feed project's labels 257 # Feed project's labels
227 # 258 #
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) 259 + for project, labels in project_labels.items():
  260 + print(f"Project {project}")
  261 + n_p = Project.query.filter(Project.name == project).one()
  262 + for label in labels:
  263 + n_l = Label.query.filter(Label.name == label).one()
  264 + n_pl = ProjectLabel(project=n_p, label=n_l)
234 db.session.add(n_pl) 265 db.session.add(n_pl)
235 db.session.commit() 266 db.session.commit()
236 267
@@ -313,8 +344,9 @@ def feed_from_lesia(): @@ -313,8 +344,9 @@ def feed_from_lesia():
313 domain_category = Category(name="Domaine") 344 domain_category = Category(name="Domaine")
314 domains = lesia_session.query(lesia_domains) 345 domains = lesia_session.query(lesia_domains)
315 for d in domains: 346 for d in domains:
316 - n_l = Label(name=d.nom, category=domain_category)  
317 - db.session.add(n_l) 347 + n_l = Label(name=d.nom)
  348 + n_cl = CategoryLabel(category=domain_category, label=n_l)
  349 + db.session.add(n_cl)
318 db.session.commit() 350 db.session.commit()
319 351
320 # Feed all lesia 'pôle' names and link to new category "Pôle" 352 # Feed all lesia 'pôle' names and link to new category "Pôle"
@@ -322,8 +354,9 @@ def feed_from_lesia(): @@ -322,8 +354,9 @@ def feed_from_lesia():
322 pole_category = Category(name="Pôle") 354 pole_category = Category(name="Pôle")
323 poles = lesia_session.query(lesia_poles) 355 poles = lesia_session.query(lesia_poles)
324 for p in poles: 356 for p in poles:
325 - n_l = Label(name=p.nom, category=pole_category)  
326 - db.session.add(n_l) 357 + n_l = Label(name=p.nom)
  358 + n_cl = CategoryLabel(category=pole_category, label=n_l)
  359 + db.session.add(n_cl)
327 db.session.commit() 360 db.session.commit()
328 361
329 # Feed lesia project with proper "pôle" 362 # Feed lesia project with proper "pôle"
@@ -338,7 +371,7 @@ def feed_from_lesia(): @@ -338,7 +371,7 @@ def feed_from_lesia():
338 pole_name = lesia_session.query(lesia_poles).filter(lesia_poles.id == p.pole_id).one().nom 371 pole_name = lesia_session.query(lesia_poles).filter(lesia_poles.id == p.pole_id).one().nom
339 # search corresponding Label and store in ProjectLabel table 372 # search corresponding Label and store in ProjectLabel table
340 n_l = Label.query.filter(Label.name == pole_name).one() 373 n_l = Label.query.filter(Label.name == pole_name).one()
341 - n_pl = ProjectLabel(project=n_p, category=n_l.category, label=n_l) 374 + n_pl = ProjectLabel(project=n_p, label=n_l)
342 db.session.add(n_pl) 375 db.session.add(n_pl)
343 db.session.commit() 376 db.session.commit()
344 377
@@ -350,7 +383,7 @@ def feed_from_lesia(): @@ -350,7 +383,7 @@ def feed_from_lesia():
350 domain_name = lesia_session.query(lesia_domains).filter(lesia_domains.id == dp.domaine_id).one().nom 383 domain_name = lesia_session.query(lesia_domains).filter(lesia_domains.id == dp.domaine_id).one().nom
351 n_p = Project.query.filter(Project.name == project_name).one() 384 n_p = Project.query.filter(Project.name == project_name).one()
352 n_l = Label.query.filter(Label.name == domain_name).one() 385 n_l = Label.query.filter(Label.name == domain_name).one()
353 - n_pl = ProjectLabel(project=n_p, category=n_l.category, label=n_l) 386 + n_pl = ProjectLabel(project=n_p, label=n_l)
354 db.session.add(n_pl) 387 db.session.add(n_pl)
355 # Some projects have 2 domain labels in lesia db 388 # Some projects have 2 domain labels in lesia db
356 # That is not allowed any more in the new model. 389 # That is not allowed any more in the new model.
@@ -10,7 +10,13 @@ charge_unit = 100 @@ -10,7 +10,13 @@ charge_unit = 100
10 10
11 def projects(): 11 def projects():
12 """ 12 """
13 - Build the list of all agents, with their charges for the current period 13 + Build the list of all projects, with their charges for the current period
  14 +
  15 + Returns a table with headers in the first line:
  16 + Id, Project name, Category_1, ... , Category_n, Total_Charge_for_the_period
  17 +
  18 + The category cells embed the list of the labels of the project for that category.
  19 +
14 :return: 20 :return:
15 """ 21 """
16 current_period_id = get_current_period() 22 current_period_id = get_current_period()
@@ -26,21 +32,33 @@ def projects(): @@ -26,21 +32,33 @@ def projects():
26 projects_charges = db.session.execute(sql_txt).fetchall() 32 projects_charges = db.session.execute(sql_txt).fetchall()
27 # First row is table titles 33 # First row is table titles
28 all_projects = [["Id", "Projet"]] 34 all_projects = [["Id", "Projet"]]
29 - # Add all categories as last table titles  
30 - for c in Category.query.all(): 35 + # Add all categories as next table titles
  36 + # headers will then look like [["Id", "Projet", "Domaine", "Pôle"]]
  37 + categories = Category.query.all()
  38 + for c in categories:
31 all_projects[0].append(c.name) 39 all_projects[0].append(c.name)
  40 + # then add charge title
  41 + # headers become [["Id", "Projet", "Domaine", "Pôle", "Charge"]]
32 all_projects[0].append("Charge") 42 all_projects[0].append("Charge")
33 # Build the table row by row 43 # Build the table row by row
34 - for pc in projects_charges:  
35 - p_id = pc[0]  
36 - p = Project.query.get(int(p_id))  
37 - p_labels = p.labels  
38 - # adding 3 first columns: id, name and total charge  
39 - project_row = [p.id, p.name]  
40 - # then labels, one for each category  
41 - for pl in p_labels:  
42 - project_row.append(pl.label.name)  
43 - project_row.append(pc[1]) 44 + for _pc in projects_charges:
  45 + p_id = _pc[0]
  46 + project = Project.query.get(int(p_id))
  47 + # adding 2 first columns: id, name
  48 + project_row = [project.id, project.name]
  49 + # then labels, many for each category
  50 + for category in categories:
  51 + # we build the labels.name list of the intersection of current category's labels with project's labels
  52 + # Comprehensive shortcut is:
  53 + # labels = [_cl.label.name for _cl in category.labels if _cl.label in [_pl.label for _pl in project.labels]]
  54 + #
  55 + category_labels = [_cl.label for _cl in category.labels]
  56 + project_labels = [_pl.label for _pl in project.labels]
  57 + intersection_labels = list(set.intersection(set(project_labels), set(category_labels)))
  58 + labels = [label.name for label in intersection_labels]
  59 + project_row.append(labels)
  60 + # then add total charge
  61 + project_row.append(_pc[1])
44 all_projects.append(project_row) 62 all_projects.append(project_row)
45 return all_projects 63 return all_projects
46 64
app/main/routes.py
@@ -91,7 +91,7 @@ def project(project_id): @@ -91,7 +91,7 @@ def project(project_id):
91 this_project = Project.query.get(int(project_id)) 91 this_project = Project.query.get(int(project_id))
92 charges_table = db_mgr.charges_by_project(project_id) 92 charges_table = db_mgr.charges_by_project(project_id)
93 return render_template('project.html', 93 return render_template('project.html',
94 - project=this_project, 94 + project=this_project.to_struct(),
95 charges=charges_table, 95 charges=charges_table,
96 subtitle="{}".format(this_project.name)) 96 subtitle="{}".format(this_project.name))
97 97
app/main/templates/project.html
@@ -15,10 +15,10 @@ @@ -15,10 +15,10 @@
15 <div class="card-body"> 15 <div class="card-body">
16 <dl class="row"> 16 <dl class="row">
17 <dt class="col-sm-2 text-right">ID :</dt> 17 <dt class="col-sm-2 text-right">ID :</dt>
18 - <dd class="col-sm-10 text-left">{{project.id}}</dd>  
19 - {% for pl in project.labels %}  
20 - <dt class="col-sm-2 text-right">{{pl.label.category.name}} :</dt>  
21 - <dd class="col-sm-10 text-left">{{pl.label.name}}</dd> 18 + <dd class="col-sm-10 text-left">{{project['id']}}</dd>
  19 + {% for category, labels in project['category_labels'].items() %}
  20 + <dt class="col-sm-2 text-right">{{category}} :</dt>
  21 + <dd class="col-sm-10 text-left">{{labels|join(",")}}</dd>
22 {% endfor %} 22 {% endfor %}
23 <dt class="col-sm-2 text-right">Etat :</dt> 23 <dt class="col-sm-2 text-right">Etat :</dt>
24 <dd class="col-sm-10 text-left"></dd> 24 <dd class="col-sm-10 text-left"></dd>
app/main/templates/projects.html
@@ -18,8 +18,9 @@ @@ -18,8 +18,9 @@
18 <td><a href="{{url_for('main.project', project_id=project[0])}}"> 18 <td><a href="{{url_for('main.project', project_id=project[0])}}">
19 {{ project[1] }}</a> 19 {{ project[1] }}</a>
20 </td> 20 </td>
  21 + {#the category cells#}
21 {% for c in project[2:-1] %} 22 {% for c in project[2:-1] %}
22 - <td>{{c}}</td> 23 + <td>{{c|join(',')}}</td>
23 {% endfor %} 24 {% endfor %}
24 <td>{{ project[-1] /100}}</td> 25 <td>{{ project[-1] /100}}</td>
25 </tr> 26 </tr>
@@ -41,36 +41,82 @@ class Formable: @@ -41,36 +41,82 @@ class Formable:
41 # 41 #
42 # Categorized projects 42 # Categorized projects
43 # 43 #
  44 +# There is one label list,
  45 +# each label belongs to one or more categories.
  46 +#
  47 +# The projects are labelled by one or more label.
  48 +#
  49 +# Thus this is modeled with classes
  50 +# Project, Label and Category
  51 +# And many_to_many association are done through
  52 +# ProjectLabel and CategoryLabel
  53 +#
44 54
45 -class Project(db.Model): 55 +class Project(db.Model, Formable):
46 id = db.Column(db.Integer, primary_key=True) 56 id = db.Column(db.Integer, primary_key=True)
47 name = db.Column(db.String) 57 name = db.Column(db.String)
48 labels = relationship("ProjectLabel", back_populates="project") 58 labels = relationship("ProjectLabel", back_populates="project")
49 59
  60 + export_keys = ['name']
50 61
51 -class Category(db.Model): 62 + def to_struct(self):
  63 + """
  64 + overide parent method to include one key: agent.fullname
  65 +
  66 + Mainly we add the 'labels' element containing a dict
  67 + where category key contains labels for that project.
  68 + :return:
  69 + """
  70 + _struct = super(Project, self).to_struct()
  71 + _struct['category_labels'] = {}
  72 + for _c in Category.query.all():
  73 + category_labels = []
  74 + for _l in self.labels:
  75 + if _l.label in [_cl.label for _cl in _c.labels]:
  76 + category_labels.append(_l.label.name)
  77 + _struct['category_labels'][_c.name] = category_labels
  78 + return _struct
  79 +
  80 +
  81 +class ProjectLabel(db.Model):
  82 + """
  83 + Labelling projects.
  84 + On project can have many labels.
  85 + And one label will be set to many projects
  86 + """
52 id = db.Column(db.Integer, primary_key=True) 87 id = db.Column(db.Integer, primary_key=True)
53 - name = db.Column(db.String)  
54 - labels = relationship("Label", back_populates="category")  
55 - projects = relationship("ProjectLabel", back_populates="category") 88 + project_id = db.Column(db.Integer, db.ForeignKey('project.id'))
  89 + label_id = db.Column(db.Integer, db.ForeignKey('label.id'))
  90 + project = relationship("Project", back_populates="labels")
  91 + label = relationship("Label", back_populates="projects")
56 92
57 93
58 class Label(db.Model): 94 class Label(db.Model):
59 id = db.Column(db.Integer, primary_key=True) 95 id = db.Column(db.Integer, primary_key=True)
60 name = db.Column(db.String, unique=True) 96 name = db.Column(db.String, unique=True)
61 category_id = db.Column(db.Integer, db.ForeignKey('category.id')) 97 category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
62 - category = relationship("Category", back_populates="labels")  
63 projects = relationship("ProjectLabel", back_populates="label") 98 projects = relationship("ProjectLabel", back_populates="label")
  99 + categories = relationship("CategoryLabel", back_populates="label")
64 100
65 101
66 -class ProjectLabel(db.Model):  
67 - project_id = db.Column(db.Integer, db.ForeignKey('project.id'), primary_key=True)  
68 - category_id = db.Column(db.Integer, db.ForeignKey('category.id'), primary_key=True) 102 +class CategoryLabel(db.Model):
  103 + """
  104 + Categorizing labels:
  105 + one label can be added to many categories
  106 + one category hosts many labels
  107 + """
  108 + id = db.Column(db.Integer, primary_key=True)
  109 + category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
69 label_id = db.Column(db.Integer, db.ForeignKey('label.id')) 110 label_id = db.Column(db.Integer, db.ForeignKey('label.id'))
  111 + category = relationship("Category", back_populates="labels")
  112 + label = relationship("Label", back_populates="categories")
70 113
71 - project = relationship("Project", back_populates="labels")  
72 - category = relationship("Category", back_populates="projects")  
73 - label = relationship("Label", back_populates="projects") 114 +
  115 +class Category(db.Model):
  116 + id = db.Column(db.Integer, primary_key=True)
  117 + name = db.Column(db.String)
  118 + labels = relationship("Label", back_populates="category")
  119 + labels = relationship("CategoryLabel", back_populates="category")
74 120
75 121
76 # 122 #
resources/lesia-btp.sqlite
No preview for this file type
tests/backend_tests.py
1 import os 1 import os
2 import unittest 2 import unittest
  3 +from pprint import pprint
3 4
4 from pdc_config import TestConfig 5 from pdc_config import TestConfig
5 from app import create_app, db_mgr 6 from app import create_app, db_mgr
@@ -40,6 +41,22 @@ class DbMgrTestCase(BaseTestCase): @@ -40,6 +41,22 @@ class DbMgrTestCase(BaseTestCase):
40 all_projects = db_mgr.projects() 41 all_projects = db_mgr.projects()
41 self.assertEqual(5, len(all_projects[0])) 42 self.assertEqual(5, len(all_projects[0]))
42 43
  44 + def test_projects_all_columns(self):
  45 + all_projects = db_mgr.projects()
  46 + for p in all_projects:
  47 + with self.subTest(p):
  48 + self.assertEqual(5, len(p), f"Failed on {p[1]}")
  49 +
  50 + def test_projects_labels(self):
  51 + self.assertEqual(0, 0)
  52 + all_projects = db_mgr.projects()
  53 + # test all projects but skip headers first row
  54 + for p in all_projects[1:]:
  55 + with self.subTest(p):
  56 + # the number of labels for each category and any project should be less than 2
  57 + self.assertTrue(len(p[2]) <= 2, f"Failed on {p[1]}: " + ", ".join(p[2]))
  58 + self.assertTrue(len(p[3]) <= 2, f"Failed on {p[1]}: " + ", ".join(p[3]))
  59 +
43 def test_agents(self): 60 def test_agents(self):
44 all_agents = db_mgr.agents() 61 all_agents = db_mgr.agents()
45 self.assertEqual(548, len(all_agents)) 62 self.assertEqual(548, len(all_agents))
tests/common_db_feed.py
@@ -14,41 +14,42 @@ def resources_to_instancedb(app): @@ -14,41 +14,42 @@ def resources_to_instancedb(app):
14 copyfile(sqlite_file_name, db_path) 14 copyfile(sqlite_file_name, db_path)
15 return db_path 15 return db_path
16 16
17 -  
18 -categorized_labels = {'pole': ['Spatial', 'Sol'], 'domaine': ['soleil-terre', 'atmosphere', 'r&t', 'géologie']}  
19 -projects_categories = {'ChemCam': {'pole': 'Spatial', 'domaine': 'géologie'},  
20 - 'Pilot': {'pole': 'Spatial', 'domaine': 'atmosphere'},  
21 - 'Ambre': {'pole': 'Spatial', 'domaine': 'soleil-terre'}}  
22 -  
23 -  
24 -def feed_projects():  
25 - for c_name, labels in categorized_labels.items():  
26 - n_c = Category(name=c_name)  
27 - db.session.add(n_c)  
28 - for l_name in labels:  
29 - n_l = Label(name=l_name, category=n_c)  
30 - db.session.add(n_l)  
31 -  
32 - db.session.commit()  
33 -  
34 - project_names = projects_categories.keys()  
35 -  
36 - for p_name in set(project_names):  
37 - n_p = Project(name=p_name)  
38 - db.session.add(n_p)  
39 - db.session.commit()  
40 -  
41 - for p, categories in projects_categories.items():  
42 - n_p = db.session.query(Project).filter(Project.name == p).one()  
43 - for c_name, l_name in categories.items():  
44 - n_c = db.session.query(Category).filter(Category.name == c_name).one()  
45 - n_l = db.session.query(Label).filter(Label.name == l_name).one()  
46 - n_pc = ProjectLabel(project=n_p, category=n_c, label=n_l)  
47 - db.session.add(n_pc)  
48 -  
49 - db.session.commit()  
50 -  
51 -  
52 -def show_categories():  
53 - for c in db.session.query(Category).all():  
54 - print(c.name + ": ", ",".join([l.name for l in c.categorized_labels])) 17 +# TODO: rewrite for new category/label model
  18 +#
  19 +# categorized_labels = {'pole': ['Spatial', 'Sol'], 'domaine': ['soleil-terre', 'atmosphere', 'r&t', 'géologie']}
  20 +# projects_categories = {'ChemCam': {'pole': 'Spatial', 'domaine': 'géologie'},
  21 +# 'Pilot': {'pole': 'Spatial', 'domaine': 'atmosphere'},
  22 +# 'Ambre': {'pole': 'Spatial', 'domaine': 'soleil-terre'}}
  23 +#
  24 +#
  25 +# def feed_projects():
  26 +# for c_name, labels in categorized_labels.items():
  27 +# n_c = Category(name=c_name)
  28 +# db.session.add(n_c)
  29 +# for l_name in labels:
  30 +# n_l = Label(name=l_name, category=n_c)
  31 +# db.session.add(n_l)
  32 +#
  33 +# db.session.commit()
  34 +#
  35 +# project_names = projects_categories.keys()
  36 +#
  37 +# for p_name in set(project_names):
  38 +# n_p = Project(name=p_name)
  39 +# db.session.add(n_p)
  40 +# db.session.commit()
  41 +#
  42 +# for p, categories in projects_categories.items():
  43 +# n_p = db.session.query(Project).filter(Project.name == p).one()
  44 +# for c_name, l_name in categories.items():
  45 +# n_c = db.session.query(Category).filter(Category.name == c_name).one()
  46 +# n_l = db.session.query(Label).filter(Label.name == l_name).one()
  47 +# n_pc = ProjectLabel(project=n_p, category=n_c, label=n_l)
  48 +# db.session.add(n_pc)
  49 +#
  50 +# db.session.commit()
  51 +#
  52 +#
  53 +# def show_categories():
  54 +# for c in db.session.query(Category).all():
  55 +# print(c.name + ": ", ",".join([l.name for l in c.categorized_labels]))
tests/db_tests.py
1 import os 1 import os
2 import unittest 2 import unittest
  3 +from pprint import pprint
3 4
4 from app import create_app, db, User 5 from app import create_app, db, User
5 from app.models import Project 6 from app.models import Project
6 from pdc_config import TestConfig 7 from pdc_config import TestConfig
7 -from tests.common_db_feed import feed_projects, resources_to_instancedb 8 +from tests.common_db_feed import resources_to_instancedb
8 9
9 10
10 class DbBaseTestCase(unittest.TestCase): 11 class DbBaseTestCase(unittest.TestCase):
@@ -36,7 +37,8 @@ class DbBaseTestCase(unittest.TestCase): @@ -36,7 +37,8 @@ class DbBaseTestCase(unittest.TestCase):
36 # 37 #
37 if self.mode == 'memory': 38 if self.mode == 'memory':
38 db.create_all() 39 db.create_all()
39 - feed_projects() 40 + # TODO: to be rewriten for new category/label model
  41 + # feed_projects()
40 42
41 def tearDown(self): 43 def tearDown(self):
42 if self.mode == 'memory': 44 if self.mode == 'memory':
@@ -48,6 +50,21 @@ class DbBaseTestCase(unittest.TestCase): @@ -48,6 +50,21 @@ class DbBaseTestCase(unittest.TestCase):
48 self.app_context.pop() 50 self.app_context.pop()
49 51
50 52
  53 +class AnyModelTestCase(DbBaseTestCase):
  54 + def setUp(self):
  55 + DbBaseTestCase.setUp(self, 'btp')
  56 +
  57 + def tearDown(self):
  58 + DbBaseTestCase.tearDown(self)
  59 +
  60 + def test_projects_struct(self):
  61 + for project in Project.query.all():
  62 + with self.subTest(project):
  63 + categories = list(project.to_struct()['category_labels'].keys())
  64 + self.assertEqual(['Domaine', 'Pôle'], categories,
  65 + f"Failed on {project.name} categories: {categories}")
  66 +
  67 +
51 class ChargeModelTestCase(DbBaseTestCase): 68 class ChargeModelTestCase(DbBaseTestCase):
52 def setUp(self): 69 def setUp(self):
53 DbBaseTestCase.setUp(self, 'btp') 70 DbBaseTestCase.setUp(self, 'btp')
tests/frontend_tests.py
@@ -112,6 +112,20 @@ class AccessTestCase(BaseFrontTestCase): @@ -112,6 +112,20 @@ class AccessTestCase(BaseFrontTestCase):
112 self.driver.get(target_url) 112 self.driver.get(target_url)
113 self.assertEqual(self.driver.current_url, 'http://localhost:8943/projects') 113 self.assertEqual(self.driver.current_url, 'http://localhost:8943/projects')
114 114
  115 + def test_projects_trs(self):
  116 + target_url = self.get_server_url() + url_for('main.projects')
  117 + self.driver.get(target_url)
  118 + td_elmts = self.driver.find_elements_by_xpath("//table/tbody/tr")
  119 + self.assertEqual(101, len(td_elmts))
  120 +
  121 + def test_projects_tds(self):
  122 + target_url = self.get_server_url() + url_for('main.projects')
  123 + self.driver.get(target_url)
  124 + for tr in self.driver.find_elements_by_xpath("//table/tbody/tr"):
  125 + with self.subTest(tr):
  126 + tds = tr.find_elements_by_tag_name('td')
  127 + self.assertEqual(4, len(tds), tds[0].text + " has wrong number of columns")
  128 +
115 def test_project_page(self): 129 def test_project_page(self):
116 project_id = 8 130 project_id = 8
117 target_url = self.get_server_url() + url_for('main.project', project_id=project_id) 131 target_url = self.get_server_url() + url_for('main.project', project_id=project_id)
@@ -120,6 +134,17 @@ class AccessTestCase(BaseFrontTestCase): @@ -120,6 +134,17 @@ class AccessTestCase(BaseFrontTestCase):
120 td_elmts = self.driver.find_elements_by_xpath("//table[@id='charge_table']/tbody/tr/td") 134 td_elmts = self.driver.find_elements_by_xpath("//table[@id='charge_table']/tbody/tr/td")
121 self.assertEqual(1085, len(td_elmts)) 135 self.assertEqual(1085, len(td_elmts))
122 136
  137 + def test_project_page_categories(self):
  138 + project_id = 84
  139 + target_url = self.get_server_url() + url_for('main.project', project_id=project_id)
  140 + self.driver.get(target_url)
  141 + self.assertEqual(self.driver.current_url, f'http://localhost:8943/project/{project_id}')
  142 + # pole_dt_db = self.driver.find_element_by_xpath("//dt[text()='Pôle']/following-sibling::dd")
  143 + pole_dt_db = self.driver.find_element_by_xpath("//dt[contains(text(),'Pôle')]/following-sibling::dd")
  144 + self.assertEqual('Solaire', pole_dt_db.text)
  145 + domaine_dt_db = self.driver.find_element_by_xpath("//dt[contains(text(),'Domaine')]/following-sibling::dd")
  146 + self.assertTrue('LESIA' in domaine_dt_db.text)
  147 +
123 148
124 class FormsTestCase(BaseFrontTestCase): 149 class FormsTestCase(BaseFrontTestCase):
125 150