Browse Source

wip: cleaning code and features

develop
Mindiell 3 months ago
parent
commit
77d0b98641
  1. 2
      app/__init__.py
  2. 16
      app/controller/admin/__init__.py
  3. 76
      app/controller/admin/country.py
  4. 118
      app/controller/admin/entity.py
  5. 143
      app/controller/admin/importer.py
  6. 119
      app/controller/admin/membership.py
  7. 156
      app/controller/admin/representative.py
  8. 45
      app/controller/api/country.py
  9. 25
      app/controller/api/representative.py
  10. 19
      app/controller/core.py
  11. 10
      app/controller/representative.py
  12. 19
      app/controller/stance.py
  13. 16
      app/form/stance.py
  14. 12
      app/model/__init__.py
  15. 32
      app/model/address.py
  16. 34
      app/model/contact.py
  17. 21
      app/model/country.py
  18. 29
      app/model/decision.py
  19. 25
      app/model/entity.py
  20. 30
      app/model/matter.py
  21. 26
      app/model/membership.py
  22. 4
      app/model/model.py
  23. 43
      app/model/recommendation.py
  24. 75
      app/model/representative.py
  25. 21
      app/model/representative_origin.py
  26. 12
      app/model/role.py
  27. 17
      app/model/source.py
  28. 44
      app/model/stance.py
  29. 9
      app/model/type.py
  30. 5
      app/routes.py
  31. 1
      app/view/menu.html
  32. 2
      migrations/README
  33. 32
      migrations/versions/0df00d383cb1_.py
  34. 44
      migrations/versions/49d256e40a4c_.py
  35. 43
      migrations/versions/6a205c6b23bb_.py
  36. 179
      migrations/versions/6ce21d3cdf0e_.py
  37. 28
      migrations/versions/6dcc965ab0d4_.py
  38. 48
      migrations/versions/aa24a81be355_.py
  39. 34
      migrations/versions/bc290d035406_.py
  40. 65
      migrations/versions/c968d84e9996_.py
  41. 32
      migrations/versions/cd76771172a8_.py
  42. 58
      migrations/versions/f238158c8ad6_.py
  43. 45
      migrations/versions/f448ec882889_.py
  44. 8
      settings.py

2
app/__init__.py

@ -12,4 +12,4 @@ api = Api()
babel = Babel()
db = SQLAlchemy()
login_manager = LoginManager()
migrate = Migrate()
migrate = Migrate(compare_type=True)

16
app/controller/admin/__init__.py

@ -1,22 +1,14 @@
# encoding: utf-8
from app.controller.admin.importer import (ImportAddressView, ImportContactView,
ImportCountryView, ImportDecisionView, ImportEntityView, ImportMatterView,
ImportMembershipView, ImportRecommendationView, ImportRepresentativeView,
ImportRoleView, ImportStanceView, ImportTypeView)
from app.controller.admin.country import ImportCountryView
from app.controller.admin.entity import ImportEntityView
from app.controller.admin.membership import ImportMembershipView
from app.controller.admin.representative import ImportRepresentativeView
admin_routes = (
(ImportAddressView, "Addresses", "addresses", "Import"),
(ImportContactView, "Contacts", "contacts", "Import"),
(ImportCountryView, "Countries", "countries", "Import"),
(ImportDecisionView, "Decisions", "decisions", "Import"),
(ImportEntityView, "Entities", "entities", "Import"),
(ImportMatterView, "Matters", "matters", "Import"),
(ImportMembershipView, "Memberships", "memberships", "Import"),
(ImportRecommendationView, "Recommendations", "recommendations", "Import"),
(ImportRepresentativeView, "Representatives", "representatives", "Import"),
(ImportRoleView, "Roles", "roles", "Import"),
(ImportStanceView, "Stances", "stances", "Import"),
(ImportTypeView, "Types", "types", "Import"),
)

76
app/controller/admin/country.py

