{"action":"created","comment":{"url":"https://api.github.com/repos/mozilla/kitsune/pulls/comments/49919927","id":49919927,"diff_hunk":"@@ -496,3 +496,92 @@ def survey_recent_askers():\n             add_email_to_campaign('askers', email)\n \n     statsd.gauge('survey.askers', len(emails))\n+\n+\n+@cronjobs.register\n+def cohort_analysis():\n+    today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)\n+    boundaries = [today - timedelta(days=today.weekday())]\n+    for _ in range(12):\n+        previous_week = boundaries[-1] - timedelta(weeks=1)\n+        boundaries.append(previous_week)\n+    boundaries.reverse()\n+    ranges = zip(boundaries[:-1], boundaries[1:])\n+\n+    reports = [\n+        (CONTRIBUTOR_COHORT_CODE, [\n+            (Revision.objects.all(), ('creator', 'reviewer',)),\n+            (Answer.objects.not_by_asker(), ('creator',)),\n+            (Reply.objects.all(), ('user',))]),\n+        (KB_CONTRIBUTOR_COHORT_CODE, [\n+            (Revision.objects.filter(document__locale='en-US'), ('creator', 'reviewer',))]),\n+        (KB_L10N_CONTRIBUTOR_COHORT_CODE, [\n+            (Revision.objects.exclude(document__locale='en-US'), ('creator', 'reviewer',))]),\n+        (SUPPORT_FORUM_HELPER_COHORT_CODE, [\n+            (Answer.objects.not_by_asker(), ('creator',))]),\n+        (AOA_CONTRIBUTOR_COHORT_CODE, [\n+            (Reply.objects.all(), ('user',))])\n+    ]\n+\n+    for kind, querysets in reports:\n+        cohort_kind = CohortKind.objects.get_or_create(code=kind)[0]\n+\n+        for i, cohort_range in enumerate(ranges):\n+            cohort_users = _get_cohort(querysets, cohort_range)\n+\n+            # Sometimes None will be added to the cohort_users list, so remove it\n+            if None in cohort_users:\n+                cohort_users.remove(None)\n+\n+            cohort = Cohort.objects.get_or_create(kind=cohort_kind, start=cohort_range[0],\n+                                                  end=cohort_range[1])[0]\n+            cohort.size = len(cohort_users)\n+            cohort.save()\n+\n+            for retention_range in ranges[i + 1:]:\n+                retained_user_count = _count_contributors_in_range(\n+                    querysets, cohort_users, retention_range)\n+                retention_metric = RetentionMetric.objects.get_or_create(\n+                    cohort=cohort, start=retention_range[0], end=retention_range[1])[0]\n+                retention_metric.size = retained_user_count\n+                retention_metric.save()\n+\n+\n+def _count_contributors_in_range(querysets, users, date_range):\n+    \"\"\"Of the group ``users``, count how many made a contribution in ``date_range``.\"\"\"\n+    start, end = date_range\n+    retained_users = set()\n+\n+    for queryset, fields in querysets:\n+        for field in fields:\n+            filters = {'%s__in' % field: users, 'created__gte': start, 'created__lt': end}\n+            retained_users = retained_users.union(\n+                set(getattr(o, field) for o in queryset.filter(**filters)))\n+\n+    return len(retained_users)\n+\n+\n+def _get_cohort(querysets, date_range):\n+    start, end = date_range\n+    cohort = []","path":"kitsune/kpi/cron.py","position":98,"original_position":98,"commit_id":"9cdbb4665890bbfd5b6731fc28db63cb1bca2395","original_commit_id":"9cdbb4665890bbfd5b6731fc28db63cb1bca2395","user":{"login":"mythmon","id":305049,"avatar_url":"https://avatars.githubusercontent.com/u/305049?v=3","gravatar_id":"","url":"https://api.github.com/users/mythmon","html_url":"https://github.com/mythmon","followers_url":"https://api.github.com/users/mythmon/followers","following_url":"https://api.github.com/users/mythmon/following{/other_user}","gists_url":"https://api.github.com/users/mythmon/gists{/gist_id}","starred_url":"https://api.github.com/users/mythmon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mythmon/subscriptions","organizations_url":"https://api.github.com/users/mythmon/orgs","repos_url":"https://api.github.com/users/mythmon/repos","events_url":"https://api.github.com/users/mythmon/events{/privacy}","received_events_url":"https://api.github.com/users/mythmon/received_events","type":"User","site_admin":false},"body":"Should this be a `set()` to filter out duplicate users?","created_at":"2016-01-15T23:58:54Z","updated_at":"2016-01-15T23:58:54Z","html_url":"https://github.com/mozilla/kitsune/pull/2774#discussion_r49919927","pull_request_url":"https://api.github.com/repos/mozilla/kitsune/pulls/2774","_links":{"self":{"href":"https://api.github.com/repos/mozilla/kitsune/pulls/comments/49919927"},"html":{"href":"https://github.com/mozilla/kitsune/pull/2774#discussion_r49919927"},"pull_request":{"href":"https://api.github.com/repos/mozilla/kitsune/pulls/2774"}}},"pull_request":{"url":"https://api.github.com/repos/mozilla/kitsune/pulls/2774","id":56028378,"html_url":"https://github.com/mozilla/kitsune/pull/2774","diff_url":"https://github.com/mozilla/kitsune/pull/2774.diff","patch_url":"https://github.com/mozilla/kitsune/pull/2774.patch","issue_url":"https://api.github.com/repos/mozilla/kitsune/issues/2774","number":2774,"state":"open","locked":false,"title":"[bug 1225370] Calculate retention metrics for KPI dashboard","user":{"login":"rehandalal","id":987136,"avatar_url":"https://avatars.githubusercontent.com/u/987136?v=3","gravatar_id":"","url":"https://api.github.com/users/rehandalal","html_url":"https://github.com/rehandalal","followers_url":"https://api.github.com/users/rehandalal/followers","following_url":"https://api.github.com/users/rehandalal/following{/other_user}","gists_url":"https://api.github.com/users/rehandalal/gists{/gist_id}","starred_url":"https://api.github.com/users/rehandalal/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rehandalal/subscriptions","organizations_url":"https://api.github.com/users/rehandalal/orgs","repos_url":"https://api.github.com/users/rehandalal/repos","events_url":"https://api.github.com/users/rehandalal/events{/privacy}","received_events_url":"https://api.github.com/users/rehandalal/received_events","type":"User","site_admin":false},"body":"r?","created_at":"2016-01-14T12:22:50Z","updated_at":"2016-01-15T23:58:54Z","closed_at":null,"merged_at":null,"merge_commit_sha":"50895d7de7a41e0f9e34181c047b1815d3990bc9","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/mozilla/kitsune/pulls/2774/commits","review_comments_url":"https://api.github.com/repos/mozilla/kitsune/pulls/2774/comments","review_comment_url":"https://api.github.com/repos/mozilla/kitsune/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mozilla/kitsune/issues/2774/comments","statuses_url":"https://api.github.com/repos/mozilla/kitsune/statuses/9cdbb4665890bbfd5b6731fc28db63cb1bca2395","head":{"label":"rehandalal:cohorts-analysis","ref":"cohorts-analysis","sha":"9cdbb4665890bbfd5b6731fc28db63cb1bca2395","user":{"login":"rehandalal","id":987136,"avatar_url":"https://avatars.githubusercontent.com/u/987136?v=3","gravatar_id":"","url":"https://api.github.com/users/rehandalal","html_url":"https://github.com/rehandalal","followers_url":"https://api.github.com/users/rehandalal/followers","following_url":"https://api.github.com/users/rehandalal/following{/other_user}","gists_url":"https://api.github.com/users/rehandalal/gists{/gist_id}","starred_url":"https://api.github.com/users/rehandalal/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rehandalal/subscriptions","organizations_url":"https://api.github.com/users/rehandalal/orgs","repos_url":"https://api.github.com/users/rehandalal/repos","events_url":"https://api.github.com/users/rehandalal/events{/privacy}","received_events_url":"https://api.github.com/users/rehandalal/received_events","type":"User","site_admin":false},"repo":{"id":4328128,"name":"kitsune","full_name":"rehandalal/kitsune","owner":{"login":"rehandalal","id":987136,"avatar_url":"https://avatars.githubusercontent.com/u/987136?v=3","gravatar_id":"","url":"https://api.github.com/users/rehandalal","html_url":"https://github.com/rehandalal","followers_url":"https://api.github.com/users/rehandalal/followers","following_url":"https://api.github.com/users/rehandalal/following{/other_user}","gists_url":"https://api.github.com/users/rehandalal/gists{/gist_id}","starred_url":"https://api.github.com/users/rehandalal/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rehandalal/subscriptions","organizations_url":"https://api.github.com/users/rehandalal/orgs","repos_url":"https://api.github.com/users/rehandalal/repos","events_url":"https://api.github.com/users/rehandalal/events{/privacy}","received_events_url":"https://api.github.com/users/rehandalal/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rehandalal/kitsune","description":"Platform for Firefox Help","fork":true,"url":"https://api.github.com/repos/rehandalal/kitsune","forks_url":"https://api.github.com/repos/rehandalal/kitsune/forks","keys_url":"https://api.github.com/repos/rehandalal/kitsune/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rehandalal/kitsune/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rehandalal/kitsune/teams","hooks_url":"https://api.github.com/repos/rehandalal/kitsune/hooks","issue_events_url":"https://api.github.com/repos/rehandalal/kitsune/issues/events{/number}","events_url":"https://api.github.com/repos/rehandalal/kitsune/events","assignees_url":"https://api.github.com/repos/rehandalal/kitsune/assignees{/user}","branches_url":"https://api.github.com/repos/rehandalal/kitsune/branches{/branch}","tags_url":"https://api.github.com/repos/rehandalal/kitsune/tags","blobs_url":"https://api.github.com/repos/rehandalal/kitsune/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rehandalal/kitsune/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rehandalal/kitsune/git/refs{/sha}","trees_url":"https://api.github.com/repos/rehandalal/kitsune/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rehandalal/kitsune/statuses/{sha}","languages_url":"https://api.github.com/repos/rehandalal/kitsune/languages","stargazers_url":"https://api.github.com/repos/rehandalal/kitsune/stargazers","contributors_url":"https://api.github.com/repos/rehandalal/kitsune/contributors","subscribers_url":"https://api.github.com/repos/rehandalal/kitsune/subscribers","subscription_url":"https://api.github.com/repos/rehandalal/kitsune/subscription","commits_url":"https://api.github.com/repos/rehandalal/kitsune/commits{/sha}","git_commits_url":"https://api.github.com/repos/rehandalal/kitsune/git/commits{/sha}","comments_url":"https://api.github.com/repos/rehandalal/kitsune/comments{/number}","issue_comment_url":"https://api.github.com/repos/rehandalal/kitsune/issues/comments{/number}","contents_url":"https://api.github.com/repos/rehandalal/kitsune/contents/{+path}","compare_url":"https://api.github.com/repos/rehandalal/kitsune/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rehandalal/kitsune/merges","archive_url":"https://api.github.com/repos/rehandalal/kitsune/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rehandalal/kitsune/downloads","issues_url":"https://api.github.com/repos/rehandalal/kitsune/issues{/number}","pulls_url":"https://api.github.com/repos/rehandalal/kitsune/pulls{/number}","milestones_url":"https://api.github.com/repos/rehandalal/kitsune/milestones{/number}","notifications_url":"https://api.github.com/repos/rehandalal/kitsune/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rehandalal/kitsune/labels{/name}","releases_url":"https://api.github.com/repos/rehandalal/kitsune/releases{/id}","created_at":"2012-05-14T19:41:48Z","updated_at":"2015-04-09T20:27:24Z","pushed_at":"2016-01-15T21:43:51Z","git_url":"git://github.com/rehandalal/kitsune.git","ssh_url":"git@github.com:rehandalal/kitsune.git","clone_url":"https://github.com/rehandalal/kitsune.git","svn_url":"https://github.com/rehandalal/kitsune","homepage":"http://support.mozilla.com/","size":114440,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":false,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"mozilla:master","ref":"master","sha":"8eefb30593013e1fb69ed4b4724ef5d457e020bf","user":{"login":"mozilla","id":131524,"avatar_url":"https://avatars.githubusercontent.com/u/131524?v=3","gravatar_id":"","url":"https://api.github.com/users/mozilla","html_url":"https://github.com/mozilla","followers_url":"https://api.github.com/users/mozilla/followers","following_url":"https://api.github.com/users/mozilla/following{/other_user}","gists_url":"https://api.github.com/users/mozilla/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla/subscriptions","organizations_url":"https://api.github.com/users/mozilla/orgs","repos_url":"https://api.github.com/users/mozilla/repos","events_url":"https://api.github.com/users/mozilla/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla/received_events","type":"Organization","site_admin":false},"repo":{"id":489645,"name":"kitsune","full_name":"mozilla/kitsune","owner":{"login":"mozilla","id":131524,"avatar_url":"https://avatars.githubusercontent.com/u/131524?v=3","gravatar_id":"","url":"https://api.github.com/users/mozilla","html_url":"https://github.com/mozilla","followers_url":"https://api.github.com/users/mozilla/followers","following_url":"https://api.github.com/users/mozilla/following{/other_user}","gists_url":"https://api.github.com/users/mozilla/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla/subscriptions","organizations_url":"https://api.github.com/users/mozilla/orgs","repos_url":"https://api.github.com/users/mozilla/repos","events_url":"https://api.github.com/users/mozilla/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mozilla/kitsune","description":"Platform for Mozilla Support","fork":false,"url":"https://api.github.com/repos/mozilla/kitsune","forks_url":"https://api.github.com/repos/mozilla/kitsune/forks","keys_url":"https://api.github.com/repos/mozilla/kitsune/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mozilla/kitsune/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mozilla/kitsune/teams","hooks_url":"https://api.github.com/repos/mozilla/kitsune/hooks","issue_events_url":"https://api.github.com/repos/mozilla/kitsune/issues/events{/number}","events_url":"https://api.github.com/repos/mozilla/kitsune/events","assignees_url":"https://api.github.com/repos/mozilla/kitsune/assignees{/user}","branches_url":"https://api.github.com/repos/mozilla/kitsune/branches{/branch}","tags_url":"https://api.github.com/repos/mozilla/kitsune/tags","blobs_url":"https://api.github.com/repos/mozilla/kitsune/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mozilla/kitsune/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mozilla/kitsune/git/refs{/sha}","trees_url":"https://api.github.com/repos/mozilla/kitsune/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mozilla/kitsune/statuses/{sha}","languages_url":"https://api.github.com/repos/mozilla/kitsune/languages","stargazers_url":"https://api.github.com/repos/mozilla/kitsune/stargazers","contributors_url":"https://api.github.com/repos/mozilla/kitsune/contributors","subscribers_url":"https://api.github.com/repos/mozilla/kitsune/subscribers","subscription_url":"https://api.github.com/repos/mozilla/kitsune/subscription","commits_url":"https://api.github.com/repos/mozilla/kitsune/commits{/sha}","git_commits_url":"https://api.github.com/repos/mozilla/kitsune/git/commits{/sha}","comments_url":"https://api.github.com/repos/mozilla/kitsune/comments{/number}","issue_comment_url":"https://api.github.com/repos/mozilla/kitsune/issues/comments{/number}","contents_url":"https://api.github.com/repos/mozilla/kitsune/contents/{+path}","compare_url":"https://api.github.com/repos/mozilla/kitsune/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mozilla/kitsune/merges","archive_url":"https://api.github.com/repos/mozilla/kitsune/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mozilla/kitsune/downloads","issues_url":"https://api.github.com/repos/mozilla/kitsune/issues{/number}","pulls_url":"https://api.github.com/repos/mozilla/kitsune/pulls{/number}","milestones_url":"https://api.github.com/repos/mozilla/kitsune/milestones{/number}","notifications_url":"https://api.github.com/repos/mozilla/kitsune/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mozilla/kitsune/labels{/name}","releases_url":"https://api.github.com/repos/mozilla/kitsune/releases{/id}","created_at":"2010-01-26T18:53:57Z","updated_at":"2016-01-13T07:11:33Z","pushed_at":"2016-01-15T21:43:53Z","git_url":"git://github.com/mozilla/kitsune.git","ssh_url":"git@github.com:mozilla/kitsune.git","clone_url":"https://github.com/mozilla/kitsune.git","svn_url":"https://github.com/mozilla/kitsune","homepage":"http://support.mozilla.com/","size":136652,"stargazers_count":335,"watchers_count":335,"language":"Python","has_issues":false,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":321,"mirror_url":null,"open_issues_count":5,"forks":321,"open_issues":5,"watchers":335,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mozilla/kitsune/pulls/2774"},"html":{"href":"https://github.com/mozilla/kitsune/pull/2774"},"issue":{"href":"https://api.github.com/repos/mozilla/kitsune/issues/2774"},"comments":{"href":"https://api.github.com/repos/mozilla/kitsune/issues/2774/comments"},"review_comments":{"href":"https://api.github.com/repos/mozilla/kitsune/pulls/2774/comments"},"review_comment":{"href":"https://api.github.com/repos/mozilla/kitsune/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mozilla/kitsune/pulls/2774/commits"},"statuses":{"href":"https://api.github.com/repos/mozilla/kitsune/statuses/9cdbb4665890bbfd5b6731fc28db63cb1bca2395"}}}}