From 8287489b9c3ab3b3e6a426bdec2d1f1cb3c32367 Mon Sep 17 00:00:00 2001 From: Steven Eardley Date: Wed, 25 Sep 2024 13:04:49 +0100 Subject: [PATCH 01/36] reinstate weekly PDD schedule --- portality/settings.py | 379 ++++++++++++++++++++---------------------- 1 file changed, 182 insertions(+), 197 deletions(-) diff --git a/portality/settings.py b/portality/settings.py index 1ad46e872..96865aacb 100644 --- a/portality/settings.py +++ b/portality/settings.py @@ -39,7 +39,7 @@ DEBUG_PYCHARM_SERVER = 'localhost' DEBUG_PYCHARM_PORT = 6000 -#~~->DebugToolbar:Framework~~ +# ~~->DebugToolbar:Framework~~ DEBUG_TB_TEMPLATE_EDITOR_ENABLED = True DEBUG_TB_INTERCEPT_REDIRECTS = False @@ -48,7 +48,7 @@ ####################################### # Elasticsearch configuration -#~~->Elasticsearch:Technology +# ~~->Elasticsearch:Technology # elasticsearch settings # TODO: changing from single host / esprit to multi host on ES & correct the default ELASTIC_SEARCH_HOST = os.getenv('ELASTIC_SEARCH_HOST', 'http://localhost:9200') # remember the http:// or https:// @@ -66,7 +66,7 @@ ELASTIC_SEARCH_DB_PREFIX = "doaj-" # note: include the separator ELASTIC_SEARCH_TEST_DB_PREFIX = "doajtest-" -INITIALISE_INDEX = True # whether or not to try creating the index and required index types on startup +INITIALISE_INDEX = True # whether or not to try creating the index and required index types on startup ELASTIC_SEARCH_VERSION = "7.10.2" ELASTIC_SEARCH_SNAPSHOT_REPOSITORY = None ELASTIC_SEARCH_SNAPSHOT_TTL = 366 @@ -233,7 +233,7 @@ ] # GitHub base url where static content can be edited by the DOAJ team (you can leave out the trailing slash) -#~~->GitHub:ExternalService~~ +# ~~->GitHub:ExternalService~~ CMS_EDIT_BASE_URL = "https://github.com/DOAJ/doaj/edit/static_pages/cms" # Where static files are served from - in case we need to serve a file @@ -285,7 +285,7 @@ # amount of time a reset token for a new account is valid for PASSWORD_CREATE_TIMEOUT = PASSWORD_RESET_TIMEOUT * 14 -#"api" top-level role is added to all acounts on creation; it can be revoked per account by removal of the role. +# "api" top-level role is added to all accounts on creation; it can be revoked per account by removal of the role. TOP_LEVEL_ROLES = [ "admin", "publisher", @@ -437,7 +437,7 @@ "request_es_backup": {"month": "*", "day": "*", "day_of_week": "*", "hour": "6", "minute": "0"}, "check_latest_es_backup": {"month": "*", "day": "*", "day_of_week": "*", "hour": "9", "minute": "0"}, "prune_es_backups": {"month": "*", "day": "*", "day_of_week": "*", "hour": "9", "minute": "15"}, - "public_data_dump": {"month": "*", "day": "*", "day_of_week": "*", "hour": "10", "minute": "0"}, + "public_data_dump": {"month": "*", "day": "*/6", "day_of_week": "*", "hour": "10", "minute": "0"}, "harvest": {"month": "*", "day": "*", "day_of_week": "*", "hour": "5", "minute": "30"}, "anon_export": {"month": "*", "day": "10", "day_of_week": "*", "hour": "6", "minute": "30"}, "old_data_cleanup": {"month": "*", "day": "12", "day_of_week": "*", "hour": "6", "minute": "30"}, @@ -447,9 +447,6 @@ "article_bulk_create": {"month": "*", "day": "*", "day_of_week": "*", "hour": "*", "minute": "20"}, } -# Standard schedule for PDD (#3970) -# "public_data_dump": {"month": "*", "day": "*/6", "day_of_week": "*", "hour": "10", "minute": "0"}, - HUEY_TASKS = { "ingest_articles": {"retries": 10, "retry_delay": 15}, @@ -690,15 +687,6 @@ 'settings': DEFAULT_INDEX_SETTINGS } } -# MAPPINGS['article'] = {'article': DEFAULT_DYNAMIC_MAPPING} #~~->Article:Model~~ -# MAPPINGS['upload'] = {'upload': DEFAULT_DYNAMIC_MAPPING} #~~->Upload:Model~~ -# MAPPINGS['cache'] = {'cache': DEFAULT_DYNAMIC_MAPPING} #~~->Cache:Model~~ -# MAPPINGS['lcc'] = {'lcc': DEFAULT_DYNAMIC_MAPPING} #~~->LCC:Model~~ -# MAPPINGS['editor_group'] = {'editor_group': DEFAULT_DYNAMIC_MAPPING} #~~->EditorGroup:Model~~ -# MAPPINGS['news'] = {'news': DEFAULT_DYNAMIC_MAPPING} #~~->News:Model~~ -# MAPPINGS['lock'] = {'lock': DEFAULT_DYNAMIC_MAPPING} #~~->Lock:Model~~ -# MAPPINGS['provenance'] = {'provenance': DEFAULT_DYNAMIC_MAPPING} #~~->Provenance:Model~~ -# MAPPINGS['preserve'] = {'preserve': DEFAULT_DYNAMIC_MAPPING} #~~->Preservation:Model~~ MAPPINGS['article'] = MAPPINGS["account"] #~~->Article:Model~~ MAPPINGS['upload'] = MAPPINGS["account"] #~~->Upload:Model~~ @@ -717,222 +705,223 @@ # ~~->Query:WebRoute~~ QUERY_ROUTE = { - "query" : { + "query": { # ~~->PublicJournalQuery:Endpoint~~ - "journal" : { - "auth" : False, - "role" : None, - "query_validators" : ["non_public_fields_validator", "public_query_validator"], - "query_filters" : ["only_in_doaj", "last_update_fallback", "search_all_meta"], - "result_filters" : ["public_result_filter"], - "dao" : "portality.models.Journal", # ~~->Journal:Model~~ - "required_parameters" : {"ref" : ["ssw", "public_journal", "subject_page"]} + "journal": { + "auth": False, + "role": None, + "query_validators": ["non_public_fields_validator", "public_query_validator"], + "query_filters": ["only_in_doaj", "last_update_fallback", "search_all_meta"], + "result_filters": ["public_result_filter"], + "dao": "portality.models.Journal", # ~~->Journal:Model~~ + "required_parameters": {"ref": ["ssw", "public_journal", "subject_page"]} }, # ~~->PublicArticleQuery:Endpoint~~ - "article" : { - "auth" : False, - "role" : None, - "query_validators" : ["non_public_fields_validator", "public_query_validator"], - "query_filters" : ["only_in_doaj"], - "result_filters" : ["public_result_filter"], - "dao" : "portality.models.Article", # ~~->Article:Model~~ - "required_parameters" : {"ref" : ["public_article", "toc", "subject_page"]} + "article": { + "auth": False, + "role": None, + "query_validators": ["non_public_fields_validator", "public_query_validator"], + "query_filters": ["only_in_doaj"], + "result_filters": ["public_result_filter"], + "dao": "portality.models.Article", # ~~->Article:Model~~ + "required_parameters": {"ref": ["public_article", "toc", "subject_page"]} }, # back-compat for fixed query widget # ~~->PublicJournalArticleQuery:Endpoint~~ - "journal,article" : { - "auth" : False, - "role" : None, - "query_validators" : ["non_public_fields_validator", "public_query_validator"], - "query_filters" : ["only_in_doaj", "strip_facets", "es_type_fix", "journal_article_filter"], - "result_filters" : ["public_result_filter", "add_fqw_facets", "fqw_back_compat"], - "dao" : "portality.models.JournalArticle", # ~~->JournalArticle:Model~~ - "required_parameters" : {"ref" : ["fqw"]} + "journal,article": { + "auth": False, + "role": None, + "query_validators": ["non_public_fields_validator", "public_query_validator"], + "query_filters": ["only_in_doaj", "strip_facets", "es_type_fix", "journal_article_filter"], + "result_filters": ["public_result_filter", "add_fqw_facets", "fqw_back_compat"], + "dao": "portality.models.JournalArticle", # ~~->JournalArticle:Model~~ + "required_parameters": {"ref": ["fqw"]} } }, - "publisher_query" : { + "publisher_query": { # ~~->PublisherJournalQuery:Endpoint~~ - "journal" : { - "auth" : True, - "role" : "publisher", - "query_validators" : ["non_public_fields_validator"], - "query_filters" : ["owner", "only_in_doaj", "search_all_meta"], - "result_filters" : ["publisher_result_filter"], - "dao" : "portality.models.Journal" # ~~->Journal:Model~~ + "journal": { + "auth": True, + "role": "publisher", + "query_validators": ["non_public_fields_validator"], + "query_filters": ["owner", "only_in_doaj", "search_all_meta"], + "result_filters": ["publisher_result_filter"], + "dao": "portality.models.Journal" # ~~->Journal:Model~~ }, # ~~->PublisherApplicationQuery:Endpoint~~ - "applications" : { - "auth" : True, - "role" : "publisher", - "query_validators" : ["non_public_fields_validator"], - "query_filters" : ["owner", "not_update_request", "search_all_meta"], - "result_filters" : ["publisher_result_filter"], - "dao" : "portality.models.AllPublisherApplications" # ~~->AllPublisherApplications:Model~~ + "applications": { + "auth": True, + "role": "publisher", + "query_validators": ["non_public_fields_validator"], + "query_filters": ["owner", "not_update_request", "search_all_meta"], + "result_filters": ["publisher_result_filter"], + "dao": "portality.models.AllPublisherApplications" # ~~->AllPublisherApplications:Model~~ }, # ~~->PublisherUpdateRequestsQuery:Endpoint~~ - "update_requests" : { - "auth" : True, - "role" : "publisher", - "query_validators" : ["non_public_fields_validator"], - "query_filters" : ["owner", "update_request", "search_all_meta"], - "result_filters" : ["publisher_result_filter"], - "dao" : "portality.models.Application" # ~~->Application:Model~~ + "update_requests": { + "auth": True, + "role": "publisher", + "query_validators": ["non_public_fields_validator"], + "query_filters": ["owner", "update_request", "search_all_meta"], + "result_filters": ["publisher_result_filter"], + "dao": "portality.models.Application" # ~~->Application:Model~~ } }, - "admin_query" : { + "admin_query": { # ~~->AdminJournalQuery:Endpoint~~ - "journal" : { - "auth" : True, - "role" : "admin", - "dao" : "portality.models.Journal" # ~~->Journal:Model~~ + "journal": { + "auth": True, + "role": "admin", + "dao": "portality.models.Journal" # ~~->Journal:Model~~ }, # ~~->AdminApplicationQuery:Endpoint~~ - "suggestion" : { - "auth" : True, - "role" : "admin", - "query_filters" : ["not_update_request"], - "dao" : "portality.models.Application" # ~~->Application:Model~~ + "suggestion": { + "auth": True, + "role": "admin", + "query_filters": ["not_update_request"], + "dao": "portality.models.Application" # ~~->Application:Model~~ }, # ~~->AdminUpdateRequestQuery:Endpoint~~ "update_requests": { "auth": True, "role": "admin", - "query_filters" : ["update_request"], + "query_filters": ["update_request"], "dao": "portality.models.Application" # ~~->Application:Model~~ }, # ~~->AdminEditorGroupQuery:Endpoint~~ - "editor,group" : { - "auth" : True, - "role" : "admin", - "dao" : "portality.models.EditorGroup" # ~~->EditorGroup:Model~~ + "editor,group": { + "auth": True, + "role": "admin", + "dao": "portality.models.EditorGroup" # ~~->EditorGroup:Model~~ }, # ~~->AdminAccountQuery:Endpoint~~ - "account" : { - "auth" : True, - "role" : "admin", - "dao" : "portality.models.Account" # ~~->Account:Model~~ + "account": { + "auth": True, + "role": "admin", + "dao": "portality.models.Account" # ~~->Account:Model~~ }, # ~~->AdminJournalArticleQuery:Endpoint~~ - "journal,article" : { - "auth" : True, - "role" : "admin", - "dao" : "portality.models.search.JournalArticle" # ~~->JournalArticle:Model~~ + "journal,article": { + "auth": True, + "role": "admin", + "dao": "portality.models.search.JournalArticle" # ~~->JournalArticle:Model~~ }, # ~~->AdminBackgroundJobQuery:Endpoint~~ - "background,job" : { - "auth" : True, - "role" : "admin", - "dao" : "portality.models.BackgroundJob" # ~~->BackgroundJob:Model~~ + "background,job": { + "auth": True, + "role": "admin", + "dao": "portality.models.BackgroundJob" # ~~->BackgroundJob:Model~~ }, # ~~->APINotificationQuery:Endpoint~~ - "notifications" : { - "auth" : False, - "role" : "admin", - "dao" : "portality.models.Notification", # ~~->Notification:Model~~ - "required_parameters" : None + "notifications": { + "auth": False, + "role": "admin", + "dao": "portality.models.Notification", # ~~->Notification:Model~~ + "required_parameters": None } }, - "associate_query" : { + "associate_query": { # ~~->AssEdJournalQuery:Endpoint~~ - "journal" : { - "auth" : True, - "role" : "associate_editor", - "query_validators" : ["non_public_fields_validator"], - "query_filters" : ["associate", "search_all_meta"], - "dao" : "portality.models.Journal" # ~~->Journal:Model~~ + "journal": { + "auth": True, + "role": "associate_editor", + "query_validators": ["non_public_fields_validator"], + "query_filters": ["associate", "search_all_meta"], + "dao": "portality.models.Journal" # ~~->Journal:Model~~ }, # ~~->AssEdApplicationQuery:Endpoint~~ - "suggestion" : { - "auth" : True, - "role" : "associate_editor", - "query_validators" : ["non_public_fields_validator"], - "query_filters" : ["associate", "search_all_meta"], - "dao" : "portality.models.Application" # ~~->Application:Model~~ + "suggestion": { + "auth": True, + "role": "associate_editor", + "query_validators": ["non_public_fields_validator"], + "query_filters": ["associate", "search_all_meta"], + "dao": "portality.models.Application" # ~~->Application:Model~~ } }, - "editor_query" : { + "editor_query": { # ~~->EditorJournalQuery:Endpoint~~ - "journal" : { - "auth" : True, - "role" : "editor", - "query_validators" : ["non_public_fields_validator"], - "query_filters" : ["editor", "search_all_meta"], - "dao" : "portality.models.Journal" # ~~->Journal:Model~~ + "journal": { + "auth": True, + "role": "editor", + "query_validators": ["non_public_fields_validator"], + "query_filters": ["editor", "search_all_meta"], + "dao": "portality.models.Journal" # ~~->Journal:Model~~ }, # ~~->EditorApplicationQuery:Endpoint~~ - "suggestion" : { - "auth" : True, - "role" : "editor", - "query_validators" : ["non_public_fields_validator"], - "query_filters" : ["editor", "search_all_meta"], - "dao" : "portality.models.Application" # ~~->Application:Model~~ + "suggestion": { + "auth": True, + "role": "editor", + "query_validators": ["non_public_fields_validator"], + "query_filters": ["editor", "search_all_meta"], + "dao": "portality.models.Application" # ~~->Application:Model~~ } }, - "api_query" : { + "api_query": { # ~~->APIArticleQuery:Endpoint~~ - "article" : { - "auth" : False, - "role" : None, - "query_filters" : ["only_in_doaj", "public_source"], - "dao" : "portality.models.Article", # ~~->Article:Model~~ - "required_parameters" : None, - "keepalive" : "10m" + "article": { + "auth": False, + "role": None, + "query_filters": ["only_in_doaj", "public_source"], + "dao": "portality.models.Article", # ~~->Article:Model~~ + "required_parameters": None, + "keepalive": "10m" }, # ~~->APIJournalQuery:Endpoint~~ - "journal" : { - "auth" : False, - "role" : None, + "journal": { + "auth": False, + "role": None, "query_validators": ["non_public_fields_validator"], - "query_filters" : ["only_in_doaj", "public_source", "search_all_meta"], - "dao" : "portality.models.Journal", # ~~->Journal:Model~~ - "required_parameters" : None + "query_filters": ["only_in_doaj", "public_source", "search_all_meta"], + "dao": "portality.models.Journal", # ~~->Journal:Model~~ + "required_parameters": None }, # ~~->APIApplicationQuery:Endpoint~~ - "application" : { - "auth" : True, - "role" : None, + "application": { + "auth": True, + "role": None, "query_validators": ["non_public_fields_validator"], - "query_filters" : ["owner", "private_source", "search_all_meta"], - "dao" : "portality.models.Suggestion", # ~~->Application:Model~~ - "required_parameters" : None + "query_filters": ["owner", "private_source", "search_all_meta"], + "dao": "portality.models.Suggestion", # ~~->Application:Model~~ + "required_parameters": None } }, "dashboard_query": { # ~~->APINotificationQuery:Endpoint~~ - "notifications" : { - "auth" : False, - "role" : "read_notifications", - "query_filters" : ["who_current_user"], # ~~-> WhoCurrentUser:Query - "dao" : "portality.models.Notification", # ~~->Notification:Model~~ - "required_parameters" : None + "notifications": { + "auth": False, + "role": "read_notifications", + "query_filters": ["who_current_user"], # ~~-> WhoCurrentUser:Query + "dao": "portality.models.Notification", # ~~->Notification:Model~~ + "required_parameters": None } } } QUERY_FILTERS = { # sanitisers - "public_query_validator" : "portality.lib.query_filters.public_query_validator", - "non_public_fields_validator" : "portality.lib.query_filters.non_public_fields_validator", + "public_query_validator": "portality.lib.query_filters.public_query_validator", + "non_public_fields_validator": "portality.lib.query_filters.non_public_fields_validator", # query filters - "only_in_doaj" : "portality.lib.query_filters.only_in_doaj", - "owner" : "portality.lib.query_filters.owner", - "update_request" : "portality.lib.query_filters.update_request", - "associate" : "portality.lib.query_filters.associate", - "editor" : "portality.lib.query_filters.editor", - "strip_facets" : "portality.lib.query_filters.strip_facets", - "es_type_fix" : "portality.lib.query_filters.es_type_fix", - "last_update_fallback" : "portality.lib.query_filters.last_update_fallback", - "not_update_request" : "portality.lib.query_filters.not_update_request", - "who_current_user" : "portality.lib.query_filters.who_current_user", # ~~-> WhoCurrentUser:Query ~~ - "search_all_meta" : "portality.lib.query_filters.search_all_meta", # ~~-> SearchAllMeta:Query ~~ - "journal_article_filter" : "portality.lib.query_filters.journal_article_filter", # ~~-> JournalArticleFilter:Query ~~ + "only_in_doaj": "portality.lib.query_filters.only_in_doaj", + "owner": "portality.lib.query_filters.owner", + "update_request": "portality.lib.query_filters.update_request", + "associate": "portality.lib.query_filters.associate", + "editor": "portality.lib.query_filters.editor", + "strip_facets": "portality.lib.query_filters.strip_facets", + "es_type_fix": "portality.lib.query_filters.es_type_fix", + "last_update_fallback": "portality.lib.query_filters.last_update_fallback", + "not_update_request": "portality.lib.query_filters.not_update_request", + "who_current_user": "portality.lib.query_filters.who_current_user", # ~~-> WhoCurrentUser:Query ~~ + "search_all_meta": "portality.lib.query_filters.search_all_meta", # ~~-> SearchAllMeta:Query ~~ + "journal_article_filter": "portality.lib.query_filters.journal_article_filter", + # ~~-> JournalArticleFilter:Query ~~ # result filters "public_result_filter": "portality.lib.query_filters.public_result_filter", "publisher_result_filter": "portality.lib.query_filters.publisher_result_filter", - "add_fqw_facets" : "portality.lib.query_filters.add_fqw_facets", - "fqw_back_compat" : "portality.lib.query_filters.fqw_back_compat", + "add_fqw_facets": "portality.lib.query_filters.add_fqw_facets", + "fqw_back_compat": "portality.lib.query_filters.fqw_back_compat", # source filters "private_source": "portality.lib.query_filters.private_source", @@ -947,7 +936,7 @@ ] ADMIN_NOTES_INDEX_ONLY_FIELDS = { - "all_meta" : { + "all_meta": { "type": "text", "fields": { "exact": { @@ -993,8 +982,8 @@ # ~~->BibJSON:Model~~ AUTOCOMPLETE_ADVANCED_FIELD_MAPS = { - "bibjson.publisher.name" : "index.publisher_ac", - "bibjson.institution.name" : "index.institution_ac" + "bibjson.publisher.name": "index.publisher_ac", + "bibjson.institution.name": "index.institution_ac" } #################################################### @@ -1123,7 +1112,6 @@ TOC_CHANGEFREQ = "monthly" - ################################################## # News feed settings # ~~->News:Feature~~ @@ -1159,9 +1147,6 @@ # ENTER YOUR OWN TOKEN IN APPROPRIATE .cfg FILE #BITLY_OAUTH_TOKEN = "" -############################################### -# Date handling -# See portality.lib.dates - moved to prevent circular import ################################################# # API configuration @@ -1176,42 +1161,42 @@ # ~~->ArticleBibJSON:Model~~ DISCOVERY_ARTICLE_SEARCH_SUBS = { - "title" : "bibjson.title", - "doi" : "bibjson.identifier.id.exact", - "issn" : "index.issn.exact", - "publisher" : "bibjson.journal.publisher", - "journal" : "bibjson.journal.title", - "abstract" : "bibjson.abstract" + "title": "bibjson.title", + "doi": "bibjson.identifier.id.exact", + "issn": "index.issn.exact", + "publisher": "bibjson.journal.publisher", + "journal": "bibjson.journal.title", + "abstract": "bibjson.abstract" } DISCOVERY_ARTICLE_SORT_SUBS = { - "title" : "index.unpunctitle.exact" + "title": "index.unpunctitle.exact" } # ~~->JournalBibJSON:Model~~ DISCOVERY_JOURNAL_SEARCH_SUBS = { - "title" : "index.title", - "issn" : "index.issn.exact", - "publisher" : "bibjson.publisher", - "license" : "index.license.exact", - "username" : "admin.owner.exact" + "title": "index.title", + "issn": "index.issn.exact", + "publisher": "bibjson.publisher", + "license": "index.license.exact", + "username": "admin.owner.exact" } DISCOVERY_JOURNAL_SORT_SUBS = { - "title" : "index.unpunctitle.exact", - "issn" : "index.issn.exact" + "title": "index.unpunctitle.exact", + "issn": "index.issn.exact" } DISCOVERY_APPLICATION_SEARCH_SUBS = { - "title" : "index.title", - "issn" : "index.issn.exact", - "publisher" : "bibjson.publisher", - "license" : "index.license.exact" + "title": "index.title", + "issn": "index.issn.exact", + "publisher": "bibjson.publisher", + "license": "index.license.exact" } DISCOVERY_APPLICATION_SORT_SUBS = { - "title" : "index.unpunctitle.exact", - "issn" : "index.issn.exact" + "title": "index.unpunctitle.exact", + "issn": "index.issn.exact" } # API data dump settings @@ -1332,12 +1317,12 @@ ############################################# -## Harvester Configuration +# Harvester Configuration # ~~->Harvester:Feature~~ -## Configuration options for the DOAJ API Client +# Configuration options for the DOAJ API Client -## EPMC Client configuration +# EPMC Client configuration # ~~-> EPMC:ExternalService~~ EPMC_REST_API = "https://www.ebi.ac.uk/europepmc/webservices/rest/" EPMC_TARGET_VERSION = "6.9" # doc here: https://europepmc.org/docs/Europe_PMC_RESTful_Release_Notes.pdf @@ -1467,7 +1452,7 @@ } ################################################## -## Public data dump settings +# Public data dump settings # how long should the temporary URL for public data dumps last PUBLIC_DATA_DUMP_URL_TIMEOUT = 3600 @@ -1545,7 +1530,7 @@ # Datalog # ~~->Datalog:Feature~~ -### Datalog for Journal Added +# Datalog for Journal Added # google sheet filename for datalog ja DATALOG_JA_FILENAME = 'DOAJ: journals added and withdrawn' From bcb10890de1705c64b38567ef0d0e7a539eb177d Mon Sep 17 00:00:00 2001 From: Ramakrishna Sakhamuru Date: Tue, 25 Jun 2024 12:27:18 +0530 Subject: [PATCH 02/36] implementation for historical numbers --- doajtest/unit/test_bll_todo_top_todo_maned.py | 58 +++++++++++++- portality/bll/services/todo.py | 80 +++++++++++++++++++ portality/dao.py | 4 +- portality/view/dashboard.py | 4 +- portality/view/editor.py | 3 +- 5 files changed, 144 insertions(+), 5 deletions(-) diff --git a/doajtest/unit/test_bll_todo_top_todo_maned.py b/doajtest/unit/test_bll_todo_top_todo_maned.py index 5322a8c9a..f3f9d180f 100644 --- a/doajtest/unit/test_bll_todo_top_todo_maned.py +++ b/doajtest/unit/test_bll_todo_top_todo_maned.py @@ -216,4 +216,60 @@ def build_application(self, id, lmu_diff, cd_diff, status, app_registry, additio additional_fn(ap) ap.save() - app_registry.append(ap) \ No newline at end of file + app_registry.append(ap) + + def test_historical_count(self): + EDITOR_GROUP_SOURCE = EditorGroupFixtureFactory.make_editor_group_source() + eg = models.EditorGroup(**EDITOR_GROUP_SOURCE) + maned = models.Account(**AccountFixtureFactory.make_managing_editor_source()) + + EDITOR_SOURCE = AccountFixtureFactory.make_editor_source() + ASSED1_SOURCE = AccountFixtureFactory.make_assed1_source() + ASSED2_SOURCE = AccountFixtureFactory.make_assed2_source() + ASSED3_SOURCE = AccountFixtureFactory.make_assed3_source() + editor = models.Account(**EDITOR_SOURCE) + assed1 = models.Account(**ASSED1_SOURCE) + assed2 = models.Account(**ASSED2_SOURCE) + assed3 = models.Account(**ASSED3_SOURCE) + editor.save(blocking=True) + assed1.save(blocking=True) + assed2.save(blocking=True) + assed3.save(blocking=True) + eg.set_maned(maned.id) + eg.set_editor(editor.id) + eg.set_associates([assed1.id, assed2.id, assed3.id]) + eg.save(blocking=True) + + self.add_provenance_record("status:" + constants.APPLICATION_STATUS_READY, "editor", editor.id, eg) + self.add_provenance_record("status:" + constants.APPLICATION_STATUS_COMPLETED, "associate_editor", assed1.id, eg) + self.add_provenance_record("status:" + constants.APPLICATION_STATUS_COMPLETED, "associate_editor", assed2.id, eg) + self.add_provenance_record("status:" + constants.APPLICATION_STATUS_COMPLETED, "associate_editor", assed3.id, eg) + + stats = self.svc.historical_numbers(eg) + + self.assertEqual(stats["year"], dates.now_str(dates.FMT_YEAR)) + self.assertEqual(stats["editor"]["name"], editor.name) + self.assertEqual(stats["editor"]["count"], 1) + + associate_editors = [assed1.name, assed2.name, assed3.name] + + for assed in stats["associate_editors"]: + self.assertTrue(assed["name"] in associate_editors) + self.assertEqual(assed["count"], 1) + + editor_count = self.svc.historical_count(editor) + self.assertEqual(editor_count, 1) + assed_count = self.svc.historical_count(assed1) + self.assertEqual(assed_count, 1) + + + def add_provenance_record(self, status, role, user, editor_group): + data = { + "user": user, + "roles": [role], + "type": "suggestion", + "action": status, + "editor_group": [editor_group.id] + } + p1 = models.Provenance(**data) + p1.save(blocking=True) \ No newline at end of file diff --git a/portality/bll/services/todo.py b/portality/bll/services/todo.py index fc57f66da..e9f16dad3 100644 --- a/portality/bll/services/todo.py +++ b/portality/bll/services/todo.py @@ -61,8 +61,59 @@ def group_stats(self, group_id): elif b["key"] == constants.APPLICATION_TYPE_UPDATE_REQUEST: stats["by_status"][bucket["key"]]["update_requests"] = b["doc_count"] + stats["historical_numbers"] = self.historical_numbers(eg) + + return stats + + def historical_numbers(self, editor_group:models.EditorGroup): + """ + Get the count of applications in an editor group where + Associate Editors set to Completed when they have done their review + Editors set them to Ready + in current year + :param editor_group: + :return: historical for editor and associate editor in dict + """ + editor_status = "status:" + constants.APPLICATION_STATUS_READY + associate_status = "status:" + constants.APPLICATION_STATUS_COMPLETED + + stats = {"year":dates.now_str(dates.FMT_YEAR)} + + hs = HistoricalNumbersQuery(editor_group.editor, editor_status, editor_group.id) + # ~~-> Provenance:Model ~~ + editor_count = models.Provenance.count(body=hs.query()) + + # ~~-> Account:Model ~~ + acc = models.Account.pull(editor_group.editor) + stats["editor"] = {"name":acc.name, "count": editor_count} + + stats["associate_editors"] = [] + for associate in editor_group.associates: + hs = HistoricalNumbersQuery(associate, associate_status, editor_group.id) + associate_count = models.Provenance.count(body=hs.query()) + acc = models.Account.pull(associate) + stats["associate_editors"].append({"name":acc.name, "count":associate_count}) + return stats + def historical_count(self, account): + """ + Get the count of overall applications + Associate Editors set to Completed + Editors set them to Ready + in current year + :param account: + :return: + """ + if account.has_role("editor"): + hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_READY) + elif account.has_role("associate_editor"): + hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_COMPLETED) + + count = models.Provenance.count(body=hs.query()) + + return count + def top_todo(self, account, size=25, new_applications=True, update_requests=True): """ @@ -631,4 +682,33 @@ def query(self): } } } + } + + +class HistoricalNumbersQuery: + """ + ~~->$HistoricalNumbers:Query~~ + ~~^->Elasticsearch:Technology~~ + """ + def __init__(self, editor, application_status, editor_group=None): + self.editor_group = editor_group + self.editor = editor + self.application_status = application_status + + def query(self): + must_terms = [{"range": {"last_updated": {"gte": "now/y", "lte": "now"}}}, + {"term": {"type": "suggestion"}}, + {"term": {"user": self.editor}}, + {"term": {"action": self.application_status}} + ] + + if self.editor_group: + must_terms.append({"term": {"editor_group": self.editor_group}}) + + return { + "query": { + "bool": { + "must": must_terms + } + } } \ No newline at end of file diff --git a/portality/dao.py b/portality/dao.py index 80635d714..ae4362f82 100644 --- a/portality/dao.py +++ b/portality/dao.py @@ -855,8 +855,8 @@ def all(cls, size=10000, **kwargs): return cls.q2obj(size=size, **kwargs) @classmethod - def count(cls): - res = ES.count(index=cls.index_name(), doc_type=cls.doc_type()) + def count(cls, body=None): + res = ES.count(index=cls.index_name(), doc_type=cls.doc_type(), body=body) return res.get("count") # return requests.get(cls.target() + '_count').json()['count'] diff --git a/portality/view/dashboard.py b/portality/view/dashboard.py index 2f63949a1..908287ba3 100644 --- a/portality/view/dashboard.py +++ b/portality/view/dashboard.py @@ -32,8 +32,10 @@ def top_todo(): new_applications=new_applications, update_requests=update_requests) + count = svc.historical_count(current_user._get_current_object()) + # ~~-> Dashboard:Page~~ - return render_template('dashboard/index.html', todos=todos) + return render_template('dashboard/index.html', todos=todos, historical_count=count) @blueprint.route("/top_notifications") diff --git a/portality/view/editor.py b/portality/view/editor.py index 0ee5ed511..a8a560846 100644 --- a/portality/view/editor.py +++ b/portality/view/editor.py @@ -30,8 +30,9 @@ def index(): # ~~-> Todo:Service~~ svc = DOAJ.todoService() todos = svc.top_todo(current_user._get_current_object(), size=app.config.get("TODO_LIST_SIZE"), update_requests=False) + count = svc.historical_count(current_user._get_current_object()) # ~~-> Dashboard:Page~~ - return render_template('editor/dashboard.html', todos=todos) + return render_template('editor/dashboard.html', todos=todos, historical_count=count) @blueprint.route('/group_journals') From 0e7b3c21acad33d1eafe3c97a65ae23cdeeb4821 Mon Sep 17 00:00:00 2001 From: Aga Date: Tue, 25 Jun 2024 10:48:34 +0100 Subject: [PATCH 03/36] add banners text --- cms/data/motivational_banners.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 cms/data/motivational_banners.yml diff --git a/cms/data/motivational_banners.yml b/cms/data/motivational_banners.yml new file mode 100644 index 000000000..644364b37 --- /dev/null +++ b/cms/data/motivational_banners.yml @@ -0,0 +1,10 @@ +banners: + - "Whoa! {{ COUNT }} applications already? You’re crushing it!" + - "{{ COUNT }} applications down already? You’re on fire! Keep it up, superstar!" + - "{{ COUNT }} applications down, many more to go! Keep rocking!" + - "{{ COUNT }} applications completed? You’re making it look easy!" + - "{{ COUNT }} applications down and still going strong!" + - "Wait, you’ve completed {{ COUNT }} applications this year already? You’re on fire!" + - "Impressive! You’ve already completed {{ COUNT }} applications this year!" + - "{{ COUNT }} applications in the bag this year! You’re smashing it!" + - "Congratulations, you have completed {{ COUNT }} applications this year so far! Keep up!" \ No newline at end of file From 218884e261224a4ca79251cdcdc982897d991aab Mon Sep 17 00:00:00 2001 From: Aga Date: Tue, 25 Jun 2024 12:34:01 +0100 Subject: [PATCH 04/36] add top banner --- cms/sass/components/_alert.scss | 8 + cms/sass/components/_motivational-banner.scss | 14 + cms/sass/main.scss | 1 + portality/static/js/dashboard.js | 1 + portality/templates/includes/svg/award.svg | 4 + .../templates/layouts/dashboard_base.html | 286 ++++++++++-------- 6 files changed, 187 insertions(+), 127 deletions(-) create mode 100644 cms/sass/components/_motivational-banner.scss create mode 100644 portality/templates/includes/svg/award.svg diff --git a/cms/sass/components/_alert.scss b/cms/sass/components/_alert.scss index 47f841bdb..84992cad3 100644 --- a/cms/sass/components/_alert.scss +++ b/cms/sass/components/_alert.scss @@ -26,6 +26,14 @@ border: 2px solid $grapefruit; } + &--success { + border: 2px solid $dark-green; + } + + &--info { + border: 2px solid $dark-grey; + } + code { background-color: rgba($dark-grey, 0.1); } diff --git a/cms/sass/components/_motivational-banner.scss b/cms/sass/components/_motivational-banner.scss new file mode 100644 index 000000000..1a1854387 --- /dev/null +++ b/cms/sass/components/_motivational-banner.scss @@ -0,0 +1,14 @@ +.motivational-banner { + width: 100%; + + h3 { + text-align: center; + margin-bottom: 0; + + .tag { + margin-bottom: 0; + margin-right: 0; + } + } + +} \ No newline at end of file diff --git a/cms/sass/main.scss b/cms/sass/main.scss index 0f72c8eac..5ef3041c9 100644 --- a/cms/sass/main.scss +++ b/cms/sass/main.scss @@ -43,6 +43,7 @@ "components/loading", "components/logo", "components/modal", + "components/motivational-banner", "components/notifications", "components/numbered-table", "components/pager-buttons", diff --git a/portality/static/js/dashboard.js b/portality/static/js/dashboard.js index 4acc2ae0b..d3e5e2146 100644 --- a/portality/static/js/dashboard.js +++ b/portality/static/js/dashboard.js @@ -22,6 +22,7 @@ doaj.dashboard.init = function(context) { if (first) { first.trigger("click"); } + } doaj.dashboard.groupTabClick = function(event) { diff --git a/portality/templates/includes/svg/award.svg b/portality/templates/includes/svg/award.svg new file mode 100644 index 000000000..73caf4bf8 --- /dev/null +++ b/portality/templates/includes/svg/award.svg @@ -0,0 +1,4 @@ + + + + diff --git a/portality/templates/layouts/dashboard_base.html b/portality/templates/layouts/dashboard_base.html index f60482ed0..1d16c7874 100644 --- a/portality/templates/layouts/dashboard_base.html +++ b/portality/templates/layouts/dashboard_base.html @@ -9,7 +9,8 @@ {# ~~Dashboard:Template~~ #} {% block base_content %} - + {# global site note #} {% if config.get("SITE_NOTE_ACTIVE", False) and not request.cookies.get(config.get("SITE_NOTE_KEY")) %} @@ -19,145 +20,176 @@