@ -0,0 +1,76 @@
# encoding: utf-8
from flask import current_app, g, request, redirect, url_for
from flask_admin import BaseView, expose
from slugify import slugify
from app.form.admin import ImportForm
from app.controller.admin.importer import default_import
from app.model.country import CountryModel
class ImportCountryView(BaseView):
@expose("/", methods=["GET", "POST"])
def index(self):
g.what = {
"title": "Import countries",
"description": "Importing countries will add unknown ones and update"
" known ones. If a country is not present in imported file it"
" will not be deleted.",
"endpoint": "countries.index",
"formats": [
"File format accepted is CSV (Comma Separated Values).",
"First line represents column headers.",
"Other lines are values:",
"One column MUST be 'name'",
"One column COULD be 'alpha_2'",
"One column COULD be 'alpha_3'",
"One column COULD be 'official_name'",
],
"examples": [
"name,alpha_2",
"Spain,es",
"Germany,DE",
],
}
headers = {
"name": None,
"alpha_2": "optional",
"alpha_3": "optional",
"official_name": "optional",
}
reader = default_import(headers)
if len(g.errors) == 0 and reader is not None:
for row in reader:
country = CountryModel.query.filter_by(
name=row[headers["name"]],
).first()
if headers["alpha_2"] is not None:
alpha_2 = row[headers["alpha_2"]]
else:
alpha_2 = None
if headers["alpha_3"] is not None:
alpha_3 = row[headers["alpha_3"]]
else:
alpha_3 = None
if headers["official_name"] is not None:
official_name = row[headers["official_name"]]
else:
official_name = None
if country is None:
country = CountryModel(
name = row[headers["name"]],
slug = slugify(row[headers["name"]]),
alpha_2 = alpha_2,
alpha_3 = alpha_3,
official_state_name = official_name,
)
g.messages.append(
f"{row[headers['name']]} added."
)
country.save()
else:
# Mise à jour du pays !
pass
return self.render("admin/import.html")

118
app/controller/admin/entity.py

@ -0,0 +1,118 @@
# encoding: utf-8
from datetime import datetime
from flask import current_app, g, request, redirect, url_for
from flask_admin import BaseView, expose
from slugify import slugify
from app.form.admin import ImportForm
from app.controller.admin.importer import default_import
from app.model.entity import EntityModel
from app.model.type import TypeModel
class ImportEntityView(BaseView):
@expose("/", methods=["GET", "POST"])
def index(self):
g.what = {
"title": "Import entities",
"description": "Importing entities will add unknown ones and update"
" known ones. If an entity is not present in imported file it"
" will not be deleted.",
"endpoint": "entities.index",
"formats": [
"File format accepted is CSV (Comma Separated Values).",
"First line represents column headers.",
"Other lines are values:",
"One column MUST be 'name'",
"One column MUST be 'reference'",
"One column MUST be 'parent_reference'",
"One column MUST be 'start'",
"One column COULD be 'end'",
"One column COULD be 'source'",
"One column COULD be 'type_code'",
"One column COULD be 'type_name'",
],
"examples": [
"name,reference,parent_reference,source,type_code,type_name,start,end",
"Thingy Commission,CO1234,NA123,French National Assembly,COMM,Commission,2020-01-01,",
"Group Assembly,NA123,,French National Assembly,GROU,Group,2019-01-01,2099-12-31",
],
}
headers = {
"name": None,
"reference": None,
"parent_reference": None,
"source": "optional",
"type_code": "optional",
"type_name": "optional",
"start": None,
"end": "optional",
}
reader = default_import(headers)
if len(g.errors) == 0 and reader is not None:
for row in reader:
if headers["type_code"] is not None:
entity_type = TypeModel.query.filter_by(
code=row[headers["type_code"]].upper(),
).first()
if entity_type is None:
entity_type = TypeModel(
code=row[headers["type_code"]].upper(),
name=row[headers["type_name"]],
slug=slugify(row[headers["type_name"]]),
)
entity_type.save()
if headers["source"] is not None:
source = row[headers["source"]]
else:
source = None
if row[headers["start"]] != "":
start = datetime.strptime(
row[headers["start"]], "%Y-%m-%d"
).date()
else:
start = None
end = None
if headers["end"] is not None:
if row[headers["end"]] != "":
end = datetime.strptime(
row[headers["end"]], "%Y-%m-%d"
).date()
parent = EntityModel.query.filter_by(
reference=row[headers["parent_reference"]].upper(),
).first()
if parent is not None:
parent_id = parent.id
else:
parent_id = None
entity = EntityModel.query.filter_by(
reference=row[headers["reference"]].upper()
).first()
if entity is None:
entity = EntityModel(
name = row[headers["name"]],
slug = slugify(row[headers["name"]]),
reference = row[headers["reference"]].upper(),
parent_id = parent_id,
source = source,
type = entity_type,
start = start,
end = end,
active = True if end is None else False,
)
g.messages.append(
f"{row[headers['name']]} added."
)
entity.save()
else:
# updating information ?
pass
return self.render("admin/import.html")

143
app/controller/admin/importer.py

