update the route model for the forum to <id>/<page>/<slug>

This works by bundling the topic object and page number in a pair during
conversion to/from URL, so that the slug can be computed effortlessly
and put in all links.
This commit is contained in:
Lephe 2020-07-16 23:58:21 +02:00
parent 4bcd70ea62
commit 17c78204a6
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
9 changed files with 47 additions and 30 deletions

View File

@ -20,9 +20,8 @@ login.login_view = 'login'
login.login_message = "Veuillez vous authentifier avant de continuer."
from app.utils.converters import *
app.url_map.converters['topicslug'] = TopicSlugConverter
app.url_map.converters['forum'] = ForumConverter
app.url_map.converters['topicpage'] = TopicPageConverter
@app.before_request
def request_time():

View File

@ -51,6 +51,6 @@ def forum_page(f):
flash('Le sujet a bien été créé', 'ok')
return redirect(url_for('forum_topic', f=f, t=t))
return redirect(url_for('forum_topic', f=f, page=(t,1)))
return render('/forum/forum.html', f=f, form=form)

View File

@ -11,8 +11,11 @@ from app.models.thread import Thread
from app.models.comment import Comment
@app.route('/forum/<forum:f>/<topicslug:t>', methods=['GET', 'POST'])
def forum_topic(f, t):
@app.route('/forum/<forum:f>/<topicpage:page>',
methods=['GET', 'POST'])
def forum_topic(f, page):
t, page = page
# Quick n' dirty workaround to converters
if f != t.forum:
abort(404)
@ -30,18 +33,16 @@ def forum_topic(f, t):
flash('Message envoyé', 'ok')
# Redirect to empty the form
return redirect(url_for('forum_topic', f=f, t=t, page="last"))
return redirect(url_for('forum_topic', f=f, page=(t,"last")))
# Update views
t.views += 1
db.session.merge(t)
db.session.commit()
if request.args.get('page') == "last":
if page == -1:
page = (t.thread.comments.count() - 1) \
// V5Config.COMMENTS_PER_PAGE + 1
else:
page = request.args.get('page', 1, type=int)
comments = t.thread.comments.paginate(page,
V5Config.COMMENTS_PER_PAGE, True)

View File

@ -19,7 +19,7 @@
<ul>
{% for t in last_active_topics %}
<li>
<a href="{{ url_for('forum_topic', f=t.forum, t=t, page='last')}}">{{ t.title }}</a>
<a href="{{ url_for('forum_topic', f=t.forum, page=(t,'last'))}}">{{ t.title }}</a>
</li>
{% endfor %}
</ul>

View File

@ -1,7 +1,6 @@
{% extends "base/base.html" %}
{% import "widgets/editor.html" as widget_editor %}
{% import "widgets/member.html" as widget_member %}
{% import "widgets/pagination.html" as widget_pagination with context %}
{% block title %}
<a href='/forum'>Forum de Planète Casio</a> » <a href="{{ url_for('forum_page', f=t.forum) }}">{{ t.forum.name }}</a> » <h1>{{ t.title }}</h1>

View File

@ -16,7 +16,7 @@
<th>Commentaires</th><th>Vues</th></tr>
{% for t in f.topics %}
<tr><td><a href='{{ url_for('forum_topic', f=t.forum, t=t) }}'>{{ t.title }}</a></td>
<tr><td><a href='{{ url_for('forum_topic', f=t.forum, page=(t,1)) }}'>{{ t.title }}</a></td>
<td><a href='{{ url_for('user', username=t.author.name) }}'>{{ t.author.name }}</a></td>
<td>{{ t.date_created | date }}</td>
<td>{{ t.thread.comments.count() }}</td>

View File

@ -15,7 +15,7 @@
<td>{{ t.thread.top_comment.text }}</td>
</tr></table>
{{ widget_pagination.paginate(comments, 'forum_topic', {'f': t.forum, 't':t}) }}
{{ widget_pagination.paginate(comments, 'forum_topic', t, {'f': t.forum}) }}
<table class="thread">
{% for c in comments.items %}
@ -28,7 +28,7 @@
{% else %}
Posté le {{ c.date_created|date }}
{% endif %}
| <a href="{{ url_for('forum_topic', f=t.forum, t=t, page=comments.page, _anchor=c.id) }}">#</a>
| <a href="{{ url_for('forum_topic', f=t.forum, page=(t,comments.page), _anchor=c.id) }}">#</a>
| <a href="#">Modifier</a>
| <a href="#">Supprimer</a>
</div>
@ -42,7 +42,7 @@
{% endfor %}
</table>
{{ widget_pagination.paginate(comments, 'forum_topic', {'f': t.forum, 't':t}) }}
{{ widget_pagination.paginate(comments, 'forum_topic', t, {'f': t.forum}) }}
<div class=form>
<h3>Commenter le sujet</h3>

View File

@ -1,21 +1,21 @@
{% macro paginate(objects, route, route_args) %}
{% macro paginate(objects, route, obj, route_args) %}
<div class="pagination">
{% if objects.has_prev %}
<a href="{{ _url_for(route, route_args, page=objects.prev_num) }}">Page précédente</a> |
<a href="{{ _url_for(route, route_args, page=(obj,objects.prev_num)) }}">Page précédente</a> |
{% endif %}
{% for page in objects.iter_pages(1, 5, 6, 1) %}
{% if not page %}
{% elif page != objects.page %}
<a href="{{ _url_for(route, route_args, page=page) }}">{{ page }}</a>
<a href="{{ _url_for(route, route_args, page=(obj,page)) }}">{{ page }}</a>
{% else %}
<strong>{{ page }}</strong>
{% endif %}
{% endfor %}
{% if objects.has_next %}
| <a href="{{ _url_for(route, route_args, page=objects.next_num) }}">Page suivante</a>
| <a href="{{ _url_for(route, route_args, page=(obj,objects.next_num)) }}">Page suivante</a>
{% endif %}
</div>
{% endmacro %}

View File

@ -39,21 +39,39 @@ class ForumConverter(BaseConverter):
def to_url(self, forum):
return forum.url[1:]
class TopicSlugConverter(BaseConverter):
class TopicPageConverter(BaseConverter):
# Only catch integers followed by an optional slug string
regex = r'(\d+)(?:-[\w-]*)?'
# Matches integers for the topic number, then either nothing, a page
# number, a slug, or a page number followed by a slug
regex = r'(\d+)(?:/(\d+)|/last)(?:/[\w-]+)?'
def to_python(self, url):
"""Convert an URL pattern to a Python object, or raise an exception."""
m = re.fullmatch(TopicSlugConverter.regex, url)
if m is None:
raise Exception(f"TopicSlugConverter: conversation failed")
tid, *args = url.split('/')
tid = int(tid)
return Topic.query.get_or_404(int(m[1], 10))
if len(args) == 0:
page = 1
elif args[0] == "last":
page = -1
else:
# The argument is considered to be a slug if it's not "last" and it
# doesn't convert to an int
try:
page = int(args[0])
except ValueError:
page = 1
def to_url(self, topic):
return f'{topic.id}-{slugify(topic.title)}'
t = Topic.query.filter_by(id=tid).first()
if t is None:
raise Exception(f"TopicConverter: no topic with id {url}")
return (t, page)
def to_url(self, topic_and_page):
t, page = topic_and_page
page = str(page) if page != -1 else "last"
slug = slugify(t.title)
return f'{t.id}/{page}/{slug}'
# Export only the converter classes
__all__ = "ForumConverter TopicSlugConverter".split()
__all__ = "ForumConverter TopicPageConverter".split()