agneta-platform
Version:
Agneta Platform - Integrate and customize business applications
340 lines (255 loc) • 7.87 kB
JavaScript
/* Copyright 2017 Agneta Network Applications, LLC.
*
* Source file: services/server/remotes/activity_feed.js
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var Promise = require('bluebird');
var _ = require('lodash');
var moment = require('moment');
var S = require('string');
var refreshRate = 3000;
module.exports = function(Model, app) {
require('./activity_feed/getInfo')(Model, app);
Model.observe('access', function(ctx) {
var data = ctx.query.where;
if (data && data.value) {
data.value = format(data.value);
}
return Promise.resolve();
});
Model.observe('before save', function event(ctx, next) {
var data = ctx.instance || ctx.data;
if (data.value) {
data.value = format(data.value);
}
next();
});
function format(name) {
var res = S(name)
.collapseWhitespace()
.trim()
.s.toLowerCase();
return res;
}
////////////////////////////////////////////////////////////////////
Model.getByType = function(type) {
return Model.find({
where: {
type: type
}
})
.then(function(feeds) {
return Promise.map(feeds, function(feed) {
return Model.getInfo(feed);
});
});
};
////////////////////////////////////////////////////////////////////
var feedUpdates = {};
var delayUpdate;
(function() {
var updating = false;
var update = false;
delayUpdate = function() {
if (updating) {
update = true;
return;
}
updating = true;
setTimeout(function() {
updateFeeds(_.values(feedUpdates))
.then(function() {
update = false;
updating = false;
if (update) {
delayUpdate();
}
//console.log('feeds updated');
});
feedUpdates = {};
}, refreshRate);
};
})();
Model.prototype.onUpdate = function(activity) {
var feedUpdate = feedUpdates[this.id] = feedUpdates[this.id] || {
id: this.id,
updates: {}
};
var key = activity.year + ':' + activity.hourOfYear;
var update = feedUpdate.updates[key] = feedUpdate.updates[key] || {
hour: activity.hourOfYear,
day: activity.dayOfYear,
week: activity.week,
month: activity.month,
year: activity.year,
activities: []
};
update.activities.push(activity.id);
delayUpdate();
};
var updateQueue = [{
key: 'days',
type: 'dayOfYear'
}, {
key: 'weeks',
type: 'week'
}, {
key: 'months',
type: 'month'
}, {
key: 'years',
type: 'year'
}];
function updateFeeds(feedUpdates) {
var Count = Model.getModel('Activity_Count');
var Activity = Model.getModel('Activity_Item');
return Promise.map(feedUpdates, function(feedUpdate) {
var feed;
return Model.findById(feedUpdate.id)
.then(function(_feed) {
feed = _feed;
var ancestors = {
days: {},
weeks: {},
months: {},
years: {}
};
return Promise.map(_.values(feedUpdate.updates), function(update) {
return feed.getCount({
type: 'hourOfYear',
year: update.year,
key: update.hour,
create: true
})
.then(function(count) {
return Activity.count({
hourOfYear: update.hour,
feeds: {
inq: [feed.id]
}
})
.then(function(total) {
return count.updateAttribute('total', total);
})
.then(function(count) {
var prefix = update.year + ':';
ancestors.days[prefix + update.day] = true;
ancestors.weeks[prefix + update.week] = true;
ancestors.months[prefix + update.month] = true;
ancestors.years[prefix + update.year] = true;
return count;
});
});
})
.then(function() {
return Promise.each(updateQueue, function(data) {
return Promise.each(Object.keys(ancestors[data.key]), function(key) {
key = parseUpdateKey(key);
var count = null;
return feed.getCount({
type: data.type,
year: key.year,
key: key.value,
create: true
})
.then(function(_count) {
count = _count;
return Count.find({
limit: 0,
where: {
parentId: count.id
}
});
})
.then(function(children) {
//console.log(key, count.id, children.length);
var total = children.reduce(function(last, child) {
return child.total + (last || 0);
}, 0);
return count.updateAttribute('total', total);
});
});
});
function parseUpdateKey(key) {
key = key.split(':');
return {
year: key[0],
value: key[1]
};
}
})
.then(function() {
Model.emit('activity-update', feed);
});
});
})
.catch(function(err) {
console.error(err);
});
}
Model.prototype.getCount = function(options) {
var Count = Model.getModel('Activity_Count');
var instance = this;
var countProps = {
feedId: instance.id,
type: options.type,
year: options.year,
key: options.key
};
return Count.findOne({
where: countProps
})
.then(function(count) {
if (count) {
return count;
}
if (!options.create) {
return;
}
return Count.create(countProps)
.then(function(count) {
var parentType;
switch (options.type) {
case 'hourOfYear':
parentType = 'dayOfYear';
break;
case 'dayOfYear':
parentType = 'week';
break;
case 'week':
parentType = 'month';
break;
case 'month':
parentType = 'year';
break;
}
if (parentType) {
var utc = moment().utc().year(options.year);
var parentKey = utc[options.type](options.key)[parentType]();
return instance.getCount({
type: parentType,
key: parentKey,
year: options.year,
create: true
})
.then(function(parent) {
count.parentId = parent.id;
return count.save();
});
}
return count;
});
});
};
};