@ -222,52 +222,6 @@ class ImportContactView(BaseView):
return self.render("admin/import.html")
class ImportCountryView(BaseView):
@expose("/", methods=["GET", "POST"])
def index(self):
headers = {"name": None, "code": None}
reader = default_import(headers)
g.what = {
"title": "Import countries",
"description": "Importing countries will add unknown ones and update known"
" ones. If a country is not present in imported file it will not be"
" deleted.",
"endpoint": "countries.index",
"formats": [
"File format accepted is CSV (Comma Separated Values).",
"First line chould be column headers.",
"Other lines are values.",
"One column MUST be 'name'.",
"One column MUST be 'code'.",
],
"examples": [
"name,code",
"France,FR",
"United States of America,US",
"Spain,SP",
],
}
if len(g.errors) == 0 and reader is not None:
for row in reader:
country = model.CountryModel.query.filter_by(code=row[headers["code"]]).first()
if country is None:
country = model.CountryModel(
name = row[headers["name"]],
slug = slugify(row[headers["name"]]),
code = row[headers["code"]].upper(),
)
g.messages.append(f"{row[headers['name']]} added.")
country.save()
else:
if country.name != row[headers["name"]]:
country.name = row[headers["name"]]
country.slug = slugify(row[headers["name"]])
g.messages.append(f"{row[headers['name']]} updated.")
country.save()
return self.render("admin/import.html")
class ImportDecisionView(BaseView):
@expose("/", methods=["GET", "POST"])
def index(self):
@ -665,102 +619,6 @@ class ImportRecommendationView(BaseView):
return self.render("admin/import.html")
class ImportRepresentativeView(BaseView):
@expose("/", methods=["GET", "POST"])
def index(self):
headers = {
"code": None,
"name": None,
"picture": None,
"nationality": None,
"sex": None,
"birth_date": None,
"birth_place": None,
"job": None,
}
reader = default_import(headers)
g.what = {
"title": "Import representatives",
"description": "Importing representatives will add unknown ones and update"
" known ones. If a representative is not present in imported file it"
" will not be deleted.",
"endpoint": "representatives.index",
"formats": [
"File format accepted is CSV (Comma Separated Values).",
"First line chould be column headers.",
"Other lines are values.",
"One column MUST be 'code' and be the unique identifier of the representative.",
"One column MUST be 'name'.",
"One column MUST be 'picture'.",
"One column MUST be 'nationality' and be an ISO country code.",
"One column MUST be 'sex' and be 'F' or 'M'.",
"One column MUST be 'birth_date'.",
"One column MUST be 'birth_place'.",
"One column MUST be 'birth_job'.",
],
"examples": [
"name,iso2,iso3",
"France,FR,FRA",
"United States of America,US,USA",
"Spain,SP,SPA",
],
}
if len(g.errors) == 0 and reader is not None:
# Values
for row in reader:
representative = model.RepresentativeModel.query.filter_by(
code=row[headers["code"]],
).first()
country = model.CountryModel.query.filter_by(
code=row[headers["nationality"]].upper(),
).first()
if row[headers["birth_date"]] != "":
birth_date = datetime.strptime(row[headers["birth_date"]], "%Y-%m-%d").date()
else:
birth_date = None
if representative is None:
representative = model.RepresentativeModel(
code = row[headers["code"]],
name = row[headers["name"]],
slug = slugify(row[headers["name"]]),
picture = row[headers["picture"]],
nationality = country,
sex = row[headers["sex"]],
birth_date = birth_date,
birth_place = row[headers["birth_place"]],
job = row[headers["job"]],
)
g.messages.append(f"{row[headers['name']]} added.")
representative.save()
else:
updated = False
if representative.picture != row[headers["picture"]]:
representative.picture = row[headers["picture"]]
updated = True
if representative.nationality != country:
representative.nationality = country
updated = True
if representative.sex != row[headers["sex"]]:
representative.sex = row[headers["sex"]]
updated = True
if representative.birth_date != birth_date:
print(representative.birth_date)
print(birth_date)
representative.birth_date = birth_date
updated = True
if representative.birth_place != row[headers["birth_place"]]:
representative.birth_place = row[headers["birth_place"]]
updated = True
if representative.job != row[headers["job"]]:
representative.job = row[headers["job"]]
updated = True
if updated:
g.messages.append(f"{row[headers['name']]} updated.")
representative.save()
return self.render("admin/import.html")
class ImportRoleView(BaseView):
@expose("/", methods=["GET", "POST"])
def index(self):
@ -953,4 +811,3 @@ class ImportTypeView(BaseView):
type_.save()
return self.render("admin/import.html")

119
app/controller/admin/membership.py

