From 00d25deb9fb9fd6653df2d53f76b04b3540b9fb9 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 4 Nov 2021 22:34:13 +0100 Subject: [PATCH] My nvidia is on fire --- .../2_structure/1_backend/1_techstack.rst | 16 ++ .../3_dev/2_structure/1_backend/2_sophon.rst | 89 ++++++++ .../3_dev/2_structure/1_backend/3_core.rst | 214 ++++++++++++++++++ .../2_structure/1_backend/4_projects.rst | 6 + .../2_structure/1_backend/5_notebooks.rst | 6 + .../3_dev/2_structure/1_backend/index.rst | 154 +------------ docs/source/3_dev/2_structure/index.rst | 2 + 7 files changed, 342 insertions(+), 145 deletions(-) create mode 100644 docs/source/3_dev/2_structure/1_backend/1_techstack.rst create mode 100644 docs/source/3_dev/2_structure/1_backend/2_sophon.rst create mode 100644 docs/source/3_dev/2_structure/1_backend/3_core.rst create mode 100644 docs/source/3_dev/2_structure/1_backend/4_projects.rst create mode 100644 docs/source/3_dev/2_structure/1_backend/5_notebooks.rst diff --git a/docs/source/3_dev/2_structure/1_backend/1_techstack.rst b/docs/source/3_dev/2_structure/1_backend/1_techstack.rst new file mode 100644 index 0000000..576a583 --- /dev/null +++ b/docs/source/3_dev/2_structure/1_backend/1_techstack.rst @@ -0,0 +1,16 @@ +Librerie e tecnologie utilizzate +-------------------------------- + +.. note:: + + Sono elencate solo le principali librerie utilizzate; dipendenze e librerie minori non sono specificate, ma sono visibili all'interno del file ``poetry.lock``. + +- Il linguaggio di programmazione `Python `_ + - Il gestore di dipendenze `Poetry `_ + - Il framework web `Django `_ + - L'estensione per Django `Django REST Framework `_ + - L'estensione per Django `Django CORS Headers `_ + - L'adattatore database per PostgreSQL `Psycopg `_ + - Il `Docker SDK for Python `_ + - I server web `Gunicorn `_ e `Uvicorn `_ + - L'utilità `lazy-object-proxy `_ diff --git a/docs/source/3_dev/2_structure/1_backend/2_sophon.rst b/docs/source/3_dev/2_structure/1_backend/2_sophon.rst new file mode 100644 index 0000000..db9b562 --- /dev/null +++ b/docs/source/3_dev/2_structure/1_backend/2_sophon.rst @@ -0,0 +1,89 @@ +Il progetto sophon +------------------ +.. default-domain:: py +.. default-role:: obj +.. module:: sophon + +Il progetto Django Sophon aggiunge varie funzionalità al template base dei progetti Django. + + +Pagina di amministrazione personalizzata +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. module:: sophon.admin + +La pagina di amministrazione viene personalizzata con la classe `SophonAdminSite`, che modifica alcuni parametri della classe base. + +Inoltre, il template predefinito viene sovrascritto da quello all'interno del file ``templates/admin/base.html``, che sostituisce il foglio di stile con uno personalizzato per Sophon. + +.. class:: SophonAdminSite(django.contrib.admin.AdminSite) + + .. attribute:: site_header = "Sophon Server Administration" + + Il nome della pagina nell'header viene modificato a *Sophon Server Administration*. + + .. attribute:: site_title = "Sophon Server Administration" + + Il titolo della pagina nell'header viene anch'esso modificato a *Sophon Server Administration*. + + .. attribute:: site_url = None + + Il collegamento *View Site* viene rimosso, in quanto è possibile accedere all'interfaccia web di Sophon da più domini contemporaneamente. + + .. attribute:: index_title = "Resources Administration" + + Il titolo dell'indice viene modificato a *Resources Administration*. + +.. class:: SophonAdminConfig(django.contrib.admin.apps.AdminConfig) + + .. attribute:: default_site = "sophon.admin.SophonAdminSite" + + `.SophonAdminSite` è selezionata come classe predefinita per il sito di amministrazione. + + +Impostazioni dinamiche +^^^^^^^^^^^^^^^^^^^^^^ +.. module:: sophon.settings + +Il file di impostazioni viene modificato per **permettere la configurazione attraverso variabili di ambiente** invece che attraverso il file ``settings.py``, rendendo il deployment con Docker molto più semplice. + +.. code-block:: python + + try: + DATABASE_ENGINE = os.environ["DJANGO_DATABASE_ENGINE"] + except KeyError: + log.warning("DJANGO_DATABASE_ENGINE was not set, defaulting to PostgreSQL") + DATABASE_ENGINE = "django.db.backends.postgresql" + log.debug(f"{DATABASE_ENGINE = }") + +Inoltre, viene configurato il modulo `logging` per emettere testo colorato di più facile comprensione usando il package `coloredlogs`. + +.. code-block:: python + + "detail": { + "()": coloredlogs.ColoredFormatter, + "format": "{asctime:>19} | {name:<24} | {levelname:>8} | {message}", + "style": "{", + } + + +Autenticazione migliorata +^^^^^^^^^^^^^^^^^^^^^^^^^ +.. module:: sophon.auth1 + +La classe `rest_framework.authentication.TokenAuthentication` viene modificata per ottenere un comportamento conforme agli standard del web. + +.. class:: BearerTokenAuthentication(rest_framework.authentication.TokenAuthentication) + + .. attribute:: keyword = "Bearer" + + Si configura `rest_framework` per accettare header di autenticazione nella forma ``Bearer ``, invece che ``Token ``. + +.. module:: sophon.auth2 + +La view `rest_framework.authtoken.views.ObtainAuthToken` viene estesa per aggiungere dati alla risposta di autenticazione riuscita. + +.. class:: CustomObtainAuthToken(rest_framework.authtoken.views.ObtainAuthToken) + + .. method:: post(self, request, *args, **kwargs) + + In particolare, viene aggiunta una chiave ``user``, che contiene i dettagli sull'utente che ha effettuato il login. diff --git a/docs/source/3_dev/2_structure/1_backend/3_core.rst b/docs/source/3_dev/2_structure/1_backend/3_core.rst new file mode 100644 index 0000000..041f3a1 --- /dev/null +++ b/docs/source/3_dev/2_structure/1_backend/3_core.rst @@ -0,0 +1,214 @@ +L'app sophon.core +----------------- +.. default-domain:: py +.. default-role:: obj +.. module:: sophon.core + + +L'app `sophon.core` è l'app principale del progetto, e non può essere disattivata, in quanto dipendenza obbligatoria di tutte le altre app. + + +Aggiunta di un nuovo comando di gestione +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. module:: sophon.core.management.commands.initsuperuser + +Per permettere l'integrazione la creazione automatica del primo :ref:`superutente` quando Sophon viene eseguito da Docker, viene introdotto il comando di gestione ``initsuperuser``. + +.. class:: Command + + Questo comando crea automaticamente un :ref:`superutente` con le credenziali specificate in :ref:`\`\`DJANGO_SU_USERNAME\`\``, :ref:`\`\`DJANGO_SU_EMAIL\`\`` e :ref:`\`\`DJANGO_SU_PASSWORD\`\``. + + +Modello base astratto +^^^^^^^^^^^^^^^^^^^^^ +.. module:: sophon.core.models + +Viene estesa la classe astratta `django.db.models.Model` con funzioni per stabilire il livello di accesso di un utente all'oggetto e per generare automaticamente i `rest_framework.serializers.ModelSerializer` in base al livello di accesso. + +.. class:: SophonModel(django.db.models.Model) + + .. method:: can_edit(self, user: django.contrib.auth.models.User) -> bool + :abstractmethod: + + Controlla se un utente può modificare l'oggetto attuale. + + :param user: L'utente da controllare. + :returns: `True` se l'utente deve poter modificare l'oggetto, altrimenti `False`. + + .. method:: can_admin(self, user: django.contrib.auth.models.User) -> bool + :abstractmethod: + + Controlla se un utente può amministrare l'oggetto attuale. + + :param user: L'utente da controllare. + :returns: `True` se l'utente deve poter amministrare l'oggetto, altrimenti `False`. + + .. classmethod:: get_fields(cls) -> set[str] + + :returns: il `set` di nomi di campi che devono essere mostrati quando viene richiesto l'oggetto attraverso l'API. + + .. classmethod:: get_editable_fields(cls) -> set[str] + + :returns: il `set` di nomi di campi di cui deve essere permessa la modifica se l'utente può modificare (`.can_edit`) l'oggetto. + + .. classmethod:: get_administrable_fields(cls) -> set[str] + + :returns: il `set` di nomi di campi di cui deve essere permessa la modifica se l'utente può amministrare (`.can_admin`) l'oggetto. + + .. classmethod:: get_creation_fields(cls) -> set[str] + + :returns: il `set` di nomi di campi che possono essere specificati dall'utente al momento della creazione dell'oggetto. + + +Modello di autorizzazione astratto +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Viene definito un nuovo modello astratto, basato su `SophonModel`, che permette di determinare i permessi dell'utente in base alla sua appartenenza al gruppo a cui è collegato l'oggetto implementatore. + +.. class:: SophonGroupModel(SophonModel) + + .. method:: get_group(self) -> ResearchGroup + :abstractmethod: + + :returns: Il gruppo a cui appartiene l'oggetto. + + .. classmethod:: get_access_to_edit(cls) -> sophon.core.enums.SophonGroupAccess + + :returns: Il livello di autorità all'interno del gruppo necessario per modificare l'oggetto. + + .. classmethod:: get_access_to_admin(cls) -> sophon.core.enums.SophonGroupAccess + + :returns: Il livello di autorità all'interno del gruppo necessario per amministrare l'oggetto. + + .. method:: get_access_serializer(self, user: User) -> typing.Type[rest_framework.serializers.ModelSerializer] + + :returns: Restituisce il `rest_framework.serializers.ModelSerializer` adeguato al livello di autorità dell'utente. + + +.. class:: sophon.core.enums.SophonGroupAccess(enum.IntEnum) + + Enumerazione che stabilisce il livello di autorità che un utente può avere all'interno di un gruppo. + + .. attribute:: NONE = 0 + + Utente :ref:`ospite`. + + .. attribute:: REGISTERED = 10 + + :ref:`Utente` registrato. + + .. attribute:: MEMBER = 50 + + Membro del :ref:`gruppo di ricerca`. + + .. attribute:: OWNER = 100 + + Creatore del :ref:`gruppo di ricerca`. + + .. attribute:: SUPERUSER = 200 + + :ref:`Superutente` con privilegi universali. + + +Modello dei dettagli dell'istanza +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Viene creato il modello che rappresenta i dettagli dell':ref:`istanza` Sophon. + +.. class:: SophonInstanceDetails(SophonModel) + + .. attribute:: id: IntegerField [1] + + Impostando ``1`` come unica scelta per il campo della chiave primaria ``id``, si crea un modello "singleton", ovvero un modello di cui può esistere un'istanza sola in tutto il database. + + .. attribute:: name: CharField + .. attribute:: description: TextField + .. attribute:: theme: CharField ["sophon", "paper", "royalblue", "hacker", "amber"] + + .. method:: version: str + :property: + + :returns: La versione installata del pacchetto `sophon`. + + .. seealso:: + + :ref:`Sophon instance details` nella guida per l'amministratore. + + +Modello del gruppo di ricerca +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. class:: ResearchGroup(SophonGroupModel) + + Modello che rappresenta un :ref:`gruppo di ricerca`. + + .. attribute:: slug: SlugField + .. attribute:: name: CharField + .. attribute:: description: TextField + .. attribute:: members: ManyToManyField → django.contrib.auth.models.User + .. attribute:: owner: ForeignKey → django.contrib.auth.models.User + .. attribute:: access: CharField ["MANUAL", "OPEN"] + + +Estensione ai permessi di Django +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. module:: sophon.core.permissions + +I permessi di `rest_framework` vengono estesi con due nuove classi che utilizzano il :ref:`modello di autorizzazione` precedentemente definito. + +.. class:: Edit(rest_framework.permissions.BasePermission) + + Consente l'interazione solo agli utenti che possono modificare (`.can_edit`) l'oggetto. + +.. class:: Admin(rest_framework.permissions.BasePermission) + + Consente l'interazione solo agli utenti che possono amministrare (`.can_admin`) l'oggetto. + + +Viewset astratte +^^^^^^^^^^^^^^^^ +.. module:: sophon.core.views + +Vengono definiti due viewset in grado di utilizzare i metodi aggiunti dalle classi astratte `.models.SophonModel` e `.models.SophonGroupModel`. + +.. class:: ReadSophonViewSet(rest_framework.viewsets.ReadOnlyModelViewSet, metaclass=abc.ABCMeta) + + Estende la classe base `rest_framework.viewsets.ReadOnlyModelViewSet` con metodi di utilità mancanti nell'implementazione originale, allacciandola inoltre a `.models.SophonGroupModel`. + + .. method:: get_queryset(self) -> QuerySet + :abstractmethod: + + Imposta come astratto (e quindi obbligatorio) il metodo `rest_framework.viewsets.ReadOnlyModelViewSet.get_queryset`. + + .. method:: permission_classes(self) + :property: + + Sovrascrive il campo di classe `rest_framework.viewsets.ReadOnlyModelViewSet.permission_classes` con una funzione, permettendone la selezione dei permessi richiesti al momento di ricezione di una richiesta HTTP (invece che al momento di definizione della classe). + + Delega la selezione delle classi a `.get_permission_classes`. + + .. method:: get_permission_classes(self) -> typing.Collection[typing.Type[permissions.BasePermission]] + + Funzione che permette la selezione dei permessi necessari per effetuare una determinata richiesta al momento di ricezione di quest'ultima. + + Utile per le classi che erediteranno da questa. + + .. method:: get_serializer_class(self) -> typing.Type[Serializer] + :final: + + Funzione che permette la selezione del `rest_framework.serializers.Serializer` da utilizzare per una determinata richiesta al momento di ricezione di quest'ultima. + + Utilizza: + + - il serializzatore **in sola lettura** per elencare gli oggetti (azione ``list``); + - il serializzatore **di creazione** per creare nuovi oggetti (azione ``create``) e per generare i metadati del viewset (azione ``metadata``); + - il serializzatore ottenuto da `.models.SophonGroupModel.get_access_serializer` per la visualizzazione dettagliata (azione ``retrieve``), la modifica (azioni ``update`` e ``partial_update``) e l'eliminazione (azione ``destroy``) di un singolo oggetto; + - il serializzatore ottenuto da `.get_custom_serializer_classes` per le azioni personalizzate. + + .. seealso:: + + `.models.SophonGroupModel` + + .. method:: get_custom_serializer_classes(self) -> t.Type[Serializer] + + Permette alle classi che ereditano da questa di selezionare quale `rest_framework.serializers.Serializer` utilizzare per le azioni personalizzate. \ No newline at end of file diff --git a/docs/source/3_dev/2_structure/1_backend/4_projects.rst b/docs/source/3_dev/2_structure/1_backend/4_projects.rst new file mode 100644 index 0000000..8f38cf7 --- /dev/null +++ b/docs/source/3_dev/2_structure/1_backend/4_projects.rst @@ -0,0 +1,6 @@ +L'app sophon.projects +----------------------- +.. default-domain:: py +.. default-role:: obj +.. module:: sophon.projects + diff --git a/docs/source/3_dev/2_structure/1_backend/5_notebooks.rst b/docs/source/3_dev/2_structure/1_backend/5_notebooks.rst new file mode 100644 index 0000000..b831918 --- /dev/null +++ b/docs/source/3_dev/2_structure/1_backend/5_notebooks.rst @@ -0,0 +1,6 @@ +L'app sophon.notebooks +---------------------- +.. default-domain:: py +.. default-role:: obj +.. module:: sophon.notebooks + diff --git a/docs/source/3_dev/2_structure/1_backend/index.rst b/docs/source/3_dev/2_structure/1_backend/index.rst index 7c2e0fe..cee31c5 100644 --- a/docs/source/3_dev/2_structure/1_backend/index.rst +++ b/docs/source/3_dev/2_structure/1_backend/index.rst @@ -4,153 +4,17 @@ Modulo backend .. default-role:: obj .. py:currentmodule:: sophon -Il *modulo backend* consiste in un server web che consente agli utenti: - -- Attraverso l'API: - - *autenticazione* e *autorizzazione* degli utenti; - - *visualizzazione*, *interazione*, *creazione*, *modifica* ed *eliminazione* di gruppi di ricerca, progetti di ricerca e notebook - - *visualizzazione* di utenti e dettagli sull'istanza Sophon. - -- Attraverso pagine web dinamiche: - - *amministrazione* dell'istanza Sophon. - -Inoltre, effettua le seguenti operazioni in risposta a determinate richieste effettuate dagli utenti: - -- *configurazione*, *avvio* e *arresto* di container Docker basati sulle immagini specificate dai notebook; -- *configurazione*, *attivazione* e *disattivazione* del servizio di proxying effettuato dal :ref:`modulo proxy`. +Il *modulo backend* consiste in un server web che espone un'API e un sito web per l'amministrazione. È collocato all'interno del repository in ``/backend``. +È formato dal package Python `sophon`, che contiene al suo interno un progetto Django, che a sua volta contiene le tre app Django `sophon.core`, `sophon.projects` e `sophon.notebooks`. -Librerie e tecnologie utilizzate --------------------------------- - -.. note:: - - Sono elencate solo le principali librerie utilizzate; dipendenze e librerie minori non sono specificate, ma sono visibili all'interno del file ``poetry.lock``. - -- Il linguaggio di programmazione `Python `_ - - Il gestore di dipendenze `Poetry `_ - - Il framework web `Django `_ - - L'estensione per Django `Django REST Framework `_ - - L'estensione per Django `Django CORS Headers `_ - - L'adattatore database per PostgreSQL `Psycopg `_ - - Il `Docker SDK for Python `_ - - I server web `Gunicorn `_ e `Uvicorn `_ - - L'utilità `lazy-object-proxy `_ - - -Struttura del modulo --------------------- - -Il modulo consiste nel package Python :mod:`sophon`, che contiene al suo interno un progetto Django, che a sua volta contiene tre app Django. - - -Il progetto `sophon` -^^^^^^^^^^^^^^^^^^^^ -.. module:: sophon - -Il progetto Django Sophon aggiunge varie funzionalità al template base dei progetti Django. - - -Pagina di amministrazione personalizzata -"""""""""""""""""""""""""""""""""""""""" - -.. module:: sophon.admin - -.. class:: SophonAdminSite(django.contrib.admin.AdminSite) - - La pagina di amministrazione viene personalizzata con la classe `SophonAdminSite`, che sovrascrive alcuni parametri della classe di default. - - Inoltre, il template predefinito viene sovrascritto da quello all'interno del file ``templates/admin/base.html``, che sostituisce il foglio di stile con uno personalizzato per Sophon. - - .. attribute:: site_header = "Sophon Server Administration" - - Il nome della pagina nell'header viene modificato a *Sophon Server Administration*. - - .. attribute:: site_title = "Sophon Server Administration" - - Il titolo della pagina nell'header viene anch'esso modificato a *Sophon Server Administration*. - - .. attribute:: site_url = None - - Il collegamento *View Site* viene rimosso, in quanto è possibile accedere all'interfaccia web di Sophon da più domini contemporaneamente. - - .. attribute:: index_title = "Resources Administration" - - Il titolo dell'indice viene modificato a *Resources Administration*. - -.. class:: SophonAdminConfig(django.contrib.admin.apps.AdminConfig) - - La configurazione di default della pagina di amministrazione viene sovrascritta da questa classe. - - .. attribute:: default_site = "sophon.admin.SophonAdminSite" - - `.SophonAdminSite` è selezionata come classe predefinita. - - -Impostazioni dinamiche -"""""""""""""""""""""" -.. module:: sophon.settings - -Il file di impostazioni viene modificato per **permettere la configurazione attraverso variabili di ambiente** invece che attraverso il file ``settings.py``, rendendo il deployment con Docker molto più semplice. - -.. code-block:: python - - try: - DATABASE_ENGINE = os.environ["DJANGO_DATABASE_ENGINE"] - except KeyError: - log.warning("DJANGO_DATABASE_ENGINE was not set, defaulting to PostgreSQL") - DATABASE_ENGINE = "django.db.backends.postgresql" - log.debug(f"{DATABASE_ENGINE = }") - -Inoltre, viene configurato il modulo `logging` per emettere testo colorato di più facile comprensione usando il package `coloredlogs`. - -.. code-block:: python - - "detail": { - "()": coloredlogs.ColoredFormatter, - "format": "{asctime:>19} | {name:<24} | {levelname:>8} | {message}", - "style": "{", - } - - -Autenticazione migliorata -""""""""""""""""""""""""" -.. module:: sophon.auth1 - -.. class:: BearerTokenAuthentication(rest_framework.authentication.TokenAuthentication) - - La classe `rest_framework.authentication.TokenAuthentication` viene modificata per ottenere un comportamento conforme agli standard del web. - - .. attribute:: keyword = "Bearer" - - Si configura `rest_framework` per accettare header di autenticazione nella forma ``Bearer ``, invece che ``Token ``. - -.. module:: sophon.auth2 - -.. class:: CustomObtainAuthToken(rest_framework.authtoken.views.ObtainAuthToken) - - La view `rest_framework.authtoken.views.ObtainAuthToken` viene estesa per aggiungere dati alla risposta di autenticazione riuscita. - - .. method:: post(self, request, *args, **kwargs) - - In particolare, viene aggiunta una chiave ``user``, che contiene i dettagli sull'utente che ha effettuato il login. - -.. todo: whoa ma io mi ero scordato di sta cosa - - -L'app `sophon.core` -^^^^^^^^^^^^^^^^^^^ -.. module:: sophon.core - - -L'app `sophon.projects` -^^^^^^^^^^^^^^^^^^^^^^^ -.. module:: sophon.projects - - -L'app `sophon.notebooks` -^^^^^^^^^^^^^^^^^^^^^^^^ -.. module:: sophon.notebooks +.. toctree:: + :maxdepth: 1 + 1_techstack + 2_sophon + 3_core + 4_projects + 5_notebooks \ No newline at end of file diff --git a/docs/source/3_dev/2_structure/index.rst b/docs/source/3_dev/2_structure/index.rst index 778dfbd..98dca12 100644 --- a/docs/source/3_dev/2_structure/index.rst +++ b/docs/source/3_dev/2_structure/index.rst @@ -3,6 +3,8 @@ Struttura del progetto Sophon è composto da quattro moduli, *backend*, *frontend*, *proxy* e *jupyter*, che interagiscono tra loro per fornire agli utenti tutti i servizi necessari. + + .. toctree:: :maxdepth: 2