diff --git a/server/helpers/authorization.js b/server/helpers/authorization.js index a5eb6768..1e6f37aa 100644 --- a/server/helpers/authorization.js +++ b/server/helpers/authorization.js @@ -174,7 +174,7 @@ const Authorization = { * @param {String} permission * @returns {Boolean | GraphQLError} */ - HasPermmission: (session, jwt, permission) => { + HasPermission: (session, jwt, permission) => { if (!Authorization.CheckSession(session, jwt)) { session.destroy(); return APIError('UNAUTHORIZED', null, { diff --git a/server/package.json b/server/package.json index 4f4b9143..40c3c6b8 100644 --- a/server/package.json +++ b/server/package.json @@ -59,7 +59,7 @@ "graphql-type-json": "^0.3.2", "https": "^1.0.0", "mongoose": "^5.10.13", - "pm2": "^4.5.0", + "pm2": "^4.5.5", "winston": "^3.3.3" }, "devDependencies": { diff --git a/server/schema/club/club.model.js b/server/schema/club/club.model.js index 0006dae5..066b7263 100644 --- a/server/schema/club/club.model.js +++ b/server/schema/club/club.model.js @@ -27,13 +27,18 @@ const ClubSchema = new Schema( logo: { type: Schema.Types.ObjectId, ref: 'Media', - required: true, + // TODO: set it to true in future. + required: false, }, bio: { type: String, required: false, trim: true, }, + facAd: { + type: String, + required: true, + }, facebook: { type: String, required: false, diff --git a/server/schema/club/club.mutation.js b/server/schema/club/club.mutation.js index e69de29b..6bb24b7b 100644 --- a/server/schema/club/club.mutation.js +++ b/server/schema/club/club.mutation.js @@ -0,0 +1,77 @@ +/** + * @module app.schema.ClubMutation + * @description Club Mutation + * + * @requires module:app.schema.scalars + * + * @version v1 + * @since 0.1.0 + */ + +const { + GraphQLObjectType, + GraphQLString, + // GraphQLSchema, + GraphQLID, + GraphQLList, + // GraphQLBoolean, + // GraphQLInt, + GraphQLNonNull, + // GraphQLDate, + // GraphQLTime, + // GraphQLDateTime, + //GraphQLJSON, + GraphQLJSONObject, +} = require('../scalars'); +const { addClub, updateClub, deleteClub } = require('./club.resolver'); +const ClubType = require('./club.type'); + +module.exports = new GraphQLObjectType({ + name: 'ClubMutation', + fields: { + addClub: { + description: 'Adds a single club', + type: ClubType, + args: { + id: { type: GraphQLID }, + name: { type: GraphQLNonNull(GraphQLString) }, + website: { type: GraphQLString }, + instagram: { type: GraphQLString }, + facebook: { type: GraphQLString }, + twitter: { type: GraphQLString }, + logo: { type: GraphQLID }, + description: { type: GraphQLNonNull(GraphQLString) }, + facAd: { type: GraphQLString }, + society: { type: GraphQLNonNull(GraphQLString) }, + executive: { type: GraphQLList(GraphQLJSONObject) }, + }, + resolve: addClub, + }, + updateClub: { + description: 'Updates a single club', + type: ClubType, + args: { + id: { type: GraphQLID }, + name: { type: GraphQLString }, + website: { type: GraphQLString }, + instagram: { type: GraphQLString }, + facebook: { type: GraphQLString }, + twitter: { type: GraphQLString }, + logo: { type: GraphQLID }, + description: { type: GraphQLString }, + facAd: { type: GraphQLString }, + society: { type: GraphQLString }, + executive: { type: GraphQLList(GraphQLJSONObject) }, + }, + resolve: updateClub, + }, + deleteClub: { + description: 'Deletes a single club', + type: ClubType, + args: { + id: { type: GraphQLID }, + }, + resolve: deleteClub, + }, + }, +}); diff --git a/server/schema/club/club.query.js b/server/schema/club/club.query.js index e69de29b..4cb5fc1b 100644 --- a/server/schema/club/club.query.js +++ b/server/schema/club/club.query.js @@ -0,0 +1,66 @@ +/** + * @module app.schema.ClubQuery + * @description Club Query + * + * @requires module:app.schema.scalars + * + * @version v1 + * @since 0.1.0 + */ + +const { + GraphQLObjectType, + GraphQLString, + // GraphQLSchema, + GraphQLID, + GraphQLList, + // GraphQLBoolean, + // GraphQLInt, + GraphQLNonNull, + // GraphQLDate, + // GraphQLTime, + // GraphQLDateTime, + // GraphQLJSON, + // GraphQLJSONObject, +} = require('../scalars'); +const ClubType = require('./club.type'); +const { getClubByID, listClubs, searchClubs } = require('./club.resolver'); + +module.exports = new GraphQLObjectType({ + name: 'ClubQuery', + fields: { + getClubByID: { + description: 'Retrieves a single club', + type: ClubType, + args: { + id: { + type: GraphQLNonNull(GraphQLID), + description: "The club's mongo ID.", + }, + }, + resolve: getClubByID, + }, + listClubs: { + description: 'Retrieves a list of specified clubs', + type: GraphQLList(ClubType), + args: { + ids: { + type: GraphQLList(GraphQLID), + description: 'The List of club mongo IDs.', + }, + }, + resolve: listClubs, + }, + searchClubs: { + description: 'Searches a club for keywords', + type: GraphQLList(ClubType), + args: { + keywords: { + description: 'The search keywords', + type: new GraphQLNonNull(GraphQLString), + }, + }, + resolve: searchClubs, + }, + }, +}); diff --git a/server/schema/club/club.resolver.js b/server/schema/club/club.resolver.js index e69de29b..336e7ec5 100644 --- a/server/schema/club/club.resolver.js +++ b/server/schema/club/club.resolver.js @@ -0,0 +1,166 @@ +/** + * @module app.schema.ClubResolver + * @description Club Resolver + * + * @requires module:app.schema.ClubType + * @requires module:app.schema.ClubModel + * @requires module:app.authorization + + * @version v1 + * @since 0.1.0 + */ + +const { GraphQLError, APIError, FirebaseAuthError } = require('../../helpers/errorHandler'); +const { Model } = require('mongoose'); + +/** + * @type {Model} + */ +const { HasPermission } = require('../../helpers/authorization'); +const ClubModel = require('./club.model'); +const { GraphQLExtension } = require('graphql-extensions'); + +module.exports = { + getClubByID: async (parent, { id }, context, info, _ClubModel = ClubModel) => { + try { + const _club = await _ClubModel.findById(id); + + if (!_club) { + return APIError('NOT_FOUND'); + } + return _club; + } catch (e) { + if (e instanceof GraphQLError) { + return e; + } + return APIError(null, e); + } + }, + addClub: async ( + parent, + { name, website, instagram, twitter, facebook, description, facAd, society, executive }, + context, + info, + _ClubModel = ClubModel + ) => { + try { + //if (!HasPermission(context, 'club.write.all')) { + // return APIError('FORBIDDEN'); + //} + + const _club = await _ClubModel.create({ + name, + website, + instagram, + facebook, + twitter, + // TODO: create an object in the media collection and use ID + // logo: args.logo, + description, + society, + facAd, + executive, + }); + return _club; + } catch (error) { + if (error instanceof GraphQLError) { + return error; + } + return APIError(null, error); + } + }, + listClubs: async (parent, { ids }, context, info, _ClubModel = ClubModel) => { + try { + // TODO: if length == 0, APIError doesn.t work + if (!ids || !(ids instanceof Array || ids.length <= 0)) { + return APIError('BAD_REQUEST'); + } + //TODO: set permission and error handling + // if (!HasPermmission(context, 'club.list.all') || !HasPermmission(context, 'club.read.public')) { + // return APIError('FORBIDDEN'); + // } + + const _clubs = await _ClubModel.find().where('_id').in(ids).exec(); + + return _clubs; + } catch (error) { + if (error instanceof GraphQLError) { + return error; + } + return APIError(null, error); + } + }, + searchClubs: async (parent, { keywords }, context, info, _ClubModel = ClubModel) => { + //TODO: non functional and incomplete as of now + if (!keywords) { + return APIError('BAD_REQUEST'); + } + + const _clubs = _ClubModel.find({ + $text: { + $search: keywords, + $caseSensitive: true, + }, + }); + return _clubs; + }, + updateClub: async ( + parent, + { id, name, website, executive, instagram, facebook, facAd, description }, + context, + info, + _ClubModel = ClubModel + ) => { + try { + if (!(await _ClubModel.exists({ id }))) { + return APIError('NOT_FOUND'); + } + + /** + * The getUpdateObject function returns an object that contains the + * key-value pairs of the club fields that are needed to be updated. + */ + const getUpdateObject = (propertiesObject) => { + /**propertiesObject + * Initialises an empty object that stores the updated fields. + */ + const updateObject = {}; + /** + * The propertiesObject(an object which contains the club fields that + * can be updated) is looped through and only the fields that are + * required to be updated are added to updateObject. + */ + for (key in propertiesObject) { + if (propertiesObject[key]) { + updateObject[key] = propertiesObject[key]; + } + } + + return updateObject; + }; + + const updateClub = getUpdateObject({ name, website, executive, instagram, facebook, facAd, description }); + const _club = await _ClubModel.findByIdAndUpdate(id, updateClub); + return _club; + } catch (error) { + if (error instanceof GraphQLError) { + return error; + } + return APIError(null, error); + } + }, + deleteClub: async (parent, { id }, context, info, _ClubModel = ClubModel) => { + try { + if (!(await _ClubModel.exists({ id }))) { + return APIError('NOT_FOUND'); + } + const _club = await _ClubModel.findByIdAndDelete(id); + return _club; + } catch (error) { + if (error instanceof GraphQLError) { + return error; + } + return APIError(null, error); + } + }, +}; diff --git a/server/schema/club/club.schema.js b/server/schema/club/club.schema.js new file mode 100644 index 00000000..e53b4963 --- /dev/null +++ b/server/schema/club/club.schema.js @@ -0,0 +1,34 @@ +/** + * @module app.schema.Club + * @description Club Schema + * + * @requires module:app.schema.scalars + * @requires module:app.schema.ClubQuery + * @requires module:app.schema.ClubMutation + * + * @version v1 + * @since 0.1.0 + */ + +const { + // GraphQLObjectType, + // GraphQLString, + GraphQLSchema, + // GraphQLID, + // GraphQLList, + // GraphQLBoolean, + // GraphQLInt, + // GraphQLNonNull, + // GraphQLDate, + // GraphQLTime, + // GraphQLDateTime, + // GraphQLJSON, + // GraphQLJSONObject, +} = require('../scalars'); +const ClubMutation = require('./club.mutation'); +const ClubQuery = require('./club.query'); + +module.exports = new GraphQLSchema({ + query: ClubQuery, + mutation: ClubMutation, +}); diff --git a/server/schema/club/club.type.js b/server/schema/club/club.type.js index e69de29b..feb4da77 100644 --- a/server/schema/club/club.type.js +++ b/server/schema/club/club.type.js @@ -0,0 +1,50 @@ +/** + * @module app.schema.ClubType + * @description User Type + * + * @requires module:app.schema.scalars + * + * @version v1 + * @since 0.1.0 + */ + +const { + GraphQLObjectType, + GraphQLString, + // GraphQLSchema, + GraphQLID, + GraphQLList, + // GraphQLBoolean, + GraphQLInt, + // GraphQLNonNull, + // GraphQLDate, + // GraphQLTime, + GraphQLDateTime, + // GraphQLJSON, + // GraphQLJSONObject, +} = require('../scalars'); +const ExecutiveType = require('./executive.type'); + +const ClubType = new GraphQLObjectType({ + name: 'Club', + fields: () => ({ + id: { type: GraphQLID }, + name: { type: GraphQLString }, + website: { type: GraphQLString }, + instagram: { type: GraphQLString }, + facebook: { type: GraphQLString }, + twitter: { type: GraphQLString }, + logo: { type: GraphQLID}, + executive: { type: GraphQLList(ExecutiveType) }, + society: { type: GraphQLString }, + description: { type: GraphQLString }, + facAd: { type: GraphQLString }, + createdAt: { type: GraphQLID }, + createdBy: { type: GraphQLID }, + updatedAt: { type: GraphQLDateTime }, + updatedBy: { type: GraphQLID }, + schemaVersion: { type: GraphQLInt }, + }), +}); + +module.exports = ClubType; diff --git a/server/schema/club/executive.type.js b/server/schema/club/executive.type.js new file mode 100644 index 00000000..db5105be --- /dev/null +++ b/server/schema/club/executive.type.js @@ -0,0 +1,39 @@ +const { + GraphQLObjectType, + GraphQLString, + // GraphQLSchema, + GraphQLID, + // GraphQLList, + // GraphQLBoolean, + // GraphQLInt, + // GraphQLNonNull, + // GraphQLDate, + // GraphQLTime, + // GraphQLDateTime, + // GraphQLJSON, + // GraphQLJSONObject, +} = require('../scalars'); + +const ExecutiveType = new GraphQLObjectType({ + name: 'Executive', + fields: () => ({ + id: { type: GraphQLID }, + user: { + type: GraphQLID, + }, + name: { + type: GraphQLString, + }, + picture: { + type: GraphQLID, + }, + nitrMail: { + type: GraphQLString, + }, + designation: { + type: GraphQLString, + }, + }), +}); + +module.exports = ExecutiveType; diff --git a/server/schema/index.js b/server/schema/index.js index c2e8c2ca..ba9dda6b 100644 --- a/server/schema/index.js +++ b/server/schema/index.js @@ -12,8 +12,9 @@ */ const { mergeSchemas } = require('graphql-tools'); +const ClubSchema = require('./club/club.schema'); const UserSchema = require('./user/user.schema'); module.exports = mergeSchemas({ - schemas: [UserSchema], + schemas: [UserSchema, ClubSchema], });