Merge pull request #643 from RocketChat/cron

Automate statistics generation and send statistics to Rocket.Chat, unless opt-out.
pull/646/head
Gabriel Engel 11 years ago
commit 0d0044bc73
  1. 3
      .meteor/packages
  2. 9
      .meteor/versions
  3. 18
      client/views/admin/adminStatistics.coffee
  4. 10
      client/views/admin/adminStatistics.html
  5. 3
      i18n/en.i18n.json
  6. 4
      packages/rocketchat-lib/package.js
  7. 2
      packages/rocketchat-lib/server/functions/checkUsernameAvailability.coffee
  8. 5
      packages/rocketchat-lib/server/functions/saveStatistics.coffee
  9. 2
      packages/rocketchat-lib/server/functions/setUsername.coffee
  10. 11
      packages/rocketchat-lib/server/methods/generateStatistics.coffee
  11. 2
      packages/rocketchat-lib/settings/server/startup.coffee
  12. 3
      packages/rocketchat-statistics/i18n/en.i18n.json
  13. 1
      packages/rocketchat-statistics/lib/rocketchat.coffee
  14. 0
      packages/rocketchat-statistics/package-tap.i18n
  15. 36
      packages/rocketchat-statistics/package.js
  16. 1
      packages/rocketchat-statistics/server/collections/MapReducedStatistics.coffee
  17. 1
      packages/rocketchat-statistics/server/collections/Statistics.coffee
  18. 6
      packages/rocketchat-statistics/server/functions/get.coffee
  19. 4
      packages/rocketchat-statistics/server/functions/getAverage.coffee
  20. 6
      packages/rocketchat-statistics/server/functions/save.coffee
  21. 11
      packages/rocketchat-statistics/server/methods/getStatistics.coffee
  22. 1
      server/lib/collections.coffee
  23. 22
      server/startup/cron.coffee
  24. 6
      server/startup/initialData.coffee

@ -63,7 +63,7 @@ nimble:restivus
nooitaf:colors
pauli:accounts-linkedin
percolate:migrations
percolatestudio:synced-cron
percolate:synced-cron
raix:handlebar-helpers
raix:ui-dropped-event
tap:i18n
@ -80,3 +80,4 @@ jalik:ufs-gridfs
monbro:mongodb-mapreduce-aggregation
rocketchat:custom-oauth
rocketchat:gitlab
rocketchat:statistics

@ -44,8 +44,8 @@ jparker:crypto-md5@0.1.1
jparker:gravatar@0.4.1
jquery@1.11.3_2
json@1.0.3
kadira:blaze-layout@2.0.0
kadira:flow-router@2.3.0
kadira:blaze-layout@2.0.1
kadira:flow-router@2.4.0
kevohagan:sweetalert@1.0.0
konecty:autolinker@1.0.2
konecty:change-case@2.3.0
@ -63,7 +63,7 @@ matb33:collection-hooks@0.7.14
meteor@1.1.6
meteor-developer@1.1.3
meteor-platform@1.2.2
meteorhacks:kadira@2.23.0
meteorhacks:kadira@2.23.1
meteorhacks:meteorx@1.3.1
meteorspark:util@0.2.0
minifiers@1.1.5
@ -88,7 +88,7 @@ ordered-dict@1.0.3
pauli:accounts-linkedin@1.1.2
pauli:linkedin@1.1.2
percolate:migrations@0.7.6
percolatestudio:synced-cron@1.1.0
percolate:synced-cron@1.2.1
qnub:emojione@0.0.3
raix:eventemitter@0.1.3
raix:eventstate@0.0.2
@ -115,6 +115,7 @@ rocketchat:markdown@0.0.1
rocketchat:me@0.0.1
rocketchat:mentions@0.0.1
rocketchat:oembed@0.0.1
rocketchat:statistics@0.0.1
rocketchat:webrtc@0.0.1
routepolicy@1.0.5
service-configuration@1.0.4

@ -26,12 +26,30 @@ Template.adminStatistics.helpers
return out
numFormat: (number) ->
return _.numberFormat(number, 2)
optOut: ->
return RocketChat.settings.get 'Statistics_opt_out'
Template.adminStatistics.events
'click input[name=opt-out-statistics]': (e) ->
if $(e.currentTarget).prop('checked')
$('#opt-out-warning').show()
RocketChat.settings.set 'Statistics_opt_out', true, ->
toastr.success TAPi18next.t 'project:Settings_updated'
else
$('#opt-out-warning').hide()
RocketChat.settings.set 'Statistics_opt_out', false, ->
toastr.success TAPi18next.t 'project:Settings_updated'
Template.adminStatistics.onRendered ->
Tracker.afterFlush ->
SideNav.setFlex "adminFlex"
SideNav.openFlex()
if RocketChat.settings.get 'Statistics_opt_out'
$('#opt-out-warning').show()
else
$('#opt-out-warning').hide()
Template.adminStatistics.onCreated ->
instance = @
@statistics = new ReactiveVar {}

