diff --git a/Documentation/DjangoPhoto_app.sql b/Documentation/DjangoPhoto_app.sql index 12fd571..0c2d57e 100644 --- a/Documentation/DjangoPhoto_app.sql +++ b/Documentation/DjangoPhoto_app.sql @@ -2,6 +2,28 @@ ---destinée à la réalisation de l'application Python pour la fin du module ---dispensé aux M2-TNAH par Thibault CLérice +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS `user` ( + `user_id` integer NOT NULL PRIMARY KEY AUTOINCREMENT, + `user_nom` TINYTEXT NOT NULL, + `user_prenom` TINYTEXT NOT NULL, + `user_login` VARCHAR ( 45 ) NOT NULL, + `user_email` TINYTEXT NOT NULL, + `user_motdepasse` VARCHAR ( 100 ) NOT NULL, + `user_type` TEXT DEFAULT 'user' +); + +DROP TABLE IF EXISTS `authorship`; +CREATE TABLE IF NOT EXISTS `authorship` ( + `authorship_id` integer NOT NULL PRIMARY KEY AUTOINCREMENT, + `authorship_user_id` integer NOT NULL, + `authorship_image_id` integer NOT NULL, + `authorship_date` DATETIME DEFAULT current_timestamp, + FOREIGN KEY(authorship_user_id) REFERENCES user(user_id), + FOREIGN KEY(authorship_image_id) REFERENCES image(id) +); + CREATE TABLE IF NOT EXISTS Image ( id INTEGER PRIMARY KEY AUTOINCREMENT, titre TEXT NOT NULL, @@ -11,9 +33,41 @@ CREATE TABLE IF NOT EXISTS Image ( description TEXT NOT NULL, source TEXT NOT NULL, tag TEXT NOT NULL, - orientation TEXT NOT NULL + orientation TEXT NOT NULL, + image_valid TINYTEXT DEFAULT 'y', + img_user_id INTEGER +); + +CREATE TABLE IF NOT EXISTS tag_img ( + tag_mot TEXT NOT NULL PRIMARY KEY ); +INSERT INTO `tag` ( + `tag_mot`) +VALUES +("quintette"), +("musicien"), +("famille"), +("portrait"), +("autre") +; + +CREATE TABLE IF NOT EXISTS orientation_img ( + orientation_type TEXT NOT NULL PRIMARY KEY +); + +INSERT INTO `orientation` ( + `orientation_type`) +VALUES +("portrait"), +("paysage") +; + + +COMMIT; + +BEGIN TRANSACTION; + INSERT or IGNORE INTO Image (titre, chemin, date, nom_photographe,description,source,tag,orientation) VALUES ('Django en famille', '', 'circa 1920','', 'Django en famille. De gauche à droite : sa mère, dite Negros (la deuxième), Django (le septième).', 'BnF / Fonds Ch. Delaunay, Boîte 71, page 3', 'famille', 'paysage'); INSERT or IGNORE INTO Image (titre, chemin, date, nom_photographe,description,source,tag,orientation) VALUES ('Django adolescent au banjo', '', 'circa 1923','', 'Django adolescent au banjo. ', 'BnF / Fonds Ch. Delaunay, Boîte 71, page 4', 'banjo', 'portrait'); INSERT or IGNORE INTO Image (titre, chemin, date, nom_photographe,description,source,tag,orientation) VALUES ('Django adolescent avec un Borsalino', '', 'circa 1931','', 'Django adolescent avec un Borsalino.', 'BnF / Fonds Ch. Delaunay, Boîte 71, page 5', 'adolescent', 'portrait'); diff --git a/README.md b/README.md index 2860660..bca2afa 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,13 @@ Est une application web réalisée dans le cadre des enseignements (``CSS``, ``HTML``, ``Python`` et ``SQL``) pour le Master 2 en Technologies numériques appliquées à l'histoire, promotion 2019-2020, à l'Ecole nationale des chartes. ## Présentation du projet -L'application vise à présenter un corpus composé de 22 photographies de Django Reinhardt retraçant la vie du guitariste. +L'application vise à présenter un corpus composé d'une vingtaine de photographies de Django Reinhardt retraçant la vie du guitariste. A partir d'une base de données ``SQLite``, le projet est développé en ``Python 3`` et utilise ``Bootstrap`` pour la mise en forme graphique. * Une galerie globale du corpus permet donc le renvoi à partir du titre de chaque photographie sur une notice décrivant le document et présentant également le nom du photographe et sa source. * La recherche s'effectue par mots-clefs (famille, portrait, musicien, quintette), par nom du photographe, par date, par l'orientation de l'image (portrait/paysage), ou en accès direct via la Galerie. * Une biographie de l'auteur est proposée avec des liens vers des sources. +* Avec la création d'un compte, l'utilisateur peut enrichir la photothèque en créant une notice et téléchargeant une image. Après être connecté, l'utilisateur pourra modifier sa notice ou supprimer son image. L'utilisateur ne peut modifier que les images de son compte. ## Son installation ### :penguin: Linux diff --git a/projet_DjangoPhoto/app/__init__.py b/__init__.py similarity index 100% rename from projet_DjangoPhoto/app/__init__.py rename to __init__.py diff --git a/commentaire.md b/commentaire.md new file mode 100644 index 0000000..babba78 --- /dev/null +++ b/commentaire.md @@ -0,0 +1,97 @@ +## Phase d'installation + +- `git init` inutile +- `MySLQ` inutile? +- Erreur: se déplacer dans `./projetDangoPhoto` et non `~/` + +## Lancement + +- Le premier lancement ne fonctionne pas: la fonction `secure_filename` ne fonctionne pas car mauvaise version de Werkzeug + - Bug connu il y a 17 mois: donc pas de tentative de réinstallation avant soumission + https://stackoverflow.com/questions/61628503/flask-uploads-importerror-cannot-import-name-secure-filename + +## Hygiène du code + +- Problème d'indentation ici et là (exemple: fichier donnees.py, ligne 77-86) +- 2 fichiers inutiles dans routes (api et generic.py) +- Les noms de variables: éviter les noms commençant par des majuscules pour les instances: il faut réserver cela aux classes +- Les imports dans `routes/__init__.py` sont illogiques ou répétés, proposition de correction: + +```python +from djangophoto.app import app, login, db +from djangophoto.modeles.donnees import Orientation_img, Tag_img, Image, Authorship +from djangophoto.modeles.utilisateurs import User +from djangophoto.utils import lenTitle, lenDesc, extension_ok +from djangophoto.constantes import DOSSIER_UPLOAD +``` + +## Modeles + +Note générale: + +Une seule table est véritablement modifiable: celle des photos. Il n'y a aucune gestion dynamique des mots clefs, des photographes... Un mot clef n'est pas un mot-clef s'il est "unique": c'est une catégorie. +On regrette donc la très faible utilisation du moteur relationnel et de ses capacités. + +### Partie SQL + +- La table `Orientation_img` est inutile: elle ne fournit aucune fonctionnalité qu'un champ ne pourrait pas offrir +- La table `Tag_img` n'est pas réellement utilisée, dans la mesure où sa clef primaire est aussi sa seule valeur. Par ailleurs, on attend, pour un système de `tags`, d'avoir une relation N-to-N +- La date en `integer` est probablement une erreur mais pose problème +- Le champ image_valid n'est jamais utilisé. + +### Partie Python + +- La fonction get_id ne sert à rien. +- `return` ne prend pas de parenthèse (fonction `get_id()`) + +### Mixte + +- Il n'est pas normal de sauvegarder un tag HTML là où un chemin aurait suffit (Image.chemin), forçant à des bidouillages (`deleteImg.chemin [21:-14]`) +- Vu la situation, le nom du fichier aurait suffit (083.jpg): sauvegarder le nom complet du fichier pose un problème pour des maintenances futures (changement de dossier par exemple) +- La mise à jour de l'imag ede permet pas de changer l'image +- Où est utilisé paysage vs. portrait ? + +## Fonctionnalités + +- Pas de pagination +- Pas de possibilité de mise à jour des images +- Moteur de recherche "simple" +- La page `liste` n'utilise pas `Authorship`. Dans cette même page, la fonction `group_by` ne fait pas sens car des personnes peuvent partager le même nom de famille. + + +## Code + +- Les lignes 204-206 ne servent à rien dans `routes/__init__.py` car elles ne peuvent pas être atteintes +- Le carousel n'est pas dynamique: si je supprime les images, il ne marche plus +- Dans le HTML, il reste des liens qui n'utilisent pas `url_for` (biographie.html) +- Vous pourriez simplifier: + +```python + {% for clef in tag_img %} + {% if clef.tag_mot == updateImg.tag %} + + {% else %} + + {% endif %} + {% endfor %} + +``` + +en +```python +{% for clef in tag_img %} + +{% endfor %} + +``` +- Votre bouton ligne 87 dans update-image n'est pas dans sa colonne. + +# Notes + +## Note SQL : 9 + +Vous ne faites pas vraiment usage des possibilités de SQL et le modèle pose quelques problèmes (y compris quand on voit en base ensuite des valeurs non numériques dans des champs numériques). + +## Note python: 7.5 + +Des progrès, mais encore loin de ce qui était attendu: vous restez à la surface des possibles et ne remplissez pas la feuille de route que nous avions établi, à savoir produire une véritable application qui mette en valeurs vos compétences. diff --git a/projet_DjangoPhoto/app/__pycache__/app.cpython-36.pyc b/projet_DjangoPhoto/app/__pycache__/app.cpython-36.pyc deleted file mode 100644 index 5e48f0d..0000000 Binary files a/projet_DjangoPhoto/app/__pycache__/app.cpython-36.pyc and /dev/null differ diff --git a/projet_DjangoPhoto/app/modeles/__pycache__/donnees.cpython-36.pyc b/projet_DjangoPhoto/app/modeles/__pycache__/donnees.cpython-36.pyc deleted file mode 100644 index 4c02613..0000000 Binary files a/projet_DjangoPhoto/app/modeles/__pycache__/donnees.cpython-36.pyc and /dev/null differ diff --git a/projet_DjangoPhoto/app/modeles/donnees.py b/projet_DjangoPhoto/app/modeles/donnees.py deleted file mode 100644 index a3ec1aa..0000000 --- a/projet_DjangoPhoto/app/modeles/donnees.py +++ /dev/null @@ -1,16 +0,0 @@ -from sqlalchemy import Column, Integer, String -from ..app import db -#On importe l'objet SQLAlchemy du module flask_sqlachemy - -#On crée une classe par table ; une ligne par colonne -class Image(db.Model): - __tablename__="image" - id = db.Column(db.Integer, primary_key=True, autoincrement=True) - titre = db.Column(db.String(64)) - chemin = db.Column(db.String(64), index=True, unique=True) - date = db.Column(db.Integer) - nom_photographe = db.Column(db.String(64)) - description = db.Column(db.String(64)) - source = db.Column(db.String(64)) - tag = db.Column(db.String(64)) - orientation = db.Column(db.String(64)) diff --git a/projet_DjangoPhoto/app/routes.py b/projet_DjangoPhoto/app/routes.py deleted file mode 100644 index bc4a7fe..0000000 --- a/projet_DjangoPhoto/app/routes.py +++ /dev/null @@ -1,90 +0,0 @@ -#On importe la variable app qui instancie l'application -from .app import app -#On importe flask : -#- render_template permet de relier les templates aux URLS -#- url_for permet de construire les URLS vers les fonctions et les pages HTML -from flask import render_template, url_for -from flask import Flask -#On importe SQLAlchemy ainsi que l'opérateur or_ -#qui sert dans la fonction de requête pour la recherche plein texte -from flask_sqlalchemy import SQLAlchemy -from sqlalchemy import or_ -#La fonction request permet d'afficher les requêtes -from flask import request - -#On déclare les tables de la BDD -from app.modeles.donnees import Image - -#On souhaite avoir 5 résultats par page lors de la recherche -RESULTATS_PAR_PAGES = 5 - -#On définit les différentes routes -#page d'accueil -@app.route("/") -def accueil(): - return render_template("pages/accueil.html") - -#page Galerie -@app.route("/Galerie") -def galerie(): - cheminImages = Image.query.all() - return render_template("pages/galerie.html", Images=cheminImages) -#Permet de faire apparaitre l'ensemble des images dans la page Galerie - -#page de la biographie d'Atget -@app.route("/Biographie") -def biographie(): - return render_template("pages/biographie.html") - -#page à propos -@app.route("/A_propos") -def a_propos(): - return render_template("pages/a_propos.html") - -# Définition de la route vers chaque image grâce à leur identifiant (int) -@app.route("/Imgs/") -def img(id): - unique_img = Image.query.get(id) - return render_template("pages/imgs.html", img = unique_img, id=id) - -#On définit la route pour la recherche plein-texte -@app.route("/recherche") -def recherche(): - motclef = request.args.get("keyword", None) - page = request.args.get("page",1) - - if isinstance(page, str) and page.isdigit(): - page = int(page) - else: - page = 1 - -#Création d'une liste vide pour les résultats - resultats = [] - titre = "Recherche" - - if motclef: - # Si on a un mot-clé, on requête toutes les tables de notre base de données pour vérifier s'il y a des correspondances - # Le résultat de cette requête est stocké dans la liste resultats = [] - resultats = Image.query.filter( - or_( - Image.date.like("%{}%".format(motclef)), - Image.orientation.like("%{}%".format(motclef)), - Image.description.like("%{}%".format(motclef)), - Image.tag.like("%{}%".format(motclef)), - Image.titre.like("%{}%".format(motclef)), - Image.nom_photographe.like("%{}%".format(motclef)), - Image.source.like("%{}%".format(motclef)), - ) - ).paginate(page=page, per_page=RESULTATS_PAR_PAGES) - titre = "Résultats pour votre recherche '"+ motclef + "'" - # On affiche une phrase de titre qui indiquera les résultats de la recherche en fonction du mot-clé rentré par l'utilisateur - # Cette variable titre sera réutilisée dans la page recherche.html - return render_template("pages/recherche.html", resultats=resultats, titre=titre, keyword=motclef) - # On retourne la page recherhce.html, et on indique à quoi correspondent les variables resultats, titre et keyword, - # qui seront appelées ensuite au sein des pages html - -#page de l'erreur 404 lorsque la page demandée est introuvable -#template "error/404" -@app.errorhandler(404) -def page_not_found(error): - return render_template("error/404.html"), 404 \ No newline at end of file diff --git a/projet_DjangoPhoto/app/templates/containeur.html b/projet_DjangoPhoto/app/templates/containeur.html deleted file mode 100644 index 89e51c6..0000000 --- a/projet_DjangoPhoto/app/templates/containeur.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends 'layouts/default.html'%} -{%block body%} - - - - -{%block contenu%}{%endblock contenu%} - - - - -{%endblock body%} diff --git a/projet_DjangoPhoto/db_DjangoPhoto.sqlite b/projet_DjangoPhoto/db_DjangoPhoto.sqlite index eb12afe..e31e4b3 100644 Binary files a/projet_DjangoPhoto/db_DjangoPhoto.sqlite and b/projet_DjangoPhoto/db_DjangoPhoto.sqlite differ diff --git a/projet_DjangoPhoto/app/modeles/__init__.py b/projet_DjangoPhoto/djangophoto/__init__.py similarity index 100% rename from projet_DjangoPhoto/app/modeles/__init__.py rename to projet_DjangoPhoto/djangophoto/__init__.py diff --git a/projet_DjangoPhoto/app/__pycache__/__init__.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/__pycache__/__init__.cpython-36.pyc similarity index 100% rename from projet_DjangoPhoto/app/__pycache__/__init__.cpython-36.pyc rename to projet_DjangoPhoto/djangophoto/__pycache__/__init__.cpython-36.pyc diff --git a/projet_DjangoPhoto/djangophoto/__pycache__/app.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/__pycache__/app.cpython-36.pyc new file mode 100644 index 0000000..c7a9bf3 Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/__pycache__/app.cpython-36.pyc differ diff --git a/projet_DjangoPhoto/djangophoto/__pycache__/constantes.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/__pycache__/constantes.cpython-36.pyc new file mode 100644 index 0000000..e20a843 Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/__pycache__/constantes.cpython-36.pyc differ diff --git a/projet_DjangoPhoto/app/__pycache__/routes.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/__pycache__/routes.cpython-36.pyc similarity index 97% rename from projet_DjangoPhoto/app/__pycache__/routes.cpython-36.pyc rename to projet_DjangoPhoto/djangophoto/__pycache__/routes.cpython-36.pyc index 1173db7..185346c 100644 Binary files a/projet_DjangoPhoto/app/__pycache__/routes.cpython-36.pyc and b/projet_DjangoPhoto/djangophoto/__pycache__/routes.cpython-36.pyc differ diff --git a/projet_DjangoPhoto/djangophoto/__pycache__/utils.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/__pycache__/utils.cpython-36.pyc new file mode 100644 index 0000000..65ba195 Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/__pycache__/utils.cpython-36.pyc differ diff --git a/projet_DjangoPhoto/app/app.py b/projet_DjangoPhoto/djangophoto/app.py similarity index 63% rename from projet_DjangoPhoto/app/app.py rename to projet_DjangoPhoto/djangophoto/app.py index 21de717..b337649 100644 --- a/projet_DjangoPhoto/app/app.py +++ b/projet_DjangoPhoto/djangophoto/app.py @@ -1,8 +1,10 @@ #import des packages from flask import Flask from flask_sqlalchemy import SQLAlchemy +from flask_login import LoginManager import os -import os.path +from .constantes import SECRET_KEY +from .constantes import DOSSIER_UPLOAD #Stockage des chemins courants chemin_actuel = os.path.dirname(os.path.abspath(__file__)) @@ -10,6 +12,9 @@ templates = os.path.join(chemin_actuel, "templates") #Stockage des chemins vers les "static" statics = os.path.join(chemin_actuel, "static") +# on stocke le chemin vers le dossier où stocker les images téléchargées +uploads = os.path.join(chemin_actuel, "img") + #On paramètre l'application web app = Flask( @@ -18,6 +23,8 @@ static_folder=statics ) +# On configure le secret +app.config['SECRET_KEY'] = SECRET_KEY #On configure la base de données app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///./db_DjangoPhoto.sqlite' app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False @@ -25,4 +32,7 @@ #On initie l'extension db = SQLAlchemy(app) -from .routes import accueil, biographie, galerie, a_propos, img, recherche +# On met en place la gestion d'utilisateur-rice-s +login = LoginManager(app) + +import djangophoto.routes diff --git a/projet_DjangoPhoto/djangophoto/constantes.py b/projet_DjangoPhoto/djangophoto/constantes.py new file mode 100644 index 0000000..326eeca --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/constantes.py @@ -0,0 +1,16 @@ +from warnings import warn + +# Déclaration de toutes les constantes à utiliser dans le projet +# Convention : les constantes portent des noms en majuscule + +RESULTATS_PAR_PAGE = 6 +# variable qui définit le nombre de résultats par page (utilisée pour l'index et la recherche simple) +DOSSIER_UPLOAD = "./djangophoto/static/img/" + +SECRET_KEY = "JE SUIS UN SECRET !" +# variable utilisée comme clé cryptographique, qui permet de générer des signatures ou tokens + +if SECRET_KEY == "JE SUIS UN SECRET !": + warn("Le secret par défaut n'a pas été changé, vous devriez le faire", Warning) + + diff --git a/projet_DjangoPhoto/djangophoto/modeles/__init__.py b/projet_DjangoPhoto/djangophoto/modeles/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projet_DjangoPhoto/app/modeles/__pycache__/__init__.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/modeles/__pycache__/__init__.cpython-36.pyc similarity index 100% rename from projet_DjangoPhoto/app/modeles/__pycache__/__init__.cpython-36.pyc rename to projet_DjangoPhoto/djangophoto/modeles/__pycache__/__init__.cpython-36.pyc diff --git a/projet_DjangoPhoto/djangophoto/modeles/__pycache__/donnees.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/modeles/__pycache__/donnees.cpython-36.pyc new file mode 100644 index 0000000..f1e4ebf Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/modeles/__pycache__/donnees.cpython-36.pyc differ diff --git a/projet_DjangoPhoto/djangophoto/modeles/__pycache__/utilisateurs.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/modeles/__pycache__/utilisateurs.cpython-36.pyc new file mode 100644 index 0000000..2269acf Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/modeles/__pycache__/utilisateurs.cpython-36.pyc differ diff --git a/projet_DjangoPhoto/djangophoto/modeles/donnees.py b/projet_DjangoPhoto/djangophoto/modeles/donnees.py new file mode 100644 index 0000000..9e1b8a3 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/modeles/donnees.py @@ -0,0 +1,201 @@ +from flask import url_for, flash +from flask_login import login_user, current_user, logout_user +from djangophoto.constantes import DOSSIER_UPLOAD +from djangophoto.modeles.utilisateurs import User +import os +import datetime + +from sqlalchemy import Column, Integer, String + +from .. app import db +#On importe l'objet SQLAlchemy du module flask_sqlachemy + +#On crée une classe par table ; une ligne par colonne +class Orientation_img(db.Model): + orientation_type = db.Column(db.String(64), unique=True, nullable=False, primary_key=True) + +class Tag_img(db.Model): + tag_mot = db.Column(db.String(64), unique=True, nullable=False, primary_key=True) + + +#On crée une classe par table ; une ligne par colonne +class Image(db.Model): + __tablename__="image" + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + titre = db.Column(db.String(64)) + chemin = db.Column(db.String(64), index=True, unique=True) + date = db.Column(db.Integer) + nom_photographe = db.Column(db.String(64)) + description = db.Column(db.String(64)) + source = db.Column(db.String(64)) + tag = db.Column(db.String(64), db.ForeignKey('tag_img.tag_mot'), nullable=False) + orientation = db.Column(db.String(64), db.ForeignKey('orientation_img.orientation_type'), nullable=False) + image_valid = db.Column(db.String(2)) + img_user_id = db.Column(db.Integer) + + def get_id(self): + return(self.id) + + + @staticmethod + def add_img(titre, description, sens, date, nom_photographe, source, clef, downloadlink): + """ + Fonction qui permet d'ajouter un nouveau document dans la BDD + :param titre: titre donné à l'image (str) + :param description: courte présentation sur l'image (str) + :param orientation: "portait", "paysage" (str) + :param date: date de la photographie (str) + :param nom_photographe: nom du photographe (str) + :param source: Nom du propriétaire de l'image (str) + :param tag: liste des mots-clefs (str) + :param downloadLink: lien de téléchargement de l'image (str) + :return: + """ + + errors = [] + if not titre: + errors.append("Veuillez renseigner un titre pour cette image.") + if not description: + errors.append("Veuillez renseigner une description pour cette image.") + if not sens: + errors.append("Veuillez renseigner une orientation pour cette image.") + if not date: + errors.append("Veuillez renseigner une date pour cette image, si elle est inconnue, indiquer: n.d.") + if not nom_photographe: + errors.append("Veuillez renseigner un nom du photographe pour cette image, si le nom est inconnu, indiquer: n.n.") + if not source: + errors.append("Veuillez renseigner un propriétaire pour cette image.") + if not clef: + errors.append("Veuillez renseigner une mot-clef pour cette image.") + if not downloadlink: + errors.append("Aucun lien de téléchargement pour cette image, si aucun lien, indiquer : n.l.") + + if len(errors) > 0: + return False, errors + + new_image = Image( + titre=titre, + description=description, + orientation=sens, + date=date, + nom_photographe=nom_photographe, + source=source, + tag=clef, + chemin="", + img_user_id=current_user.user_id + ) + + # on ajoute une nouvelle entrée dans la table document avec les champs correspondant aux paramètres du modèle + + try: + # On essaie d'ajouter une image à la BDD + db.session.add(new_image) + db.session.commit() + new_authorship=Authorship( + authorship_user_id=current_user.user_id, + authorship_image_id=new_image.id + ) + db.session.add(new_authorship) + db.session.commit() + return True, new_image + + except Exception as erreur: + return False, [str(erreur)] + + @staticmethod + def delete_img(id): + """ + Fonction qui supprime la notice d'une image, ses données et le fichier image + :param id: id de l'image (int) + :return: Booléen + """ + deleteImg = Image.query.get(id) + nom_fichier = DOSSIER_UPLOAD + deleteImg.chemin [21:-14] + + if os.path.exists(nom_fichier): + os.remove(nom_fichier) + else: + flash("Fichier inexistant : " + str(nom_fichier)) + + try: + db.session.delete(deleteImg) + db.session.commit() + return True + + except Exception as erreur: + return False, [str(erreur)] + + + + @staticmethod + def update_img(id, titre, description, sens, date, nom_photographe, source, clef): + """ + Fonction qui permet de modifier la description de l'image dans la BDD + :param id: id de l'image (str) + :param titre: titre donné à l'image (str) + :param description: courte présentation sur l'image (str) + :param orientation: "portait", "paysage" (str) + :param date: date de la photographie (str) + :param nom_photographe: nom du photographe (str) + :param source: Nom du propriétaire de l'image (str) + :param tag: liste des mots-clefs (str) + :return: + """ + + errors = [] + if not titre: + errors.append("Veuillez renseigner un titre pour cette image.") + if not description: + errors.append("Veuillez renseigner une description pour cette image.") + if not sens: + errors.append("Veuillez renseigner une orientation pour cette image.") + if not date: + errors.append("Veuillez renseigner une date pour cette image, si elle est inconnue, indiquer: n.d.") + if not nom_photographe: + errors.append("Veuillez renseigner un nom du photographe pour cette image, si le nom est inconnu, indiquer: n.n.") + if not source: + errors.append("Veuillez renseigner un propriétaire pour cette image.") + if not clef: + errors.append("Veuillez renseigner une mot-clef pour cette image.") + + if len(errors) > 0: + return False, errors + + update_img = Image.query.get(id) + + if update_img.titre == titre \ + and update_img.description == description \ + and update_img.date == date \ + and update_img.orientation == sens \ + and update_img.nom_photographe == nom_photographe \ + and update_img.source == source \ + and update_img.tag == clef: + errors.append("Aucune modification n'a été réalisée") + + if len(errors) > 0: + return False, errors + + else: + update_img.titre=titre + update_img.description=description + update_img.date=date + update_img.orientation=sens + update_img.nom_photographe=nom_photographe + update_img.source=source + update_img.tag=clef + + try: + db.session.add(update_img) + db.session.commit() + return True, update_img + + except Exception as erreur: + return False, [str(erreur)] + +#On crée une classe par table ; une ligne par colonne +class Authorship(db.Model): + __tablename__ = "authorship" + authorship_id = db.Column(db.Integer, nullable=True, primary_key=True, autoincrement=True) + authorship_user_id = db.Column(db.Integer, db.ForeignKey(User.user_id)) + authorship_image_id = db.Column(db.Integer, db.ForeignKey(Image.id)) + authorship_date = db.Column(db.DateTime, default=datetime.datetime.utcnow) diff --git a/projet_DjangoPhoto/djangophoto/modeles/utilisateurs.py b/projet_DjangoPhoto/djangophoto/modeles/utilisateurs.py new file mode 100644 index 0000000..3ac84ed --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/modeles/utilisateurs.py @@ -0,0 +1,103 @@ +from werkzeug.security import generate_password_hash, check_password_hash +# importation de generate_password_hash et check_password_hash depuis werkzeug pour hascher les mots de passe +from flask_login import UserMixin +# importation d'UserMixin qui implémente par défaut les méthodes is_authenticated, is_active, is_anonymous, get_id(identifier) + +from .. app import db, login +# importation de la BDD et de login pour gérer les utilisateur·rice·s + +class User(UserMixin, db.Model): + __tablename__ = "user" + user_id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True) + user_nom = db.Column(db.Text, nullable=False) + user_prenom = db.Column(db.Text, nullable=False) + user_login = db.Column(db.String(45), nullable=False) + user_email = db.Column(db.Text, nullable=False) + user_motdepasse = db.Column(db.String(100), nullable=False) + user_type = db.Column(db.Text, nullable=False) + + + + @staticmethod + def identification(login, motdepasse): + """ Identifie un utilisateur. Si cela fonctionne, renvoie les données de l'utilisateurs. + + :param login: Login de l'utilisateur + :param motdepasse: Mot de passe envoyé par l'utilisateur + :returns: Si réussite, données de l'utilisateur. Sinon None + :rtype: User or None + """ + utilisateur = User.query.filter(User.user_login == login).first() + if utilisateur and check_password_hash(utilisateur.user_motdepasse, motdepasse): + return utilisateur + return None + + @staticmethod + def creer(login, email, nom, prenom, motdepasse): + """ Crée un compte utilisateur-rice. Retourne un tuple (booléen, User ou liste). + Si il y a une erreur, la fonction renvoie False suivi d'une liste d'erreur + Sinon, elle renvoie True suivi de la donnée enregistrée + + :param login: Login de l'utilisateur-rice + :param email: Email de l'utilisateur-rice + :param nom: Nom de l'utilisateur-rice + :param prenom: Nom de l'utilisateur-rice + :param motdepasse: Mot de passe de l'utilisateur-rice (Minimum 6 caractères) + + """ + erreurs = [] + if not login: + erreurs.append("Le login fourni est vide") + if not email: + erreurs.append("L'email fourni est vide") + if not nom: + erreurs.append("Le nom fourni est vide") + if not prenom: + erreurs.append("Le prénom fourni est vide") + if not motdepasse or len(motdepasse) < 6: + erreurs.append("Le mot de passe fourni est vide ou trop court") + + # On vérifie que personne n'a utilisé cet email ou ce login + uniques = User.query.filter( + db.or_(User.user_email == email, User.user_login == login) + ).count() + if uniques > 0: + erreurs.append("L'email ou le login sont déjà inscrits dans notre base de données") + + # Si on a au moins une erreur + if len(erreurs) > 0: + return False, erreurs + + # On crée un utilisateur + utilisateur = User( + user_nom=nom, + user_prenom=prenom, + user_login=login, + user_email=email, + user_motdepasse=generate_password_hash(motdepasse), + user_type="user" + ) + + try: + # On l'ajoute au transport vers la base de données + db.session.add(utilisateur) + # On envoie le paquet + db.session.commit() + + # On renvoie l'utilisateur + return True, utilisateur + except Exception as erreur: + return False, [str(erreur)] + + def get_id(self): + """ Retourne l'id de l'objet actuellement utilisé + + :returns: ID de l'utilisateur + :rtype: int + """ + return self.user_id + + +@login.user_loader +def trouver_utilisateur_via_id(identifiant): + return User.query.get(int(identifiant)) diff --git a/projet_DjangoPhoto/djangophoto/routes/__init__.py b/projet_DjangoPhoto/djangophoto/routes/__init__.py new file mode 100644 index 0000000..049a5a8 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/routes/__init__.py @@ -0,0 +1,347 @@ +from flask import render_template, request, flash, redirect + +#La fonction request permet d'afficher les requêtes + +#On importe la variable app qui instancie l'application +from djangophoto.app import app, login +#On déclare les tables de la BDD +from djangophoto.modeles.donnees import Orientation_img +from djangophoto.modeles.donnees import Tag_img +from djangophoto.modeles.donnees import Image +from djangophoto.modeles.donnees import Authorship +from djangophoto.modeles.utilisateurs import User +from flask_login import login_user, current_user, logout_user +from djangophoto.utils import lenTitle, lenDesc, extension_ok +from werkzeug import secure_filename +from djangophoto.constantes import DOSSIER_UPLOAD + +#On importe flask : +#- render_template permet de relier les templates aux URLS +#- url_for permet de construire les URLS vers les fonctions et les pages HTML +from flask import render_template, url_for +from flask import Flask +#On importe SQLAlchemy ainsi que l'opérateur or_ +#qui sert dans la fonction de requête pour la recherche plein texte +from flask_sqlalchemy import SQLAlchemy +from sqlalchemy import or_, text, func +# on importe or_, text et func de la librairie sqlalchemy +from .. app import db +from datetime import date + +#On souhaite avoir 5 résultats par page lors de la recherche +RESULTATS_PAR_PAGES = 5 + +#On définit les différentes routes +#page d'accueil +@app.route("/") +def accueil(): + return render_template("pages/accueil.html") + +#page Galerie +@app.route("/galerie") +def galerie(): + # cheminImages = Image.query.filter(Image.image_valid=="y").all + # développement futur pour la validation des images par l'administrateur.() + cheminImages = Image.query.all() + return render_template("pages/galerie.html", Images=cheminImages) +#Permet de faire apparaitre l'ensemble des images dans la page Galerie + +#page de la liste des contributions +@app.route("/liste") +def liste(): + contribute = User.query.group_by(User.user_nom).order_by(User.user_nom).all() + nb_contributor=0 + for i_liste in contribute: + i_liste.nombre = db.session.query(func.count(Image.id)).filter(Image.img_user_id == i_liste.user_id).scalar() + if i_liste.nombre != 0: + nb_contributor = nb_contributor + 1 + return render_template("pages/liste.html", contribute=contribute, nb_contributor=nb_contributor) + +#page galerie_contribute +@app.route("/galerie_contribute/") +def galerie_contribute(user_id): + user_contribute = User.query.filter(User.user_id == user_id) + # cheminImages = Image.query.filter(Image.image_valid=="y").all + # développement futur pour la validation des images par l'administrateur.() + cheminImages = Image.query.filter(Image.img_user_id == user_id).all() + return render_template("pages/galerie_contribute.html", Images=cheminImages, user_contribute=user_contribute) +#Permet de faire apparaitre l'ensemble des images fournies par une personne contributrice (user_id) dans la page Galerie_contribute + + +#page de la biographie de Django Reinhardt +@app.route("/biographie") +def biographie(): + return render_template("pages/biographie.html") + +#page de l'ajout d'image +@app.route("/importer") +def edit_image(): + orientation_img = Orientation_img.query.all() + tag_img = Tag_img.query.all() + return render_template("pages/edit_image.html", orientation_img=orientation_img, tag_img=tag_img) + +@app.route('/upload', methods=['GET', 'POST']) +def upload(): + # # # VALEURS RENSEIGNÉES PAR L'UTILISATEUR + + # # # LISTE DE TOUS LES LIENS VERS LES IMAGES DÉJÀ EXISTANTES SUR LE SERVEUR + img_links = Image.query.with_entities(Image.chemin) + img_links = [link[0] for link in img_links.all()] + + orientation_img = Orientation_img.query.all() + tag_img = Tag_img.query.all() + # # # IMPORT DE FICHIER + if request.method == 'POST': + f = request.files['file'] + # dans f, on stocke le fichier uploadé + if f: # on vérifie qu'un fichier a bien été envoyé + if extension_ok(f.filename): # on vérifie que son extension est valide + nom = secure_filename(f.filename) # on stocke le nom de fichier dans nom + downloadlink = url_for('static', filename = "img/" + nom) + + # on stocke le lien de stockage sur le serveur du fichier uploadé + if downloadlink in img_links: + # Si le document est déjà présent sur le serveur + return redirect(url_for('oups')) + else: + status, new_image = Image.add_img( + titre = request.form.get("titre", None), + description = request.form.get("description", None), + sens = request.form.get("sens", None), + date = request.form.get("date", None), + nom_photographe = request.form.get("author", None), + source = request.form.get("source", None), + clef = request.form.get("clef", None), + downloadlink = downloadlink + ) + # on ajoute l'image à la BDD + if status is True: + f.save(DOSSIER_UPLOAD + nom) # on l'enregistre dans le dossier img + flash("Votre image a bien été ajoutée à la base de donnée ! Merci de votre contribution, vous pouvez modifier ses données si nécessaire.", "success") + droit_modif = True + return render_template("pages/imgs.html", img = new_image, id=new_image.id, droit_modif=droit_modif, orientation_img=orientation_img, tag_img=tag_img) + else: + flash("L'ajout d'une nouvelle oeuvre a échoué pour les raisons suivantes : " + ", ".join(new_image), "error") + return render_template("pages/edit_image.html", orientation_img=orientation_img, tag_img=tag_img) + else: + flash(u'Ce fichier ne porte pas une extension autorisée !', 'error') + else: + flash(u'Vous avez oublié le fichier !', 'error') + + return render_template("pages/edit_image.html", orientation_img=orientation_img, tag_img=tag_img) + + + +@app.route("/upped") +def upped(): + """ + Route pour la page à afficher après avoir importé un nouvelle image dans la BDD + + + unique_img = Image.query.get(id) + droit_modif = True + if status is True: + flash("Modification réussie !", "success") + return render_template("pages/imgs.html", img = unique_img, id=id, droit_modif=droit_modif, orientation_img=orientation_img, tag_img=tag_img) + """ + return render_template("pages/upped.html") + +@app.route("/oups/") +def oups(): + """ + Route pour la page à afficher si le fichier à importer est déjà sur le serveur + + """ + + return render_template("pages/oups.html") + + +#page à propos +@app.route("/a_propos") +def a_propos(): + return render_template("pages/a_propos.html") + +#page de la modification des légendes de l'image +@app.route("/update_img/", methods=["POST", "GET"]) +def update_img(id): + """ + Route permettant de modifier les données d'une image + :param id: ID de l'image + :return: redirection ou template Imgs.html + :rtype: template + """ + orientation_img = Orientation_img.query.all() + tag_img = Tag_img.query.all() + + if request.method == "GET": + updateImg = Image.query.get(id) + + return render_template("pages/update-image.html", updateImg=updateImg, orientation_img=orientation_img, tag_img=tag_img) + + else: + status, data = Image.update_img( + id=id, + titre = request.form.get("titre", None), + description = request.form.get("description", None), + sens = request.form.get("sens", None), + date = request.form.get("date", None), + nom_photographe = request.form.get("author", None), + source = request.form.get("source", None), + clef = request.form.get("clef", None) + ) + unique_img = Image.query.get(id) + droit_modif = True + + if status is True: + flash("Modification réussie !", "success") + return render_template("pages/imgs.html", img = unique_img, id=id, droit_modif=droit_modif, orientation_img=orientation_img, tag_img=tag_img) + else: + flash("Les erreurs suivantes ont été rencontrées : " + ", ".join(data), "danger") + updateImg = Image.query.get(id) + return render_template("pages/update-image.html", updateImg=updateImg, orientation_img=orientation_img, tag_img=tag_img) + + + unique_img = Image.query.get(id) + + return render_template("pages/update-image.html", img = unique_img, id=id, orientation_img=orientation_img, tag_img=tag_img) + + +#page de la suppression de l'image +@app.route("/delete_img/") +def delete_img(id): + """ + Route pour supprimer une image et ses données dans la base + :param _id : ID de l'image + :return: redirection ou template galerie.html + :rtype: template + """ + deleteImg = Image.query.get(id) + + + status = Image.delete_img( + id=deleteImg.id + ) + + if status is True: + cheminImages = Image.query.all() + return render_template("pages/galerie.html", Images=cheminImages) + + else: + flash("La suppresion a échoué...", "error") + cheminImages = Image.query.all() + return render_template("pages/galerie.html", Images=cheminImages) + + + + +# Définition de la route vers chaque image grâce à leur identifiant (int) +@app.route("/imgs/") +def imgs(id): + unique_img = Image.query.get(id) + droit_modif = False + + if current_user.is_authenticated is True: + + if ((current_user.user_type == 'admin') + or (unique_img.img_user_id == current_user.user_id) + ): + droit_modif = True + return render_template("pages/imgs.html", img = unique_img, id=id, droit_modif=droit_modif) + + +#On définit la route pour la recherche plein-texte +@app.route("/recherche") +def recherche(): + motclef = request.args.get("keyword", None) + page = request.args.get("page",1) + + if isinstance(page, str) and page.isdigit(): + page = int(page) + else: + page = 1 + +#Création d'une liste vide pour les résultats + resultats = [] + titre = "Recherche" + + if motclef: + # Si on a un mot-clé, on requête toutes les tables de notre base de données pour vérifier s'il y a des correspondances + # Le résultat de cette requête est stocké dans la liste resultats = [] + resultats = Image.query.filter( + or_( + Image.date.like("%{}%".format(motclef)), + Image.orientation.like("%{}%".format(motclef)), + Image.description.like("%{}%".format(motclef)), + Image.tag.like("%{}%".format(motclef)), + Image.titre.like("%{}%".format(motclef)), + Image.nom_photographe.like("%{}%".format(motclef)), + Image.source.like("%{}%".format(motclef)), + ) + ).paginate(page=page, per_page=RESULTATS_PAR_PAGES) + titre = "Résultats pour votre recherche '"+ motclef + "'" + # On affiche une phrase de titre qui indiquera les résultats de la recherche en fonction du mot-clé rentré par l'utilisateur + # Cette variable titre sera réutilisée dans la page recherche.html + return render_template("pages/recherche.html", resultats=resultats, titre=titre, keyword=motclef) + # On retourne la page recherhce.html, et on indique à quoi correspondent les variables resultats, titre et keyword, + # qui seront appelées ensuite au sein des pages html + +@app.route("/inscription", methods=["GET", "POST"]) +def inscription(): + + #Route gérant les inscriptions + # + # Si on est en POST, cela veut dire que le formulaire a été envoyé + if request.method == "POST": + statut, donnees = User.creer( + login=request.form.get("login", None), + email=request.form.get("email", None), + nom=request.form.get("nom", None), + prenom=request.form.get("prenom", None), + motdepasse=request.form.get("motdepasse", None) + ) + if statut is True: + flash("Enregistrement effectué. Identifiez-vous maintenant", "success") + return redirect("/") + else: + flash("Les erreurs suivantes ont été rencontrées : " + ",".join(donnees), "error") + return render_template("pages/inscription.html") + else: + return render_template("pages/inscription.html") + + +@app.route("/connexion", methods=["POST", "GET"]) +def connexion(): + """ Route gérant les connexions + """ + if current_user.is_authenticated is True: + flash("Vous êtes déjà connecté-e", "info") + return redirect("/") + # Si on est en POST, cela veut dire que le formulaire a été envoyé + if request.method == "POST": + utilisateur = User.identification( + login=request.form.get("login", None), + motdepasse=request.form.get("motdepasse", None) + ) + if utilisateur: + flash("Connexion effectuée", "success") + login_user(utilisateur) + return redirect("/") + else: + flash("Les identifiants n'ont pas été reconnus", "error") + + return render_template("pages/connexion.html") +login.login_view = 'connexion' + + +@app.route("/deconnexion", methods=["POST", "GET"]) +def deconnexion(): + if current_user.is_authenticated is True: + logout_user() + flash("Vous êtes déconnecté-e", "info") + return redirect("/") + +#page de l'erreur 404 lorsque la page demandée est introuvable +#template "error/404" +@app.errorhandler(404) +def page_not_found(error): + return render_template("error/404.html"), 404 diff --git a/projet_DjangoPhoto/djangophoto/routes/__pycache__/__init__.cpython-36.pyc b/projet_DjangoPhoto/djangophoto/routes/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..39c7401 Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/routes/__pycache__/__init__.cpython-36.pyc differ diff --git a/projet_DjangoPhoto/djangophoto/routes/__pycache__/__init__.cpython-38.pyc b/projet_DjangoPhoto/djangophoto/routes/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..008bb23 Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/routes/__pycache__/__init__.cpython-38.pyc differ diff --git a/projet_DjangoPhoto/djangophoto/routes/api.py b/projet_DjangoPhoto/djangophoto/routes/api.py new file mode 100644 index 0000000..e69de29 diff --git a/projet_DjangoPhoto/djangophoto/routes/generic.py b/projet_DjangoPhoto/djangophoto/routes/generic.py new file mode 100644 index 0000000..e69de29 diff --git a/projet_DjangoPhoto/app/static/bootstrap.min.css b/projet_DjangoPhoto/djangophoto/static/bootstrap.min.css similarity index 100% rename from projet_DjangoPhoto/app/static/bootstrap.min.css rename to projet_DjangoPhoto/djangophoto/static/bootstrap.min.css diff --git a/projet_DjangoPhoto/app/static/img/002.jpg b/projet_DjangoPhoto/djangophoto/static/img/002.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/002.jpg rename to projet_DjangoPhoto/djangophoto/static/img/002.jpg diff --git a/projet_DjangoPhoto/app/static/img/003.jpg b/projet_DjangoPhoto/djangophoto/static/img/003.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/003.jpg rename to projet_DjangoPhoto/djangophoto/static/img/003.jpg diff --git a/projet_DjangoPhoto/app/static/img/004.jpg b/projet_DjangoPhoto/djangophoto/static/img/004.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/004.jpg rename to projet_DjangoPhoto/djangophoto/static/img/004.jpg diff --git a/projet_DjangoPhoto/djangophoto/static/img/008.jpg b/projet_DjangoPhoto/djangophoto/static/img/008.jpg new file mode 100644 index 0000000..75f3140 Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/static/img/008.jpg differ diff --git a/projet_DjangoPhoto/app/static/img/010.jpg b/projet_DjangoPhoto/djangophoto/static/img/010.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/010.jpg rename to projet_DjangoPhoto/djangophoto/static/img/010.jpg diff --git a/projet_DjangoPhoto/app/static/img/017.jpg b/projet_DjangoPhoto/djangophoto/static/img/017.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/017.jpg rename to projet_DjangoPhoto/djangophoto/static/img/017.jpg diff --git a/projet_DjangoPhoto/djangophoto/static/img/01Enguerand.jpg b/projet_DjangoPhoto/djangophoto/static/img/01Enguerand.jpg new file mode 100644 index 0000000..d8bdf8d Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/static/img/01Enguerand.jpg differ diff --git a/projet_DjangoPhoto/app/static/img/029.jpg b/projet_DjangoPhoto/djangophoto/static/img/029.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/029.jpg rename to projet_DjangoPhoto/djangophoto/static/img/029.jpg diff --git a/projet_DjangoPhoto/djangophoto/static/img/02enguerand.jpg b/projet_DjangoPhoto/djangophoto/static/img/02enguerand.jpg new file mode 100644 index 0000000..79bc32a Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/static/img/02enguerand.jpg differ diff --git a/projet_DjangoPhoto/app/static/img/042.jpg b/projet_DjangoPhoto/djangophoto/static/img/042.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/042.jpg rename to projet_DjangoPhoto/djangophoto/static/img/042.jpg diff --git a/projet_DjangoPhoto/app/static/img/043.jpg b/projet_DjangoPhoto/djangophoto/static/img/043.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/043.jpg rename to projet_DjangoPhoto/djangophoto/static/img/043.jpg diff --git a/projet_DjangoPhoto/app/static/img/044.jpg b/projet_DjangoPhoto/djangophoto/static/img/044.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/044.jpg rename to projet_DjangoPhoto/djangophoto/static/img/044.jpg diff --git a/projet_DjangoPhoto/app/static/img/061.jpg b/projet_DjangoPhoto/djangophoto/static/img/061.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/061.jpg rename to projet_DjangoPhoto/djangophoto/static/img/061.jpg diff --git a/projet_DjangoPhoto/app/static/img/073.jpg b/projet_DjangoPhoto/djangophoto/static/img/073.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/073.jpg rename to projet_DjangoPhoto/djangophoto/static/img/073.jpg diff --git a/projet_DjangoPhoto/app/static/img/074.jpg b/projet_DjangoPhoto/djangophoto/static/img/074.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/074.jpg rename to projet_DjangoPhoto/djangophoto/static/img/074.jpg diff --git a/projet_DjangoPhoto/app/static/img/078.jpg b/projet_DjangoPhoto/djangophoto/static/img/078.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/078.jpg rename to projet_DjangoPhoto/djangophoto/static/img/078.jpg diff --git a/projet_DjangoPhoto/app/static/img/080.jpg b/projet_DjangoPhoto/djangophoto/static/img/080.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/080.jpg rename to projet_DjangoPhoto/djangophoto/static/img/080.jpg diff --git a/projet_DjangoPhoto/app/static/img/082.jpg b/projet_DjangoPhoto/djangophoto/static/img/082.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/082.jpg rename to projet_DjangoPhoto/djangophoto/static/img/082.jpg diff --git a/projet_DjangoPhoto/app/static/img/083.jpg b/projet_DjangoPhoto/djangophoto/static/img/083.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/083.jpg rename to projet_DjangoPhoto/djangophoto/static/img/083.jpg diff --git a/projet_DjangoPhoto/app/static/img/084.jpg b/projet_DjangoPhoto/djangophoto/static/img/084.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/084.jpg rename to projet_DjangoPhoto/djangophoto/static/img/084.jpg diff --git a/projet_DjangoPhoto/app/static/img/085.jpg b/projet_DjangoPhoto/djangophoto/static/img/085.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/085.jpg rename to projet_DjangoPhoto/djangophoto/static/img/085.jpg diff --git a/projet_DjangoPhoto/app/static/img/086.jpg b/projet_DjangoPhoto/djangophoto/static/img/086.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/086.jpg rename to projet_DjangoPhoto/djangophoto/static/img/086.jpg diff --git a/projet_DjangoPhoto/app/static/img/203.jpg b/projet_DjangoPhoto/djangophoto/static/img/203.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/203.jpg rename to projet_DjangoPhoto/djangophoto/static/img/203.jpg diff --git a/projet_DjangoPhoto/app/static/img/267.jpg b/projet_DjangoPhoto/djangophoto/static/img/267.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/267.jpg rename to projet_DjangoPhoto/djangophoto/static/img/267.jpg diff --git a/projet_DjangoPhoto/app/static/img/291.jpg b/projet_DjangoPhoto/djangophoto/static/img/291.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/291.jpg rename to projet_DjangoPhoto/djangophoto/static/img/291.jpg diff --git a/projet_DjangoPhoto/djangophoto/static/img/Album2-phot011.jpg b/projet_DjangoPhoto/djangophoto/static/img/Album2-phot011.jpg new file mode 100644 index 0000000..c8a1c5a Binary files /dev/null and b/projet_DjangoPhoto/djangophoto/static/img/Album2-phot011.jpg differ diff --git a/projet_DjangoPhoto/app/static/img/bandeau01.jpg b/projet_DjangoPhoto/djangophoto/static/img/bandeau01.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/bandeau01.jpg rename to projet_DjangoPhoto/djangophoto/static/img/bandeau01.jpg diff --git a/projet_DjangoPhoto/app/static/img/bandeau01.png b/projet_DjangoPhoto/djangophoto/static/img/bandeau01.png similarity index 100% rename from projet_DjangoPhoto/app/static/img/bandeau01.png rename to projet_DjangoPhoto/djangophoto/static/img/bandeau01.png diff --git a/projet_DjangoPhoto/app/static/img/bandeau02.jpg b/projet_DjangoPhoto/djangophoto/static/img/bandeau02.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/bandeau02.jpg rename to projet_DjangoPhoto/djangophoto/static/img/bandeau02.jpg diff --git a/projet_DjangoPhoto/app/static/img/bandeau03.jpg b/projet_DjangoPhoto/djangophoto/static/img/bandeau03.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/bandeau03.jpg rename to projet_DjangoPhoto/djangophoto/static/img/bandeau03.jpg diff --git a/projet_DjangoPhoto/app/static/img/img_error.jpg b/projet_DjangoPhoto/djangophoto/static/img/img_error.jpg similarity index 100% rename from projet_DjangoPhoto/app/static/img/img_error.jpg rename to projet_DjangoPhoto/djangophoto/static/img/img_error.jpg diff --git a/projet_DjangoPhoto/app/static/style.css b/projet_DjangoPhoto/djangophoto/static/style.css similarity index 100% rename from projet_DjangoPhoto/app/static/style.css rename to projet_DjangoPhoto/djangophoto/static/style.css diff --git a/projet_DjangoPhoto/djangophoto/templates/containeur.html b/projet_DjangoPhoto/djangophoto/templates/containeur.html new file mode 100644 index 0000000..47cc6f4 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/templates/containeur.html @@ -0,0 +1,83 @@ +{% extends 'layouts/default.html'%} +{%block body%} + + + + + + + +
+{% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
+
+ {% for category, message in messages %} +
+ +
+ {% endfor %} +
+
+ {% endif %} +{% endwith %} +
+
+{% block contenu %}{% endblock contenu %} +
+
+
+ + + + + +{%endblock body%} diff --git a/projet_DjangoPhoto/app/templates/error/404.html b/projet_DjangoPhoto/djangophoto/templates/error/404.html similarity index 80% rename from projet_DjangoPhoto/app/templates/error/404.html rename to projet_DjangoPhoto/djangophoto/templates/error/404.html index 3bab83b..accd141 100644 --- a/projet_DjangoPhoto/app/templates/error/404.html +++ b/projet_DjangoPhoto/djangophoto/templates/error/404.html @@ -3,5 +3,5 @@
Error 404

Retournez à la page d'accueil!


-
pellicule PNG
+
pellicule PNG
{%endblock body%} diff --git a/projet_DjangoPhoto/app/templates/layouts/default.html b/projet_DjangoPhoto/djangophoto/templates/layouts/default.html similarity index 100% rename from projet_DjangoPhoto/app/templates/layouts/default.html rename to projet_DjangoPhoto/djangophoto/templates/layouts/default.html diff --git a/projet_DjangoPhoto/app/templates/pages/a_propos.html b/projet_DjangoPhoto/djangophoto/templates/pages/a_propos.html similarity index 50% rename from projet_DjangoPhoto/app/templates/pages/a_propos.html rename to projet_DjangoPhoto/djangophoto/templates/pages/a_propos.html index 315581e..10ef1d6 100644 --- a/projet_DjangoPhoto/app/templates/pages/a_propos.html +++ b/projet_DjangoPhoto/djangophoto/templates/pages/a_propos.html @@ -3,14 +3,14 @@ -

A propos

+

À propos

L'application "Photothèque Django Reinhardt" est réalisée dans le cadre du cours dispensé par Thibault Clérice au Master 2 Technologies Numériques Appliquées à l'Histoire à l'Ecole nationale des Chartes.

-

L'exercice consiste en la réalisation d'une API en se basant sur le langage de programmation Python 3.x, le micro-framework Flask et les langages HTML et CSS. Les éléments qui composent l'habillage du site (carousel, cards pour affichage des images, etc) proviennent du framework Bootstrap 4. La base de données est réalisée à partir de SQLlite et est gérée par Python grâce à l'ORM SQLAlchemy afin de permettre l'utilisation de la fonction Recherche dans le corpus.

-

Souvent sollicitée pour retrouver la source ou l'auteur des photographies concernant Django Reinhardt (1910-1953), le choix du devoir porte sur la réalisation d'une base de données simple rassemblant un échantillon des photographies du guitariste retraçant sa vie. Le corpus présenté est restreint pour les besoins de l'exercice. Cette application présente donc une courte biographie du guitariste et une galerie de 22 photographies. Un moteur de recherche permet d'accéder aux visuels grâce à des requêtes constituées de mots-clefs, du titre de la photographie, de son année et ou de sa source. Une notice accompagne chaque photographie, en rassemblant ses éléments descriptifs.

-

Cette photothèque pourrait servir de base à un projet plus complet sur le long terme. Elle pourrait être enrichie par des institutions ou utilisateurs avec la création d'un compte. Un identifiant permettrait un accès à un espace personnel et l'utilisateur pourrait ajouter de nouvelles photographies dans un cadre précis établi au préalable par le concepteur de l'API et sous son contrôle.

+

L'exercice consiste en la réalisation d'une API en se basant sur le langage de programmation Python 3.x, le micro-framework Flask et les langages HTML et CSS. Les éléments qui composent l'habillage du site (carousel, cards pour affichage des images, etc) proviennent du framework Bootstrap 4. La base de données est réalisée à partir de SQLlite et elle est gérée par Python grâce à l'ORM SQLAlchemy afin de permettre l'utilisation de la fonction Recherche dans le corpus.

+

Étant souvent sollicitée pour retrouver la source ou l'auteur des photographies concernant Django Reinhardt (1910-1953), le choix de mon devoir s'est naturellement porté sur la réalisation d'une base de données simple rassemblant un échantillon des photographies du guitariste retraçant sa vie. Le corpus présenté est restreint pour les besoins de l'exercice. Cette application présente donc une courte biographie du guitariste et une galerie de photographies. Un moteur de recherche permet d'accéder aux visuels grâce à des requêtes constituées de mots-clefs, du titre de la photographie, de son année et ou de sa source. Une notice accompagne chaque photographie, en rassemblant ses éléments descriptifs.

+

Cette photothèque peut être enrichie par des utilisateurs avec la création d'un compte. Un identifiant permet un accès à un espace personnel et l'utilisateur peut ajouter de nouvelles photographies. Il peut également modifier les notices de ses images de son compte ou les supprimer. Cette photothèque peut être améliorée et servir de base à un projet plus complet sur le long terme. L'ajout d'une image devra se faire sous le contrôle du concepteur de l'API. L'insertion d'une source dans la notice devra permettre de l'associer à un lien internet.

-

Je tiens à remercier Chloé Fize, car mon devoir s'inspire du sien ! +

Je tiens à remercier Chloé Fize, car mon devoir s'inspire de la présentation du sien !
Je remercie également les professeurs de l'Ecole nationale des Chartes et tous les étudiants de ce Master 2, promotion 2019-2020, pour leur soutien tout au long de cette année universitaire si particulière !

diff --git a/projet_DjangoPhoto/app/templates/pages/accueil.html b/projet_DjangoPhoto/djangophoto/templates/pages/accueil.html similarity index 87% rename from projet_DjangoPhoto/app/templates/pages/accueil.html rename to projet_DjangoPhoto/djangophoto/templates/pages/accueil.html index 9b2c5fb..041a18b 100644 --- a/projet_DjangoPhoto/app/templates/pages/accueil.html +++ b/projet_DjangoPhoto/djangophoto/templates/pages/accueil.html @@ -11,9 +11,10 @@

Photothèque Django Reinhardt

Une base de données des photographies de Django Reinhardt indiquant le nom du photographe et sa source !

+ -
-
+
@@ -58,6 +59,7 @@

Une base de données des photographies de Django Reinhardt indiquant le nom

Cette base de données vous permet d'accèder aux photographies du guitariste Django Reinhardt.

La recherche s'effectue par mots-clefs (famille, portrait, musicien, quintette), nom du photographe, date, orientation de l'image (portrait/paysage), ou en accès direct via la Galerie.

Vous pouvez à tout moment revenir à cette page d'accueil en cliquant sur l'icône Django Reinhardt en haut à gauche.

+

Vous pouvez enrichir cette base en créant votre compte utilisateur. Si vous êtes connectés, vous pouvez modifier la notice de vos images ou les supprimer.



Avertissement :
diff --git a/projet_DjangoPhoto/app/templates/pages/biographie.html b/projet_DjangoPhoto/djangophoto/templates/pages/biographie.html similarity index 96% rename from projet_DjangoPhoto/app/templates/pages/biographie.html rename to projet_DjangoPhoto/djangophoto/templates/pages/biographie.html index 7de1271..1988a15 100644 --- a/projet_DjangoPhoto/app/templates/pages/biographie.html +++ b/projet_DjangoPhoto/djangophoto/templates/pages/biographie.html @@ -5,7 +5,8 @@

Biographie

Portrait de Django Reinhardt
-
+
+

Le 16 mai 1953, à peine âgé de 43 ans, le génial guitariste Django Reinhardt disparaissait.. Comme d'autres génies fugitifs de l'histoire du jazz, Charlie Parker, Billie Holiday, John Coltrane, Art Tatum, Clifford Brown ou Charlie Christian, en à peine vingt années de carrière, Django a révolutionné la guitare, inventé un style (aujourd'hui appelé à son insu Jazz manouche) et laissé une centaine de compositions. Comme le soulignait en 2010 le talentueux guitariste manouche Bireli Lagrene : "Django est un inventeur. Il avait un son qui ne ressemblait à personne d'autre, celui de la guitare acoustique des années 1930 comme celui de la guitare électrique du début des années 1950. Il a révolutionné la guitare. Après sa mort, il faut attendre les années 1960 pour trouver quelqu'un comme Jimmy Hendrix qui à son tour va apporter quelque chose de nouveau".

Son corps avait été cruellement marqué par les brûlures consécutives à l'incendie de sa roulotte alors qu'il n'avait que 18 ans, un évènement qui allait bouleverser l'histoire du jazz et celle de la guitare. Django, alors banjoïste de musette dans les bals et bars de Paris, va grâce à une extraordinaire volonté, défier les lois de la médecine : il va rééduquer lui-même sa main gauche atrophiée, et mettre au point une technique lui permettant de jouer essentiellement avec le majeur, l'index et le pouce. Grâce à cette technique, Django va devenir un guitariste dont le talent et le génie créatif vont marquer l'histoire de la guitare de jazz !

Car ils sont peu nombreux, les musiciens de jazz européens ayant transfiguré cette musique, et d’en avoir infléchi l’histoire ! D'ailleurs, Martial Solal, pianiste de jazz au style unique et qui réalisa son premier enregistrement avec Django Reinhardt, le souligne dans ce documentaire avec justesse, en expliquant que la valeur de Django réside essentiellement dans le fait qu'il avait  « son » jazz ! Il ne copiait pas les maîtres du jazz américain de l'époque mais s'en inspirait. Et si Django avait un port de tête princier, comme le notent tous les musiciens qui l'ont connu, il avait largement gagné son statut de Prince auprès du Duke ou du Count et autres héros légendaires de cette musique.

@@ -14,9 +15,12 @@

Biographie

De l'un de ses premiers solos enregistrés, comme dans la chanson Le jour où je te vis en 1934, à l'une des dernières versions enregistrées de Nuages en 1953, Django transforme la musique en langage. Tel un poète, il construit, cisèle ou ornemente sa phrase, raconte une histoire et lui donne intuitivement une forme. Emmanuel Soudieux, un des contrebassistes du Quintette des années 1930, racontait que Django n'aimait pas parler. Il connaissait la langue des Manouches et savait que son français n'était pas correct. En public, il était timide, redoutait les micros et n'aimait pas être interviewé. Alors, il prenait sa guitare et son âme s'exprimait à travers sa musique.

La vie de Django restera à tout jamais un profond mystère… On pourra toujours chercher à comprendre comment un garçon né dans un camp de Manouches en Belgique, à Liberchies, ayant fait ses armes musicales entre la Porte de Montreuil et celle d'Italie, est devenu une figure mythique de la musique de jazz et de la guitare, sans trouver une seule réponse. Plus de cinquante ans après sa mort, des légendes courent encore sur son histoire de prince nomade que ce documentaire raconte avec la plus grande honnêteté. Il laisse la parole à des musiciens qui l'ont connu (André Hodeir, Alf « Totol » Masselier, Roger Paraboschi, Martial Solal, Jean-Louis Chautemps), et l’émouvante interprétation d'Anouman, une de ses plus belles compositions, par son petit-fils David fait écho à celle de son grand-père pour nous signifier que la musique de Django résonnera pour l'éternité.

Anne Legrand, texte pour le DVD du documentaire de Christian Cascio, "Django Reinhardt, 3 doigts de génie"

+
-
+
+

Autres sources : Cité de la musique - Wikipedia

-
+
+
{% endblock contenu %} diff --git a/projet_DjangoPhoto/djangophoto/templates/pages/connexion.html b/projet_DjangoPhoto/djangophoto/templates/pages/connexion.html new file mode 100644 index 0000000..ae45728 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/templates/pages/connexion.html @@ -0,0 +1,28 @@ +{% extends "containeur.html" %} +{%block contenu%} + + + +{% block corps %} + +

Inscription

+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ + Inscription +
+
+{% endblock %} +{%endblock contenu%} diff --git a/projet_DjangoPhoto/djangophoto/templates/pages/edit_image.html b/projet_DjangoPhoto/djangophoto/templates/pages/edit_image.html new file mode 100644 index 0000000..695f59e --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/templates/pages/edit_image.html @@ -0,0 +1,101 @@ +{% extends "containeur.html" %} +{%block contenu%} + + + +{% block corps %} + +
+
+

Ajouter une image

+

Complétez le formulaire et cliquez sur "Ajouter" pour ajouter une nouvelle image à la photothèque

+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ + +
+
+
+ + +
+

Extensions autorisées :

+

.jpg, + .jpeg, .gif, .bmp, .png

+
+
+
+ + + +
+
+ +
+
+
+ {% endblock %} + + +
+{%endblock contenu%} diff --git a/projet_DjangoPhoto/app/templates/pages/galerie.html b/projet_DjangoPhoto/djangophoto/templates/pages/galerie.html similarity index 77% rename from projet_DjangoPhoto/app/templates/pages/galerie.html rename to projet_DjangoPhoto/djangophoto/templates/pages/galerie.html index 09d8833..2d33352 100644 --- a/projet_DjangoPhoto/app/templates/pages/galerie.html +++ b/projet_DjangoPhoto/djangophoto/templates/pages/galerie.html @@ -6,16 +6,18 @@

Galerie des photographies de Django Reinhardt

Le site recense {{Images|length}} photos actuellement

+
{% endfor %}
{%endblock contenu%} diff --git a/projet_DjangoPhoto/djangophoto/templates/pages/galerie_contribute.html b/projet_DjangoPhoto/djangophoto/templates/pages/galerie_contribute.html new file mode 100644 index 0000000..d33ae0c --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/templates/pages/galerie_contribute.html @@ -0,0 +1,36 @@ +{% extends 'containeur.html'%} +{%block contenu%} + + + +

Contributions

+ +
+
+
+
+ {% for contr in user_contribute %} +

Liste des photographies fournies par {{contr.user_prenom}} {{contr.user_nom}} :

+ {% endfor %} +
+
+
+
+ + + +{%endblock contenu%} + + + + \ No newline at end of file diff --git a/projet_DjangoPhoto/app/templates/pages/imgs.html b/projet_DjangoPhoto/djangophoto/templates/pages/imgs.html similarity index 67% rename from projet_DjangoPhoto/app/templates/pages/imgs.html rename to projet_DjangoPhoto/djangophoto/templates/pages/imgs.html index 2e394e6..87ff607 100644 --- a/projet_DjangoPhoto/app/templates/pages/imgs.html +++ b/projet_DjangoPhoto/djangophoto/templates/pages/imgs.html @@ -8,6 +8,16 @@ {% block contenu %} {% if img %} + {% if droit_modif %} +
  • + +
  • + {% endif %} + @@ -32,7 +42,7 @@

    {{img.titre}}

    + l'affichage de celle-ci --> {% else %}

    La base de données est en cours de constitution

    {% endif %} diff --git a/projet_DjangoPhoto/djangophoto/templates/pages/inscription.html b/projet_DjangoPhoto/djangophoto/templates/pages/inscription.html new file mode 100644 index 0000000..385fa20 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/templates/pages/inscription.html @@ -0,0 +1,46 @@ +{% extends "containeur.html" %} +{%block contenu%} + + + +{% block corps %} + +

    Inscription

    +

    Complétez le formulaire et cliquez sur "S'inscrire".

    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    +{% endblock %} +{%endblock contenu%} diff --git a/projet_DjangoPhoto/djangophoto/templates/pages/liste.html b/projet_DjangoPhoto/djangophoto/templates/pages/liste.html new file mode 100644 index 0000000..3646e89 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/templates/pages/liste.html @@ -0,0 +1,45 @@ +{% extends 'containeur.html'%} +{% block contenu %} + + + +

    Liste des contributions dans la photothèque Django Reinhardt

    + + +
    +
    +
    +
    +

    {{nb_contributor}} personnes contribuent actuellement à la photothèque :

    +
    +
    +
    + + + + +
    +
    +{% for contr in contribute %} +{% if contr.nombre != 0 %} +
    +
    +
  • {{contr.user_prenom}} {{contr.user_nom}} : {{contr.nombre}} contribution(s)
  • +

    Afficher les contributions

    +
    +
    +{% endif %} +{% endfor %} +
    +
    + + +{% endblock contenu %} + + + + + diff --git a/projet_DjangoPhoto/djangophoto/templates/pages/oups.html b/projet_DjangoPhoto/djangophoto/templates/pages/oups.html new file mode 100755 index 0000000..72cae16 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/templates/pages/oups.html @@ -0,0 +1,39 @@ +{% extends "containeur.html" %} + +{% block titre %} + {%if docu %}| Oups {% endif %} +{% endblock %} + +{% block corps %} +
    +

    Le document a déjà été ajouté au serveur !

    + +
    +
    +
    +

    Merci de choisir un autre fichier ou de renommer le vôtre.

    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    + + {% include "partials/retour_accueil.html" %} +{% endblock %} + diff --git a/projet_DjangoPhoto/app/templates/pages/recherche.html b/projet_DjangoPhoto/djangophoto/templates/pages/recherche.html similarity index 93% rename from projet_DjangoPhoto/app/templates/pages/recherche.html rename to projet_DjangoPhoto/djangophoto/templates/pages/recherche.html index 9b4dab9..6452010 100644 --- a/projet_DjangoPhoto/app/templates/pages/recherche.html +++ b/projet_DjangoPhoto/djangophoto/templates/pages/recherche.html @@ -9,7 +9,7 @@

    {{titre}}

    Il y a {{resultats.total}} résultats qui correspondent à votre requête :

    + + + + + +
    +
    + +
    + + + {% endblock %} + + + +{%endblock contenu%} diff --git a/projet_DjangoPhoto/djangophoto/templates/pages/upped.html b/projet_DjangoPhoto/djangophoto/templates/pages/upped.html new file mode 100755 index 0000000..c649e38 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/templates/pages/upped.html @@ -0,0 +1,40 @@ +{% extends "containeur.html" %} +{%block contenu%} + +{% block titre %} + {%if docu %}| Document téléchargé {% endif %} +{% endblock %} + +{% block corps %} +
    +

    Le document a bien été ajouté à la base de donnée

    + +
    +
    +
    +

    Merci pour votre contribution !

    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + + +
    + + +{% endblock %} +{%endblock contenu%} diff --git a/projet_DjangoPhoto/djangophoto/utils.py b/projet_DjangoPhoto/djangophoto/utils.py new file mode 100644 index 0000000..85e5d95 --- /dev/null +++ b/projet_DjangoPhoto/djangophoto/utils.py @@ -0,0 +1,31 @@ +def lenTitle(title): + ''' + Fonction qui mesure la longueur d'une chaine de caractère et renvoie 1 si elle est supérieure à 20 caractères + :param title: chaine de caractère à mesurer (str) + :return: 1 (si desc > 20) ou 0 (si desc < 20) + ''' + if len(title) > 20: + lentitle = 1 + else: + lentitle = 0 + + return lentitle + + +def lenDesc(desc): + ''' + Fonction qui mesure la longueur d'une chaine de caractère et renvoie 1 si elle est supérieure à 60 caractères + :param desc: chaine de caractère à mesurer (str) + :return: 1 (si desc > 60) ou 0 (si desc < 60) + ''' + if len(desc) > 60: + lendesc = 1 + else: + lendesc = 0 + + return lendesc + + +def extension_ok(nom_fichier=""): + """ Renvoie True si le fichier possède une extension valide. """ + return '.' in nom_fichier and nom_fichier.rsplit('.', 1)[1] in ('pdf', 'jpg', 'JPG', 'jpeg', 'gif', 'bmp', 'png') diff --git a/projet_DjangoPhoto/path.py b/projet_DjangoPhoto/path.py index 41adfe0..6aa28f8 100644 --- a/projet_DjangoPhoto/path.py +++ b/projet_DjangoPhoto/path.py @@ -3,7 +3,7 @@ chemin_actuel = os.path.dirname(os.path.abspath(__file__)) print(chemin_actuel) -templates = os.path.join(chemin_actuel, "app", "templates") +templates = os.path.join(chemin_actuel, "djangophoto", "templates") print(templates) -chemin_db = os.path.join(chemin_actuel, "db_DjangoPhoto.sqlite") + diff --git a/projet_DjangoPhoto/run.py b/projet_DjangoPhoto/run.py index 29cf1f4..d1296df 100644 --- a/projet_DjangoPhoto/run.py +++ b/projet_DjangoPhoto/run.py @@ -1,3 +1,8 @@ -from app.app import app +from djangophoto.app import app +# du fichier app.py dans le dossier djangophoto j'importe la fonction config_app + + if __name__ == '__main__': - app.run() \ No newline at end of file + app.run(debug=True) + # app.run() lance l'application +# le mode debug permet de lancer un débogueur pendant le développement de l'application diff --git a/requirements.txt b/requirements.txt index 9aefb20..1384fb2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ Flask==1.1.1 +Flask-Login==0.5.0 Flask-SQLAlchemy==2.4.1 SQLAlchemy==1.3.15 - +Werkzeug==1.0.0