Skip to content

Commit

Permalink
Add deck stats store and actions
Browse files Browse the repository at this point in the history
  • Loading branch information
stavmars committed Nov 1, 2018
1 parent b233185 commit 369d591
Show file tree
Hide file tree
Showing 11 changed files with 289 additions and 35 deletions.
25 changes: 25 additions & 0 deletions actions/stats/loadDeckStats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import async from 'async';
const log = require('../log/clog');
import serviceUnavailable from '../error/serviceUnavailable';
import loadDeckUserStats from './loadDeckUserStats';
import loadDeckStatsByTime from './loadDeckStatsByTime';


export default function loadDeckStats(context, payload, done) {
log.info(context);
async.parallel([
(callback) => {
context.executeAction(loadDeckStatsByTime, payload, callback);
},
(callback) => {
context.executeAction(loadDeckUserStats, payload, callback);
},
], (err, results) => {
if (err) {
log.error(context, {filepath: __filename});
context.executeAction(serviceUnavailable, payload, done);
return;
}
done();
});
}
23 changes: 23 additions & 0 deletions actions/stats/loadDeckStatsByTime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const log = require('../log/clog');
import serviceUnavailable from '../error/serviceUnavailable';
import DeckStatsStore from '../../stores/DeckStatsStore';


export default function loadDeckStatsByTime(context, payload, done) {
let datePeriod = context.getStore(DeckStatsStore).timelineFilters.datePeriod;
let activityType = context.getStore(DeckStatsStore).timelineFilters.activityType;

log.info(context);

context.dispatch('SET_DECK_STATS_BY_TIME_LOADING');

context.service.read('stats.deckStatsByTime', {datePeriod, deckId: payload.deckId, activityType}, {timeout: 20 * 1000}, (err, res) => {
if (err) {
log.error(context, {filepath: __filename});
context.executeAction(serviceUnavailable, payload, done);
} else {
context.dispatch('LOAD_DECK_STATS_BY_TIME', {statsByTime: res});
}
done();
});
}
23 changes: 23 additions & 0 deletions actions/stats/loadDeckUserStats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const log = require('../log/clog');
import serviceUnavailable from '../error/serviceUnavailable';
import DeckStatsStore from '../../stores/DeckStatsStore';


export default function loadDeckUserStats(context, payload, done) {
let datePeriod = context.getStore(DeckStatsStore).membersStatsFilters.datePeriod;
let activityType = context.getStore(DeckStatsStore).membersStatsFilters.activityType;

log.info(context);

context.dispatch('SET_DECK_USER_STATS_LOADING');

context.service.read('stats.deckUserStats', {datePeriod, deckId: payload.deckId, activityType}, {timeout: 20 * 1000}, (err, res) => {
if (err) {
log.error(context, {filepath: __filename});
context.executeAction(serviceUnavailable, payload, done);
} else {
context.dispatch('LOAD_DECK_USER_STATS', {deckUserStats: res});
}
done();
});
}
23 changes: 23 additions & 0 deletions actions/stats/updateDeckActivityTimelineFilters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import async from 'async';
const log = require('../log/clog');
import serviceUnavailable from '../error/serviceUnavailable';
import loadDeckStatsByTime from '../stats/loadDeckStatsByTime';


export default function updateDeckStatsActivityType(context, payload, done) {
log.info(context);
context.dispatch('UPDATE_DECK_ACTIVITY_TIMELINE_FILTERS', payload);

async.parallel([
(callback) => {
context.executeAction(loadDeckStatsByTime, payload, callback);
},
], (err, results) => {
if (err) {
log.error(context, {filepath: __filename});
context.executeAction(serviceUnavailable, payload, done);
return;
}
done();
});
}
23 changes: 23 additions & 0 deletions actions/stats/updateDeckUserStatsFilters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import async from 'async';
const log = require('../log/clog');
import serviceUnavailable from '../error/serviceUnavailable';
import loadDeckUserStats from '../stats/loadDeckUserStats';


