""" utils.converter: Custom URL converters to match patterns in @app.route() The Flask documentation is elusive on this topic. To add a new converter, proceed as follows: 1. Define a new converter class. 2. Set the [regex] attribute to decide which portion of the URL will be considered for conversion (apparently the default is everything until next slash or end of string). 3. Define the to_python() and to_url() methods to actually convert. 4. Add the class to __all__ at the bottom of this file. 5. In app/__init__.py, add a dictionary entry to [app.url_map.converters]. For more information, see the Werkzeug documentation: """ from werkzeug.routing import BaseConverter, ValidationError from app.models.forum import Forum from app.models.topic import Topic from slugify import slugify class ForumConverter(BaseConverter): # This regex will decide which portion of the URL is matched by the curtom # converter. By default, slashes are not included, so we must add them. regex = r'[a-z/]+' def to_python(self, url): url = '/' + url f = Forum.query.filter_by(url=url).first() if f is None: raise ValidationError(f"ForumConverter: no forum with url {url}") return f def to_url(self, forum): return forum.url[1:] class PageConverter(BaseConverter): # 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+)|/fin)?(?:/[\w-]+)?' object = None def to_python(self, url): tid, *args = url.split('/') tid = int(tid) if len(args) == 0: page = 1 elif args[0] == "fin": 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 t = self.object.query.filter_by(id=tid).first() if t is None: raise Exception(f"BaseConverter: no object with id {url}") return (t, page) def to_url(self, object_and_page): o, page = object_and_page page = str(page) if page != -1 else "fin" slug = slugify(o.title) return f'{o.id}/{page}/{slug}' class TopicPageConverter(PageConverter): object = Topic # Export only the converter classes __all__ = "ForumConverter TopicPageConverter".split()