Skip to content
Snippets Groups Projects
Commit aeee9f5d authored by Guillaume WANG's avatar Guillaume WANG
Browse files

update schema wish-list

parent a1dd32f4
No related branches found
No related tags found
No related merge requests found
# ce fichier en .gql sert juste a forcer VSCode a colorier correctement le langage graphQL.
# son contenu sera copie dans actions.js tout simplement
/**
* @file définit les types query et mutation, points d'entree du schéma graphQL. ce fichier est la wish list de kadabra (qui veut avoir un schema clair pour travailler sereinement sur le front)
* @author akka vodol, kadabra
*/
# hawkspar->akka ; pas clair
const RootQuery = `
# Requêtes
type Query {
# User queries de base
user(uid:ID!): User
# Group queries de base
group(uid:ID!): Group
simpleGroup(uid:ID!): SimpleGroup
metaGroup(uid:ID!): MetaGroup
# Message queries de base
message(id:ID!): Message
announcement(id:ID!): Announcement
event(id:ID!): Event
privatePost(id:ID!): PrivatePost
question(id:ID!): Question
answer(id:ID!): Answer
# Request queries de base
request(id:ID!): Request
userJoinGroupRequest(id:ID!): UserJoinGroup
groupCoauthorEventRequest(id:ID!): GroupCoauthorEvent
# Messages créés par un AuthorUnion=Group|[Group]|User
messagesFromGroup(uid:ID!): [Message]
announcementsFromGroup(uid:ID!): [Announcement]
eventsFromGroup(uid:ID!): [Event]
privatepostsFromUser(uid:ID!): [Post]
questionsFromUser(uid:ID!): [Question]
answersFromGroup(uid:ID!): [Answer]
# Messages adressés à un Group
messagesToGroup(uid:ID!): [Message]
announcementsToGroup(uid:ID!): [Announcement]
eventsToGroup(uid:ID!): [Event]
privatepostsToGroup(uid:ID!): [Post]
questionsToGroup(uid:ID!): [Question]
answersToGroup(uid:ID!): [Answer]
# Toutes les Requests auxquelles un groupe doit répondre
requestsToGroup(uid:ID!): [Request]
userJoinGroupRequestsToGroup(id:ID!): UserJoinGroup
groupCoauthorEventRequestsToGroup(id:ID!): GroupCoauthorEvent
# Tous les xxx visibles par un utilisateur
allGroups(uid:ID!): [Group]
allSimpleGroups(uid:ID!): [SimpleGroup]
allMetaGroups(uid:ID!): [MetaGroup]
allMessages(uid:ID!): [Message]
allAnnouncements(uid:ID!): [Announcement]
allEvents(uid:ID!): [Event]
# TOL
searchTOL(
givenName: String,
lastName: String,
nickname: String,
nationality: String,
school: String,
promotion: String,
groups: String,
studies: String,
sport: String,
phone: String,
mail: String,
address: String,
ip: String
): [User!]
}
`;
const RootMutation = `
# Mutations
type Mutation {
# Par rapport à un groupe donné, un user peut avoir différents niveaux de droits :
# none : aucun droit (typiquement, une connection ou l'utilisateur ne s'est pas authentifie)
# viewer : le user sait que le groupe existe et a accès aux infos de base, mais rien de plus
# member : le user est membre du groupe et a acces aux Message dont le groupe est auteur ou destinataire
# speaker : le user peut parler au nom du groupe. Il a le droit de publier des annonces et d'organiser des évènements
# admin : le user a tous les droits sur le groupe
# Viewer mutations
requestJoin(userid: ID!, groupuid: ID!): Boolean
# Member mutations
leave(userid: ID!, groupuid: ID!): Boolean
postInGroup(userid: ID!, groupuid: ID!, postContent: String)
# Speaker mutations
writeAnnouncement(
from: uid!,
to: [uid!],
title: String,
date: String,
content: String
)
writeEvent(
from: ID!,
to: [uid!],
title: String,
date: String,
content:String
)
# Admin mutations
createSubgroup(
from: ID!,
newUid: ID,
name: String!,
website: String,
description: String,
school: String
): Group
addUser(userid: ID!, groupuid: ID!): User
removeUser(userid: String!, groupuid: ID!): User
addAdmin(userid: String!, groupuid: ID!): User
removeAdmin(userid: String!, groupuid: ID!): User
editGroup(
from: String!,
name: String,
website: String,
description: String,
school: String
): Group
}
`;
\ No newline at end of file
"""
@file Définit les types spéciaux Query et Mutation, points d'entrée du schéma GraphQL.
Ce fichier est la wish-list de kadabra (qui veut avoir un schéma clair pour travailler sereinement sur le front).
@author akka vodol, kadabra
"""
type Query {
# User queries de base
user(uid:ID!): User
# Group queries de base
group(gid:ID!): Group
simpleGroup(gid:ID!): SimpleGroup
metaGroup(gid:ID!): MetaGroup
# Message queries de base
message(id:ID!): Message
announcement(id:ID!): Announcement
event(id:ID!): Event
privatePost(id:ID!): PrivatePost
question(id:ID!): Question
answer(id:ID!): Answer
# Request queries de base
request(rid:ID!): Request
userJoinGroupRequest(rid:ID!): UserJoinGroup
groupCoauthorEventRequest(rid:ID!): GroupCoauthorEvent
# Tous les Messages visibles par un utilisateur (dont le uid, et donc les autorisations, est passé par context)
allMessages: [Message]
allAnnouncements: [Announcement]
allEvents: [Event]
# Tous les Groupes visibles par un utilisateur.
# Correspondrait au sous-champ "viewerOf" de User, volontairement non-défini comme tel. Tous les autres cas de figure sont couverts par les sous-champs "<permission>Of" de User
allGroups: [Group]
# Toutes les Requests auxquelles un groupe doit répondre
requestsToGroup(gid:ID!): [Request]
userJoinGroupRequestsToGroup(gid:ID!): UserJoinGroup
groupCoauthorEventRequestsToGroup(gid:ID!): GroupCoauthorEvent
# TOL
searchTOL(
givenName: String,
lastName: String,
nickname: String,
nationality: String,
school: String,
promotion: String,
groups: String,
studies: String,
sport: String,
phone: String,
mail: String,
address: String,
ip: String
): [User!]
}
type Mutation {
"""
Par rapport à un groupe donné, un user peut avoir différents niveaux de droits :
- none : sait que le groupe existe, mais aucun autre droit (typiquement, une connection l'utilisateur ne s'est pas authentifié)
- viewer : le user a aussi accès à l'activité publique du groupe : frontpage, Q&A, liste des membres, speakers et admins
- member : le user a aussi acces à l'activité interne du groupe : les PrivatePost, ainsi que les Message dont le groupe est auteur ou destinataire
- speaker : le user peut aussi parler au nom du groupe. Il a le droit de publier des annonces et d'organiser des évènements
- admin : le user a tous les droits sur le groupe
Un des les du *graphe organique des groupes* est de finir le niveau de droit des users pour chaque groupe.
D'abord, petit tail de terminologie : les cinq niveaux de droits sont inclus les uns dans les autres (un speaker est aussi un viewer, par ex.)
- Les conditions pour qu'un user soit membre, speaker ou admin sont claires, puisque cette information est stockée directement en BDD.
- Un user non-membre est viewer du groupe G :
- s'il est membre d'un groupe immédiatement parent de G (one-edge-down visibility), ou
- s'il est membre d'un groupe faisant partie du champ "visibilityEdge" de G
- s'il est membre d'un tagroupe dont G est membre (implicit visibility-edges).
- Dans tous les autres cas, le user a le niveau de droits "none".
L'autre le du *graphe organique des groupes* est de permettre l'administration "en cascade" des groupes enfants.
Si un groupe est le parent d'un autre, alors les admins du groupe parent peuvent se clarer admins du groupe enfant. Exemples :
- BR est parent de Chocapix. L'admin de Chocapix est parti en vacances. L'admin de BR peut se clarer admin de Chocapix et faire ce qu'il a à faire, sans attendre le retour du respo Chocapix.
- Cotisants-Kès est parent de Troll'X. Troll'X fait n'importe quoi (en floodant de Messages par ex). Les admins de Cotisants-Kès (les kessiers) peuvent se clarer admin de Troll'X et stopper les dégâts.
Remarque sur speaker :
Il s'agit d'un nouveau niveau de droit par rapport à Frankiz 3.0 ; il n'est pas implémenté dans le LDAP frankiz.
Par conséquent, il est probable que, au but du moins, on impose que speaker=admin, pour pouvoir continuer à utiliser ce LDAP.
Les mutations ci-dessous sont divisées en quatre, selon le niveau de droit requis pour pouvoir les appeler.
Les Mutations concernant les *Requests* suivent à peu près toutes le schéma suivant :
- <typeAuteur>Request<NatureDeLaRequest>(auteur, destinataire, comment): Request
- accept<NatureDeLaRequest>Request(request: ID!, comment: String): Boolean
- refuse<NatureDeLaRequest>Request(request: ID!, comment: String): Boolean
- le paramètre est le rid de la Request à accepter ou refuser
- seul les admins du groupe destinataire peuvent accepter ou refuser une Request
Les Mutations concernant les *Messages* suivent à peu près toutes le schéma suivant :
- create<TypeDeMessage>(auteur, destinataire, title, content, etc.): <TypeDeMessage>
- edit<TypeDeMessage>(<typeDeMessage>ToEdit: ID!): <TypeDeMessage>
- remove<TypeDeMessage>(<typeDeMessage>ToRemove: ID!): Boolean
- = l'auteur supprime le message
- pour les Messages l'auteur est un utilisateur, seul l'auteur a le droit de remove son Message
- pour les Messages l'auteur est un groupe, n'importe quel admin du groupe (ou speaker selon le cas) a le droit de remove le Message
- censor<TypeDeMessage>(<typeDeMessage>ToCensor: ID!): Boolean
- = le groupe destinataire supprime le message
- n'importe quel admin du groupe a le droit de censurer un Message qui lui est adressé
- (le destinataire est un Group pour tous les Messages)
"""
# Viewer mutations
likeGroup(groupId: ID!): Boolean # devenir sympathisant
userParticipate(
forEvent: ID!
): Boolean
userUnparticipate(
forEvent: ID!
): Boolean
userRequestJoinGroup(toGroup: ID!, comment: String): Request
createQuestion(
toGroup: ID!,
title: String,
content: String,
): Question
editQuestion(
questionToEdit: ID!,
title: String,
content: String,
): Question
removeQuestion(
questionToRemove: ID!
): Question
# Member mutations
userLeaveGroup(groupId: ID!): Boolean
createPrivatePost(
toGroup: ID!,
title: String,
content: String
): PrivatePost
editPrivatePost(
privatePostToEdit: ID!,
title: String,
content: String
): PrivatePost
removePrivatePost(
privatePostToRemove: ID!
): PrivatePost
# Speaker mutations
writePostsSummary(forGroup: ID!, content: String): Boolean
groupRequestCoauthorEvent(
fromGroup: ID!,
toGroup: ID!,
forEvent: ID!,
comment: String
): Request
createAnnouncement(
fromGroup: ID!,
toGroups: [ID!],
title: String,
content: String,
forEvent: ID
): Announcement
editAnnouncement(
announcementToEdit: ID!,
title: String,
content: String,
forEvent: ID
): Announcement
removeAnnouncement(
announcementToRemove: ID!
): Boolean
createEvent(
fromGroup: ID!,
toGroups: [ID!],
title: String,
content: String,
location: String,
startTime: String,
endTime: String,
forAnnouncement: ID
): Event
editEvent(
eventToEdit: ID!,
title: String,
content:String,
location: String,
startTime: String,
endTime: String,
forAnnouncement: ID
): Event
removeEvent(
eventToRemove: ID!
): Boolean
createAnswer(
forQuestion: ID!,
title: String,
content: String
)
editAnswer(
answerToEdit: ID!,
title: String,
content: String
)
removeAnswer(
answerToRemove: ID!
): Boolean
# Admin mutations
createSubgroup(
fromGroup: ID!,
subGid: ID,
subName: String!,
subDescription: String,
subMail: String,
subWebsite: String,
subSchool: String
): Group
becomeAdmin(forGroup: ID!): Boolean # requiert que l'utilisateur soit admin du groupe parent de forGroup
makeAdmin(forGroup: ID!, userId: ID!): User
unmakeAdmin(forGroup: ID!, userId: ID!): User
editGroup(
forGroup: ID!,
name: String,
description: String,
mail: String,
website: String,
school: String
): Group
groupRequestJoinMetagroup(fromGroup: ID!, toMetagroup: ID!, comment: String): Request
acceptUserJoinRequest(request: ID!, comment: String): Boolean
acceptGroupJoinRequest(request: ID!, comment: String): Boolean
refuseUserJoinRequest(request: ID!, comment: String): Boolean
refuseGroupJoinRequest(request: ID!, comment: String): Boolean
censorQuestion(questionToCensor: ID!): Boolean
censorPrivatePost(privatePostToCensor: ID!): Boolean
censorAnnouncement(announcementToCensor: ID!): Boolean
censorEvent(eventToCensor: ID!): Boolean
censorAnswer(answerToCensor: ID!): Boolean
}
# Un utilisateur
"""
@file Définit les types du schéma GraphQL. Il y en a quatre catégories : User, Group, Message, Request.
Ce fichier est la wish-list de kadabra (qui veut avoir un schéma clair pour travailler sereinement sur le front).
Conseils généraux pour toute tentative d'amélioration du schéma :
- mettre un -s aux champs array [SomeType].
- ... et même aux champs union *pouvant être* des array.
- ne pas rajouter un champ si on peut prévoir qu'il ne sera jamais utilisé.
- ne pas rajouter un champ si cela complexifie trop la gestion des autorisations.
- (par exemple pour User, tous les champs doivent pouvoir être vus par toute personne ayant accès au TOL.)
- dans ce cas créer un nouveau query, tout simplement.
- respecter la convention :
- uid = user id
- gid = group id
- id = message id
- rid = request id
- choisir des noms clairs, précis, concis.
- commenter lorsque c'est pertinent, également en étant clair, précis, concis.
@author akka vodol, kadabra
"""
"""
Un utilisateur
"""
type User {
uid: ID!
......@@ -16,17 +40,22 @@ type User {
address: [String] # Adresse(s) de l'utilisateur (numero de casert par exemple)
# Ses interactions avec des groupes
groups: [SimpleGroup] # Groupes dont l'utilisateur est membre
likes: [Group] # Groupes que l'utilisateur sympathise
memberOf: [SimpleGroup] # Groupes dont l'utilisateur est membre
speakerOf: [SimpleGroup]
adminOf: [Group]
likes: [Group] # Groupes dont l'utilisateur est sympathisant (purement indicatif, pas d'influence sur les niveaux de droit)
# Les Message dont il est l'auteur
questionsFromUser: [Question] # Les seuls Messages publics où `authors` est de type User
}
"""
L'interface Group représente les deux types de groupes implémentés dans Sigma : les groupes
simples, dont les membres sont des utilisateurs, et les métagroupes, dont les membres sont
des groupes simples (tel que Federez, dont les membres incluent le BR et DaTA).
L'interface Group représente les deux types de groupes implémentés dans Sigma :
- les groupes simples, dont les membres sont des utilisateurs, et
- les métagroupes, dont les membres sont des groupes simples (tel que Federez, dont les membres incluent le BR et DaTA).
"""
interface Group {
uid: ID!
gid: ID!
createdAt: String! # Date et heure de création du groupe.
updatedAt: String! # Date et heure de mise a jour des informations du groupe.
......@@ -37,51 +66,55 @@ interface Group {
# Pour le contacter
mail: String
website: String
# Administrateurs, à contacter directement en cas de problème
admins: [User]
}
# Le groupe de base, dont les membres sont des utilisateurs : binets, Kès...
type SimpleGroup implements Group {
uid: ID!
gid: ID!
createdAt: String!
updatedAt: String!
name: String
name: String!
description: String
mail: String
website: String
# Admin, membres, sympathisants du groupe
admins: [User]
# Admins, speakers (respos com), membres, sympathisants du groupe
members: [User]
speakers: [User]
admins: [User]
likers: [User]
# Graphe organique des groupes
parent: SimpleGroup # Groupe parent
children: [SimpleGroup] # Groupes enfants
memberOfMeta: [MetaGroup]
visibilityEdge: [Group] # visible par des groupes en plus du graphe organique
visibilityEdges: [Group] # se rendre visible par des groupes en plus du graphe organique
school: String # École d'origine du groupe (pour information)
# Activité publique du groupe
announcementsFromGroup: [Announcement] # annonces écrites par le groupe
announcementsToGroup: [Announcement] # annonces adressées au groupe
eventsFromGroup: [Event]
eventsToGroup: [Event]
frontPage: String # page d'accueil du groupe, en markdown
questions: [Question]
answers: [Answer] # permet d'obtenir les questions qui ont eu une réponse
# Activité interne
announcementsFromGroup: [Announcement] # annonces écrites par le groupe
announcementsToGroup: [Announcement] # annonces adressées au groupe
eventsFromGroup: [Event]
eventsToGroup: [Event]
posts: [Post]
postsSummary: String # récapitulatif de l'activité interne du groupe, en markdown
}
# Un groupe dont les membre sont d'autres groupes
type MetaGroup implements Group {
uid: ID!
gid: ID!
createdAt: String!
updatedAt: String!
name: String
name: String!
description: String
mail: String
website: String
......@@ -90,7 +123,7 @@ type MetaGroup implements Group {
admins: [User]
members: [SimpleGroup] # Par choix de paradigme, on veut éviter d'avoir des méta-méta-groupes.
visibilityEdge: [Group] # visible par des groupes en plus du graphe organique
visibilityEdges: [Group] # se rendre visible par des groupes en plus du graphe organique
}
union AuthorUnion = Group | [Group] | User
......@@ -111,7 +144,7 @@ interface Message {
content: String!
authors: AuthorUnion
recipient: RecipientUnion # destinataire du Message. forcement (un ou plusieurs) Group
recipients: RecipientUnion # destinataire du Message. forcement (un ou plusieurs) Group
}
# Annonce effectuée par un ou plusieurs groupes.
......@@ -125,8 +158,8 @@ type Announcement implements Message {
authors: [Group]
recipients: [Group]
importance: Int # TODO: mettre un commentaire pour expliquer
views: Int # TODO mettre un commentaire pour expliquer
importance: Int # importance de cette Announcement, sur une échelle de [??] à [??] (TODO)
views: Int # nombre de vues
# Si cette Announcement annonce un événement, référence le Event. Sinon null.
forEvent: Event
......@@ -147,8 +180,8 @@ type Event implements Message {
startTime: String!
endTime: String!
# Personnes qui participent à l'événement.
participatingGroups: [Group]
# Personnes et groupes qui participent à l'événement.
participatingGroups: [Group] # contributeurs mais pas organisateurs (par ex, Fanfare à une proj' JTX)
participatingUsers: [User]
# Si cet Event a été annoncé par un Announcement, le référence. Sinon null.
......@@ -164,7 +197,7 @@ type PrivatePost implements Message {
content: String!
authors: User
recipient: Group
recipients: Group
}
# Question posée par un user à un groupe
......@@ -176,7 +209,7 @@ type Question implements Message {
content: String!
authors: User
recipient: Group
recipients: Group
# Référence la réponse donnée par le groupe à cette Question. Si pas encore répondu, null.
forAnswer: Answer
......@@ -191,38 +224,62 @@ type Answer implements Message {
content: String!
authors: Group
recipient: Group
recipients: Group # doit être le même que authors
# La question à laquelle cette Answer répond. Non-nullable bien sûr
forQuestion: Question!
}
"""
Différents types de requêtes peuvent être adressées à un groupe. Elles sont stockées en BDD en attente d'être traitées.
Par exemple (le plus évident) demander à devenir membre, mais il existe aussi d'autres cas de figure.
On peut les voir comme des Mutations potentielles : en cas de validation de la requête, des entrées de la BDD seront modifiées.
Seuls les admins d'un Group (qu'il soit Simple ou Meta) ont le droit de valider ou refuser une requête.
Les différents types implémentant Request représentent des types de requête :
- UserJoinGroup: un User demande à devenir membre d'un SimpleGroup
- GroupCoauthorEvent: un groupe demande à devenir (co-)organisateur d'un événement *déjà existant*
TODO :
Il n'y a pas de type pour représenter la réponse à une Request. A première vue on peut penser qu'on n'en a pas besoin.
Cependant il faut bien qu'un utilisateur du frontend puisse dire au serveur back qu'il souhaite valider ou refuser une Request.
Or, on a choisi de faire passer absolument toutes les communications frontend/backend par GraphQL...
Il faut donc intégrer les réponses aux Requests au schéma.
"""
# Emetteur possible d'une Request
union RequesterUnion = Group | User
interface Request {
id: ID!
message: String # court message accompagnant la demande
rid: ID!
comment: String # court message accompagnant la demande
from: RequesterUnion # Émet la demande
to: Group # Reçoit la demande
from: RequesterUnion! # Émet la demande
to: Group! # Reçoit la demande
}
# Demande d'un utilisateur désirant rejoindre le groupe.
# Un utilisateur demande à devenir membre d'un groupe (simple bien sûr).
type UserJoinGroup implements Request{
id: ID!
message: String
rid: ID!
comment: String
from: User
to: Group
from: User!
to: SimpleGroup!
}
# Un groupe simple demande à devenir membre d'un méta-groupe
type GroupJoinMetagroup implements Request{
rid: ID!
comment: String
from: SimpleGroup!
to: MetaGroup!
}
# Invite un groupe à co-organiser son événement (et pas l'inverse!)
# Un Group demande à devenir (co-)author d'un Event *déjà existant*.
type GroupCoauthorEvent implements Request{
id: ID!
message: String
rid: ID!
comment: String
from: Group # Groupe authorant l'évènement et lançant l'invitation
to: Group # Groupe récipiendaire de l'invitation à co-hoster l'événement
forEvent: Event
from: Group! # Groupe souhaitant l'évènement et lançant l'invitation
to: Group! # un des Groupes organisant l'événement (erreur sinon)
forEvent: Event!
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment