Skip to content

Commit

Permalink
Merge pull request CoderDojo#173 from CoderDojo/staging
Browse files Browse the repository at this point in the history
Staging sync
  • Loading branch information
Wardormeur authored Nov 15, 2017
2 parents cbafa69 + ee0a230 commit 43ffaa4
Show file tree
Hide file tree
Showing 17 changed files with 222 additions and 539 deletions.
11 changes: 6 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
FROM mhart/alpine-node:0.10.48
MAINTAINER butlerx <[email protected]>
ENV NODE_ENV=production
ARG DEP_VERSION=latest
RUN apk add --update git build-base python postgresql-client
RUN mkdir -p /usr/src/app
RUN apk add --update git build-base python postgresql-client &&\
mkdir -p /usr/src/app
WORKDIR /usr/src/app
ADD . /usr/src/app
COPY . /usr/src/app
RUN npm install && \
npm install cp-translations@$DEP_VERSION && \
npm install cp-translations@"$DEP_VERSION" && \
apk del build-base python && \
rm -rf /tmp/* /root/.npm /root/.node-gyp
EXPOSE 10306
CMD ["npm", "start"]
CMD ["npm", "start"]
1 change: 1 addition & 0 deletions dev.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
FROM mhart/alpine-node:0.10.48
MAINTAINER butlerx <[email protected]>
ENV NODE_ENV=development
RUN apk add --update git build-base python postgresql-client && \
mkdir -p /usr/src/app /usr/src/cp-translations
COPY docker-entrypoint.sh /usr/src
Expand Down
3 changes: 3 additions & 0 deletions lib/cd-events.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,12 @@ module.exports = function () {

// CRUD
seneca.add({role: plugin, entity: 'invite', cmd: 'list'}, require('./entity/invite/list'));
seneca.add({role: plugin, entity: 'event', cmd: 'save'}, require('./entity/event/save'));
seneca.add({role: plugin, entity: 'next-events', cmd: 'list'}, require('./entity/next-events/list'));

// Controllers
seneca.add({role: plugin, ctrl: 'applications', cmd: 'list'}, require('./controllers/application/list'));
seneca.add({role: plugin, ctrl: 'events', cmd: 'updateAddress'}, require('./controllers/event/update-address'));

// PERMS
seneca.add({role: plugin, cmd: 'is_ticketing_admin'}, isTicketingAdmin.bind(seneca));
Expand Down
43 changes: 43 additions & 0 deletions lib/controllers/event/update-address.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
var async = require('async');
/**
* updateAddress function - Called to update all upcoming event address upon dojo address change
* By default asynchronous
* @param {String} dojoId Identifier of the parent entity
* @param {Object} location Object containing the information of the address
* @return {Void}
*/
module.exports = function (args, done) {
var seneca = this;
var plugin = args.role;
var dojoId = args.dojoId;
var location = args.location;
// Retrieve all events in the future
function getUpcomingEvents (wfCb) {
seneca.act({role: plugin, entity: 'next-events', cmd: 'list', query: {dojoId: dojoId, useDojoAddress: true}},
function (err, events) {
if (events && events.length > 0) {
wfCb(null, events);
} else {
done();
}
});
}
function updateEvents (events, wfCb) {
async.eachSeries(events, updateAddress, wfCb);
}
// Save the new address
function updateAddress (event, sCb) {
var payload = {
id: event.id,
country: location.country,
city: location.city,
address: location.address,
position: location.position
};
seneca.act({role: plugin, entity: 'event', cmd: 'save', event: payload}, sCb);
}
async.waterfall([
getUpcomingEvents,
updateEvents
], done);
}
103 changes: 103 additions & 0 deletions lib/controllers/event/update-address.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
'use strict';

var lab = exports.lab = require('lab').script();
var chai = require('chai');
var expect = chai.expect;
chai.use(require('sinon-chai'));
var sinon = require('sinon');
var _ = require('lodash');
var fn = require(__dirname + '/update-address.js');

