From 16430a663615d7a41a7b453be73b7baf404d3fda Mon Sep 17 00:00:00 2001 From: allegroai <> Date: Tue, 5 Jan 2021 19:02:48 +0200 Subject: [PATCH] Support query by task state in projects.get_tasks_parents, return task project names --- apiserver/apimodels/projects.py | 5 +- apiserver/bll/organization/__init__.py | 23 ++++-- apiserver/schema/services/projects.conf | 17 ++++ apiserver/services/projects.py | 18 ++--- .../tests/automated/test_project_tags.py | 27 ------- .../tests/automated/test_task_parents.py | 79 +++++++++++++++++++ 6 files changed, 126 insertions(+), 43 deletions(-) create mode 100644 apiserver/tests/automated/test_task_parents.py diff --git a/apiserver/apimodels/projects.py b/apiserver/apimodels/projects.py index 1175dd4..4b6b8b9 100644 --- a/apiserver/apimodels/projects.py +++ b/apiserver/apimodels/projects.py @@ -1,7 +1,8 @@ from jsonmodels import models, fields -from apiserver.apimodels import ListField +from apiserver.apimodels import ListField, ActualEnumField from apiserver.apimodels.organization import TagsRequest +from apiserver.database.model import EntityVisibility class ProjectReq(models.Base): @@ -19,3 +20,5 @@ class ProjectTagsRequest(TagsRequest): class ProjectTaskParentsRequest(ProjectReq): projects = ListField(str) + tasks_state = ActualEnumField(EntityVisibility) + diff --git a/apiserver/bll/organization/__init__.py b/apiserver/bll/organization/__init__.py index 0d0426a..bb6baf1 100644 --- a/apiserver/bll/organization/__init__.py +++ b/apiserver/bll/organization/__init__.py @@ -1,11 +1,12 @@ from collections import defaultdict from enum import Enum from operator import itemgetter -from typing import Sequence, Dict +from typing import Sequence, Dict, Optional from mongoengine import Q from apiserver.config_repo import config +from apiserver.database.model import EntityVisibility from apiserver.database.model.model import Model from apiserver.database.model.task.task import Task from apiserver.redis_manager import redman @@ -67,7 +68,10 @@ class OrgBLL: @classmethod def get_parent_tasks( - cls, company_id: str, projects: Sequence[str] + cls, + company_id: str, + projects: Sequence[str], + state: Optional[EntityVisibility] = None, ) -> Sequence[dict]: """ Get list of unique parent tasks sorted by task name for the passed company projects @@ -76,12 +80,19 @@ class OrgBLL: query = Q(company=company_id) if projects: query &= Q(project__in=projects) + if state == EntityVisibility.archived: + query &= Q(system_tags__in=[EntityVisibility.archived.value]) + elif state == EntityVisibility.active: + query &= Q(system_tags__nin=[EntityVisibility.archived.value]) + parent_ids = set(Task.objects(query).distinct("parent")) if not parent_ids: return [] - parents = [ - {"id": task.id, "name": task.name} - for task in Task.objects(id__in=parent_ids).only("id", "name") - ] + parents = Task.get_many_with_join( + company_id, + query=Q(id__in=parent_ids), + allow_public=True, + override_projection=("id", "name", "project.name"), + ) return sorted(parents, key=itemgetter("name")) diff --git a/apiserver/schema/services/projects.conf b/apiserver/schema/services/projects.conf index 0f4874d..dcc9dd2 100644 --- a/apiserver/schema/services/projects.conf +++ b/apiserver/schema/services/projects.conf @@ -650,6 +650,12 @@ get_task_parents { type: array items { type: string } } + tasks_state { + description: "Return parents for tasks in the specified state. If Null is provided, parents for all task states will be returned." + type: string + enum: [ active, archived ] + default: active + } } } response { @@ -669,6 +675,17 @@ get_task_parents { description: "The name of the parent task" type: string } + project { + type: object + id { + description: "The ID of the parent task project" + type: string + } + name { + description: "The name of the parent task project" + type: string + } + } } } } diff --git a/apiserver/services/projects.py b/apiserver/services/projects.py index 49a76ac..1fff9ab 100644 --- a/apiserver/services/projects.py +++ b/apiserver/services/projects.py @@ -429,20 +429,18 @@ def get_tags(call: APICall, company, request: ProjectTagsRequest): "projects.make_public", min_version="2.9", request_data_model=MakePublicRequest ) def make_public(call: APICall, company_id, request: MakePublicRequest): - with translate_errors_context(): - call.result.data = Project.set_public( - company_id, ids=request.ids, invalid_cls=InvalidProjectId, enabled=True - ) + call.result.data = Project.set_public( + company_id, ids=request.ids, invalid_cls=InvalidProjectId, enabled=True + ) @endpoint( "projects.make_private", min_version="2.9", request_data_model=MakePublicRequest ) def make_public(call: APICall, company_id, request: MakePublicRequest): - with translate_errors_context(): - call.result.data = Project.set_public( - company_id, ids=request.ids, invalid_cls=InvalidProjectId, enabled=False - ) + call.result.data = Project.set_public( + company_id, ids=request.ids, invalid_cls=InvalidProjectId, enabled=False + ) @endpoint( @@ -454,5 +452,7 @@ def get_task_parents( call: APICall, company_id: str, request: ProjectTaskParentsRequest ): call.result.data = { - "parents": org_bll.get_parent_tasks(company_id, projects=request.projects) + "parents": org_bll.get_parent_tasks( + company_id, projects=request.projects, state=request.tasks_state + ) } diff --git a/apiserver/tests/automated/test_project_tags.py b/apiserver/tests/automated/test_project_tags.py index abce67f..95b09f4 100644 --- a/apiserver/tests/automated/test_project_tags.py +++ b/apiserver/tests/automated/test_project_tags.py @@ -7,33 +7,6 @@ class TestProjectTags(TestService): def setUp(self, version="2.12"): super().setUp(version=version) - def test_task_parent(self): - # stand alone task - parent_sa_name = "Test parent parent standalone" - parent_sa = self.new_task(name=parent_sa_name) - self.new_task(name="Test parent task standalone", parent=parent_sa) - - # tasks in projects - parent_name = "Test parent parent" - parent = self.new_task(name=parent_name) - p1 = self.create_temp("projects", name="Test parents1", description="test") - self.new_task(project=p1, name="Test parent task1", parent=parent) - p2 = self.create_temp("projects", name="Test parents2", description="test") - self.new_task(project=p1, name="Test parent task2", parent=parent) - - parents = self.api.projects.get_task_parents(projects=[p1, p2]).parents - self.assertEqual([{"id": parent, "name": parent_name}], parents) - - res = self.api.projects.get_task_parents() - parents = [p for p in res.parents if p.id in (parent, parent_sa)] - self.assertEqual( - [ - {"id": parent, "name": parent_name}, - {"id": parent_sa, "name": parent_sa_name}, - ], - parents, - ) - def test_project_tags(self): tags_1 = ["Test tag 1", "Test tag 2"] tags_2 = ["Test tag 3", "Test tag 4"] diff --git a/apiserver/tests/automated/test_task_parents.py b/apiserver/tests/automated/test_task_parents.py new file mode 100644 index 0000000..677a318 --- /dev/null +++ b/apiserver/tests/automated/test_task_parents.py @@ -0,0 +1,79 @@ +from apiserver.tests.automated import TestService + + +class TestTaskParent(TestService): + def setUp(self, version="2.12"): + super().setUp(version=version) + + def test_query_by_project(self): + # stand alone task + parent_sa_name = "Test parent parent standalone" + parent_sa = self.new_task(name=parent_sa_name) + self.new_task(name="Test parent task standalone", parent=parent_sa) + + # tasks in projects + project_name = "Test parents project" + project = self.create_temp("projects", name=project_name, description="test") + + parent_name = "Test parent parent" + parent = self.new_task(project=project, name=parent_name) + + self.new_task(project=project, name="Test parent task1", parent=parent) + self.new_task(project=project, name="Test parent task2", parent=parent) + + parents = self.api.projects.get_task_parents(projects=[project]).parents + self.assertEqual( + [ + { + "id": parent, + "name": parent_name, + "project": {"id": project, "name": project_name}, + } + ], + parents, + ) + + res = self.api.projects.get_task_parents() + parents = [p for p in res.parents if p.id in (parent, parent_sa)] + self.assertEqual( + [ + { + "id": parent, + "name": parent_name, + "project": {"id": project, "name": project_name}, + }, + {"id": parent_sa, "name": parent_sa_name}, + ], + parents, + ) + + def test_query_by_state(self): + project_name = "Test parents project" + project = self.create_temp("projects", name=project_name, description="test") + + parent1_name = "Test parent parent1" + parent1 = self.new_task(project=project, name=parent1_name) + t1 = self.new_task(project=project, name="Test parent task1", parent=parent1) + + parent2_name = "Test parent parent2" + parent2 = self.new_task(project=project, name=parent2_name) + t2 = self.new_task(project=project, name="Test parent task2", parent=parent2) + self.api.tasks.archive(tasks=[t2]) + + # No state filter + parents = self.api.projects.get_task_parents(projects=[project]).parents + self.assertEqual([parent1, parent2], [p.id for p in parents]) + + # Active tasks + parents = self.api.projects.get_task_parents(projects=[project], tasks_state="active").parents + self.assertEqual([parent1], [p.id for p in parents]) + + # Archived tasks + parents = self.api.projects.get_task_parents(projects=[project], tasks_state="archived").parents + self.assertEqual([parent2], [p.id for p in parents]) + + def new_task(self, **kwargs): + self.update_missing( + kwargs, type="testing", name="test project tags", input=dict(view=dict()) + ) + return self.create_temp("tasks", **kwargs)