Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
Mindiell | 8a48b73eae | |
Mindiell | 77d0b98641 | |
Mindiell | 6c6f2d11e8 | |
Mindiell | 6440bab46b | |
Mindiell | 1f19252dcc | |
Mindiell | d33757e754 | |
Mindiell | 3faa1689e7 |
|
@ -0,0 +1,8 @@
|
|||
FLASK_APP=server.py
|
||||
FLASK_ENV=development
|
||||
BABEL_DEFAULT_LOCALE=fr
|
||||
|
||||
BCRYPT_ROUNDS=6
|
||||
SECRET_KEY=blabla
|
||||
SQLALCHEMY_DATABASE_URI=mysql://politikorama:politikorama@localhost/politikorama
|
||||
API_PER_PAGE=30
|
|
@ -12,4 +12,4 @@ api = Api()
|
|||
babel = Babel()
|
||||
db = SQLAlchemy()
|
||||
login_manager = LoginManager()
|
||||
migrate = Migrate()
|
||||
migrate = Migrate(compare_type=True)
|
||||
|
|
|
@ -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"),
|
||||
)
|
||||
|
|
|
@ -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")
|
|
@ -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")
|
|
@ -11,18 +11,7 @@ from slugify import slugify
|
|||
from sqlalchemy import or_
|
||||
|
||||
from app.form.admin import ImportForm
|
||||
from app.model.address import AddressModel
|
||||
from app.model.contact import ContactModel
|
||||
from app.model.country import CountryModel
|
||||
from app.model.decision import DecisionModel
|
||||
from app.model.entity import EntityModel
|
||||
from app.model.matter import MatterModel
|
||||
from app.model.membership import MembershipModel
|
||||
from app.model.recommendation import RecommendationModel
|
||||
from app.model.representative import RepresentativeModel
|
||||
from app.model.role import RoleModel
|
||||
from app.model.stance import StanceModel
|
||||
from app.model.type import TypeModel
|
||||
from app import model
|
||||
|
||||
|
||||
def default_import(headers):
|
||||
|
@ -91,14 +80,14 @@ class ImportAddressView(BaseView):
|
|||
}
|
||||
if len(g.errors) == 0 and reader is not None:
|
||||
for row in reader:
|
||||
address_country = CountryModel.query.filter_by(
|
||||
address_country = model.CountryModel.query.filter_by(
|
||||
code=row[headers["country_code"]].upper()
|
||||
).first()
|
||||
address = AddressModel.query.filter_by(
|
||||
address = model.AddressModel.query.filter_by(
|
||||
slug==slugify(row[headers["name"]]),
|
||||
).first()
|
||||
if address is None:
|
||||
address = AddressModel(
|
||||
address = model.AddressModel(
|
||||
name = row[headers["name"]],
|
||||
slug = slugify(row[headers["name"]]),
|
||||
country = address_country,
|
||||
|
@ -195,21 +184,21 @@ class ImportContactView(BaseView):
|
|||
}
|
||||
if len(g.errors) == 0 and reader is not None:
|
||||
for row in reader:
|
||||
contact_representative = RepresentativeModel.query.filter_by(
|
||||
contact_representative = model.RepresentativeModel.query.filter_by(
|
||||
slug=row[headers["representative_slug"]],
|
||||
).first()
|
||||
if headers["addres_slug"] is not None:
|
||||
contact_address = AddressModel.query.filter_by(
|
||||
contact_address = model.AddressModel.query.filter_by(
|
||||
slug==row[headers["address_slug"]],
|
||||
).first()
|
||||
else:
|
||||
contact_address = None
|
||||
contact = ContactModel.query.filter_by(
|
||||
contact = model.ContactModel.query.filter_by(
|
||||
slug==slugify(row[headers["name"]]),
|
||||
representative_id=contact_representative.id,
|
||||
).first()
|
||||
if contact is None:
|
||||
contact = ContactModel(
|
||||
contact = model.ContactModel(
|
||||
representative = contact_representative,
|
||||
address = contact_address,
|
||||
name = row[headers["name"]],
|
||||
|
@ -233,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 = CountryModel.query.filter_by(code=row[headers["code"]]).first()
|
||||
if country is None:
|
||||
country = 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):
|
||||
|
@ -311,18 +254,18 @@ class ImportDecisionView(BaseView):
|
|||
}
|
||||
if len(g.errors) == 0 and reader is not None:
|
||||
for row in reader:
|
||||
decision_representative = RepresentativeModel.query.filter_by(
|
||||
decision_representative = model.RepresentativeModel.query.filter_by(
|
||||
slug=row[headers["representative_slug"]],
|
||||
).first()
|
||||
decision_recommendation = RecommendationModel.query.filter_by(
|
||||
decision_recommendation = model.RecommendationModel.query.filter_by(
|
||||
slug=row[headers["recommendation_slug"]],
|
||||
).first()
|
||||
decision = DecisionModel.query.filter_by(
|
||||
decision = model.DecisionModel.query.filter_by(
|
||||
representative=decision_representative,
|
||||
recommendation=decision_recommendation,
|
||||
).first()
|
||||
if decision is None:
|
||||
decision = DecisionModel(
|
||||
decision = model.DecisionModel(
|
||||
representative = decision_representative,
|
||||
recommendation = decision_recommendation,
|
||||
value = value,
|
||||
|
@ -378,13 +321,13 @@ class ImportEntityView(BaseView):
|
|||
}
|
||||
if len(g.errors) == 0 and reader is not None:
|
||||
for row in reader:
|
||||
entity_type = TypeModel.query.filter_by(
|
||||
entity_type = model.TypeModel.query.filter_by(
|
||||
code=row[headers["type_code"]]
|
||||
).first()
|
||||
entity_country = CountryModel.query.filter_by(
|
||||
entity_country = model.CountryModel.query.filter_by(
|
||||
code=row[headers["country_code"]].upper()
|
||||
).first()
|
||||
entity = EntityModel.query.filter_by(
|
||||
entity = model.EntityModel.query.filter_by(
|
||||
code=row[headers["code"]]
|
||||
).first()
|
||||
if row[headers["start"]] != "":
|
||||
|
@ -400,7 +343,7 @@ class ImportEntityView(BaseView):
|
|||
else:
|
||||
picture = None
|
||||
if entity is None:
|
||||
entity = EntityModel(
|
||||
entity = model.EntityModel(
|
||||
type = entity_type,
|
||||
country = entity_country,
|
||||
name = row[headers["name"]],
|
||||
|
@ -470,7 +413,7 @@ class ImportMatterView(BaseView):
|
|||
}
|
||||
if len(g.errors) == 0 and reader is not None:
|
||||
for row in reader:
|
||||
matter = MatterModel.query.filter_by(
|
||||
matter = model.MatterModel.query.filter_by(
|
||||
slug=slugify(row[headers["name"]]),
|
||||
).first()
|
||||
if headers["description"] is not None:
|
||||
|
@ -478,7 +421,7 @@ class ImportMatterView(BaseView):
|
|||
else:
|
||||
description = None
|
||||
if matter is None:
|
||||
matter = DecisionModel(
|
||||
matter = model.DecisionModel(
|
||||
name = row[headers["name"]],
|
||||
slug = slugify(row[headers["name"]]),
|
||||
description = description,
|
||||
|
@ -530,13 +473,13 @@ class ImportMembershipView(BaseView):
|
|||
}
|
||||
if len(g.errors) == 0 and reader is not None:
|
||||
for row in reader:
|
||||
representative = RepresentativeModel.query.filter_by(
|
||||
representative = model.RepresentativeModel.query.filter_by(
|
||||
slug=slugify(row[headers["representative_slug"]]),
|
||||
).first()
|
||||
entity = EntityModel.query.filter_by(
|
||||
entity = model.EntityModel.query.filter_by(
|
||||
code=row[headers["entity_code"]],
|
||||
).first()
|
||||
role = RoleModel.query.filter_by(
|
||||
role = model.RoleModel.query.filter_by(
|
||||
code=row[headers["role_code"]],
|
||||
).first()
|
||||
if row[headers["start"]] != "":
|
||||
|
@ -547,14 +490,14 @@ class ImportMembershipView(BaseView):
|
|||
end_date = datetime.strptime(row[headers["end"]], "%Y-%m-%d")
|
||||
else:
|
||||
end_date = None
|
||||
membership = MembershipModel.query.filter_by(
|
||||
membership = model.MembershipModel.query.filter_by(
|
||||
representative=representative,
|
||||
entity=entity,
|
||||
role=role,
|
||||
start=start_date,
|
||||
).first()
|
||||
if membership is None:
|
||||
membership = MembershipModel(
|
||||
membership = model.MembershipModel(
|
||||
representative = representative,
|
||||
entity = entity,
|
||||
role = role,
|
||||
|
@ -614,10 +557,10 @@ class ImportRecommendationView(BaseView):
|
|||
}
|
||||
if len(g.errors) == 0 and reader is not None:
|
||||
for row in reader:
|
||||
matter = MatterModel.query.filter_by(
|
||||
matter = model.MatterModel.query.filter_by(
|
||||
slug=row[headers["matter_slug"]],
|
||||
).first()
|
||||
entity = EntityModel.query.filter_by(
|
||||
entity = model.EntityModel.query.filter_by(
|
||||
code=row[headers["entity_code"]],
|
||||
).first()
|
||||
if row[headers["date"]] != "":
|
||||
|
@ -632,13 +575,13 @@ class ImportRecommendationView(BaseView):
|
|||
weight = int(row[headers["weight"]])
|
||||
else:
|
||||
weight = 1
|
||||
recommendation = RecommendationModel.query.filter_by(
|
||||
recommendation = model.RecommendationModel.query.filter_by(
|
||||
matter=matter,
|
||||
entity=entity,
|
||||
code=row[headers["code"]],
|
||||
).first()
|
||||
if recommendation is None:
|
||||
recommendation = RecommendationModel(
|
||||
recommendation = model.RecommendationModel(
|
||||
matter = matter,
|
||||
entity = entity,
|
||||
name = row[headers["name"]],
|
||||
|
@ -676,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 = RepresentativeModel.query.filter_by(
|
||||
code=row[headers["code"]],
|
||||
).first()
|
||||
country = 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 = 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):
|
||||
|
@ -800,9 +647,9 @@ class ImportRoleView(BaseView):
|
|||
if len(g.errors) == 0 and reader is not None:
|
||||
# Values
|
||||
for row in reader:
|
||||
role = RoleModel.query.filter_by(code=row[headers["code"]]).first()
|
||||
role = model.RoleModel.query.filter_by(code=row[headers["code"]]).first()
|
||||
if role is None:
|
||||
role = RoleModel(
|
||||
role = model.RoleModel(
|
||||
name = row[headers["name"]],
|
||||
slug = slugify(row[headers["name"]]),
|
||||
code = row[headers["code"]],
|
||||
|
@ -856,21 +703,21 @@ class ImportStanceView(BaseView):
|
|||
# Values
|
||||
for row in reader:
|
||||
# Representative
|
||||
representative = RepresentativeModel.query.filter_by(
|
||||
representative = model.RepresentativeModel.query.filter_by(
|
||||
slug=row[headers["slug"]],
|
||||
).first()
|
||||
if representative is None:
|
||||
representative = RepresentativeModel(
|
||||
representative = model.RepresentativeModel(
|
||||
name = row[headers["name"]],
|
||||
slug = row[headers["slug"]],
|
||||
)
|
||||
representative.save()
|
||||
# Matter
|
||||
matter = MatterModel.query.filter_by(
|
||||
matter = model.MatterModel.query.filter_by(
|
||||
slug=slugify(row[headers["matter"]]),
|
||||
).first()
|
||||
if matter is None:
|
||||
matter = MatterModel(
|
||||
matter = model.MatterModel(
|
||||
name = row[headers["matter"]],
|
||||
slug = slugify(row[headers["matter"]]),
|
||||
)
|
||||
|
@ -880,7 +727,7 @@ class ImportStanceView(BaseView):
|
|||
else:
|
||||
stance_date = None
|
||||
# Stance
|
||||
stance = StanceModel.query.filter_by(
|
||||
stance = model.StanceModel.query.filter_by(
|
||||
representative=representative,
|
||||
matter=matter,
|
||||
subject=row[headers["subject"]],
|
||||
|
@ -888,7 +735,7 @@ class ImportStanceView(BaseView):
|
|||
source_url=row[headers["source_url"]],
|
||||
).first()
|
||||
if stance is None:
|
||||
stance = StanceModel(
|
||||
stance = model.StanceModel(
|
||||
representative = representative,
|
||||
matter = matter,
|
||||
subject = row[headers["subject"]],
|
||||
|
@ -947,9 +794,9 @@ class ImportTypeView(BaseView):
|
|||
if len(g.errors) == 0 and reader is not None:
|
||||
# Values
|
||||
for row in reader:
|
||||
type_ = TypeModel.query.filter_by(code=row[headers["code"]]).first()
|
||||
type_ = model.TypeModel.query.filter_by(code=row[headers["code"]]).first()
|
||||
if type_ is None:
|
||||
type_ = TypeModel(
|
||||
type_ = model.TypeModel(
|
||||
name = row[headers["name"]],
|
||||
slug = slugify(row[headers["name"]]),
|
||||
code = row[headers["code"]],
|
||||
|
|
|
@ -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")
|
|
@ -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")
|
|
@ -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()
|
|
@ -10,20 +10,61 @@ 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)
|
||||
return [
|
||||
representative.serialize()
|
||||
{
|
||||
"first_name": representative.first_name,
|
||||
"last_name": representative.last_name,
|
||||
"full_name": representative.full_name,
|
||||
"picture": representative.picture,
|
||||
"active": True,
|
||||
"memberships": [
|
||||
{
|
||||
"reference": membership.reference,
|
||||
"source": membership.entity.source,
|
||||
"start_date": membership.start.strftime("%Y-%m-%d"),
|
||||
"end_date": membership.end.strftime("%Y-%m-%d") if membership.end is not None else None,
|
||||
"entity": {
|
||||
"reference": membership.entity.reference,
|
||||
"type": {
|
||||
"code": membership.entity.type.code,
|
||||
"name": membership.entity.type.name,
|
||||
},
|
||||
"name": membership.entity.name,
|
||||
},
|
||||
"role": {
|
||||
"code": membership.role.code,
|
||||
"name": membership.role.name,
|
||||
},
|
||||
}
|
||||
for membership
|
||||
in representative.memberships
|
||||
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"reference": reference.reference,
|
||||
"source": reference.source.name,
|
||||
}
|
||||
for reference
|
||||
in representative.references
|
||||
],
|
||||
}
|
||||
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 +73,5 @@ class RepresentativeApi(Resource):
|
|||
representative = RepresentativeModel.query.get(representative_id)
|
||||
if representative is None:
|
||||
return None, 404
|
||||
print(representative.serialize())
|
||||
return representative.serialize()
|
||||
|
|
|
@ -5,41 +5,16 @@ import random
|
|||
|
||||
from flask import g, render_template
|
||||
|
||||
from app import model
|
||||
from app.controller.controller import Controller
|
||||
from app.model.decision import DecisionModel
|
||||
from app.model.matter import MatterModel
|
||||
from app.model.recommendation import RecommendationModel
|
||||
from app.model.representative import RepresentativeModel
|
||||
from app.model.stance import StanceModel
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy.sql.expression import func
|
||||
|
||||
|
||||
class Core(Controller):
|
||||
def home(self):
|
||||
random.seed(int(datetime.today().timestamp()/100))
|
||||
try:
|
||||
g.motd = random.choice(MatterModel.query.filter_by(
|
||||
active=True
|
||||
).all())
|
||||
except:
|
||||
g.motd = None
|
||||
g.rotd = random.choice(RepresentativeModel.query.filter_by(
|
||||
active=True
|
||||
).all())
|
||||
g.last_decisions = DecisionModel.query.join(DecisionModel.recommendation).order_by(RecommendationModel.date.desc()).limit(10).all()
|
||||
g.last_stances = StanceModel.query.order_by(StanceModel.date.desc()).limit(10).all()
|
||||
return render_template("core/home.html")
|
||||
|
||||
def representative(self, representative_id=None):
|
||||
if representative_id is None:
|
||||
representative_id = random.choice(RepresentativeModel.query.filter_by(
|
||||
active=True
|
||||
).all()).id
|
||||
g.representative = RepresentativeModel.query.get(representative_id)
|
||||
g.title = g.representative.name
|
||||
return render_template("core/representative.html")
|
||||
|
||||
def about(self):
|
||||
return render_template("core/about.html")
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# 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
|
||||
|
||||
|
||||
class Representative(Controller):
|
||||
def view(self, representative_id=None):
|
||||
if representative_id is None:
|
||||
g.representative = random.choice(
|
||||
model.RepresentativeModel.query.filter_by(active=True).all()
|
||||
)
|
||||
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")
|
|
@ -3,16 +3,12 @@
|
|||
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
|
||||
|
|
|
@ -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(2000))
|
||||
slug = db.Column(db.String(2000))
|
||||
country_id = db.Column(db.Integer, db.ForeignKey("country.id"))
|
||||
country = db.relationship("CountryModel")
|
||||
number = db.Column(db.String(2000))
|
||||
street = db.Column(db.String(2000))
|
||||
miscellaneous = db.Column(db.String(2000))
|
||||
city = db.Column(db.String(2000))
|
||||
zipcode = db.Column(db.String(2000))
|
||||
building = db.Column(db.String(2000))
|
||||
floor = db.Column(db.String(2000))
|
||||
stair = db.Column(db.String(2000))
|
||||
office = db.Column(db.String(2000))
|
||||
latitude = db.Column(db.String(2000))
|
||||
longitude = db.Column(db.String(2000))
|
||||
|
||||
|
||||
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"))
|
|
@ -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(2000))
|
||||
slug = db.Column(db.String(2000))
|
||||
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"))
|
|
@ -7,27 +7,14 @@ from app.model.model import Model, View
|
|||
class CountryModel(db.Model, Model):
|
||||
__tablename__ = "country"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(2000))
|
||||
slug = db.Column(db.String(2000))
|
||||
code = db.Column(db.String(2000))
|
||||
|
||||
@property
|
||||
def flag(self):
|
||||
"""
|
||||
HTML unicode sequence for display country flag.
|
||||
"""
|
||||
return "".join([f"&#{hex(127397+ord(l))[1:]};" for l in self.code])
|
||||
name = db.Column(db.String(200))
|
||||
slug = db.Column(db.String(200))
|
||||
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"))
|
||||
|
|
|
@ -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(2000))
|
||||
|
||||
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"))
|
|
@ -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(2000))
|
||||
slug = db.Column(db.String(2000))
|
||||
code = db.Column(db.String(2000))
|
||||
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.DateTime)
|
||||
end = db.Column(db.DateTime)
|
||||
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")
|
||||
start = db.Column(db.Date)
|
||||
end = db.Column(db.Date)
|
||||
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"))
|
||||
|
|
|
@ -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(2000))
|
||||
slug = db.Column(db.String(2000), 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"))
|
|
@ -11,28 +11,25 @@ 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.DateTime)
|
||||
end = db.Column(db.DateTime)
|
||||
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", "representative.full_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")
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
@ -11,14 +11,14 @@ from app import db
|
|||
|
||||
class View(ModelView):
|
||||
def is_accessible(self):
|
||||
# TODO: develop mode
|
||||
# TODO: develop mode, refer to current_app.config.debug
|
||||
return True
|
||||
if not current_user.is_authenticated:
|
||||
return False
|
||||
return current_user.is_authenticated and current_user.admin
|
||||
|
||||
def inaccessible_callback(self, name, **kwargs):
|
||||
# TODO: develop mode
|
||||
# TODO: develop mode, refer to current_app.config.debug
|
||||
return redirect(url_for("core.login"))
|
||||
return redirect(url_for("admin.login", next=request.url))
|
||||
|
||||
|
@ -51,8 +51,8 @@ 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)
|
||||
return result_dict
|
||||
return result_dict
|
||||
|
|
|
@ -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(2000))
|
||||
slug = db.Column(db.String(2000), unique=True)
|
||||
code = db.Column(db.String(2000))
|
||||
date = db.Column(db.Date)
|
||||
description = db.Column(db.Text)
|
||||
value = db.Column(db.String(2000))
|
||||
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")
|
||||
)
|
|
@ -2,75 +2,42 @@
|
|||
|
||||
from app import admin, db
|
||||
from app.model.model import Model, View
|
||||
from app.model.country import CountryModel
|
||||
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
|
||||
|
||||
class RepresentativeModel(db.Model, Model):
|
||||
__tablename__ = "representative"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(2000), unique=True)
|
||||
name = db.Column(db.String(2000))
|
||||
slug = db.Column(db.String(2000))
|
||||
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"
|
||||
)
|
||||
job = db.Column(db.String(200))
|
||||
nationality_id = db.Column(db.Integer, db.ForeignKey("country.id"))
|
||||
nationality = db.relationship(
|
||||
"CountryModel", foreign_keys=[nationality_id], backref=db.backref("representatives", lazy="dynamic")
|
||||
"CountryModel", foreign_keys="RepresentativeModel.nationality_id"
|
||||
)
|
||||
sex = db.Column(db.String(1))
|
||||
birth_date = db.Column(db.Date)
|
||||
birth_place = db.Column(db.String(2000))
|
||||
job = db.Column(db.String(2000))
|
||||
picture = db.Column(db.String(200))
|
||||
|
||||
@property
|
||||
def parpol(self):
|
||||
"""
|
||||
A representative is maybe part of a political party.
|
||||
"""
|
||||
# Active one first
|
||||
for membership in [membership for membership in self.memberships if membership.end is None]:
|
||||
if membership.entity.type.code == "PARPOL":
|
||||
return membership.entity.name
|
||||
# Else old one
|
||||
for membership in sorted(self.memberships, key=lambda x: x.start, reverse=True):
|
||||
if membership.entity.type.code == "PARPOL":
|
||||
return membership.entity.name
|
||||
|
||||
@property
|
||||
def is_female(self):
|
||||
return self.sex == "F"
|
||||
|
||||
@property
|
||||
def is_active(self):
|
||||
"""
|
||||
A representative is active if she has at least one membership not ended.
|
||||
"""
|
||||
for membership in self.memberships:
|
||||
if membership.end is None:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def score(self):
|
||||
total = 0
|
||||
for decision in self.decisions:
|
||||
if decision.value == decision.recommendation.value:
|
||||
total += decision.recommendation.weight
|
||||
else:
|
||||
total -= decision.recommendation.weight
|
||||
return total
|
||||
@hybrid_property
|
||||
def full_name(self):
|
||||
return self.first_name + " " + self.last_name
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
return f"{self.first_name.capitalize()} {self.last_name.upper()}"
|
||||
|
||||
|
||||
class AdminView(View):
|
||||
column_default_sort = "name"
|
||||
column_exclude_list = ["picture"]
|
||||
column_filters = ["name", "nationality.name"]
|
||||
|
||||
def on_model_change(self, form, model, is_created):
|
||||
model.slug = slugify(model.name)
|
||||
|
||||
column_default_sort = "last_name"
|
||||
column_exclude_list = [
|
||||
"birth_region", "birth_country", "picture",
|
||||
]
|
||||
column_filters = ["last_name", "first_name", "nationality.name", ]
|
||||
|
||||
admin.add_view(AdminView(RepresentativeModel, db.session, name="Representative", category="CRUD"))
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# encoding: utf-8
|
||||
|
||||
from app import admin, db
|
||||
from app.model.model import Model, View
|
||||
|
||||
|
||||
class RepresentativeOriginModel(db.Model, Model):
|
||||
__tablename__ = "representative_origin"
|
||||
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("references", lazy="dynamic")
|
||||
)
|
||||
source_id = db.Column(db.Integer, db.ForeignKey("source.id"))
|
||||
source = db.relationship("SourceModel")
|
||||
reference = db.Column(db.String(200))
|
||||
|
||||
|
||||
admin.add_view(View(
|
||||
RepresentativeOriginModel, db.session, name="RepresentativeOrigin", category="CRUD"
|
||||
))
|
|
@ -7,20 +7,12 @@ from app.model.model import Model, View
|
|||
class RoleModel(db.Model, Model):
|
||||
__tablename__ = "role"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(2000))
|
||||
slug = db.Column(db.String(2000))
|
||||
code = db.Column(db.String(2000))
|
||||
code = db.Column(db.String(200))
|
||||
name = db.Column(db.String(200))
|
||||
slug = db.Column(db.String(200))
|
||||
|
||||
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(RoleModel, db.session, name="Role", category="CRUD"))
|
||||
admin.add_view(View(RoleModel, db.session, name="Role", category="CRUD"))
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# encoding: utf-8
|
||||
|
||||
from app import admin, db
|
||||
from app.model.model import Model, View
|
||||
|
||||
|
||||
class SourceModel(db.Model, Model):
|
||||
__tablename__ = "source"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(200))
|
||||
slug = db.Column(db.String(200))
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
admin.add_view(View(SourceModel, db.session, name="Source", category="CRUD"))
|
|
@ -1,44 +0,0 @@
|
|||
# encoding: utf-8
|
||||
|
||||
from app import admin, db
|
||||
from app.model.model import Model, View
|
||||
from app.model.matter import MatterModel
|
||||
from app.model.representative import RepresentativeModel
|
||||
|
||||
|
||||
class StanceModel(db.Model, Model):
|
||||
__tablename__ = "stance"
|
||||
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("stances", lazy="dynamic")
|
||||
)
|
||||
matter_id = db.Column(db.Integer, db.ForeignKey("matter.id"), nullable=True)
|
||||
matter = db.relationship(
|
||||
"MatterModel", backref=db.backref("stances", lazy="dynamic")
|
||||
)
|
||||
date = db.Column(db.Date)
|
||||
subject = db.Column(db.String(2000))
|
||||
extract = db.Column(db.Text)
|
||||
source_url = db.Column(db.String(2000))
|
||||
active = db.Column(db.Boolean, default=False)
|
||||
|
||||
def __repr__(self):
|
||||
return self.representative.name + " : " + self.extract[:50]
|
||||
|
||||
@property
|
||||
def extract_html(self):
|
||||
return "<p>" + self.extract.replace("\n", "</p><p>") + "</p>"
|
||||
|
||||
@property
|
||||
def extract_chapo(self):
|
||||
return " ".join((self.extract + " ")[:60].split(" ")[:-1])
|
||||
|
||||
|
||||
class AdminView(View):
|
||||
column_default_sort = ("date", False)
|
||||
column_exclude_list = ["extract"]
|
||||
column_filters = ["representative.name", "subject", "date"]
|
||||
|
||||
|
||||
admin.add_view(AdminView(StanceModel, db.session, name="Stance", category="CRUD"))
|
|
@ -9,17 +9,16 @@ from app.model.model import Model, View
|
|||
class TypeModel(db.Model, Model):
|
||||
__tablename__ = "type"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(2000))
|
||||
slug = db.Column(db.String(2000))
|
||||
code = db.Column(db.String(2000))
|
||||
code = db.Column(db.String(200))
|
||||
name = db.Column(db.String(500))
|
||||
slug = db.Column(db.String(500))
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class AdminView(View):
|
||||
column_default_sort = "name"
|
||||
column_filters = ["name", "code"]
|
||||
form_excluded_columns = ["slug"]
|
||||
|
||||
def on_model_change(self, form, model, is_created):
|
||||
model.slug = slugify(model.name)
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# encoding: utf-8
|
||||
|
||||
import bcrypt
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from app import admin, db
|
||||
from app.model.model import Model, View
|
||||
|
||||
|
||||
def get_user(user_id):
|
||||
return UserModel.query.get(user_id)
|
||||
|
||||
|
||||
class UserModel(db.Model, Model):
|
||||
__tablename__ = "user"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
login = db.Column(db.String(500), unique=True)
|
||||
password_hash = db.Column(db.String(128))
|
||||
email = db.Column(db.String(500), unique=True)
|
||||
active = db.Column(db.Boolean)
|
||||
admin = db.Column(db.Boolean)
|
||||
|
||||
@property
|
||||
def password(self):
|
||||
return self.password_hash
|
||||
|
||||
@password.setter
|
||||
def password(self, password):
|
||||
self.password_hash = bcrypt.hashpw(
|
||||
password.encode("utf-8"),
|
||||
bcrypt.gensalt(rounds=current_app.config["BCRYPT_ROUNDS"]),
|
||||
)
|
||||
|
||||
def check_password(self, password):
|
||||
return bcrypt.checkpw(password.encode("utf-8"), self.password_hash)
|
||||
|
||||
@property
|
||||
def is_active(self):
|
||||
return self.active or False
|
||||
|
||||
@property
|
||||
def is_anonymous(self):
|
||||
return self.id is None
|
||||
|
||||
@property
|
||||
def is_authenticated(self):
|
||||
return self.id is not None
|
||||
|
||||
def get_id(self):
|
||||
return str(self.id)
|
||||
|
||||
|
||||
class AdminView(View):
|
||||
column_default_sort = "login"
|
||||
column_exclude_list = ["password_hash", ]
|
||||
|
||||
def on_model_change(self, form, model, is_created):
|
||||
if len(form.password_hash.data) < 128:
|
||||
model.password = form.password_hash.data
|
||||
|
||||
|
||||
admin.add_view(AdminView(UserModel, db.session, name="User"))
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
from app import admin
|
||||
from app.controller.admin import admin_routes
|
||||
from app.controller.api.country import CountriesApi, CountryApi
|
||||
from app.controller.api.representative import RepresentativesApi, RepresentativeApi
|
||||
from app.controller.core import Core
|
||||
from app.controller.representative import Representative
|
||||
|
||||
|
||||
# Adding admin endpoints
|
||||
|
@ -14,15 +14,13 @@ for route in admin_routes:
|
|||
# Listing normal endpoints
|
||||
routes = [
|
||||
("/", Core.as_view("home")),
|
||||
("/representative/<int:representative_id>", Core.as_view("representative")),
|
||||
("/about", Core.as_view("about")),
|
||||
("/who", Core.as_view("who")),
|
||||
("/representative/<int:representative_id>", Representative.as_view("view")),
|
||||
]
|
||||
|
||||
# Listing API endpoints
|
||||
apis = [
|
||||
('/api/country', CountriesApi),
|
||||
('/api/country/<country_id>', CountryApi),
|
||||
('/api/representative', RepresentativesApi),
|
||||
('/api/representative/<representative_id>', RepresentativeApi),
|
||||
]
|
||||
|
|
|
@ -9,4 +9,4 @@
|
|||
</ul>
|
||||
{%endif%}
|
||||
</div>
|
||||
{%endmacro%}
|
||||
{%endmacro%}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
<li>Find a representative</li>
|
||||
<li>Find a matter</li>
|
||||
-->
|
||||
<li><a href="">{{_("Ajouter une prise de position")}}</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
@ -19,4 +18,4 @@
|
|||
</div>
|
||||
-->
|
||||
<hr />
|
||||
</header>
|
||||
</header>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
|
||||
<h1>{{_("Ajouter une prise de position")}}</h1>
|
||||
|
||||
<form method="POST" action="{{url_for('stance.add')}}">
|
||||
{{g.form.hidden_tag()}}
|
||||
{{g.form.representative()}}
|
||||
{{g.form.matter()}}
|
||||
|
||||
<div class="field">
|
||||
<label>{{_("Représentant :")}}</label> <input type="text" />
|
||||
<span class="field-description">{{_("Le représentant ayant pris cette position")}}</span>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>{{_("Dossier :")}}</label> <input type="text" />
|
||||
<span class="field-description">{{_("Le dossier lié à cette prise de position. Ce champ reste optionnel.")}}</span>
|
||||
</div>
|
||||
|
||||
{{render_field(g.form.date)}}
|
||||
{{render_field(g.form.source_url)}}
|
||||
{{render_field(g.form.extract)}}
|
||||
<input type="submit" value="{{_('Ajouter')}}" class="btn" />
|
||||
<a href="{{url_for('core.home')}}" class="btn">{{_("Annuler")}}</a>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
37
config.py
37
config.py
|
@ -1,37 +0,0 @@
|
|||
# encoding: utf-8
|
||||
"""
|
||||
Minimal configuration able to run but maybe not as you want it.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
DEBUG = False
|
||||
HOST = "0.0.0.0"
|
||||
PORT = 5000
|
||||
SECRET_KEY = "No secret key"
|
||||
|
||||
JINJA_ENV = {
|
||||
"TRIM_BLOCKS": True,
|
||||
"LSTRIP_BLOCKS": True,
|
||||
}
|
||||
|
||||
# defining base directory
|
||||
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
# defining database URI
|
||||
# MySQL example
|
||||
# SQLALCHEMY_DATABASE_URI = "mysql://username:password@server/db"
|
||||
# SQLite example
|
||||
# SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(BASE_DIR, "db.sqlite3")
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
|
||||
# defining Babel settings
|
||||
BABEL_DEFAULT_LOCALE = "fr"
|
||||
|
||||
# Languages available
|
||||
AVAILABLE_LANGUAGES = {
|
||||
"en": "English",
|
||||
"fr": "Français",
|
||||
}
|
||||
|
||||
API_PER_PAGE = 30
|
|
@ -1 +1 @@
|
|||
Generic single-database configuration.
|
||||
Single-database configuration for Flask.
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic
|
||||
keys = root,sqlalchemy,alembic,flask_migrate
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
@ -34,6 +34,11 @@ level = INFO
|
|||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[logger_flask_migrate]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = flask_migrate
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
|
|
|
@ -3,8 +3,6 @@ from __future__ import with_statement
|
|||
import logging
|
||||
from logging.config import fileConfig
|
||||
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy import pool
|
||||
from flask import current_app
|
||||
|
||||
from alembic import context
|
||||
|
@ -24,7 +22,8 @@ logger = logging.getLogger('alembic.env')
|
|||
# target_metadata = mymodel.Base.metadata
|
||||
config.set_main_option(
|
||||
'sqlalchemy.url',
|
||||
str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%'))
|
||||
str(current_app.extensions['migrate'].db.get_engine().url).replace(
|
||||
'%', '%%'))
|
||||
target_metadata = current_app.extensions['migrate'].db.metadata
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
|
@ -72,11 +71,7 @@ def run_migrations_online():
|
|||
directives[:] = []
|
||||
logger.info('No changes in schema detected.')
|
||||
|
||||
connectable = engine_from_config(
|
||||
config.get_section(config.config_ini_section),
|
||||
prefix='sqlalchemy.',
|
||||
poolclass=pool.NullPool,
|
||||
)
|
||||
connectable = current_app.extensions['migrate'].db.get_engine()
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 0df00d383cb1
|
||||
Revises: c968d84e9996
|
||||
Create Date: 2022-05-27 21:31:07.974570
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '0df00d383cb1'
|
||||
down_revision = 'c968d84e9996'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('country', sa.Column('slug', sa.String(length=200), nullable=True))
|
||||
op.add_column('entity', sa.Column('slug', sa.String(length=200), nullable=True))
|
||||
op.add_column('role', sa.Column('slug', sa.String(length=200), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('role', 'slug')
|
||||
op.drop_column('entity', 'slug')
|
||||
op.drop_column('country', 'slug')
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,44 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 49d256e40a4c
|
||||
Revises:
|
||||
Create Date: 2022-05-26 13:01:00.915135
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '49d256e40a4c'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('representative',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=200), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('user',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('login', sa.String(length=500), nullable=True),
|
||||
sa.Column('password_hash', sa.String(length=128), nullable=True),
|
||||
sa.Column('email', sa.String(length=500), nullable=True),
|
||||
sa.Column('active', sa.Boolean(), nullable=True),
|
||||
sa.Column('admin', sa.Boolean(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('email'),
|
||||
sa.UniqueConstraint('login')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('user')
|
||||
op.drop_table('representative')
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,43 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 6a205c6b23bb
|
||||
Revises: bc290d035406
|
||||
Create Date: 2022-05-27 11:12:44.242389
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '6a205c6b23bb'
|
||||
down_revision = 'bc290d035406'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('entity',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=200), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('membership',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('representative_id', sa.Integer(), nullable=True),
|
||||
sa.Column('entity_id', sa.Integer(), nullable=True),
|
||||
sa.Column('start', sa.Date(), nullable=True),
|
||||
sa.Column('end', sa.Date(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['entity_id'], ['entity.id'], ),
|
||||
sa.ForeignKeyConstraint(['representative_id'], ['representative.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('membership')
|
||||
op.drop_table('entity')
|
||||
# ### end Alembic commands ###
|
|
@ -1,8 +1,8 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: ac34a07322f6
|
||||
Revises: b83b29dc60b0
|
||||
Create Date: 2021-07-21 15:36:01.454538
|
||||
Revision ID: 6dcc965ab0d4
|
||||
Revises: f448ec882889
|
||||
Create Date: 2022-05-28 19:35:20.965988
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
|
@ -10,19 +10,19 @@ import sqlalchemy as sa
|
|||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'ac34a07322f6'
|
||||
down_revision = 'b83b29dc60b0'
|
||||
revision = '6dcc965ab0d4'
|
||||
down_revision = 'f448ec882889'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('representative', sa.Column('active', sa.Boolean(), nullable=True))
|
||||
op.add_column('membership', sa.Column('active', sa.Boolean(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('representative', 'active')
|
||||
op.drop_column('membership', 'active')
|
||||
# ### end Alembic commands ###
|
|
@ -1,28 +0,0 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 8b260b23ba3a
|
||||
Revises: e0001237a466
|
||||
Create Date: 2021-07-21 14:03:53.023739
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '8b260b23ba3a'
|
||||
down_revision = 'e0001237a466'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('representative', sa.Column('code', sa.String(length=2000), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('representative', 'code')
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,48 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: aa24a81be355
|
||||
Revises: 0df00d383cb1
|
||||
Create Date: 2022-05-28 15:52:36.923253
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'aa24a81be355'
|
||||
down_revision = '0df00d383cb1'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('type',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('code', sa.String(length=200), nullable=True),
|
||||
sa.Column('name', sa.String(length=200), nullable=True),
|
||||
sa.Column('slug', sa.String(length=200), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.add_column('entity', sa.Column('parent_id', sa.Integer(), nullable=True))
|
||||
op.add_column('entity', sa.Column('reference', sa.String(length=200), nullable=True))
|
||||
op.add_column('entity', sa.Column('source', sa.String(length=200), nullable=True))
|
||||
op.add_column('entity', sa.Column('type_id', sa.Integer(), nullable=True))
|
||||
op.create_foreign_key(None, 'entity', 'type', ['type_id'], ['id'])
|
||||
op.create_foreign_key(None, 'entity', 'entity', ['parent_id'], ['id'])
|
||||
op.drop_column('membership', 'source')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('membership', sa.Column('source', mysql.VARCHAR(length=200), nullable=True))
|
||||
op.drop_constraint(None, 'entity', type_='foreignkey')
|
||||
op.drop_constraint(None, 'entity', type_='foreignkey')
|
||||
op.drop_column('entity', 'type_id')
|
||||
op.drop_column('entity', 'source')
|
||||
op.drop_column('entity', 'reference')
|
||||
op.drop_column('entity', 'parent_id')
|
||||
op.drop_table('type')
|
||||
# ### end Alembic commands ###
|
|
@ -1,30 +0,0 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: b83b29dc60b0
|
||||
Revises: 8b260b23ba3a
|
||||
Create Date: 2021-07-21 14:04:54.107335
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'b83b29dc60b0'
|
||||
down_revision = '8b260b23ba3a'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint('representative_slug_key', 'representative', type_='unique')
|
||||
op.create_unique_constraint(None, 'representative', ['code'])
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, 'representative', type_='unique')
|
||||
op.create_unique_constraint('representative_slug_key', 'representative', ['slug'])
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,34 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: bc290d035406
|
||||
Revises: 49d256e40a4c
|
||||
Create Date: 2022-05-26 13:29:55.124869
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'bc290d035406'
|
||||
down_revision = '49d256e40a4c'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('representative', sa.Column('first_name', sa.String(length=200), nullable=True))
|
||||
op.add_column('representative', sa.Column('last_name', sa.String(length=200), nullable=True))
|
||||
op.add_column('representative', sa.Column('picture', sa.String(length=200), nullable=True))
|
||||
op.drop_column('representative', 'name')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('representative', sa.Column('name', mysql.VARCHAR(length=200), nullable=True))
|
||||
op.drop_column('representative', 'picture')
|
||||
op.drop_column('representative', 'last_name')
|
||||
op.drop_column('representative', 'first_name')
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,65 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: c968d84e9996
|
||||
Revises: 6a205c6b23bb
|
||||
Create Date: 2022-05-27 17:56:50.589477
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'c968d84e9996'
|
||||
down_revision = '6a205c6b23bb'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('country',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=200), nullable=True),
|
||||
sa.Column('official_state_name', sa.String(length=200), nullable=True),
|
||||
sa.Column('alpha_2', sa.String(length=2), nullable=True),
|
||||
sa.Column('alpha_3', sa.String(length=3), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('role',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=200), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.add_column('membership', sa.Column('source', sa.String(length=200), nullable=True))
|
||||
op.add_column('membership', sa.Column('reference', sa.String(length=200), nullable=True))
|
||||
op.add_column('membership', sa.Column('role_id', sa.Integer(), nullable=True))
|
||||
op.create_foreign_key(None, 'membership', 'role', ['role_id'], ['id'])
|
||||
op.add_column('representative', sa.Column('birth_date', sa.Date(), nullable=True))
|
||||
op.add_column('representative', sa.Column('birth_place', sa.String(length=200), nullable=True))
|
||||
op.add_column('representative', sa.Column('birth_region', sa.String(length=200), nullable=True))
|
||||
op.add_column('representative', sa.Column('birth_country_id', sa.Integer(), nullable=True))
|
||||
op.add_column('representative', sa.Column('job', sa.String(length=200), nullable=True))
|
||||
op.add_column('representative', sa.Column('nationality_id', sa.Integer(), nullable=True))
|
||||
op.create_foreign_key(None, 'representative', 'country', ['birth_country_id'], ['id'])
|
||||
op.create_foreign_key(None, 'representative', 'country', ['nationality_id'], ['id'])
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, 'representative', type_='foreignkey')
|
||||
op.drop_constraint(None, 'representative', type_='foreignkey')
|
||||
op.drop_column('representative', 'nationality_id')
|
||||
op.drop_column('representative', 'job')
|
||||
op.drop_column('representative', 'birth_country_id')
|
||||
op.drop_column('representative', 'birth_region')
|
||||
op.drop_column('representative', 'birth_place')
|
||||
op.drop_column('representative', 'birth_date')
|
||||
op.drop_constraint(None, 'membership', type_='foreignkey')
|
||||
op.drop_column('membership', 'role_id')
|
||||
op.drop_column('membership', 'reference')
|
||||
op.drop_column('membership', 'source')
|
||||
op.drop_table('role')
|
||||
op.drop_table('country')
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,32 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: cd76771172a8
|
||||
Revises: f238158c8ad6
|
||||
Create Date: 2022-05-28 17:21:55.500700
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'cd76771172a8'
|
||||
down_revision = 'f238158c8ad6'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('entity', sa.Column('start', sa.Date(), nullable=True))
|
||||
op.add_column('entity', sa.Column('end', sa.Date(), nullable=True))
|
||||
op.add_column('entity', sa.Column('active', sa.Boolean(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('entity', 'active')
|
||||
op.drop_column('entity', 'end')
|
||||
op.drop_column('entity', 'start')
|
||||
# ### end Alembic commands ###
|
|
@ -1,178 +0,0 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: e0001237a466
|
||||
Revises:
|
||||
Create Date: 2021-07-16 19:43:05.321519
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'e0001237a466'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('country',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('code', sa.String(length=2000), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('matter',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('active', sa.Boolean(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('slug')
|
||||
)
|
||||
op.create_table('role',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('code', sa.String(length=2000), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('type',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('code', sa.String(length=2000), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('address',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('country_id', sa.Integer(), nullable=True),
|
||||
sa.Column('number', sa.String(length=2000), nullable=True),
|
||||
sa.Column('street', sa.String(length=2000), nullable=True),
|
||||
sa.Column('miscellaneous', sa.String(length=2000), nullable=True),
|
||||
sa.Column('city', sa.String(length=2000), nullable=True),
|
||||
sa.Column('zipcode', sa.String(length=2000), nullable=True),
|
||||
sa.Column('building', sa.String(length=2000), nullable=True),
|
||||
sa.Column('floor', sa.String(length=2000), nullable=True),
|
||||
sa.Column('stair', sa.String(length=2000), nullable=True),
|
||||
sa.Column('office', sa.String(length=2000), nullable=True),
|
||||
sa.Column('latitude', sa.String(length=2000), nullable=True),
|
||||
sa.Column('longitude', sa.String(length=2000), nullable=True),
|
||||
sa.ForeignKeyConstraint(['country_id'], ['country.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('entity',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('code', sa.String(length=2000), nullable=True),
|
||||
sa.Column('picture', sa.String(length=2000), nullable=True),
|
||||
sa.Column('type_id', sa.Integer(), nullable=True),
|
||||
sa.Column('start', sa.DateTime(), nullable=True),
|
||||
sa.Column('end', sa.DateTime(), nullable=True),
|
||||
sa.Column('country_id', sa.Integer(), nullable=True),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['country_id'], ['country.id'], ),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['entity.id'], ),
|
||||
sa.ForeignKeyConstraint(['type_id'], ['type.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('representative',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('picture', sa.String(length=2000), nullable=True),
|
||||
sa.Column('nationality_id', sa.Integer(), nullable=True),
|
||||
sa.Column('sex', sa.String(length=1), nullable=True),
|
||||
sa.Column('birth_date', sa.Date(), nullable=True),
|
||||
sa.Column('birth_place', sa.String(length=2000), nullable=True),
|
||||
sa.Column('job', sa.String(length=2000), nullable=True),
|
||||
sa.ForeignKeyConstraint(['nationality_id'], ['country.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('slug')
|
||||
)
|
||||
op.create_table('contact',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('representative_id', sa.Integer(), nullable=True),
|
||||
sa.Column('address_id', sa.Integer(), nullable=True),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('value', sa.String(length=2000), nullable=True),
|
||||
sa.ForeignKeyConstraint(['address_id'], ['address.id'], ),
|
||||
sa.ForeignKeyConstraint(['representative_id'], ['representative.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('membership',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('representative_id', sa.Integer(), nullable=True),
|
||||
sa.Column('role_id', sa.Integer(), nullable=True),
|
||||
sa.Column('start', sa.DateTime(), nullable=True),
|
||||
sa.Column('end', sa.DateTime(), nullable=True),
|
||||
sa.Column('entity_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['entity_id'], ['entity.id'], ),
|
||||
sa.ForeignKeyConstraint(['representative_id'], ['representative.id'], ),
|
||||
sa.ForeignKeyConstraint(['role_id'], ['role.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('recommendation',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('matter_id', sa.Integer(), nullable=True),
|
||||
sa.Column('entity_id', sa.Integer(), nullable=True),
|
||||
sa.Column('name', sa.String(length=2000), nullable=True),
|
||||
sa.Column('slug', sa.String(length=2000), nullable=True),
|
||||
sa.Column('code', sa.String(length=2000), nullable=True),
|
||||
sa.Column('date', sa.Date(), nullable=True),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('value', sa.String(length=2000), nullable=True),
|
||||
sa.Column('weight', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['entity_id'], ['entity.id'], ),
|
||||
sa.ForeignKeyConstraint(['matter_id'], ['matter.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('slug')
|
||||
)
|
||||
op.create_table('stance',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('representative_id', sa.Integer(), nullable=True),
|
||||
sa.Column('matter_id', sa.Integer(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.Column('subject', sa.String(length=2000), nullable=True),
|
||||
sa.Column('extract', sa.Text(), nullable=True),
|
||||
sa.Column('source_url', sa.String(length=2000), nullable=True),
|
||||
sa.Column('active', sa.Boolean(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['matter_id'], ['matter.id'], ),
|
||||
sa.ForeignKeyConstraint(['representative_id'], ['representative.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('decision',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('representative_id', sa.Integer(), nullable=True),
|
||||
sa.Column('recommendation_id', sa.Integer(), nullable=True),
|
||||
sa.Column('value', sa.String(length=2000), nullable=True),
|
||||
sa.ForeignKeyConstraint(['recommendation_id'], ['recommendation.id'], ),
|
||||
sa.ForeignKeyConstraint(['representative_id'], ['representative.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('decision')
|
||||
op.drop_table('stance')
|
||||
op.drop_table('recommendation')
|
||||
op.drop_table('membership')
|
||||
op.drop_table('contact')
|
||||
op.drop_table('representative')
|
||||
op.drop_table('entity')
|
||||
op.drop_table('address')
|
||||
op.drop_table('type')
|
||||
op.drop_table('role')
|
||||
op.drop_table('matter')
|
||||
op.drop_table('country')
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,58 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: f238158c8ad6
|
||||
Revises: aa24a81be355
|
||||
Create Date: 2022-05-28 16:41:01.047513
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'f238158c8ad6'
|
||||
down_revision = 'aa24a81be355'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('entity', 'name',
|
||||
existing_type=mysql.VARCHAR(length=200),
|
||||
type_=sa.String(length=500),
|
||||
existing_nullable=True)
|
||||
op.alter_column('entity', 'slug',
|
||||
existing_type=mysql.VARCHAR(length=200),
|
||||
type_=sa.String(length=500),
|
||||
existing_nullable=True)
|
||||
op.alter_column('type', 'name',
|
||||
existing_type=mysql.VARCHAR(length=200),
|
||||
type_=sa.String(length=500),
|
||||
existing_nullable=True)
|
||||
op.alter_column('type', 'slug',
|
||||
existing_type=mysql.VARCHAR(length=200),
|
||||
type_=sa.String(length=500),
|
||||
existing_nullable=True)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('type', 'slug',
|
||||
existing_type=sa.String(length=500),
|
||||
type_=mysql.VARCHAR(length=200),
|
||||
existing_nullable=True)
|
||||
op.alter_column('type', 'name',
|
||||
existing_type=sa.String(length=500),
|
||||
type_=mysql.VARCHAR(length=200),
|
||||
existing_nullable=True)
|
||||
op.alter_column('entity', 'slug',
|
||||
existing_type=sa.String(length=500),
|
||||
type_=mysql.VARCHAR(length=200),
|
||||
existing_nullable=True)
|
||||
op.alter_column('entity', 'name',
|
||||
existing_type=sa.String(length=500),
|
||||
type_=mysql.VARCHAR(length=200),
|
||||
existing_nullable=True)
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,45 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: f448ec882889
|
||||
Revises: cd76771172a8
|
||||
Create Date: 2022-05-28 18:53:26.059567
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'f448ec882889'
|
||||
down_revision = 'cd76771172a8'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('source',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=200), nullable=True),
|
||||
sa.Column('slug', sa.String(length=200), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('representative_origin',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('representative_id', sa.Integer(), nullable=True),
|
||||
sa.Column('source_id', sa.Integer(), nullable=True),
|
||||
sa.Column('reference', sa.String(length=200), nullable=True),
|
||||
sa.ForeignKeyConstraint(['representative_id'], ['representative.id'], ),
|
||||
sa.ForeignKeyConstraint(['source_id'], ['source.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.add_column('role', sa.Column('code', sa.String(length=200), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('role', 'code')
|
||||
op.drop_table('representative_origin')
|
||||
op.drop_table('source')
|
||||
# ### end Alembic commands ###
|
|
@ -1,5 +0,0 @@
|
|||
[build-system]
|
||||
requires = ["setuptools", "wheel"]
|
||||
|
||||
[tool.black]
|
||||
exclude = "migrations/"
|
|
@ -1,3 +0,0 @@
|
|||
black
|
||||
pytest
|
||||
pytest-black
|
|
@ -7,5 +7,7 @@ flask_migrate
|
|||
flask_restful
|
||||
flask_sqlalchemy
|
||||
flask_wtf
|
||||
python-dotenv
|
||||
python-slugify
|
||||
requests
|
||||
mysqlclient
|
||||
|
|
32
server.py
32
server.py
|
@ -13,38 +13,34 @@ from app.routes import apis, routes
|
|||
from command import commands
|
||||
|
||||
|
||||
app = flask.Flask(__name__, template_folder="app/view")
|
||||
app.config.from_object("config")
|
||||
try:
|
||||
app.config.from_object(f"config-{app.config['ENV']}")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
application = flask.Flask(__name__, template_folder="app/view")
|
||||
application.config.from_object("settings")
|
||||
|
||||
if "JINJA_ENV" in app.config:
|
||||
app.jinja_env.trim_blocks = app.config["JINJA_ENV"]["TRIM_BLOCKS"]
|
||||
app.jinja_env.lstrip_blocks = app.config["JINJA_ENV"]["LSTRIP_BLOCKS"]
|
||||
if "JINJA_ENV" in application.config:
|
||||
application.jinja_env.trim_blocks = application.config["JINJA_ENV"]["TRIM_BLOCKS"]
|
||||
application.jinja_env.lstrip_blocks = application.config["JINJA_ENV"]["LSTRIP_BLOCKS"]
|
||||
|
||||
# Loading routes
|
||||
for route in routes:
|
||||
if len(route) < 3:
|
||||
app.add_url_rule(route[0], route[1].__name__, route[1], methods=["GET"])
|
||||
application.add_url_rule(route[0], route[1].__name__, route[1], methods=["GET"])
|
||||
else:
|
||||
app.add_url_rule(route[0], route[1].__name__, route[1], methods=route[2])
|
||||
application.add_url_rule(route[0], route[1].__name__, route[1], methods=route[2])
|
||||
# Loading API routes
|
||||
for route in apis:
|
||||
api.add_resource(route[1], route[0])
|
||||
|
||||
# Initialisation of extensions
|
||||
admin.init_app(app)
|
||||
api.init_app(app)
|
||||
babel.init_app(app)
|
||||
db.init_app(app)
|
||||
login_manager.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
admin.init_app(application)
|
||||
api.init_app(application)
|
||||
babel.init_app(application)
|
||||
db.init_app(application)
|
||||
login_manager.init_app(application)
|
||||
migrate.init_app(application, db)
|
||||
|
||||
# Manage commands
|
||||
for command in commands:
|
||||
app.cli.add_command(command)
|
||||
application.cli.add_command(command)
|
||||
|
||||
|
||||
# Manage locale
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# encoding: utf-8
|
||||
|
||||
import os
|
||||
|
||||
|
||||
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
DEBUG = os.environ.get("DEBUG", False)
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY", "Choose a secret key")
|
||||
JINJA_ENV = {
|
||||
"TRIM_BLOCKS": True,
|
||||
"LSTRIP_BLOCKS": True,
|
||||
}
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get("SQLALCHEMY_DATABASE_URI", "sqlite:///" + os.path.join(BASE_DIR, "db.sqlite3"))
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
BCRYPT_ROUNDS = os.environ.get("BCRYPT_ROUNDS", 15)
|
||||
BABEL_DEFAULT_LOCALE = os.environ.get("BABEL_DEFAULT_LOCALE", "fr")
|
||||
AVAILABLE_LANGUAGES = {
|
||||
"fr": "Français",
|
||||
"en": "English",
|
||||
}
|
||||
API_PER_PAGE = int(os.environ.get("API_PER_PAGE", 10))
|
Loading…
Reference in New Issue