Commit 593f2c73 authored by Nacim Goura's avatar Nacim Goura

add statistique

parent 40d432f3
......@@ -20,7 +20,8 @@ caching-compiler@1.1.9
caching-html-compiler@1.1.2
callback-hook@1.0.10
check@1.2.5
coffeescript@1.12.6_1
coffeescript@1.12.7_1
coffeescript-compiler@1.12.7_1
cosmos:browserify@0.10.0
dburles:collection-helpers@1.1.0
ddp@1.3.0
......@@ -57,14 +58,14 @@ livedata@1.0.18
localstorage@1.1.1
logging@1.1.17
matb33:collection-hooks@0.8.4
meteor@1.7.0
meteor@1.7.1
meteor-base@1.1.0
minifier-css@1.2.16
minifier-js@2.1.1
minimongo@1.2.1
mobile-experience@1.0.4
mobile-status-bar@1.0.14
modules@0.9.2
modules@0.9.4
modules-runtime@0.8.0
momentjs:moment@2.18.1
mongo@1.1.22
......@@ -74,7 +75,7 @@ npm-mongo@2.2.30
observe-sequence@1.0.16
ordered-dict@1.0.9
ostrio:cookies@2.2.2
ostrio:files@1.8.0
ostrio:files@1.8.2
percolate:synced-cron@1.3.2
practicalmeteor:chai@2.1.0_1
practicalmeteor:loglevel@1.2.0_2
......@@ -94,7 +95,7 @@ service-configuration@1.0.11
session@1.1.7
sha@1.0.9
spacebars@1.0.15
spacebars-compiler@1.1.2
spacebars-compiler@1.1.3
srp@1.0.10
standard-minifier-css@1.3.4
standard-minifier-js@2.1.1
......
......@@ -3,7 +3,7 @@ import SimpleSchema from 'simpl-schema';
import { Mongo } from 'meteor/mongo';
/**
* this collection keep tracks of all notification of this application
* this collection keep tracks of all jobs of this application
* @type {Mongo.Collection}
*/
const jobsCollection = new Mongo.Collection('jobs');
......
......@@ -4,6 +4,7 @@ import { Meteor } from 'meteor/meteor';
import _ from 'lodash';
import Search from '/imports/api/search/server/search';
import formSearchSchema from '/imports/api/search/formSearchSchema';
import statCollection from '/imports/api/statistique/statCollection';
export async function searchWebsite(data, userId) {
check(data, Object);
......@@ -11,8 +12,16 @@ export async function searchWebsite(data, userId) {
const search = new Search(userId);
try {
const results = await search.searchWebsite(data.searchTerm);
const responseTime = results.took ? results.took / 1000 : null;
statCollection.rawCollection().insert({
term: data.searchTerm,
numberResult: results.hits.total,
responseTime,
userId,
createdAt: new Date(),
});
return {
time: results.took ? results.took / 1000 : null,
time: responseTime,
total: results.hits.total,
list: _.map(results.hits.hits, '_source'),
};
......
import { Meteor } from 'meteor/meteor';
import statCollection from '../statCollection';
Meteor.publish('stats', () => statCollection.find({ userId: Meteor.userId() }));
import SimpleSchema from 'simpl-schema';
import { Mongo } from 'meteor/mongo';
/**
* this collection keep tracks of all stats of this application
* @type {Mongo.Collection}
*/
const statsCollection = new Mongo.Collection('stats');
SimpleSchema.statsCollection = new SimpleSchema({
term: {
type: String,
},
numberResult: {
type: Number,
defaultValue: 0,
},
responseTime: {
type: Number,
},
createdAt: {
type: Date,
},
userId: {
type: String,
},
});
statsCollection.attachSchema(SimpleSchema.statsCollection);
export default statsCollection;
......@@ -39,22 +39,6 @@ adminSection.route('/account', {
}],
});
adminSection.route('/stat', {
name: 'statistique',
action() {
BlazeLayout.render('mainLayoutTpl', {
sidebar: 'sidebarLayoutTpl',
main: 'statTpl',
navbar: 'navbarLayoutTpl',
});
},
triggersEnter: [(context, redirect) => {
if (Meteor.user() && Meteor.user().roles && Meteor.user().roles[0] !== 'admin') {
redirect('home');
}
}],
});
adminSection.route('/notif', {
name: 'notif',
action() {
......
......@@ -16,7 +16,7 @@ import '/imports/ui/pages/login/login';
import '/imports/ui/pages/not-found/not-found';
import '/imports/ui/pages/admin/indexation/indexation';
import '/imports/ui/pages/admin/account/account';
import '/imports/ui/pages/admin/statistique/statistique';
import '/imports/ui/pages/statistique/statistique';
import '/imports/ui/pages/notif/notif';
import '/imports/ui/components/testSearch/testSearch';
......@@ -58,6 +58,20 @@ FlowRouter.route('/login', {
},
});
FlowRouter.route('/stat', {
name: 'statistique',
action() {
BlazeLayout.render('mainLayoutTpl', {
sidebar: 'sidebarLayoutTpl',
main: 'statTpl',
navbar: 'navbarLayoutTpl',
});
},
subscriptions() {
this.register('stats', Meteor.subscribe('stats'));
},
});
FlowRouter.route('/logout', {
name: 'logout',
action() {
......
......@@ -9,8 +9,9 @@ import '/imports/api/testSearch/methods';
import '/imports/api/search/methods';
// publications
import '/imports/api/crawl/publications';
import '/imports/api/config/publications';
import '/imports/api/crawl/server/publications';
import '/imports/api/config/server/publications';
import '/imports/api/statistique/server/publications';
// tabular
import '/imports/tabular/tabularUser';
......
......@@ -18,7 +18,7 @@
<a href="/admin/account"><i class="fa fa-fw fa-user fa-20px" aria-hidden="true"></i> Comptes</a>
</li>
<li>
<a href="/admin/stat"><i class="fa fa-fw fa-bar-chart-o fa-20px" aria-hidden="true"></i> Statistiques</a>
<a href="/stat"><i class="fa fa-fw fa-bar-chart-o fa-20px" aria-hidden="true"></i> Statistiques</a>
</li>
{{/if}}
<li>
......
<template name="statTpl">
<div class="row">
<h3 class="text-center">Page des statistiques</h3>
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
<select name="selectDateChart" id="selectDateChart" class="form-control">
<option value="day">Jour</option>
<option value="week">Semaine</option>
<option value="month">Mois</option>
</select>
<div class="col-md-6">
<canvas id="termFrequencyChart"></canvas>
</div>
<div class="col-md-6">
<canvas id="responseTimeChart"></canvas>
</div>
</div>
</div>
</div>
</div>
</template>
import _ from 'lodash';
import { Template } from 'meteor/templating';
import moment from 'moment';
import statCollection from '/imports/api/statistique/statCollection';
import Chart from 'chart.js';
import './statistique.html';
function countOccurrence(arr) {
const a = [];
const b = [];
let prev = null;
arr.sort();
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== prev) {
a.push(arr[i]);
b.push(1);
} else {
b[b.length - 1]++;
}
prev = arr[i];
}
return [a, b];
}
function defineFrequencyTerm(stats) {
const listTerm = _.map(stats, 'term');
const data = countOccurrence(listTerm);
const ctx = document.getElementById('termFrequencyChart').getContext('2d');
new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: data[0],
datasets: [{
backgroundColor: ['#3e95cd', '#8e5ea2', '#3cba9f', '#e8c3b9', '#c45850'],
data: data[1],
}],
},
options: {
legend: { display: false },
title: {
display: true,
text: 'Fréquence des termes',
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
callback(value) { if (value % 1 === 0) { return value; } },
},
}],
},
},
});
}
function defineResponseTime(stats, filter) {
const format = filter === 'day' ? 'LT' : 'L';
const ctx = document.getElementById('responseTimeChart').getContext('2d');
const data = {};
_.forEach(stats, (item) => {
item.createdAt = moment(item.createdAt).format(format);
if (data[item.createdAt]) {
data[item.createdAt].number++;
data[item.createdAt].responseTime += item.responseTime;
} else {
data[item.createdAt] = {
number: 1,
responseTime: item.responseTime,
};
}
});
_.forOwn(data, (item) => {
item.responseTime /= item.number;
});
new Chart(ctx, {
type: 'line',
data: {
labels: _.keys(data),
datasets: [{
data: _.map(data, 'responseTime'),
borderColor: '#3e95cd',
fill: false,
}],
},
options: {
legend: { display: false },
title: {
display: true,
text: 'Temps de réponse (en seconde)',
},
scales: {
yAxes: [{
stacked: true,
}],
},
},
});
}
Template.statTpl.hooks({
rendered() {
this.autorun(() => {
const stats = statCollection.find({}).fetch();
if (stats && stats.length) {
defineResponseTime(stats, 'day');
defineFrequencyTerm(stats);
}
});
},
});
Template.statTpl.events({
'change #selectDateChart': (event) => {
const filter = event.currentTarget.value;
if (filter) {
const stats = statCollection.find({
createdAt: {
$gte: moment().startOf(filter).toDate(),
$lte: moment().endOf(filter).toDate(),
},
}).fetch();
if (stats && stats.length) {
defineResponseTime(stats, filter);
defineFrequencyTerm(stats);
}
}
},
});
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment