Skip to content

Commit

Permalink
Merge pull request #2788 from rehandalal/kpi-csat
Browse files Browse the repository at this point in the history
[bug 1241661] Calculate CSAT metrics
  • Loading branch information
Mike Cooper committed Feb 25, 2016
2 parents 5b082fd + b8188a5 commit 80990a6
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 1 deletion.
12 changes: 12 additions & 0 deletions kitsune/kpi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,18 @@ def merge_results(metrics_qs, label):
results_list, key=itemgetter('date'), reverse=True)]


class CSATMetricList(CachedAPIView):
"""The API list view for contributor CSAT metrics"""
code = None

def get_objects(self, request):
kind = MetricKind.objects.get(code=self.code)
since = date.today() - timedelta(days=30)
metrics = Metric.objects.filter(start__gte=since, kind=kind).order_by('-start')

return [{'date': m.start, 'csat': m.value} for m in metrics]


def _daily_qs_for(model_cls):
"""Return the daily grouped queryset we need for model_cls."""
# Limit to newer than 2011/1/1 and active creators.
Expand Down
123 changes: 122 additions & 1 deletion kitsune/kpi/cron.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
import operator
from datetime import datetime, date, timedelta
from functools import reduce
Expand All @@ -6,6 +7,7 @@
from django.db.models import Count, F, Q

import cronjobs
import requests
from statsd import statsd

from kitsune.customercare.models import Reply
Expand All @@ -17,7 +19,10 @@
SUPPORT_FORUM_CONTRIBUTORS_METRIC_CODE, VISITORS_METRIC_CODE, SEARCH_SEARCHES_METRIC_CODE,
SEARCH_CLICKS_METRIC_CODE, EXIT_SURVEY_YES_CODE, EXIT_SURVEY_NO_CODE,
EXIT_SURVEY_DONT_KNOW_CODE, CONTRIBUTOR_COHORT_CODE, KB_ENUS_CONTRIBUTOR_COHORT_CODE,
KB_L10N_CONTRIBUTOR_COHORT_CODE, SUPPORT_FORUM_HELPER_COHORT_CODE, AOA_CONTRIBUTOR_COHORT_CODE)
KB_L10N_CONTRIBUTOR_COHORT_CODE, SUPPORT_FORUM_HELPER_COHORT_CODE, AOA_CONTRIBUTOR_COHORT_CODE,
CONTRIBUTORS_CSAT_METRIC_CODE, AOA_CONTRIBUTORS_CSAT_METRIC_CODE,
KB_ENUS_CONTRIBUTORS_CSAT_METRIC_CODE, KB_L10N_CONTRIBUTORS_CSAT_METRIC_CODE,
SUPPORT_FORUM_CONTRIBUTORS_CSAT_METRIC_CODE)
from kitsune.kpi.surveygizmo_utils import (
get_email_addresses, add_email_to_campaign, get_exit_survey_results,
SURVEYS)
Expand Down Expand Up @@ -581,3 +586,119 @@ def is_in_cohort(u):
cohort |= set(filter(is_in_cohort, potential_users))

return cohort


@cronjobs.register
def calculate_csat_metrics():
user = settings.SURVEYGIZMO_USER
password = settings.SURVEYGIZMO_PASSWORD
startdate = date.today() - timedelta(days=2)
enddate = date.today() - timedelta(days=1)
page = 1
more_pages = True
survey_id = SURVEYS['general']['community_health']

csat = {
CONTRIBUTORS_CSAT_METRIC_CODE: 0,
SUPPORT_FORUM_CONTRIBUTORS_CSAT_METRIC_CODE: 0,
AOA_CONTRIBUTORS_CSAT_METRIC_CODE: 0,
KB_ENUS_CONTRIBUTORS_CSAT_METRIC_CODE: 0,
KB_L10N_CONTRIBUTORS_CSAT_METRIC_CODE: 0,
}

counts = {
CONTRIBUTORS_CSAT_METRIC_CODE: 0,
SUPPORT_FORUM_CONTRIBUTORS_CSAT_METRIC_CODE: 0,
AOA_CONTRIBUTORS_CSAT_METRIC_CODE: 0,
KB_ENUS_CONTRIBUTORS_CSAT_METRIC_CODE: 0,
KB_L10N_CONTRIBUTORS_CSAT_METRIC_CODE: 0,
}

