Count own tasks/models for projects

This commit is contained in:
allegroai 2022-07-08 17:35:01 +03:00
parent f8b9d9802e
commit 62d5779bd5
7 changed files with 133 additions and 36 deletions

View File

@ -183,6 +183,7 @@ class ProjectBLL:
if new_location != old_location: if new_location != old_location:
raise errors.bad_request.CannotUpdateProjectLocation(name=new_name) raise errors.bad_request.CannotUpdateProjectLocation(name=new_name)
fields["name"] = new_name fields["name"] = new_name
fields["basename"] = new_name.split("/")[-1]
fields["last_update"] = datetime.utcnow() fields["last_update"] = datetime.utcnow()
updated = project.update(upsert=False, **fields) updated = project.update(upsert=False, **fields)
@ -225,6 +226,7 @@ class ProjectBLL:
user=user, user=user,
company=company, company=company,
name=name, name=name,
basename=name.split("/")[-1],
description=description, description=description,
tags=tags, tags=tags,
system_tags=system_tags, system_tags=system_tags,
@ -328,6 +330,7 @@ class ProjectBLL:
project_ids: Sequence[str], project_ids: Sequence[str],
specific_state: Optional[EntityVisibility] = None, specific_state: Optional[EntityVisibility] = None,
filter_: Mapping[str, Any] = None, filter_: Mapping[str, Any] = None,
users: Sequence[str] = None,
) -> Tuple[Sequence, Sequence]: ) -> Tuple[Sequence, Sequence]:
archived = EntityVisibility.archived.value archived = EntityVisibility.archived.value
@ -352,7 +355,10 @@ class ProjectBLL:
# count tasks per project per status # count tasks per project per status
{ {
"$match": cls.get_match_conditions( "$match": cls.get_match_conditions(
company=company_id, project_ids=project_ids, filter_=filter_ company=company_id,
project_ids=project_ids,
filter_=filter_,
users=users,
) )
}, },
ensure_valid_fields(), ensure_valid_fields(),
@ -469,7 +475,10 @@ class ProjectBLL:
{ {
"$match": { "$match": {
**cls.get_match_conditions( **cls.get_match_conditions(
company=company_id, project_ids=project_ids, filter_=filter_ company=company_id,
project_ids=project_ids,
filter_=filter_,
users=users,
), ),
**get_state_filter(), **get_state_filter(),
} }
@ -516,13 +525,18 @@ class ProjectBLL:
include_children: bool = True, include_children: bool = True,
search_hidden: bool = False, search_hidden: bool = False,
filter_: Mapping[str, Any] = None, filter_: Mapping[str, Any] = None,
users: Sequence[str] = None,
user_active_project_ids: Sequence[str] = None,
) -> Tuple[Dict[str, dict], Dict[str, dict]]: ) -> Tuple[Dict[str, dict], Dict[str, dict]]:
if not project_ids: if not project_ids:
return {}, {} return {}, {}
child_projects = ( child_projects = (
_get_sub_projects( _get_sub_projects(
project_ids, _only=("id", "name"), search_hidden=search_hidden project_ids,
_only=("id", "name"),
search_hidden=search_hidden,
allowed_ids=user_active_project_ids,
) )
if include_children if include_children
else {} else {}
@ -535,6 +549,7 @@ class ProjectBLL:
project_ids=list(project_ids_with_children), project_ids=list(project_ids_with_children),
specific_state=specific_state, specific_state=specific_state,
filter_=filter_, filter_=filter_,
users=users,
) )
default_counts = dict.fromkeys(get_options(TaskStatus), 0) default_counts = dict.fromkeys(get_options(TaskStatus), 0)
@ -701,7 +716,7 @@ class ProjectBLL:
users: Sequence[str], users: Sequence[str],
project_ids: Optional[Sequence[str]] = None, project_ids: Optional[Sequence[str]] = None,
allow_public: bool = True, allow_public: bool = True,
) -> Sequence[str]: ) -> Tuple[Sequence[str], Sequence[str]]:
""" """
Get the projects ids where user created any tasks including all the parents of these projects Get the projects ids where user created any tasks including all the parents of these projects
If project ids are specified then filter the results by these project ids If project ids are specified then filter the results by these project ids
@ -725,13 +740,16 @@ class ProjectBLL:
res = list(res) res = list(res)
if not res: if not res:
return res return res, res
ids_with_parents = _ids_with_parents(res) user_active_project_ids = _ids_with_parents(res)
if project_ids: filtered_ids = (
return [pid for pid in ids_with_parents if pid in project_ids] list(set(user_active_project_ids) & set(project_ids))
if project_ids
else list(user_active_project_ids)
)
return ids_with_parents return filtered_ids, user_active_project_ids
@classmethod @classmethod
def get_task_parents( def get_task_parents(
@ -800,12 +818,18 @@ class ProjectBLL:
@staticmethod @staticmethod
def get_match_conditions( def get_match_conditions(
company: str, project_ids: Sequence[str], filter_: Mapping[str, Any] company: str,
project_ids: Sequence[str],
filter_: Mapping[str, Any],
users: Sequence[str],
): ):
conditions = { conditions = {
"company": {"$in": [None, "", company]}, "company": {"$in": [None, "", company]},
"project": {"$in": project_ids}, "project": {"$in": project_ids},
} }
if users:
conditions["user"] = {"$in": users}
if not filter_: if not filter_:
return conditions return conditions
@ -828,7 +852,11 @@ class ProjectBLL:
@classmethod @classmethod
def calc_own_contents( def calc_own_contents(
cls, company: str, project_ids: Sequence[str], filter_: Mapping[str, Any] = None cls,
company: str,
project_ids: Sequence[str],
filter_: Mapping[str, Any] = None,
users: Sequence[str] = None,
) -> Dict[str, dict]: ) -> Dict[str, dict]:
""" """
Returns the amount of task/models per requested project Returns the amount of task/models per requested project
@ -841,7 +869,10 @@ class ProjectBLL:
pipeline = [ pipeline = [
{ {
"$match": cls.get_match_conditions( "$match": cls.get_match_conditions(
company=company, project_ids=project_ids, filter_=filter_ company=company,
project_ids=project_ids,
filter_=filter_,
users=users,
) )
}, },
{"$project": {"project": 1}}, {"$project": {"project": 1}},

View File

@ -51,6 +51,7 @@ def _ensure_project(
created=now, created=now,
last_update=now, last_update=now,
name=name, name=name,
basename=name.split("/")[-1],
**(creation_params or dict(description="")), **(creation_params or dict(description="")),
) )
parent = _ensure_project(company, user, location, creation_params=creation_params) parent = _ensure_project(company, user, location, creation_params=creation_params)
@ -104,6 +105,7 @@ def _get_sub_projects(
project_ids: Sequence[str], project_ids: Sequence[str],
_only: Sequence[str] = ("id", "path"), _only: Sequence[str] = ("id", "path"),
search_hidden=True, search_hidden=True,
allowed_ids: Sequence[str] = None,
) -> Mapping[str, Sequence[Project]]: ) -> Mapping[str, Sequence[Project]]:
""" """
Return the list of child projects of all the levels for the parent project ids Return the list of child projects of all the levels for the parent project ids
@ -111,6 +113,9 @@ def _get_sub_projects(
query = dict(path__in=project_ids) query = dict(path__in=project_ids)
if not search_hidden: if not search_hidden:
query["system_tags__nin"] = [EntityVisibility.hidden.value] query["system_tags__nin"] = [EntityVisibility.hidden.value]
if allowed_ids:
query["id__in"] = allowed_ids
qs = Project.objects(**query) qs = Project.objects(**query)
if _only: if _only:
_only = set(_only) | {"path"} _only = set(_only) | {"path"}

View File

@ -12,12 +12,23 @@ events_retrieval {
# should not exceed the amount of concurrent connections set in the ES driver # should not exceed the amount of concurrent connections set in the ES driver
max_metrics_concurrency: 4 max_metrics_concurrency: 4
# If set then max_metrics_count and max_variants_count are calculated dynamically on user data
dynamic_metrics_count: true
# The percentage from the ES aggs limit (10000) to use for the max_metrics and max_variants calculation
dynamic_metrics_count_threshold: 80
# the max amount of metrics to aggregate on # the max amount of metrics to aggregate on
max_metrics_count: 100 max_metrics_count: 100
# the max amount of variants to aggregate on # the max amount of variants to aggregate on
max_variants_count: 100 max_variants_count: 100
debug_images {
# Allow to return the debug images for the variants with uninitialized valid iterations border
allow_uninitialized_variants: true
}
max_raw_scalars_size: 200000 max_raw_scalars_size: 200000
scroll_id_key: "cTN5VEtWEC6QrHvUl0FTx9kNyO0CcCK1p57akxma" scroll_id_key: "cTN5VEtWEC6QrHvUl0FTx9kNyO0CcCK1p57akxma"

View File

@ -704,6 +704,45 @@ class GetMixin(PropsMixin):
v for k, v in cls._field_collation_overrides.items() if field.startswith(k) v for k, v in cls._field_collation_overrides.items() if field.startswith(k)
) )
@classmethod
def get_count(
cls: Union["GetMixin", Document],
company,
query_dict: dict = None,
query_options: QueryParameterOptions = None,
query: Q = None,
allow_public=False,
) -> int:
_query = cls._get_combined_query(
company=company,
query_dict=query_dict,
query_options=query_options,
query=query,
allow_public=allow_public,
)
return cls.objects(_query).count()
@classmethod
def _get_combined_query(
cls,
company,
query_dict: dict = None,
query_options: QueryParameterOptions = None,
query: Q = None,
allow_public=False,
) -> Q:
if query_dict is not None:
q = cls.prepare_query(
parameters=query_dict,
company=company,
parameters_options=query_options,
allow_public=allow_public,
)
else:
q = cls._prepare_perm_query(company, allow_public=allow_public)
return (q & query) if query else q
@classmethod @classmethod
def get_many( def get_many(
cls, cls,
@ -749,16 +788,13 @@ class GetMixin(PropsMixin):
if override_collation: if override_collation:
break break
if query_dict is not None: _query = cls._get_combined_query(
q = cls.prepare_query( company=company,
parameters=query_dict, query_dict=query_dict,
company=company, query_options=query_options,
parameters_options=query_options, query=query,
allow_public=allow_public, allow_public=allow_public,
) )
else:
q = cls._prepare_perm_query(company, allow_public=allow_public)
_query = (q & query) if query else q
if return_dicts: if return_dicts:
data_getter = partial( data_getter = partial(

View File

@ -9,7 +9,7 @@ from apiserver.database.model.base import GetMixin
class Project(AttributedDocument): class Project(AttributedDocument):
get_all_query_options = GetMixin.QueryParameterOptions( get_all_query_options = GetMixin.QueryParameterOptions(
pattern_fields=("name", "description"), pattern_fields=("name", "basename", "description"),
list_fields=("tags", "system_tags", "id", "parent", "path"), list_fields=("tags", "system_tags", "id", "parent", "path"),
range_fields=("last_update",), range_fields=("last_update",),
) )
@ -21,6 +21,7 @@ class Project(AttributedDocument):
"parent", "parent",
"path", "path",
("company", "name"), ("company", "name"),
("company", "basename"),
{ {
"name": "%s.project.main_text_index" % Database.backend, "name": "%s.project.main_text_index" % Database.backend,
"fields": ["$name", "$id", "$description"], "fields": ["$name", "$id", "$description"],
@ -37,6 +38,7 @@ class Project(AttributedDocument):
min_length=3, min_length=3,
sparse=True, sparse=True,
) )
basename = StrippedStringField(required=True)
description = StringField() description = StringField()
created = DateTimeField(required=True) created = DateTimeField(required=True)
tags = SafeSortedListField(StringField(required=True)) tags = SafeSortedListField(StringField(required=True))

View File

@ -25,6 +25,10 @@ _definitions {
description: "Project name" description: "Project name"
type: string type: string
} }
basename {
description: "Project base name"
type: string
}
description { description {
description: "Project description" description: "Project description"
type: string type: string
@ -156,6 +160,10 @@ _definitions {
description: "Project name" description: "Project name"
type: string type: string
} }
basename {
description: "Project base name"
type: string
}
description { description {
description: "Project description" description: "Project description"
type: string type: string
@ -214,6 +222,14 @@ _definitions {
} }
} }
} }
own_tasks {
description: "The amount of tasks under this project (without children projects). Returned if 'check_own_contents' flag is set in the request"
type: integer
}
own_models {
description: "The amount of models under this project (without children projects). Returned if 'check_own_contents' flag is set in the request"
type: integer
}
} }
} }
metric_variant_result { metric_variant_result {
@ -385,6 +401,10 @@ get_all {
description: "Get only projects whose name matches this pattern (python regular expression syntax)" description: "Get only projects whose name matches this pattern (python regular expression syntax)"
type: string type: string
} }
basename {
description: "Project base name"
type: string
}
description { description {
description: "Get only projects whose description matches this pattern (python regular expression syntax)" description: "Get only projects whose description matches this pattern (python regular expression syntax)"
type: string type: string
@ -530,18 +550,6 @@ get_all_ex {
} }
} }
} }
response {
properties {
own_tasks {
description: "The amount of tasks under this project (without children projects). Returned if 'check_own_contents' flag is set in the request"
type: integer
}
own_models {
description: "The amount of models under this project (without children projects). Returned if 'check_own_contents' flag is set in the request"
type: integer
}
}
}
} }
"2.14": ${get_all_ex."2.13"} { "2.14": ${get_all_ex."2.13"} {
request.properties.search_hidden { request.properties.search_hidden {

View File

@ -110,8 +110,9 @@ def get_all_ex(call: APICall, company_id: str, request: ProjectsGetRequest):
data, shallow_search=request.shallow_search, data, shallow_search=request.shallow_search,
) )
with TimingContext("mongo", "projects_get_all"): with TimingContext("mongo", "projects_get_all"):
user_active_project_ids = None
if request.active_users: if request.active_users:
ids = project_bll.get_projects_with_active_user( ids, user_active_project_ids = project_bll.get_projects_with_active_user(
company=company_id, company=company_id,
users=request.active_users, users=request.active_users,
project_ids=requested_ids, project_ids=requested_ids,
@ -139,6 +140,7 @@ def get_all_ex(call: APICall, company_id: str, request: ProjectsGetRequest):
company=company_id, company=company_id,
project_ids=list(existing_requested_ids), project_ids=list(existing_requested_ids),
filter_=request.include_stats_filter, filter_=request.include_stats_filter,
users=request.active_users,
) )
for project in projects: for project in projects:
project.update(**contents.get(project["id"], {})) project.update(**contents.get(project["id"], {}))
@ -156,6 +158,8 @@ def get_all_ex(call: APICall, company_id: str, request: ProjectsGetRequest):
include_children=request.stats_with_children, include_children=request.stats_with_children,
search_hidden=request.search_hidden, search_hidden=request.search_hidden,
filter_=request.include_stats_filter, filter_=request.include_stats_filter,
users=request.active_users,
user_active_project_ids=user_active_project_ids,
) )
for project in projects: for project in projects: