diff --git a/cms/data/notifications.yml b/cms/data/notifications.yml index 6aca840e49..1a67c6c7c2 100644 --- a/cms/data/notifications.yml +++ b/cms/data/notifications.yml @@ -142,3 +142,8 @@ update_request:publisher:rejected:notify: short: Your update request was rejected +journal:assed:discontinuing_soon:notify: + long: | + Journal "{title}" (id: {id}) will discontinue in {days} days. + short: + Journal discontinuing \ No newline at end of file diff --git a/doajtest/testbook/public_site/ToC.yml b/doajtest/testbook/public_site/ToC.yml new file mode 100644 index 0000000000..b481085cf9 --- /dev/null +++ b/doajtest/testbook/public_site/ToC.yml @@ -0,0 +1,15 @@ +suite: Public Site +testset: ToC +tests: +- title: Test Correctly Displayed Discontinued Date + context: + role: anonymous + steps: + - step: To prepare to do this test make sure there are 3 journals publically available in DOAJ + one with discontinued date in the past + one with discontinued date in the future + one with discontinued date today + - step: Search for every journal from the list above + results: + - On the ToC of the journal with discontinued date in the past or today - the discontinued date is displayed + - On the ToC of the journal with discontinued date in the future - the discontinued date is not displayed diff --git a/doajtest/unit/api_tests/test_apiv3_discovery.py b/doajtest/unit/api_tests/test_apiv3_discovery.py index b847c48b5b..ffc94feacc 100644 --- a/doajtest/unit/api_tests/test_apiv3_discovery.py +++ b/doajtest/unit/api_tests/test_apiv3_discovery.py @@ -241,7 +241,7 @@ def test_03_applications(self): for i in range(5): a = models.Suggestion() a.set_owner("owner") - a.set_created(dates.format(dates.after(now, i))) + a.set_created(dates.format(dates.seconds_after(now, i))) bj = a.bibjson() bj.title = "Test Suggestion {x}".format(x=i) bj.add_identifier(bj.P_ISSN, "{x}000-0000".format(x=i)) @@ -256,7 +256,7 @@ def test_03_applications(self): for i in range(5): a = models.Suggestion() a.set_owner("stranger") - a.set_created(dates.format(dates.after(now, i + 5))) + a.set_created(dates.format(dates.seconds_after(now, i + 5))) bj = a.bibjson() bj.title = "Test Suggestion {x}".format(x=i) bj.add_identifier(bj.P_ISSN, "{x}000-0000".format(x=i)) diff --git a/doajtest/unit/event_consumers/test_journal_discontinuing_soon_notify.py b/doajtest/unit/event_consumers/test_journal_discontinuing_soon_notify.py new file mode 100644 index 0000000000..f4f70f2f78 --- /dev/null +++ b/doajtest/unit/event_consumers/test_journal_discontinuing_soon_notify.py @@ -0,0 +1,86 @@ +from portality import models +from portality import constants +from portality.bll import exceptions +from doajtest.helpers import DoajTestCase +from doajtest.fixtures import JournalFixtureFactory, ApplicationFixtureFactory +from portality.events.consumers.journal_discontinuing_soon_notify import JournalDiscontinuingSoonNotify +from doajtest.fixtures import BackgroundFixtureFactory +import time + +# Mock required to make application lookup work +@classmethod +def pull_application(cls, id): + app = models.Application(**ApplicationFixtureFactory.make_application_source()) + return app + +@classmethod +def pull_by_key(cls, key, value): + ed = models.EditorGroup() + acc = models.Account() + acc.set_id('testuser') + acc.set_email("test@example.com") + acc.save(blocking=True) + ed.set_maned(acc.id) + ed.save(blocking=True) + + return ed + +class TestJournalDiscontinuingSoonNotify(DoajTestCase): + def setUp(self): + super(TestJournalDiscontinuingSoonNotify, self).setUp() + self.pull_application = models.Application.pull + models.Application.pull = pull_application + self.pull_by_key = models.EditorGroup.pull_by_key + models.EditorGroup.pull_by_key = pull_by_key + + def tearDown(self): + super(TestJournalDiscontinuingSoonNotify, self).tearDown() + models.Application.pull = self.pull_application + models.EditorGroup.pull_by_key = self.pull_by_key + + def test_consumes(self): + + event = models.Event("test:event", context={"data" : {"1234"}}) + assert not JournalDiscontinuingSoonNotify.consumes(event) + + event = models.Event("test:event", context={"data": {}}) + assert not JournalDiscontinuingSoonNotify.consumes(event) + + event = models.Event(constants.EVENT_JOURNAL_DISCONTINUING_SOON) + assert not JournalDiscontinuingSoonNotify.consumes(event) + + event = models.Event(constants.EVENT_JOURNAL_DISCONTINUING_SOON, context = {"journal": {"1234"}, "discontinue_date": "2002-22-02"}) + assert JournalDiscontinuingSoonNotify.consumes(event) + + def test_consume_success(self): + self._make_and_push_test_context("/") + + source = BackgroundFixtureFactory.example() + bj = models.BackgroundJob(**source) + # bj.save(blocking=True) + + acc = models.Account() + acc.set_id('testuser') + acc.set_email("test@example.com") + acc.add_role('admin') + acc.save(blocking=True) + + source = JournalFixtureFactory.make_journal_source() + journal = models.Journal(**source) + journal.save(blocking=True) + + event = models.Event(constants.BACKGROUND_JOB_FINISHED, context={"job" : bj.data, "journal" : journal.id}) + JournalDiscontinuingSoonNotify.consume(event) + + time.sleep(2) + ns = models.Notification.all() + assert len(ns) == 1 + + n = ns[0] + assert n.who == acc.id + assert n.created_by == JournalDiscontinuingSoonNotify.ID + assert n.classification == constants.NOTIFICATION_CLASSIFICATION_STATUS + assert n.long is not None + assert n.short is not None + assert n.action is not None + assert not n.is_seen() diff --git a/doajtest/unit/test_task_discontinued_soon.py b/doajtest/unit/test_task_discontinued_soon.py new file mode 100644 index 0000000000..3c9e4bcd1d --- /dev/null +++ b/doajtest/unit/test_task_discontinued_soon.py @@ -0,0 +1,77 @@ +import unittest +import datetime + +from doajtest.helpers import DoajTestCase + +from portality.core import app +from portality import models +from portality.tasks import find_discontinued_soon +from portality.ui.messages import Messages +from doajtest.fixtures import JournalFixtureFactory + +DELTA = app.config.get('DISCONTINUED_DATE_DELTA',1) + +class TestDiscontinuedSoon(DoajTestCase): + + def _date_to_found(self): + return (datetime.datetime.today() + datetime.timedelta(days=DELTA)).strftime('%Y-%m-%d') + + def _date_too_late(self): + return (datetime.datetime.today() + datetime.timedelta(days=DELTA+1)).strftime('%Y-%m-%d') + + def test_discontinued_soon_found(self): + + # Both these should be found + journal_discontinued_to_found_1 = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True)) + journal_discontinued_to_found_1.set_id("1") + jbib = journal_discontinued_to_found_1.bibjson() + jbib.title = "Discontinued Tomorrow 1" + jbib.discontinued_date = self._date_to_found() + journal_discontinued_to_found_1.save(blocking=True) + + journal_discontinued_to_found_2 = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True)) + journal_discontinued_to_found_2.set_id("2") + jbib = journal_discontinued_to_found_2.bibjson() + jbib.title = "Discontinued Tomorrow 2" + jbib.discontinued_date = self._date_to_found() + journal_discontinued_to_found_2.save(blocking=True) + + # that shouldn't be found + journal_discontinued_too_late = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True)) + journal_discontinued_too_late.set_id("3") + jbib = journal_discontinued_too_late.bibjson() + jbib.title = "Discontinued In 2 days" + jbib.discontinued_date = self._date_too_late() + journal_discontinued_too_late.save(blocking=True) + + job = find_discontinued_soon.FindDiscontinuedSoonBackgroundTask.prepare("system") + task = find_discontinued_soon.FindDiscontinuedSoonBackgroundTask(job) + task.run() + + assert len(job.audit) == 2 + assert job.audit[0]["message"] == Messages.DISCONTINUED_JOURNAL_FOUND_LOG.format(id="1") + assert job.audit[1]["message"] == Messages.DISCONTINUED_JOURNAL_FOUND_LOG.format(id="2") + + def test_discontinued_soon_not_found(self): + + # None of these should be found - this one discontinues in 2 days + journal_discontinued_too_late = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True)) + journal_discontinued_too_late.set_id("1") + jbib = journal_discontinued_too_late.bibjson() + jbib.title = "Discontinued In 2 days" + jbib.discontinued_date = self._date_too_late() + journal_discontinued_too_late.save(blocking=True) + + # this one is not in doaj + journal_not_in_doaj = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=False)) + journal_not_in_doaj.set_id("2") + jbib = journal_not_in_doaj.bibjson() + jbib.discontinued_date = self._date_to_found() + journal_not_in_doaj.save(blocking=True) + + job = find_discontinued_soon.FindDiscontinuedSoonBackgroundTask.prepare("system") + task = find_discontinued_soon.FindDiscontinuedSoonBackgroundTask(job) + task.run() + + assert len(job.audit) == 1 + assert job.audit[0]["message"] == Messages.NO_DISCONTINUED_JOURNALS_FOUND_LOG diff --git a/portality/app.py b/portality/app.py index 4d1bf787c8..9f6b4d2466 100644 --- a/portality/app.py +++ b/portality/app.py @@ -285,6 +285,10 @@ def form_diff_table_subject_expand(val): return ", ".join(results) +@app.template_filter("is_in_the_past") +def is_in_the_past(dttm): + return dates.is_before(dttm, dates.today()) + ####################################################### diff --git a/portality/bll/services/events.py b/portality/bll/services/events.py index 2b27b85beb..3c5e96473c 100644 --- a/portality/bll/services/events.py +++ b/portality/bll/services/events.py @@ -21,6 +21,7 @@ from portality.events.consumers.journal_editor_group_assigned_notify import JournalEditorGroupAssignedNotify from portality.events.consumers.application_publisher_inprogress_notify import ApplicationPublisherInprogressNotify from portality.events.consumers.update_request_publisher_rejected_notify import UpdateRequestPublisherRejectedNotify +from portality.events.consumers.journal_discontinuing_soon_notify import JournalDiscontinuingSoonNotify class EventsService(object): @@ -44,7 +45,8 @@ class EventsService(object): JournalEditorGroupAssignedNotify, UpdateRequestPublisherAcceptedNotify, UpdateRequestPublisherAssignedNotify, - UpdateRequestPublisherRejectedNotify + UpdateRequestPublisherRejectedNotify, + JournalDiscontinuingSoonNotify ] def __init__(self): diff --git a/portality/constants.py b/portality/constants.py index ec908a4e82..ce7ed5e406 100644 --- a/portality/constants.py +++ b/portality/constants.py @@ -53,7 +53,9 @@ EVENT_APPLICATION_EDITOR_GROUP_ASSIGNED = "application:editor_group:assigned" EVENT_JOURNAL_ASSED_ASSIGNED = "journal:assed:assigned" EVENT_JOURNAL_EDITOR_GROUP_ASSIGNED = "journal:editor_group:assigned" +EVENT_JOURNAL_DISCONTINUING_SOON = "journal:discontinuing_soon" +NOTIFICATION_CLASSIFICATION_STATUS = "alert" NOTIFICATION_CLASSIFICATION_STATUS_CHANGE = "status_change" NOTIFICATION_CLASSIFICATION_ASSIGN = "assign" NOTIFICATION_CLASSIFICATION_CREATE = "create" diff --git a/portality/events/consumers/journal_discontinuing_soon_notify.py b/portality/events/consumers/journal_discontinuing_soon_notify.py new file mode 100644 index 0000000000..11da31bb96 --- /dev/null +++ b/portality/events/consumers/journal_discontinuing_soon_notify.py @@ -0,0 +1,55 @@ +# ~~JournalDiscontinuingSoonNotify:Consumer~~ +import json +import urllib.parse + +from portality.util import url_for +from portality.events.consumer import EventConsumer +from portality.core import app +from portality import constants +from portality import models +from portality.bll import DOAJ, exceptions +from portality.lib import edges +from portality import dao + +class JournalDiscontinuingSoonNotify(EventConsumer): + ID = "journal:assed:discontinuing_soon:notify" + + @classmethod + def consumes(cls, event): + return event.id == constants.EVENT_JOURNAL_DISCONTINUING_SOON and \ + event.context.get("journal") is not None and \ + event.context.get("discontinue_date") is not None + + @classmethod + def consume(cls, event): + journal_id = event.context.get("journal") + discontinued_date = event.context.get("discontinue_date") + + journal = models.Journal.pull(journal_id) + if journal is None: + return + + if not journal.editor_group: + return + + eg = models.EditorGroup.pull_by_key("name", journal.editor_group) + managing_editor = eg.maned + if not managing_editor: + return + + # ~~-> Notifications:Service ~~ + svc = DOAJ.notificationsService() + + notification = models.Notification() + notification.who = managing_editor + notification.created_by = cls.ID + notification.classification = constants.NOTIFICATION_CLASSIFICATION_STATUS + notification.long = svc.long_notification(cls.ID).format( + days=app.config.get('DISCONTINUED_DATE_DELTA',0), + title=journal.bibjson().title, + id=journal.id + ) + notification.short = svc.short_notification(cls.ID) + notification.action = url_for("admin.journal_page", journal_id=journal.id) + + svc.notify(notification) diff --git a/portality/lib/dates.py b/portality/lib/dates.py index a1af162b0b..52f6b0a809 100644 --- a/portality/lib/dates.py +++ b/portality/lib/dates.py @@ -119,15 +119,27 @@ def before_now(seconds: int) -> datetime: return before(now(), seconds) -def after(timestamp, seconds) -> datetime: +def seconds_after(timestamp, seconds) -> datetime: return timestamp + timedelta(seconds=seconds) +def seconds_after_now(seconds: int): + return seconds_after(datetime.utcnow(), seconds) + + +def days_after(timestamp, days): + return timestamp + timedelta(days=days) + + +def days_after_now(days: int): + return days_after(datetime.utcnow(), days) + + def eta(since, sofar, total) -> str: td = (now() - since).total_seconds() spr = float(td) / float(sofar) alltime = int(math.ceil(total * spr)) - fin = after(since, alltime) + fin = seconds_after(since, alltime) return format(fin) @@ -163,3 +175,13 @@ def day_ranges(fro: datetime, to: datetime) -> 'list[str]': def human_date(stamp, string_format=FMT_DATE_HUMAN) -> str: return reformat(stamp, out_format=string_format) + +def is_before(mydate, comparison=None): + if comparison is None: + comparison = datetime.utcnow() + if isinstance(mydate, str): + mydate = parse(mydate) + if isinstance(comparison, str): + comparison = parse(comparison) + return mydate < comparison + diff --git a/portality/migrate/20180106_1463_ongoing_updates/sync_journals_applications.py b/portality/migrate/20180106_1463_ongoing_updates/sync_journals_applications.py index adb85410aa..4315618d51 100644 --- a/portality/migrate/20180106_1463_ongoing_updates/sync_journals_applications.py +++ b/portality/migrate/20180106_1463_ongoing_updates/sync_journals_applications.py @@ -52,7 +52,7 @@ app_created = application.created_timestamp for journal in related_journals: almu = application.last_manual_update_timestamp - almu_adjusted = dates.after(almu, 3600) + almu_adjusted = dates.seconds_after(almu, 3600) # do a load of reporting prep jc_ac_diff = int((journal.created_timestamp - app_created).total_seconds()) diff --git a/portality/models/v2/journal.py b/portality/models/v2/journal.py index 41c50a7ce9..ac1ce42585 100644 --- a/portality/models/v2/journal.py +++ b/portality/models/v2/journal.py @@ -1131,4 +1131,4 @@ def query(self): "sort" : [ {"created_date" : {"order" : "desc"}} ] - } \ No newline at end of file + } diff --git a/portality/settings.py b/portality/settings.py index 152e3ec2d4..168f20498a 100644 --- a/portality/settings.py +++ b/portality/settings.py @@ -9,7 +9,7 @@ # Application Version information # ~~->API:Feature~~ -DOAJ_VERSION = "6.3.10" +DOAJ_VERSION = "6.3.11" API_VERSION = "3.0.1" ###################################### @@ -439,6 +439,7 @@ "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"}, "monitor_bgjobs": {"month": "*", "day": "*/6", "day_of_week": "*", "hour": "10", "minute": "0"}, + "find_discontinued_soon": {"month": "*", "day": "*", "day_of_week": "*", "hour": "0", "minute": "3"} } HUEY_TASKS = { @@ -1385,3 +1386,6 @@ # Pages under maintenance PRESERVATION_PAGE_UNDER_MAINTENANCE = False + +# report journals that discontinue in ... days (eg. 1 = tomorrow) +DISCONTINUED_DATE_DELTA = 0 \ No newline at end of file diff --git a/portality/static/js/edges/notifications.edge.js b/portality/static/js/edges/notifications.edge.js index 65788540ad..4b8c00e083 100644 --- a/portality/static/js/edges/notifications.edge.js +++ b/portality/static/js/edges/notifications.edge.js @@ -10,6 +10,10 @@ $.extend(true, doaj, { seen_url: "/dashboard/notifications/{notification_id}/seen", icons: { + alert: ` + + + `, finished: ` @@ -34,6 +38,7 @@ $.extend(true, doaj, { }, classifications: { + alert: "Requires attention", finished: "Task has completed", status_change: "Application status change", assign: "Assigned to user" diff --git a/portality/tasks/article_duplicate_report.py b/portality/tasks/article_duplicate_report.py index b92616d837..04419674e6 100644 --- a/portality/tasks/article_duplicate_report.py +++ b/portality/tasks/article_duplicate_report.py @@ -72,7 +72,7 @@ def run(self): n = dates.now() diff = (n - start).total_seconds() expected_total = ((diff / a_count) * total) - estimated_finish = dates.format(dates.after(start, expected_total)) + estimated_finish = dates.format(dates.seconds_after(start, expected_total)) a_count += 1 article = models.Article(_source={'id': a[0], 'created_date': a[1], 'bibjson': {'identifier': json.loads(a[2]), 'link': json.loads(a[3]), 'title': a[4]}, 'admin': {'in_doaj': json.loads(a[5])}}) diff --git a/portality/tasks/consumer_long_running.py b/portality/tasks/consumer_long_running.py index bf0aa61b61..ff8763e148 100644 --- a/portality/tasks/consumer_long_running.py +++ b/portality/tasks/consumer_long_running.py @@ -16,4 +16,4 @@ from portality.tasks.harvester import scheduled_harvest # noqa from portality.tasks.anon_export import scheduled_anon_export, anon_export # noqa from portality.tasks.old_data_cleanup import scheduled_old_data_cleanup, execute_old_data_cleanup # noqa -from portality.tasks.monitor_bgjobs import scheduled_monitor_bgjobs, execute_monitor_bgjobs +from portality.tasks.monitor_bgjobs import scheduled_monitor_bgjobs, execute_monitor_bgjobs # noqa diff --git a/portality/tasks/consumer_main_queue.py b/portality/tasks/consumer_main_queue.py index 2eda75d8da..ea3774d560 100644 --- a/portality/tasks/consumer_main_queue.py +++ b/portality/tasks/consumer_main_queue.py @@ -26,3 +26,4 @@ from portality.tasks.async_workflow_notifications import async_workflow_notifications # noqa from portality.tasks.check_latest_es_backup import scheduled_check_latest_es_backup, check_latest_es_backup # noqa from portality.tasks.request_es_backup import scheduled_request_es_backup, request_es_backup # noqa +from portality.tasks.find_discontinued_soon import scheduled_find_discontinued_soon, find_discontinued_soon # noqa diff --git a/portality/tasks/find_discontinued_soon.py b/portality/tasks/find_discontinued_soon.py new file mode 100644 index 0000000000..379618dc0a --- /dev/null +++ b/portality/tasks/find_discontinued_soon.py @@ -0,0 +1,119 @@ +from portality.core import app +from portality.bll import DOAJ +from portality.lib import dates +from portality import models + +from portality.tasks.redis_huey import main_queue + +from portality.background import BackgroundTask, BackgroundApi +from portality.tasks.helpers import background_helper +from portality.ui.messages import Messages +from portality import constants + + +class DiscontinuedSoonQuery: + def __init__(self): + self._delta = app.config.get('DISCONTINUED_DATE_DELTA', 0) + self._date = dates.days_after_now(days=self._delta) + + def query(self): + return { + "query": { + "bool": { + "filter": { + "bool": { + "must": [ + {"term": {"bibjson.discontinued_date": dates.format(self._date, format="%Y-%m-%d")}}, + {"term": {"admin.in_doaj": True}} + ] + } + } + } + } + } + + +# ~~FindDiscontinuedSoonBackgroundTask:Task~~ +class FindDiscontinuedSoonBackgroundTask(BackgroundTask): + __action__ = "find_discontinued_soon" + + def __init__(self, job): + super(FindDiscontinuedSoonBackgroundTask, self).__init__(job) + self._delta = app.config.get('DISCONTINUED_DATE_DELTA', 0) + self._date = dates.days_after_now(days=self._delta) + + def find_journals_discontinuing_soon(self): + jdata = [] + + for journal in models.Journal.iterate(q=DiscontinuedSoonQuery().query(), keepalive='5m', wrap=True): + # ~~->Journal:Model~~ + jdata.append(journal.id) + self.background_job.add_audit_message(Messages.DISCONTINUED_JOURNAL_FOUND_LOG.format(id=journal.id)) + + return jdata + + def run(self): + journals = self.find_journals_discontinuing_soon() + if len(journals): + for j in journals: + DOAJ.eventsService().trigger(models.Event( + constants.EVENT_JOURNAL_DISCONTINUING_SOON, + self.background_job.user, + { + "journal": j, + "discontinue_date": self._date + })) + self.background_job.add_audit_message(Messages.DISCONTINUED_JOURNALS_FOUND_NOTIFICATION_SENT_LOG) + else: + self.background_job.add_audit_message(Messages.NO_DISCONTINUED_JOURNALS_FOUND_LOG) + + def cleanup(self): + """ + Cleanup after a successful OR failed run of the task + :return: + """ + pass + + @classmethod + def prepare(cls, username, **kwargs): + """ + Take an arbitrary set of keyword arguments and return an instance of a BackgroundJob, + or fail with a suitable exception + + :param username: User account for this task to complete as + :param kwargs: arbitrary keyword arguments pertaining to this task type + :return: a BackgroundJob instance representing this task + """ + + # first prepare a job record + job = background_helper.create_job(username, cls.__action__, + queue_id=huey_helper.queue_id, ) + return job + + @classmethod + def submit(cls, background_job): + """ + Submit the specified BackgroundJob to the background queue + + :param background_job: the BackgroundJob instance + :return: + """ + background_job.save() + find_discontinued_soon.schedule(args=(background_job.id,), delay=10) + + +huey_helper = FindDiscontinuedSoonBackgroundTask.create_huey_helper(main_queue) + + +@huey_helper.register_schedule +def scheduled_find_discontinued_soon(): + user = app.config.get("SYSTEM_USERNAME") + job = FindDiscontinuedSoonBackgroundTask.prepare(user) + FindDiscontinuedSoonBackgroundTask.submit(job) + + +@huey_helper.register_execute(is_load_config=False) +def find_discontinued_soon(job_id): + job = models.BackgroundJob.pull(job_id) + task = FindDiscontinuedSoonBackgroundTask(job) + BackgroundApi.execute(task) diff --git a/portality/templates/doaj/toc.html b/portality/templates/doaj/toc.html index acf0077a7e..276d9392be 100644 --- a/portality/templates/doaj/toc.html +++ b/portality/templates/doaj/toc.html @@ -75,7 +75,7 @@