while more_pages:
response = requests.get(
'https://restapi.surveygizmo.com/v2/survey/{survey}'
'/surveyresponse?'
'filter[field][0]=datesubmitted'
'&filter[operator][0]=>=&filter[value][0]={start}+0:0:0'
'&filter[field][1]=datesubmitted'
'&filter[operator][1]=<&filter[value][1]={end}+0:0:0'
'&filter[field][2]=status&filter[operator][2]=='
'&filter[value][2]=Complete'
'&resultsperpage=500'
'&page={page}'
'&user:pass={user}:{password}'.format(
survey=survey_id, start=startdate,
end=enddate, page=page, user=user, password=password),
timeout=300)

results = json.loads(response.content)
total_pages = results['total_pages']
more_pages = page < total_pages

for r in results['data']:
try:
rating = int(r['[question(3)]'])
except ValueError:
# CSAT question was not answered
pass
else:
csat[CONTRIBUTORS_CSAT_METRIC_CODE] += rating
counts[CONTRIBUTORS_CSAT_METRIC_CODE] += 1

if len(r['[question(4), option(10010)]']): # Army of Awesome
csat[AOA_CONTRIBUTORS_CSAT_METRIC_CODE] += rating
counts[AOA_CONTRIBUTORS_CSAT_METRIC_CODE] += 1

if len(r['[question(4), option(10011)]']): # Support Forum
csat[SUPPORT_FORUM_CONTRIBUTORS_CSAT_METRIC_CODE] += rating
counts[SUPPORT_FORUM_CONTRIBUTORS_CSAT_METRIC_CODE] += 1

if len(r['[question(4), option(10012)]']): # KB EN-US
csat[KB_ENUS_CONTRIBUTORS_CSAT_METRIC_CODE] += rating
counts[KB_ENUS_CONTRIBUTORS_CSAT_METRIC_CODE] += 1

if len(r['[question(4), option(10013)]']): # KB L10N
csat[KB_L10N_CONTRIBUTORS_CSAT_METRIC_CODE] += rating
counts[KB_L10N_CONTRIBUTORS_CSAT_METRIC_CODE] += 1

page += 1

for code in csat:
metric_kind, _ = MetricKind.objects.get_or_create(code=code)
value = csat[code] / counts[code] if counts[code] else 50 # If no responses assume neutral
Metric.objects.update_or_create(kind=metric_kind, start=startdate, end=enddate,
defaults={'value': value})


@cronjobs.register
def csat_survey_emails():
querysets = [(Revision.objects.all(), ('creator', 'reviewer',)),
(Answer.objects.not_by_asker(), ('creator',)),
(Reply.objects.all(), ('user',))]

end = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
start = end - timedelta(days=30)

users = _get_cohort(querysets, (start, end))

for u in users:
p = u.profile
if p.csat_email_sent is None or p.csat_email_sent < start:
user = settings.SURVEYGIZMO_USER
password = settings.SURVEYGIZMO_PASSWORD

survey_id = SURVEYS['general']['community_health']
campaign_id = SURVEYS['general']['community_health_campaign_id']

try:
requests.put(
'https://restapi.surveygizmo.com/v2/survey/{survey}/surveycampaign/'
'{campaign}/contact?semailaddress={email}&user:pass={user}:{password}'.format(
survey=survey_id, campaign=campaign_id,
email=u.email, user=user, password=password),
timeout=30)
except requests.exceptions.Timeout:
print 'Timed out adding: %s' % u.email
else:
p.csat_email_sent = datetime.now()
p.save()
6 changes: 6 additions & 0 deletions kitsune/kpi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
EXIT_SURVEY_NO_CODE = 'exit-survey:no'
EXIT_SURVEY_DONT_KNOW_CODE = 'exit-survey:dont-know'

CONTRIBUTORS_CSAT_METRIC_CODE = 'csat contributors'
AOA_CONTRIBUTORS_CSAT_METRIC_CODE = 'csat contributors:aoa'
SUPPORT_FORUM_CONTRIBUTORS_CSAT_METRIC_CODE = 'csat contributors:supportforum'
KB_ENUS_CONTRIBUTORS_CSAT_METRIC_CODE = 'csat contributors:kb:en-US'
KB_L10N_CONTRIBUTORS_CSAT_METRIC_CODE = 'csat contributors:kb-l10n'

