diff --git a/lib/usageStats.js b/lib/usageStats.js new file mode 100644 index 000000000..a6fc908a4 --- /dev/null +++ b/lib/usageStats.js @@ -0,0 +1,228 @@ +var moment = require('moment') +var papaparse = require('papaparse') + +export async function getActiveUsers (startTime, endTime) { + const startTimeISOString = new Date(startTime).toISOString() + const endTimeISOString = new Date(endTime).toISOString() + + return bookshelf.knex.raw(` + -- Post created + SELECT posts.user_id + FROM posts + WHERE posts.type NOT IN('welcome', 'thread') + AND posts.created_at > '${startTimeISOString}' + AND posts.created_at <= '${endTimeISOString}' + + UNION + + -- Comment created + SELECT comments.user_id + FROM comments + JOIN posts ON posts.id = comments.post_id + WHERE comments.created_at > '${startTimeISOString}' + AND comments.created_at <= '${endTimeISOString}' + AND posts.type NOT IN('welcome', 'thread') + + UNION + + -- Direct Message created + SELECT comments.user_id + FROM comments + JOIN posts ON posts.id = comments.post_id + WHERE comments.created_at > '${startTimeISOString}' + AND comments.created_at <= '${endTimeISOString}' + AND posts.type = 'thread' + + UNION + + -- Community created + SELECT communities.created_by_id + FROM communities + WHERE communities.created_at > '${startTimeISOString}' + AND communities.created_at <= '${endTimeISOString}' + + UNION + + -- Tags created: + SELECT user_id + FROM communities_tags + WHERE communities_tags.created_at > '${startTimeISOString}' + AND communities_tags.created_at <= '${endTimeISOString}' + + UNION + + -- Tag followed + SELECT tag_follows.user_id + FROM tag_follows + WHERE tag_follows.created_at > '${startTimeISOString}' + AND tag_follows.created_at <= '${endTimeISOString}' + + UNION + + -- Community Invites created + SELECT community_invites.invited_by_id + FROM community_invites + WHERE community_invites.created_at > '${startTimeISOString}' + AND community_invites.created_at <= '${endTimeISOString}' + + UNION + + -- Community Invites accepted + SELECT community_invites.used_by_id + FROM community_invites + WHERE community_invites.used_at > '${startTimeISOString}' + AND community_invites.used_at <= '${endTimeISOString}' + + UNION + + -- Upvote created (~ base on post.created_at date...) + SELECT votes.user_id + FROM votes + JOIN posts ON posts.id = votes.post_id + WHERE posts.created_at > '${startTimeISOString}' + AND posts.created_at <= '${endTimeISOString}' + `) +} + +export async function getActiveCommunities (startTime, endTime) { + const startTimeISOString = new Date(startTime).toISOString() + const endTimeISOString = new Date(endTime).toISOString() + + return bookshelf.knex.raw(` + -- Post created + -- Post created + SELECT communities_posts.community_id + FROM posts + JOIN communities_posts ON communities_posts.post_id = posts.id + WHERE posts.type NOT IN('welcome', 'thread') + AND posts.created_at > '${startTimeISOString}' + AND posts.created_at <= '${endTimeISOString}' + + UNION + + -- Comment created + SELECT communities_posts.community_id + FROM comments + JOIN posts ON posts.id = comments.post_id + JOIN communities_posts ON communities_posts.post_id = posts.id + WHERE comments.created_at > '${startTimeISOString}' + AND comments.created_at <= '${endTimeISOString}' + AND posts.type NOT IN('welcome', 'thread') + + UNION + + -- Direct Message created + SELECT communities_posts.community_id + FROM comments + JOIN posts ON posts.id = comments.post_id + JOIN communities_posts ON communities_posts.post_id = posts.id + WHERE comments.created_at > '${startTimeISOString}' + AND comments.created_at <= '${endTimeISOString}' + AND posts.type = 'thread' + + UNION + + -- Community created + SELECT communities.id + FROM communities + WHERE communities.created_at > '${startTimeISOString}' + AND communities.created_at <= '${endTimeISOString}' + + UNION + + -- Tags created + SELECT communities_tags.community_id + FROM communities_tags + WHERE communities_tags.created_at > '${startTimeISOString}' + AND communities_tags.created_at <= '${endTimeISOString}' + + UNION + + -- Tag followed + SELECT tag_follows.community_id + FROM tag_follows + WHERE tag_follows.created_at > '${startTimeISOString}' + AND tag_follows.created_at <= '${endTimeISOString}' + + UNION + + -- Community Invites created + SELECT community_invites.community_id + FROM community_invites + WHERE community_invites.created_at > '${startTimeISOString}' + AND community_invites.created_at <= '${endTimeISOString}' + + UNION + + -- Community Invites accepted + SELECT community_invites.community_id + FROM community_invites + WHERE community_invites.used_at > '${startTimeISOString}' + AND community_invites.used_at <= '${endTimeISOString}' + + UNION + + -- Upvote created (~ base on post.created_at date...) + SELECT communities_posts.community_id + FROM votes + JOIN posts ON posts.id = votes.post_id + JOIN communities_posts ON communities_posts.post_id = posts.id + WHERE posts.created_at > '${startTimeISOString}' + AND posts.created_at <= '${endTimeISOString}' + `) +} + +export async function getCreatedUsers (startTime, endTime) { + const startTimeISOString = new Date(startTime).toISOString() + const endTimeISOString = new Date(endTime).toISOString() + + return bookshelf.knex.raw(` + SELECT id + FROM users + WHERE users.created_at > '${startTimeISOString}' + AND users.created_at <= '${endTimeISOString}' + `) +} + +export async function getCreatedCommunities (startTime, endTime) { + const startTimeISOString = new Date(startTime).toISOString() + const endTimeISOString = new Date(endTime).toISOString() + + return bookshelf.knex.raw(` + SELECT id + FROM communities + WHERE communities.created_at > '${startTimeISOString}' + AND communities.created_at <= '${endTimeISOString}' + `) +} + +export async function generateMonthlyData (startTime = '2015-1-1') { + var time = moment(startTime) + const now = moment() + const months = [] + while (time < now) { + const nextMonth = time.clone().add(1, 'month') + const active_users = (await getActiveUsers(time, nextMonth)).rows.length + const created_users = (await getCreatedUsers(time, nextMonth)).rows.length + const active_communities = (await getActiveCommunities(time, nextMonth)).rows.length + const created_communities = (await getCreatedCommunities(time, nextMonth)).rows.length + + months.push( + { + date: time.format('YYYY-M-D'), + active_users, + created_users, + active_communities, + created_communities + } + ) + time.add(1, 'month') + } + + return months +} + +export async function monthlyDataCSV () { + const data = await generateMonthlyData() + return papaparse.unparse(data) +} \ No newline at end of file diff --git a/package.json b/package.json index fb0e96a99..74cb6b226 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "moment-timezone": "^0.5.0", "newrelic": "^1.35.1", "node-uuid": "^1.4.7", + "papaparse": "^4.6.3", "parse-redis-url": "0.0.1", "passport": "^0.2.1", "passport-facebook": "2.1.1", diff --git a/yarn.lock b/yarn.lock index ca87e00bd..0e4e47b7d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5934,18 +5934,14 @@ oauth@0.9.x: version "0.9.14" resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.14.tgz#c5748883a40b53de30ade9cabf2100414b8a0971" -object-assign@^4: +object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" -object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" @@ -6118,6 +6114,10 @@ pako@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" +papaparse@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-4.6.3.tgz#742e5eaaa97fa6c7e1358d2934d8f18f44aee781" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"