From d3db3d4c63a73c577a3785f8c9c9b35a37068cf8 Mon Sep 17 00:00:00 2001 From: Oliver Facklam <oliver.facklam.lfgeb@gmail.com> Date: Mon, 31 Dec 2018 23:23:33 +0100 Subject: [PATCH] resolvers.ts part 2 --- src/adminview/admin_router.ts | 5 +- src/app.ts | 2 +- src/graphql/connectors/userModel.ts | 2 +- src/graphql/resolvers.ts | 394 ++++++++++++++++++++++++++- src/graphql/typeDefs/actions.graphql | 16 +- src/graphql/typeDefs/objects.graphql | 4 +- src/ldap/internal/config.ts | 8 +- 7 files changed, 401 insertions(+), 30 deletions(-) diff --git a/src/adminview/admin_router.ts b/src/adminview/admin_router.ts index 931c4fb..4a9d314 100644 --- a/src/adminview/admin_router.ts +++ b/src/adminview/admin_router.ts @@ -40,6 +40,7 @@ const whitelist = [ "mew.two", "lippou.tou", "guillaume.wang", + "oliver.facklam" ]; /** * @function ensureIsAdmin @@ -51,7 +52,7 @@ function ensureIsAdmin(returnTo) { // ensure that the request was authenticated by passport ensureLoggedIn(returnTo); // lookup req.user against whitelist of admin users - if (req.user && req.user.uid in whitelist) { + if (req.user && whitelist.includes(req.user.uid)) { console.log("is an admin"); } else { console.log("is NOT an admin"); @@ -137,7 +138,7 @@ router.post('/avlogin', console.log(req.user); // redirect to /admin // in /admin, user will be looked up against whitelist anyway - res.redirect('adminview/admin'); + res.redirect('/adminview/admin'); } ); diff --git a/src/app.ts b/src/app.ts index 750632f..3f940da 100644 --- a/src/app.ts +++ b/src/app.ts @@ -60,7 +60,7 @@ app.use(cors(corsOptions)); // favicon middleware is placed near the top of the middleware stack, to answer favicon requests faster, as they are relatively frequent // (plus, they should not have to trigger any authentication middleware) import favicon from 'serve-favicon'; // tres tres important :p -app.use(favicon(path.resolve(__dirname, 'assets', 'favicon.ico'))); +app.use(favicon(path.resolve(__dirname, '..', 'assets', 'favicon.ico'))); /** * @desc Authentification de la requête contre le session-store (cookie) diff --git a/src/graphql/connectors/userModel.ts b/src/graphql/connectors/userModel.ts index c3446bd..3d41492 100644 --- a/src/graphql/connectors/userModel.ts +++ b/src/graphql/connectors/userModel.ts @@ -71,7 +71,7 @@ export class UserModel { * @arg {editProfileArgs} args - les données a modifier * @return {Promise(User)} Renvoie l'utilisateur mis a jour * @async - * @rights authentified + * @rights authenticated */ async editProfile(args: editProfileArgs): Promise<User> { let data = await UT.peek(this.contextUser); diff --git a/src/graphql/resolvers.ts b/src/graphql/resolvers.ts index 4285c87..5fa1116 100644 --- a/src/graphql/resolvers.ts +++ b/src/graphql/resolvers.ts @@ -10,7 +10,7 @@ import { User } from "./resolvers/users"; import { Group, SimpleGroup, MetaGroup } from "./resolvers/groups"; import { Announcement, Event, PrivatePost, Question, Answer, Message } from "./resolvers/messages"; import { UserJoinGroup, GroupJoinMetagroup, GroupCoauthorEvent, Request } from "./resolvers/requests"; -import { GroupCollection } from "./connectors/tools"; +import { GroupCollection, GroupSet } from "./connectors/tools"; /* Le tag @rights est la gestion des autorisations. @@ -248,25 +248,395 @@ export const resolvers = { Mutation: { - // Superviser mutations + // Groups - independent mutations + // @rights authenticated + editProfile: async function (root, args, context: Context): Promise<User> { + if(context.models.auth.isAuthenticated()) { + return context.models.user.editProfile(args); + } + throw new AuthenticationError("Not authenticated"); + }, + + // Viewer mutations + // @rights viewer + likeGroup: async function (root, args, context: Context): Promise<boolean> { + if (context.models.auth.isViewer(args.gid)) { + return context.models.group.likeGroup(args.gid) + } + throw new AuthenticationError("Not a viewer"); + }, + + // @rights viewer + unlikeGroup: async function (root, args, context: Context): Promise<boolean> { + if (context.models.auth.isViewer(args.gid)) { + return context.models.group.unlikeGroup(args.gid) + } + throw new AuthenticationError("Not a viewer"); + }, + + // @rights member d'un groupe author ou recipient + userParticipate: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + //TODO : Vérifier les autorisations + return context.models.message.userParticipate(context.user.uid, args.forEvent); + throw new AuthenticationError("Not a viewer"); + }, + + // @rights member d'un groupe author ou recipient + userUnparticipate: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + //TODO : Vérifier les autorisations + return context.models.message.userUnparticipate(context.user.uid, args.forEvent); + throw new AuthenticationError("Not a viewer"); + }, + + // @rights viewer + userRequestJoinGroup: async function (root, args, context: Context): Promise<UserJoinGroup> { + if(context.models.auth.isViewer(args.toGroup)) { + return context.models.request.userRequestJoinGroup(args.toGroup, args.comment); + } + throw new AuthenticationError("Not a viewer"); + }, + + // @rights viewer + createQuestion: async function (root, args, context: Context): Promise<Question> { + if (context.models.auth.isViewer(args.toGroup)) { + return context.models.message.createQuestion(args.toGroup, args.title, args.content); + } + throw new AuthenticationError("Not a viewer"); + }, + + // @rights viewer du groupe et author de la question + editQuestion: async function (root, args, context: Context): Promise<Question> { + throw "Not implemented"; + // TODO : Vérifier qu'il est l'auteur de la question et viewer + return context.models.message.editQuestion(args.questionToEdit, args.title, args.content); + throw new AuthenticationError("Not a viewer"); + }, + + // @rights viewer du groupe et author de la question + removeQuestion: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + // TODO : Vérifier qu'il est l'auteur de la question et viewer + return context.models.message.removeQuestion(args.questionToRemove); + throw new AuthenticationError("Not a viewer"); + }, + + // Member mutations + // @rights member + userLeaveGroup: async function (root, args, context: Context): Promise<boolean> { + if (context.models.auth.isMember(args.gid)) { + return context.models.group.userLeaveGroup(args.gid); + } + throw new AuthenticationError("Not a member"); + }, + + // @rights member + createPrivatePost: async function (root, args, context: Context): Promise<PrivatePost> { + if (context.models.auth.isMember(args.toGroup)) { + return context.models.message.createPrivatePost(args.toGroup, args.title, args.content); + } + throw new AuthenticationError("Not a member"); + }, + + // @rights member du groupe et author du post + editPrivatePost: async function (root, args, context: Context): Promise<PrivatePost> { + throw "Not implemented"; + // TODO : Vérifier qu'il est l'auteur du post et member + return context.models.message.editPrivatePost(args.privatePostToEdit, args.title, args.content); + throw new AuthenticationError("Not a member"); + }, + + // @rights member du groupe et author du post + removePrivatePost: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + // TODO : Vérifier qu'il est l'auteur du post et member + return context.models.message.removePrivatePost(args.privatePostToRemove); + throw new AuthenticationError("Not a member"); + }, - takeAdminRights : async function(obj, args, context) : Promise<boolean>{ - const justification = await auth.isSupervisor(context.user, args.from); - if(justification){ - return conn.takeAdminRights(context.user, args.from, justification); - }else{ - return false; + // Speaker mutations + // @rights speaker + writePostsSummary: async function (root, args, context: Context): Promise<boolean> { + if (context.models.auth.isSpeaker(args.forGroup)) { + return context.models.group.writePostsSummary(args.forGroup, args.content); } + throw new AuthenticationError("Not a speaker"); }, - releaseAdminRights : async function(obj, args, context){ - await conn.releaseAdminRights(context.user, args.from); + // @rights speaker du groupe émetteur + groupRequestCoauthorEvent: async function (root, args, context: Context): Promise<GroupCoauthorEvent> { + if (context.models.auth.isSpeaker(args.fromGroup)) { + return context.models.request.groupRequestCoauthorEvent(args.fromGroup, args.toGroup, args.forEvent, args.comment); + } + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe émetteur + createAnnouncement: async function (root, args, context: Context): Promise<Announcement> { + if (context.models.auth.isSpeaker(args.fromGroup)) { + return context.models.message.createAnnouncement(args.fromGroup, new GroupSet(args.toGroups), args.title, args.content, args.forEvent); + } + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe émetteur + editAnnouncement: async function (root, args, context: Context): Promise<Announcement> { + throw "Not implemented"; + // TODO : Vérifier les autorisations. + return context.models.message.editAnnouncement(args.announcementToEdit, args.title, args.content, args.forEvent); + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe émetteur + removeAnnouncement: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + // TODO : Vérifier les autorisations + return context.models.message.removeAnnouncement(args.announcementToRemove); + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe émetteur + createEvent: async function (root, args, context: Context): Promise<Event> { + if (context.models.auth.isSpeaker(args.fromGroup)) { + return context.models.message.createEvent(args.fromGroup, + new GroupSet(args.toGroups), + args.title, + args.content, + args.location, + args.startTime, + args.endTime, + args.forAnnouncement); + } + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe émetteur + editEvent: async function (root, args, context: Context): Promise<Event> { + throw "Not implemented"; + // TODO : Vérifier les autorisations. + return context.models.message.editEvent(args.eventToEdit, + args.title, + args.content, + args.location, + args.startTime, + args.endTime, + args.forAnnouncement); + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe émetteur + removeEvent: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + // TODO : Vérifier les autorisations + return context.models.message.removeEvent(args.eventToRemove); + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe + createAnswer: async function (root, args, context: Context): Promise<Answer> { + throw "Not implemented"; + // TODO : Vérifier les autorisations. + return context.models.message.createAnswer(args.forQuestion, args.title, args.content); + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe + editAnswer: async function (root, args, context: Context): Promise<Answer> { + throw "Not implemented"; + // TODO : Vérifier les autorisations. + return context.models.message.editAnswer(args.answerToEdit, args.title, args.content); + throw new AuthenticationError("Not a speaker"); + }, + + // @rights speaker du groupe + removeAnswer: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + // TODO : Vérifier les autorisations + return context.models.message.removeAnswer(args.answerToRemove); + throw new AuthenticationError("Not a speaker"); }, // Admin mutations + // @rights admin of parent group + createSubgroup: async function (root, args, context: Context): Promise<Group> { + if(context.models.auth.isAdmin(args.fromGroup)) { + return context.models.group.createSubgroup(args); + } + throw new AuthenticationError("Not an admin"); + }, - createSubgroup: async function (obj, args, context){ - throw new Error('Not implemented'); + // @rights admin + makeAdmin: async function (root, args, context: Context): Promise<User> { + if (context.models.auth.isAdmin(args.forGroup)) { + return context.models.group.makeAdmin(args.forGroup, args.uid); + } + throw new AuthenticationError("Not an admin"); }, + + // @rights admin + unmakeAdmin: async function (root, args, context: Context): Promise<User> { + if (context.models.auth.isAdmin(args.forGroup)) { + return context.models.group.unmakeAdmin(args.forGroup, args.uid); + } + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin + makeSpeaker: async function (root, args, context: Context): Promise<User> { + if (context.models.auth.isAdmin(args.forGroup)) { + return context.models.group.makeSpeaker(args.forGroup, args.uid); + } + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin + unmakeSpeaker: async function (root, args, context: Context): Promise<User> { + if (context.models.auth.isAdmin(args.forGroup)) { + return context.models.group.unmakeSpeaker(args.forGroup, args.uid); + } + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin + editGroup: async function (root, args, context: Context): Promise<Group> { + if (context.models.auth.isAdmin(args.forGroup)) { + return context.models.group.editGroup(args); + } + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe émetteur + groupRequestJoinMetagroup: async function (root, args, context: Context): Promise<GroupJoinMetagroup> { + if (context.models.auth.isAdmin(args.fromGroup)) { + return context.models.request.groupRequestJoinMetagroup(args.fromGroup, args.toMetagroup, args.comment); + } + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe destinataire + acceptUserJoinRequest: async function (root, args, context: Context): Promise<boolean> { + let req = await UserJoinGroup.tryCreate(args.request); + throw "Not implemented"; + //TODO : Vérifier les autorisations + //if (context.models.auth.isAdmin(req.to)) { + return context.models.request.acceptUserJoinRequest(req, args.comment); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe destinataire + acceptGroupJoinRequest: async function (root, args, context: Context): Promise<boolean> { + let req = await GroupJoinMetagroup.tryCreate(args.request); + throw "Not implemented"; + //TODO : Vérifier les autorisations + //if (context.models.auth.isAdmin(req.to)) { + return context.models.request.acceptGroupJoinRequest(req, args.comment); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe destinataire + refuseUserJoinRequest: async function (root, args, context: Context): Promise<boolean> { + let req = await UserJoinGroup.tryCreate(args.request); + throw "Not implemented"; + //TODO : Vérifier les autorisations + //if (context.models.auth.isAdmin(req.to)) { + return context.models.request.refuseUserJoinRequest(req, args.comment); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe destinataire + refuseGroupJoinRequest: async function (root, args, context: Context): Promise<boolean> { + let req = await GroupJoinMetagroup.tryCreate(args.request); + throw "Not implemented"; + //TODO : Vérifier les autorisations + //if (context.models.auth.isAdmin(req.to)) { + return context.models.request.refuseGroupJoinRequest(req, args.comment); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin + removeUser: async function (root, args, context: Context): Promise<User> { + if(context.models.auth.isAdmin(args.fromGroup)) { + return context.models.group.removeUser(args.fromGroup, args.uid); + } + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe destinataire + acceptGroupCoauthorEventRequest: async function (root, args, context: Context): Promise<boolean> { + let req = await GroupCoauthorEvent.tryCreate(args.request); + throw "Not implemented"; + //TODO : Vérifier les autorisations + //if (context.models.auth.isAdmin(req.to)) { + return context.models.request.acceptGroupCoauthorEventRequest(req, args.comment); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe destinataire + refuseGroupCoauthorEventRequest: async function (root, args, context: Context): Promise<boolean> { + let req = await GroupCoauthorEvent.tryCreate(args.request); + throw "Not implemented"; + //TODO : Vérifier les autorisations + //if (context.models.auth.isAdmin(req.to)) { + return context.models.request.refuseGroupCoauthorEventRequest(req, args.comment); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe + censorQuestion: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + //TODO : Vérifier les autorisations + return context.models.message.censorQuestion(args.questionToCensor); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe + censorAnswer: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + //TODO : Vérifier les autorisations + return context.models.message.censorAnswer(args.answerToCensor); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe + censorPrivatePost: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + //TODO : Vérifier les autorisations + return context.models.message.censorPrivatePost(args.privatePostToCensor); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe + censorAnnouncement: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + //TODO : Vérifier les autorisations + return context.models.message.censorAnnouncement(args.announcementToCensor); + throw new AuthenticationError("Not an admin"); + }, + + // @rights admin du groupe + censorEvent: async function (root, args, context: Context): Promise<boolean> { + throw "Not implemented"; + //TODO : Vérifier les autorisations + return context.models.message.censorEvent(args.eventToCensor); + throw new AuthenticationError("Not an admin"); + }, + + // Supervisor mutations + // @rights supervisor + takeAdminRights : async function(root, args, context: Context): Promise<boolean> { + if (context.models.auth.isSupervisor(args.forGroup)) { + return context.models.group.takeAdminRights(args.forGroup, context.user.uid); + } + throw new AuthenticationError("Not a supervisor"); + }, + + // @rights supervisor + releaseAdminRights: async function (root, args, context: Context): Promise<boolean> { + if (context.models.auth.isSupervisor(args.forGroup)) { + return context.models.group.releaseAdminRights(args.forGroup, context.user.uid); + } + throw new AuthenticationError("Not a supervisor"); + } } }; diff --git a/src/graphql/typeDefs/actions.graphql b/src/graphql/typeDefs/actions.graphql index 1a7fa65..42395a2 100644 --- a/src/graphql/typeDefs/actions.graphql +++ b/src/graphql/typeDefs/actions.graphql @@ -122,8 +122,8 @@ type Mutation { ): User # Viewer mutations - likeGroup(groupId: ID!): Boolean # devenir sympathisant - unlikeGroup(groupID: ID!): Boolean + likeGroup(gid: ID!): Boolean # devenir sympathisant + unlikeGroup(gid: ID!): Boolean userParticipate( forEvent: ID! ): Boolean @@ -148,7 +148,7 @@ type Mutation { ): Boolean # Member mutations - userLeaveGroup(groupId: ID!): Boolean + userLeaveGroup(gid: ID!): Boolean createPrivatePost( toGroup: ID!, @@ -239,10 +239,10 @@ type Mutation { subSchool: String ): Group - makeAdmin(forGroup: ID!, userId: ID!): User - unmakeAdmin(forGroup: ID!, userId: ID!): User - makeSpeaker(forGroup: ID!, userId: ID!): User - unmakeSpeaker(forGroup: ID!, userId: ID!): User + makeAdmin(forGroup: ID!, uid: ID!): User + unmakeAdmin(forGroup: ID!, uid: ID!): User + makeSpeaker(forGroup: ID!, uid: ID!): User + unmakeSpeaker(forGroup: ID!, uid: ID!): User editGroup( forGroup: ID!, @@ -260,7 +260,7 @@ type Mutation { refuseUserJoinRequest(request: ID!, comment: String): Boolean refuseGroupJoinRequest(request: ID!, comment: String): Boolean - removeUser(fromGroup: ID!, userid: ID!): User + removeUser(fromGroup: ID!, uid: ID!): User acceptGroupCoauthorEventRequest(request: ID!, comment: String): Boolean refuseGroupCoauthorEventRequest(request: ID!, comment: String): Boolean diff --git a/src/graphql/typeDefs/objects.graphql b/src/graphql/typeDefs/objects.graphql index 3244955..05dc650 100644 --- a/src/graphql/typeDefs/objects.graphql +++ b/src/graphql/typeDefs/objects.graphql @@ -269,13 +269,13 @@ Les différents types implémentant Request représentent des types de requête - GroupCoauthorEvent: un groupe demande à devenir (co-)organisateur d'un événement *déjà existant* """ # Emetteur possible d'une Request -union RequesterUnion = Group | User +# union RequesterUnion = SimpleGroup | MetaGroup | User interface Request { rid: ID! comment: String # court message accompagnant la demande - from: RequesterUnion! # Émet la demande + #from: RequesterUnion! # Émet la demande to: Group! # Reçoit la demande } diff --git a/src/ldap/internal/config.ts b/src/ldap/internal/config.ts index 6cbfcf7..ad76623 100644 --- a/src/ldap/internal/config.ts +++ b/src/ldap/internal/config.ts @@ -13,10 +13,10 @@ import fs from 'fs'; import path from 'path'; import colors from 'colors'; // Point central ; tous les champs de la BDD sont 'cachés' dans config.json et pas visibles directement -let path_config = path.resolve(__dirname,'..', '..','ldap_config.json'); +let path_config = path.resolve(__dirname,'..', '..', '..', 'ldap_config.json'); console.log(colors.cyan("Loading LDAP config file from "+path_config)); export const ldapConfig = JSON.parse(fs.readFileSync(path_config).toString()); -let path_credentials = path.resolve(__dirname,'..', '..','ldap_credentials.json') +let path_credentials = path.resolve(__dirname,'..', '..', '..', 'ldap_credentials.json') console.log(colors.cyan("Loading LDAP credentials from "+path_credentials)); export const credentialsLdapConfig = JSON.parse(fs.readFileSync(path_credentials).toString()); // Override config server from environment @@ -24,6 +24,6 @@ if (process.env.LDAP_URI != null) { ldapConfig.server = process.env.LDAP_URI; } else { - if (process.env.TARGET_ENV =`production`) { ldapConfig.server = ldapConfig.server_prod; } - else { ldapConfig.server = ldapConfig.server_dev; } + if (process.env.TARGET_ENV == `production`) { ldapConfig.server = ldapConfig.server_prod; } + else { ldapConfig.server = ldapConfig.server_dev; } } \ No newline at end of file -- GitLab