/** * @file Resolvers pour tous les types de messages * @author akka, ofacklam */ import {Group, SimpleGroup, MetaGroup} from './groups'; import {User} from './users'; import knex from '../../../db/knex_router'; import { Context } from '../typeDefs/queries'; import { ApolloError } from 'apollo-server-core'; import { GroupSet } from '../models/tools'; export abstract class Message { /** * @memberof GraphQL * @class Message * @summary Resolvers des messages * @classdesc Une classe abstraite représentant l'interface Message du schéma. * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement. * @arg {number} mid - Identifiant du message, supposé valide. * @rights dépend du type de message * @abstract */ constructor(mid: number) { this.mid = mid; this.m_dataLoaded = false; } /** * @memberof GraphQL.Message# * @function fetchData * @summary Fonction qui va chercher toutes les données sur ce message dans la BDD, si ce n'est pas déja fait. * @returns {Promise(boolean)} Renvoie true si le chargement est réussi. * @async * @protected * @abstract */ protected abstract async fetchData(): Promise<boolean> /** * Protected properties. * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD, * ce qui permet d'etre plus efficace. * La variable dataLoaded témoigne de si on est déja allés chercher les données. * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma. */ protected m_dataLoaded: boolean protected m_createdAt: string protected m_updatedAt: string protected m_title: string protected m_content: string /** * Ci-dessous les resolvers a proprement parler. */ /** * @memberof GraphQL.Message# * @function __resolveType * @summary Renvoie quel type de Message c'est * @return {string} * @rights same as message object */ __resolveType(): string { if (this instanceof Announcement) { return "Announcement"; } else if (this instanceof Event) { return "Event"; } else if (this instanceof Question) { return "Question"; } else if (this instanceof Answer) { return "Answer"; } else if (this instanceof PrivatePost) { return "PrivatePost"; } else { throw new ApolloError("Bad message type"); } } /** @rights same as message object */ mid: number; /** * @memberof GraphQL.Message# * @function createdAt * @summary Renvoie la date de création * @return {Promise(string)} * @rights same as message object * @async */ async createdAt(args, context: Context, info): Promise<string> { await this.fetchData(); return this.m_createdAt; } /** * @memberof GraphQL.Message# * @function updatedAt * @summary Renvoie la date de mise a jour * @return {Promise(string)} * @rights same as message object * @async */ async updatedAt(args, context: Context, info): Promise<string> { await this.fetchData(); return this.m_updatedAt; } /** * @memberof GraphQL.Message# * @function title * @summary Renvoie le titre du message * @return {Promise(string)} * @rights same as message object * @async */ async title(args, context: Context, info): Promise<string> { await this.fetchData(); return this.m_title; } /** * @memberof GraphQL.Message# * @function content * @summary Renvoie le contenu du message * @return {Promise(string)} * @rights same as message object * @async */ async content(args, context: Context, info): Promise<string> { await this.fetchData(); return this.m_content; } } export class Announcement extends Message { /** * @memberof GraphQL * @class Announcement * @extends GraphQL.Message * @summary Resolvers des announcements * @classdesc Une classe représentant le type Announcement du schéma. * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement. * @arg {number} mid - Identifiant du message, supposé valide. * @rights membre d'un groupe author ou d'un groupe recipient */ constructor(mid: number) { super(mid); this.m_authors = new GroupSet(); this.m_recipients = new GroupSet(); } /** * @memberof GraphQL.Announcement# * @function tryCreate * @summary Fonction qui va essayer de créer l'annonce correspondante * @arg {number} mid - Identifiant du message, sans hypothese sur la validité. * @returns {Promise(Announcement)} - Renvoie le Announcement créé, ou null en cas d'erreur. * @rights membre d'un groupe author ou d'un groupe recipient * @async * @static */ static async tryCreate(mid: number): Promise<Announcement> { let m = new Announcement(mid); if(await m.fetchData()) { return m; } return null; } /** * @memberof GraphQL.Announcement# * @function fetchData * @summary Fonction qui va chercher toutes les données sur cet announcement dans la BDD, si ce n'est pas déja fait. * @returns {Promise(boolean)} Renvoie true si le chargement est réussi. * @async * @protected */ protected async fetchData(): Promise<boolean> { if(!this.m_dataLoaded) { let data = await knex.select('created_at', 'updated_at', 'title', 'content', //'importance', 'views').from('messages_announcements').where('mid', this.mid); if (data.length > 0) { let m = data[0]; this.m_createdAt = m.created_at; this.m_updatedAt = m.updated_at; this.m_title = m.title; this.m_content = m.content; //this.m_importance = m.importance; this.m_views = m.views; this.m_dataLoaded = true; } else { return false; } //Charge les authors dans m_authors data = await knex.select('gid').from('announcements_authors').where('mid', this.mid); for(let t of data) { this.m_authors.add(t.gid); } //Charge les recipients dans m_recipients data = await knex.select('gid').from('announcements_recipients').where('mid', this.mid); for (let t of data) { this.m_authors.add(t.gid); } } return true; } /** * Protected properties. * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD, * ce qui permet d'etre plus efficace. * La variable dataLoaded témoigne de si on est déja allés chercher les données. * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma. */ protected m_importance: number protected m_views : number protected m_authors : GroupSet protected m_recipients : GroupSet /** * Ci-dessous les resolvers a proprement parler. */ /** * @memberof GraphQL.Announcement# * @function authors * @summary Renvoie les groupes auteurs * @return {Promise(Group[])} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async authors(args, context: Context, info): Promise<Group[]> { //TODO: verifier les authorisations throw "Not implemented"; await this.fetchData(); var ret:Group[]; for(let t of this.m_authors) { ret.push(new SimpleGroup(t)); } return ret; } /** * @memberof GraphQL.Announcement# * @function recipients * @summary Renvoie les groupes destinataires * @return {Promise(Group[])} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async recipients(args, context: Context, info): Promise<Group[]> { //TODO: verifier les authorisations throw "Not implemented"; await this.fetchData(); var ret: Group[]; for (let t of this.m_recipients) { ret.push(new SimpleGroup(t)); } return ret; } /** * @memberof GraphQL.Announcement# * @function importance * @summary Renvoie l'importance * @return {Promise(number)} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async importance(args, context: Context, info): Promise<number> { await this.fetchData(); return this.m_importance; } /** * @memberof GraphQL.Announcement# * @function views * @summary Renvoie le nombre de vues * @return {Promise(number)} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async views(args, context: Context, info): Promise<number> { await this.fetchData(); return this.m_views; } /** * @memberof GraphQL.Announcement# * @function forEvent * @summary Renvoie l'evenement correspondant, s'il existe * @return {Promise(Event)} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async forEvent(args, context: Context, info): Promise<Event> { let data = await knex.select('mid').from('messages_events').where('for_announcement', this.mid); if(data.length > 0) { return new Event(data[0].mid); } return null; } } export class Event extends Message { /** * @memberof GraphQL * @class Event * @extends GraphQL.Message * @summary Resolvers des events * @classdesc Une classe représentant le type Event du schéma. * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement. * @arg {number} mid - Identifiant du message, supposé valide. * @rights membre d'un groupe author ou d'un groupe recipient */ constructor(mid: number) { super(mid); } /** * @memberof GraphQL.Event# * @function tryCreate * @summary Fonction qui va essayer de créer l'evenement correspondant * @arg {number} mid - Identifiant du message, sans hypothese sur la validité. * @returns {Promise(Event)} - Renvoie le Event créé, ou null en cas d'erreur. * @rights membre d'un groupe author ou d'un groupe recipient * @async * @static */ static async tryCreate(mid: number): Promise<Event> { let m = new Event(mid); if(await m.fetchData()) { return m; } return null; } /** * @memberof GraphQL.Event# * @function fetchData * @summary Fonction qui va chercher toutes les données sur cet event dans la BDD, si ce n'est pas déja fait. * @returns {Promise(boolean)} Renvoie true si le chargement est réussi. * @async * @protected */ protected async fetchData(): Promise<boolean> { if (!this.m_dataLoaded) { let data = await knex.select('created_at', 'updated_at', 'title', 'content', 'location', 'start_time', 'end_time', 'for_announcement').from('messages_events').where('mid', this.mid); if (data.length > 0) { let m = data[0]; this.m_createdAt = m.created_at; this.m_updatedAt = m.updated_at; this.m_title = m.title; this.m_content = m.content; this.m_location = m.location; this.m_startTime = m.start_time; this.m_endTime = m.end_time; this.m_forAnnouncement = m.for_announcement; this.m_dataLoaded = true; return true; } else { return false; } } return true; } /** * Protected properties. * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD, * ce qui permet d'etre plus efficace. * La variable dataLoaded témoigne de si on est déja allés chercher les données. * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma. */ protected m_location: string protected m_startTime: string protected m_endTime: string protected m_forAnnouncement: number /** * Ci-dessous les resolvers a proprement parler. */ /** * @memberof GraphQL.Event# * @function authors * @summary Renvoie les groupes auteurs * @return {Promise(Group[])} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async authors(args, context: Context, info): Promise<Group[]> { throw "Not implemented"; /*return knex.select({ uid: 'group' }).from('group_message_relationships') .where('message', messageID).whereIn('status', ['host', 'publish']);*/ } /** * @memberof GraphQL.Event# * @function recipients * @summary Renvoie les groupes destinataires * @return {Promise(Group[])} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async recipients(args, context: Context, info): Promise<Group[]> { throw "Not implemented"; /*return knex.select({ uid: 'group' }).from('group_message_relationships') .where('message', messageID).where('status', 'recieve');*/ } /** * @memberof GraphQL.Event# * @function location * @summary Renvoie l'endroit * @return {Promise(string)} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async location(args, context: Context, info): Promise<string> { await this.fetchData(); return this.m_location; } /** * @memberof GraphQL.Event# * @function startTime * @summary Renvoie l'horaire de début * @return {Promise(string)} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async startTime(args, context: Context, info): Promise<string> { await this.fetchData(); return this.m_startTime; } /** * @memberof GraphQL.Event# * @function endTime * @summary Renvoie l'horaire de fin * @return {Promise(string)} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async endTime(args, context: Context, info): Promise<string> { await this.fetchData(); return this.m_endTime; } /** * @memberof GraphQL.Event# * @function participatingGroups * @summary Renvoie les groupes qui participent * @return {Promise(Group[])} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async participatingGroups(args, context: Context, info): Promise<Group[]> { throw "Not implemented"; } /** * @memberof GraphQL.Event# * @function participatingUsers * @summary Renvoie les users qui participent * @return {Promise(User[])} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async participatingUsers(args, context: Context, info): Promise<User[]> { throw "Not implemented"; } /** * @memberof GraphQL.Event# * @function forAnnouncement * @summary Renvoie l'announcement correspondant, s'il existe * @return {Promise(Announcement)} * @rights membre d'un groupe author ou d'un groupe recipient * @async */ async forAnnouncement(args, context: Context, info): Promise<Announcement> { await this.fetchData(); if (this.m_forAnnouncement == 0) { //what is the default ????? return null; } else { return new Announcement(this.m_forAnnouncement); } } } export class PrivatePost extends Message { /** * @memberof GraphQL * @class PrivatePost * @extends GraphQL.Message * @summary Resolvers des posts privés * @classdesc Une classe représentant le type PrivatePost du schéma. * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement. * @arg {number} mid - Identifiant du message, supposé valide. * @rights membre du groupe recipient */ constructor(mid: number) { super(mid); } /** * @memberof GraphQL.PrivatePost# * @function tryCreate * @summary Fonction qui va essayer de créer le post privé correspondant * @arg {number} mid - Identifiant du message, sans hypothese sur la validité. * @returns {Promise(PrivatePost)} - Renvoie le PrivatePost créé, ou null en cas d'erreur. * @rights membre du groupe recipient * @async * @static */ static async tryCreate(mid: number): Promise<PrivatePost> { let m = new PrivatePost(mid); if(await m.fetchData()) { return m; } return null; } /** * @memberof GraphQL.PrivatePost# * @function fetchData * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait. * @returns {Promise(boolean)} Renvoie true si le chargement est réussi. * @async * @protected */ protected async fetchData(): Promise<boolean> { if (!this.m_dataLoaded) { let data = await knex.select('created_at', 'updated_at', 'title', 'content', 'author', 'recipient').from('messages_private_posts').where('mid', this.mid); if (data.length > 0) { let m = data[0]; this.m_createdAt = m.created_at; this.m_updatedAt = m.updated_at; this.m_title = m.title; this.m_content = m.content; this.m_author = m.author; this.m_recipient = m.recipient; this.m_dataLoaded = true; return true; } else { return false; } } return true; } /** * Protected properties. * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD, * ce qui permet d'etre plus efficace. * La variable dataLoaded témoigne de si on est déja allés chercher les données. * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma. */ protected m_author: string protected m_recipient: string /** * Ci-dessous les resolvers a proprement parler. */ /** * @memberof GraphQL.PrivatePost# * @function author * @summary Renvoie le user auteur * @return {Promise(User)} * @rights membre du groupe recipient * @async */ async author(args, context: Context, info): Promise<User> { await this.fetchData(); return new User(this.m_author); } /** * @memberof GraphQL.PrivatePost# * @function recipient * @summary Renvoie le groupe destinataire * @return {Promise(Group)} * @rights membre du groupe recipient * @async */ async recipient(args, context: Context, info): Promise<Group> { await this.fetchData(); throw "Not implemented"; } } export class Question extends Message { /** * @memberof GraphQL * @class Question * @extends GraphQL.Message * @summary Resolvers des questions * @classdesc Une classe représentant le type Question du schéma. * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement. * @arg {number} mid - Identifiant du message, supposé valide. * @rights viewer du groupe recipient */ constructor(mid: number) { super(mid); } /** * @memberof GraphQL.Question# * @function tryCreate * @summary Fonction qui va essayer de créer la question correspondante * @arg {number} mid - Identifiant du message, sans hypothese sur la validité. * @returns {Promise(Question)} - Renvoie la Question créée, ou null en cas d'erreur. * @rights viewer du groupe recipient * @async * @static */ static async tryCreate(mid: number): Promise<Question> { let m = new Question(mid); if(await m.fetchData()) { return m; } return null; } /** * @memberof GraphQL.Question# * @function fetchData * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait. * @returns {Promise(boolean)} Renvoie true si le chargement est réussi. * @async * @protected */ protected async fetchData(): Promise<boolean> { if (!this.m_dataLoaded) { let data = await knex.select('created_at', 'updated_at', 'title', 'content', 'author', 'recipient').from('messages_questions').where('mid', this.mid); if (data.length > 0) { let m = data[0]; this.m_createdAt = m.created_at; this.m_updatedAt = m.updated_at; this.m_title = m.title; this.m_content = m.content; this.m_author = m.author; this.m_recipient = m.recipient; this.m_dataLoaded = true; return true; } else { return false; } } return true; } /** * Protected properties. * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD, * ce qui permet d'etre plus efficace. * La variable dataLoaded témoigne de si on est déja allés chercher les données. * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma. */ protected m_author: string protected m_recipient: string /** * Ci-dessous les resolvers a proprement parler. */ /** * @memberof GraphQL.Question# * @function author * @summary Renvoie le user auteur * @return {Promise(User)} * @rights viewer du groupe recipient * @async */ async author(args, context: Context, info): Promise<User> { await this.fetchData(); return new User(this.m_author); } /** * @memberof GraphQL.Question# * @function recipient * @summary Renvoie le groupe destinataire * @return {Promise(Group)} * @rights viewer du groupe recipient * @async */ async recipient(args, context: Context, info): Promise<Group> { await this.fetchData(); throw "Not implemented"; } /** * @memberof GraphQL.Question# * @function forAnswer * @summary Renvoie la réponse correspondante, si elle existe * @return {Promise(Answer)} * @rights viewer du groupe recipient * @async */ async forAnswer(args, context: Context, info): Promise<Answer> { let data = await knex.select('mid').from('messages_answers').where('for_question', this.mid); if (data.length > 0) { return new Answer(data[0].mid); } return null; } } export class Answer extends Message { /** * @memberof GraphQL * @class Answer * @extends GraphQL.Message * @summary Resolvers des réponses * @classdesc Une classe représentant le type Answer du schéma. * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement. * @arg {number} mid - Identifiant du message, supposé valide. * @rights viewer du groupe author */ constructor(mid: number) { super(mid); } /** * @memberof GraphQL.Answer# * @function tryCreate * @summary Fonction qui va essayer de créer la réponse correspondante * @arg {number} mid - Identifiant du message, sans hypothese sur la validité. * @returns {Promise(Answer)} - Renvoie la Answer créée, ou null en cas d'erreur. * @rights viewer du groupe author * @async * @static */ static async tryCreate(mid: number): Promise<Answer> { let m = new Answer(mid); if(await m.fetchData()) { return m; } return null; } /** * @memberof GraphQL.Answer# * @function fetchData * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait. * @returns {Promise(boolean)} Renvoie true si le chargement est réussi. * @async * @protected */ protected async fetchData(): Promise<boolean> { if (!this.m_dataLoaded) { let data = await knex.select('created_at', 'updated_at', 'title', 'content', 'recipient', //<--- WTF ???? 'for_question').from('messages_answers').where('mid', this.mid); if (data.length > 0) { let m = data[0]; this.m_createdAt = m.created_at; this.m_updatedAt = m.updated_at; this.m_title = m.title; this.m_content = m.content; this.m_author = m.recipient; this.m_forQuestion = m.for_question; this.m_dataLoaded = true; return true; } else { return false; } } return true; } /** * Protected properties. * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD, * ce qui permet d'etre plus efficace. * La variable dataLoaded témoigne de si on est déja allés chercher les données. * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma. */ protected m_author: string protected m_forQuestion: number /** * Ci-dessous les resolvers a proprement parler. */ /** * @memberof GraphQL.Answer# * @function author * @summary Renvoie le groupe auteur * @return {Promise(Group)} * @rights viewer du groupe author * @async */ async author(args, context: Context, info): Promise<Group> { await this.fetchData(); throw "Not implemented"; } /** * @memberof GraphQL.Answer# * @function forQuestion * @summary Renvoie la question correspondante * @return {Promise(Question)} * @rights viewer du groupe author * @async */ async forQuestion(args, context: Context, info): Promise<Question> { await this.fetchData(); return new Question(this.m_forQuestion); } }