@ -28,6 +28,10 @@
<th>{{_ "Stats_Online_Users"}}</th>
<td>{{statistics.onlineUsers}}</td>
</tr>
<tr>
<th>{{_ "Stats_Away_Users"}}</th>
<td>{{statistics.awayUsers}}</td>
</tr>
<tr>
<th>{{_ "Stats_Offline_Users"}}</th>
<td>{{statistics.offlineUsers}}</td>
@ -105,6 +109,12 @@
{{_ "Please_wait_statistics"}}
{{/if}}
{{/unless}}
<div style="margin: 30px 0">
<label for="opt-out-statistics"><input type="checkbox" value="1" name="opt-out-statistics" id="opt-out-statistics" checked="{{optOut}}"> {{_ "Opt_out_statistics"}}</label>
<div id="opt-out-warning" class="alert-warning" style="margin-top: 10px; padding: 10px;">
{{_ "Opt_out_statistics_warning"}}
</div>
</div>
</div>
</section>
</template>

@ -177,6 +177,8 @@
"Notify_all_in_this_room" : "Notify all in this room",
"Online" : "Online",
"Oops!" : "Oops",
"Opt_out_statistics": "Don't send my anonymous statistics to Rocket.Chat",
"Opt_out_statistics_warning": "By sending your anonymous statistics, you'll help us identify how many instances of Rocket.Chat are deployed, as well as how good the system is behaving, so we can further improve it. If you want to continue sending us your anonymous statistics, uncheck the above checkbox. Thank you.",
"others" : "others",
"Password" : "Password",
"Password_changed_successfully" : "Password changed successfully",
@ -242,6 +244,7 @@
"Stats_Avg_Private_Group_Users": "Average Private Group Users",
"Stats_Max_Room_Users": "Max Rooms Users",
"Stats_Non_Active_Users": "Inactive Users",
"Stats_Away_Users": "Away Users",
"Stats_Offline_Users": "Offline Users",
"Stats_Online_Users": "Online Users",
"Stats_OS_Arch": "OS Arch",

