diff --git a/houdini.config.js b/houdini.config.js index e86aa667dd22a62cc00862421e320a05ec723991..29e2b4dea248c43302e656de962c38c4197097c6 100644 --- a/houdini.config.js +++ b/houdini.config.js @@ -17,24 +17,9 @@ export default { } }, scalars: { - Date: { - type: 'string' - }, - DateTime: { - type: 'string' - }, Url: { type: 'string' }, - SmolStr: { - type: 'string' - }, - UUID: { - type: 'string' - }, - Identifier: { - type: 'string' - }, Base64: { type: 'string' } diff --git a/src/lib/data.ts b/src/lib/data.ts index a9cf2921b6209adffe5ca7c0913a27cc48bcd7d3..e482317c77006c9769fd8196a79fd8dfa4a02cc5 100644 --- a/src/lib/data.ts +++ b/src/lib/data.ts @@ -1,32 +1,50 @@ -// import { GetPromotionStore, UserDetailsStore } from '$houdini'; -// import { pageIterator } from '$lib/graphql/query'; +import { GetPromotionStore } from '$houdini'; +import { pageIterator } from '$lib/graphql/query'; +import type { RequestEvent } from '@sveltejs/kit'; -// type Promotion = unknown[]; +type UserId = string; +type PromoCache = { + lastUpdateMs: number; + promo: Set<UserId>; +}; -// const cache = new Map<number, Promotion>(); +const cache = new Map<number, PromoCache>(); +// 1 hour +const CACHE_DURATION_MS = 1000 * 60 * 60; -// function fetchPromotion(promotion: number) { -// return Array.fromAsync(pageIterator(event, GetPromotionStore, { promotion })); -// } +async function fetchPromotion(promotion: number, event: RequestEvent): Promise<PromoCache> { + const array = await Array.fromAsync(pageIterator(GetPromotionStore, { promotion }, event)); + return { + lastUpdateMs: new Date().getTime(), + promo: new Set(array.map((node) => node.id)) + }; +} -// export async function getPromotion(promo: number): Promise<Promotion> { -// if (cache.has(promo)) { -// return cache.get(promo)!; -// } -// const promotion = await fetchPromotion(promo); -// cache.set(promo, promotion); -// return promotion; -// } +export async function getPromotion(promo: number, event: RequestEvent): Promise<Set<UserId>> { + if (cache.has(promo)) { + const data = cache.get(promo)!; + if (new Date().getTime() - data.lastUpdateMs < CACHE_DURATION_MS) return data.promo; + } + const freshData = await fetchPromotion(promo, event); + cache.set(promo, freshData); + return freshData.promo; +} -// export async function* promotionIterator( -// min: number, -// max: number -// ): AsyncGenerator<Promotion, void, unknown> { -// for (let i = min; i <= max; i++) { -// yield getPromotion(i); -// } -// } +export async function* promotionIterator( + min: number, + max: number, + event: RequestEvent +): AsyncGenerator<UserId, void, undefined> { + for (let i = min; i <= max; i++) { + const promo = await getPromotion(i, event); + yield* promo; + } +} -// export function getPromotionRange(min: number, max: number): Promise<Promotion> { -// return Array.fromAsync(promotionIterator(min, max)); -// } +export function getPromotionRange( + min: number, + max: number, + event: RequestEvent +): Promise<Set<UserId>> { + return Array.fromAsync(promotionIterator(min, max, event)).then((array) => new Set(array)); +} diff --git a/src/lib/graphql/query.ts b/src/lib/graphql/query.ts index 7619ffb411e3d7eed205e946c1a333f07396aa57..b6dac16843f2eef2c9cdca405962a1a4ed40f726 100644 --- a/src/lib/graphql/query.ts +++ b/src/lib/graphql/query.ts @@ -22,9 +22,9 @@ export async function* pageIterator< Data extends Page<GraphQLValue>, Input extends PageArgs | GraphQLVariables >( - event: RequestEvent, queryStore: new () => QueryStore<Data, Input>, variables: Omit<Input, 'first' | 'after'>, + event: RequestEvent, pageSize = 100 ): AsyncGenerator<NodeType<Data>, void, undefined> { const store = new queryStore(); diff --git a/src/lib/graphql/schema.gql b/src/lib/graphql/schema.gql index 2bfded716899b2699ed44ca056eab67a07628e29..b601941fffcf88ca5a600728a1b603f94810faca 100644 --- a/src/lib/graphql/schema.gql +++ b/src/lib/graphql/schema.gql @@ -20,167 +20,137 @@ directive @oneOf on INPUT_OBJECT union Account = Group | User input AccountId { - id: SmolStr - uuid: UUID + id: SmolStr + uuid: UUID } type Address { - """ - # **ADMIN ONLY** - ## UUID interne de l'adresse - - Par exemple, `72c612f8-1d07-432e-8f71-60584be51f40` - """ - accountUuid: UUID! - - """ - ## Pays de l'adresse - """ - country: String! - - """ - ## Adresse postale complète de l'adresse - Formatée pour être affichée ou utilisée sur une étiquette d'envoi. - Ce champ PEUT contenir plusieurs lignes, séparées par des retours à la ligne. - Les nouvelles lignes peuvent être représentées soit par une paire retour - chariot/saut de ligne ("\r\n"), soit par un seul caractère de saut de ligne ("\n"). - """ - formatted: String! - - """ - ## Ville ou localité de l'adresse - """ - locality: String! - - """ - ## Nom de l'adresse - Le nom usuel de l'adresse s'il existe. Limite de **64** caractères. - - Par exemple, `Pyroloc` ou `Résidence "Les Estudines du Parc"`. - """ - name: String - - """ - ## Code postal de l'adresse - """ - postalCode: String! - - """ - ## Région de l'adresse - Province, de la préfecture ou région. - """ - region: String - - """ - ## Rue de l'adresse - Composante complète de l'adresse de la rue, qui PEUT inclure le numéro de la maison, - le nom de la rue, la boîte postale et des informations sur plusieurs lignes concernant - l'adresse de la rue. Ce champ PEUT contenir plusieurs lignes, séparées par des retours - à la ligne. Les nouvelles lignes peuvent être représentées soit par une paire retour - chariot/saut de ligne ("\r\n"), soit par un seul caractère de saut de ligne ("\n"). - """ - streetAddress: String! -} - -""" -Base64 [RFC4648](https://www.rfc-editor.org/rfc/rfc4648) -""" + """ + # **ADMIN ONLY** + ## UUID interne de l'adresse + + Par exemple, `72c612f8-1d07-432e-8f71-60584be51f40` + """ + accountUuid: UUID! + + """## Pays de l'adresse""" + country: String! + + """ + ## Adresse postale complète de l'adresse + Formatée pour être affichée ou utilisée sur une étiquette d'envoi. + Ce champ PEUT contenir plusieurs lignes, séparées par des retours à la ligne. + Les nouvelles lignes peuvent être représentées soit par une paire retour + chariot/saut de ligne ("\r\n"), soit par un seul caractère de saut de ligne ("\n"). + """ + formatted: String! + + """## Ville ou localité de l'adresse""" + locality: String! + + """ + ## Nom de l'adresse + Le nom usuel de l'adresse s'il existe. Limite de **64** caractères. + + Par exemple, `Pyroloc` ou `Résidence "Les Estudines du Parc"`. + """ + name: String + + """## Code postal de l'adresse""" + postalCode: String! + + """ + ## Région de l'adresse + Province, de la préfecture ou région. + """ + region: String + + """ + ## Rue de l'adresse + Composante complète de l'adresse de la rue, qui PEUT inclure le numéro de la maison, + le nom de la rue, la boîte postale et des informations sur plusieurs lignes concernant + l'adresse de la rue. Ce champ PEUT contenir plusieurs lignes, séparées par des retours + à la ligne. Les nouvelles lignes peuvent être représentées soit par une paire retour + chariot/saut de ligne ("\r\n"), soit par un seul caractère de saut de ligne ("\n"). + """ + streetAddress: String! +} + +"""Base64 [RFC4648](https://www.rfc-editor.org/rfc/rfc4648)""" scalar Base64 input BooleanFilter { - eq: Boolean! + eq: Boolean! } type BuildInfo { - ref: String - sha: String + ref: String + sha: String } -""" -Rôles dans un group -""" +"""Rôles dans un group""" enum ClaimAccess { - """ - Création - """ - CREATE + """Création""" + CREATE - """ - Suppression - """ - DELETE + """Suppression""" + DELETE - """ - Aucun - """ - NONE + """Aucun""" + NONE - """ - Lecture - """ - READ + """Lecture""" + READ - """ - Écriture - """ - WRITE + """Écriture""" + WRITE } input CreateGroup { - id: Identifier! - name: String! - type: GroupType + id: Identifier! + name: String! + type: GroupType } input CreateToken { - allowedIps: [String!] - claims: [NewTokenClaim!] - description: String! - globalAccess: ClaimAccess - id: String! + allowedIps: [String!] + claims: [NewTokenClaim!] + description: String! + globalAccess: ClaimAccess + id: String! } input CreateTraining { - fullName: String - id: Identifier! - name: String! + fullName: String + id: Identifier! + name: String! } input CreateUnixAccount { - vhost: String + vhost: String } input CreateUser { - familyName: String! - givenName: String! - password: Password - promotion: Int! - trainingId: Identifier! + familyName: String! + givenName: String! + password: Password + promotion: Int! + trainingId: Identifier! } -""" -Rôles dans un groupe -""" +"""Rôles dans un groupe""" enum CurrentGroupRole { - """ - Administrateur·trice - """ - ADMIN + """Administrateur·trice""" + ADMIN - """ - Membre du bureau - """ - BOARD_MEMBER + """Membre du bureau""" + BOARD_MEMBER - """ - Membre ordinaire - """ - MEMBER + """Membre ordinaire""" + MEMBER - """ - Président·e - """ - OWNER + """Président·e""" + OWNER } """ @@ -205,332 +175,292 @@ format, but it is always normalized to the UTC (Z) offset, e.g. scalar DateTime input DateTimeFilter { - eq: [LocalDateTime!] - gt: LocalDateTime - lt: LocalDateTime + eq: [LocalDateTime!] + gt: LocalDateTime + lt: LocalDateTime } enum FromNull { - BOOLEAN - LIST - NUMBER - OBJECT - STRING + BOOLEAN + LIST + NUMBER + OBJECT + STRING } -""" -Genre d'une personne -""" +"""Genre d'une personne""" enum Gender { - """ - Féminin - """ - FEMALE + """Féminin""" + FEMALE - """ - Masculin - """ - MALE + """Masculin""" + MALE - """ - Non binaire - """ - NON_BINARY + """Non binaire""" + NON_BINARY - """ - Inconnu - """ - UNKNOWN + """Inconnu""" + UNKNOWN } input GenderFilter { - isIn: [Gender!]! + isIn: [Gender!]! } type GlobalValues { - evenSemester: Boolean! - integration: Boolean! - schoolYear: Int! + evenSemester: Boolean! + integration: Boolean! + schoolYear: Int! } type Group { - """ - ## Groupe actif - **VRAI** si le group est encore actif. - Se traduit par une déclaration lors d'une réunion publique de l'AEIIE s'il - s'agit d'un group BdE. Les listes candidates à l'élection BdE sont actives le - temps de la campagne. - """ - active: Boolean! - - """ - ## URL de la photo de profil du groupe - Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, - JPEG ou GIF), plutôt qu'à une page Web contenant une image. - - Par exemple, `https://api.iiens.net/picture/acier2020` ou `https://api.iiens.net/picture/dupontj2042` - """ - backgroundImage: Url! - - """ - Hash de l'image d'arrière plan du groupe - """ - backgroundImageThumbnailHash: Base64! - - """ - ## Date de la création du compte du group - Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, - mesuré en UTC, et la date/heure. - """ - createdAt: DateTime! - - """ - ## Description du group - Une description plus complète que `short_description`, sans limite de caractères. - """ - description: String - - """ - ## Adresse électronique préférée de l'utilisateur. - Sa valeur DOIT être conforme à la syntaxe addr-spec de la RFC 5322 [RFC5322]. - - Par exemple, `arise@iiens.net` ou `bde@iiens.net`. - """ - email: String! - - """ - # **ADMIN ONLY** - ## Compte caché - Le compte du group sera invisible de toutes les requêtes, sauf admin si le filtre - de la requête le demande. - """ - hidden: Boolean! - - """ - ## Identifiant du group - Le nom du group normalisé (sans accents, caractères spéciaux ni espaces). - Ne peut contenir que des caractères ASCII et éventuellement des tirets pour - remplacer les espaces. - - Par exemple, `arise` ou `aeiie`. - """ - id: Identifier! - - """ - ## Nom du group - Le nom usuel du group, présenté sous forme d'acronyme ou sous forme longue. - - Par exemple, `ARISE` ou `BdE`. - """ - name: String! - - """ - ## URL de la photo de profil du groupe - Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, - JPEG ou GIF), plutôt qu'à une page Web contenant une image. - - Par exemple, `https://api.iiens.net/picture/acier2020` ou `https://api.iiens.net/picture/dupontj2042` - """ - picture: Url! - - """ - Hash de la photo de profil du groupe - """ - pictureThumbnailHash: Base64! - - """ - ## URL de la page de profil du group - Page de profil sur [www.iiens.net]. - - Par exemple, `https://www.iiens.net/eleve/acier2020` ou `https://www.iiens.net/eleve/dupontj2042` - """ - profile: Url! - - """ - ## Description courte du group - 64 caractères maximum, de quoi présenter le group succinctement. - """ - shortDescription: String - - """ - ## Type de groupe - Club, Association 1901, etc. - """ - type: GroupType! - unixAccount: UnixAccount - - """ - ## Date de la dernière mise à jour des informations relatives au group - Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, - mesuré en UTC, et la date/heure. - """ - updatedAt: DateTime! - - """ - # **ADMIN ONLY** - ## UUID interne du group - - Par exemple, `72c612f8-1d07-432e-8f71-60584be51f40` - """ - uuid: UUID! - - """ - ## URL du site perso du groupe - """ - website: Url + """ + ## Groupe actif + **VRAI** si le group est encore actif. + Se traduit par une déclaration lors d'une réunion publique de l'AEIIE s'il + s'agit d'un group BdE. Les listes candidates à l'élection BdE sont actives le + temps de la campagne. + """ + active: Boolean! + + """ + ## URL de la photo de profil du groupe + Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, + JPEG ou GIF), plutôt qu'à une page Web contenant une image. + + Par exemple, `https://api.iiens.net/picture/acier2020` ou `https://api.iiens.net/picture/dupontj2042` + """ + backgroundImage: Url! + + """Hash de l'image d'arrière plan du groupe""" + backgroundImageThumbnailHash: Base64! + + """ + ## Date de la création du compte du group + Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, + mesuré en UTC, et la date/heure. + """ + createdAt: DateTime! + + """ + ## Description du group + Une description plus complète que `short_description`, sans limite de caractères. + """ + description: String + + """ + ## Adresse électronique préférée de l'utilisateur. + Sa valeur DOIT être conforme à la syntaxe addr-spec de la RFC 5322 [RFC5322]. + + Par exemple, `arise@iiens.net` ou `bde@iiens.net`. + """ + email: String! + + """ + # **ADMIN ONLY** + ## Compte caché + Le compte du group sera invisible de toutes les requêtes, sauf admin si le filtre + de la requête le demande. + """ + hidden: Boolean! + + """ + ## Identifiant du group + Le nom du group normalisé (sans accents, caractères spéciaux ni espaces). + Ne peut contenir que des caractères ASCII et éventuellement des tirets pour + remplacer les espaces. + + Par exemple, `arise` ou `aeiie`. + """ + id: Identifier! + + """ + ## Nom du group + Le nom usuel du group, présenté sous forme d'acronyme ou sous forme longue. + + Par exemple, `ARISE` ou `BdE`. + """ + name: String! + + """ + ## URL de la photo de profil du groupe + Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, + JPEG ou GIF), plutôt qu'à une page Web contenant une image. + + Par exemple, `https://api.iiens.net/picture/acier2020` ou `https://api.iiens.net/picture/dupontj2042` + """ + picture: Url! + + """Hash de la photo de profil du groupe""" + pictureThumbnailHash: Base64! + + """ + ## URL de la page de profil du group + Page de profil sur [www.iiens.net]. + + Par exemple, `https://www.iiens.net/eleve/acier2020` ou `https://www.iiens.net/eleve/dupontj2042` + """ + profile: Url! + + """ + ## Description courte du group + 64 caractères maximum, de quoi présenter le group succinctement. + """ + shortDescription: String + + """ + ## Type de groupe + Club, Association 1901, etc. + """ + type: GroupType! + unixAccount: UnixAccount + + """ + ## Date de la dernière mise à jour des informations relatives au group + Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, + mesuré en UTC, et la date/heure. + """ + updatedAt: DateTime! + + """ + # **ADMIN ONLY** + ## UUID interne du group + + Par exemple, `72c612f8-1d07-432e-8f71-60584be51f40` + """ + uuid: UUID! + + """## URL du site perso du groupe""" + website: Url } type GroupConnection { - """ - A list of edges. - """ - edges: [GroupEdge!]! + """A list of edges.""" + edges: [GroupEdge!]! - """ - A list of nodes. - """ - nodes: [Group!]! + """A list of nodes.""" + nodes: [Group!]! - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - remainingCount: Int! + """Information to aid in pagination.""" + pageInfo: PageInfo! + remainingCount: Int! } -""" -An edge in a connection. -""" +"""An edge in a connection.""" type GroupEdge { - """ - A cursor for use in pagination - """ - cursor: String! + """A cursor for use in pagination""" + cursor: String! - """ - The item at the end of the edge - """ - node: Group! - remainingCount: Int! + """The item at the end of the edge""" + node: Group! + remainingCount: Int! } input GroupFilter { - accountUuid: UuidFilter - active: BooleanFilter - createdAt: DateTimeFilter - description: NullableTextFilter - email: TextFilter - emailVerified: BooleanFilter - hidden: BooleanFilter - id: TextFilter - name: TextFilter - or: [GroupFilter!] - shortDescription: NullableTextFilter - type: GroupTypeFilter - unixAccount: UnixAccountFilter - updatedAt: DateTimeFilter - uuid: UuidFilter - website: NullableTextFilter + accountUuid: UuidFilter + active: BooleanFilter + createdAt: DateTimeFilter + description: NullableTextFilter + email: TextFilter + emailVerified: BooleanFilter + hidden: BooleanFilter + id: TextFilter + name: TextFilter + or: [GroupFilter!] + shortDescription: NullableTextFilter + type: GroupTypeFilter + unixAccount: UnixAccountFilter + updatedAt: DateTimeFilter + uuid: UuidFilter + website: NullableTextFilter } input GroupId { - email: String - id: SmolStr - uuid: UUID + email: String + id: SmolStr + uuid: UUID } type GroupOfMember { - group: Group! - isAdmin: Boolean! - isBoardMember: Boolean! - isOwner: Boolean! - role: CurrentGroupRole! - since: Date! + group: Group! + isAdmin: Boolean! + isBoardMember: Boolean! + isOwner: Boolean! + role: CurrentGroupRole! + since: Date! } input GroupOfMemberFilter { - role: CurrentGroupRole - since: NeverDateFilter - strictRole: Boolean! = false + role: CurrentGroupRole + since: NeverDateFilter + strictRole: Boolean! = false } -""" -Rôles dans un groupe -""" +"""Rôles dans un groupe""" enum GroupRole { - """ - Administrateur·trice - """ - ADMIN + """Administrateur·trice""" + ADMIN - """ - Membre du bureau - """ - BOARD_MEMBER + """Membre du bureau""" + BOARD_MEMBER - """ - A quitté le groupe - """ - GONE + """A quitté le groupe""" + GONE - """ - Membre ordinaire - """ - MEMBER + """Membre ordinaire""" + MEMBER - """ - Président·e - """ - OWNER + """Président·e""" + OWNER } enum GroupType { - ASSOCIATION - CLUB - COMMISSION - HOME - LIST - OTHER - UNKNOWN + ASSOCIATION + CLUB + COMMISSION + HOME + LIST + OTHER + UNKNOWN } input GroupTypeFilter { - isIn: [GroupType!]! + isIn: [GroupType!]! } type Health { - db: String! + db: String! } type HistoricalGroupOfMember { - group: Group! - role: GroupRole! - since: Date! + group: Group! + role: GroupRole! + since: Date! } input HistoricalGroupOfMemberFilter { - role: GroupRole - since: NeverDateFilter - strictRole: Boolean! = false + role: GroupRole + since: NeverDateFilter + strictRole: Boolean! = false } type HistoricalMemberOfGroup { - role: GroupRole! - since: Date! - user: User! + role: GroupRole! + since: Date! + user: User! } scalar Identifier input Int16Filter { - eq: [Int!] - gt: Int - lt: Int + eq: [Int!] + gt: Int + lt: Int } input LevenshteinFilter { - threshold: Int - value: String! + threshold: Int + value: String! } """ @@ -542,161 +472,149 @@ subseconds. E.g. "2022-01-12T07:30:19.12345". scalar LocalDateTime type Mutation { - addClaims(claims: [NewTokenClaim!]!, token: TokenId!): Token! - addGroupMemberRole(group: GroupId!, role: GroupRole!, user: UserId!): HistoricalMemberOfGroup! - copyClaims(dstToken: TokenId!, srcToken: TokenId!): Token! - - """ - Création d'un groupe - """ - createGroup(group: CreateGroup!): Group! - createGroupUnixAccount(account: CreateUnixAccount!, group: GroupId!): UnixAccount! - createToken(token: CreateToken!): PlainToken! - createTraining(training: CreateTraining!): Training! - - """ - Création d'un utilisateur - ### Erreurs possibles - - `NOT_FOUND`: La formation n'existe pas. - - `ID_GENERATION_FAILURE`: L'identifiant de l'utilisateur n'a pas pu être généré. - """ - createUser(user: CreateUser!): User! - createUserUnixAccount(account: CreateUnixAccount!, user: UserId!): UnixAccount! - deleteClaims(claims: [String!], token: TokenId!): Token! - - """ - Suppression d'un groupe - ### Erreurs possibles - - `NOT_FOUND`: Le groupe n'existe pas. - """ - deleteGroup(group: GroupId!): Boolean! - deleteToken(token: TokenId!): Int! - deleteTraining(training: TrainingId!): Int! - - """ - Suppression d'un utilisateur - ### Erreurs possibles - - `NOT_FOUND`: L'utilisateur n'existe pas. - """ - deleteUser(user: UserId!): Int! - endOfIntegration: Boolean! - evenSemester: Boolean! - newYear: Int! - regenerateToken(token: TokenId!): PlainToken! - status: Int! - - """ - Mise à jour d'un groupe - ### Erreurs possibles - - `NOT_FOUND`: Le groupe n'existe pas. - """ - updateGroup(group: GroupId!, update: UpdateGroup!): Group! - updateToken(token: TokenId!, update: UpdateToken!): Token! - updateTraining(training: TrainingId!, update: UpdateTraining!): Training! - updateUnixAccount(unixAccount: UnixAccountId!, update: UpdateUnixAccount!): UnixAccount! - - """ - Mise à jour d'un utilisateur - ### Erreurs possibles - - `NOT_FOUND`: L'utilisateur ou la formation n'existe pas. - """ - updateUser(update: UpdateUser!, user: UserId!): User! + addClaims(claims: [NewTokenClaim!]!, token: TokenId!): Token! + addGroupMemberRole(group: GroupId!, role: GroupRole!, user: UserId!): HistoricalMemberOfGroup! + copyClaims(dstToken: TokenId!, srcToken: TokenId!): Token! + + """Création d'un groupe""" + createGroup(group: CreateGroup!): Group! + createGroupUnixAccount(account: CreateUnixAccount!, group: GroupId!): UnixAccount! + createToken(token: CreateToken!): PlainToken! + createTraining(training: CreateTraining!): Training! + + """ + Création d'un utilisateur + ### Erreurs possibles + - `NOT_FOUND`: La formation n'existe pas. + - `ID_GENERATION_FAILURE`: L'identifiant de l'utilisateur n'a pas pu être généré. + """ + createUser(user: CreateUser!): User! + createUserUnixAccount(account: CreateUnixAccount!, user: UserId!): UnixAccount! + deleteClaims(claims: [String!], token: TokenId!): Token! + + """ + Suppression d'un groupe + ### Erreurs possibles + - `NOT_FOUND`: Le groupe n'existe pas. + """ + deleteGroup(group: GroupId!): Boolean! + deleteToken(token: TokenId!): Int! + deleteTraining(training: TrainingId!): Int! + + """ + Suppression d'un utilisateur + ### Erreurs possibles + - `NOT_FOUND`: L'utilisateur n'existe pas. + """ + deleteUser(user: UserId!): Int! + endOfIntegration: Boolean! + evenSemester: Boolean! + newYear: Int! + regenerateToken(token: TokenId!): PlainToken! + status: Int! + + """ + Mise à jour d'un groupe + ### Erreurs possibles + - `NOT_FOUND`: Le groupe n'existe pas. + """ + updateGroup(group: GroupId!, update: UpdateGroup!): Group! + updateToken(token: TokenId!, update: UpdateToken!): Token! + updateTraining(training: TrainingId!, update: UpdateTraining!): Training! + updateUnixAccount(unixAccount: UnixAccountId!, update: UpdateUnixAccount!): UnixAccount! + + """ + Mise à jour d'un utilisateur + ### Erreurs possibles + - `NOT_FOUND`: L'utilisateur ou la formation n'existe pas. + """ + updateUser(update: UpdateUser!, user: UserId!): User! } input NeverDateFilter { - eq: [Date!] - gt: Date - lt: Date + eq: [Date!] + gt: Date + lt: Date } input NewTokenClaim { - access: ClaimAccess! - claim: String! + access: ClaimAccess! + claim: String! } input NullableDateFilter { - day: Int - eq: [Date!] - gt: Date - lt: Date - month: Int - null: Boolean + day: Int + eq: [Date!] + gt: Date + lt: Date + month: Int + null: Boolean } input NullableDateTimeFilter { - eq: [LocalDateTime!] - gt: LocalDateTime - lt: LocalDateTime - null: Boolean + eq: [LocalDateTime!] + gt: LocalDateTime + lt: LocalDateTime + null: Boolean } input NullableFilter { - null: Boolean + null: Boolean } input NullableTextFilter { - levenshtein: [LevenshteinFilter!] - like: [String!] - notLike: [String!] - null: Boolean - similar: [SimilarFilter!] + levenshtein: [LevenshteinFilter!] + like: [String!] + notLike: [String!] + null: Boolean + similar: [SimilarFilter!] } enum OrderByGroup { - CREATED_AT - ID - NAME - UPDATED_AT - UUID + CREATED_AT + ID + NAME + UPDATED_AT + UUID } enum OrderByUser { - BIRTH_DATE - CREATED_AT - FAMILY_NAME - GIVEN_NAME - ID - LAST_USED_AT - NICKNAME - PROMOTION - UPDATED_AT - UUID - YEAR -} - -""" -Information about pagination in a connection -""" + BIRTH_DATE + CREATED_AT + FAMILY_NAME + GIVEN_NAME + ID + LAST_USED_AT + NICKNAME + PROMOTION + UPDATED_AT + UUID + YEAR +} + +"""Information about pagination in a connection""" type PageInfo { - """ - When paginating forwards, the cursor to continue. - """ - endCursor: String + """When paginating forwards, the cursor to continue.""" + endCursor: String - """ - When paginating forwards, are there more items? - """ - hasNextPage: Boolean! + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! - """ - When paginating backwards, are there more items? - """ - hasPreviousPage: Boolean! + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! - """ - When paginating backwards, the cursor to continue. - """ - startCursor: String + """When paginating backwards, the cursor to continue.""" + startCursor: String } input Password { - hash: String - plain: String + hash: String + plain: String } type PlainToken { - base64: String! - raw: String! + base64: String! + raw: String! } """ @@ -704,105 +622,91 @@ Ensemble des requêtes possibles pour l'API Arise. Certaines peuvent être cachées, en fonction des permissions courantes. """ type Query { - account(account: AccountId!): Account - buildInfo: BuildInfo! - currentToken: Token! - globalsValues: GlobalValues! - group(group: GroupId!): Group - groups( - after: String - before: String - filter: GroupFilter - first: Int - last: Int - orderBy: [OrderByGroup!]! = [] - ): GroupConnection! - health: Health! - oAuthAppOwner: Account! - token(token: TokenId!): Token - tokens: [Token!]! - trainings: [Training!]! - user(user: UserId!): User - users( - after: String - before: String - filter: UserFilter - first: Int - last: Int - orderBy: [OrderByUser!]! = [] - ): UserConnection! + account(account: AccountId!): Account + buildInfo: BuildInfo! + currentToken: Token! + globalsValues: GlobalValues! + group(group: GroupId!): Group + groups(after: String, before: String, filter: GroupFilter, first: Int, last: Int, orderBy: [OrderByGroup!]! = []): GroupConnection! + health: Health! + oAuthAppOwner: Account! + token(token: TokenId!): Token + tokens: [Token!]! + trainings: [Training!]! + user(user: UserId!): User + users(after: String, before: String, filter: UserFilter, first: Int, last: Int, orderBy: [OrderByUser!]! = []): UserConnection! } input SimilarFilter { - threshold: Float - value: String! + threshold: Float + value: String! } scalar SmolStr input TextFilter { - levenshtein: [LevenshteinFilter!] - like: [String!] - notLike: [String!] - similar: [SimilarFilter!] + levenshtein: [LevenshteinFilter!] + like: [String!] + notLike: [String!] + similar: [SimilarFilter!] } type Token { - allowedIps: [String!]! - claims: [TokenClaim!]! - - """ - # **ADMIN ONLY** - ## Description du jeton - """ - description: String! - globalAccess: ClaimAccess - - """ - # **ADMIN ONLY** - ## Identifiant du jeton - """ - id: String! - - """ - # **ADMIN ONLY** - ## Hash du jeton - Standard actuel : BLAKE3 - - Par exemple, `$blake3$1ChQCR0BrfBO42AkRogZaw$+COVVpcK/ptUTSckqIdI/rFF1JdIkvk9V++z56kLNf4'` - """ - tokenHash: String! - - """ - # **ADMIN ONLY** - ## UUID interne du jeton - - Par exemple, `72c612f8-1d07-432e-8f71-60584be51f40` - """ - uuid: UUID! + allowedIps: [String!]! + claims: [TokenClaim!]! + + """ + # **ADMIN ONLY** + ## Description du jeton + """ + description: String! + globalAccess: ClaimAccess + + """ + # **ADMIN ONLY** + ## Identifiant du jeton + """ + id: String! + + """ + # **ADMIN ONLY** + ## Hash du jeton + Standard actuel : BLAKE3 + + Par exemple, `$blake3$1ChQCR0BrfBO42AkRogZaw$+COVVpcK/ptUTSckqIdI/rFF1JdIkvk9V++z56kLNf4'` + """ + tokenHash: String! + + """ + # **ADMIN ONLY** + ## UUID interne du jeton + + Par exemple, `72c612f8-1d07-432e-8f71-60584be51f40` + """ + uuid: UUID! } type TokenClaim { - access: ClaimAccess! - claim: String! + access: ClaimAccess! + claim: String! } input TokenId { - globalAccess: ClaimAccess - id: SmolStr - uuid: UUID + globalAccess: ClaimAccess + id: SmolStr + uuid: UUID } type Training { - fullName: String - id: Identifier! - name: String! - uuid: UUID! + fullName: String + id: Identifier! + name: String! + uuid: UUID! } input TrainingId { - id: SmolStr - uuid: UUID + id: SmolStr + uuid: UUID } """ @@ -818,89 +722,89 @@ entities without requiring a central allocating authority. scalar UUID type UnixAccount { - accountUuid: UUID! - uid: Int! - vhost: String - - """ - URL du site personnel de l'utilisateur + accountUuid: UUID! + uid: Int! + vhost: String - Page "perso" de l'utilisateur hébergée sur les serveurs d'ARISE. - - Par exemple, `https://acier.perso.iiens.net` - """ - website: Url + """ + URL du site personnel de l'utilisateur + + Page "perso" de l'utilisateur hébergée sur les serveurs d'ARISE. + + Par exemple, `https://acier.perso.iiens.net` + """ + website: Url } input UnixAccountFilter { - null: Boolean - uid: Int16Filter - uuid: UuidFilter - vhost: TextFilter + null: Boolean + uid: Int16Filter + uuid: UuidFilter + vhost: TextFilter } input UnixAccountId { - uid: Int - uuid: UUID + uid: Int + uuid: UUID } input UpdateGroup { - active: Boolean - description: String - email: String - emailVerified: Boolean - hidden: Boolean - id: Identifier - name: String - shortDescription: String - type: GroupType - website: Url + active: Boolean + description: String + email: String + emailVerified: Boolean + hidden: Boolean + id: Identifier + name: String + shortDescription: String + type: GroupType + website: Url } input UpdateToken { - allowedIps: [String!] - description: String - id: String + allowedIps: [String!] + description: String + id: String } input UpdateTraining { - fullName: String - name: String + fullName: String + name: String } input UpdateUnixAccount { - uid: Int - vhost: String + uid: Int + vhost: String } input UpdateUser { - aeiieMember: Boolean - birthdate: Date - diplomaYearDuration: Int - email: String - emailVerified: Boolean - extendedTrialPeriod: Boolean - familyName: String - gapYear: Int - gender: Gender - givenNameAtBirth: String - givenNameInUse: String - hidden: Boolean - id: Identifier - initialPromotion: Int - lastUsedAt: LocalDateTime - locale: String - middleName: String - nickname: String - password: Password - phoneNumber: String - phoneNumberVerified: Boolean - public: Boolean - schoolLogin: String - suspended: Boolean - trainingId: SmolStr - website: Url - zoneinfo: String + aeiieMember: Boolean + birthdate: Date + diplomaYearDuration: Int + email: String + emailVerified: Boolean + extendedTrialPeriod: Boolean + familyName: String + gapYear: Int + gender: Gender + givenNameAtBirth: String + givenNameInUse: String + hidden: Boolean + id: Identifier + initialPromotion: Int + lastUsedAt: LocalDateTime + locale: String + middleName: String + nickname: String + password: Password + phoneNumber: String + phoneNumberVerified: Boolean + public: Boolean + schoolLogin: String + suspended: Boolean + trainingId: SmolStr + website: Url + zoneinfo: String } """ @@ -911,569 +815,541 @@ scalar Url scalar Urn type User { - """ - Adresse de l'utilisateur - """ - address: Address - - """ - Adhérent de l'AEIIE - - **VRAI** si l'utilisateur est membre de l'AEIIE. **FAUX** à la création du compte. - """ - aeiieMember: Boolean! - - """ - URL de l'image d'arrière plan de l'utilisateur - - Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, - JPEG ou GIF), plutôt qu'à une page Web contenant une image. - - Par exemple, `https://api.iiens.net/picture/acier2020` - """ - backgroundImage: Url! - - """ - Hash de l'image d'arrière plan de l'utilisateur - """ - backgroundImageThumbnailHash: Base64! - - """ - Date de naissance de l'utilisateur - """ - birthdate: Date - - """ - Nom complet administratif de l'utilisateur - - Présenté sous une forme affichable, avec toutes les parties du nom, **SAUF** le surnom. - - Par exemple, `Jean Dupont` - """ - civilName: String! - - """ - Date de la création du compte de l'utilisateur - - Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, - mesuré en UTC, et la date/heure. - """ - createdAt: DateTime! - - """ - Années d'études requises jusqu'au diplôme - - Par défaut cette valeur est de 03. - """ - diplomaYearDuration: Int! - - """ - Adresse électronique de l'utilisateur - - Un alias de l'adresse électronique véritable de l'utilisateur. - À utiliser en priorité pour la création de comptes. - - Par exemple, `acier2020.e2e01581919c@alias.iiens.net`. - """ - email: String! - - """ - Adresse électronique réelle de l'utilisateur - - Sa valeur DOIT être conforme à la syntaxe addr-spec de la RFC 5322 [RFC5322]. - - Par exemple, `foo.bar@ensiie.fr` ou `dupont.jean@gmail.com`. - """ - emailForwardAddress: String - - """ - Adresse électronique de l'utilisateur vérifiée - - Vrai si l'adresse électronique préférée de l'utilisateur a été vérifiée, sinon faux. - Lorsque cette valeur d'allégation est vraie, cela signifie qu'ARISE a pris des mesures - positives pour s'assurer que l'adresse électronique était contrôlée par l'utilisateur - au moment où la vérification a été effectuée. - """ - emailVerified: Boolean! - - """ - Période d'essai étendue de l'utilisateur - - **FAUX** lors de la création du compte. - - Cette variable permet d'outrepasser le champ `restricted_access`. - """ - extendedTrialPeriod: Boolean! - - """ - Nom(s) de famille de l'utilisateur - - Notez que dans certaines cultures, les personnes peuvent avoir plusieurs noms de famille ou - aucun nom de famille ; tous peuvent être présents, les noms étant séparés par des caractères d'espacement. - - Par exemple, `Leroy` - """ - familyName: String! - - """ - Prénoms de l'utilisateur - - Tous les prénoms de l'utilisateur concaténés ensembles. - - Par exemple, `Jean Pierre-Jacques` ou `Robert` - """ - forenames: String! - - """ - Années d'étude d'écart de l'utilisateur - - Désigne des périodes de temps où un utilisateur prend une pause ou un écart par - rapport à la norme. Cela peut être causé par une année sabbatique, une année de - redoublement ou pour d'autres raisons. - - Par défaut cette valeur est de 0. - """ - gapYear: Int! - - """ - Genre de l'utilisateur - - Par défaut à `UNKNOWN`. - """ - gender: Gender! - - """ - Prénom(s) de l'utilisateur - - Notez que dans certaines cultures, les personnes peuvent avoir plusieurs prénoms ; - tous peuvent être présents, les noms étant séparés par des caractères d'espacement. - - Par exemple, `Jean` ou `Pierre Jacques` - """ - givenName: String! - - """ - Prénom(s) de naissance de l'utilisateur - - Notez que dans certaines cultures, les personnes peuvent avoir plusieurs prénoms ; - tous peuvent être présents, les noms étant séparés par des caractères d'espacement. - - Par exemple, `Jean` ou `Pierre Jacques` - """ - givenNameAtBirth: String! - - """ - Prénom(s) d'usage de l'utilisateur - - Notez que dans certaines cultures, les personnes peuvent avoir plusieurs prénoms ; - tous peuvent être présents, les noms étant séparés par des caractères d'espacement. - - Par exemple, `Jeanne` ou `Pierre Jacques` - """ - givenNameInUse: String - - """ - Groupe de l'utilisateur - """ - group(id: GroupId!): GroupOfMember - - """ - Historique des groupes de l'utilisateur - - Cet historique retrace tous les rôles que l'utilisateur à pu prendre au - sein des groups de l'école. - """ - groupHistory(filter: HistoricalGroupOfMemberFilter): [HistoricalGroupOfMember!]! - - """ - Groupes de l'utilisateur - - Les rôles passés ne seront pas renvoyés dans cette requête. - Pour cela, se référer à `group_history.` - """ - groups(filter: GroupOfMemberFilter): [GroupOfMember!]! - - """ - Compte caché - - Le compte utilisateur sera invisible de toutes les requêtes, sauf admin si le filtre - de la requête le demande. - """ - hidden: Boolean! - - """ - Identifiant de l'utilisateur - - Plus communément appelé AriseID, il est composé de 8 caractères maximum formés du nom - et du prénom, et de 4 chiffre représentant l'année d'arrivée pour arriver à un identifiant unique. - - Par exemple, `acier2020` ou `dupontj2042`. - """ - id: Identifier! - - """ - Promotion d'origine de l'utilisateur - - La promotion présupposée de l'utilisateur au moment où il rentre à l'école. - - Habituellement `année d'entrée + 3` - """ - initialPromotion: Int! - - """ - Date de la dernière activité via l'API de l'utilisateur - - Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, - mesuré en UTC, et la date/heure. - """ - lastUsedAt: DateTime - - """ - Langue - - Les paramètres régionaux de l'utilisateur, représentés par une balise de - langue BCP47 [RFC5646]. Il s'agit généralement d'un code de langue ISO 639-1 - Alpha-2 [ISO639-1] en minuscules et d'un code de pays ISO 3166-1 Alpha-2 - [ISO3166-1] en majuscules, séparés par un tiret. - - Par exemple, `en-US` ou `fr-CA`. - """ - locale: String! - - """ - Deuxième(s) prénom(s) de l'utilisateur - - Notez que dans certaines cultures, les personnes peuvent avoir plusieurs seconds prénoms ; - tous peuvent être présents, les noms étant séparés par des caractères d'espacement. - Notez également que dans certaines cultures, les seconds prénoms ne sont pas utilisés. - - Par exemple, `Robert` - """ - middleName: String - - """ - Nom complet de l'utilisateur - - Présenté sous une forme affichable, avec toutes les parties du nom, **Y COMPRIS** le surnom. - - Par exemple, `Jean "Foobar" Dupont` ou `Jean Dupont` - """ - name: String! - - """ - Surnom de l'utilisateur - - Le surnom qu'a choisi l'utilisateur. - - Par exemple, `Foobar` ou `Jean` - """ - nickname: String - - """ - Groupe courant de l'utilisateur - - Retourne le propriétaire de l'application si ce dernier est un groupe. - - Les rôles passés ne seront pas renvoyés dans cette requête. - Pour cela, se référer à `current_group_history.` - """ - oAuthGroup: GroupOfMember - - """ - Hash du mot de passe de l'utilisateur - - Standard actuel : Argon2id - - Par exemple, `$argon2id$v=19$m=19456,t=2,p=1$XMBjfqZtpEyVxZbGNjKPCg$krFvSFSL3XUr6736galD8YVmGgXpqNSc02VyLqFesPY'` - """ - passwordHash: String - - """ - Numéro de téléphone de l'utilisateur - - E.164 [E.164] est le format adopté pour ce champ. - - Par exemple, `+14255551212` ou `+5626872400`. - """ - phoneNumber: String - - """ - Numéro de téléphone de l'utilisateur vérifié - - Vrai si le numéro de téléphone de l'utilisateur a été vérifié, sinon faux. - Lorsque cette valeur d'allégation est vraie, cela signifie qu'ARISE a pris - des mesures positives pour s'assurer que ce numéro de téléphone était contrôlé - par l'utilisateur final au moment où la vérification a été effectuée. Les moyens - par lesquels un numéro de téléphone est vérifié sont spécifiques au contexte - et dépendent du cadre de confiance ou des accords contractuels dans lesquels - les parties opèrent. - """ - phoneNumberVerified: Boolean! - - """ - URL de la photo de trombinoscope de l'utilisateur - - Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, - JPEG ou GIF), plutôt qu'à une page Web contenant une image. - - Par exemple, `https://api.iiens.net/rest/v0/photo/acier2020` - """ - photo: Url - - """ - Hash de la photo de trombinoscope de l'utilisateur - """ - photoThumbnailHash: Base64 - - """ - URL de l'image de profil de l'utilisateur - - Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, - JPEG ou GIF), plutôt qu'à une page Web contenant une image. - - Par exemple, `https://api.iiens.net/picture/acier2020` - """ - picture: Url! - - """ - Hash de la photo de profil de l'utilisateur - """ - pictureThumbnailHash: Base64! - - """ - Pseudo préféré - - Pseudo abrégé non unique par lequel l'utilisateur souhaite être désigné. - - Surnom si renseigné par l'utilisateur, sinon nom civil par défaut. - - Par exemple, `Foobar` ou `dupontj2042` - """ - preferredNickname: String! - - """ - Nom d'utilisateur préféré - - Nom abrégé non unique par lequel l'utilisateur souhaite être désigné. - - Surnom si renseigné par l'utilisateur, sinon identifiant ARISE par défaut. - - Par exemple, `Foobar` ou `dupontj2042` - """ - preferredUsername: String! - - """ - URL de la page de profil de l'utilisateur - - Page de profil sur [www.iiens.net](https://www.iiens.net). - - Par exemple, `https://www.iiens.net/eleve/acier2020` - """ - profile: Url! - - """ - Promotion effective de l'utilisateur - - Promotion de l'utilisateur en tenant compte des redoublements et autres facteurs. - """ - promotion: Int! - - """ - Accès restreint aux services d'ARISE - - **VRAI** si la période d'essai est arrivée à terme (42 jours) et que l'utilisateur n'est pas - membre d'ARISE **ET** de l'AEIIE. - """ - restrictedAccess: Boolean! - - """ - Adresse électronique scolaire de l'utilisateur - - Sa valeur DOIT être conforme à la syntaxe addr-spec de la RFC 5322 [RFC5322]. - - Par exemple, `mael.acier@ensiie.eu` ou `dupont.jean@ensiie.eu`. - """ - schoolEmail: String! - - """ - Identifiant de connexion scolaire de l'utilisateur - - Habituellement sous la forme `prenom.nom` - """ - schoolLogin: String! - - """ - Semestre actuel de l'utilisateur - - Compteur de semestres en fonction de l'année de promotion effective. - Les redoublements sont pris en compte dans l'évaluation de cette valeur. - - Par exemple, `S1`, `S2`, `S3` *(Le `S` n'est pas ajouté automatiquement)* - """ - semester: Int! - - """ - Compte suspendu - - Le compte utilisateur ne sera plus utilisable pour se connecter aux services d'ARISE. - """ - suspended: Boolean! - - """ - ## Parcours - - Par exemple, "FISE", "FISA" - """ - training: Training! - - """ - Nombre de jours restants sur la période d'essai de l'utilisateur - - **42** lors de la création du compte. - """ - trialPeriodDaysLeft: Int! - - """ - Compte UNIX - """ - unixAccount: UnixAccount - - """ - Date de la dernière mise à jour des informations relatives à l'utilisateur - - Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, - mesuré en UTC, et la date/heure. - """ - updatedAt: DateTime! - - """ - UUID du compte de l'utilisateur - """ - uuid: UUID! - - """ - URL du site Web ou du blog de l'utilisateur - - Par exemple, `https://foo.com` - """ - website: Url - - """ - Année en cours de l'utilisateur - - Compteur d'années en fonction de l'année de promotion effective. - Les redoublements sont pris en compte dans l'évaluation de cette valeur. - - Par exemple, `1A`, `2A`, `3A` *(Le `A` n'est pas ajouté automatiquement)* - """ - year: Int! - - """ - Fuseau horaire - - Chaîne de caractères provenant de la base de données des fuseaux horaires zoneinfo - [zoneinfo] représentant le fuseau horaire de l'utilisateur. - - Par exemple, `Europe/Paris` ou `Amérique/Los_Angeles`. - """ - zoneinfo: String! + """Adresse de l'utilisateur""" + address: Address + + """ + Adhérent de l'AEIIE + + **VRAI** si l'utilisateur est membre de l'AEIIE. **FAUX** à la création du compte. + """ + aeiieMember: Boolean! + + """ + URL de l'image d'arrière plan de l'utilisateur + + Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, + JPEG ou GIF), plutôt qu'à une page Web contenant une image. + + Par exemple, `https://api.iiens.net/picture/acier2020` + """ + backgroundImage: Url! + + """Hash de l'image d'arrière plan de l'utilisateur""" + backgroundImageThumbnailHash: Base64! + + """Date de naissance de l'utilisateur""" + birthdate: Date + + """ + Nom complet administratif de l'utilisateur + + Présenté sous une forme affichable, avec toutes les parties du nom, **SAUF** le surnom. + + Par exemple, `Jean Dupont` + """ + civilName: String! + + """ + Date de la création du compte de l'utilisateur + + Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, + mesuré en UTC, et la date/heure. + """ + createdAt: DateTime! + + """ + Années d'études requises jusqu'au diplôme + + Par défaut cette valeur est de 03. + """ + diplomaYearDuration: Int! + + """ + Adresse électronique de l'utilisateur + + Un alias de l'adresse électronique véritable de l'utilisateur. + À utiliser en priorité pour la création de comptes. + + Par exemple, `acier2020.e2e01581919c@alias.iiens.net`. + """ + email: String! + + """ + Adresse électronique réelle de l'utilisateur + + Sa valeur DOIT être conforme à la syntaxe addr-spec de la RFC 5322 [RFC5322]. + + Par exemple, `foo.bar@ensiie.fr` ou `dupont.jean@gmail.com`. + """ + emailForwardAddress: String + + """ + Adresse électronique de l'utilisateur vérifiée + + Vrai si l'adresse électronique préférée de l'utilisateur a été vérifiée, sinon faux. + Lorsque cette valeur d'allégation est vraie, cela signifie qu'ARISE a pris des mesures + positives pour s'assurer que l'adresse électronique était contrôlée par l'utilisateur + au moment où la vérification a été effectuée. + """ + emailVerified: Boolean! + + """ + Période d'essai étendue de l'utilisateur + + **FAUX** lors de la création du compte. + + Cette variable permet d'outrepasser le champ `restricted_access`. + """ + extendedTrialPeriod: Boolean! + + """ + Nom(s) de famille de l'utilisateur + + Notez que dans certaines cultures, les personnes peuvent avoir plusieurs noms de famille ou + aucun nom de famille ; tous peuvent être présents, les noms étant séparés par des caractères d'espacement. + + Par exemple, `Leroy` + """ + familyName: String! + + """ + Prénoms de l'utilisateur + + Tous les prénoms de l'utilisateur concaténés ensembles. + + Par exemple, `Jean Pierre-Jacques` ou `Robert` + """ + forenames: String! + + """ + Années d'étude d'écart de l'utilisateur + + Désigne des périodes de temps où un utilisateur prend une pause ou un écart par + rapport à la norme. Cela peut être causé par une année sabbatique, une année de + redoublement ou pour d'autres raisons. + + Par défaut cette valeur est de 0. + """ + gapYear: Int! + + """ + Genre de l'utilisateur + + Par défaut à `UNKNOWN`. + """ + gender: Gender! + + """ + Prénom(s) de l'utilisateur + + Notez que dans certaines cultures, les personnes peuvent avoir plusieurs prénoms ; + tous peuvent être présents, les noms étant séparés par des caractères d'espacement. + + Par exemple, `Jean` ou `Pierre Jacques` + """ + givenName: String! + + """ + Prénom(s) de naissance de l'utilisateur + + Notez que dans certaines cultures, les personnes peuvent avoir plusieurs prénoms ; + tous peuvent être présents, les noms étant séparés par des caractères d'espacement. + + Par exemple, `Jean` ou `Pierre Jacques` + """ + givenNameAtBirth: String! + + """ + Prénom(s) d'usage de l'utilisateur + + Notez que dans certaines cultures, les personnes peuvent avoir plusieurs prénoms ; + tous peuvent être présents, les noms étant séparés par des caractères d'espacement. + + Par exemple, `Jeanne` ou `Pierre Jacques` + """ + givenNameInUse: String + + """Groupe de l'utilisateur""" + group(id: GroupId!): GroupOfMember + + """ + Historique des groupes de l'utilisateur + + Cet historique retrace tous les rôles que l'utilisateur à pu prendre au + sein des groups de l'école. + """ + groupHistory(filter: HistoricalGroupOfMemberFilter): [HistoricalGroupOfMember!]! + + """ + Groupes de l'utilisateur + + Les rôles passés ne seront pas renvoyés dans cette requête. + Pour cela, se référer à `group_history.` + """ + groups(filter: GroupOfMemberFilter): [GroupOfMember!]! + + """ + Compte caché + + Le compte utilisateur sera invisible de toutes les requêtes, sauf admin si le filtre + de la requête le demande. + """ + hidden: Boolean! + + """ + Identifiant de l'utilisateur + + Plus communément appelé AriseID, il est composé de 8 caractères maximum formés du nom + et du prénom, et de 4 chiffre représentant l'année d'arrivée pour arriver à un identifiant unique. + + Par exemple, `acier2020` ou `dupontj2042`. + """ + id: Identifier! + + """ + Promotion d'origine de l'utilisateur + + La promotion présupposée de l'utilisateur au moment où il rentre à l'école. + + Habituellement `année d'entrée + 3` + """ + initialPromotion: Int! + + """ + Date de la dernière activité via l'API de l'utilisateur + + Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, + mesuré en UTC, et la date/heure. + """ + lastUsedAt: DateTime + + """ + Langue + + Les paramètres régionaux de l'utilisateur, représentés par une balise de + langue BCP47 [RFC5646]. Il s'agit généralement d'un code de langue ISO 639-1 + Alpha-2 [ISO639-1] en minuscules et d'un code de pays ISO 3166-1 Alpha-2 + [ISO3166-1] en majuscules, séparés par un tiret. + + Par exemple, `en-US` ou `fr-CA`. + """ + locale: String! + + """ + Deuxième(s) prénom(s) de l'utilisateur + + Notez que dans certaines cultures, les personnes peuvent avoir plusieurs seconds prénoms ; + tous peuvent être présents, les noms étant séparés par des caractères d'espacement. + Notez également que dans certaines cultures, les seconds prénoms ne sont pas utilisés. + + Par exemple, `Robert` + """ + middleName: String + + """ + Nom complet de l'utilisateur + + Présenté sous une forme affichable, avec toutes les parties du nom, **Y COMPRIS** le surnom. + + Par exemple, `Jean "Foobar" Dupont` ou `Jean Dupont` + """ + name: String! + + """ + Surnom de l'utilisateur + + Le surnom qu'a choisi l'utilisateur. + + Par exemple, `Foobar` ou `Jean` + """ + nickname: String + + """ + Groupe courant de l'utilisateur + + Retourne le propriétaire de l'application si ce dernier est un groupe. + + Les rôles passés ne seront pas renvoyés dans cette requête. + Pour cela, se référer à `current_group_history.` + """ + oAuthGroup: GroupOfMember + + """ + Hash du mot de passe de l'utilisateur + + Standard actuel : Argon2id + + Par exemple, `$argon2id$v=19$m=19456,t=2,p=1$XMBjfqZtpEyVxZbGNjKPCg$krFvSFSL3XUr6736galD8YVmGgXpqNSc02VyLqFesPY'` + """ + passwordHash: String + + """ + Numéro de téléphone de l'utilisateur + + E.164 [E.164] est le format adopté pour ce champ. + + Par exemple, `+14255551212` ou `+5626872400`. + """ + phoneNumber: String + + """ + Numéro de téléphone de l'utilisateur vérifié + + Vrai si le numéro de téléphone de l'utilisateur a été vérifié, sinon faux. + Lorsque cette valeur d'allégation est vraie, cela signifie qu'ARISE a pris + des mesures positives pour s'assurer que ce numéro de téléphone était contrôlé + par l'utilisateur final au moment où la vérification a été effectuée. Les moyens + par lesquels un numéro de téléphone est vérifié sont spécifiques au contexte + et dépendent du cadre de confiance ou des accords contractuels dans lesquels + les parties opèrent. + """ + phoneNumberVerified: Boolean! + + """ + URL de la photo de trombinoscope de l'utilisateur + + Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, + JPEG ou GIF), plutôt qu'à une page Web contenant une image. + + Par exemple, `https://api.iiens.net/rest/v0/photo/acier2020` + """ + photo: Url + + """Hash de la photo de trombinoscope de l'utilisateur""" + photoThumbnailHash: Base64 + + """ + URL de l'image de profil de l'utilisateur + + Cette URL fait référence à un fichier image (par exemple, un fichier image PNG, + JPEG ou GIF), plutôt qu'à une page Web contenant une image. + + Par exemple, `https://api.iiens.net/picture/acier2020` + """ + picture: Url! + + """Hash de la photo de profil de l'utilisateur""" + pictureThumbnailHash: Base64! + + """ + Pseudo préféré + + Pseudo abrégé non unique par lequel l'utilisateur souhaite être désigné. + + Surnom si renseigné par l'utilisateur, sinon nom civil par défaut. + + Par exemple, `Foobar` ou `dupontj2042` + """ + preferredNickname: String! + + """ + Nom d'utilisateur préféré + + Nom abrégé non unique par lequel l'utilisateur souhaite être désigné. + + Surnom si renseigné par l'utilisateur, sinon identifiant ARISE par défaut. + + Par exemple, `Foobar` ou `dupontj2042` + """ + preferredUsername: String! + + """ + URL de la page de profil de l'utilisateur + + Page de profil sur [www.iiens.net](https://www.iiens.net). + + Par exemple, `https://www.iiens.net/eleve/acier2020` + """ + profile: Url! + + """ + Promotion effective de l'utilisateur + + Promotion de l'utilisateur en tenant compte des redoublements et autres facteurs. + """ + promotion: Int! + + """ + Accès restreint aux services d'ARISE + + **VRAI** si la période d'essai est arrivée à terme (42 jours) et que l'utilisateur n'est pas + membre d'ARISE **ET** de l'AEIIE. + """ + restrictedAccess: Boolean! + + """ + Adresse électronique scolaire de l'utilisateur + + Sa valeur DOIT être conforme à la syntaxe addr-spec de la RFC 5322 [RFC5322]. + + Par exemple, `mael.acier@ensiie.eu` ou `dupont.jean@ensiie.eu`. + """ + schoolEmail: String! + + """ + Identifiant de connexion scolaire de l'utilisateur + + Habituellement sous la forme `prenom.nom` + """ + schoolLogin: String! + + """ + Semestre actuel de l'utilisateur + + Compteur de semestres en fonction de l'année de promotion effective. + Les redoublements sont pris en compte dans l'évaluation de cette valeur. + + Par exemple, `S1`, `S2`, `S3` *(Le `S` n'est pas ajouté automatiquement)* + """ + semester: Int! + + """ + Compte suspendu + + Le compte utilisateur ne sera plus utilisable pour se connecter aux services d'ARISE. + """ + suspended: Boolean! + + """ + ## Parcours + + Par exemple, "FISE", "FISA" + """ + training: Training! + + """ + Nombre de jours restants sur la période d'essai de l'utilisateur + + **42** lors de la création du compte. + """ + trialPeriodDaysLeft: Int! + + """Compte UNIX""" + unixAccount: UnixAccount + + """ + Date de la dernière mise à jour des informations relatives à l'utilisateur + + Sa valeur est un string JSON [RFC3339] représentant le temps entre 1970-01-01T0:0:0Z, + mesuré en UTC, et la date/heure. + """ + updatedAt: DateTime! + + """UUID du compte de l'utilisateur""" + uuid: UUID! + + """ + URL du site Web ou du blog de l'utilisateur + + Par exemple, `https://foo.com` + """ + website: Url + + """ + Année en cours de l'utilisateur + + Compteur d'années en fonction de l'année de promotion effective. + Les redoublements sont pris en compte dans l'évaluation de cette valeur. + + Par exemple, `1A`, `2A`, `3A` *(Le `A` n'est pas ajouté automatiquement)* + """ + year: Int! + + """ + Fuseau horaire + + Chaîne de caractères provenant de la base de données des fuseaux horaires zoneinfo + [zoneinfo] représentant le fuseau horaire de l'utilisateur. + + Par exemple, `Europe/Paris` ou `Amérique/Los_Angeles`. + """ + zoneinfo: String! } type UserConnection { - """ - A list of edges. - """ - edges: [UserEdge!]! + """A list of edges.""" + edges: [UserEdge!]! - """ - A list of nodes. - """ - nodes: [User!]! + """A list of nodes.""" + nodes: [User!]! - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - remainingCount: Int! + """Information to aid in pagination.""" + pageInfo: PageInfo! + remainingCount: Int! } -""" -An edge in a connection. -""" +"""An edge in a connection.""" type UserEdge { - """ - A cursor for use in pagination - """ - cursor: String! + """A cursor for use in pagination""" + cursor: String! - """ - The item at the end of the edge - """ - node: User! - remainingCount: Int! + """The item at the end of the edge""" + node: User! + remainingCount: Int! } input UserFilter { - accountUuid: UuidFilter - aeiieMember: BooleanFilter - backgroundThumbnailHash: NullableFilter - birthdate: NullableDateFilter - createdAt: DateTimeFilter - diplomaYearDuration: Int16Filter - email: TextFilter - emailVerified: BooleanFilter - extendedTrialPeriod: BooleanFilter - familyName: TextFilter - gapYear: Int16Filter - gender: GenderFilter - givenName: TextFilter - givenNameAtBirth: TextFilter - givenNameInUse: NullableTextFilter - groups: UserGroupsFilter - hidden: BooleanFilter - id: TextFilter - initialPromotion: Int16Filter - lastUsedAt: NullableDateTimeFilter - locale: TextFilter - middleName: NullableTextFilter - nickname: NullableTextFilter - or: [UserFilter!] - phoneNumber: NullableTextFilter - phoneNumberVerified: BooleanFilter - photoThumbnailHash: NullableFilter - pictureThumbnailHash: NullableFilter - promotion: Int16Filter - public: BooleanFilter - restrictedAccess: BooleanFilter - schoolLogin: TextFilter - semester: Int16Filter - suspended: BooleanFilter - training: TextFilter - trialPeriodDaysLeft: Int16Filter - unixAccount: UnixAccountFilter - updatedAt: DateTimeFilter - uuid: UuidFilter - website: NullableTextFilter - year: Int16Filter - zoneinfo: TextFilter + accountUuid: UuidFilter + aeiieMember: BooleanFilter + backgroundThumbnailHash: NullableFilter + birthdate: NullableDateFilter + createdAt: DateTimeFilter + diplomaYearDuration: Int16Filter + email: TextFilter + emailVerified: BooleanFilter + extendedTrialPeriod: BooleanFilter + familyName: TextFilter + gapYear: Int16Filter + gender: GenderFilter + givenName: TextFilter + givenNameAtBirth: TextFilter + givenNameInUse: NullableTextFilter + groups: UserGroupsFilter + hidden: BooleanFilter + id: TextFilter + initialPromotion: Int16Filter + lastUsedAt: NullableDateTimeFilter + locale: TextFilter + middleName: NullableTextFilter + nickname: NullableTextFilter + or: [UserFilter!] + phoneNumber: NullableTextFilter + phoneNumberVerified: BooleanFilter + photoThumbnailHash: NullableFilter + pictureThumbnailHash: NullableFilter + promotion: Int16Filter + public: BooleanFilter + restrictedAccess: BooleanFilter + schoolLogin: TextFilter + semester: Int16Filter + suspended: BooleanFilter + training: TextFilter + trialPeriodDaysLeft: Int16Filter + unixAccount: UnixAccountFilter + updatedAt: DateTimeFilter + uuid: UuidFilter + website: NullableTextFilter + year: Int16Filter + zoneinfo: TextFilter } input UserGroupsFilter { - active: BooleanFilter - hidden: BooleanFilter - id: TextFilter - name: TextFilter - type: GroupTypeFilter - uuid: UuidFilter + active: BooleanFilter + hidden: BooleanFilter + id: TextFilter + name: TextFilter + type: GroupTypeFilter + uuid: UuidFilter } input UserId { - id: SmolStr - personalEmail: String - urn: Urn - uuid: UUID + id: SmolStr + personalEmail: String + urn: Urn + uuid: UUID } input UuidFilter { - isIn: [UUID!]! + isIn: [UUID!]! } diff --git a/src/routes/quiz/+page.server.ts b/src/routes/quiz/+page.server.ts index 19af07168aa66fd727eb7c989df84feb3e034775..d7c9432595cc12ec5ae3128cc899d56635a2f015 100644 --- a/src/routes/quiz/+page.server.ts +++ b/src/routes/quiz/+page.server.ts @@ -2,10 +2,10 @@ import { superValidate } from 'sveltekit-superforms'; import { zod } from 'sveltekit-superforms/adapters'; import { schema } from './schema'; import { fail, redirect } from '@sveltejs/kit'; -import { GetPromotionStore, UserDetailsStore } from '$houdini'; -import { pageIterator } from '$lib/graphql/query'; +import { UserDetailsStore } from '$houdini'; import { getRandomItems } from '$lib/utils'; import { GameStage, Game } from '$lib/game'; +import { getPromotion } from '$lib/data'; type Option = { value: string; @@ -18,10 +18,7 @@ export async function load(event) { if (game.state.stage === GameStage.GAME_OVER) redirect(303, '/quiz/game-over'); if (game.state.stage === GameStage.NEXT) { - const pagination = pageIterator(event, GetPromotionStore, { promotion: 2023 }); - - const promotion = await Array.fromAsync(pagination); - const all = new Set(promotion.map((p) => p.id)); + const all = await getPromotion(2023, event); const previous = new Set(game.state.history); const available = all.difference(previous);