@ -0,0 +1,119 @@
# encoding: utf-8
from datetime import datetime
from flask import current_app, g, request, redirect, url_for
from flask_admin import BaseView, expose
from slugify import slugify
from sqlalchemy import or_
from app.form.admin import ImportForm
from app.controller.admin.importer import default_import
from app.model.entity import EntityModel
from app.model.membership import MembershipModel
from app.model.representative_origin import RepresentativeOriginModel
from app.model.role import RoleModel
class ImportMembershipView(BaseView):
@expose("/", methods=["GET", "POST"])
def index(self):
g.what = {
"title": "Import memberships",
"description": "Importing memberships will add unknown ones and update"
" known ones. If a membership is not present in imported file it"
" will not be deleted.",
"endpoint": "memberships.index",
"formats": [
"File format accepted is CSV (Comma Separated Values).",
"First line represents column headers.",
"Other lines are values:",
"One column MUST be 'reference'",
"One column MUST be 'representative_reference'",
"One column MUST be 'entity_reference'",
"One column MUST be 'role_code'",
"One column MUST be 'role'",
"One column MUST be 'start'",
"One column COULD be 'end'",
],
"examples": [
"reference,representative_reference,entity_reference,role_code,role,start,end",
"12,23,34,MBR,Member,2020-01-01,",
"45,67,89,PDT,President,2018-01-01,2019-12-31",
],
}
headers = {
"reference": None,
"representative_reference": None,
"entity_reference": None,
"role_code": None,
"role": None,
"start": None,
"end": "optional",
}
reader = default_import(headers)
if len(g.errors) == 0 and reader is not None:
for row in reader:
role = RoleModel.query.filter_by(
code=row[headers["role_code"]].upper()
).first()
if role is None:
role = RoleModel(
code=row[headers["role_code"]].upper(),
name=row[headers["role"]],
slug=slugify(row[headers["role"]]),
)
role.save()
entity = EntityModel.query.filter_by(
reference=row[headers["entity_reference"]].upper()
).first()
if entity is None:
g.messages.append("UNKNOWN entity :"
f"{row[headers['entity_reference']].upper()}"
)
continue
representative_origin = RepresentativeOriginModel.query.filter_by(
reference=row[headers["representative_reference"]].upper(),
).first()
if representative_origin is None:
g.messages.append("UNKNOWN representative :"
f"{row[headers['representative_reference']].upper()}"
)
continue
if row[headers["start"]] != "":
start = datetime.strptime(
row[headers["start"]], "%Y-%m-%d"
).date()
else:
start = None
end = None
if headers["end"] is not None:
if row[headers["end"]] != "":
end = datetime.strptime(
row[headers["end"]], "%Y-%m-%d"
).date()
membership = MembershipModel.query.filter_by(
reference=row[headers["reference"]].upper()
).first()
if membership is None:
membership = MembershipModel(
representative_id = representative_origin.representative_id,
entity_id = entity.id,
reference = row[headers["reference"]].upper(),
role_id = role.id,
start = start,
end = end,
active = True if end is None else False,
)
g.messages.append(
f"{role.name} added"
f" for {representative_origin.representative.first_name}"
f" {representative_origin.representative.last_name}."
)
membership.save()
return self.render("admin/import.html")

156
app/controller/admin/representative.py

@ -0,0 +1,156 @@
# encoding: utf-8
from datetime import datetime
from flask import current_app, g, request, redirect, url_for
from flask_admin import BaseView, expose
from slugify import slugify
from sqlalchemy import or_
from app.form.admin import ImportForm
from app.controller.admin.importer import default_import
from app.model.country import CountryModel
from app.model.representative import RepresentativeModel
from app.model.source import SourceModel
from app.model.representative_origin import RepresentativeOriginModel
class ImportRepresentativeView(BaseView):
@expose("/", methods=["GET", "POST"])
def index(self):
g.what = {
"title": "Import representatives",
"description": "Importing representatives will add unknown ones and update"
" known ones. If a representative is not present in imported file it"
" will not be deleted.",
"endpoint": "representatives.index",
"formats": [
"File format accepted is CSV (Comma Separated Values).",
"First line represents column headers.",
"Other lines are values:",
"One column MUST be 'source'",
"One column MUST be 'reference'",
"One column MUST be 'first_name'",
"One column MUST be 'last_name'",
"One column COULD be 'picture' and be a URI",
"One column COULD be 'birth_date'",
"One column COULD be 'birth_place'",
"One column COULD be 'birth_region'",
"One column COULD be 'birth_country'",
"One column COULD be 'nationality'",
"One column COULD be 'job'",
],
"examples": [
"source,reference,first_name,last_name,job",
"somewhere,123,Victor,Hugo,Writer",
"somewhere,456,Antonio,Vivaldi,Musician",
],
}
headers = {
"source": None,
"reference": None,
"first_name": None,
"last_name": None,
"picture": "optional",
"birth_date": "optional",
"birth_place": "optional",
"birth_region": "optional",
"birth_country": "optional",
"nationality": "optional",
"job": "optional",
}
reader = default_import(headers)
if len(g.errors) == 0 and reader is not None:
for row in reader:
if row[headers["nationality"]] !="":
nationality = CountryModel.query.filter(or_(
CountryModel.slug == slugify(row[headers["nationality"]]),
CountryModel.alpha_2 == row[headers["nationality"]].upper(),
)).first()
if nationality is None:
if len(row[headers["nationality"]])==2:
nationality = CountryModel(
name=row[headers["nationality"]],
slug=slugify(row[headers["nationality"]]),
alpha_2=row[headers["nationality"]].upper(),
)
else:
nationality = CountryModel(
name=row[headers["nationality"]],
slug=slugify(row[headers["nationality"]]),
)
nationality.save()
if row[headers["birth_country"]] !="":
birth_country = CountryModel.query.filter(or_(
CountryModel.slug == slugify(row[headers["birth_country"]]),
CountryModel.alpha_2 == row[headers["birth_country"]].upper(),
)).first()
if birth_country is None:
if len(row[headers["birth_country"]])==2:
birth_country = CountryModel(
name=row[headers["birth_country"]],
slug=slugify(row[headers["birth_country"]]),
alpha_2=row[headers["birth_country"]].upper(),
)
else:
birth_country = CountryModel(
name=row[headers["birth_country"]],
slug=slugify(row[headers["birth_country"]]),
)
birth_country.save()
if row[headers["birth_date"]] != "":
birth_date = datetime.strptime(
row[headers["birth_date"]], "%Y-%m-%d"
).date()
else:
birth_date = None
source = SourceModel.query.filter_by(
slug=slugify(row[headers["source"]]),
).first()
if source is None:
source = SourceModel(
name = row[headers["source"]],
slug = slugify(row[headers["source"]]),
)
source.save()
representative = RepresentativeModel.query.filter_by(
last_name=row[headers["last_name"]],
).filter_by(
first_name=row[headers["first_name"]],
).first()
if representative is None:
representative = RepresentativeModel(
first_name = row[headers["first_name"]],
last_name = row[headers["last_name"]],
birth_date = birth_date,
birth_place = row[headers["birth_place"]],
birth_region = row[headers["birth_region"]],
birth_country = birth_country,
job = row[headers["job"]],
nationality = nationality,
picture = row[headers["picture"]],
)
g.messages.append(
f"{row[headers['first_name']]} {row[headers['last_name']]}"
" added."
)
representative.save()
representative_origin = RepresentativeOriginModel.query.filter_by(
source_id=source.id,
).filter_by(
reference=row[headers["reference"]].upper(),
).first()
if representative_origin is None:
representative_origin = RepresentativeOriginModel(
source_id = source.id,
representative_id = representative.id,
reference = row[headers["reference"]].upper(),
)
representative_origin.save()
return self.render("admin/import.html")

45
app/controller/api/country.py

@ -1,45 +0,0 @@
# encoding: utf-8
from flask import request, current_app
from flask_restful import Resource
from sqlalchemy import or_
from app.model.country import CountryModel
class CountriesApi(Resource):
def get(self):
page = int(request.args.get("page", 1))
query = CountryModel.query
if request.args.get("name", "") != "":
query = query.filter(
CountryModel
.name
.like('%%%s%%' % request.args.get("name", ""))
)
if request.args.get("iso2", "") != "":
query = query.filter_by(iso2=request.args.get("iso2", "").upper())
if request.args.get("iso3", "") != "":
query = query.filter_by(iso3=request.args.get("iso3", "").upper())
if request.args.get("m49", "") != "":
query = query.filter_by(m49=request.args.get("m49", "").upper())
query = query.order_by(CountryModel.name)
return [
country.serialize()
for country
in query
.paginate(page, current_app.config['API_PER_PAGE'], error_out=False)
.items
]
class CountryApi(Resource):
def get(self, country_id):
country = CountryModel.query.filter(or_(
CountryModel.iso2==country_id,
CountryModel.iso3==country_id,
CountryModel.m49==country_id,
)).first()
if country is None:
return None, 404
return country.serialize()

25
app/controller/api/representative.py

@ -10,20 +10,26 @@ from app.model.representative import RepresentativeModel
class RepresentativesApi(Resource):
def get(self):
page = int(request.args.get("page", 1))
print(page)
query = RepresentativeModel.query
if request.args.get("name", "") != "":
query = query.filter(
RepresentativeModel
.name
.like('%%%s%%' % request.args.get("name", ""))
)
query = query.order_by(RepresentativeModel.name)
query = query.filter(or_(
RepresentativeModel.last_name.like(
f"%{request.args.get('name')}%"
),
RepresentativeModel.first_name.like(
f"%{request.args.get('name')}%"
),
))
query = query.order_by(RepresentativeModel.last_name)
print(request.args.get("name"))
print(query)
return [
representative.serialize()
for representative
in query
.paginate(page, current_app.config['API_PER_PAGE'], error_out=False)
.items
in query.paginate(
page, current_app.config["API_PER_PAGE"], error_out=False
).items
]
@ -32,4 +38,5 @@ class RepresentativeApi(Resource):
representative = RepresentativeModel.query.get(representative_id)
if representative is None:
return None, 404
print(representative.serialize())
return representative.serialize()

