Implemented issues filters data api rest endpoint.
parent
649df99977
commit
f31b2fafa9
|
@ -0,0 +1,138 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from contextlib import closing
|
||||||
|
from django.db import connection
|
||||||
|
|
||||||
|
|
||||||
|
def _get_issues_tags(project):
|
||||||
|
extra_sql = ("select unnest(unpickle(tags)) as tagname, count(unnest(unpickle(tags))) "
|
||||||
|
"from issues_issue where project_id = %s "
|
||||||
|
"group by unnest(unpickle(tags)) "
|
||||||
|
"order by tagname asc")
|
||||||
|
|
||||||
|
with closing(connection.cursor()) as cursor:
|
||||||
|
cursor.execute(extra_sql, [project.id])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
return dict(rows)
|
||||||
|
|
||||||
|
def _get_issues_statuses(project):
|
||||||
|
extra_sql = ("select status_id, count(status_id) from issues_issue "
|
||||||
|
"where project_id = %s group by status_id;")
|
||||||
|
|
||||||
|
extra_sql = """
|
||||||
|
select id, (select count(*) from issues_issue
|
||||||
|
where project_id = m.project_id and status_id = m.id)
|
||||||
|
from projects_issuestatus as m
|
||||||
|
where project_id = %s;
|
||||||
|
"""
|
||||||
|
|
||||||
|
with closing(connection.cursor()) as cursor:
|
||||||
|
cursor.execute(extra_sql, [project.id])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
return dict(rows)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_issues_priorities(project):
|
||||||
|
extra_sql = """
|
||||||
|
select id, (select count(*) from issues_issue
|
||||||
|
where project_id = m.project_id and priority_id = m.id)
|
||||||
|
from projects_priority as m
|
||||||
|
where project_id = %s;
|
||||||
|
"""
|
||||||
|
|
||||||
|
with closing(connection.cursor()) as cursor:
|
||||||
|
cursor.execute(extra_sql, [project.id])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
return dict(rows)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_issues_types(project):
|
||||||
|
extra_sql = """
|
||||||
|
select id, (select count(*) from issues_issue
|
||||||
|
where project_id = m.project_id and type_id = m.id)
|
||||||
|
from projects_issuetype as m
|
||||||
|
where project_id = %s;
|
||||||
|
"""
|
||||||
|
|
||||||
|
with closing(connection.cursor()) as cursor:
|
||||||
|
cursor.execute(extra_sql, [project.id])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
return dict(rows)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_issues_severities(project):
|
||||||
|
extra_sql = """
|
||||||
|
select id, (select count(*) from issues_issue
|
||||||
|
where project_id = m.project_id and severity_id = m.id)
|
||||||
|
from projects_severity as m
|
||||||
|
where project_id = %s;
|
||||||
|
"""
|
||||||
|
|
||||||
|
with closing(connection.cursor()) as cursor:
|
||||||
|
cursor.execute(extra_sql, [project.id])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
return dict(rows)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_issues_assigned_to(project):
|
||||||
|
extra_sql = """
|
||||||
|
select user_id, (select count(*) from issues_issue
|
||||||
|
where project_id = pm.project_id and assigned_to_id = pm.user_id)
|
||||||
|
from projects_membership as pm
|
||||||
|
where project_id = %s;
|
||||||
|
"""
|
||||||
|
|
||||||
|
with closing(connection.cursor()) as cursor:
|
||||||
|
cursor.execute(extra_sql, [project.id])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
return dict(rows)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_issues_owners(project):
|
||||||
|
extra_sql = """
|
||||||
|
select user_id, (select count(*) from issues_issue
|
||||||
|
where project_id = pm.project_id and owner_id = pm.user_id)
|
||||||
|
from projects_membership as pm
|
||||||
|
where project_id = %s;
|
||||||
|
"""
|
||||||
|
|
||||||
|
with closing(connection.cursor()) as cursor:
|
||||||
|
cursor.execute(extra_sql, [project.id])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
return dict(rows)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_issues_created_by(project):
|
||||||
|
extra_sql = """
|
||||||
|
select user_id, (select count(*) from issues_issue
|
||||||
|
where project_id = pm.project_id and owner_id = pm.user_id)
|
||||||
|
from projects_membership as pm
|
||||||
|
where project_id = %s;
|
||||||
|
"""
|
||||||
|
|
||||||
|
with closing(connection.cursor()) as cursor:
|
||||||
|
cursor.execute(extra_sql, [project.id])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
return dict(rows)
|
||||||
|
|
||||||
|
|
||||||
|
def get_issues_filters_data(project):
|
||||||
|
data = {
|
||||||
|
"owners": _get_issues_owners(project),
|
||||||
|
"tags": _get_issues_tags(project),
|
||||||
|
"statuses": _get_issues_statuses(project),
|
||||||
|
"priorities": _get_issues_priorities(project),
|
||||||
|
"assigned_to": _get_issues_assigned_to(project),
|
||||||
|
"created_by": _get_issues_created_by(project),
|
||||||
|
"types": _get_issues_types(project),
|
||||||
|
"severities": _get_issues_severities(project),
|
||||||
|
}
|
||||||
|
return data
|
|
@ -1,7 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from django.db.models import Q, Count
|
from django.db.models import Q
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
|
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
@ -14,7 +13,9 @@ from greenmine.base.notifications.api import NotificationSenderMixin
|
||||||
from . import serializers
|
from . import serializers
|
||||||
from . import models
|
from . import models
|
||||||
from . import permissions
|
from . import permissions
|
||||||
|
|
||||||
from .aggregates import stats
|
from .aggregates import stats
|
||||||
|
from .aggregates import filters as filters_aggr
|
||||||
|
|
||||||
|
|
||||||
class ProjectViewSet(ModelCrudViewSet):
|
class ProjectViewSet(ModelCrudViewSet):
|
||||||
|
@ -33,6 +34,11 @@ class ProjectViewSet(ModelCrudViewSet):
|
||||||
project = self.get_object()
|
project = self.get_object()
|
||||||
return Response(stats.get_stats_for_project_issues(project))
|
return Response(stats.get_stats_for_project_issues(project))
|
||||||
|
|
||||||
|
@detail_route(methods=['get'])
|
||||||
|
def issue_filters_data(self, request, pk=None):
|
||||||
|
project = self.get_object()
|
||||||
|
return Response(filters_aggr.get_issues_filters_data(project))
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = super(ProjectViewSet, self).get_queryset()
|
qs = super(ProjectViewSet, self).get_queryset()
|
||||||
qs = qs.filter(Q(owner=self.request.user) |
|
qs = qs.filter(Q(owner=self.request.user) |
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import reversion
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.decorators import list_route
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
from greenmine.base import filters
|
from greenmine.base import filters
|
||||||
from greenmine.base import exceptions as exc
|
from greenmine.base import exceptions as exc
|
||||||
|
@ -16,8 +20,6 @@ from . import models
|
||||||
from . import permissions
|
from . import permissions
|
||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
import reversion
|
|
||||||
|
|
||||||
|
|
||||||
class IssueAttachmentViewSet(ModelCrudViewSet):
|
class IssueAttachmentViewSet(ModelCrudViewSet):
|
||||||
model = Attachment
|
model = Attachment
|
||||||
|
@ -90,3 +92,4 @@ class IssueViewSet(NotificationSenderMixin, ModelCrudViewSet):
|
||||||
# Update the comment in the last version
|
# Update the comment in the last version
|
||||||
reversion.set_comment(self.request.DATA["comment"])
|
reversion.set_comment(self.request.DATA["comment"])
|
||||||
super().post_save(obj, created)
|
super().post_save(obj, created)
|
||||||
|
|
||||||
|
|
|
@ -161,10 +161,6 @@ class Project(models.Model):
|
||||||
role_model = get_model("users", "Role")
|
role_model = get_model("users", "Role")
|
||||||
return role_model.objects.all()
|
return role_model.objects.all()
|
||||||
|
|
||||||
# TODO: do not remove this
|
|
||||||
# return role_model.objects.filter(id__in=list(self.memberships.values_list(
|
|
||||||
# "role", flat=True)))
|
|
||||||
|
|
||||||
def get_users(self):
|
def get_users(self):
|
||||||
user_model = get_user_model()
|
user_model = get_user_model()
|
||||||
return user_model.objects.filter(
|
return user_model.objects.filter(
|
||||||
|
|
32
sql/tags.sql
32
sql/tags.sql
|
@ -1,3 +1,5 @@
|
||||||
|
CREATE INDEX issues_unpickle_tags_index ON issues_issue USING btree (unpickle(tags));
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION unpickle (data text)
|
CREATE OR REPLACE FUNCTION unpickle (data text)
|
||||||
RETURNS text[]
|
RETURNS text[]
|
||||||
AS $$
|
AS $$
|
||||||
|
@ -7,18 +9,18 @@ AS $$
|
||||||
return pickle.loads(base64.b64decode(data))
|
return pickle.loads(base64.b64decode(data))
|
||||||
$$ LANGUAGE plpythonu;
|
$$ LANGUAGE plpythonu;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION array_uniq_join (data text[], data2 text[])
|
-- CREATE OR REPLACE FUNCTION array_uniq_join (data text[], data2 text[])
|
||||||
RETURNS text[]
|
-- RETURNS text[]
|
||||||
AS $$
|
-- AS $$
|
||||||
tmp = set(data)
|
-- tmp = set(data)
|
||||||
tmp.update(data2)
|
-- tmp.update(data2)
|
||||||
return tuple(tmp)
|
-- return tuple(tmp)
|
||||||
$$ LANGUAGE plpythonu;
|
-- $$ LANGUAGE plpythonu;
|
||||||
|
--
|
||||||
DROP AGGREGATE array_uniq_concat (text[]);
|
-- DROP AGGREGATE array_uniq_concat (text[]);
|
||||||
CREATE AGGREGATE array_uniq_concat (text[])
|
-- CREATE AGGREGATE array_uniq_concat (text[])
|
||||||
(
|
-- (
|
||||||
sfunc = array_uniq_join,
|
-- sfunc = array_uniq_join,
|
||||||
stype = text[],
|
-- stype = text[],
|
||||||
initcond = '{}'
|
-- initcond = '{}'
|
||||||
);
|
-- );
|
||||||
|
|
Loading…
Reference in New Issue