- {% if bibjson.discontinued_date %} + {% if bibjson.discontinued_date is not none and bibjson.discontinued_date | is_in_the_past %}

Ceased publication on {{ bibjson.discontinued_datestamp.strftime("%d %B %Y") }}

{% endif %} diff --git a/portality/templates/email/discontinue_soon.jinja2 b/portality/templates/email/discontinue_soon.jinja2 new file mode 100644 index 0000000000..25debb60a8 --- /dev/null +++ b/portality/templates/email/discontinue_soon.jinja2 @@ -0,0 +1,7 @@ +{# +~~FindDiscontinuedSoonBackgroundTask:Email~~ +#} + +Following journals will discontinue in {{ days }} days. + +{{ data }} \ No newline at end of file diff --git a/portality/ui/messages.py b/portality/ui/messages.py index 094751c97c..ac7f9163bc 100644 --- a/portality/ui/messages.py +++ b/portality/ui/messages.py @@ -110,6 +110,12 @@ class Messages(object): NOTIFY__DEFAULT_SHORT_NOTIFICATION = "You have a new notification" + DISCONTINUED_JOURNAL_FOUND_LOG = "Journal discontinuing soon found: {id}" + DISCONTINUED_JOURNALS_FOUND_NOTIFICATION_SENT_LOG = "Notification with journals discontinuing soon sent." + DISCONTINUED_JOURNALS_FOUND_NOTIFICATION_ERROR_LOG = "Error sending notification with journals discontinuing soon." + NO_DISCONTINUED_JOURNALS_FOUND_LOG = "No journals discontinuing soon found" + + @classmethod def flash(cls, tup): if isinstance(tup, tuple): diff --git a/setup.py b/setup.py index 571b37f957..04a9736d53 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name='doaj', - version='6.3.10', + version='6.3.11', packages=find_packages(), install_requires=[ "awscli==1.20.50", diff --git a/test.cfg b/test.cfg index 01f2c9c5bf..ff4bd661e8 100644 --- a/test.cfg +++ b/test.cfg @@ -55,7 +55,8 @@ HUEY_SCHEDULE = { "harvest": {"month": "*", "day": "*", "day_of_week": "*", "hour": "5", "minute": "30"}, "anon_export": CRON_NEVER, "old_data_cleanup": {"month": "*", "day": "*", "day_of_week": "3", "hour": "12", "minute": "0"}, - "monitor_bgjobs": {"month": "*", "day": "*/6", "day_of_week": "*", "hour": "10", "minute": "0"} + "monitor_bgjobs": {"month": "*", "day": "*/6", "day_of_week": "*", "hour": "10", "minute": "0"}, + "find_discontinued_soon": {"month": "*", "day": "*", "day_of_week": "*", "hour": "0", "minute": "3"} } # =======================