19
app/controller/core.py

@ -13,25 +13,6 @@ from sqlalchemy.sql.expression import func
class Core(Controller):
def home(self):
random.seed(int(datetime.today().timestamp()/100))
try:
g.motd = random.choice(model.MatterModel.query.filter_by(
active=True
).all())
except:
g.motd = None
try:
g.rotd = random.choice(model.RepresentativeModel.query.filter_by(
active=True
).all())
except:
g.rotd = None
g.last_decisions = model.DecisionModel.query.join(
model.DecisionModel.recommendation
).order_by(model.RecommendationModel.date.desc()).limit(10).all()
g.last_stances = model.StanceModel.query.order_by(
model.StanceModel.date.desc()
).limit(10).all()
return render_template("core/home.html")
def about(self):

10
app/controller/representative.py

@ -7,19 +7,17 @@ from flask import g, redirect, render_template, url_for
from app import model
from app.controller.controller import Controller
from sqlalchemy import desc
from sqlalchemy.sql.expression import func
class Representative(Controller):
def view(self, representative_id=None):
if representative_id is None:
representative_id = random.choice(
g.representative = random.choice(
model.RepresentativeModel.query.filter_by(active=True).all()
).id
g.representative = model.RepresentativeModel.query.get(representative_id)
)
else:
g.representative = model.RepresentativeModel.query.get(representative_id)
if g.representative is None:
return redirect(url_for("core.home"))
g.title = g.representative.name
return render_template("representative/view.html")

19
app/controller/stance.py

@ -1,19 +0,0 @@
# encoding: utf-8
from datetime import datetime
import random
from flask import g, redirect, render_template, url_for
from app import model
from app.controller.controller import Controller
from app.form.stance import AddStanceForm
from sqlalchemy import desc
from sqlalchemy.sql.expression import func
class Stance(Controller):
def add(self):
g.form = AddStanceForm()
return render_template("stance/add.html")

16
app/form/stance.py

@ -1,16 +0,0 @@
# encoding: utf-8
from flask_babel import gettext as _
from flask_wtf import FlaskForm
from wtforms import DateField, HiddenField, SelectField, TextField
from wtforms.validators import DataRequired
class AddStanceForm(FlaskForm):
representative = HiddenField(_("Représentant(e)"), validators=[DataRequired()])
matter = HiddenField(_("Dossier"))
date = DateField(_("Date"), validators=[DataRequired()])
subject = TextField(_("Sujet"), validators=[DataRequired()])
extract = TextField(_("Extrait"))
source_url = TextField(_("URL de la source"), validators=[DataRequired()])

12
app/model/__init__.py