export default function updateDeckUserStatsFilters(context, payload, done) {
log.info(context);
context.dispatch('UPDATE_DECK_USER_STATS_FILTERS', payload);

async.parallel([
(callback) => {
context.executeAction(loadDeckUserStats, payload, callback);
},
], (err, results) => {
if (err) {
log.error(context, {filepath: __filename});
context.executeAction(serviceUnavailable, payload, done);
return;
}
done();
});
}
5 changes: 4 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ import LoginModalStore from './stores/LoginModalStore';
import UserStatsStore from './stores/UserStatsStore';
import UserGroupsStore from './stores/UserGroupsStore';
import GroupStatsStore from './stores/GroupStatsStore';
import DeckStatsStore from './stores/DeckStatsStore';


// create new fluxible instance & register all stores
const app = new Fluxible({
Expand Down Expand Up @@ -112,7 +114,8 @@ const app = new Fluxible({
LoginModalStore,
UserStatsStore,
UserGroupsStore,
GroupStatsStore
GroupStatsStore,
DeckStatsStore,
]
});

Expand Down
52 changes: 24 additions & 28 deletions components/Deck/DeckStats.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import {Grid} from 'semantic-ui-react';

// import updateDeckActivityTimelineFilters from '../../actions/stats/updateDeckActivityTimelineFilters';
// import updateDeckUsersStatsFilters from '../../actions/stats/updateDeckUsersStatsFilters';
import updateDeckActivityTimelineFilters from '../../actions/stats/updateDeckActivityTimelineFilters';
import updateDeckUserStatsFilters from '../../actions/stats/updateDeckUserStatsFilters';

import {defineMessages} from 'react-intl';
import ActivityTimeline from '../../components/Stats/ActivityTimeline';
Expand All @@ -20,43 +20,39 @@ class DeckStats extends React.Component {

getIntlMessages() {
return defineMessages({
membersStatsTitle: {
id: 'Stats.deckUsersStatsTitle',
deckUserStatsTitle: {
id: 'Stats.deckUserStatsTitle',
defaultMessage: 'User Activity'
},
});
}

handleTimelinePeriodChange(event, {value}) {
// TODO
// this.context.executeAction(updateDeckActivityTimelineFilters, {
// datePeriod: value,
// deckid: this.props.deckid,
// });
this.context.executeAction(updateDeckActivityTimelineFilters, {
datePeriod: value,
deckId: this.props.deckId,
});
}

handleTimelineActivityChange(event, {value}) {
// TODO
// this.context.executeAction(updateDeckActivityTimelineFilters, {
// activityType: value,
// deckid: this.props.deckid,
// });
this.context.executeAction(updateDeckActivityTimelineFilters, {
activityType: value,
deckId: this.props.deckId,
});
}

handleMembersStatsPeriodChange(event, {value}) {
// TODO
// this.context.executeAction(updateDeckUsersStatsFilters, {
// datePeriod: value,
// deckid: this.props.deckid,
// });
this.context.executeAction(updateDeckUserStatsFilters, {
datePeriod: value,
deckId: this.props.deckId,
});
}

handleMembersStatsActivityChange(event, {value}) {
// TODO
// this.context.executeAction(updateDeckUsersStatsFilters, {
// activityType: value,
// deckid: this.props.deckid,
// });
this.context.executeAction(updateDeckUserStatsFilters, {
activityType: value,
deckId: this.props.deckId,
});
}

render() {
Expand All @@ -74,10 +70,10 @@ class DeckStats extends React.Component {
</Grid.Row>
<Grid.Row columns={1}>
<Grid.Column>
<UserBarChart title={this.context.intl.formatMessage(this.messages.membersStatsTitle)} data={this.props.deckStats.membersStats}
loading={this.props.deckStats.membersStatsLoading}
activityType={this.props.deckStats.membersStatsFilters.activityType}
datePeriod={this.props.deckStats.membersStatsFilters.datePeriod}
<UserBarChart title={this.context.intl.formatMessage(this.messages.deckUserStatsTitle)} data={this.props.deckStats.deckUserStats}
loading={this.props.deckStats.deckUserStatsLoading}
activityType={this.props.deckStats.deckUserStatsFilters.activityType}
datePeriod={this.props.deckStats.deckUserStatsFilters.datePeriod}
handleActivityTypeChange={this.handleMembersStatsActivityChange.bind(this)}
handleDatePeriodChange={this.handleMembersStatsPeriodChange.bind(this)} />
</Grid.Column>
Expand Down
8 changes: 4 additions & 4 deletions components/Deck/DeckStatsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Grid, Divider, Button, Header, Image, Icon, Item, Label, Menu, Segment,
import { connectToStores } from 'fluxible-addons-react';
import DeckPageStore from '../../stores/DeckPageStore';
import DeckViewStore from '../../stores/DeckViewStore';
import GroupStatsStore from '../../stores/GroupStatsStore'; // TODO remove this
import DeckStatsStore from '../../stores/DeckStatsStore';

import { Microservices } from '../../configs/microservices';
import CustomDate from './util/CustomDate';
Expand Down Expand Up @@ -87,7 +87,7 @@ class DeckStatsPage extends React.Component {
</div>
);

let statsElement = <DeckStats deckid={null} deckStats={this.props.GroupStatsStore} />;
let statsElement = <DeckStats deckId={selector.id} deckStats={this.props.DeckStatsStore} />;

return (
<Grid padded="vertically" stackable>
Expand All @@ -110,11 +110,11 @@ class DeckStatsPage extends React.Component {
}
}

DeckStatsPage = connectToStores(DeckStatsPage, [DeckPageStore, DeckViewStore, GroupStatsStore], (context, props) => {
DeckStatsPage = connectToStores(DeckStatsPage, [DeckPageStore, DeckViewStore, DeckStatsStore], (context, props) => {
return {
DeckPageStore: context.getStore(DeckPageStore).getState(),
DeckViewStore: context.getStore(DeckViewStore).getState(),
GroupStatsStore: context.getStore(GroupStatsStore).getState(),
DeckStatsStore: context.getStore(DeckStatsStore).getState(),
};
});

Expand Down
16 changes: 15 additions & 1 deletion configs/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import checkReviewableUser from '../actions/userReview/checkReviewableUser';
import loadCollection from '../actions/collections/loadCollection';
import prepareSSO from '../actions/user/prepareSSO';
import {navigateAction} from 'fluxible-router';
import loadDeckStats from '../actions/stats/loadDeckStats';


export default {
//-----------------------------------HomePage routes------------------------------
Expand Down Expand Up @@ -381,7 +383,19 @@ export default {
handler: require('../components/Deck/DeckStatsPage'),
page: 'deckstatspage',
action: (context, payload, done) => {
context.executeAction(loadDeck, payload, done);
async.series([
(callback) => {
context.executeAction(loadDeck, payload, callback);
},
(callback) => {
context.executeAction(loadDeckStats, {deckId: payload.params.id}, callback);
},
(err, result) => {
if(err) console.log(err);
done();
}
]);

}
},

Expand Down
42 changes: 41 additions & 1 deletion services/stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default {
name: 'stats',
read: (req, resource, params, config, callback) => {
let args = params.params ? params.params : params;
let {username, activityType, datePeriod, groupid} = args;
let {username, activityType, datePeriod, groupid, deckId} = args;

if (resource === 'stats.userStatsByTime') {
let fromDate = periodToDate(datePeriod);
Expand Down Expand Up @@ -92,6 +92,46 @@ export default {
json: true
}).then((response) => callback(null, fillMissingDates(fromDate, response)))
.catch((err) => callback(err));
} else if (resource === 'stats.deckStatsByTime') {
let fromDate = periodToDate(datePeriod);
let pipeline = [{
'$match': {
'timestamp': {'$gte': {'$dte': fromDate.toISOString()}},
'statement.verb.id': activityTypeToVerb(activityType),
'statement.context.contextActivities.parent.id': {'$regex': new RegExp(`/deck/${deckId.split('-')[0]}$`)}
}
}, {
'$project': {
'date': {
'$dateToString': {
'format': '%Y-%m-%d',
'date': '$timestamp'
}
}
}
}, {
'$group': {
'_id': '$date',
'count': {
'$sum': 1
}
}
}, {
'$sort': {
'_id': 1
}
}];
console.log(JSON.stringify(pipeline));
rp({
method: 'GET',
uri: Microservices.lrs.uri + '/statements/aggregate',
qs: {
pipeline: JSON.stringify(pipeline),
},
headers: {'Authorization': 'Basic ' + Microservices.lrs.basicAuth},
json: true
}).then((response) => callback(null, fillMissingDates(fromDate, response)))
.catch((err) => callback(err));
} else if (resource === 'stats.groupStatsByTime') {
let fromDate = periodToDate(datePeriod);
rp.post({
Expand Down
Loading

0 comments on commit 369d591

Please sign in to comment.