From e8916c454f6c6d5e792932e65fb2257b4da7a2e8 Mon Sep 17 00:00:00 2001 From: Phuoc CAO Date: Sat, 21 Jan 2023 16:43:29 +0100 Subject: [PATCH] final test before release v1.0 --- cao_blogr.sqlite | Bin 32768 -> 32768 bytes .../alembic/versions/20230121_a632e375e7dc.py | 26 ++++++ .../alembic/versions/20230121_d335bb2cb9da.py | 55 ------------ cao_blogr/forms.py | 15 ++-- cao_blogr/models/blog_record.py | 2 +- cao_blogr/routes.py | 2 + cao_blogr/services/blog_record.py | 39 ++++++-- cao_blogr/templates/blog.jinja2 | 33 +++---- cao_blogr/templates/blog_edit.jinja2 | 55 +++++++++--- cao_blogr/templates/home.jinja2 | 23 ++--- cao_blogr/templates/layout.jinja2 | 41 ++++----- cao_blogr/templates/tag_edit.jinja2 | 55 ++++++++++++ cao_blogr/templates/tags.jinja2 | 17 ++++ cao_blogr/views/blog.py | 84 ++++++++++++++++-- cao_blogr/views/default.py | 3 +- 15 files changed, 313 insertions(+), 137 deletions(-) create mode 100644 cao_blogr/alembic/versions/20230121_a632e375e7dc.py delete mode 100644 cao_blogr/alembic/versions/20230121_d335bb2cb9da.py create mode 100644 cao_blogr/templates/tag_edit.jinja2 create mode 100644 cao_blogr/templates/tags.jinja2 diff --git a/cao_blogr.sqlite b/cao_blogr.sqlite index aa89269484af894ed1ef28bd8a14060d4bc43462..1602273b4035608e46ad4e308d84a02c3657e7dc 100644 GIT binary patch delta 435 zcmZo@U}|V!njkGG&cMLH0mLxCHc`h|TAV>o;sh^W0RubtZ3cc`{+)c2c*FQyxo`8T zZx$5r=2qY8I%i(^3#hF zb8|EE(lLr7nQ ti9rCOVuJK0hd_RQ0}Cq?ODkhjJu@Q{3j^cL3I0n2kkqhofqVtm0su=$KbHUi diff --git a/cao_blogr/alembic/versions/20230121_a632e375e7dc.py b/cao_blogr/alembic/versions/20230121_a632e375e7dc.py new file mode 100644 index 0000000..4092575 --- /dev/null +++ b/cao_blogr/alembic/versions/20230121_a632e375e7dc.py @@ -0,0 +1,26 @@ +"""init + +Revision ID: a632e375e7dc +Revises: +Create Date: 2023-01-21 11:25:48.517435 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'a632e375e7dc' +down_revision = None +branch_labels = None +depends_on = None + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('entries', 'author') + # ### end Alembic commands ### + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('entries', sa.Column('author', sa.VARCHAR(length=50), nullable=True)) + # ### end Alembic commands ### diff --git a/cao_blogr/alembic/versions/20230121_d335bb2cb9da.py b/cao_blogr/alembic/versions/20230121_d335bb2cb9da.py deleted file mode 100644 index c01a3df..0000000 --- a/cao_blogr/alembic/versions/20230121_d335bb2cb9da.py +++ /dev/null @@ -1,55 +0,0 @@ -"""init - -Revision ID: d335bb2cb9da -Revises: -Create Date: 2023-01-21 08:05:36.719719 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'd335bb2cb9da' -down_revision = None -branch_labels = None -depends_on = None - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('tags', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('tag', sa.Unicode(length=25), nullable=True), - sa.Column('tag_name', sa.Unicode(length=25), nullable=False), - sa.PrimaryKeyConstraint('id', name=op.f('pk_tags')) - ) - op.create_table('users', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.Unicode(length=255), nullable=False), - sa.Column('password', sa.Unicode(length=255), nullable=False), - sa.Column('last_logged', sa.DateTime(), nullable=True), - sa.PrimaryKeyConstraint('id', name=op.f('pk_users')), - sa.UniqueConstraint('name', name=op.f('uq_users_name')) - ) - op.create_table('entries', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('title', sa.Unicode(length=255), nullable=False), - sa.Column('body', sa.UnicodeText(), nullable=True), - sa.Column('created', sa.DateTime(), nullable=True), - sa.Column('creator', sa.Unicode(length=50), nullable=True), - sa.Column('edited', sa.DateTime(), nullable=True), - sa.Column('editor', sa.Unicode(length=50), nullable=True), - sa.Column('tag', sa.Unicode(length=25), nullable=True), - sa.Column('author', sa.Unicode(length=50), nullable=True), - sa.Column('status', sa.Unicode(length=50), nullable=True), - sa.PrimaryKeyConstraint('id', name=op.f('pk_entries')), - sa.UniqueConstraint('title', name=op.f('uq_entries_title')) - ) - # ### end Alembic commands ### - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('entries') - op.drop_table('users') - op.drop_table('tags') - # ### end Alembic commands ### diff --git a/cao_blogr/forms.py b/cao_blogr/forms.py index 8ad68ec..c0bd4b1 100644 --- a/cao_blogr/forms.py +++ b/cao_blogr/forms.py @@ -1,4 +1,4 @@ -from wtforms import Form, StringField, TextAreaField, validators +from wtforms import Form, StringField, TextAreaField, SelectField, validators from wtforms import IntegerField, PasswordField from wtforms.validators import InputRequired, Length from wtforms.widgets import HiddenInput @@ -10,10 +10,8 @@ class BlogCreateForm(Form): filters=[strip_filter]) body = TextAreaField('Corps du texte', validators=[InputRequired(), Length(min=1)], filters=[strip_filter]) - topic = StringField('Topic', validators=[InputRequired(), Length(min=1, max=255)], - filters=[strip_filter]) - tag = StringField('Tag', validators=[InputRequired(), Length(min=1, max=20)], - filters=[strip_filter]) + tag = SelectField('Tag') + status = SelectField('Statut', choices=[('brouillon','Brouillon'),('privé','Privé'),('publié','Publié')]) class BlogUpdateForm(BlogCreateForm): id = IntegerField(widget=HiddenInput()) @@ -22,6 +20,13 @@ class BlogSearchForm(Form): criteria = StringField('Critère', validators=[InputRequired(), Length(min=3, max=45)], filters=[strip_filter]) +class TagForm(Form): + id = IntegerField(widget=HiddenInput()) + + tag = StringField('Tag', validators=[InputRequired(), Length(min=1, max=25)], + filters=[strip_filter]) + + class UserCreateForm(Form): username = StringField('Nom', validators=[InputRequired(), Length(min=1, max=255)], filters=[strip_filter]) diff --git a/cao_blogr/models/blog_record.py b/cao_blogr/models/blog_record.py index a889358..4fb3fe4 100644 --- a/cao_blogr/models/blog_record.py +++ b/cao_blogr/models/blog_record.py @@ -21,7 +21,6 @@ class BlogRecord(Base): edited = Column(DateTime, default=datetime.datetime.now) editor = Column(Unicode(50), default='') tag = Column(Unicode(25)) - author = Column(Unicode(50), default='') status = Column(Unicode(50), default='brouillon') @property @@ -38,3 +37,4 @@ class Tags(Base): __tablename__ = 'tags' id = Column(Integer, primary_key=True) tag = Column(Unicode(25)) + diff --git a/cao_blogr/routes.py b/cao_blogr/routes.py index 5515009..cf1e8da 100644 --- a/cao_blogr/routes.py +++ b/cao_blogr/routes.py @@ -7,6 +7,8 @@ def includeme(config): config.add_route('blog_search', '/blog_search') config.add_route('login', '/login') config.add_route('logout', '/logout') + config.add_route('tags', '/tags') + config.add_route('tag_edit', '/tag_edit/{id}') config.add_route('users', '/users') config.add_route('user_add', '/user_add/{name}') config.add_route('user_pwd', '/user_pwd/{name}') diff --git a/cao_blogr/services/blog_record.py b/cao_blogr/services/blog_record.py index a3fe4b0..46283f2 100644 --- a/cao_blogr/services/blog_record.py +++ b/cao_blogr/services/blog_record.py @@ -2,22 +2,21 @@ import sqlalchemy as sa import datetime #<- will be used to set default dates on models from sqlalchemy import or_ -from ..models.blog_record import BlogRecord +from ..models.blog_record import BlogRecord, Tags class BlogRecordService(object): - @classmethod - def all(cls, request): - query = request.dbsession.query(BlogRecord) - return query.order_by(sa.desc(BlogRecord.created)) - @classmethod def by_criteria(cls, request, criteria): search = "%{}%".format(criteria) - query = request.dbsession.query(BlogRecord).filter(or_(BlogRecord.title.like(search), - BlogRecord.body.like(search))).all() + query = request.dbsession.query(BlogRecord) + if request.authenticated_userid == None: + # if user is anonym, display only published posts + query = query.filter(BlogRecord.status == 'publié') + query = query.filter(or_(BlogRecord.title.like(search), + BlogRecord.body.like(search))).all() return query @classmethod @@ -29,6 +28,30 @@ class BlogRecordService(object): def get_last_created(cls, request): # gest the 10 last created posts query = request.dbsession.query(BlogRecord) + if request.authenticated_userid == None: + # if user is anonym, display only published posts + query = query.filter(BlogRecord.status == 'publié') query = query.order_by(sa.desc(BlogRecord.created)).limit(10).all() return query + @classmethod + def delete(cls, request, id): + request.dbsession.query(BlogRecord).filter(BlogRecord.id == id).delete(synchronize_session=False) + return + + @classmethod + def get_tags(cls, request): + query = request.dbsession.query(Tags) + query = query.order_by(Tags.tag).all() + return query + + @classmethod + def get_tags_byId(cls, request, id): + # gest the last 5 items modified + query = request.dbsession.query(Tags).filter(Tags.id == id).first() + return query + + @classmethod + def tag_delete(cls, request, id): + request.dbsession.query(Tags).filter(Tags.id == id).delete(synchronize_session=False) + return diff --git a/cao_blogr/templates/blog.jinja2 b/cao_blogr/templates/blog.jinja2 index ceb8a8d..531903f 100644 --- a/cao_blogr/templates/blog.jinja2 +++ b/cao_blogr/templates/blog.jinja2 @@ -12,20 +12,23 @@

{{ body_html | safe }}


- {% if request.authenticated_userid %} -

- Topic : {{ entry.topic }} -  |  - Tag : {{ entry.tag }} -  |  - Créé le : {{ entry.created.strftime("%d-%m-%Y - %H:%M") }} -  |  - Modifié le : {{ entry.edited.strftime("%d-%m-%Y - %H:%M") }} -

- {% else %} -

- Créé : {{ entry.created_in_words }} -

- {% endif %} +

+ Auteur : {{ entry.author }}
+ Publié le : {{ entry.created.strftime("%d-%m-%Y - %H:%M") }}
+ {% if request.authenticated_userid %} + Modifié le : {{ entry.edited.strftime("%d-%m-%Y - %H:%M") }}
+ Tag : {{ entry.tag }}
+ Statut : {{ entry.status }} + {% endif %} +

+ + {% endblock %} + diff --git a/cao_blogr/templates/blog_edit.jinja2 b/cao_blogr/templates/blog_edit.jinja2 index 9256505..640c0f0 100644 --- a/cao_blogr/templates/blog_edit.jinja2 +++ b/cao_blogr/templates/blog_edit.jinja2 @@ -19,30 +19,31 @@ {{ form.body(class_='form-control', cols="35", rows="20") }} - {% for error in form.topic.errors %} -
{{ error }}
- {% endfor %} -
- - {{ form.topic(class_='form-control') }} -
- - {% for error in form.tag.errors %} -
{{ error }}
- {% endfor %}
{{ form.tag(class_='form-control') }}
+
+ + {{ form.status(class_='form-control') }} +
+ +

+ {% if blog_id != '0' %} + Créé le : {{ entry.created.strftime("%d-%m-%Y - %H:%M") }}
+ Modifié le : {{ entry.edited.strftime("%d-%m-%Y - %H:%M") }} + {% endif %} +

+
Retour - {% if action == 'edit' %} - + {% if blog_id != '0' %} + {% endif %}
@@ -50,4 +51,30 @@ + + + {% endblock %} diff --git a/cao_blogr/templates/home.jinja2 b/cao_blogr/templates/home.jinja2 index 88ca4a4..ad1e1af 100644 --- a/cao_blogr/templates/home.jinja2 +++ b/cao_blogr/templates/home.jinja2 @@ -3,21 +3,24 @@ {% block content %} {% if request.authenticated_userid %} -

- [Nouveau post] -

+

+ Nouveau +

{% endif%} {% for entry in last_ten %} - - - - - + + + + {% if entry.status != 'publié' %} + + {% else %} + + {% endif%} {% else %}

Aucun post trouvé

diff --git a/cao_blogr/templates/layout.jinja2 b/cao_blogr/templates/layout.jinja2 index ecd8cd7..67f6fbb 100644 --- a/cao_blogr/templates/layout.jinja2 +++ b/cao_blogr/templates/layout.jinja2 @@ -32,27 +32,28 @@ CAO Blogr diff --git a/cao_blogr/templates/tag_edit.jinja2 b/cao_blogr/templates/tag_edit.jinja2 new file mode 100644 index 0000000..ce19311 --- /dev/null +++ b/cao_blogr/templates/tag_edit.jinja2 @@ -0,0 +1,55 @@ +{% extends "cao_blogr:templates/layout.jinja2" %} + +{% block content %} + + + + {% for error in form.tag.errors %} +
{{ error }}
+ {% endfor %} + +
+ + {{form.tag(class_='form-control')}} +
+ +
+ + Retour + + {% if form.id.data %} + + {% endif %} +
+ + + + + + + +{% endblock %} diff --git a/cao_blogr/templates/tags.jinja2 b/cao_blogr/templates/tags.jinja2 new file mode 100644 index 0000000..7ef752a --- /dev/null +++ b/cao_blogr/templates/tags.jinja2 @@ -0,0 +1,17 @@ +{% extends "cao_blogr:templates/layout.jinja2" %} + +{% block content %} + +

+ Nouveau +

+ +
    + {% for entry in tags %} +
  • + {{ entry.tag }} +
  • + {% endfor %} + + +{% endblock %} diff --git a/cao_blogr/views/blog.py b/cao_blogr/views/blog.py index 25041f0..3b7adc8 100644 --- a/cao_blogr/views/blog.py +++ b/cao_blogr/views/blog.py @@ -1,8 +1,8 @@ from pyramid.view import view_config from pyramid.httpexceptions import HTTPNotFound, HTTPFound -from ..models.blog_record import BlogRecord +from ..models.blog_record import BlogRecord, Tags from ..services.blog_record import BlogRecordService -from ..forms import BlogCreateForm, BlogUpdateForm, BlogSearchForm +from ..forms import BlogCreateForm, BlogUpdateForm, BlogSearchForm, TagForm import markdown import datetime #<- will be used to set default dates on models @@ -35,13 +35,16 @@ def blog_edit(request): blog_id = request.matchdict['id'] url = request.route_url('blog_edit',id=blog_id) + # get the list of tags + tags = BlogRecordService.get_tags(request) + if blog_id == '0': # create a new post entry = BlogRecord() # set default values - entry.tag = 'pyramid' - entry.topic = 'blog' form = BlogCreateForm(request.POST, entry) + form.tag.choices = [(row.tag, row.tag) for row in tags] + page_title = 'Nouvelle page' else: # modify post entry = BlogRecordService.by_id(request, blog_id) @@ -49,26 +52,39 @@ def blog_edit(request): request.session.flash(u"Page non trouvée : %s" % blog_id, 'warning') return HTTPFound(location=request.route_url('home')) form = BlogUpdateForm(request.POST, entry) + form.tag.choices = [(row.tag, row.tag) for row in tags] + page_title = 'Modifier : ' + entry.title if 'form.submitted' in request.params and form.validate(): if blog_id == '0': form.populate_obj(entry) - import pdb;pdb.set_trace() + # interdire le car '/' dans le titre à cause du slug + entry.title = entry.title.replace('/','.') + entry.creator = request.authenticated_userid + entry.editor = entry.creator request.dbsession.add(entry) return HTTPFound(location=request.route_url('home')) else: del form.id # SECURITY: prevent overwriting of primary key form.populate_obj(entry) + # interdire le car '/' dans le titre à cause du slug + entry.title = entry.title.replace('/','.') entry.edited = datetime.datetime.now() - + entry.editor = request.authenticated_userid return HTTPFound(location=request.route_url('blog', id=entry.id, slug=entry.slug)) + if 'form.deleted' in request.params: + BlogRecordService.delete(request, blog_id) + request.session.flash("La page a été supprimée avec succès.", 'success') + return HTTPFound(location=request.route_url('home')) + return { - 'page_title': entry.title, + 'page_title': page_title, 'url': url, 'form': form, - } + 'blog_id': blog_id, + 'entry': entry, } @view_config(route_name='blog_search', @@ -90,3 +106,55 @@ def blog_search(request): 'criteria': criteria, } +@view_config(route_name='tags', renderer='cao_blogr:templates/tags.jinja2', permission='view') +def tags(request): + + # get the list of tags of this topic + tags = BlogRecordService.get_tags(request) + + return { + 'page_title': 'Tags', + 'tags': tags, + } + +@view_config(route_name='tag_edit', renderer='cao_blogr:templates/tag_edit.jinja2', permission='view') +def tag_edit(request): + # get tag parameters from request + tag_id = request.matchdict['id'] + url = request.route_url('tag_edit', id=tag_id) + + if tag_id == '0': + # create a new tag + entry = Tags() + form = TagForm(request.POST, entry) + page_title = "Nouveau Tag" + + else: + # modify post + entry = BlogRecordService.get_tags_byId(request, tag_id) + if not entry: + request.session.flash(u"Tag non trouvé : %s" % tag_id, 'warning') + return HTTPFound(location=request.route_url('tags')) + form = TagForm(request.POST, entry) + page_title = entry.tag + + if 'form.submitted' in request.params and form.validate(): + if tag_id == '0': + form.populate_obj(entry) + request.dbsession.add(entry) + return HTTPFound(location=request.route_url('tags')) + else: + del form.id # SECURITY: prevent overwriting of primary key + form.populate_obj(entry) + return HTTPFound(location=request.route_url('tags')) + + if 'form.deleted' in request.params: + BlogRecordService.tag_delete(request, entry.id) + request.session.flash("La fiche a été supprimée avec succès.", 'success') + return HTTPFound(location=request.route_url('tags')) + + return { + 'page_title': page_title, + 'url': url, + 'form': form, + } diff --git a/cao_blogr/views/default.py b/cao_blogr/views/default.py index a422d4b..bdc058a 100644 --- a/cao_blogr/views/default.py +++ b/cao_blogr/views/default.py @@ -62,8 +62,9 @@ def login(request): @view_config(route_name='logout', renderer='string') def logout(request): + username = request.authenticated_userid headers = forget(request) - request.session.flash('Vous avez bien été déconnecté.', 'success') + request.session.flash('Au revoir ' + username + ' !', 'success') return HTTPFound(location=request.route_url('home'), headers=headers)
    {{ entry.created.strftime("%d.%m.%Y") }} - {{ entry.title }} - {{ entry.topic }}{{ entry.tag }}{{ entry.created.strftime("%d.%m.%Y") }} + {{ entry.title }} + {{ entry.tag }}{{ entry.status }}