CONTRIBUTOR_COHORT_CODE = 'contributor'
KB_ENUS_CONTRIBUTOR_COHORT_CODE = 'contributor:kb:en-US'
KB_L10N_CONTRIBUTOR_COHORT_CODE = 'contributor:kb:l10n'
Expand Down
2 changes: 2 additions & 0 deletions kitsune/kpi/surveygizmo_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
'email_collection_survey_id': 1002970,
'exit_survey_id': 991425,
'exit_survey_campaign_id': 878533,
'community_health': 2466367,
'community_health_campaign_id': 3369235,
},
'questions': { # This is for users that are browsing questions.
'email_collection_survey_id': 1717268,
Expand Down
19 changes: 19 additions & 0 deletions kitsune/kpi/urls_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,31 @@
from rest_framework import routers

from kitsune.kpi import api
from kitsune.kpi.models import (CONTRIBUTORS_CSAT_METRIC_CODE, AOA_CONTRIBUTORS_CSAT_METRIC_CODE,
SUPPORT_FORUM_CONTRIBUTORS_CSAT_METRIC_CODE,
KB_ENUS_CONTRIBUTORS_CSAT_METRIC_CODE,
KB_L10N_CONTRIBUTORS_CSAT_METRIC_CODE)

router = routers.SimpleRouter()
router.register(r'cohort', api.CohortViewSet)

urlpatterns = patterns(
'',
url(r'^api/v1/kpi/csat-contributors/?$',
api.CSATMetricList.as_view(code=CONTRIBUTORS_CSAT_METRIC_CODE),
name='api.kpi.csat-contributors'),
url(r'^api/v1/kpi/csat-contributors/aoa/?$',
api.CSATMetricList.as_view(code=AOA_CONTRIBUTORS_CSAT_METRIC_CODE),
name='api.kpi.csat-contributors-aoa'),
url(r'^api/v1/kpi/csat-contributors/support-forum/?$',
api.CSATMetricList.as_view(code=SUPPORT_FORUM_CONTRIBUTORS_CSAT_METRIC_CODE),
name='api.kpi.csat-contributors-support-forum'),
url(r'^api/v1/kpi/csat-contributors/kb-enus/?$',
api.CSATMetricList.as_view(code=KB_ENUS_CONTRIBUTORS_CSAT_METRIC_CODE),
name='api.kpi.csat-contributors-kb-enus'),
url(r'^api/v1/kpi/csat-contributors/kb-l10n/?$',
api.CSATMetricList.as_view(code=KB_L10N_CONTRIBUTORS_CSAT_METRIC_CODE),
name='api.kpi.csat-contributors-kb-l10n'),
url(r'^api/v1/kpi/l10n-coverage/?$', api.L10nCoverageMetricList.as_view(),
name='api.kpi.l10n-coverage'),
url(r'^api/v1/kpi/exit-survey/?$', api.ExitSurveyMetricList.as_view(),
Expand Down
20 changes: 20 additions & 0 deletions kitsune/users/migrations/0011_add_csat_email_sent_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('users', '0010_auto_20151110_1307'),
]

operations = [
migrations.AddField(
model_name='profile',
name='csat_email_sent',
field=models.DateField(null=True, verbose_name='When the user was sent a community health survey', blank=True),
preserve_default=True,
),
]
3 changes: 3 additions & 0 deletions kitsune/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class Profile(ModelBase, SearchMixin):
default=False, help_text=_lazy(u'Has been sent a first revision contribution email.'))
involved_from = models.DateField(null=True, blank=True,
verbose_name=_lazy(u'Involved with Mozilla from'))
csat_email_sent = models.DateField(null=True, blank=True,
verbose_name=_lazy(u'When the user was sent a community '
u'health survey'))

class Meta(object):
permissions = (('view_karma_points', 'Can view karma points'),
Expand Down
1 change: 1 addition & 0 deletions scripts/crontab/crontab.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ HOME = /tmp
00 00 * * * {{ cron }} rebuild_kb
42 00 * * * {{ cron }} update_top_contributors
00 01 * * * {{ cron }} update_l10n_coverage_metrics
00 01 * * * {{ cron }} calculate_csat_metrics
11 01 * * * {{ cron }} report_employee_answers
30 01 * * * {{ cron }} reindex_users_that_contributed_yesterday
40 01 * * * {{ cron }} update_weekly_votes
Expand Down

0 comments on commit 80990a6

Please sign in to comment.