diff --git a/.meteor/packages b/.meteor/packages index 4610b7e4b2e..1f8dcda4e2e 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -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 diff --git a/.meteor/versions b/.meteor/versions index 2ac6859d26b..6d51817b864 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -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 diff --git a/client/views/admin/adminStatistics.coffee b/client/views/admin/adminStatistics.coffee index 454a0e16711..f0d629a7f78 100644 --- a/client/views/admin/adminStatistics.coffee +++ b/client/views/admin/adminStatistics.coffee @@ -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 {} diff --git a/client/views/admin/adminStatistics.html b/client/views/admin/adminStatistics.html index 24d29dc72df..fd02286c166 100644 --- a/client/views/admin/adminStatistics.html +++ b/client/views/admin/adminStatistics.html @@ -28,6 +28,10 @@ {{_ "Stats_Online_Users"}} {{statistics.onlineUsers}} + + {{_ "Stats_Away_Users"}} + {{statistics.awayUsers}} + {{_ "Stats_Offline_Users"}} {{statistics.offlineUsers}} @@ -105,6 +109,12 @@ {{_ "Please_wait_statistics"}} {{/if}} {{/unless}} +
+ +
+ {{_ "Opt_out_statistics_warning"}} +
+
\ No newline at end of file diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 8fbf6ba1533..119d29f1d79 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -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", diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index fc6d85e3824..4aa1ae6af4d 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -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', diff --git a/packages/rocketchat-lib/server/functions/checkUsernameAvailability.coffee b/packages/rocketchat-lib/server/functions/checkUsernameAvailability.coffee index 1dd34b347b5..ea855eb7ecc 100644 --- a/packages/rocketchat-lib/server/functions/checkUsernameAvailability.coffee +++ b/packages/rocketchat-lib/server/functions/checkUsernameAvailability.coffee @@ -1,2 +1,2 @@ RocketChat.checkUsernameAvailability = (username) -> - return not Meteor.users.findOne({ username: { $regex : new RegExp("^" + _.trim(username) + "$", "i") } }) \ No newline at end of file + return not Meteor.users.findOne({ username: { $regex : new RegExp("^" + s.trim(username) + "$", "i") } }) \ No newline at end of file diff --git a/packages/rocketchat-lib/server/functions/saveStatistics.coffee b/packages/rocketchat-lib/server/functions/saveStatistics.coffee deleted file mode 100644 index fca2fb1c808..00000000000 --- a/packages/rocketchat-lib/server/functions/saveStatistics.coffee +++ /dev/null @@ -1,5 +0,0 @@ -RocketChat.saveStatistics = -> - statistics = RocketChat.getStatistics() - statistics.createdAt = new Date - Statistics.insert statistics - return statistics \ No newline at end of file diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index b16764b61fa..aed65e1e30a 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -1,5 +1,5 @@ RocketChat.setUsername = (user, username) -> - username = _.trim username + username = s.trim username if not user or not username return false diff --git a/packages/rocketchat-lib/server/methods/generateStatistics.coffee b/packages/rocketchat-lib/server/methods/generateStatistics.coffee deleted file mode 100644 index 2f6174ea08a..00000000000 --- a/packages/rocketchat-lib/server/methods/generateStatistics.coffee +++ /dev/null @@ -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() \ No newline at end of file diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 1cb75e2b1bc..26625bc159c 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -80,6 +80,8 @@ Meteor.startup -> RocketChat.settings.add 'Layout_Privacy_Policy', 'Privacy Policy
Go to APP SETTINGS -> Layout to customize this page.', { type: 'string', multiline: true, group: 'Layout', public: true } RocketChat.settings.add 'Layout_Sidenav_Footer', '', { 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') diff --git a/packages/rocketchat-statistics/i18n/en.i18n.json b/packages/rocketchat-statistics/i18n/en.i18n.json new file mode 100644 index 00000000000..4eb7c3f9836 --- /dev/null +++ b/packages/rocketchat-statistics/i18n/en.i18n.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/packages/rocketchat-statistics/lib/rocketchat.coffee b/packages/rocketchat-statistics/lib/rocketchat.coffee new file mode 100644 index 00000000000..3111fcc9479 --- /dev/null +++ b/packages/rocketchat-statistics/lib/rocketchat.coffee @@ -0,0 +1 @@ +RocketChat.statistics = {} diff --git a/packages/rocketchat-statistics/package-tap.i18n b/packages/rocketchat-statistics/package-tap.i18n new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-statistics/package.js b/packages/rocketchat-statistics/package.js new file mode 100644 index 00000000000..541d7a82532 --- /dev/null +++ b/packages/rocketchat-statistics/package.js @@ -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) { + +}); diff --git a/packages/rocketchat-statistics/server/collections/MapReducedStatistics.coffee b/packages/rocketchat-statistics/server/collections/MapReducedStatistics.coffee new file mode 100644 index 00000000000..be489dba370 --- /dev/null +++ b/packages/rocketchat-statistics/server/collections/MapReducedStatistics.coffee @@ -0,0 +1 @@ +@MapReducedStatistics = new Meteor.Collection 'rocketchat_mr_statistics' diff --git a/packages/rocketchat-statistics/server/collections/Statistics.coffee b/packages/rocketchat-statistics/server/collections/Statistics.coffee new file mode 100644 index 00000000000..3cf64d0319c --- /dev/null +++ b/packages/rocketchat-statistics/server/collections/Statistics.coffee @@ -0,0 +1 @@ +@Statistics = new Meteor.Collection 'rocketchat_statistics' diff --git a/packages/rocketchat-lib/server/functions/getStatistics.coffee b/packages/rocketchat-statistics/server/functions/get.coffee similarity index 91% rename from packages/rocketchat-lib/server/functions/getStatistics.coffee rename to packages/rocketchat-statistics/server/functions/get.coffee index cfb726ed408..e79c9c68118 100644 --- a/packages/rocketchat-lib/server/functions/getStatistics.coffee +++ b/packages/rocketchat-statistics/server/functions/get.coffee @@ -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() diff --git a/packages/rocketchat-lib/server/functions/getAvgStatistics.coffee b/packages/rocketchat-statistics/server/functions/getAverage.coffee similarity index 93% rename from packages/rocketchat-lib/server/functions/getAvgStatistics.coffee rename to packages/rocketchat-statistics/server/functions/getAverage.coffee index b76754d3f36..68098b50655 100644 --- a/packages/rocketchat-lib/server/functions/getAvgStatistics.coffee +++ b/packages/rocketchat-statistics/server/functions/getAverage.coffee @@ -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 diff --git a/packages/rocketchat-statistics/server/functions/save.coffee b/packages/rocketchat-statistics/server/functions/save.coffee new file mode 100644 index 00000000000..ed19daf541e --- /dev/null +++ b/packages/rocketchat-statistics/server/functions/save.coffee @@ -0,0 +1,6 @@ +RocketChat.statistics.save = -> + statistics = RocketChat.statistics.get() + statistics.createdAt = new Date + Statistics.insert statistics + return statistics + diff --git a/packages/rocketchat-statistics/server/methods/getStatistics.coffee b/packages/rocketchat-statistics/server/methods/getStatistics.coffee new file mode 100644 index 00000000000..dde2b348a10 --- /dev/null +++ b/packages/rocketchat-statistics/server/methods/getStatistics.coffee @@ -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() \ No newline at end of file diff --git a/server/lib/collections.coffee b/server/lib/collections.coffee index 4c22f223ad0..cf46a682a08 100644 --- a/server/lib/collections.coffee +++ b/server/lib/collections.coffee @@ -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' diff --git a/server/startup/cron.coffee b/server/startup/cron.coffee new file mode 100644 index 00000000000..fb431b6bd39 --- /dev/null +++ b/server/startup/cron.coffee @@ -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() diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee index 9eb3d92c4fb..9af24b91b5b 100644 --- a/server/startup/initialData.coffee +++ b/server/startup/initialData.coffee @@ -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'