lab.experiment('Event - Update address', { timeout: 5000 }, function () {
var sandbox;
var senecaStub;
var updateAddress;

lab.beforeEach(function (done) {
sandbox = sinon.sandbox.create();
senecaStub = {
act: sandbox.stub(),
make: sandbox.stub()
};
updateAddress = fn.bind(senecaStub);
done();
});

lab.afterEach(function (done) {
sandbox.restore();
done();
});

lab.test('should get next events and update addresses of those events', function (done) {
// ARRANGE
var dojoId = 1;
var mockLocation = {
address: 'aha',
city: { placeName: 'place' },
country: {
alpha2: 'FR',
countryName: 'France'
},
position: { lat: 1, lng: 1 } };
var mockEvents = [{ id: 1, name: 'event1' }];
var eventMock = _.assign({},
mockLocation,
{ id: mockEvents[0].id });
// PREPARE
senecaStub.act
.withArgs(sinon.match({ role: 'cd-events', entity: 'next-events', cmd: 'list' }))
.callsFake(function (args, cb) {
expect(args.query).to.be.eql({
dojoId: dojoId,
useDojoAddress: true
});
cb(null, mockEvents);
});
senecaStub.act
.withArgs(sinon.match({ role: 'cd-events', entity: 'event', cmd: 'save' }))
.callsFake(function (args, cb) {
expect(args.event).to.be.eql(eventMock);
cb(null, eventMock);
});
// ACT
updateAddress({ role: 'cd-events', dojoId: 1, location: mockLocation }, function (err, ret) {
expect(err).to.be.eql(undefined);
expect(ret).to.be.eql(undefined);
done();
});
});

lab.test('should not save if there is no events', function (done) {
// ARRANGE
var dojoId = 1;
var mockLocation = {
address: 'aha',
city: { placeName: 'place' },
country: {
alpha2: 'FR',
countryName: 'France'
},
position: { lat: 1, lng:1 }
};
var mockEvents = [];
// PREPARE
senecaStub.act
.withArgs(sinon.match({ role: 'cd-events', entity: 'next-events', cmd: 'list' }))
.callsFake(function (args, cb) {
expect(args.query).to.be.eql({
dojoId: dojoId,
useDojoAddress: true
});
cb(null, mockEvents);
});
// ACT
updateAddress({role: 'cd-events', dojoId: 1, location: mockLocation}, function (err, ret) {
expect(err).to.be.eql(undefined);
expect(ret).to.be.eql(undefined);
expect(senecaStub.act
.withArgs(sinon.match({ role: 'cd-events', entity: 'event', cmd: 'save' }))
).to.not.have.been.called;
done();
});
});
});
5 changes: 5 additions & 0 deletions lib/entity/event/save.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = function (args, done) {
var seneca = this;
var event = args.event;
seneca.make$('cd/events').save$(event, done);
};
9 changes: 9 additions & 0 deletions lib/entity/next-events/list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = function (args, done) {
var seneca = this;
var query = args.query;
if (query) {
seneca.make$('v/next_events').list$(query, done);
} else {
done(null, []);
}
}
2 changes: 2 additions & 0 deletions lib/save-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function saveEvent (args, callback) {
public: eventInfo.public,
status: eventInfo.status,
type: eventInfo.type,
useDojoAddress: eventInfo.useDojoAddress || false, // Backward compat : set it as false
recurringType: eventInfo.recurringType,
ticketApproval: eventInfo.ticketApproval,
notifyOnApplicant: eventInfo.notifyOnApplicant
Expand All @@ -73,6 +74,7 @@ function saveEvent (args, callback) {
});

if (pastDateFound && !eventInfo.id) return done(new Error('Past events cannot be created'));
if (pastDateFound && eventInfo.id) return done(new Error('Past events cannot be edited'));

