diff --git a/.gitignore b/.gitignore index 5e522f55230586043cddad095cc97aaa28902fb1..7d955d7bb1191986e53978d6b935bba3e590b88d 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ typings/ doc/ build/ tsbuild/ +db/dev.sqlite3 # Config files ldap_credentials.json diff --git a/db/migrations/20181110192012_create_messages_announcements.js b/db/migrations/20181110192012_create_messages_announcements.js index 654dd0e687d26d46ba63ad7b7dac773b88ced71b..db6cfd16116bba2da5db7d370d649e8fc61ab619 100644 --- a/db/migrations/20181110192012_create_messages_announcements.js +++ b/db/migrations/20181110192012_create_messages_announcements.js @@ -8,6 +8,8 @@ exports.up = function (knex, Promise) { table.text('content'); table.integer('views').defaultTo(0); + /* + Les auteurs et destinataires des annonces sont dans les tables announcements_authors et announcements_recipients table.string('recipient',128).notNullable().defaultTo('noone') .references('gid').inTable('groups') .onDelete('SET DEFAULT'); //if recipient is deleted, direct to the special "no-one" group @@ -15,6 +17,7 @@ exports.up = function (knex, Promise) { table.string('author',128).notNullable() .references('gid').inTable('groups') .onDelete('CASCADE'); //delete message if author is deleted + */ /* we cannot declare this column yet, as table 'message_events' is not yet created. diff --git a/db/migrations/20181110192431_create_messages_events.js b/db/migrations/20181110192431_create_messages_events.js index 35ed0fa6d1c2c61b65cd1be317c699b67f782a70..c1ac334c0af15d7c05aeb93136081248d01db0aa 100644 --- a/db/migrations/20181110192431_create_messages_events.js +++ b/db/migrations/20181110192431_create_messages_events.js @@ -10,19 +10,23 @@ exports.up = function (knex, Promise) { table.dateTime('start_time').notNullable(); table.dateTime('end_time').notNullable(); //TODO: add a CHECK (https://www.postgresql.org/docs/current/ddl-constraints.html) that start_time < end_time + /* + Les auteurs et destinataires des évenements sont dans les tables events_authors et events_recipients table.string('recipient',128).notNullable().defaultTo('noone') .references('gid').inTable('groups') .onDelete('SET DEFAULT'); //if recipient is deleted, direct to the special "no-one" group //TODO: for now, we support only 1 author (where as graphql schema indicates support for [Group] authors) + table.string('author',128).notNullable() .references('gid').inTable('groups') .onDelete('CASCADE'); //delete message if author is deleted + */ table.integer('for_announcement') .references('mid').inTable('messages_announcements') .onDelete('SET NULL'); - //TODO: add support for participatingGroups and participatingUsers from the graphql schema + //participatingGroups and participatingUsers from the graphql schema are in tables `events_participating_groups` and `events_participating_users` }).then(() => { //update 'announcements' table by adding the 'for_event' column diff --git a/db/migrations/20190310155826_create_events_participating_groups.js b/db/migrations/20190310155826_create_events_participating_groups.js new file mode 100644 index 0000000000000000000000000000000000000000..fc3038c63920fe229b192b87ae5acb9c62ce065f --- /dev/null +++ b/db/migrations/20190310155826_create_events_participating_groups.js @@ -0,0 +1,18 @@ + +exports.up = function(knex, Promise) { + return knex.schema.createTable('events_participating_groups', function (table) { + table.increments('id'); //autoincrementing (non-nullable) primary key + + table.integer('mid').notNullable() + .references('mid').inTable('messages_events') + .onDelete('CASCADE'); //if event is deleted, also delete from participating_groups + + table.string('gid', 128).notNullable() + .references('gid').inTable('groups') + .onDelete('CASCADE'); //if group is deleted, also delete it as a participating group + }); +}; + +exports.down = function(knex, Promise) { + return knex.schema.dropTable('events_participating_groups'); +}; diff --git a/db/migrations/20190310155843_create_events_participating_users.js b/db/migrations/20190310155843_create_events_participating_users.js new file mode 100644 index 0000000000000000000000000000000000000000..0ccfb4592971b760240cb4be7853acaf1b52176d --- /dev/null +++ b/db/migrations/20190310155843_create_events_participating_users.js @@ -0,0 +1,16 @@ + +exports.up = function(knex, Promise) { + return knex.schema.createTable('events_participating_users', function (table) { + table.increments('id'); //autoincrementing (non-nullable) primary key + + table.integer('mid').notNullable() + .references('mid').inTable('messages_events') + .onDelete('CASCADE'); //if event is deleted, also delete from participating_groups + + table.string('uid', 128).notNullable(); // Must refer to a user id + }); +}; + +exports.down = function(knex, Promise) { + return knex.schema.dropTable('events_participating_users'); +}; diff --git a/db/seeds/04_dummy_announcements.js b/db/seeds/04_dummy_announcements.js index 66d5a412a9cc3e2fa2414f06258f462411465835..81ceea5715ac60a7817834190c58eae97063ba4d 100644 --- a/db/seeds/04_dummy_announcements.js +++ b/db/seeds/04_dummy_announcements.js @@ -4,37 +4,35 @@ exports.seed = async function (knex, Promise) { await knex('messages_announcements').del(); // Inserts seed entries const announcements = [{ - mid: 0, title: "Fissurer c'est bien", content: "Les nouveaux ordis du JTX sont arrivés ! Le BR aide à les installer ;)", - //authors: ['br'] - author: 'br' + authors: ['br'], + recipients: ['jtx'] },{ - mid: 1, title: "Proj'et Promotion", content: "La nouvelle proj' du JTX arrive !", - //authors: ['jtx'] - author: 'jtx' + authors: ['jtx'] },{ - mid: 2, title: "Fête de la Lune", content: "C'est bientôt la fête de la Lune ! Inscrivez-vous pour un dîner-spectacle dans le Grand Hall !", - //authors: ['x-chine'] - author: 'x-chine' + authors: ['x-chine'] },{ - mid: 3, title: "Formation Web", content: "Envie d'apprendre à faire un site Web en Django ? Alors viens en amphi Sauvy ce jeudi à 20h !", - //authors: ['br'] - author: 'br' + authors: ['br'] },{ - mid: 4, title: "Journées FedeRez", content: "Cette année, nous parlerons de vie privée, protection des données et sécurité", - //authors: ['federez'] - author: 'federez' + authors: ['federez'] } ]; - return knex('messages_announcements').insert(announcements) - .then(console.log("finished running 04_dummy_announcements")); + for(let announcement of announcements){ + let mid = (await knex('messages_announcements').insert({title:announcement.title, content:announcement.content}, ["mid"]))[0].mid; + if(announcements.authors) + await knex('announcements_authors').insert(announcement.authors.map(obj => ({mid:mid, gid:obj}))); + if(announcements.recipients) + await knex('announcements_recipients').insert(announcement.recipients.map(obj => ({mid:mid, gid:obj}))); + } + console.log("finished running 04_dummy_announcements"); + return; }; diff --git a/db/seeds/05_dummy_events.js b/db/seeds/05_dummy_events.js index 69bc78b5223dbb4df1374f08b70b3af9dc16c138..a4aa04b86644a15aa7116ca65980f02c8a197b94 100644 --- a/db/seeds/05_dummy_events.js +++ b/db/seeds/05_dummy_events.js @@ -9,34 +9,42 @@ exports.seed = async function(knex, Promise) { location: "Grand Hall", start_time : knex.fn.now(), end_time: knex.fn.now(), - //authors: ['x-chine'] - author: 'x-chine' + authors: ['x-chine'] },{ title: "Perm BR du mardi soir", content: "La perm' BR c'est maintenant!", location: "Amphi Sauvy", start_time: knex.fn.now(), end_time: knex.fn.now(), - //authors: ['br'] - author: 'br' + authors: ['br'] },{ title: "Formation Git", content: "Aujourd'hui, on va parler du système de contrôle de versions Git, qui est particulièrement utile pour travailler à plusieurs sur des projets informatiques: PSC, code de PI ou de projet de MAP, site binet, quoi que ce soit!", location: "Amphi Painlevé", start_time: knex.fn.now(), end_time: knex.fn.now(), - //authors: ['br'] - author: 'br' + authors: ['br'] },{ title: "Formation Web", content: "Envie d'apprendre à faire un site Web en Django ? Alors viens en amphi Sauvy ce jeudi à 20h !", location: "Amphi Painlevé", start_time: knex.fn.now(), end_time: knex.fn.now(), - //authors: ['br'] - author: 'br' + authors: ['br'] } ]; - return knex('messages_events').insert(events) - .then(console.log("finished running 05_dummy_events")); + + for(let event of events){ + let mid = (await knex('messages_events').insert({title:event.title, + content:event.content, + location:event.location, + start_time:event.start_time, + end_time: event.end_time}, ["mid"]))[0].mid; + if (event.authors) + await knex('events_authors').insert(event.authors.map(obj => ({mid:mid, gid:obj}))); + if (event.recipients) + await knex('events_arecipients').insert(event.recipients.map(obj => ({mid:mid, gid:obj}))); + } + console.log("finished running 05_dummy_events"); + return; }; diff --git a/db/seeds/07_dummy_requests.js b/db/seeds/07_dummy_requests.js index ae99368ed8450965b030ebda525c91bfc584e365..5c5fa33996c567ecd7a9d33b481d3b14f173defe 100644 --- a/db/seeds/07_dummy_requests.js +++ b/db/seeds/07_dummy_requests.js @@ -6,19 +6,16 @@ exports.seed = async function(knex, Promise) { await knex('requests_group_coauthor_event').del(); // Inserts seed entries const user_join_group_reqs = [{ - rid: 1, request_to: 'br', request_comment: "C'est ici pour développer sigma ?", request_from: "anatole.romon" }, { - rid: 2, request_to: 'br', request_comment: "Bonjour, je cherche le binet subaisse", request_from: "quentin.gendre" }, { - rid: 3, request_to: 'jtx', request_comment: "Quand je serais grand je serais cinéaste !", request_from: "anatole.romon" diff --git a/src/graphql/models/messageModel.ts b/src/graphql/models/messageModel.ts index a2b20b8400351ff2f2159fb375375c4507a53ee6..1e2683c5a93d075ec733a87cdffd188054e67c2d 100644 --- a/src/graphql/models/messageModel.ts +++ b/src/graphql/models/messageModel.ts @@ -6,7 +6,7 @@ import { Announcement, Event, PrivatePost, Question, Answer, Message } from "../object_resolvers/messages"; import knex from "../../../db/knex_router" -import { GroupCollection, GroupSet } from "./tools"; +import { Tools, GroupCollection, GroupSet } from "./tools"; export class MessageModel { @@ -97,8 +97,13 @@ export class MessageModel { * @async * @rights member of groups */ - async getAllMessages(groups: GroupCollection): Promise<Message[]> { - throw "Not implemented"; + async getAllMessages(groups: GroupSet): Promise<Message[]> { + let r1 = await this.getAllAnnouncements(groups); + let r2 = await this.getAllEvents(groups); + let r3 = await this.getAllPrivatePosts(groups); + + let r: Message[]; + return r.concat(r1, r2, r3); } /** @@ -111,16 +116,10 @@ export class MessageModel { * @rights member of groups */ async getAllAnnouncements(groups: GroupSet): Promise<Announcement[]> { - throw "Not implemented"; - - /*let result = await knex.select().from('announcements').whereIn('id', selection); - result = result.concat( - await knex.select().from('events').whereIn('id', selection) - ); - for (let r of result) { - r.type = 'Announcement'; - } - return result;*/ + let sent = await this.getAllAnnouncementsSent(groups); + let received = await this.getAllAnnouncementsReceived(groups); + + return sent.concat(received); } /** @@ -133,16 +132,9 @@ export class MessageModel { * @rights member of groups */ async getAllAnnouncementsSent(groups: GroupSet): Promise<Announcement[]> { - throw "Not implemented"; + let result = await knex.select('mid').from('announcements_authors').whereIn('gid', Array.from(groups)); - /*let result = await knex.select().from('announcements').whereIn('gid'); - result = result.concat( - await knex.select().from('events').whereIn('id') - ); - for (let r of result) { - r.type = 'Announcement'; - } - return result;*/ + return result.map(async obj => await this.getAnnouncement(obj.mid)); } /** @@ -155,16 +147,9 @@ export class MessageModel { * @rights member of groups */ async getAllAnnouncementsReceived(groups: GroupSet): Promise<Announcement[]> { - throw "Not implemented"; + let result = await knex.select('mid').from('announcements_recipients').whereIn('gid', Array.from(groups)); - /*let result = await knex.select().from('announcements').whereIn('gid'); - result = result.concat( - await knex.select().from('events').whereIn('id') - ); - for (let r of result) { - r.type = 'Announcement'; - } - return result;*/ + return result.map(async obj => await this.getAnnouncement(obj.mid)); } /** @@ -177,13 +162,10 @@ export class MessageModel { * @rights member of groups */ async getAllEvents(groups: GroupSet): Promise<Event[]> { - throw "Not implemented"; + let from = await this.getAllEventsFrom(groups); + let to = await this.getAllEventsTo(groups); - /*let result = await knex.select().from('events').whereIn('id', selection); - for (let r of result) { - r.type = 'Announcement'; - } - return result;*/ + return from.concat(to); } /** @@ -196,13 +178,9 @@ export class MessageModel { * @rights member of groups */ async getAllEventsFrom(groups: GroupSet): Promise<Event[]> { - throw "Not implemented"; - - /*let result = await knex.select().from('events').whereIn('gid'); - for (let r of result) { - r.type = 'Announcement'; - } - return result;*/ + let result = await knex.select('mid').from('events_authors').whereIn('gid', Array.from(groups)); + + return result.map(async obj => await this.getEvent(obj.mid)); } /** @@ -215,13 +193,9 @@ export class MessageModel { * @rights member of groups */ async getAllEventsTo(groups: GroupSet): Promise<Event[]> { - throw "Not implemented"; - - /*let result = await knex.select().from('events').whereIn('gid'); - for (let r of result) { - r.type = 'Announcement'; - } - return result;*/ + let result = await knex.select('mid').from('events_recipients').whereIn('gid', Array.from(groups)); + + return result.map(async obj => await this.getEvent(obj.mid)); } /** @@ -234,15 +208,48 @@ export class MessageModel { * @rights member of groups */ async getAllPrivatePosts(groups: GroupSet): Promise<PrivatePost[]> { - throw "Not implemented"; + let result = await knex.select('mid').from('messages_private_posts').whereIn('recipient', Array.from(groups)); + + return result.map(async obj => await this.getPrivatePost(obj.mid)); + } - // let result = await knex('private_posts').select().whereIn('id', received_messages); - // for(let entry of result){ - // entry.type = "PrivatePost"; - // } - // return result; + /** + * @memberof GraphQL.MessageModel# + * @function getAllQuestions + * @summary Fonction qui renvoie toutes les questions posées aux groupes. + * @arg {GroupSet} groups - Un ensemble d'identifiants, supposés valides. + * @return {Promise(Announcement[])} Renvoie toutes les annonces émises par ces groupes + * @async + * @rights member of groups + */ + async getAllQuestions(groups: GroupSet): Promise<Announcement[]> { + let result = await knex.select('mid').from('messages_questions').whereIn('recipient', Array.from(groups)); + + return result.map(async obj => await this.getQuestion(obj.mid)); + } + + + /** + * @memberof GraphQL.MessageModel# + * @function getAllAnswers + * @summary Fonction qui renvoie toutes les réponses données par le groupe. + * @arg {GroupSet} groups - Un ensemble d'identifiants, supposés valides. + * @return {Promise(Announcement[])} Renvoie toutes les annonces émises par ces groupes + * @async + * @rights member of groups + */ + async getAllAnswers(groups: GroupSet): Promise<Announcement[]> { + // L'auteur de la réponse n'est pas dans la table messages_answers car c'est forcément le recipient de la + // question à laquelle il répond. + let result = await knex.select('messages_answers.mid').from('messages_answers') + .innerJoin('messages_questions', 'messages_answers.for_question', 'messages_questions.mid') + .whereIn('messages_questions.recipient', groups); + + return result.map(async obj => await this.getAnswer(obj.mid)); } + + /** * @memberof GraphQL.MessageModel# * @function userParticipate diff --git a/src/graphql/resolvers.ts b/src/graphql/resolvers.ts index 4d87f18428aa8fdf2edef6d12e531cba40f13a51..f3f367c6c9d8916b22a5a7817fac2e404b32f131 100644 --- a/src/graphql/resolvers.ts +++ b/src/graphql/resolvers.ts @@ -137,7 +137,7 @@ export const resolvers = { // @rights member of groups allMessages: async function (root, args, context: Context): Promise<Message[]> { let groups = context.models.auth.groupsMember(); - return context.models.message.getAllMessages(groups); + return context.models.message.getAllMessages(Tools.union(groups.simpleGroups, groups.metaGroups)); }, // @rights member of groups