-
Notifications
You must be signed in to change notification settings - Fork 0
Deleghe, Permessi e Livelli di Accesso
Schema riassuntivo: https://gist.github.com/AlfioEmanueleFresta/832b210c0cdccd336ab1
E' estremamente importante tenere questo documento aggiornato.
- Elenco Costanti
- Sicurezza e Protezione
- Guide alla creazione:
In questa sezione sono documentati i Permessi che derivano da ogni delega.
-
PRESIDENTE (Sede)
- GESTIONE_SOCI per tutti i membri della Sede
- GESTIONE_ATTIVITA_SEDE per la Sede
- GESTIONE_CORSI_SEDE per la Sede
-
UFFICIO_SOCI (Sede)
- GESTIONE_SOCI per tutti i membri della Sede
-
REFERENTE_ATTIVITA (Attivita)
- GESTIONE_ATTIVITA per l'Attivita
In questa sezione sono documentati i vari Permessi e la relativa espansione in Livelli di Accesso.
-
GESTIONE_SEDE (QuerySet{Sede}) Permette la modifica dei dati di locazione, contatto e preferenze di una data Sede.
- MODIFICA per la sede Selezionata
- MODIFICA per tutte le Sedi sottostanti
-
GESTIONE_SOCI (QuerySet{Sede}) Permette la modifica dei membri direttamente annessi alle Sedi selezionate. Permette inoltre la lettura dei membri estesi presso le Sedi selezionate.
- MODIFICA per tutti i membri diretti delle Sedi
- LETTURA per tutti i membri estesi presso le Sedi
-
ELENCHI_SOCI (QuerySet{Sede}) Permette la lettura degli Elenchi soci. Permette la lettura degli elenchi soci delle Sedi sottostanti.
- LETTURA per tutti i membri diretti delle Sedi
- LETTURA per tutti i membri estesi presso le Sedi
- LETTURA per tutti i membri diretti e estesi presso le Sedi sottostanti.
-
GESTIONE_ATTIVITA_SEDE (QuerySet{Sede})
- COMPLETO per tutte le attivita' della sede
- LETTURA per tutti i membri che partecipano alle attivita' della Sede
-
GESTIONE_ATTIVITA_AREA (QuerySet{Sede})
- COMPLETO per tutte le attivita' dell'Area
- LETTURA per tutti i membri che partecipano alle attivita' dell'Area
-
GESTIONE_ATTIVITA (QuerySet{Attivita})
- MODIFICA per l'attivita' selezionata
- LETTURA per tutti i membri che hanno partecipazioni, confermate o meno, alla attivita' selezionata
-
GESTIONE_CORSI_SEDE (QuerySet{Sede})
- COMPLETO per tutti i Corsi organizzati dalla Sede
- MODIFICA per tutti gli Aspiranti iscritti ai Corsi dela Sede
- LETTURA per tutti i Soci iscritti ai Corsi del Comitato
-
GESTIONE_CORSO (QuerySet{Corso})
- MODIFICA per il Corso selezionato
- MODIFICA per tutti gli Aspiranti iscritti al Corso selezionato
- LETTURA per tutti i Soci iscritti al Corso selezionato
Questa sezione contiene importanti informazioni relative ai metodi di protezione delle pagine, utilizzando il concetto dei permessi e livelli di accesso sopra elencati.
I nuovi metodi per la protezione delle pagine, basate sui permessi, vanno a sostituire i vecchi metodi di Gaia, basate sulle deleghe, similari a:
paginaApp(APP_PRESIDENTE);
paginaAPP([APP_PRESIDENTE, APP_UFFICIOSOCI]);
In Jorvik, le pagine private, protette con il decoratore
@pagina_privata
possono utilizzare il parametro permessi=
per indicare un permesso che deve essere posseduto per accedere alla pagina.
Se il permesso non è posseduto ed attuale, l'utente viene rediretto alla pagina ERRORE_PERMESSI (/errore/permessi/
).
Es.:
@pagina_privata(permessi=ELENCHI_SOCI)
def us_elenchi(request, me):
contesto = {
msg: me.nome_completo + " ha i permessi di elenco soci"
}
return 'us_elenchi.html', contesto
E' possibile passare un elenco (lista o tupla) di valori al parametro permessi
del decoratore @pagina_privata
. In questo caso, tutti i permessi devono essere posseduti dall'utente al fine di poter accedere alla pagina.
Es.:
@pagina_privata(permessi=(ELENCHI_SOCI, GESTIONE_COMITATO))
def presidente_info_comitato(request, me):
contesto = {
msg: me.nome_completo + " ha i permessi di elenco soci, e anche di gestione comitato"
}
return 'presidente_info_comitato.html', contesto
Se per qualsiasi motivo si vuole controllare se l'utente ha dei permessi, ad esempio per visualizzare o meno dei pulsanti, e' possibile effettuare il controllo utilizzando la funzione:
-
Persona.ha_permesso (permesso, al_giorno=date.today())
- Argomenti
- permesso è il permesso che si vuole controllare. Vedi l'elenco in testa a questa pagina.
- al_giorno (Opzionale) e' il giorno in cui si vuole controllare che la Persona abbia il permesso. Default e' oggi.
- La funzione ritorna True se il permesso è posseduto ed attuale, False altrimenti.
- Argomenti
Es.:
@pagina_privata(permessi=ELENCHI_SOCI)
def us_elenchi(request, me):
pulsante_link = "/fai-qualcosa-come-ufficio-soci/"
if me.ha_permesso(GESTIONE_COMITATO):
pulsante_link = "/fai-qualcosa-come-presidente/"
contesto = {
pulsante_testo: "Fai qualcosa",
pulsante_link: pulsante_link
}
return 'us_elenchi.html', contesto
In varie situazioni si può desiderare ottenere un elenco di oggetti sui quali si ha permesso di agire. Ad esempio, nell'ambito dell'Ufficio Soci, è possibile desiderare di recuperare l'elenco delle Sedi (Comitati) per i quali si ha permesso di ELENCHI_SOCI.
Questo è permesso dalla funzione:
-
Persona.oggetti_permesso (permesso, al_giorno=date.today())
- Argomenti
- permesso è il permesso che si vuole controllare. Vedi l'elenco in testa a questa pagina.
- al_giorno (Opzionale) e' il giorno in cui si vuole controllare che la Persona abbia il permesso. Default e' oggi.
- La funzione ritorna un QuerySet, pronto all'elaborazione, che contiene tutti gli oggetti per i quali la persona possiede il permesso specificato.
- Argomenti
Es.:
@pagina_privata(permessi=ELENCHI_SOCI)
def us_elenchi(request, me):
sedi = me.oggetti_permesso(ELENCHI_SOCI)
contesto = {
sedi: sedi
}
return 'us_elenchi.html', contesto
{% extends 'base_vuota.html` %}
{% block pagina_principale %}
<h2>Elenco delle Sedi</h2>
<p>Clicca su una Sede per visionare l'elenco dei Membri.</p>
<ul>
{% for sede in sedi %}
<li>
{{ sede.nome_completo }}
<a href="/us/elenchi/{{ sede.pk }}/">
Vedi elenco
</a>
</li>
{% empty %}
<li>Nessuna sede.</li>
{% endfor %}
</ul>
{% endblock %}
I livelli di accesso possono essere utilizzati per controllare, per un singolo oggetto, se si hanno i permessi o meno di effettuare delle determinate operazioni (es. lettura, modifica, eliminazione).
Questo va a sosituzione dei vecchi metodi inconsistenti, in Gaia, sui modelli:
$me->puoModificare($attivita);
$attivita->modificabileDa($me);
$oggetto->modificabileDa($me);
Un controllo binario rapido puo' essere fatto per verificare che un utente abbia un livello minimo di permessi su di un determinato oggetto. Ad esempio, e' possibile verificare, in testa alla pagina che permette la modifica della scheda di un socio, che l'utente attuale disponga effettivamente dei permessi per la modifica dell'anagrafica.
Questo puo' essere fatto con la funzione:
-
Persona.permessi_almeno (oggetto, minimo, al_giorno=date.today())
- Argomenti
- oggetto e' l'oggetto per il quale si vogliono controllare i permessi,
- minimo e' il livello minimo che si intende testare, es. MODIFICA. Un intero, tra NESSUNO, LETTURA, MODIFICA, ..., COMPLETO.
- al_giorno (Opzionale) e' il giorno in cui si vuole controllare che la Persona abbia il permesso. Default e' oggi.
- La funzione ritorna True se i permessi sono esistenti per l'oggetto e di livello pari ad almeno quanto specificato in
minimo
, False altrimenti.-
Nota bene: Alcuni oggetti sono di natura pubblica, quindi sempre leggibili. Per controllare o modificare i livelli minimi per ogni tipologia di oggetto, fare riferimento al dizionario
PERMESSI_MINIMO
inanagrafica/permessi/costanti.py
.
-
Nota bene: Alcuni oggetti sono di natura pubblica, quindi sempre leggibili. Per controllare o modificare i livelli minimi per ogni tipologia di oggetto, fare riferimento al dizionario
- Argomenti
Es.:
@pagina_privata(permessi=GESTIONE_SOCI)
def us_modifica_socio(request, me):
socio = get_object_or_404(Persona, pk=request.GET['id'])
# Controllo dei permessi
if not me.permessi_almeno(socio, MODIFICA):
return redirect(ERRORE_PERMESSI)
contesto = {
socio: socio
}
return 'us_modifica_socio.html', contesto
Se non si vuole fare un controllo binario, ma si vuole controllare esattamente che livello di accesso un utente abbia su un determinato contenuto, e' possibile utilizzare la funzione:
-
Persona.permessi (oggetto, minimo, al_giorno=date.today())
- Argomenti
- oggetto e' l'oggetto per il quale si vogliono controllare i permessi,
- al_giorno (Opzionale) e' il giorno in cui si vuole controllare che la Persona abbia il permesso. Default e' oggi.
- La funzione ritorna un valore intero tra NESSUNO, LETTURA, MODIFICA, ..., COMPLETO. Se il permesso non è esistente, viene ritornato il valore minimo per la categoria di oggetti. A scopo esemplificativo, i Commenti sono di natura pubblica, quindi passando un oggetto di tipo Commento per
oggetto
, non si otterrà mai un valore minore a LETTURA.-
Nota bene, per controllare o modificare i livelli minimi per ogni tipologia di oggetto, fare riferimento al dizionario
PERMESSI_MINIMO
inanagrafica/permessi/costanti.py
. -
IMPORTANTE, alcuni oggetti possono specificare le proprie costanti di livello. E' bene utilizzare sempre operatori non esatti (es.
>=
e<=
quando si ha a che fare con i livelli di permessi).
-
Nota bene, per controllare o modificare i livelli minimi per ogni tipologia di oggetto, fare riferimento al dizionario
- Argomenti
Es.:
@pagina_privata(permessi=ELENCHI_SOCI)
def us_scheda_socio(request, me):
socio = get_object_or_404(Persona, pk=request.GET['id'])
# Controllo dei permessi minimi
if not me.permessi_almeno(socio, LETTURA):
return redirect(ERRORE_PERMESSI)
# Controllo dei permessi aggiuntivi
permessi = me.permessi(socio)
posso_cancellare = False
posso_modificare = False
if permessi >= COMPLETO:
posso_cancellare = True
posso_modificare = True
if permessi >= MODIFICA:
posso_modificare = True
contesto = {
socio: socio
posso_cancellare: posso_cancellare,
posso_modificare: posso_modificare
}
return 'us_scheda_socio.html', contesto
-
In
anagrafica/permessi/applicazioni.py
1. Creare una costante ed assegnarvi un valore di due caratteri, es.UFFICIO_SOCI = 'US'
2. Assegnare un nome alla delega creata, modificando `PERMESSI_NOMI`, es.
```python
PERMESSI_NOMI = (
...,
(UFFICIO_SOCI, "Ufficio Soci"),
)
```
3. Assegnare [uno slug](https://en.wikipedia.org/wiki/Semantic_URL#Slug), modificando `APPLICAZIONI_SLUG`, es.
```python
APPLICAZIONI_SLUG = (
...,
(UFFICIO_SOCI, "ufficio-soci"),
)
```
-
In
anagrafica/permessi/costanti.py
1. Assegnare una tipo di oggetto alla Delega. Ad esempio, si è delegati Ufficio Soci di una Sede (Comitato). In modo diverso, ad esempio, si è referenti di una Attività. Es.DELEGHE_OGGETTI = ( ..., # Notasi che il secondo parametro è una Stringa, pari al nome del modello assegnato, # piuttosto che una referenza al modello. Questo è voluto e necessario, al fine di # evitare referenze circolari (oh, python...). (UFFICIO_SOCI, 'Sede'), )
-
In
anagrafica/permessi/funzioni.py
1. Creare una funzione che restituisca i permessi che scaturiscono dalla delega creata. Es.def permessi_ufficio_soci(sede): """ Permessi della delega di UFFICIO SOCI. :param sede: Sede di cui si e' ufficio soci. :return: Lista di permessi. """ from anagrafica.models import Sede return [ (GESTIONE_SOCI, Sede.objects.filter(pk=sede.pk)), (ELENCHI_SOCI, sede.esplora()), ]
Notasi che:
- La funzione deve aver nome di tipo
permessi_{nome_delega}
- La funzione accetta un solo parametro. Questo è un oggetto del tipo specificato al punto (2).
- La funzione ritorna una lista di tuple, nel formato
(Permesso, QuerySetOggetti)
.- Il Permesso è una costante tra i permessi dichiarati in
anagrafica/permessi/costanti.py
- Il QuerySet è l'elenco degli oggetti sui quali è valido il permesso.
- Il tipo di modello del QuerySet deve essere concorde da quello aspettato dal Permesso, specificato e verificabile in
PERMESSI_OGGETTI
all'interno dianagrafica/permessi/costanti.py
- Il tipo di modello del QuerySet deve essere concorde da quello aspettato dal Permesso, specificato e verificabile in
- La lista deve essere elencata in ordine dal permesso più vasto a quello più restrittivo.
- Il Permesso è una costante tra i permessi dichiarati in
- Gli import dei modelli necessari deve essere fatto internamente alla funzione, piuttosto che in testa al file (per evitare referenze circolari).
-
IMPORTANTE La funzione non deve effettuare operazioni sul database (hit), ma ritornare solo oggetti QuerySet che non sono ancora stati elaborati. Altrimenti, le performance dell'intero sistema potrebbero essere seriamente compromesse.
2. Aggiungere la funzione a
PERMESSI_FUNZIONI
per la relativa Delega creata. Es.
PERMESSI_FUNZIONI = ( ..., (UFFICIO_SOCI, permessi_ufficio_soci), # Il secondo parametro è il nome della funzione # sopra creata, SENZA parantesi o argomenti. )
- La funzione deve aver nome di tipo
-
Finito. Verificarne il funzionamento. * Se adeguato, creare un test in
anagrafica/tests.py
.
Seguendo questi punti è possibile creare un nuovo permesso (es. ELENCHI_SOCI
) ed assegnarvi dei relativi livelli di permesso su degli oggetti in Jorvik.
-
In
anagrafica/permessi/costanti.py
1. Creare una costante di permesso ed assegnarvi lo stesso nome come stringa, per valore, es.ELENCHI_SOCI = "ELENCHI_SOCI"
2. Aggiungere la tipologia di QuerySet di input per i permessi in `PERMESSI_OGGETTI`. Ad esempio, `ELENCHI_SOCI` agisce su un elenco di Sedi (Comitati) per i quali si hanno i permessi di gestire gli elenchi. Al contrario, `GESTIONE_ATTIVITA` agisce direttamente su un elenco di attività che si possono gestire.
```python
PERMESSI_OGGETTI = (
...,
# Notasi che il secondo parametro è una Stringa, pari al nome del modello assegnato,
# piuttosto che una referenza al modello. Questo è voluto e necessario, al fine di
# evitare referenze circolari (oh, python...).
(ELENCHI_SOCI, 'Sede')
)
```
-
In
anagrafica/permessi/espansioni.py
1. Creare una funzione che restituisca i livelli di permesso che scaturiscono dal permesso creato. Es.def espandi_elenchi_soci(qs_sedi, al_giorno=date.today()): from anagrafica.models import Persona, Appartenenza, Sede return [ # 1. Modifica su tutti i membri diretti delle Sedi sulle quali si ha il permesso (MODIFICA, Persona.objects.filter(Appartenenza.query_attuale(al_giorno=al_giorno, sede__in=qs_sedi, membro__in=Appartenenza.MEMBRO_DIRETTO).via("appartenenze"))), # 2. Lettura su tutti i membri estesi delle Sedi sulle quali si ha il permesso (LETTURA, Persona.objects.filter(Appartenenza.query_attuale(al_giorno=al_giorno, sede__in=qs_sedi, membro__in=Appartenenza.MEMBRO_ESTESO).via("appartenenze"))), # 3. Lettura su tutti i membri delle Sedi figlie di quelle sulle quali si ha il permesso (LETTURA, Persona.objects.filter(Appartenenza.query_attuale(al_giorno=al_giorno, sede__in=Sede.objects.get_queryset_descendants(qs_sedi, include_self=True)).via("appartenenze"))), ]
Notasi che:
- La funzione deve aver nome di tipo
espandi_{nome_permesso}
- La funzione accetta esattamente due parametri.
- Il primo è il QuerySet contenente gli oggetti sui quali si ha il permesso. In questo esempio, è l'elenco delle Sedi per le quali si ha il permesso di ELENCO_SOCI. Questo parametro è un oggetto queryset del modello specificato al punto (1.2).
- Il secondo deve avere firma
al_giorno=date.today()
ed è relativo al momento in cui vengono controllati i permessi.- Se applicabile, gli elenchi degli oggetti devono essere ottenuti tenendo conto del momento della verifica dei permessi.
- Se non applicabile, il parametro deve comunque essere mantenuto in firma, ma può essere non utilizzato nel corpo della funzione.
- La funzione ritorna una lista di tuple, nel formato
(Livello, QuerySetOggetti)
.- Il Livello è una costante intera tra quelle dichiarate in
anagrafica/permessi/costanti.py
(es. LETTURA, ..., COMPLETO) - Il QuerySet è l'elenco degli oggetti per i quali, al livello di permesso corrispondente, viene dato accesso dal permesso creato.
- Gli oggetti ritornati possono essere DI QUALUNQUE TIPO.
- La lista deve essere elencata in ordine dal livello più vasto (in termine di numeri di oggetti aspettati) a quello più restrittivo, per motivi di performance.
- Il Livello è una costante intera tra quelle dichiarate in
- Gli import dei modelli necessari deve essere fatto internamente alla funzione, piuttosto che in testa al file (per evitare referenze circolari).
- IMPORTANTE La funzione non deve effettuare operazioni sul database (hit), ma ritornare solo oggetti QuerySet che non sono ancora stati elaborati. Altrimenti, le performance dell'intero sistema potrebbero essere seriamente compromesse.
- La funzione deve aver nome di tipo
-
Finito. Verificarne il funzionamento. * Se adeguato, creare un test in
anagrafica/tests.py
.