Improved system stats
parent
eb200b7607
commit
3531b440bd
|
@ -437,6 +437,7 @@ FEEDBACK_EMAIL = "support@taiga.io"
|
|||
|
||||
# Stats module settings
|
||||
STATS_ENABLED = False
|
||||
STATS_CACHE_TIMEOUT = 60*60 # In second
|
||||
|
||||
# 0 notifications will work in a synchronous way
|
||||
# >0 an external process will check the pending notifications and will send them
|
||||
|
|
|
@ -69,6 +69,7 @@ DATABASES = {
|
|||
|
||||
# STATS MODULE
|
||||
#STATS_ENABLED = False
|
||||
#FRONT_SITEMAP_CACHE_TIMEOUT = 60*60 # In second
|
||||
|
||||
# SITEMAP
|
||||
# If is True /front/sitemap.xml show a valid sitemap of taiga-front client
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from django.views.decorators.cache import cache_page
|
||||
|
||||
from taiga.base.api import viewsets
|
||||
from taiga.base import response
|
||||
|
@ -24,10 +28,15 @@ class SystemStatsViewSet(viewsets.ViewSet):
|
|||
permission_classes = (permissions.SystemStatsPermission,)
|
||||
|
||||
def list(self, request, **kwargs):
|
||||
stats = {
|
||||
"total_users": services.get_total_users(),
|
||||
"total_projects": services.get_total_projects(),
|
||||
"total_userstories": services.grt_total_user_stories(),
|
||||
"total_issues": services.get_total_issues(),
|
||||
}
|
||||
import ipdb; ipdb.set_trace()
|
||||
stats = OrderedDict()
|
||||
stats["users"] = services.get_users_stats()
|
||||
stats["projects"] = services.get_projects_stats()
|
||||
stats["userstories"] = services.get_user_stories_stats()
|
||||
return response.Ok(stats)
|
||||
|
||||
def _get_cache_timeout(self):
|
||||
return getattr(settings, "STATS_CACHE_TIMEOUT", 0)
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return cache_page(self._get_cache_timeout())(super().dispatch)(*args, **kwargs)
|
||||
|
|
|
@ -12,33 +12,96 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from contextlib import closing
|
||||
|
||||
from django.apps import apps
|
||||
from django.db import connection
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
def get_total_projects():
|
||||
def get_users_stats():
|
||||
model = apps.get_model("users", "User")
|
||||
queryset = model.objects.filter(is_active=True, is_system=False)
|
||||
stats = OrderedDict()
|
||||
|
||||
# Total
|
||||
stats["total"] = queryset.count()
|
||||
|
||||
# Average last 7 days
|
||||
today = timezone.now()
|
||||
seven_days_ago = today-timedelta(days=7)
|
||||
stats["average_last_seven_days"] = (queryset.filter(date_joined__range=(seven_days_ago, today))
|
||||
.count()) / 7
|
||||
|
||||
# Graph: users last year
|
||||
a_year_ago = timezone.now() - timedelta(days=365)
|
||||
sql_query = """
|
||||
SELECT date_trunc('week', "filtered_users"."date_joined") AS "week",
|
||||
count(*)
|
||||
FROM (SELECT *
|
||||
FROM "users_user"
|
||||
WHERE "users_user"."is_active" = TRUE
|
||||
AND "users_user"."is_system" = FALSE
|
||||
AND "users_user"."date_joined" >= %s) AS "filtered_users"
|
||||
GROUP BY "week"
|
||||
ORDER BY "week";
|
||||
"""
|
||||
with closing(connection.cursor()) as cursor:
|
||||
cursor.execute(sql_query, [a_year_ago])
|
||||
rows = cursor.fetchall()
|
||||
|
||||
counts_last_year_per_week = OrderedDict()
|
||||
sumatory = queryset.filter(date_joined__lt=rows[0][0]).count()
|
||||
for row in rows:
|
||||
sumatory += row[1]
|
||||
counts_last_year_per_week[str(row[0].date())] = sumatory
|
||||
|
||||
stats["counts_last_year_per_week"] = counts_last_year_per_week
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
def get_projects_stats():
|
||||
model = apps.get_model("projects", "Project")
|
||||
queryset = model.objects.all()
|
||||
return queryset.count()
|
||||
stats = OrderedDict()
|
||||
|
||||
stats["total"] = queryset.count()
|
||||
|
||||
today = timezone.now()
|
||||
seven_days_ago = today-timedelta(days=7)
|
||||
stats["average_last_seven_days"] = (queryset.filter(created_date__range=(seven_days_ago, today))
|
||||
.count()) / 7
|
||||
|
||||
stats["total_with_backlog"] = (queryset.filter(is_backlog_activated=True,
|
||||
is_kanban_activated=False)
|
||||
.count())
|
||||
stats["percent_with_backlog"] = stats["total_with_backlog"] * 100 / stats["total"]
|
||||
|
||||
stats["total_with_kanban"] = (queryset.filter(is_backlog_activated=False,
|
||||
is_kanban_activated=True)
|
||||
.count())
|
||||
stats["percent_with_kanban"] = stats["total_with_kanban"] * 100 / stats["total"]
|
||||
|
||||
stats["total_with_backlog_and_kanban"] = (queryset.filter(is_backlog_activated=True,
|
||||
is_kanban_activated=True)
|
||||
.count())
|
||||
stats["percent_with_backlog_and_kanban"] = stats["total_with_backlog_and_kanban"] * 100 / stats["total"]
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
def grt_total_user_stories():
|
||||
def get_user_stories_stats():
|
||||
model = apps.get_model("userstories", "UserStory")
|
||||
queryset = model.objects.all()
|
||||
return queryset.count()
|
||||
stats = OrderedDict()
|
||||
|
||||
stats["total"] = queryset.count()
|
||||
|
||||
def get_total_issues():
|
||||
model = apps.get_model("issues", "Issue")
|
||||
queryset = model.objects.all()
|
||||
return queryset.count()
|
||||
|
||||
|
||||
def get_total_users(only_active=True, no_system=True):
|
||||
model = apps.get_model("users", "User")
|
||||
queryset = model.objects.all()
|
||||
if only_active:
|
||||
queryset = queryset.filter(is_active=True)
|
||||
if no_system:
|
||||
queryset = queryset.filter(is_system=False)
|
||||
return queryset.count()
|
||||
today = timezone.now()
|
||||
seven_days_ago = today-timedelta(days=7)
|
||||
stats["average_last_seven_days"] = (queryset.filter(created_date__range=(seven_days_ago, today))
|
||||
.count()) / 7
|
||||
return stats
|
||||
|
|
Loading…
Reference in New Issue