2017-11-16 00:55:49 +01:00
|
|
|
import datetime
|
|
|
|
from argparse import ArgumentParser
|
2016-06-04 16:52:18 +02:00
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
from django.db.models import Count, QuerySet
|
2017-04-15 04:03:56 +02:00
|
|
|
from django.utils.timezone import now as timezone_now
|
2013-09-25 19:30:45 +02:00
|
|
|
|
2017-07-14 00:48:41 +02:00
|
|
|
from zerver.lib.management import ZulipBaseCommand
|
|
|
|
from zerver.models import UserActivity
|
2013-09-25 19:30:45 +02:00
|
|
|
|
2017-07-14 00:48:41 +02:00
|
|
|
class Command(ZulipBaseCommand):
|
2013-09-25 19:30:45 +02:00
|
|
|
help = """Report rough client activity globally, for a realm, or for a user
|
|
|
|
|
|
|
|
Usage examples:
|
|
|
|
|
2017-07-14 00:48:41 +02:00
|
|
|
./manage.py client_activity --target server
|
|
|
|
./manage.py client_activity --target realm --realm zulip
|
|
|
|
./manage.py client_activity --target user --user hamlet@zulip.com --realm zulip"""
|
2013-09-25 19:30:45 +02:00
|
|
|
|
2015-08-21 02:10:41 +02:00
|
|
|
def add_arguments(self, parser):
|
2016-06-04 16:52:18 +02:00
|
|
|
# type: (ArgumentParser) -> None
|
2017-07-14 00:48:41 +02:00
|
|
|
parser.add_argument('--target', dest='target', required=True, type=str,
|
|
|
|
help="'server' will calculate client activity of the entire server. "
|
|
|
|
"'realm' will calculate client activity of realm. "
|
|
|
|
"'user' will calculate client activity of the user.")
|
|
|
|
parser.add_argument('--user', dest='user', type=str,
|
2017-11-09 16:26:38 +01:00
|
|
|
help="The email address of the user you want to calculate activity.")
|
2017-07-14 00:48:41 +02:00
|
|
|
self.add_realm_args(parser)
|
2015-08-21 02:10:41 +02:00
|
|
|
|
2013-09-25 19:30:45 +02:00
|
|
|
def compute_activity(self, user_activity_objects):
|
2016-06-04 16:52:18 +02:00
|
|
|
# type: (QuerySet) -> None
|
2013-09-25 19:30:45 +02:00
|
|
|
# Report data from the past week.
|
|
|
|
#
|
|
|
|
# This is a rough report of client activity because we inconsistently
|
|
|
|
# register activity from various clients; think of it as telling you
|
|
|
|
# approximately how many people from a group have used a particular
|
|
|
|
# client recently. For example, this might be useful to get a sense of
|
|
|
|
# how popular different versions of a desktop client are.
|
|
|
|
#
|
|
|
|
# Importantly, this does NOT tell you anything about the relative
|
|
|
|
# volumes of requests from clients.
|
2017-04-15 04:03:56 +02:00
|
|
|
threshold = timezone_now() - datetime.timedelta(days=7)
|
2013-09-25 19:30:45 +02:00
|
|
|
client_counts = user_activity_objects.filter(
|
|
|
|
last_visit__gt=threshold).values("client__name").annotate(
|
|
|
|
count=Count('client__name'))
|
|
|
|
|
|
|
|
total = 0
|
|
|
|
counts = []
|
|
|
|
for client_type in client_counts:
|
|
|
|
count = client_type["count"]
|
|
|
|
client = client_type["client__name"]
|
|
|
|
total += count
|
|
|
|
counts.append((count, client))
|
|
|
|
|
|
|
|
counts.sort()
|
|
|
|
|
|
|
|
for count in counts:
|
2015-11-01 17:11:06 +01:00
|
|
|
print("%25s %15d" % (count[1], count[0]))
|
|
|
|
print("Total:", total)
|
2013-09-25 19:30:45 +02:00
|
|
|
|
|
|
|
def handle(self, *args, **options):
|
2016-06-04 16:52:18 +02:00
|
|
|
# type: (*Any, **str) -> None
|
2017-07-14 00:48:41 +02:00
|
|
|
realm = self.get_realm(options)
|
|
|
|
if options["user"] is None:
|
|
|
|
if options["target"] == "server" and realm is None:
|
|
|
|
# Report global activity.
|
|
|
|
self.compute_activity(UserActivity.objects.all())
|
|
|
|
elif options["target"] == "realm" and realm is not None:
|
|
|
|
self.compute_activity(UserActivity.objects.filter(user_profile__realm=realm))
|
|
|
|
else:
|
|
|
|
self.print_help("./manage.py", "client_activity")
|
|
|
|
elif options["target"] == "user":
|
|
|
|
user_profile = self.get_user(options["user"], realm)
|
|
|
|
self.compute_activity(UserActivity.objects.filter(user_profile=user_profile))
|
2015-08-21 02:10:41 +02:00
|
|
|
else:
|
2017-07-14 00:48:41 +02:00
|
|
|
self.print_help("./manage.py", "client_activity")
|