DOAJ Dashboard

- + + {% block nav %} {% include 'dashboard/nav.html' %} {% endblock %} - {% block extra_header %}{% endblock %} + {% block extra_header %}{% endblock %}
{% block main_panel %} -
-
-
-
-

- - - - {{ current_user.id }} - {% if current_user.has_role("admin") %} - (Managing Editor) - {% elif current_user.has_role("editor") %} - (Editor) - {% elif current_user.has_role("associate_editor") %} - (Associate Editor) - {% endif %} - - -

-

- {% block page_title %} - Hi, {% if current_user.name %}{{ current_user.name }}{% else %} - {{ current_user.id }}{% endif %}! - {% endblock %} -

-
- +
+
+
+ {% if historical_count > 0 %} +
+

{% include "includes/svg/award.svg" %} Congratulations! You completed {{ historical_count }} applications so far this year!

+
+ {% else %} +
+

You haven't completed any applications this year yet. Start by choosing one from the list below.

+
+ {% endif %} +
+
+
+ {% include "includes/_flash_notification.html" %} + {% block content %}{% endblock %}

@@ -176,12 +208,12 @@

{% endblock %} {% include '_js_includes.html' %} - + {% block extra_js_bottom %}{% endblock extra_js_bottom %} {% if not request.cookies.get("doaj-consent") %} + + + diff --git a/portality/templates/layouts/dashboard_base.html b/portality/templates/layouts/dashboard_base.html index 63d857f36..4b0608464 100644 --- a/portality/templates/layouts/dashboard_base.html +++ b/portality/templates/layouts/dashboard_base.html @@ -175,17 +175,15 @@