@ -20,14 +20,10 @@ Package.onUse(function(api) {
api.addFiles([
'server/functions/checkUsernameAvailability.coffee',
'server/functions/getAvgStatistics.coffee',
'server/functions/getStatistics.coffee',
'server/functions/saveStatistics.coffee',
'server/functions/setUsername.coffee'
], ['server']);
api.addFiles([
'server/methods/generateStatistics.coffee',
'server/methods/joinDefaultChannels.coffee',
'server/methods/setAdminStatus.coffee',
'server/methods/setUsername.coffee',

@ -1,2 +1,2 @@
RocketChat.checkUsernameAvailability = (username) ->
return not Meteor.users.findOne({ username: { $regex : new RegExp("^" + _.trim(username) + "$", "i") } })
return not Meteor.users.findOne({ username: { $regex : new RegExp("^" + s.trim(username) + "$", "i") } })

@ -1,5 +0,0 @@
RocketChat.saveStatistics = ->
statistics = RocketChat.getStatistics()
statistics.createdAt = new Date
Statistics.insert statistics
return statistics

@ -1,5 +1,5 @@
RocketChat.setUsername = (user, username) ->
username = _.trim username
username = s.trim username
if not user or not username
return false

@ -1,11 +0,0 @@
Meteor.methods
generateStatistics: ->
if not Meteor.userId()
throw new Meteor.Error('invalid-user', "[methods] generateStatistics -> Invalid user")
console.log '[methods] generateStatistics -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments
unless Meteor.user()?.admin is true
throw new Meteor.Error 'not-authorized', '[methods] setAdminStatus -> Not authorized'
return RocketChat.getStatistics()

@ -80,6 +80,8 @@ Meteor.startup ->
RocketChat.settings.add 'Layout_Privacy_Policy', 'Privacy Policy <br> Go to APP SETTINGS -> Layout to customize this page.', { type: 'string', multiline: true, group: 'Layout', public: true }
RocketChat.settings.add 'Layout_Sidenav_Footer', '<a href="https://github.com/RocketChat/Rocket.Chat" class="logo" target="_blank"> <img src="/images/logo/logo.svg?v=3" /> <small><i class="icon-github-circled"></i> Fork it on github</small> </a>', { type: 'string', group: 'Layout', public: true, i18nDescription: 'Layout_Sidenav_Footer_description' }
RocketChat.settings.add 'Statistics_opt_out', false, { type: 'boolean', group: false }
if process?.env? and not process.env['MAIL_URL']? and RocketChat.settings.get('SMTP_Host') and RocketChat.settings.get('SMTP_Username') and RocketChat.settings.get('SMTP_Password')
process.env['MAIL_URL'] = "smtp://" + encodeURIComponent(RocketChat.settings.get('SMTP_Username')) + ':' + encodeURIComponent(RocketChat.settings.get('SMTP_Password')) + '@' + encodeURIComponent(RocketChat.settings.get('SMTP_Host'))
if RocketChat.settings.get('SMTP_Port')

@ -0,0 +1,36 @@
Package.describe({
name: 'rocketchat:statistics',
version: '0.0.1',
summary: 'Statistics generator',
git: ''
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.use([
'templating',
'coffeescript',
'rocketchat:lib@0.0.1'
]);
// TAPi18n
api.use(["tap:i18n@1.5.1"], ["client", "server"]);
api.addFiles("package-tap.i18n", ["client", "server"]);
api.addFiles([
"i18n/en.i18n.json",
], ["client", "server"]);
// Statistics
api.addFiles('lib/rocketchat.coffee', [ 'client', 'server' ]);
api.addFiles([
'server/collections/Statistics.coffee',
'server/functions/get.coffee',
'server/functions/save.coffee'
], 'server');
});
Package.onTest(function(api) {
});

@ -0,0 +1 @@
@MapReducedStatistics = new Meteor.Collection 'rocketchat_mr_statistics'

@ -0,0 +1 @@
@Statistics = new Meteor.Collection 'rocketchat_statistics'

@ -1,7 +1,8 @@
RocketChat.getStatistics = ->
RocketChat.statistics.get = ->
statistics = {}
# Version
statistics.uniqueId = Settings.findOne({ _id: "uniqueID" })?.value
statistics.version = BuildInfo?.commit?.hash
statistics.versionDate = BuildInfo?.commit?.date
@ -10,7 +11,8 @@ RocketChat.getStatistics = ->
statistics.activeUsers = Meteor.users.find({ active: true }).count()
statistics.nonActiveUsers = statistics.totalUsers - statistics.activeUsers
statistics.onlineUsers = Meteor.users.find({ statusConnection: 'online' }).count()
statistics.offlineUsers = statistics.totalUsers - statistics.onlineUsers
statistics.awayUsers = Meteor.users.find({ statusConnection: 'away' }).count()
statistics.offlineUsers = statistics.totalUsers - statistics.onlineUsers - statistics.awayUsers
# Room statistics
statistics.totalRooms = ChatRoom.find().count()

@ -1,4 +1,4 @@
RocketChat.getAvgStatistics = ->
RocketChat.statistics.getAverage = ->
statistics = {}
m = ->
@ -14,6 +14,7 @@ RocketChat.getAvgStatistics = ->
a.activeUsers += b.activeUsers
a.nonActiveUsers += b.nonActiveUsers
a.onlineUsers += b.onlineUsers
a.awayUsers += b.awayUsers
a.offlineUsers += b.offlineUsers
a.totalRooms += b.totalRooms
a.totalChannels += b.totalChannels
@ -36,6 +37,7 @@ RocketChat.getAvgStatistics = ->
out.activeUsers = v.activeUsers / v.count
out.nonActiveUsers = v.nonActiveUsers / v.count
out.onlineUsers = v.onlineUsers / v.count
out.awayUsers = v.awayUsers / v.count
out.offlineUsers = v.offlineUsers / v.count
out.totalRooms = v.totalRooms / v.count
out.totalChannels = v.totalChannels / v.count

@ -0,0 +1,6 @@
RocketChat.statistics.save = ->
statistics = RocketChat.statistics.get()
statistics.createdAt = new Date
Statistics.insert statistics
return statistics

@ -0,0 +1,11 @@
Meteor.methods
getStatistics: ->
if not Meteor.userId()
throw new Meteor.Error('invalid-user', "[methods] getStatistics -> Invalid user")
console.log '[methods] getStatistics -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments
unless Meteor.user()?.admin is true
throw new Meteor.Error 'not-authorized', '[methods] getStatistics -> Not authorized'
return RocketChat.statistics.get()

@ -2,5 +2,4 @@
@ChatRoom = new Meteor.Collection 'rocketchat_room'
@ChatSubscription = new Meteor.Collection 'rocketchat_subscription'
@MapReducedStatistics = new Mongo.Collection 'rocketchat_mr_statistics'
@Statistics = new Mongo.Collection 'rocketchat_statistics'
@ChatReports = new Meteor.Collection 'rocketchat_reports'

@ -0,0 +1,22 @@
# Config and Start SyncedCron
SyncedCron.config
collectionName: 'rocketchat_cron_history'
Meteor.startup ->
Meteor.defer ->
# Generate and save statistics every hour
SyncedCron.add
name: 'Generate and save statistics',
schedule: (parser) -># parser is a later.parse object
return parser.text 'every 1 hour'
job: ->
statistics = RocketChat.statistics.save()
unless RocketChat.settings.get 'Statistics_opt_out'
console.log 'Sending statistics data to Rocket.Chat'
HTTP.post 'https://rocket.chat/stats',
data: statistics
return
SyncedCron.start()

@ -1,5 +1,11 @@
Meteor.startup ->
Meteor.defer ->
# Insert server unique id if it doesn't exist
if not Settings.findOne { _id: 'uniqueID' }
Settings.insert
_id: 'uniqueID'
value: Random.id()
if not ChatRoom.findOne('name': 'general')?
ChatRoom.insert
_id: 'GENERAL'

Loading…
Cancel
Save