@ -4,17 +4,11 @@ This module imports models to allow alembic and flask to find them.
"""
from app.model.user import UserModel
from app.model.country import CountryModel
from app.model.representative import RepresentativeModel
from app.model.address import AddressModel
from app.model.contact import ContactModel
from app.model.type import TypeModel
from app.model.entity import EntityModel
from app.model.representative import RepresentativeModel
from app.model.role import RoleModel
from app.model.source import SourceModel
from app.model.representative_origin import RepresentativeOriginModel
from app.model.membership import MembershipModel
from app.model.matter import MatterModel
from app.model.recommendation import RecommendationModel
from app.model.decision import DecisionModel
from app.model.stance import StanceModel

32
app/model/address.py

@ -1,32 +0,0 @@
# encoding: utf-8
from app import admin, db
from app.model.model import Model, View
class AddressModel(db.Model, Model):
__tablename__ = "address"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200))
slug = db.Column(db.String(200))
country_id = db.Column(db.Integer, db.ForeignKey("country.id"))
country = db.relationship("CountryModel")
number = db.Column(db.String(20))
street = db.Column(db.String(2000))
miscellaneous = db.Column(db.String(2000))
city = db.Column(db.String(2000))
zipcode = db.Column(db.String(20))
building = db.Column(db.String(20))
floor = db.Column(db.String(20))
stair = db.Column(db.String(20))
office = db.Column(db.String(20))
latitude = db.Column(db.String(20))
longitude = db.Column(db.String(20))
class AdminView(View):
column_default_sort = [("name", False), ("country.name", True)]
column_filters = ["name", "country.name"]
admin.add_view(AdminView(AddressModel, db.session, name="Address", category="CRUD"))

34
app/model/contact.py

@ -1,34 +0,0 @@
# encoding: utf-8
from app import admin, db
from app.model.model import Model, View
class ContactModel(db.Model, Model):
__tablename__ = "contact"
id = db.Column(db.Integer, primary_key=True)
representative_id = db.Column(db.Integer, db.ForeignKey("representative.id"))
representative = db.relationship(
"RepresentativeModel", backref=db.backref("contacts", lazy="dynamic")
)
address_id = db.Column(db.Integer, db.ForeignKey("address.id"))
address = db.relationship(
"AddressModel", backref=db.backref("contacts", lazy="dynamic")
)
name = db.Column(db.String(200))
slug = db.Column(db.String(200))
value = db.Column(db.String(2000))
def __repr__(self):
return self.name
class AdminView(View):
column_default_sort = "name"
column_filters = ["representative.name", "name"]
def on_model_change(self, form, model, is_created):
model.slug = slugify(model.name)
admin.add_view(AdminView(ContactModel, db.session, name="Contact", category="CRUD"))

21
app/model/country.py

@ -9,25 +9,12 @@ class CountryModel(db.Model, Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200))
slug = db.Column(db.String(200))
code = db.Column(db.String(20))
@property
def flag(self):
"""
HTML unicode sequence for display country flag.
"""
return "".join([f"&#{hex(127397+ord(l))[1:]};" for l in self.code])
official_state_name = db.Column(db.String(200))
alpha_2 = db.Column(db.String(2))
alpha_3 = db.Column(db.String(3))
def __repr__(self):
return self.name
class AdminView(View):
column_default_sort = "name"
column_filters = ["name", "code"]
def on_model_change(self, form, model, is_created):
model.slug = slugify(model.name)
admin.add_view(AdminView(CountryModel, db.session, name="Country", category="CRUD"))
admin.add_view(View(CountryModel, db.session, name="Country", category="CRUD"))

29
app/model/decision.py

@ -1,29 +0,0 @@
# encoding: utf-8
from app import admin, db
from app.model.model import Model, View
class DecisionModel(db.Model, Model):
__tablename__ = "decision"
id = db.Column(db.Integer, primary_key=True)
representative_id = db.Column(db.Integer, db.ForeignKey("representative.id"))
representative = db.relationship(
"RepresentativeModel", backref=db.backref("decisions", lazy="dynamic")
)
recommendation_id = db.Column(db.Integer, db.ForeignKey("recommendation.id"))
recommendation = db.relationship(
"RecommendationModel", backref=db.backref("decisions", lazy="dynamic")
)
value = db.Column(db.String(200))
def __repr__(self):
return self.value
class AdminView(View):
column_default_sort = "value"
column_filters = ["representative.name", "recommendation.name"]
admin.add_view(AdminView(DecisionModel, db.session, name="Decision", category="CRUD"))

25
app/model/entity.py

@ -1,7 +1,5 @@
# encoding: utf-8
from slugify import slugify
from app import admin, db
from app.model.model import Model, View
@ -9,18 +7,19 @@ from app.model.model import Model, View
class EntityModel(db.Model, Model):
__tablename__ = "entity"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200))
slug = db.Column(db.String(200))
code = db.Column(db.String(20))
picture = db.Column(db.String(2000))
parent_id = db.Column(db.Integer, db.ForeignKey("entity.id"))
children = db.relationship(
"EntityModel", backref=db.backref("parent", remote_side=id)
)
name = db.Column(db.String(500))
slug = db.Column(db.String(500))
reference = db.Column(db.String(200))
source = db.Column(db.String(200))
type_id = db.Column(db.Integer, db.ForeignKey("type.id"))
type = db.relationship("TypeModel")
start = db.Column(db.Date)
end = db.Column(db.Date)
country_id = db.Column(db.Integer, db.ForeignKey("country.id"))
country = db.relationship("CountryModel")
parent_id = db.Column(db.Integer, db.ForeignKey("entity.id"))
parent = db.relationship("EntityModel")
active = db.Column(db.Boolean)
def __repr__(self):
return self.name
@ -28,10 +27,6 @@ class EntityModel(db.Model, Model):
class AdminView(View):
column_default_sort = "name"
column_filters = ["name", "code", "type.name", "country.name"]
def on_model_change(self, form, model, is_created):
model.slug = slugify(model.name)
column_filters = ["name", "reference", "parent.name", "start", "end", "active"]
admin.add_view(AdminView(EntityModel, db.session, name="Entity", category="CRUD"))

30
app/model/matter.py

@ -1,30 +0,0 @@
# encoding: utf-8
from slugify import slugify
from app import admin, db
from app.model.model import Model, View
class MatterModel(db.Model, Model):
__tablename__ = "matter"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200))
slug = db.Column(db.String(200), unique=True)
description = db.Column(db.Text)
active = db.Column(db.Boolean, default=False)
def __repr__(self):
return self.name
class AdminView(View):
column_default_sort = "name"
column_filters = ["name"]
form_columns = ["name", "description", "active"]
def on_model_change(self, form, model, is_created):
model.slug = slugify(model.name)
admin.add_view(AdminView(MatterModel, db.session, name="Matter", category="CRUD"))

26
app/model/membership.py

@ -11,28 +11,22 @@ class MembershipModel(db.Model, Model):
representative = db.relationship(
"RepresentativeModel", backref=db.backref("memberships", lazy="dynamic")
)
role_id = db.Column(db.Integer, db.ForeignKey("role.id"))
role = db.relationship(
"RoleModel", backref=db.backref("memberships", lazy="dynamic")
)
start = db.Column(db.Date)
end = db.Column(db.Date)
entity_id = db.Column(db.Integer, db.ForeignKey("entity.id"))
entity = db.relationship(
"EntityModel", backref=db.backref("memberships", lazy="dynamic")
)
@property
def timestamp(self):
if self.end is None:
return 9999999999 + self.start.timestamp()
else:
return self.end.timestamp()
reference = db.Column(db.String(200))
role_id = db.Column(db.Integer, db.ForeignKey("role.id"))
role = db.relationship("RoleModel")
start = db.Column(db.Date)
end = db.Column(db.Date)
active = db.Column(db.Boolean)
class AdminView(View):
column_default_sort = [("representative.name", False), ("entity.name", False)]
column_filters = ["representative.name", "entity.name", "role.name"]
column_filters = ["entity.name", "entity.type.name", "role.name", "start", "end", "active"]
admin.add_view(AdminView(MembershipModel, db.session, name="Membership", category="CRUD"))
admin.add_view(
AdminView(MembershipModel, db.session, name="Membership", category="CRUD")
)

4
app/model/model.py

@ -1,6 +1,6 @@
# encoding: utf-8
from datetime import datetime
from datetime import datetime, date
from flask import redirect, request, url_for
from flask_admin.contrib.sqla import ModelView
@ -51,7 +51,7 @@ class Model:
result_dict = {}
for key in self.__table__.columns.keys():
if not key.startswith("_"):
if isinstance(getattr(self, key), datetime):
if isinstance(getattr(self, key), (datetime, date)):
result_dict[key] = getattr(self, key).strftime("%Y-%m-%d")
else:
result_dict[key] = getattr(self, key)

43
app/model/recommendation.py

@ -1,43 +0,0 @@
# encoding: utf-8
from slugify import slugify
from app import admin, db
from app.model.model import Model, View
class RecommendationModel(db.Model, Model):
__tablename__ = "recommendation"
id = db.Column(db.Integer, primary_key=True)
matter_id = db.Column(db.Integer, db.ForeignKey("matter.id"))
matter = db.relationship(
"MatterModel", backref=db.backref("recommendations", lazy="dynamic")
)
entity_id = db.Column(db.Integer, db.ForeignKey("entity.id"))
entity = db.relationship(
"EntityModel", backref=db.backref("recommendations", lazy="dynamic")
)
name = db.Column(db.String(200))
slug = db.Column(db.String(200))
code = db.Column(db.String(20))
date = db.Column(db.Date)
description = db.Column(db.Text)
value = db.Column(db.String(200))
weight = db.Column(db.Integer, default=1)
def __repr__(self):
return f"{self.name} - {self.value} ({self.weight})"
class AdminView(View):
column_default_sort = "name"
column_filters = ["name", "matter.name"]
form_columns = ["matter", "entity", "name", "code", "date", "description", "value", "weight"]
def on_model_change(self, form, model, is_created):
model.slug = slugify(model.name)
admin.add_view(
AdminView(RecommendationModel, db.session, name="Recommendation", category="CRUD")
)

75
app/model/representative.py

@ -2,75 +2,36 @@
from app import admin, db
from app.model.model import Model, View
from app.model.country import CountryModel
class RepresentativeModel(db.Model, Model):
__tablename__ = "representative"
id = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(20), unique=True)
name = db.Column(db.String(200))
slug = db.Column(db.String(200))
active = db.Column(db.Boolean, default=False)
picture = db.Column(db.String(2000))
first_name = db.Column(db.String(200))
last_name = db.Column(db.String(200))
birth_date = db.Column(db.Date)
birth_place = db.Column(db.String(200))
birth_region = db.Column(db.String(200))
birth_country_id = db.Column(db.Integer, db.ForeignKey("country.id"))
birth_country = db.relationship(
"CountryModel", foreign_keys="RepresentativeModel.birth_country_id"
)