Skip to content

Commit

Permalink
chore: merge pull request #122 from AEGEE/add-additional-fields-for-eqac
Browse files Browse the repository at this point in the history
Add additional fields for EQAC
  • Loading branch information
serge1peshcoff authored Dec 30, 2019
2 parents d6d31a5 + 7b4a0fc commit 7f2c67b
Show file tree
Hide file tree
Showing 12 changed files with 618 additions and 40 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
<a name="0.17.0"></a>
# [0.17.0](https://github.com/AEGEE/oms-events/compare/0.16.1...0.17.0) (2019-12-30)


### Bug Fixes

* **events:** add submitted status and its workflow. Fixes MEMB-638 ([1200969](https://github.com/AEGEE/oms-events/commit/1200969))
* **events:** display submitted events on events approval page ([3025d65](https://github.com/AEGEE/oms-events/commit/3025d65))
* **events:** only returning special fields to those who have rights ([fa142b5](https://github.com/AEGEE/oms-events/commit/fa142b5))


### Features

* **events:** added additional fields for EQAC. Fixes MEMB-737 ([22c6a39](https://github.com/AEGEE/oms-events/commit/22c6a39))
* **events:** only displaying deleted and not published events to orgs/EQAC. Fixes MEMB-730 ([3523d8d](https://github.com/AEGEE/oms-events/commit/3523d8d))



<a name="0.16.1"></a>
## [0.16.1](https://github.com/AEGEE/oms-events/compare/0.16.0...0.16.1) (2019-12-26)

Expand Down
18 changes: 18 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ module.exports = {
created_at: 'Created at',
updated_at: 'Updated at'
},
EVENT_PUBLIC_FIELDS: [
'id',
'name',
'url',
'image',
'description',
'application_starts',
'application_ends',
'starts',
'ends',
'fee',
'organizing_bodies',
'locations',
'type',
'questions',
'max_participants',
'application_status'
],
EVENT_TYPES: ['wu', 'es', 'nwm', 'ltc', 'rtc', 'european'],
CURRENT_USER_PREFIX: 'me'
};
18 changes: 15 additions & 3 deletions lib/events.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const errors = require('./errors');
const merge = require('./merge');
const constants = require('./constants');
const helpers = require('./helpers');
const { Event, Application } = require('../models');
const { Sequelize } = require('./sequelize');
Expand Down Expand Up @@ -106,7 +107,7 @@ exports.listApprovableEvents = async (req, res) => {
const events = await Event.findAll({
where: {
deleted: false,
status: 'draft',
status: { [Sequelize.Op.ne]: 'published' },
type: { [Sequelize.Op.in]: allowedEventTypes }
}
});
Expand Down Expand Up @@ -152,7 +153,18 @@ exports.addEvent = async (req, res) => {
};

exports.eventDetails = async (req, res) => {
const event = req.event.toJSON();
if (!req.permissions.see_event) {
return errors.makeForbiddenError(res, 'You cannot see this event.');
}

let event = req.event.toJSON();

// Some fields shouldn't be public and only should be displayed to EQAC/CD/admins/organizers.
if (!helpers.isOrganizer(event, req.user)
&& !req.permissions.manage_event[event.type]
&& !req.permissions.approve_event[event.type]) {
event = helpers.whitelistObject(event, constants.EVENT_PUBLIC_FIELDS);
}

return res.json({
success: true,
Expand Down Expand Up @@ -210,7 +222,7 @@ exports.deleteEvent = async (req, res) => {
};

exports.setApprovalStatus = async (req, res) => {
if (!req.permissions.set_status) {
if (!req.permissions.change_status[req.body.status]) {
return errors.makeForbiddenError(res, 'You are not allowed to change status.');
}

Expand Down
37 changes: 35 additions & 2 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ exports.getDefaultQuery = (req) => {
// Default filter is empty.
const queryObj = {
where: {},
order: [['starts', 'ASC']]
order: [['starts', 'ASC']],
select: constants.EVENT_PUBLIC_FIELDS
};

// If search is set, searching for event by name or description case-insensitive.
Expand Down Expand Up @@ -115,6 +116,16 @@ exports.beautify = (value) => {
return value;
};

// A helper to whilelist object's properties.
exports.whitelistObject = (object, allowedFields) => {
const newObject = {};
for (const field of allowedFields) {
newObject[field] = object[field];
}

return newObject;
};

// A helper to get the names for application fields. Useful for exporting for getting columns headers.
exports.getApplicationFields = (event) => {
const fields = { ...constants.APPLICATION_FIELD_NAMES };
Expand Down Expand Up @@ -184,6 +195,15 @@ exports.getPermissions = (user, corePermissions, approvePermissions) => {
};

exports.getEventPermissions = ({ permissions, event, user }) => {
const canApprove = permissions.approve_event[event.type];
const canApproveOrIsOrganizer = exports.isOrganizer(event, user) || canApprove;

// The event can only be seen to public if it's published and not deleted.
// Otherwise (if it's deleted, submitted or draft) it should be accessible
// only to LOs and those who can approve it.
permissions.see_event = (event.status === 'published' && !event.deleted)
|| canApproveOrIsOrganizer;

permissions.edit_event = (event.status === 'draft' && exports.isOrganizer(event, user)) || permissions.manage_event[event.type];
permissions.delete_event = permissions.manage_event[event.type];

Expand All @@ -194,7 +214,20 @@ exports.getEventPermissions = ({ permissions, event, user }) => {
permissions.set_participants_attended = exports.isOrganizer(event, user) || permissions.manage_event[event.type];
permissions.set_participants_confirmed = exports.isOrganizer(event, user) || permissions.manage_event[event.type];
permissions.export = exports.isOrganizer(event, user) || permissions.manage_event[event.type];
permissions.set_status = permissions.approve_event[event.type];

// Status transitions.
// 1) draft -> submitted - by LOs or those who can approve (ask for approval)
// 2) submitted -> draft - by those who can approve (reject approval)
// 3) submitted -> published - by those who can approve (approve and publish)
// 4) published -> submitted - by those who can approve (unpublish)
// 5) draft -> published - no direct transition
// 6) published -> draft - no direct transition
permissions.change_status = {
draft: event.status === 'submitted' && canApprove, // 2
published: event.status === 'submitted' && canApprove, // 3
submitted: (event.status === 'published' && canApprove) // 4
|| (event.status === 'draft' && canApproveOrIsOrganizer) // 1
};

return permissions;
};
Expand Down
18 changes: 18 additions & 0 deletions migrations/20191226131439-add-additional-fields-to-eqac.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.addColumn(
'events',
'budget',
{ type: Sequelize.TEXT, allowNull: true }
);
await queryInterface.addColumn(
'events',
'programme',
{ type: Sequelize.TEXT, allowNull: true }
);
},
down: (queryInterface) => {
queryInterface.removeColumn('events', 'programme');
queryInterface.removeColumn('events', 'budget');
}
};
29 changes: 29 additions & 0 deletions migrations/20191226235828-add-submitted-to-event-statuses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module.exports = {
up: async (queryInterface, Sequelize) => {
// https://stackoverflow.com/questions/45437924/drop-and-create-enum-with-sequelize-correctly
await queryInterface.changeColumn(
'events',
'status',
{ type: Sequelize.TEXT }
);
await queryInterface.sequelize.query('drop type enum_events_status;');
await queryInterface.changeColumn(
'events',
'status',
{ type: Sequelize.ENUM('draft', 'submitted', 'published'), allowNull: false }
);
},
down: async (queryInterface, Sequelize) => {
await queryInterface.changeColumn(
'events',
'status',
{ type: Sequelize.TEXT }
);
await queryInterface.sequelize.query('drop type enum_events_status;');
await queryInterface.changeColumn(
'events',
'status',
{ type: Sequelize.ENUM('draft', 'requesting', 'published'), allowNull: false }
);
}
};
46 changes: 41 additions & 5 deletions models/Event.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,13 @@ const Event = sequelize.define('event', {
}
},
status: {
type: Sequelize.ENUM('draft', 'requesting', 'published'),
type: Sequelize.ENUM('draft', 'submitted', 'published'),
allowNull: false,
defaultValue: 'draft',
validate: {
isIn: {
args: [['draft', 'requesting', 'published']],
msg: 'Event status should be one of these: "draft", "requesting", "published".'
args: [['draft', 'submitted', 'published']],
msg: 'Event status should be one of these: "draft", "submitted", "published".'
}
}
},
Expand Down Expand Up @@ -321,12 +321,48 @@ const Event = sequelize.define('event', {
? 'open'
: 'closed'; // inclusive
}
}
},
budget: {
type: Sequelize.TEXT,
allowNull: true
},
programme: {
type: Sequelize.TEXT,
allowNull: true
},
}, {
underscored: true,
tableName: 'events',
createdAt: 'created_at',
updatedAt: 'updated_at'
updatedAt: 'updated_at',
validate: {
is_budget_set() {
if (this.status === 'draft') {
return;
}

if (typeof this.budget !== 'string') {
throw new Error('Budget should be a string when the event status is not "draft".');
}

if (this.budget.trim().length === 0) {
throw new Error('Budget cannot be empty when the event status is not "draft".');
}
},
is_programme_set() {
if (this.status === 'draft') {
return;
}

if (typeof this.programme !== 'string') {
throw new Error('Programme should be a string when the event status is not "draft".');
}

if (this.programme.trim().length === 0) {
throw new Error('Programme cannot be empty when the event status is not "draft".');
}
}
}
});

module.exports = Event;
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "oms-events",
"version": "0.16.1",
"version": "0.17.0",
"description": "Events-module of the OMS",
"main": "server.js",
"directories": {
Expand Down
Loading

0 comments on commit 7f2c67b

Please sign in to comment.