- {% set historical_count = 3 %}
- {% if historical_count > 0 %} -
-

{% include "includes/svg/award.svg" %} Congratulations! You completed {{ historical_count }} applications so far this year!

-
- {% else %} -
-

You haven't completed any applications this year yet. Start by choosing one from the list below.

-
- {% endif %} +
+

+ {% if historical_count > 0 %} + {% include "includes/svg/award.svg" %} + {% endif %} + +

+
@@ -212,6 +210,11 @@

You haven't completed any applications this year yet. Start by choosing one {% block extra_js_bottom %}{% endblock extra_js_bottom %} + + + {% if not request.cookies.get("doaj-consent") %} From a1703f8cc44ca5ff8d315cbe3ded6711e41411a3 Mon Sep 17 00:00:00 2001 From: Aga Date: Wed, 26 Jun 2024 13:48:58 +0100 Subject: [PATCH 08/36] refactor the renderGroupInfo function in dashboard --- portality/static/js/dashboard.js | 229 +++++++++++++++---------------- 1 file changed, 108 insertions(+), 121 deletions(-) diff --git a/portality/static/js/dashboard.js b/portality/static/js/dashboard.js index dd792e181..f6f1ea302 100644 --- a/portality/static/js/dashboard.js +++ b/portality/static/js/dashboard.js @@ -72,6 +72,7 @@ doaj.dashboard.loadGroupTab = function (groupId) { doaj.dashboard.groupLoaded = function (data) { let container = $("#group-tab"); container.html(doaj.dashboard.renderGroupInfo(data)); + console.log(data); } doaj.dashboard.groupLoadError = function (data) { @@ -79,146 +80,132 @@ doaj.dashboard.groupLoadError = function (data) { } doaj.dashboard.renderGroupInfo = function (data) { - // ~~-> EditorGroup:Model~~ - - // first remove the editor from the associates list if they are there - if (data.editor_group.associates && data.editor_group.associates.length > 0) { - let edInAssEd = data.editor_group.associates.indexOf(data.editor_group.editor) - if (edInAssEd > -1) { - data.editor_group.associates.splice(edInAssEd, 1); + // Remove the editor from the associates list if they are there + _removeEditorFromAssociates = function (data) { + if (data.editor_group.associates && data.editor_group.associates.length > 0) { + let edInAssEd = data.editor_group.associates.indexOf(data.editor_group.editor); + if (edInAssEd > -1) { + data.editor_group.associates.splice(edInAssEd, 1); + } + } else { + data.editor_group.associates = []; // to avoid having to keep checking it below } - } else { - data.editor_group.associates = []; // just to avoid having to keep checking it below } - let allEditors = [data.editor_group.editor].concat(data.editor_group.associates); + // Generate the search query source + _generateSearchQuerySource = function (term, sort) { + return doaj.searchQuerySource({ + "term": term, + "sort": sort + }); + } - let editorListFrag = ""; - for (let i = 0; i < allEditors.length; i++) { - let ed = allEditors[i]; - // ~~-> ApplicationSearch:Page~~ - let appQuerySource = doaj.searchQuerySource({ - "term": [ + // Generate the editor list fragment + _generateEditorListFragment = function (data, allEditors) { + let editorListFrag = ""; + for (let i = 0; i < allEditors.length; i++) { + let ed = allEditors[i]; + let appQuerySource = _generateSearchQuerySource([ {"admin.editor.exact": ed}, {"admin.editor_group.exact": data.editor_group.name}, - {"index.application_type.exact": "new application"} // this is required so we only see open applications, not finished ones - ], - "sort": [{"admin.date_applied": {"order": "asc"}}] - }) - // // ~~-> UpdateRequestsSearch:Page ~~ - // let urQuerySource = doaj.searchQuerySource({"term" : [ - // {"admin.editor.exact" : ed}, - // {"admin.editor_group.exact" : data.editor_group.name}, - // {"index.application_type.exact" : "update request"} // this is required so we only see open update requests, not finished ones - // ]}) - let appCount = 0; - let urCount = 0; - if (data.by_editor[ed]) { - appCount = data.by_editor[ed].applications || 0; - urCount = data.by_editor[ed].update_requests || 0; - } - - if (data.editors[ed]) { - let isEd = ""; - if (i === 0) { // first one in the list is always the editor - isEd = " (Editor)" + {"index.application_type.exact": "new application"} // only see open applications, not finished ones + ], [{"admin.date_applied": {"order": "asc"}}]); + + let appCount = data.by_editor[ed]?.applications || 0; + let urCount = data.by_editor[ed]?.update_requests || 0; + + if (data.editors[ed]) { + let isEd = i === 0 ? " (Editor)" : ""; + editorListFrag += `
  • `; + if (data.editors[ed].email) { + editorListFrag += `${ed}${isEd}`; + } else { + editorListFrag += `${ed}${isEd} (no email)`; + } + editorListFrag += `${appCount} applications
  • `; } - - editorListFrag += `
  • ` - if (data.editors[ed].email) { - editorListFrag += `${ed}${isEd}` - } else { - editorListFrag += `${ed}${isEd} (no email)` - } - - editorListFrag += `${appCount} applications -
  • `; } + return editorListFrag; } - // ~~-> ApplicationSearch:Page~~ - let appUnassignedSource = doaj.searchQuerySource({ - "term": [ + // Generate the unassigned applications fragment + _generateUnassignedApplicationsFragment = function (data) { + let appUnassignedSource = _generateSearchQuerySource([ {"admin.editor_group.exact": data.editor_group.name}, {"index.has_editor.exact": "No"}, - {"index.application_type.exact": "new application"} // this is required so we only see open applications, not finished ones - ], - "sort": [{"admin.date_applied": {"order": "asc"}}] - }); - // ~~-> UpdateRequestsSearch:Page ~~ - // let urUnassignedSource = doaj.searchQuerySource({"term" : [ - // {"admin.editor_group.exact" : data.editor_group.name}, - // {"index.has_editor.exact": "No"}, - // {"index.application_type.exact" : "update request"} // this is required so we only see open update requests, not finished ones - // ]}) - editorListFrag += `
  • - Unassigned - ${data.unassigned.applications} applications -
  • `; - - let appStatusProgressBar = ""; - - for (let j = 0; j < doaj.dashboard.statusOrder.length; j++) { - let status = doaj.dashboard.statusOrder[j]; - if (data.by_status.hasOwnProperty(status)) { - if (data.by_status[status].applications > 0) { - // ~~-> ApplicationSearch:Page~~ - let appStatusSource = doaj.searchQuerySource({ - "term": [ - {"admin.editor_group.exact": data.editor_group.name}, - {"admin.application_status.exact": status}, - {"index.application_type.exact": "new application"} // this is required so we only see open applications, not finished ones - ], - "sort": [{"admin.date_applied": {"order": "asc"}}] - }) + {"index.application_type.exact": "new application"} // only see open applications, not finished ones + ], [{"admin.date_applied": {"order": "asc"}}]); + + return `
  • + Unassigned + ${data.unassigned.applications} applications +
  • `; + } + + // Generate the status progress bar + _generateStatusProgressBar = function (data) { + let appStatusProgressBar = ""; + for (let status of doaj.dashboard.statusOrder) { + if (data.by_status[status]?.applications > 0) { + let appStatusSource = _generateSearchQuerySource([ + {"admin.editor_group.exact": data.editor_group.name}, + {"admin.application_status.exact": status}, + {"index.application_type.exact": "new application"} // only see open applications, not finished ones + ], [{"admin.date_applied": {"order": "asc"}}]); + appStatusProgressBar += `
  • ${data.by_status[status].applications}
  • `; } } + return appStatusProgressBar; } - // ~~-> ApplicationSearch:Page~~ - let appGroupSource = doaj.searchQuerySource({ - "term": [ + // Generate the main fragment + _renderMainFragment = function (data) { + _removeEditorFromAssociates(data); + + let allEditors = [data.editor_group.editor].concat(data.editor_group.associates); + let editorListFrag = _generateEditorListFragment(data, allEditors); + let unassignedFragment = _generateUnassignedApplicationsFragment(data); + let appStatusProgressBar = _generateStatusProgressBar(data); + + let appGroupSource = _generateSearchQuerySource([ {"admin.editor_group.exact": data.editor_group.name}, - {"index.application_type.exact": "new application"} // this is required so we only see open applications, not finished ones - ], - "sort": [{"admin.date_applied": {"order": "asc"}}] - }); - // ~~-> UpdateRequestsSearch:Page ~~ - // let urGroupSource = doaj.searchQuerySource({ "term" : [ - // {"admin.editor_group.exact" : data.editor_group.name}, - // {"index.application_type.exact" : "update request"} // this is required so we only see open applications, not finished ones - // ]}) - let frag = `
    -

    - ${data.editor_group.name}’s open applications - ${data.total.applications} applications -

    - -
    -

    By editor

    -
      - ${editorListFrag} -
    -
    - -
    -

    Applications by status

    -

    Status progress bar colour legend

    -
      -
    • Pending
    • -
    • In progress
    • -
    • Completed
    • -
    • On hold
    • -
    • Ready
    • -
    -
      - ${appStatusProgressBar} -
    -
    -
    `; - return frag; + {"index.application_type.exact": "new application"} // only see open applications, not finished ones + ], [{"admin.date_applied": {"order": "asc"}}]); + + return `
    +

    + ${data.editor_group.name}’s open applications + ${data.total.applications} applications +

    +
    +

    By editor

    +
      + ${editorListFrag} + ${unassignedFragment} +
    +
    +
    +

    Applications by status

    +

    Status progress bar colour legend

    +
      +
    • Pending
    • +
    • In progress
    • +
    • Completed
    • +
    • On hold
    • +
    • Ready
    • +
    +
      + ${appStatusProgressBar} +
    +
    +
    `; + } + + return _renderMainFragment(data); } + + From ec85d0fa598b353d470b9dbab0c8facc087068d9 Mon Sep 17 00:00:00 2001 From: Aga Date: Fri, 28 Jun 2024 11:13:59 +0100 Subject: [PATCH 09/36] move activities to includes file --- portality/templates/dashboard/index.html | 91 ++++++++++--------- portality/templates/editor/dashboard.html | 59 ++++++------ portality/templates/includes/_activity.html | 38 ++++++++ .../includes/_motivational_banner.html | 14 +++ .../templates/layouts/dashboard_base.html | 12 --- 5 files changed, 130 insertions(+), 84 deletions(-) create mode 100644 portality/templates/includes/_activity.html create mode 100644 portality/templates/includes/_motivational_banner.html diff --git a/portality/templates/dashboard/index.html b/portality/templates/dashboard/index.html index 99459988b..71cb151aa 100644 --- a/portality/templates/dashboard/index.html +++ b/portality/templates/dashboard/index.html @@ -5,64 +5,67 @@ {% block content %}
    {% if request.values.get("filter") == None %} - Show all + Show all {% else %} - Show all + Show all {% endif %} - {% if request.values.get("filter") == "na" %} + {% if request.values.get("filter") == "na" %} New Applications {% else %} New Applications {% endif %} - {% if request.values.get("filter") == "ur" %} - Update Requests + {% if request.values.get("filter") == "ur" %} + Update Requests {% else %} Update Requests {% endif %}
    - {% include "dashboard/_todo.html" %} -
    + {% include "dashboard/_todo.html" %} + {% set groups = managed_groups %} + {% include "includes/_activity.html" %} + {#
    #} {# ~~->$GroupStatus:Feature~~ #} -

    Activity

    -
    - - - {# TODO: there’s a bit of a11y work to be done here; we need to indicate which tabs are hidden and which - aren’t using ARIA attributes. #} - {# TODO: the first tab content needs to be shown by default, without a "click to see" message. #} -
    -
    -
    -
    -
    + {#

    Activity

    #} + {#
    #} + {# #} + {##} + {# TODO: there’s a bit of a11y work to be done here; we need to indicate which tabs are hidden and which +{# aren’t using ARIA attributes. #} + {# TODO: the first tab content needs to be shown by default, without a "click to see" message. #} + {#
    #} + {#
    #} + {#
    #} + {#
    #} + {#
    #} {% endblock %} {% block extra_js_bottom %} - - -{% include "includes/_hotjar.html" %} + + + {% include "includes/_hotjar.html" %} {% endblock %} diff --git a/portality/templates/editor/dashboard.html b/portality/templates/editor/dashboard.html index f22196c2b..c7e5b4e5f 100644 --- a/portality/templates/editor/dashboard.html +++ b/portality/templates/editor/dashboard.html @@ -1,41 +1,44 @@ {% extends "editor/editor_base.html" %} {% block editor_content %} + {% include "includes/_motivational_banner.html" %} {% include "dashboard/_todo.html" %} -
    + {% set groups = editor_of_groups %} + {% include "includes/_activity.html" %} +{#
    #} {# ~~->$GroupStatus:Feature~~ #} - {% if editor_of_groups | length != 0 %} -

    Activity

    -
    - #} +{# {% endif %}#} +{##} {# TODO: there’s a bit of a11y work to be done here; we need to indicate which tabs are hidden and which - aren’t using ARIA attributes. #} +{# aren’t using ARIA attributes. #} {# TODO: the first tab content needs to be shown by default, without a "click to see" message. #} -
    -
    -
    -
    -
    +{#
    #} +{#
    #} +{#
    #} +{# #} +{#
    #} {% endblock %} {% block extra_js_bottom %} diff --git a/portality/templates/includes/_activity.html b/portality/templates/includes/_activity.html new file mode 100644 index 000000000..fa020deb8 --- /dev/null +++ b/portality/templates/includes/_activity.html @@ -0,0 +1,38 @@ +
    + {# ~~->$GroupStatus:Feature~~ #} + {% if groups | length != 0 %} +

    Activity

    +
    + + {% endif %} + + {# TODO: there’s a bit of a11y work to be done here; we need to indicate which tabs are hidden and which + aren’t using ARIA attributes. #} + {# TODO: the first tab content needs to be shown by default, without a "click to see" message. #} +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/portality/templates/includes/_motivational_banner.html b/portality/templates/includes/_motivational_banner.html new file mode 100644 index 000000000..8617cd5fc --- /dev/null +++ b/portality/templates/includes/_motivational_banner.html @@ -0,0 +1,14 @@ +{% if historical_count != null %} +
    +
    +
    +

    + {% if historical_count > 0 %} + {% include "includes/svg/award.svg" %} + {% endif %} + +

    +
    +
    +
    +{% endif %} \ No newline at end of file diff --git a/portality/templates/layouts/dashboard_base.html b/portality/templates/layouts/dashboard_base.html index 42a1079bd..a2702eb8e 100644 --- a/portality/templates/layouts/dashboard_base.html +++ b/portality/templates/layouts/dashboard_base.html @@ -174,18 +174,6 @@

    -
    -
    -
    -

    - {% if historical_count > 0 %} - {% include "includes/svg/award.svg" %} - {% endif %} - -

    -
    -
    -
    {% include "includes/_flash_notification.html" %} {% block content %}{% endblock %} From 44d84fb9e44ace509f2b843c57560f07a83dffc1 Mon Sep 17 00:00:00 2001 From: Aga Date: Fri, 28 Jun 2024 13:07:49 +0100 Subject: [PATCH 10/36] add historical statistics --- portality/bll/services/todo.py | 4 +- portality/static/js/dashboard.js | 79 ++++++++++++------- portality/templates/includes/_activity.html | 1 + .../templates/includes/_color_legend.html | 9 +++ 4 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 portality/templates/includes/_color_legend.html diff --git a/portality/bll/services/todo.py b/portality/bll/services/todo.py index e9f16dad3..b2f0910ed 100644 --- a/portality/bll/services/todo.py +++ b/portality/bll/services/todo.py @@ -85,14 +85,14 @@ def historical_numbers(self, editor_group:models.EditorGroup): # ~~-> Account:Model ~~ acc = models.Account.pull(editor_group.editor) - stats["editor"] = {"name":acc.name, "count": editor_count} + stats["editor"] = {"name":acc.id, "count": editor_count} stats["associate_editors"] = [] for associate in editor_group.associates: hs = HistoricalNumbersQuery(associate, associate_status, editor_group.id) associate_count = models.Provenance.count(body=hs.query()) acc = models.Account.pull(associate) - stats["associate_editors"].append({"name":acc.name, "count":associate_count}) + stats["associate_editors"].append({"name":acc.id, "count":associate_count}) return stats diff --git a/portality/static/js/dashboard.js b/portality/static/js/dashboard.js index f6f1ea302..67deaf75c 100644 --- a/portality/static/js/dashboard.js +++ b/portality/static/js/dashboard.js @@ -162,6 +162,34 @@ doaj.dashboard.renderGroupInfo = function (data) { return appStatusProgressBar; } + _generateStatisticsFragment = function (data) { + let statisticsFrag = ""; + let historicalNumbers = data.historical_numbers; + + if (historicalNumbers) { + statisticsFrag += `
    +

    Statistics for the current year (${historicalNumbers.year})

    `; + + // Ready applications by editor + statisticsFrag += `

    Editor's Ready Applications: `; + statisticsFrag += `${historicalNumbers.editor.name} ${historicalNumbers.editor.count}

    `; + + + // Completed applications by associated editor + statisticsFrag += `

    Applications Completed by associated editors

    `; + statisticsFrag += `
      `; + for (let associateEditor of historicalNumbers.associate_editors) { + statisticsFrag += `
    • ${associateEditor.name} ${associateEditor.count}`; + } + + statisticsFrag += `
    +
    `; + } + + return statisticsFrag; + }; + + // Generate the main fragment _renderMainFragment = function (data) { _removeEditorFromAssociates(data); @@ -170,39 +198,36 @@ doaj.dashboard.renderGroupInfo = function (data) { let editorListFrag = _generateEditorListFragment(data, allEditors); let unassignedFragment = _generateUnassignedApplicationsFragment(data); let appStatusProgressBar = _generateStatusProgressBar(data); + let statisticsFragment = _generateStatisticsFragment(data); let appGroupSource = _generateSearchQuerySource([ {"admin.editor_group.exact": data.editor_group.name}, {"index.application_type.exact": "new application"} // only see open applications, not finished ones ], [{"admin.date_applied": {"order": "asc"}}]); - return `
    -

    - ${data.editor_group.name}’s open applications - ${data.total.applications} applications -

    -
    -

    By editor

    -
      - ${editorListFrag} - ${unassignedFragment} -
    -
    -
    -

    Applications by status

    -

    Status progress bar colour legend

    -
      -
    • Pending
    • -
    • In progress
    • -
    • Completed
    • -
    • On hold
    • -
    • Ready
    • -
    -
      - ${appStatusProgressBar} -
    -
    -
    `; + + // Combine all fragments + let frag = `
    +

    ${data.editor_group.name}’s open applications

    + +
    +

    By editor

    +
      + ${editorListFrag} +
    +
    + +
    +

    Applications by status

    +
      + ${appStatusProgressBar} +
    +
    + + ${statisticsFragment} +
    `; + + return frag; } return _renderMainFragment(data); diff --git a/portality/templates/includes/_activity.html b/portality/templates/includes/_activity.html index fa020deb8..08654d3de 100644 --- a/portality/templates/includes/_activity.html +++ b/portality/templates/includes/_activity.html @@ -2,6 +2,7 @@ {# ~~->$GroupStatus:Feature~~ #} {% if groups | length != 0 %}

    Activity

    + {% include "includes/_color_legend.html" %}
    {% include "dashboard/_todo.html" %} {% set groups = managed_groups %} + {% set person_of_assignments = maned_assignments %} {% include "includes/_activity.html" %} {% endblock %} diff --git a/portality/templates/editor/dashboard.html b/portality/templates/editor/dashboard.html index b4ce35b91..b022f0dd8 100644 --- a/portality/templates/editor/dashboard.html +++ b/portality/templates/editor/dashboard.html @@ -4,6 +4,7 @@ {% include "includes/_motivational_banner.html" %} {% include "dashboard/_todo.html" %} {% set groups = editor_of_groups %} + {% set person_of_assignments = editor_of_assignments %} {% include "includes/_activity.html" %} {% endblock %} diff --git a/portality/templates/includes/_activity.html b/portality/templates/includes/_activity.html index 08654d3de..e5821d8f2 100644 --- a/portality/templates/includes/_activity.html +++ b/portality/templates/includes/_activity.html @@ -16,11 +16,11 @@

    {% else %} {% for eg in groups %} -
  • - + {{ eg.name }} - ({{ editor_of_assignments[eg.name] }} applications) + ({{ person_of_assignments[eg.name] }} applications)
  • {% endfor %} {% endif %} From 898ac779ce3d44c8828e13731bad84b868da5ef2 Mon Sep 17 00:00:00 2001 From: Aga Date: Tue, 9 Jul 2024 15:05:49 +0100 Subject: [PATCH 21/36] remove accidental csv files --- output-by_country.csv | 1 - output-by_year.csv | 120 ------------------------------------------ 2 files changed, 121 deletions(-) delete mode 100644 output-by_country.csv delete mode 100644 output-by_year.csv diff --git a/output-by_country.csv b/output-by_country.csv deleted file mode 100644 index ae5736611..000000000 --- a/output-by_country.csv +++ /dev/null @@ -1 +0,0 @@ -ID,Title,PISSN,EISSN,Created,Country diff --git a/output-by_year.csv b/output-by_year.csv deleted file mode 100644 index a02d53207..000000000 --- a/output-by_year.csv +++ /dev/null @@ -1,120 +0,0 @@ -ID,Title,PISSN,EISSN,Country,Created -YEAR:,2021,COUNT:,12040 -9b36d2808d854c53bf65148d75594266,I-Finance,2476-8871,2615-1081,ID,2021 -422d308da76c4b3f81e4f930ec7796bd,B.R. Nahata Smriti Sansthan Agricultural Extension Journal,2582-564X,2582-3302,IN,2021 -4fec38195d69412ca9a49fe245fcc56a,Mass Communication Research,1016-1007,,TW,2021 -7eddb2f7e65f437ab038458b23bb8255,شعبہ جاتی تحقیقی مجلہ ادراک,2412-6144,2709-4413,PK,2021 -ea3399130aaf439db64bec39b6f01d26,Asian Journal of Medical Sciences,2467-9100,2091-0576,NP,2021 -d701811501d84cf19da15ee59f2de7cb,The Scientific Journal of Cihan University – Sulaimaniya (SJCUS),2520-5102,2520-7377,IQ,2021 -24a6c54e8d8c4dd080c4ba272b94e58e,Turist Rehberliği Nitel Araştırmalar Dergisi (TURNAD),,2757-6302,TR,2021 -826e19f1957f43e8aaf6b8f9b6573de4,Literary Druid,,2582-4155,IN,2021 -c5c0ecd6a847487ea400031abf62277e,Grande Medical Journal,2661-6238,2661-6386,NP,2021 -045d4f293e9e4e0caf21648971311f91,Language. Text. Society,,2687-0487,RU,2021 -2246308c2c3c4bf397a0d4cae6f15bda,Gazi Mühendislik Bilimleri Dergisi,2149-4916,2149-9373,TR,2021 -8317f462751e463da666f29ec61164dc,Revista de la AITT,,2411-3840,US,2021 -f05134611f58446db1589e2d23330646,Aula Virtual,,2665-0398,VE,2021 -cc61bb5ad2ed433c8b7bf783cd7d0a3f,Jurnal Ilmu Kebidanan,2407-6872,2579-4027,ID,2021 -b800a3f791ae42d89d24c2d03388191d,"International Journal of Analytical, Experimental and Finite Element Analysis",2394-5133,2394-5141,IN,2021 -52b9b38b58694ad6a3723634a418866c,Journal of Innovation in Applied Research,,2581-4206,IN,2021 -3edad8bc1b1e4d16ab29bced95557b58,Civics Education and Social Science Journal (CESSJ),2686-3162,2686-3170,ID,2021 -61159b566da0432fa1d9c027276dc21a,Oksident,,2687-2749,TR,2021 -e98fc26ecc824fcfbe7f39ad38253880,Function and Disability Journal,,2588-6304,IR,2021 -ed3a62fc207243caa932f978764d2ce8,Transaction on Biomedical Engineering Applications and Healthcare,,2582-7405,IN,2021 -053205be8ab345a892b48cb8cc02d726,Cadernos de Dereito Actual,2340-860X,2386-5229,ES,2021 -f8b931298f3044c1b5f077a20e5ebd98,"International Journal of Physical Education, Fitness and Sports",2277-5447,2457-0753,IN,2021 -2d7303668b714a33a71a11036117a369,Journal of Educational Research in Developing Areas,,2735-9107,NG,2021 -fa6d5265006b4394a5a9a31ff18ec4be,Arab World English Journal for Translation and Literary Studies,,2550-1542,US,2021 -3c8bcd651e1e4e1caee2e39ef9b8ed72,Studii si Cercetari Filologice: Seria Limbi Straine Aplicate,1583-2236,,RO,2021 -33dcb401bb8e476f98038bec07847308,Uluslararası Sosyal Bilimler Akademi Dergisi (USBAD),,2687-2641,TR,2021 -67c564fa2bb94d9b978469926ff24e40,Erzincan Universitesi Sosyal Bilimler Enstitüsü Dergisi,1308-6510,2148-9289,TR,2021 -0373a4eee3374193a927ef78f21b7785,The Blue Planet : A Magazine on Sustainability,2652-7995,2652-7987,AU,2021 -d309327af5b2411fa0955d495acdbc2f,Syariati: Jurnal Studi Al-Qur`an dan Hukum,2259-9778,2599-1507,ID,2021 -60bd30dda9a84640bf5a1f36af2188f1,Journal of Information and Visualization,,2746-1440,ID,2021 -651d8a7904cb422c8ad4d6e2d9f7f405,"Journal of Applied Science, Engineering, Technology, and Education",,2685-0591,ID,2021 -84c5406f6a8549bfacf8c8550a3c81c8,Quantitative Economics and Management Studies,,2722-6247,ID,2021 -60d57e4ef5f449f39e8751349e50a8f0,TMR Modern Herbal Medicine,,2537-9798,NZ,2021 -5ed7dac8f68b4a52baf59fa4234f31eb,Journal of Innovative Research in Teacher Education,,2757-6116,TR,2021 -3a3431cbaf44426d92259a3f55c47a58,EntomoBrasilis,,1983-0572,BR,2021 -d33fe32fa369467885b3e539fa2c141f,Journal of Education and Teaching Learning (JETL),,2656-0283,ID,2021 -e9975d3b622e41bfa2a241bed3be662c,Journal of Architectural Thought,2538-3019,2676-4806,IR,2021 -97c2010e8b2b472194792bd31e3a37bb,İnsan ve Toplum Bilimleri Araştırmaları Dergisi,,2147-1185,TR,2021 -6373929efbeb4e85a925bf0c5606dae6,Ecologia Balkanica,1314-0213,1313-9940,BG,2021 -542da2097bdd4bd0bc746fbc6ccfff76,Islamology,,2541-884X,RU,2021 -aad8d2fed4664513963556aaebcdc2cf,Христианство на Ближнем Востоке,2587-9316,,RU,2021 -1d5bd066a2cd47cfa03b7ebd1fcc6d0e,Anglistica AION : An Interdisciplinary Journal,,2035-8504,IT,2021 -5fbcc8a50d8c467a803cd763865b1ae3,Oğuzhan Sosyal Bilimler Dergisi,,2687-5845,TR,2021 -fa61da3e40d244a48f859003e850f639,Iranian Journal of Irrigation and Drainage,2008-7942,2676-6884,IR,2021 -00123d33611946ce95f98784f227a141,Hypertension Journal,2454-5996,2455-4987,IN,2021 -51574508c288481db22ae758932603c2,Diálogos e Perspectivas Interventivas,,2675-682X,BR,2021 -0d1a134e17004fcdbf559deb2ad6bbc6,Práticas e Cuidado: Revista de Saúde Coletiva,,2675-7591,BR,2021 -413e0f1c2e8348c8a1160079679cd963,Alifmatika,2715-6095,2715-6109,ID,2021 -a7e91eb0bedb4b558568b5ee3461d8d1,Revista Odeere,,2525-4715,BR,2021 -1a207c9f86be411aa9219708c9e490f5,Cultura e Scienza del Colore,,2384-9568,IT,2021 -596e3db92bab481c8f2fed9623ad4cdf,Dental Poster Journal,,2278-7372,IN,2021 -dc8166b078b14041b13aa56d7a60b1d7,International Journal of Political Theory,,2371-3321,CA,2021 -4d8bb36bd7d2448b87c73c0055bf9882,Journal of Innovations in Civil Engineering and Technology,,2687-2129,TR,2021 -3322f3f565594b26824690b3ce652c8b,Şehir Tıp Dergisi,,2717-9699,TR,2021 -8ff77452b1e74333a768ee2029a9b9c6,Journal of Southern Hemisphere Earth Systems Science,,2206-5865,AU,2021 -27360988c5444453a770bf009f706429,Revista Geadel,,2675-5041,BR,2021 -1a3dec7e02be4fa58ecf5fe546562a45,Jurnal Pendidikan Dasar Flobamorata,2721-9003,2721-8996,ID,2021 -54e421db7d374445a53e53e2958e654b,Jurnal Evaluasi Pendidikan,2086-7425,2620-3073,ID,2021 -252eeaec839d43c2bebb0a22fe4415dd,Iranian Journal of Medical Sciences,0253-0716,1735-3688,IR,2021 -57eece40502247769ef040dab2110a3a,Australian Journal of Science and Technology,,2208-6404,AU,2021 -e5c89143165d468baff9314f39f3610b,Informacinės Technologijos ir Valdymas,1392-124X,2335-884X,LT,2021 -0d31002ae39549c3bfa5f3bb53bc6c67,International Journal of Banking and Finance,1675-722X,,MY,2021 -b5aa08d09f5344bf83b689934c40bcfb,Journal of Cultura and Lingua,,2746-4806,ID,2021 -9a2612d8112a4ddfa656c044853fb519,Ampera: A Research Journal on Politics and Islamic Civilization,,2720-9741,ID,2021 -398579bdf28b4d5791b1bcd259f57445,Erevna,2521-5078,2709-8621,PK,2021 -1062e9e2ea124de280640d537404ca22,Tamaddun: Jurnal Kebudayaan dan Sastra Islam,1412-9027,2622-531X,ID,2021 -c35124e677a241ff8c396b76bd67efb7,International Journal of Language & Law,,2194-7414,DE,2021 -2dd096cd4dd246c1b8ba24142588c49a,Przegląd Pedagogiczny,1897-6557,,PL,2021 -b99513ea68b640e8bb59654ef0678a7b,Рослинництво та ґрунтознавство,2706-7688,2706-7696,UA,2021 -c1f006bbf2c64ce79c6068c4bb65e99b,Prace Komisji Geografii Przemysłu Polskiego Towarzystwa Geograficznego,2080-1653,2449-903X,PL,2021 -bc7a030543c8492fb5d961c62b52128e,Mediatika,1137-4462,1988-3935,ES,2021 -28fd8d9200464d04b42a17b3ecc773a9,Ulusal Kinesyoloji Dergisi,,2757-6566,TR,2021 -37b66df77bcf41c3830b0aa960fb7eaa,Biological and Applied Environmental Research,,2002-6153,SE,2021 -40f8d949f59d4009b326c6475013b41d,HU Revista,0103-3123,1982-8047,BR,2021 -8feb6432b0e94cccbffb84fe251fbcdf,Forum Bibliotek Medycznych,1899-5829,2450-0437,PL,2021 -93ee78d61b3147b8a2fd7fa21dbe7793,Teoria Jurídica Contemporânea,,2526-0464,BR,2021 -5bbc7caaefad4b4399986ceba5841eee,Analisis Pengaruh Posisi Peletakan Magnet Permanen di Rotor Terhadap Kinerja Generator Sinkron Magnet Permanen,2355-6870,,ID,2021 -2e4ccaba0acb4cc9851fd08771f8129e,Mimer Medical Journal,,2581-3072,IN,2021 -3e9870c5f9604f98b59aaea3eb6fbc63,Revista CENIC Ciencias Químicas,1015-8553,2221-2442,CU,2021 -96176fe99e7e4e8a9059d0b0de5f121f,Nefroloji Hemşireliği Dergisi,,2147-7728,TR,2021 -d14b1d3b61b94b3faec55174285ff35b,International Journal of Engineering Works,2521-2419,2409-2770,PK,2021 -09fd482c4a064041827a03831bf7d35f,Milliyetçilik Araştırmaları Dergisi,2667-4459,2667-7911,TR,2021 -100f612778d3473598aa3446e148f44e,Revista Ambientale,1984-9915,2318-454X,BR,2021 -ca5d0c759a854c5ba6e1edb66866567e,Burnished Law Journal,,2582-5534,IN,2021 -0a952c5c4b5c4071ad1b35856b7a3e83,Tamaddun,1693-394X,2722-2632,ID,2021 -0200cd4830564f178fca4e1364826f97,International Journal of TESOL Studies,2632-6779,2633-6898,GB,2021 -f21947f1b6454c2ab7a90c1285908784,Кыргызстандагы саламаттык сактоо,1694-8068,1694-805X,KG,2021 -bebf0767cc8b40e3a5bedc0db5ae1d4c,Modern Care Journal,,2423-7876,IR,2021 -600c34f418c140fdabf89adc80526fb8,Chinese Journal of Network and Information Security,2096-109X,,CN,2021 -a18c1e77c98a41a0911cb76063288e27,"Journal of Traditional Building, Architecture and Urbanism",2660-5821,2660-583X,ES,2021 -be2b7a97425d4352bd0221af40ebc0c0,Hangkong bingqi,1673-5048,,CN,2021 -3892b20297354122b96a2c06c92342ac,Iranian Journal of Field Crops Research,2008-1472,2423-3978,IR,2021 -86861d93a53d4094bec940d7cbd35f14,EARI. Educación Artística. Revista de Investigación,1695-8403,2254-7592,ES,2021 -d21d4b6789bc4577bc86e102f01f154c,Edulead : Journal of Education Management,2684-9208,,ID,2021 -939f12ab748e468f81aae8ebf2c7a2f5,"Journal of Tourism, Hospitality and Environment Management",,0128-178X,MY,2021 -d5ec27e5b5b14c87a017fec43f84432c,Journal of Information System and Technology Management,,0128-1666,MY,2021 -881e13811e474113b1047f4890080b23,"International Journal of Education, Psychology and Counselling",,0128-164X,MY,2021 -c191b60e85fe45c3adee724fcf8a7089,Journal of Clinical and Scientific Research,2277-5706,2277-8357,IN,2021 -1577aa3f98524077a22205062ef31bf9,European journal of volunteering and community-based projects,2724-0592,2724-1947,IT,2021 -509ec5363c9e4041b394e68b533cd914,Temes de Disseny,2604-9155,2604-6032,ES,2021 -665411a3c70a4c03ae4e0825b5e5d7bb,Al-Jabar: Jurnal Pendidikan Matematika,2086-5872,2540-7562,ID,2021 -b2d58af2513d4a10ae0499c750f80020,Acta Agrobotanica,0065-0951,2300-357X,PL,2021 -686bfa77d192464f9445855bade83ac6,Acta Mycologica,0001-625X,2353-074X,PL,2021 -1ad1b1a47c07428887a782b034242661,Acta Societatis Botanicorum Poloniae,0001-6977,2083-9480,PL,2021 -4a23618cee154fe7a9b03446819fbe76,Silva Balcanica,1311-8706,,BG,2021 -ac300adf31ee4d3386f338dce2df74df,Acta Palaeobotanica,,2082-0259,PL,2021 -c975f558b7f34c8494fa31296e53a321,Nordisk Tidsskrift for Ungdomsforskning,,2535-8162,NO,2021 -decd1ca48457430ca55ef1c865b3f375,Ensino em Perspectivas,,2675-9144,BR,2021 -e55d2792bc5845b9b13f97f3e77c9af9,Erciyes Tarım ve Hayvan Bilimleri Dergisi,,2651-5354,TR,2021 -40281e97d41d4918a3d3d991aeaac3a0,IETI Transactions on Engineering Research and Practice,,2616-1699,HK,2021 -584c14d8a91d41778929645aae82b93c,Российский паразитологический журнал,1998-8435,2541-7843,RU,2021 -75c14081a93045a99790b13262b0671d,Small States & Territories,,2616-8006,MT,2021 -970c4f31a1f14dc6b4d3818f28bc905c,Eurasian Journal of Critical Care,,2667-8721,TR,2021 -a6414dcf1cfb433dbc60015609858906,Journal of Sustainable Marketing,,2766-0117,US,2021 -4a960d2d76424952ae2afe1a24ec9eb1,Journal of Innovations in Digital Marketing,,2765-8341,US,2021 -fe9b9d0207144ee8889bf40fb27f9a09,Conflict and Society,2164-4543,2164-4551,US,2021 -75c89c9c97af461884be2ccd717a1776,Environment and Society,2150-6779,2150-6787,US,2021 -4ede6e6e69ef4051b7fca47fab6799de,Museum Worlds,2049-6729,2049-6737,US,2021 From 36d39cf3e4f3733b029bf08cfbbef9e53814fa75 Mon Sep 17 00:00:00 2001 From: Aga Date: Tue, 9 Jul 2024 15:07:44 +0100 Subject: [PATCH 22/36] remove accidental file --- .gitignore-local | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitignore-local diff --git a/.gitignore-local b/.gitignore-local deleted file mode 100644 index 78ba9264b..000000000 --- a/.gitignore-local +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore local setup script -setup.sh From 398524dc064888dedf3740611d9ed654ac6da977 Mon Sep 17 00:00:00 2001 From: Aga Date: Mon, 29 Jul 2024 13:00:35 +0100 Subject: [PATCH 23/36] add unassigned fragment to 'by editor' list --- portality/static/js/dashboard.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/portality/static/js/dashboard.js b/portality/static/js/dashboard.js index 69b49c13d..0937aa6b9 100644 --- a/portality/static/js/dashboard.js +++ b/portality/static/js/dashboard.js @@ -100,6 +100,7 @@ doaj.dashboard.renderGroupInfo = function (data) { // Generate the editor list fragment _generateEditorListFragment = function (data, allEditors) { let editorListFrag = ""; + let unassignedFragment = _generateUnassignedApplicationsFragment(data); for (let i = 0; i < allEditors.length; i++) { let ed = allEditors[i]; let appQuerySource = _generateSearchQuerySource([ @@ -122,6 +123,7 @@ doaj.dashboard.renderGroupInfo = function (data) { editorListFrag += `${appCount} applications`; } } + editorListFrag += `${unassignedFragment}` return editorListFrag; } @@ -194,7 +196,6 @@ doaj.dashboard.renderGroupInfo = function (data) { let allEditors = [data.editor_group.editor].concat(data.editor_group.associates); let editorListFrag = _generateEditorListFragment(data, allEditors); - let unassignedFragment = _generateUnassignedApplicationsFragment(data); let appStatusProgressBar = _generateStatusProgressBar(data); let statisticsFragment = _generateStatisticsFragment(data); From 7adf2f2eb41d95fb30628359de1ad20591c91716 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 5 Sep 2024 14:07:35 +0100 Subject: [PATCH 24/36] a bit of code tidy up --- doajtest/testdrive/statistics.py | 10 +++++----- portality/bll/services/todo.py | 6 +++--- portality/constants.py | 7 +------ portality/dao.py | 4 ++-- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/doajtest/testdrive/statistics.py b/doajtest/testdrive/statistics.py index 61e477526..e06225da0 100644 --- a/doajtest/testdrive/statistics.py +++ b/doajtest/testdrive/statistics.py @@ -108,7 +108,7 @@ def createAccounts(self): def createGroups(self): - self.groups = []; + self.groups = [] for group_key, group_info in self.EDITOR_GROUPS.items(): eg_source = EditorGroupFixtureFactory.make_editor_group_source(group_name=group_key, maned=self.admin, editor= @@ -120,13 +120,13 @@ def createGroups(self): ids_to_set = [assed['id'] for assed in self.asseds[group_info['start_assed_index']:group_info['end_assed_index']]] editor_group.set_associates(ids_to_set) - editor_group.save(blocking=True) + editor_group.save() self.groups.append(editor_group.id) def createProvenanceData(self): - self.finished_by_user = {}; - self.provenance_data = []; + self.finished_by_user = {} + self.provenance_data = [] role_mapping = { "editor": { "array": self.editors, @@ -166,7 +166,7 @@ def add_provenance_record(self, status, role, user, editor_group): "editor_group": [editor_group] } p = models.Provenance(**data) - p.save(blocking=True) + p.save() return p def teardown(self, params): diff --git a/portality/bll/services/todo.py b/portality/bll/services/todo.py index 4341e7426..8b3d0b88c 100644 --- a/portality/bll/services/todo.py +++ b/portality/bll/services/todo.py @@ -81,7 +81,7 @@ def historical_numbers(self, editor_group:models.EditorGroup): hs = HistoricalNumbersQuery(editor_group.editor, editor_status, editor_group.id) # ~~-> Provenance:Model ~~ - editor_count = models.Provenance.count(body=hs.query()) + editor_count = models.Provenance.count(query=hs.query()) # ~~-> Account:Model ~~ acc = models.Account.pull(editor_group.editor) @@ -90,7 +90,7 @@ def historical_numbers(self, editor_group:models.EditorGroup): stats["associate_editors"] = [] for associate in editor_group.associates: hs = HistoricalNumbersQuery(associate, associate_status, editor_group.id) - associate_count = models.Provenance.count(body=hs.query()) + associate_count = models.Provenance.count(query=hs.query()) acc = models.Account.pull(associate) stats["associate_editors"].append({"name":acc.id, "count":associate_count}) @@ -110,7 +110,7 @@ def historical_count(self, account): elif account.has_role("associate_editor"): hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_COMPLETED) - count = models.Provenance.count(body=hs.query()) + count = models.Provenance.count(query=hs.query()) return count diff --git a/portality/constants.py b/portality/constants.py index bd35dad7b..a1ec67545 100644 --- a/portality/constants.py +++ b/portality/constants.py @@ -60,10 +60,6 @@ TODO_ASSOCIATE_START_PENDING = "todo_associate_start_pending" TODO_ASSOCIATE_ALL_APPLICATIONS = "todo_associate_all_applications" -# Roles -ROLE_ASSOCIATE_EDITOR = 'associate_editor' -ROLE_API = "api" - EVENT_ACCOUNT_CREATED = "account:created" EVENT_ACCOUNT_PASSWORD_RESET = "account:password_reset" EVENT_APPLICATION_STATUS = "application:status" @@ -85,13 +81,12 @@ PROCESS__QUICK_REJECT = "quick_reject" -# Role +# Roles ROLE_ADMIN = "admin" ROLE_PUBLISHER = "publisher" ROLE_EDITOR = "editor" ROLE_ASSOCIATE_EDITOR = 'associate_editor' ROLE_PUBLIC_DATA_DUMP = "public_data_dump" -ROLE_PUBLISHER = "publisher" ROLE_PUBLISHER_JOURNAL_CSV = "journal_csv" ROLE_PUBLISHER_PRESERVATION = "preservation" ROLE_API = "api" diff --git a/portality/dao.py b/portality/dao.py index ae4362f82..4a5e2e2e5 100644 --- a/portality/dao.py +++ b/portality/dao.py @@ -855,8 +855,8 @@ def all(cls, size=10000, **kwargs): return cls.q2obj(size=size, **kwargs) @classmethod - def count(cls, body=None): - res = ES.count(index=cls.index_name(), doc_type=cls.doc_type(), body=body) + def count(cls, query=None): + res = ES.count(index=cls.index_name(), doc_type=cls.doc_type(), body=query) return res.get("count") # return requests.get(cls.target() + '_count').json()['count'] From bdabd30a9a50a33d60b1a3b8400e5c0179191126 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 5 Sep 2024 14:28:45 +0100 Subject: [PATCH 25/36] minor wording change to motivational banner --- cms/data/motivational_banners.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/data/motivational_banners.yml b/cms/data/motivational_banners.yml index 48aa29008..e13d52bfe 100644 --- a/cms/data/motivational_banners.yml +++ b/cms/data/motivational_banners.yml @@ -11,4 +11,4 @@ banners: - "Wait, you’ve completed {{ COUNT }} applications this year already? You’re on fire!" - "Impressive! You’ve already completed {{ COUNT }} applications this year!" - "{{ COUNT }} applications in the bag this year! You’re smashing it!" - - "Congratulations, you have completed {{ COUNT }} applications this year so far! Keep up!" \ No newline at end of file + - "Congratulations, you have completed {{ COUNT }} applications this year so far! Keep it up!" \ No newline at end of file From 1c66a718f1937600a7a73ca5d99833da07cd4ae6 Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 13:26:16 +0100 Subject: [PATCH 26/36] display 0 for groups with no apps --- portality/templates/includes/_activity.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/portality/templates/includes/_activity.html b/portality/templates/includes/_activity.html index e5821d8f2..e3bea0505 100644 --- a/portality/templates/includes/_activity.html +++ b/portality/templates/includes/_activity.html @@ -20,7 +20,7 @@

    {{ eg.name }} - ({{ person_of_assignments[eg.name] }} applications) + ({{ person_of_assignments[eg.name] | default(0) }} applications) {% endfor %} {% endif %} From 2ef0d5326a66775392158eebbd7663ac92591594 Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 13:29:31 +0100 Subject: [PATCH 27/36] remove package json files --- package-lock.json | 6 ------ package.json | 1 - 2 files changed, 7 deletions(-) delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 644551e2a..000000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "doaj", - "lockfileVersion": 2, - "requires": true, - "packages": {} -} diff --git a/package.json b/package.json deleted file mode 100644 index 0967ef424..000000000 --- a/package.json +++ /dev/null @@ -1 +0,0 @@ -{} From 4fa5415a646f8f1958fe56a99120441ab44d95f6 Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 13:30:26 +0100 Subject: [PATCH 28/36] rm unnecessary file --- node_modules/.package-lock.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 node_modules/.package-lock.json diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json deleted file mode 100644 index 644551e2a..000000000 --- a/node_modules/.package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "doaj", - "lockfileVersion": 2, - "requires": true, - "packages": {} -} From 6543693482b33ae33bfd5d30d60fb5ebb9a26781 Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 13:31:39 +0100 Subject: [PATCH 29/36] rm unnecessary file --- doajtest/testdrive/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 doajtest/testdrive/__init__.py diff --git a/doajtest/testdrive/__init__.py b/doajtest/testdrive/__init__.py deleted file mode 100644 index e69de29bb..000000000 From 1a519572a27b167beefd483ca696a95e679aa45c Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 13:33:28 +0100 Subject: [PATCH 30/36] correct historical statistics functional test for admin --- doajtest/testbook/dashboard/historical_stats.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doajtest/testbook/dashboard/historical_stats.yml b/doajtest/testbook/dashboard/historical_stats.yml index 793a09de6..419de6c12 100644 --- a/doajtest/testbook/dashboard/historical_stats.yml +++ b/doajtest/testbook/dashboard/historical_stats.yml @@ -3,16 +3,13 @@ testset: Historical Statistics tests: - title: Historical Statistics Display - Managing Editor with 3 groups context: - role: managing editor/admin + role: admin testdrive: statistics steps: - step: Navigate to "/testdrive/statistics" and wait for the page to load slowly. This should be done once at the beginning of the test session and not refreshed between individual tests. - step: Log in with provided managing_editor credentials. results: - User dashboard is displayed. - - step: Verify the motivational banner at the top of the dashboard (green) and check number of finished applications. - results: - - The motivational banner is GREEN and shows the correct sum of applications finished in all groups. - step: Verify historical statistics in the Activity section at the bottom. results: - Three groups are displayed. From 73b32a00decd6594c639287c2db7e63e50571027 Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 13:41:17 +0100 Subject: [PATCH 31/36] ensure index consistency in statistics testdrive --- doajtest/testbook/dashboard/historical_stats.yml | 14 +++++++------- doajtest/testdrive/statistics.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doajtest/testbook/dashboard/historical_stats.yml b/doajtest/testbook/dashboard/historical_stats.yml index 419de6c12..603aab4ee 100644 --- a/doajtest/testbook/dashboard/historical_stats.yml +++ b/doajtest/testbook/dashboard/historical_stats.yml @@ -20,11 +20,11 @@ tests: - step: (Optional) Click the link at the bottom of the testdrive page to free resources after finishing this test session. - title: Historical Statistics Display - Editor with 2 groups context: - role: editor_0 + role: editor testdrive: statistics steps: - step: Navigate to "/testdrive/statistics" and wait for the page to load slowly. This should be done once at the beginning of the test session and not refreshed between individual tests. - - step: Log in with provided editor_0 credentials. + - step: Log in with provided editor_1 credentials. results: - User dashboard is displayed. - step: Verify the motivational banner at the top of the dashboard (green) and check number of finished applications. @@ -40,11 +40,11 @@ tests: - step: (Optional) Click the link at the bottom of the testdrive page to free resources after finishing this test session. - title: Historical Statistics Display - Editor with 1 group context: - role: editor_1 + role: editor testdrive: statistics steps: - step: Navigate to "/testdrive/statistics" and wait for the page to load slowly. This should be done once at the beginning of the test session and not refreshed between individual tests. - - step: Log in with provided editor_1 credentials. + - step: Log in with provided editor_2 credentials. results: - User dashboard is displayed. - step: Verify the motivational banner at the top of the dashboard (green) and check number of finished applications. @@ -64,7 +64,7 @@ tests: testdrive: statistics steps: - step: Navigate to "/testdrive/statistics" and wait for the page to load slowly. This should be done once at the beginning of the test session and not refreshed between individual tests. - - step: Log in with provided associate_editor_0 credentials. + - step: Log in with provided associate_editor_1 credentials. results: - User dashboard is displayed. - step: Verify the motivational banner at the top of the dashboard (grey). @@ -75,13 +75,13 @@ tests: - No statistics are displayed in the Activity section. - step: Log out. - step: - - title: Historical Statistics Display - Associate Editor 1 + - title: Historical Statistics Display - Associate Editor 2 context: role: associate editor testdrive: statistics steps: - step: Navigate to "/testdrive/statistics" and wait for the page to load slowly. This should be done once at the beginning of the test session and not refreshed between individual tests. - - step: Log in with provided associate_editor_1 credentials. + - step: Log in with provided associate_editor_2 credentials. results: - User dashboard is displayed. - step: Verify the motivational banner at the top of the dashboard (green). diff --git a/doajtest/testdrive/statistics.py b/doajtest/testdrive/statistics.py index e06225da0..ed45ef57b 100644 --- a/doajtest/testdrive/statistics.py +++ b/doajtest/testdrive/statistics.py @@ -46,11 +46,11 @@ def setup(self) -> dict: "username": self.admin, "password": self.admin_pass }, - "editor_0": { + "editor_1": { "username": self.editors[0]["id"], "password": self.editors[0]["pass"] }, - "editor_1": { + "editor_2": { "username": self.editors[1]["id"], "password": self.editors[1]["pass"] }, From 9e051dc38366e94603095b8373a2259c5db71334 Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 19:34:47 +0100 Subject: [PATCH 32/36] Refactor methods names Fix testdrive Fix Unit tests --- doajtest/testdrive/statistics.py | 11 +- doajtest/unit/test_bll_todo_top_todo_maned.py | 12 +- portality/bll/services/todo.py | 140 ++++++++++-------- portality/view/dashboard.py | 2 +- portality/view/editor.py | 2 +- 5 files changed, 90 insertions(+), 77 deletions(-) diff --git a/doajtest/testdrive/statistics.py b/doajtest/testdrive/statistics.py index ed45ef57b..bc78f440c 100644 --- a/doajtest/testdrive/statistics.py +++ b/doajtest/testdrive/statistics.py @@ -32,9 +32,9 @@ class Statistics(TestDrive): # Define editor groups and associate editors' associations EDITOR_GROUPS = { - 'Group_0': {'editor_index': 0, 'start_assed_index': 0, 'end_assed_index': 2}, - 'Group_1': {'editor_index': 0, 'start_assed_index': 2, 'end_assed_index': 5}, - 'Group_2': {'editor_index': 1, 'start_assed_index': 5, 'end_assed_index': 8}, + 'eg0': {'editor_index': 0, 'start_assed_index': 0, 'end_assed_index': 2}, + 'eg1': {'editor_index': 0, 'start_assed_index': 2, 'end_assed_index': 5}, + 'eg2': {'editor_index': 1, 'start_assed_index': 5, 'end_assed_index': 8}, } def setup(self) -> dict: @@ -89,7 +89,7 @@ def createAccounts(self): for i in range(self.NUMBER_OF_EDITORS): us = self.create_random_str() pw = self.create_random_str() - editor = models.Account.make_account(us + "@example.com", us, "Editor" + str(i) + " " + us, + editor = models.Account.make_account(us + "@example.com", us, "Editor" + str(i+1) + " " + us, [constants.ROLE_EDITOR]) editor.set_password(pw) editor.save() @@ -100,7 +100,7 @@ def createAccounts(self): for i in range(self.NUMBER_OF_ASSEDITORS): us = self.create_random_str() pw = self.create_random_str() - assed = models.Account.make_account(us + "@example.com", us, "AssEd" + str(i) + " " + us, + assed = models.Account.make_account(us + "@example.com", us, "AssEd" + str(i+1) + " " + us, [constants.ROLE_ASSOCIATE_EDITOR]) assed.set_password(pw) assed.save() @@ -167,6 +167,7 @@ def add_provenance_record(self, status, role, user, editor_group): } p = models.Provenance(**data) p.save() + print(p.id) return p def teardown(self, params): diff --git a/doajtest/unit/test_bll_todo_top_todo_maned.py b/doajtest/unit/test_bll_todo_top_todo_maned.py index f3f9d180f..0e218d59b 100644 --- a/doajtest/unit/test_bll_todo_top_todo_maned.py +++ b/doajtest/unit/test_bll_todo_top_todo_maned.py @@ -245,21 +245,21 @@ def test_historical_count(self): self.add_provenance_record("status:" + constants.APPLICATION_STATUS_COMPLETED, "associate_editor", assed2.id, eg) self.add_provenance_record("status:" + constants.APPLICATION_STATUS_COMPLETED, "associate_editor", assed3.id, eg) - stats = self.svc.historical_numbers(eg) + stats = self.svc.group_finished_historical_counts(eg) self.assertEqual(stats["year"], dates.now_str(dates.FMT_YEAR)) - self.assertEqual(stats["editor"]["name"], editor.name) + self.assertEqual(stats["editor"]["id"], editor.id) self.assertEqual(stats["editor"]["count"], 1) - associate_editors = [assed1.name, assed2.name, assed3.name] + associate_editors = [assed1.id, assed2.id, assed3.id] for assed in stats["associate_editors"]: - self.assertTrue(assed["name"] in associate_editors) + self.assertTrue(assed["id"] in associate_editors) self.assertEqual(assed["count"], 1) - editor_count = self.svc.historical_count(editor) + editor_count = self.svc.user_finished_historical_counts(editor) self.assertEqual(editor_count, 1) - assed_count = self.svc.historical_count(assed1) + assed_count = self.svc.user_finished_historical_counts(assed1) self.assertEqual(assed_count, 1) diff --git a/portality/bll/services/todo.py b/portality/bll/services/todo.py index 8b3d0b88c..1a00c9207 100644 --- a/portality/bll/services/todo.py +++ b/portality/bll/services/todo.py @@ -14,7 +14,7 @@ class TodoService(object): def group_stats(self, group_id): # ~~-> EditorGroup:Model~~ eg = models.EditorGroup.pull(group_id) - stats = {"editor_group" : eg.data} + stats = {"editor_group": eg.data} #~~-> Account:Model ~~ stats["editors"] = {} @@ -22,8 +22,8 @@ def group_stats(self, group_id): for editor in editors: acc = models.Account.pull(editor) stats["editors"][editor] = { - "email" : None if acc is None else acc.email - } + "email": None if acc is None else acc.email + } q = GroupStatsQuery(eg.name) resp = models.Application.query(q=q.query()) @@ -61,23 +61,25 @@ def group_stats(self, group_id): elif b["key"] == constants.APPLICATION_TYPE_UPDATE_REQUEST: stats["by_status"][bucket["key"]]["update_requests"] = b["doc_count"] - stats["historical_numbers"] = self.historical_numbers(eg) + stats["historical_numbers"] = self.group_finished_historical_counts(eg) return stats - def historical_numbers(self, editor_group:models.EditorGroup): + def group_finished_historical_counts(self, editor_group: models.EditorGroup, year=None): """ Get the count of applications in an editor group where Associate Editors set to Completed when they have done their review Editors set them to Ready - in current year - :param editor_group: + in a given year (current by default) + :param editor_group + :param year :return: historical for editor and associate editor in dict """ + year_for_query = dates.now_str(dates.FMT_YEAR) if year is None else year editor_status = "status:" + constants.APPLICATION_STATUS_READY associate_status = "status:" + constants.APPLICATION_STATUS_COMPLETED - stats = {"year":dates.now_str(dates.FMT_YEAR)} + stats = {"year": year_for_query} hs = HistoricalNumbersQuery(editor_group.editor, editor_status, editor_group.id) # ~~-> Provenance:Model ~~ @@ -85,36 +87,36 @@ def historical_numbers(self, editor_group:models.EditorGroup): # ~~-> Account:Model ~~ acc = models.Account.pull(editor_group.editor) - stats["editor"] = {"name":acc.id, "count": editor_count} + stats["editor"] = {"id": acc.id, "count": editor_count} stats["associate_editors"] = [] for associate in editor_group.associates: hs = HistoricalNumbersQuery(associate, associate_status, editor_group.id) associate_count = models.Provenance.count(query=hs.query()) acc = models.Account.pull(associate) - stats["associate_editors"].append({"name":acc.id, "count":associate_count}) + stats["associate_editors"].append({"id": acc.id, "name": acc.name, "count": associate_count}) return stats - def historical_count(self, account): + def user_finished_historical_counts(self, account, year=None): """ Get the count of overall applications Associate Editors set to Completed Editors set them to Ready - in current year - :param account: + in a given year (current by default) + :param account + :param year :return: """ if account.has_role("editor"): - hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_READY) + hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_READY, year) elif account.has_role("associate_editor"): - hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_COMPLETED) + hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_COMPLETED, year) count = models.Provenance.count(query=hs.query()) return count - def top_todo(self, account, size=25, new_applications=True, update_requests=True): """ Returns the top number of todo items for a given user @@ -125,7 +127,7 @@ def top_todo(self, account, size=25, new_applications=True, update_requests=True """ # first validate the incoming arguments to ensure that we've got the right thing argvalidate("top_todo", [ - {"arg" : account, "instance" : models.Account, "allow_none" : False, "arg_name" : "account"} + {"arg": account, "instance": models.Account, "allow_none": False, "arg_name": "account"} ], exceptions.ArgumentException) queries = [] @@ -141,7 +143,7 @@ def top_todo(self, account, size=25, new_applications=True, update_requests=True queries.append(TodoRules.maned_last_month_update_requests(size, maned_of)) queries.append(TodoRules.maned_new_update_requests(size, maned_of)) - if new_applications: # editor and associate editor roles only deal with new applications + if new_applications: # editor and associate editor roles only deal with new applications if account.has_role("editor"): groups = [g for g in models.EditorGroup.groups_by_editor(account.id)] regular_groups = [g for g in groups if g.maned != account.id] @@ -177,10 +179,10 @@ def top_todo(self, account, size=25, new_applications=True, update_requests=True todos.append({ "date": ap.last_manual_update_timestamp if sort == "last_manual_update" else ap.date_applied_timestamp, "date_type": sort, - "action_id" : [aid], - "title" : ap.bibjson().title, - "object_id" : ap.id, - "object" : ap, + "action_id": [aid], + "title": ap.bibjson().title, + "object_id": ap.id, + "object": ap, "boost": boost }) @@ -415,7 +417,7 @@ def editor_assign_pending(cls, groups, size): return constants.TODO_EDITOR_ASSIGN_PENDING, assign_pending, sort_date, 1 @classmethod - def associate_stalled(cls, acc_id, size): + def associate_stalled(cls, acc_id, size): sort_field = "created_date" stalled = TodoQuery( musts=[ @@ -437,7 +439,7 @@ def associate_stalled(cls, acc_id, size): return constants.TODO_ASSOCIATE_PROGRESS_STALLED, stalled, sort_field, 0 @classmethod - def associate_follow_up_old(cls, acc_id, size): + def associate_follow_up_old(cls, acc_id, size): sort_field = "created_date" follow_up_old = TodoQuery( musts=[ @@ -499,7 +501,7 @@ class TodoQuery(object): ~~->$Todo:Query~~ ~~^->Elasticsearch:Technology~~ """ - lmu_sort = {"last_manual_update" : {"order" : "asc"}} + lmu_sort = {"last_manual_update": {"order": "asc"}} # cd_sort = {"created_date" : {"order" : "asc"}} # NOTE that admin.date_applied and created_date should be the same for applications, but for some reason this is not always the case # therefore, we take a created_date sort to mean a date_applied sort @@ -514,16 +516,16 @@ def __init__(self, musts=None, must_nots=None, sort="last_manual_update", size=1 def query(self): sort = self.lmu_sort if self._sort == "last_manual_update" else self.cd_sort q = { - "query" : { - "bool" : { + "query": { + "bool": { "must": self._musts, "must_not": self._must_nots } }, - "sort" : [ + "sort": [ sort ], - "size" : self._size + "size": self._size } return q @@ -546,8 +548,8 @@ def is_update_request(cls): @classmethod def editor_group(cls, groups): return { - "terms" : { - "admin.editor_group.exact" : [g.name for g in groups] + "terms": { + "admin.editor_group.exact": [g.name for g in groups] } } @@ -574,16 +576,16 @@ def cd_older_than(cls, count, unit="w"): @classmethod def status(cls, statuses): return { - "terms" : { - "admin.application_status.exact" : statuses + "terms": { + "admin.application_status.exact": statuses } } @classmethod def exists(cls, field): return { - "exists" : { - "field" : field + "exists": { + "field": field } } @@ -610,13 +612,14 @@ class GroupStatsQuery(): ~~->$GroupStats:Query~~ ~~^->Elasticsearch:Technology~~ """ + def __init__(self, group_name, editor_count=10): self.group_name = group_name self.editor_count = editor_count def query(self): return { - "track_total_hits" : True, + "track_total_hits": True, "query": { "bool": { "must": [ @@ -626,10 +629,10 @@ def query(self): } } ], - "must_not" : [ + "must_not": [ { - "terms" : { - "admin.application_status.exact" : [ + "terms": { + "admin.application_status.exact": [ constants.APPLICATION_STATUS_ACCEPTED, constants.APPLICATION_STATUS_REJECTED ] @@ -638,26 +641,26 @@ def query(self): ] } }, - "size" : 0, - "aggs" : { - "editor" : { - "terms" : { - "field" : "admin.editor.exact", - "size" : self.editor_count + "size": 0, + "aggs": { + "editor": { + "terms": { + "field": "admin.editor.exact", + "size": self.editor_count }, - "aggs" : { - "application_type" : { - "terms" : { + "aggs": { + "application_type": { + "terms": { "field": "admin.application_type.exact", "size": 2 } } } }, - "status" : { - "terms" : { - "field" : "admin.application_status.exact", - "size" : len(constants.APPLICATION_STATUSES_ALL) + "status": { + "terms": { + "field": "admin.application_status.exact", + "size": len(constants.APPLICATION_STATUSES_ALL) }, "aggs": { "application_type": { @@ -668,13 +671,13 @@ def query(self): } } }, - "unassigned" : { - "missing" : { + "unassigned": { + "missing": { "field": "admin.editor.exact" }, - "aggs" : { - "application_type" : { - "terms" : { + "aggs": { + "application_type": { + "terms": { "field": "admin.application_type.exact", "size": 2 } @@ -690,17 +693,26 @@ class HistoricalNumbersQuery: ~~->$HistoricalNumbers:Query~~ ~~^->Elasticsearch:Technology~~ """ - def __init__(self, editor, application_status, editor_group=None): + + def __init__(self, editor, application_status, editor_group=None, year=None): self.editor_group = editor_group self.editor = editor self.application_status = application_status + self.year = year def query(self): - must_terms = [{"range": {"last_updated": {"gte": "now/y", "lte": "now"}}}, - {"term": {"type": "suggestion"}}, - {"term": {"user.exact": self.editor}}, - {"term": {"action": self.application_status}} - ] + if self.year is None: + date_range = {"gte": "now/y", "lte": "now"} + else: + date_range = { + "gte": f"{self.year}-01-01", + "lte": f"{self.year}-12-31" + } + must_terms = [{"range": {"last_updated": date_range}}, + {"term": {"type": "suggestion"}}, + {"term": {"user.exact": self.editor}}, + {"term": {"action": self.application_status}} + ] if self.editor_group: must_terms.append({"term": {"editor_group": self.editor_group}}) @@ -711,4 +723,4 @@ def query(self): "must": must_terms } } - } \ No newline at end of file + } diff --git a/portality/view/dashboard.py b/portality/view/dashboard.py index 908287ba3..e6cb62b3b 100644 --- a/portality/view/dashboard.py +++ b/portality/view/dashboard.py @@ -32,7 +32,7 @@ def top_todo(): new_applications=new_applications, update_requests=update_requests) - count = svc.historical_count(current_user._get_current_object()) + count = svc.user_finished_historical_counts(current_user._get_current_object()) # ~~-> Dashboard:Page~~ return render_template('dashboard/index.html', todos=todos, historical_count=count) diff --git a/portality/view/editor.py b/portality/view/editor.py index a8a560846..c312e89aa 100644 --- a/portality/view/editor.py +++ b/portality/view/editor.py @@ -30,7 +30,7 @@ def index(): # ~~-> Todo:Service~~ svc = DOAJ.todoService() todos = svc.top_todo(current_user._get_current_object(), size=app.config.get("TODO_LIST_SIZE"), update_requests=False) - count = svc.historical_count(current_user._get_current_object()) + count = svc.user_finished_historical_counts(current_user._get_current_object()) # ~~-> Dashboard:Page~~ return render_template('editor/dashboard.html', todos=todos, historical_count=count) From f8b920e6db937249f84a6bb05ed7cae7d588df61 Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 19:49:25 +0100 Subject: [PATCH 33/36] check for hs being none --- portality/bll/services/todo.py | 7 ++++++- portality/templates/includes/_motivational_banner.html | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/portality/bll/services/todo.py b/portality/bll/services/todo.py index 1a00c9207..3b30a0e2e 100644 --- a/portality/bll/services/todo.py +++ b/portality/bll/services/todo.py @@ -108,12 +108,17 @@ def user_finished_historical_counts(self, account, year=None): :param year :return: """ + hs = None + if account.has_role("editor"): hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_READY, year) elif account.has_role("associate_editor"): hs = HistoricalNumbersQuery(account.id, "status:" + constants.APPLICATION_STATUS_COMPLETED, year) - count = models.Provenance.count(query=hs.query()) + if hs: + count = models.Provenance.count(query=hs.query()) + else: + count = None return count diff --git a/portality/templates/includes/_motivational_banner.html b/portality/templates/includes/_motivational_banner.html index 8617cd5fc..aa6b59f56 100644 --- a/portality/templates/includes/_motivational_banner.html +++ b/portality/templates/includes/_motivational_banner.html @@ -1,4 +1,4 @@ -{% if historical_count != null %} +{% if historical_count %}
    From 5c6a9a5a9788961cf4ec849671324d09a8d8a996 Mon Sep 17 00:00:00 2001 From: Aga Date: Tue, 1 Oct 2024 12:18:20 +0100 Subject: [PATCH 34/36] dont display the header of a by status graph if no applications and associate editors statistics if no asseds --- portality/static/js/dashboard.js | 39 +++++++++++++++++--------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/portality/static/js/dashboard.js b/portality/static/js/dashboard.js index 0937aa6b9..f7fa84a7a 100644 --- a/portality/static/js/dashboard.js +++ b/portality/static/js/dashboard.js @@ -176,14 +176,16 @@ doaj.dashboard.renderGroupInfo = function (data) { } // Completed applications by associated editor - statisticsFrag += `

    Applications Completed by associated editors

    `; - statisticsFrag += `
      `; - for (let associateEditor of historicalNumbers.associate_editors) { - statisticsFrag += `
    • ${associateEditor.name} ${associateEditor.count}`; - } + if (historicalNumbers.associate_editors.length) { + statisticsFrag += `

      Applications Completed by associated editors

      `; + statisticsFrag += `
        `; + for (let associateEditor of historicalNumbers.associate_editors) { + statisticsFrag += `
      • ${associateEditor.name} ${associateEditor.count}`; + } - statisticsFrag += `
      - `; + statisticsFrag += `
    ` + } + statisticsFrag += ``; } return statisticsFrag; @@ -214,17 +216,18 @@ doaj.dashboard.renderGroupInfo = function (data) {
      ${editorListFrag}
    - - -
    -

    Applications by status

    -
      - ${appStatusProgressBar} -
    -
    - - ${statisticsFragment} -
    `; + ` + if (data["total"]["applications"]) { + frag += `
    +

    Applications by status

    +
      + ${appStatusProgressBar} +
    +
    ` + } + frag += ` + ${statisticsFragment} +
    `; return frag; } From 45ac7a294b859793d5f94eeaf49d20a842249839 Mon Sep 17 00:00:00 2001 From: Aga Date: Tue, 1 Oct 2024 12:24:36 +0100 Subject: [PATCH 35/36] fix the name vs id bug --- portality/static/js/dashboard.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/portality/static/js/dashboard.js b/portality/static/js/dashboard.js index f7fa84a7a..9805e9fa2 100644 --- a/portality/static/js/dashboard.js +++ b/portality/static/js/dashboard.js @@ -172,7 +172,7 @@ doaj.dashboard.renderGroupInfo = function (data) { if (current_user.role.includes("admin")) { // Ready applications by editor statisticsFrag += `

    Editor's Ready Applications: `; - statisticsFrag += `${historicalNumbers.editor.name} ${historicalNumbers.editor.count}

    `; + statisticsFrag += `${historicalNumbers.editor.id} ${historicalNumbers.editor.count}

    `; } // Completed applications by associated editor @@ -180,7 +180,7 @@ doaj.dashboard.renderGroupInfo = function (data) { statisticsFrag += `

    Applications Completed by associated editors

    `; statisticsFrag += `
      `; for (let associateEditor of historicalNumbers.associate_editors) { - statisticsFrag += `
    • ${associateEditor.name} ${associateEditor.count}`; + statisticsFrag += `
    • ${associateEditor.id} ${associateEditor.count}`; } statisticsFrag += `
    ` From a8c00d079eb7e350f370f8d7f8ce4475ee3da15b Mon Sep 17 00:00:00 2001 From: Aga Date: Tue, 1 Oct 2024 17:35:28 +0100 Subject: [PATCH 36/36] move file --- doajtest/testdrive/{helpers => }/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doajtest/testdrive/{helpers => }/__init__.py (100%) diff --git a/doajtest/testdrive/helpers/__init__.py b/doajtest/testdrive/__init__.py similarity index 100% rename from doajtest/testdrive/helpers/__init__.py rename to doajtest/testdrive/__init__.py