import typing as t import urllib.parse from unidecode import unidecode # to remove accents in house and prince names in the urls from flask import Blueprint, abort, render_template, request, send_from_directory from pymongo import MongoClient import folium from .config import dbadmin, dbpassword, server_ip from .helper import find_one_or_404 main = Blueprint("main", __name__, url_prefix="/") # TODO : maybe put the mongodb connector in the flask app object # ______________________________________________________________________________ # database connexion username = urllib.parse.quote_plus(dbadmin) password = urllib.parse.quote_plus(dbpassword) dbclient = MongoClient(f'mongodb://{username}:{password}@{server_ip}:27017') # database actesdb = dbclient["actesdb"] # collections housecol = actesdb["house"] # the acte collection is the most important collection actecol = actesdb["acte"] helpers = actesdb["helpers"] #folium_map = actesdb["folium_map"] # ______________________________________________________________________________ # storage extractor utilities def extract_princes_in_houses(): """Extracts all princes from a house by queries in the storage, (not by using csv metadatas) sample: >>> extract_princes_in_houses['anjou'] [{'prince_name': "Louis Ier d'Anjou", 'prince_code': 'lo_i'}, {'prince_name': "Louis III d'Anjou", 'prince_code': 'lo_iii'}, {'prince_name': 'Isabelle de Lorraine', 'prince_code': 'isa_i'}, {'prince_name': "Louis II d'Anjou", 'prince_code': 'lo_ii'}, {'prince_name': 'Marie de Blois', 'prince_code': 'mar_i'}, {'prince_name': "René d'Anjou", 'prince_code': 're_i'}, {'prince_name': "Yollande d'Aragon", 'prince_code': 'yol_i'}] """ princes_in_houses = dict() for house in housecol.find(): housename = house['name'].lower() query = list(actecol.aggregate([{"$match": {"house": housename}}, {'$group': {'_id': {'prince_name': '$prince_name', 'prince_code': '$prince_code'}}}])) princes_in_houses[housename] = [pr['_id'] for pr in query] return princes_in_houses def normalize_trigrams(trigram): """normalizes names, usefull for the uris routes sample: Alençon -> Alencon Orléans -> Orleans """ return {unidecode(value):key for key, value in trigram.items()} # ______________________________________________________________________________ # in memory storage extracted meta informations on the database # TODO: if it takes too much time at launch, put it in something like # a `flask init` procedure helpers_dicts = helpers.find_one() house_trigram = helpers_dicts["house_trigram"] prince_bigram = helpers_dicts["prince_bigram"] princes_in_houses = extract_princes_in_houses() # normalized_trigrams house_trigram = normalize_trigrams(house_trigram) prince_bigram = normalize_trigrams(prince_bigram) def bigram_prince(prince): "Translates Charles_i -> ch_i" name, number = prince.split("_") return prince_bigram[name] + "_" + number # TODO: write tests in the datascience project `datascience/tests` #print(bigram_prince("Agnes")) #print(bigram_prince("Arthur")) #print(bigram_prince("Bernard")) #print(trigram_house("Anjou")) #print(trigram_house("Orleans")) def trigram_house(house): return house_trigram[house] def make_acteid_from_route(house=None, prince=None, date_and_item=None): "/acte/Anjou/Isabelle_i/1441_08_05a -> anj_isa_i_1441_08_05a" return "_".join([trigram_house(house), bigram_prince(prince), date_and_item]) # ______________________________________________________________________________ # routes @main.route("/") def home(): """home route""" return render_template("home.html") @main.route("/about/") def about(): """about route""" return render_template("about.html") @main.route("/actes/") def corpora_all(): """copora all lists houses sample_house_names = ["Bourbon", "Berry", "Anjou", ...] """ houses = list(housecol.find()) return render_template("corpora_all.html", houses=houses) @main.route("/actes/") # dont put a slash at the end def actes(house): """actes route shows the princes in the selected house :param: the house in the url is the house name with a capital letter at the beginning example: `house = "Berry"` """ # house in the store shall be in lower case, but let's force it, just in case house = house.lower() # the nosql query below is equivalent to this code, which is more readable but slower: #princes = [] #for act in actecol.find({"house":house}): # prince_name = act['prince_name'].capitalize() # prince_code = act['prince_code'].capitalize() # if (prince_name, prince_code) not in princes: # princes.append((prince_name, prince_code)) # [('Louis II de Bourbon', 'lo_ii'), ('Anne Dauphine', 'ann_i'), ('Agnès de Bourgogne', 'agn_i'), ('Charles Ier de Bourbon', 'ch_i')] princes = princes_in_houses[house] # TODO : modify the jinja template and suppress this line princes = [(prc['prince_name'], prc['prince_code']) for prc in princes] # [('Agnès de Bourgogne', 'agn_i'), ('Anne Dauphine', 'ann_i'), ('Charles Ier de Bourbon', 'ch_i'), ('Louis II de Bourbon', 'lo_ii') return render_template("corpus.html", house=house.capitalize(), princes=princes) @main.route("/actes//") # don't put a slash at the end def prince_corpus(house=None, prince=None): """copora prince, **timeline view**""" house = house.lower() # prince bigram -> prince_code # sample uri: /actes/Anjou/lo_i -> Louis_i -> Louis Ier d'Anjou prc_big, prc_num = prince.split("_") prince_code = prince_bigram[prc_big] + "_" + prc_num # for item in prince_acte: # print("\n\n", item) #info = [(t.date_time, t.date, t.filename, t.analysis, t.prod_place_acte, # t.diplo_type_acte, t.state_doc) # ['1418-12-20', '1418, 20 décembre', 'anj_yo_i_1418_12_20a', "Donation à Antoine de la Salle d'une maison à Arles", "Château d'Anger", 'Lettres patentes', 'Copie'] # ['1421-06-28', '1421, 28 juin', 'anj_yo_i_1421_06_28a', "Confirmation par Yolande, duchesse d'Anjou, du douaire assigné à sa belle-fille, Isabelle de Lorraine", 'NS', 'Lettres patentes', 'Original'] # ['1442-02-24', '1442 (n. st.), 24 février', 'anj_yo_i_1442_02_24a', 'Pierre Throvan, secrétaire de la reine, nommé trésorier général de Provence et de Languedoc du 16 juillet au 31 octobre 1441, puis pendant trois ans à partir du 1er novembre 1441', 'Château de Saumur', 'Lettres patentes', 'Copie'] return render_template("prince_corpus.html", houseS=house, duke_name=prince_name, lst_id=prince_acte) @main.route("/acte///") # don't put a slash at the end def acte(house=None, prince=None, dateitem=None): """specific prince's acte view :params: - house - prince - date + item (sample: 1441_08_05a) :url location sample: /acte/Anjou/Isabelle_i/1441_08_05a url transcription samples: /acte/Anjou/Isabelle_i/1441_08_05a -> anj_isa_i_1441_08_05a /acte/Bourbon/Anne_i/1388_09_15a -> brb_ann_i_1388_09_15a """ filestem = make_acteid_from_route(house, prince, dateitem) result = actecol.find_one({'_id': filestem}) return render_template("acte.html", house=house, prince=prince, #infos=None, place=None, doc=None, arch=None, #diplo=diplo_t[0].replace("_", " "), state=state[0], output_doc=result.get('xmlcontent'), name_prince=result.get("prince_name"), folium=result.get("folium"), transcribers=result.get('transcribers')) @main.route("/geoloc") def geoloc(): "global folium/leaflet map" m = folium.Map(location=[46.603354, 1.888334], zoom_start=6) for result in actecol.find(): place = result['place'] if place.get('latitude') is not None: folium.Marker( location=[place['latitude'], place['longitude']], popup=place['name'], icon=folium.Icon(color='lightgray', icon="circle", prefix='fa') #icon=folium.Icon(color='lightgray', icon='home', prefix='fa') ).add_to(m) geolocalisation = m._repr_html_() return render_template("map.html", geolocalisation=geolocalisation) #geolocalisation = folium_map.find_one() #geolocalisation = geolocalisation['globalmap'] #return render_template("map.html", geolocalisation=geolocalisation) @main.route("/contact") def contact() -> t.Text: """Displays the Contact page""" return render_template("contact.html", title="Contact") @main.route("/termsofservice") def terms() -> t.Text: """Displaysthe T&C page.""" return render_template("terms.html", title="Mentions légales") @main.route("/privacy") def privacy() -> t.Text: """Displays the privacy policy page.""" return render_template("privacy.html", title="Politique de confidentialité")