newEvent.dates = eventInfo.dates;

Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"scripts": {
"lint": "semistandard *.js config/config.js",
"testdata": "node test/lib/service.js",
"test": "bash -c 'source ./config/development.env; npm run lint && lab --ignore __core-js_shared__ --flat --threshold 48 -r html -o ./coverage/coverage.html -r lcov -o ./coverage/lcov.info -r json -o ./coverage/coverage.json -r console -o stdout'",
"test": "sh -c 'source ./config/development.env; npm run lint && lab lib/controllers -P spec --ignore __core-js_shared__ '",
"coverage": "sh -c 'source ./config/development.env; lab --threshold 68 -r html -o ./coverage/coverage.html -r lcov -o ./coverage/lcov.info -r json -o ./coverage/coverage.json -r console -o stdout'",
"start": "node service.js",
"dev": "nodemon service.js"
},
Expand All @@ -23,12 +24,13 @@
"url": "https://github.com/CoderDojo/community-platform/issues"
},
"devDependencies": {
"chai": "2.2.0",
"chai": "^4.0",
"lab": "5.15.2",
"nodemon": "1.11.0",
"pre-commit": "1.1.2",
"semistandard": "7.0.3",
"sinon": "1.16.1"
"sinon": "^2.3",
"sinon-chai": "^2.14.0"
},
"dependencies": {
"async": "0.9.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
DO $$
BEGIN
BEGIN
ALTER TABLE cd_events ADD COLUMN use_dojo_address boolean;
EXCEPTION
WHEN duplicate_column THEN RAISE NOTICE 'column useDojoAddress already exists in cd_events.';
END;
END;
$$
13 changes: 13 additions & 0 deletions scripts/database/pg/migrations/022.do.add-next-events-view.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CREATE FUNCTION f_next_events()
RETURNS void AS $$
BEGIN
CREATE OR REPLACE VIEW v_next_events AS (
SELECT DISTINCT ON (id) * FROM (
SELECT * FROM (
SELECT *, unnest(dates)->>'startTime' as next_date FROM cd_events
) x WHERE next_date IS NOT NULL AND next_date NOT LIKE 'Invalid%'
) as filtered_dates WHERE next_date > to_char(NOW(), 'YYYY-MM-DDTHH:mm:ss') ORDER BY id, next_date
);
END;
$$ LANGUAGE plpgsql;
SELECT f_next_events();
33 changes: 23 additions & 10 deletions service.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ var store = require('seneca-postgresql-store');
var dgram = require('dgram');
var service = 'cp-events-service';
var sanitizeHtml = require('sanitize-html');
var log = require('cp-logs-lib')({name: service, level: 'warn'});
var log = require('cp-logs-lib')({ name: service, level: 'warn' });
config.log = log.log;

seneca.log.info('using config', JSON.stringify(config, null, 4));
if (process.env.NODE_ENV !== 'production') {
seneca.log.info('using config', JSON.stringify(config, null, 4));
}
seneca.options(config);
/**
* TextArea fields contains user generated html.
Expand All @@ -39,26 +41,33 @@ seneca.options.sanitizeTextArea = {
};
seneca.decorate('customValidatorLogFormatter', require('./lib/custom-validator-log-formatter'));
seneca.use(store, config['postgresql-store']);
seneca.use(require('./lib/cd-events'), {logger: log.logger});
seneca.use(require('./lib/cd-events'), { logger: log.logger });
seneca.use(require('cp-permissions-plugin'), {
config: __dirname + '/config/permissions'
});

seneca.use(require('seneca-queue'));
seneca.use(require('seneca-kue'));
seneca.use(require('./lib/queues'), {config: config.kue});
seneca.use(require('./lib/queues'), { config: config.kue });

process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
process.on('uncaughtException', shutdown);
process.on('SIGUSR2', shutdown);

function shutdown (err) {
var stopQueue = seneca.export('queues/queue')['stopQueue'];
var stopQueue = seneca.export('queues/queue').stopQueue;
stopQueue();
if (err !== void 0 && err.stack !== void 0) {
console.error(new Date().toString() + ' FATAL: UncaughtException, please report: ' + util.inspect(err));
console.error(util.inspect(err.stack));
console.trace();
if (err !== undefined) {
var error = {
date: new Date().toString(),
msg: err.stack !== undefined
? 'FATAL: UncaughtException, please report: ' + util.inspect(err.stack)
: 'FATAL: UncaughtException, no stack trace',
err: util.inspect(err)
};
console.error(JSON.stringify(error));
process.exit(1);
}
process.exit(0);
}
Expand Down Expand Up @@ -86,7 +95,11 @@ require('./migrate-psql-db.js')(function (err) {
seneca.wrap('role: entity, cmd: ' + cmd, function filterFields (args, cb) {
try {
['limit$', 'skip$'].forEach(function (field) {
if (args.q[field] && args.q[field] !== 'NULL' && !/^[0-9]+$/g.test(args.q[field] + '')) {
if (
args.q[field] &&
args.q[field] !== 'NULL' &&
!/^[0-9]+$/g.test(args.q[field] + '')
) {
throw new Error('Expect limit$, skip$ to be a number');
}
});
Expand Down
Loading

0 comments on commit 43ffaa4

Please sign in to comment.