Skip to content

Latest commit

 

History

History
195 lines (151 loc) · 8.01 KB

7-create-a-new-page.md

File metadata and controls

195 lines (151 loc) · 8.01 KB

Create A New Route

This part is probably gonna be the most technical of all simply because :

  • It assumes you are able to read the Python code of Nemo (understand it a little) and some Flask understanding.
  • We are gonna need to invent something from the ground up.

We will create 2 pages in this context :

  • A page to display a text in full. Maybe some texts would be better served as a complete unit. That's what we'll provide
  • A way to serve our tutorial as static pages over our Nemo tutorial

First : Making things more readable

Things are getting a little out of hand : the app.py is quite filled. So what we'll do before hand is divise things :

Content of corpus.py

from MyCapytain.resources.prototypes.cts.inventory import CtsTextInventoryCollection, CtsTextInventoryMetadata
from MyCapytain.resolvers.utils import CollectionDispatcher


from capitains_nautilus.cts.resolver import NautilusCTSResolver

# Setting up the collections

general_collection = CtsTextInventoryCollection()
poetry = CtsTextInventoryMetadata("poetry_collection", parent=general_collection)
poetry.set_label("Poetry", "eng")
poetry.set_label("Poésie", "fre")

priapeia = CtsTextInventoryMetadata("priapeia_collection", parent=general_collection)
priapeia.set_label("Priapeia", "eng")
priapeia.set_label("Priapées", "fre")

misc = CtsTextInventoryMetadata("id:misc", parent=general_collection)
misc.set_label("Miscellaneous", "eng")
misc.set_label("Textes Divers", "fre")
organizer = CollectionDispatcher(general_collection, default_inventory_name="id:misc")


@organizer.inventory("priapeia_collection")
def organize_my_priapeia(collection, path=None, **kwargs):
    if collection.id.startswith("urn:cts:latinLit:phi1103"):
        return True
    return False


@organizer.inventory("poetry_collection")
def organize_my_poetry(collection, path=None, **kwargs):
    # If we are not dealing with Priapeia
    if not collection.id.startswith("urn:cts:latinLit:phi1103"):
        # Textgroups have a wonderful shortcut to their editions and translations : .readableDescendants
        for text in collection.readableDescendants:
            for citation in text.citation:
                if citation.name == "line":
                    return True
    return False


# Parsing the data
resolver = NautilusCTSResolver(["corpora/additional-texts", "corpora/priapeia"], dispatcher=organizer)
resolver.parse()

Building a page that reuses Nemo code

If you have tiny texts, or texts that are meant to be displayed in full, you'll probably appreciate to have the ability to do that. Unfortunately, it is not covered by Nemo in its raw version. So what we'll do is write a new route.

Extending Nemo

The best, simplest way to build onto Nemo is to extend Nemo. We'll do that simply by creating a new extension.py file where we'll write :

from flask_nemo import Nemo

class MyNemo(Nemo):
    """ We'll write more there later """

and we'll change our app.py right now to use this thing :

# Before we had
from flask_nemo import Nemo
# Now we have
from extension import MyNemo

# ...

nemo = MyNemo(
    name="InstanceNemo",
    app=flask_app,
    # ...
)

To write our own route, we are gonna need to do few things :

  • We'll read and reuse the code of the route for the normal text (The route is r_passage).
  • We'll register the route onto Nemo

Write a new route

Because we are doing a simple copy/edit of Nemo r_passage route where passage could be empty, I'd propose the following :

from flask_nemo import Nemo
# We added all imports used by r_passage and now r_full_text
from flask import Markup, redirect, url_for
from MyCapytain.resources.prototypes.cts.inventory import CtsWorkMetadata, CtsEditionMetadata
from MyCapytain.errors import UnknownCollection
from MyCapytain.common.constants import Mimetypes


class MyNemo(Nemo):
    # We removed the `subreference` parameter of the original function
    def r_full_text(self, objectId, lang=None):
        """ Retrieve the text of the passage
        :param objectId: Collection identifier
        :type objectId: str
        :param lang: Lang in which to express main data
        :type lang: str
        :return: Template, collections metadata and Markup object representing the text
        :rtype: {str: Any}
        """
        collection = self.get_collection(objectId)
        if isinstance(collection, CtsWorkMetadata):
            editions = [t for t in collection.children.values() if isinstance(t, CtsEditionMetadata)]
            if len(editions) == 0:
                raise UnknownCollection("This work has no default edition")
            # We change the rerouting here to the name of this function
            return redirect(url_for(".r_full_text", objectId=str(editions[0].id)))
        # We kept `subreference` as None here
        text = self.get_passage(objectId=objectId, subreference=None)
        passage = self.transform(text, text.export(Mimetypes.PYTHON.ETREE), objectId)
        # We removed the self.get_siblings() : full text have no siblings !
        return {
            "template": "main::text.html",
            "objectId": objectId,
            "subreference": None,
            "collections": {
                "current": {
                    "label": collection.get_label(lang),
                    "id": collection.id,
                    "model": str(collection.model),
                    "type": str(collection.type),
                    "author": text.get_creator(lang),
                    "title": text.get_title(lang),
                    "description": text.get_description(lang),
                    "citation": collection.citation,
                    "coins": self.make_coins(collection, text, "", lang=lang)
                },
                "parents": self.make_parents(collection, lang=lang)
            },
            "text_passage": Markup(passage),
            # We made sure to change the value here to None
            "prev": None,
            "next": None
        }

The most important thing you just saw are the controller functions that are available :

  • Nemo.get_passage(objectId, subreference) calls the resolver to retrieve a passage [Doc]
  • Nemo.transform(passage_as_object, text_as_xml_etree_python_objet, objectId) calls the XSL or any transform function you'd have [Doc]
  • Nemo.get_siblings(objectId, subreference, passage_as_object) which retrieve the next and previous references [Doc]
  • Nemo.get_collection(objectId) to retrieve a Metadata collection object [Doc]

Register a route

Once we have done that, we can add this as a route : Nemo takes its routes from the static property Nemo.ROUTES. We are gonna copy it and add our own new fancy route :

class MyNemo(Nemo):

    ROUTES = Nemo.ROUTES + [("/text/<objectId>/full", "r_full_text", ["GET"])]

The route description is written in a tuple where elements :

  1. is a flask route description
  2. is the name of the function it should lead to
  3. is a list of methods it responds to

Last thing last : add a link to it somewhere

To add the link, I simply went to the template templates/collection.html and added a nice little link :

<a class="card-link" href="{{url_for('.r_full_text', objectId=coll.id)}}">Full Text</a>