From 57241b843bb7160aac598bc1434a127a782ff6de Mon Sep 17 00:00:00 2001 From: John Doe Date: Fri, 5 Dec 2025 23:20:36 +0100 Subject: [PATCH] Rework blog section Wrok in bloc sectionn --- static/simplemde-custom.css | 90 +++++++++++++++++ templates/_head.html | 6 +- templates/_nav_userlogin.html | 8 +- templates/blog.html | 10 +- templates/css/simple_editor.html | 3 + templates/edit_article.html | 37 +++++-- templates/index_blog.html | 15 ++- templates/new_article_blog.html | 19 +++- templates/personnalize_blog.html | 8 ++ templates/profil.html | 74 +++++++------- templates/up_squelette.html | 15 ++- tools/databaseinit.py | 49 ++++++---- views/blog.py | 163 ++++++++++++++++++------------- 13 files changed, 339 insertions(+), 158 deletions(-) create mode 100644 static/simplemde-custom.css create mode 100644 templates/css/simple_editor.html create mode 100644 templates/personnalize_blog.html diff --git a/static/simplemde-custom.css b/static/simplemde-custom.css new file mode 100644 index 0000000..fc1ea88 --- /dev/null +++ b/static/simplemde-custom.css @@ -0,0 +1,90 @@ +.editor-toolbar a { + display: inline-block; + text-align: center; + text-decoration: none !important; + color: var(--pico-primary) !important; + width: 30px; + height: 30px; + margin: 0; + border: 1px solid transparent; + border-radius: 3px; + cursor: pointer; +} + + +.editor-toolbar.fullscreen { + width: 100%; + height: 50px; + overflow-x: auto; + overflow-y: hidden; + white-space: nowrap; + padding-top: 10px; + padding-bottom: 10px; + box-sizing: border-box; + background: var(--pico-background-color); + border: 0; + position: fixed; + top: 0; + left: 0; + opacity: 1; + z-index: 9; +} + +.CodeMirror { + background-color: var(--pico-background-color); + color: var(--pico-color) !important; + +} + + +.editor-preview-active-side { + background: var(--pico-background-color); + color: var(--pico-color) !important; + position: fixed; + bottom: 0; + width: 50%; + top: 50px; + right: 0; + z-index: 9; + border: 1px solid #ddd; +} + + +.CodeMirror .CodeMirror-code .cm-tag { + color: #63a35c; +} + +.CodeMirror .CodeMirror-code .cm-attribute { + color: #795da3; +} + +.CodeMirror .CodeMirror-code .cm-string { + color: #183691; +} + +.CodeMirror .CodeMirror-selected { + background: var(--pico-text-selection-color) !important; +} + + +.CodeMirror .CodeMirror-code .cm-link { + color: #7f8c8d; +} + +.CodeMirror .CodeMirror-code .cm-url { + color: #aab2b3; +} + +.CodeMirror-cursor { + border-left-color: var(--pico-primary); +} + +.editor-statusbar .lines:before { + color: var(--pico-primary) !important; + content: 'lignes: ' +} + +.editor-statusbar .words:before { + color: var(--pico-primary) !important; + content: 'Mots: ' +} diff --git a/templates/_head.html b/templates/_head.html index 9cef895..f18a383 100644 --- a/templates/_head.html +++ b/templates/_head.html @@ -1,4 +1,4 @@ - + @@ -11,7 +11,5 @@ - - - + diff --git a/templates/_nav_userlogin.html b/templates/_nav_userlogin.html index 9959225..923ce77 100644 --- a/templates/_nav_userlogin.html +++ b/templates/_nav_userlogin.html @@ -21,13 +21,13 @@
  • - + Configurer mon site web
  • - - Voir mon blog + + Voir le blog
  • @@ -46,6 +46,7 @@
  • Envoyer des fichiers
  • + @@ -66,7 +67,6 @@ Gerer mes alias - diff --git a/templates/blog.html b/templates/blog.html index a3fa05a..ff88043 100644 --- a/templates/blog.html +++ b/templates/blog.html @@ -1,7 +1,7 @@ - Blog de {{ user }} + Article de {{ post_info.author }} @@ -12,9 +12,11 @@

    {{ post_info.title }}

    -
    Publié le {{ post_info.time }}
    - -

    {{ post_info.subtitle }}

    +
    Publié le : {{ post_info.creation_date }}
    + {% if post_info.last_updated %} +
    Mis à jour le : {{ post_info.last_updated }}
    + {% endif %} +

    {{ post_info.subtitle }}


    {{ content|safe }} diff --git a/templates/css/simple_editor.html b/templates/css/simple_editor.html new file mode 100644 index 0000000..5ccf5d0 --- /dev/null +++ b/templates/css/simple_editor.html @@ -0,0 +1,3 @@ + + + diff --git a/templates/edit_article.html b/templates/edit_article.html index a7638a7..bf91e9f 100644 --- a/templates/edit_article.html +++ b/templates/edit_article.html @@ -2,27 +2,40 @@ {% block main %} -

    Vous pouvez modifier votre article. Actuellement seule la date de première édition sera publiée. Prochainement : intégration de la date de mise à jour dans la base de donnée.

    +

    Vous pouvez modifier votre article.

    -

    {{ oldpost[0] }}


    +

    {{ oldpost['title'] }}


    - -
    -
    +
    +
    +
    +

    Visibilité

    - {% if oldpost[2] == 'public' %} - Privé +

    Les articles brouillons ne sont visibles que par vous même

    +

    Les articles privés ne sont visibles que par les membres du serveur

    +

    Les articles public sont visibles par tout le monde

    + + + {% if oldpost['status'] == 'public' %} + Brouillon + Privé Publique - {% else %} - Privé + {% elif oldpost['status'] == 'private' %} + Brouillon + Privé Publique - + {% else %} + Brouillon + Privé + Publique + {% endif %}

    +

    @@ -30,3 +43,7 @@ {% endblock %} +{% block js %} +{% include '_js_editor.html' %} +{% endblock %} + diff --git a/templates/index_blog.html b/templates/index_blog.html index 7132a49..55b17dd 100644 --- a/templates/index_blog.html +++ b/templates/index_blog.html @@ -1,7 +1,7 @@ - Blog de {{ user }} + Le Blog du serveur @@ -14,12 +14,19 @@

    {{ post.title }}

    +
    + {% if post.last_updated %} + + + {% endif %}
    -
    + {% endfor %}
    diff --git a/templates/new_article_blog.html b/templates/new_article_blog.html index 5f00fd5..7cca29f 100644 --- a/templates/new_article_blog.html +++ b/templates/new_article_blog.html @@ -15,20 +15,31 @@
    - +

    +

    -
    +
    + +

    Visibilité

    - Privé +

    Les articles brouillons ne sont visibles que par vous même

    +

    Les articles privés ne sont visibles que par les membres du serveur

    +

    Les articles public sont visibles par tout le monde

    + + Privé Public

    - +
    +{% endblock %} + +{% block js %} +{% include '_js_editor.html' %} {% endblock %} diff --git a/templates/personnalize_blog.html b/templates/personnalize_blog.html new file mode 100644 index 0000000..b781ae0 --- /dev/null +++ b/templates/personnalize_blog.html @@ -0,0 +1,8 @@ +{% extends 'up_squelette.html' %} + + +{% block main %} + +

    Ça va venir dans la prochaine version !

    + +{% endblock %} diff --git a/templates/profil.html b/templates/profil.html index 19c417d..5bb300e 100644 --- a/templates/profil.html +++ b/templates/profil.html @@ -4,9 +4,7 @@ {% block main %} -
    - - +

    Mon profil

    @@ -15,8 +13,10 @@ cela vous convient.

    -

    Pour votre mail de secours il sert à vous envoyer un mail pour changer de mot de passe en cas de perte de ce dernier. Il n'y a - pas encore de validation de l'e-mail donc vérifiez bien ce que vous tapez.

    +

    + Pour votre mail de secours il sert à vous envoyer un mail pour changer de mot de passe en cas de perte de ce dernier. Il n'y a + pas encore de validation de l'e-mail donc vérifiez bien ce que vous tapez. +



    @@ -30,40 +30,40 @@

    - - + + -
    +
    - -
    - -
    - -
    - -
    - + +
    + +
    + +
    + +
    + diff --git a/templates/up_squelette.html b/templates/up_squelette.html index 53b108a..f36889e 100644 --- a/templates/up_squelette.html +++ b/templates/up_squelette.html @@ -1,8 +1,9 @@ - -{% include '_head.html' %} - + + {% include '_head.html' %} + {% include 'css/simple_editor.html' %} + @@ -20,9 +21,13 @@ {% include '_footer.html' %} - {% include '_js-core.html' %} - {% include '_js-gallery.html' %} + + +{% include '_js-core.html' %} + + +{% block js %} {% endblock %} diff --git a/tools/databaseinit.py b/tools/databaseinit.py index 38c6376..4749e53 100755 --- a/tools/databaseinit.py +++ b/tools/databaseinit.py @@ -32,36 +32,25 @@ def init_db(database): Mail_rescue TEXT ) """) conn.commit() - print ('table users Ok') - - cursor.execute(""" - CREATE TABLE IF NOT EXISTS posts( - id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, - title TEXT, - content TEXT, - time TEXT, - category TEXT, - author TEXT, - status TEXT - ) - """) + print ("table users Ok") cursor.execute(""" CREATE TABLE IF NOT EXISTS Blog_posts( title TEXT NOT NULL, subtitle TEXT, comments TEXT, - filename TEXT, - time TEXT, + content TEXT, + creation_date TEXT, last_updated TEXT, category TEXT, author TEXT, status TEXT, + blog_theme TEXT, PRIMARY KEY(title, author) ) """) conn.commit() - + print ("Table Blog_posts Ok !") cursor.execute("""select * from users""") accounts = cursor.fetchall() @@ -91,10 +80,12 @@ def db_migrate(database): cursor.execute("""SELECT name FROM PRAGMA_TABLE_INFO('users');""") db_columns = cursor.fetchall() invitations_col = False - blog_theme_col = False - updated_col = False lost_password_token_col = False totp_col = False + blog_theme_col = False + updated_col = False + creation_date_col = False + content_col = False for col in db_columns: if "invitations" == col[0]: @@ -111,7 +102,12 @@ def db_migrate(database): blog_theme_col = True if "last_updated" == col[0]: updated_col = True - + if "content" == col[0]: + content_col = True + if "creation_date" == col[0]: + creation_date_col= True + if "category" == col[0]: + category_col= True if not(invitations_col): @@ -143,5 +139,20 @@ def db_migrate(database): print ("Ajout du champ updated dans la table BLog") + if not(content_col): + cursor.execute("""ALTER TABLE Blog_posts RENAME COLUMN filename TO content;""") + conn.commit() + print ("Filename renomé en content") + + + if not(creation_date_col): + cursor.execute("""ALTER TABLE Blog_posts RENAME COLUMN time TO creation_date;""") + conn.commit() + print ("Time renomé en creation_date") + + if not(category_col): + cursor.execute("""ALTER TABLE Blog_posts ADD COLUMN category TEXT;""") + conn.commit() + print ("Ajout de la colono category") conn.close() diff --git a/views/blog.py b/views/blog.py index de3985c..584abc9 100644 --- a/views/blog.py +++ b/views/blog.py @@ -28,43 +28,72 @@ DOSSIER_PUBLIC= app.config['DOSSIER_PUBLIC']+'/' @login_required def new_article(): user = '%s'% escape(session['username']) - folder_blog = DOSSIER_PERSO + user + "/blog/articles/" if request.method == 'POST': title = request.form['title'] subtitle = request.form['subtitle'] + category = request.form['category'] content = request.form['content'] status = request.form['status'] post_date = time.strftime("%d/%m/%Y %H:%M:%S") - filename = title.replace(" ", "_") + ".md" - + conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée cursor = conn.cursor() # Création de l'objet "curseur" - cursor.execute("""INSERT INTO Blog_posts(title, subtitle, filename, time, author, status) VALUES(?, ?, ?, ?, ?, ?)""", (title, subtitle, filename, post_date, user, status)) # Insérer des valeurs + cursor.execute("""INSERT INTO Blog_posts(title, subtitle, category, content, creation_date, author, status) VALUES(?, ?, ?, ?, ?, ?, ?)""", (title, subtitle, category, content, post_date, user, status)) # Insérer des valeurs conn.commit() - ## On génère le fichiers markdown - with open(folder_blog + filename, 'w') as f: - f.write(content) - + return redirect(url_for('blog.list_articles_blog')) else: return render_template('new_article_blog.html') +@blog.route('/myblog/edit/', methods=['GET', 'POST']) +@login_required +def edit(title): + user='%s'% escape(session['username']) + + folder_blog = DOSSIER_PERSO + user + "/blog/articles/" + + if request.method == 'POST' : + title = requrest.form['title'] + subtitle = request.form['subtitle'] + category = request.form['category'] + newcontent = request.form['content'] + newstatus = request.form['status'] + updated = time.strftime("%d/%m/%Y %H:%M:%S") + conn = sqlite3.connect(DATABASE) + cursor = conn.cursor() + cursor.execute("""UPDATE Blog_posts SET title, subtitle=?, category=?, last_updated=?, status=?, content=? WHERE title=? AND author=?""", (title, subtitle, category, updated, newstatus, newcontent, title, user)) + conn.commit() + conn.close() + + return redirect(url_for('blog.list_articles_blog')) + else: + conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée + cursor = conn.cursor() # Création de l'objet "curseur" + cursor.execute("""SELECT title, subtitle, category, content, status FROM Blog_posts WHERE title=? AND author=?""", (title, user)) + oldpost = cursor.fetchone() + conn.close() + post = dict(title=oldpost[0], subtitle=oldpost[1], categoory=oldpost[2], content=oldpost[3], status=oldpost[4]) + return render_template('edit_article.html', + section='Post-it', + oldpost=post) + + @blog.route('/myblog/list-articles/', methods=['GET']) @login_required def list_articles_blog(): user = '%s'% escape(session['username']) conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée cursor = conn.cursor() # Création de l'objet "curseur" - cursor.execute("""SELECT title, subtitle, time, last_updated, status FROM Blog_posts WHERE author=? """, (user,) ) + cursor.execute("""SELECT title, subtitle, creation_date, last_updated, status FROM Blog_posts WHERE author=? """, (user,) ) list_posts=cursor.fetchall() posts=list() nb_articles=0 for post in list_posts: - posts.append(dict(title=post[0], + posts = [dict(title=post[0], subtitle=post[1], time=post[2], last_updated=post[3], - status=post[4])) + status=post[4])] + posts nb_articles =+ 1 return render_template('list_articles.html', @@ -79,60 +108,43 @@ def delete(title): user='%s'% escape(session['username']) folder_blog = DOSSIER_PERSO + user + "/blog/articles/" folder_blog_public = DOSSIER_PUBLIC + user + "/blog/articles/" - filename = title.replace(" ", "_") conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée cursor = conn.cursor() # Création de l'objet "curseur" cursor.execute("""DELETE FROM Blog_posts WHERE title=? AND author=?""", (title, user)) conn.commit() conn.close() - os.remove(folder_blog+filename+".md") - os.remove(folder_blog_public+filename+".html") return redirect(url_for('blog.list_articles_blog')) -@blog.route('/myblog/edit/<title>', methods=['GET', 'POST']) + +@blog.route('/myblog/personnalize/', methods=['GET']) @login_required -def edit(title): - user='%s'% escape(session['username']) - filename = title.replace(" ", "_") + ".md" - folder_blog = DOSSIER_PERSO + user + "/blog/articles/" - - if request.method == 'POST' : - subtitle = request.form['subtitle'] - newcontent = request.form['content'] - newstatus = request.form['status'] - updated = time.strftime("%d/%m/%Y %H:%M:%S") - conn = sqlite3.connect(DATABASE) - cursor = conn.cursor() - cursor.execute("""UPDATE Blog_posts SET subtitle=?, last_updated=?, status=? WHERE title=? AND author=?""", (subtitle, updated, newstatus, title, user)) - conn.commit() - conn.close() - - with open(folder_blog + filename, 'w') as f: - f.write(newcontent) - - - return redirect(url_for('blog.list_articles_blog')) - else: - conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée - cursor = conn.cursor() # Création de l'objet "curseur" - cursor.execute("""SELECT title, subtitle, status FROM Blog_posts WHERE title=? AND author=?""", (title, user)) - oldpost = cursor.fetchone() - conn.close() - - with open(folder_blog + filename, 'r') as f: - content = f.read() - - return render_template('edit_article.html', - section='Post-it', - oldpost=oldpost, - content=content) +def personnalize_blog(): + return render_template('personnalize_blog.html') -@blog.route('/blog/<username>/', methods=['GET']) -def view(username): - user = username +@blog.route('/private-blog/', methods=['GET']) +@login_required +def view_internal(): conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée cursor = conn.cursor() # Création de l'objet "curseur" - cursor.execute("""SELECT title, subtitle, time, author FROM Blog_posts WHERE status='public' AND author=? """, (user,) ) + cursor.execute("""SELECT title, subtitle, content, creation_date, last_updated, author, status FROM Blog_posts WHERE status!='draft' """ ) + list_posts=cursor.fetchall() + conn.close() + posts=list() + id=0 + + if list_posts != None: + for post in list_posts: + posts = [dict(title=post[0], subtitle=post[1], content=post[2], creation_date=post[3], last_updated=post[4], author=post[5], status=post[6] )] + posts + else: + return redirect(BASE_URL, code=404) + + return render_template('index_blog.html', section='Blog', posts=posts) + +@blog.route('/blog/', methods=['GET']) +def view(): + conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée + cursor = conn.cursor() # Création de l'objet "curseur" + cursor.execute("""SELECT title, subtitle, creation_date, author FROM Blog_posts WHERE status='public'""" ) list_posts=cursor.fetchall() posts=list() id=0 @@ -141,29 +153,46 @@ def view(username): print (list_posts) if list_posts != None: for post in list_posts: - posts.append(dict(title=post[0], subtitle=post[1], time=post[2], author=post[3])) + posts=[dict(title=post[0], subtitle=post[1], creation_date=post[2], author=post[3], status=post[4])] + posts else: return redirect(BASE_URL, code=404) - return render_template('index_blog.html', section='Blog', posts=posts, user=user) - -@blog.route('/blog/<username>/<title>', methods=['GET']) -def viewArticle(username, title): - folder_blog = DOSSIER_PERSO + username + "/blog/articles/" - filename = title.replace(" ", "_") + ".md" + return render_template('index_blog.html', section='Blog', posts=posts) + +@blog.route('/blog/private/<username>/<title>', methods=['GET']) +@login_required +def viewPrivateArticle(username, title): user = username conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée cursor = conn.cursor() # Création de l'objet "curseur" - cursor.execute("""SELECT title, subtitle, time, author FROM Blog_posts WHERE author=? AND title=? """, (user, title) ) + cursor.execute("""SELECT title, subtitle, content, creation_date, last_updated, author, status FROM Blog_posts WHERE author=? AND title=? AND status!='draft' """, (user, title) ) post = cursor.fetchone() conn.close() if post != None: - post_info = (dict(title=post[0], subtitle=post[1], time=post[2], author=post[3])) - with open(folder_blog + filename, 'r') as f: - content_md = f.read() - content = markdown(content_md) + post_info = (dict(title=post[0], subtitle=post[1], creation_date=post[3], last_updated=post[4],author=post[5])) + content= markdown(post[2]) + return render_template('blog.html', post_info=post_info, content=content) else: - flash(u"Cet article n'existe pas", 'error'); + return redirect(url_for('blog'), code=404); + + + + +@blog.route('/blog/public/<username>/<title>', methods=['GET']) +def viewArticle(username, title): + user = username + conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée + cursor = conn.cursor() # Création de l'objet "curseur" + cursor.execute("""SELECT title, subtitle, content, creation_date, last_updated, author FROM Blog_posts WHERE author=? AND title=? AND status='public' """, (user, title) ) + post = cursor.fetchone() + conn.close() + if post != None: + post_info = (dict(title=post[0], subtitle=post[1], creation_date=post[3], last_updated=post[4],author=post[5])) + content= markdown(post[2]) + + return render_template('blog.html', post_info=post_info, content=content) + else: + return redirect(url_for('blog'), code=404);