Skip to content

Commit

Permalink
Merge branch 'master' into addVerticalScrollbars
Browse files Browse the repository at this point in the history
  • Loading branch information
annyhe committed Mar 23, 2017
2 parents 84a00d9 + 8033e59 commit 3f93376
Show file tree
Hide file tree
Showing 20 changed files with 589 additions and 74 deletions.
31 changes: 19 additions & 12 deletions api/v1/controllers/samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,19 +250,26 @@ module.exports = {
deleteSampleRelatedLinks(req, res, next) {
const resultObj = { reqStartTime: new Date() };
const params = req.swagger.params;
u.findByKey(helper, params)
.then((o) => u.isWritable(req, o,
featureToggles.isFeatureEnabled('enforceWritePermission')))
.then((o) => {
let jsonData = [];
if (params.relName) {
jsonData =
u.deleteAJsonArrayElement(o.relatedLinks, params.relName.value);
}
let delRlinksPromise;
if (featureToggles.isFeatureEnabled(constants.featureName) &&
helper.modelName === 'Sample') {
delRlinksPromise = redisModelSample.deleteSampleRelatedLinks(params);
} else {
delRlinksPromise = u.findByKey(helper, params)
.then((o) => u.isWritable(req, o,
featureToggles.isFeatureEnabled('enforceWritePermission')))
.then((o) => {
let jsonData = [];
if (params.relName) {
jsonData =
u.deleteAJsonArrayElement(o.relatedLinks, params.relName.value);
}

return o.update({ relatedLinks: jsonData });
})
.then((o) => {
return o.update({ relatedLinks: jsonData });
});
}

delRlinksPromise.then((o) => {
resultObj.dbTime = new Date() - resultObj.reqStartTime;
const retval = u.responsify(o, helper, req.method);

Expand Down
2 changes: 1 addition & 1 deletion api/v1/controllers/subjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ module.exports = {

const findByKeyPromise =
featureToggles.isFeatureEnabled(sampleStoreFeature) ?
u.findByKey(helper, params, ['hierarchy']) :
u.findByKey(helper, params, ['subjectHierarchy']) :
u.findByKey(helper, params, ['hierarchy', 'samples']);
findByKeyPromise
.then((o) => {
Expand Down
9 changes: 9 additions & 0 deletions api/v1/helpers/nouns/samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
'use strict';

const Sample = require('../../../../db/index').Sample;
const Aspect = require('../../../../db/index').Aspect;
const Subject = require('../../../../db/index').Subject;

const m = 'sample';
const fieldsWithJsonArrayType = ['relatedLinks'];

Expand All @@ -33,4 +36,10 @@ module.exports = {
fieldsWithJsonArrayType,
fieldsWithEnum,
fieldsToExclude,
publishEvents: true,
associatedModels: {
aspect: Aspect,
subject: Subject,
},

}; // exports
1 change: 1 addition & 0 deletions api/v1/helpers/nouns/subjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ module.exports = {
fieldScopeMap: {
samples: 'withSamples',
hierarchy: 'hierarchy',
subjectHierarchy: 'subjectHierarchy',
},
model: Subject,
modelName: 'Subject',
Expand Down
8 changes: 8 additions & 0 deletions api/v1/helpers/verbs/doDelete.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
'use strict'; // eslint-disable-line strict

const u = require('./utils');
const publisher = u.publisher;
const event = u.realtimeEvents;
const httpStatus = require('../../constants').httpStatus;
const featureToggles = require('feature-toggles');
const constants = require('../../../../cache/sampleStore').constants;
Expand Down Expand Up @@ -58,6 +60,12 @@ function doDelete(req, res, next, props) {
);
}

// publish the delete event to the redis channel
if (props.publishEvents) {
publisher.publishSample(o, props.associatedModels.subject,
event.sample.del);
}

// when a resource is deleted, delete all its associations too
u.deleteAllAssociations(o, assocNames);
u.logAPI(req, resultObj, o);
Expand Down
9 changes: 9 additions & 0 deletions api/v1/helpers/verbs/doPatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

const featureToggles = require('feature-toggles');
const u = require('./utils');
const publisher = u.publisher;
const event = u.realtimeEvents;
const httpStatus = require('../../constants').httpStatus;
const constants = require('../../../../cache/sampleStore').constants;
const redisModelSample = require('../../../../cache/models/samples');
Expand Down Expand Up @@ -66,6 +68,13 @@ function doPatch(req, res, next, props) {
.then((retVal) => {
resultObj.dbTime = new Date() - resultObj.reqStartTime;
u.logAPI(req, resultObj, retVal);

// publish the update event to the redis channel
if (props.publishEvents) {
publisher.publishSample(retVal,
props.associatedModels.subject, event.sample.upd);
}

return res.status(httpStatus.OK)
.json(u.responsify(retVal, props, req.method));
})
Expand Down
9 changes: 9 additions & 0 deletions api/v1/helpers/verbs/doPost.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
'use strict'; // eslint-disable-line strict

const u = require('./utils');
const publisher = u.publisher;
const event = u.realtimeEvents;
const httpStatus = require('../../constants').httpStatus;
const constants = require('../../../../cache/sampleStore').constants;
const redisModelSample = require('../../../../cache/models/samples');
Expand Down Expand Up @@ -47,6 +49,13 @@ function doPost(req, res, next, props) {
postPromise.then((o) => {
resultObj.dbTime = new Date() - resultObj.reqStartTime;
u.logAPI(req, resultObj, o);

// publish the update event to the redis channel
if (props.publishEvents) {
publisher.publishSample(o, props.associatedModels.subject,
event.sample.add, props.associatedModels.aspect);
}

return res.status(httpStatus.CREATED)
.json(u.responsify(o, props, req.method));
})
Expand Down
9 changes: 9 additions & 0 deletions api/v1/helpers/verbs/doPut.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

const featureToggles = require('feature-toggles');
const u = require('./utils');
const publisher = u.publisher;
const event = u.realtimeEvents;
const httpStatus = require('../../constants').httpStatus;
const constants = require('../../../../cache/sampleStore').constants;
const redisModelSample = require('../../../../cache/models/samples');
Expand Down Expand Up @@ -75,6 +77,13 @@ function doPut(req, res, next, props) {
putPromise.then((o) => {
resultObj.dbTime = new Date() - resultObj.reqStartTime;
u.logAPI(req, resultObj, o);

// publish the update event to the redis channel
if (props.publishEvents) {
publisher.publishSample(o, props.associatedModels.subject,
event.sample.upd);
}

res.status(httpStatus.OK).json(u.responsify(o, props, req.method));
})
.catch((err) => u.handleError(next, err, props.modelName));
Expand Down
1 change: 1 addition & 0 deletions api/v1/helpers/verbs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@ function checkDuplicateRLinks(rLinkArr) {
// ----------------------------------------------------------------------------

module.exports = {

realtimeEvents,

publisher,
Expand Down
59 changes: 59 additions & 0 deletions cache/models/samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,65 @@ module.exports = {
});
},

/**
* Delete sample related links
* @param {Object} params - Request parameters
* @returns {Promise} - Resolves to a sample object
*/
deleteSampleRelatedLinks(params) {
const sampleName = params.key.value;
let currSampObj;
let aspectObj;

return redisOps.getHashPromise(sampleType, sampleName)
.then((sampObj) => {
if (!sampObj) {
throw new redisErrors.ResourceNotFoundError({
explanation: 'Sample not found.',
});
}

currSampObj = sampObj;
const aspectName = sampleName.split('|')[ONE];
return redisOps.getHashPromise(aspectType, aspectName);
})
.then((aspObj) => {
if (!aspObj) {
throw new redisErrors.ResourceNotFoundError({
explanation: 'Aspect not found.',
});
}

let updatedRlinks = [];
if (params.relName) { // delete only this related link
const currRlinks = JSON.parse(currSampObj.relatedLinks);
updatedRlinks = u.deleteAJsonArrayElement(
currRlinks, params.relName.value
);
}

// if no change in related links, then return the object.
if (JSON.stringify(updatedRlinks) ===
JSON.stringify(currSampObj.relatedLinks)) {
Promise.resolve(cleanAddAspectToSample(currSampObj, aspObj));
}

const hmsetObj = {};
hmsetObj.relatedLinks = updatedRlinks;
hmsetObj.updatedAt = new Date().toString();

// stringify arrays
constants.fieldsToStringify.sample.forEach((field) => {
if (hmsetObj[field]) {
hmsetObj[field] = JSON.stringify(hmsetObj[field]);
}
});
return redisOps.setHashMultiPromise(sampleType, sampleName, hmsetObj);
})
.then(() => redisOps.getHashPromise(sampleType, sampleName))
.then((updatedSamp) => cleanAddAspectToSample(updatedSamp, aspectObj));
},

/**
* Patch sample. First get sample, if not found, throw error, else get aspect.
* Update request body with required fields based on value and related links
Expand Down
2 changes: 1 addition & 1 deletion db/model/aspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ module.exports = function aspect(seq, dataTypes) {
* on aspectStore and the aspect hash.
* 2. if the aspect is updated to published, add an entry to the
* aspectStore and create the aspect hash
* 3. if the aspect is updated to unpublihsed, delete the entry in the
* 3. if the aspect is updated to unpublished, delete the entry in the
* aspectStore, delete the aspect hash and delete the related samples
* 4. if the aspect that is updated is already published, update the
* the aspect with the new values.
Expand Down
52 changes: 4 additions & 48 deletions db/model/sample.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,10 @@ module.exports = function sample(seq, dataTypes) {
.then((o) => resolve(o))
.catch((err) => {
if (isBulk) {
/* adding isFailed:true to differentiate failed results from
success results in bulk upsert */
/*
* adding isFailed:true to differentiate failed results from
* success results in bulk upsert
*/
resolve({ explanation: err, isFailed: true });
} else {
reject(err);
Expand Down Expand Up @@ -319,52 +321,6 @@ module.exports = function sample(seq, dataTypes) {
);
}, // hooks.beforeCreate

/**
* Publishes the created sample to redis channel *including* the values
* from its aspect association.
*
* @param {Sample} inst - The newly-created instance
*/
afterCreate(inst /* , opts */) {
let samp;
Sample.findOne({
where: {
name: {
$iLike: inst.getDataValue('name'),
},
},
})
.then((found) => {
samp = found;
return common.sampleAspectAndSubjectArePublished(seq, samp);
})
.then((published) => {
if (published) {
// augment the sample instance with the subject instance to enable
// filtering by subjecttags in the realtime socketio module
common.augmentSampleWithSubjectAspectInfo(seq, samp)
.then(() => common.publishChange(samp, eventName.add));
}
});
},

/**
* Publishes the delete to redis subscriber
*
* @param {Sample} inst - The Sample instance which was just deleted
*/
afterDelete(inst /* , opts */) {
return common.sampleAspectAndSubjectArePublished(seq, inst)
.then((published) => {
if (published) {
// augument the sample instance with the subject instance to enable
// filtering by subjecttags in the realtime socketio module
common.augmentSampleWithSubjectAspectInfo(seq, inst)
.then(() => common.publishChange(inst, eventName.del));
}
});
}, // hooks.afterDelete

/**
* Update isDeleted.
* Publishes the deleted sample to redis channel.
Expand Down
16 changes: 16 additions & 0 deletions db/model/subject.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,22 @@ module.exports = function subject(seq, dataTypes) {
},
],
});
Subject.addScope('subjectHierarchy', {
where: {
isPublished: true,
},
include: [
{
model: models.Subject,
as: 'descendents',
hierarchy: true,
required: false,
where: {
isPublished: true,
},
},
],
});
},
},
hooks: {
Expand Down
35 changes: 26 additions & 9 deletions realtime/redisPublisher.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,32 +92,49 @@ function publishObject(inst, event, changedKeys, ignoreAttributes) {
* a absolutePath field added to it before the sample is published to the redis
* channel.
* @param {Object} sampleInst - The sample instance to be published
* @param {Model} model - The subject model used to get the related subject
* instance
* @param {Model} subjectModel - The subject model to get the related
* subject instance
* @param {String} event - Type of the event that is being published
* @param {Model} aspectModel - The aspect model to get the related
* aspect instance
* @returns {Promise} - which resolves to a sample object
*/
function publishSample(sampleInst, model, event) {
function publishSample(sampleInst, subjectModel, event, aspectModel) {
const eventType = event || getSampleEventType(sampleInst);
const sample = sampleInst.get ? sampleInst.get() : sampleInst;
const subName = sample.name.split('|')[0];
const options = {};
options.where = { absolutePath: subName };
return model.findOne(options)
const nameParts = sample.name.split('|');
const subName = nameParts[0];
const aspName = nameParts[1];
const subOpts = {
where: {
absolutePath: subName,
},
};
const aspOpts = {
where: {
name: aspName,
},
};
const getAspect = aspectModel ? aspectModel.findOne(aspOpts) :
Promise.resolve(sample.aspect);
return getAspect
.then((asp) => {
sample.aspect = asp.get ? asp.get() : asp;
return subjectModel.findOne(subOpts);
})
.then((sub) => {
if (sub) {

/*
*pass the sample instance to the publishObject function only if the
*aspect and subject are published
*/
if (sample.aspect && sample.aspect.isPublished && sub.isPublished) {

// attach subject to the sample
sample.subject = sub.get();

// attach absolutePath field to the sample
sample.absolutePath = subName;

publishObject(sample, eventType);
}
}
Expand Down
Loading

0 comments on commit 3f93376

Please sign in to comment.