wip: cleaning code and features

This commit is contained in:
Mindiell 2022-05-31 07:11:49 +02:00
parent 6c6f2d11e8
commit 77d0b98641
44 changed files with 1019 additions and 803 deletions

View File

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

View File

@ -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"),
)

View File

@ -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")

View File

@ -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")

View File

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

View File

@ -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")

View File

@ -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")

View File

@ -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()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,75 +2,36 @@
from app import admin, db
from app.model.model import Model, View
from app.model.country import CountryModel
class RepresentativeModel(db.Model, Model):
__tablename__ = "representative"
id = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(20), unique=True)
name = db.Column(db.String(200))
slug = db.Column(db.String(200))
active = db.Column(db.Boolean, default=False)
picture = db.Column(db.String(2000))
first_name = db.Column(db.String(200))
last_name = db.Column(db.String(200))
birth_date = db.Column(db.Date)
birth_place = db.Column(db.String(200))
birth_region = db.Column(db.String(200))
birth_country_id = db.Column(db.Integer, db.ForeignKey("country.id"))
birth_country = db.relationship(
"CountryModel", foreign_keys="RepresentativeModel.birth_country_id"
)
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))
@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
picture = db.Column(db.String(200))
def __repr__(self):
return self.name
return f"{self.last_name.upper()} {self.first_name.capitalize()}"
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"))

View File

@ -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"
))

View File

@ -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)
code = db.Column(db.String(200))
name = db.Column(db.String(200))
slug = db.Column(db.String(200))
code = db.Column(db.String(20))
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"))

17
app/model/source.py Normal file
View File

@ -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"))

View File

@ -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"))

View File

@ -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(200))
slug = db.Column(db.String(200))
code = db.Column(db.String(20))
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)

View File

@ -2,11 +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
from app.controller.stance import Stance
# Adding admin endpoints
@ -19,13 +17,10 @@ routes = [
("/about", Core.as_view("about")),
("/who", Core.as_view("who")),
("/representative/<int:representative_id>", Representative.as_view("view")),
("/stance/add", Stance.as_view("add")),
]
# Listing API endpoints
apis = [
('/api/country', CountriesApi),
('/api/country/<country_id>', CountryApi),
('/api/representative', RepresentativesApi),
('/api/representative/<representative_id>', RepresentativeApi),
]

View File

@ -7,7 +7,6 @@
<li>Find a representative</li>
<li>Find a matter</li>
-->
<li><a href="{{url_for('stance.add')}}">{{_("Ajouter une prise de position")}}</a></li>
</ul>
</nav>
</div>

View File

@ -1 +1 @@
Generic single-database configuration.
Single-database configuration for Flask.

View File

@ -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 ###

View File

@ -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 ###

View File

@ -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 ###

View File

@ -1,179 +0,0 @@
"""empty message
Revision ID: 6ce21d3cdf0e
Revises:
Create Date: 2021-07-24 09:44:44.681657
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '6ce21d3cdf0e'
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=200), nullable=True),
sa.Column('slug', sa.String(length=200), nullable=True),
sa.Column('code', sa.String(length=20), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('matter',
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.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=200), nullable=True),
sa.Column('slug', sa.String(length=200), nullable=True),
sa.Column('code', sa.String(length=20), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('type',
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.Column('code', sa.String(length=20), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('address',
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.Column('country_id', sa.Integer(), nullable=True),
sa.Column('number', sa.String(length=20), 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=20), nullable=True),
sa.Column('building', sa.String(length=20), nullable=True),
sa.Column('floor', sa.String(length=20), nullable=True),
sa.Column('stair', sa.String(length=20), nullable=True),
sa.Column('office', sa.String(length=20), nullable=True),
sa.Column('latitude', sa.String(length=20), nullable=True),
sa.Column('longitude', sa.String(length=20), 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=200), nullable=True),
sa.Column('slug', sa.String(length=200), nullable=True),
sa.Column('code', sa.String(length=20), nullable=True),
sa.Column('picture', sa.String(length=2000), nullable=True),
sa.Column('type_id', sa.Integer(), nullable=True),
sa.Column('start', sa.Date(), nullable=True),
sa.Column('end', sa.Date(), 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('code', sa.String(length=20), nullable=True),
sa.Column('name', sa.String(length=200), nullable=True),
sa.Column('slug', sa.String(length=200), nullable=True),
sa.Column('active', sa.Boolean(), 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('code')
)
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=200), nullable=True),
sa.Column('slug', sa.String(length=200), 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.Date(), nullable=True),
sa.Column('end', sa.Date(), 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=200), nullable=True),
sa.Column('slug', sa.String(length=200), nullable=True),
sa.Column('code', sa.String(length=20), nullable=True),
sa.Column('date', sa.Date(), nullable=True),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('value', sa.String(length=200), nullable=True),
sa.Column('weight', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['entity_id'], ['entity.id'], ),
sa.ForeignKeyConstraint(['matter_id'], ['matter.id'], ),
sa.PrimaryKeyConstraint('id')
)
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.Date(), 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=200), 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 ###

View File

@ -0,0 +1,28 @@
"""empty message
Revision ID: 6dcc965ab0d4
Revises: f448ec882889
Create Date: 2022-05-28 19:35:20.965988
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '6dcc965ab0d4'
down_revision = 'f448ec882889'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
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('membership', 'active')
# ### end Alembic commands ###

View File

@ -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 ###

View File

@ -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 ###

View File

@ -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 ###

View File

@ -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 ###

View File

@ -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 ###

View File

@ -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 ###

View File

@ -5,7 +5,7 @@ import os
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
DEBUG = os.environ.get("DEBUG", False)
SECRET_KEY = os.environ.get("DEBUG", "Choose a secret key")
SECRET_KEY = os.environ.get("SECRET_KEY", "Choose a secret key")
JINJA_ENV = {
"TRIM_BLOCKS": True,
"LSTRIP_BLOCKS": True,
@ -13,9 +13,9 @@ JINJA_ENV = {
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", "en")
BABEL_DEFAULT_LOCALE = os.environ.get("BABEL_DEFAULT_LOCALE", "fr")
AVAILABLE_LANGUAGES = {
"en": "English",
"fr": "Français",
"en": "English",
}
API_PER_PAGE = os.environ.get("API_PER_PAGE", 10)
API_PER_PAGE = int(os.environ.get("API_PER_PAGE", 10))