Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow future discontinued date #2204

Closed
wants to merge 44 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
c6e136b
add custom filter to check whether the date is in the past, use it in…
amdomanska Jan 30, 2023
8e200be
add background job
amdomanska Jan 31, 2023
d5e1608
copy-paste mistakes fixed
amdomanska Jan 31, 2023
8c173c3
change delay to seconds
amdomanska Jan 31, 2023
7edc4c2
wrong file edited!
amdomanska Jan 31, 2023
c88549b
add UT and fix code
amdomanska Feb 1, 2023
1c7e0e1
refactoring
amdomanska Feb 1, 2023
1c27047
Merge branch 'develop' into feature/1529_future_discontinued_date
amdomanska Feb 1, 2023
6357e7f
add FeatureMap annotations
amdomanska Feb 1, 2023
91ad6eb
add functional test
amdomanska Feb 1, 2023
a037fd5
implement notification
amdomanska Feb 7, 2023
b2557c1
implement notification
amdomanska Feb 7, 2023
255bce2
add notif action and remove test code
amdomanska Feb 7, 2023
e8edabb
change notification classification
amdomanska Feb 8, 2023
f23b55b
revert accidental deletion
amdomanska Feb 8, 2023
8cbc146
new even notif unit tests
amdomanska Feb 8, 2023
f72e721
make sure only journals in doaj are found and fix unit tests
amdomanska Feb 8, 2023
b394331
add link to notification
amdomanska Feb 8, 2023
555e1a6
send separate notifications to appropriate managing editors
amdomanska Feb 15, 2023
b9e984f
check for current application
amdomanska Feb 15, 2023
ae807e8
remove unnecessary setting
amdomanska Feb 15, 2023
24214f7
fix imports and tests
amdomanska Feb 17, 2023
f54af1c
fix task test
amdomanska Feb 17, 2023
82b206a
fix the filter
amdomanska Mar 7, 2023
b5684a6
Merge branch 'develop' into feature/1529_future_discontinued_date
amdomanska Mar 13, 2023
ffd151d
remove unused method
amdomanska Mar 20, 2023
b354751
default discontinued date delta to 0
amdomanska Mar 20, 2023
ccf94f1
add functionality to dates lib
amdomanska Mar 20, 2023
d30fbd2
refactor DiscontinuedSoonQuery
amdomanska Mar 20, 2023
ef0510a
use dates lib in jinja filter
amdomanska Mar 20, 2023
a3d8694
fix errors
amdomanska Mar 20, 2023
368df56
Merge branch 'develop' into feature/1529_future_discontinued_date
amdomanska Mar 27, 2023
427ad2b
new full new notification type - alert
amdomanska Mar 27, 2023
34382bd
Merge branch 'develop' into feature/1529_future_discontinued_date
Steven-Eardley Apr 10, 2023
890f226
fix is_before usage
amdomanska Apr 14, 2023
7ae9295
Merge branch 'develop' into feature/1529_future_discontinued_date
Steven-Eardley Apr 14, 2023
bf63c0f
Merge branch 'develop' into feature/1529_future_discontinued_date
Steven-Eardley Apr 14, 2023
6139624
clean up
amdomanska Apr 17, 2023
4a73fde
Merge branch 'feature/1529_future_discontinued_date' of github.com:DO…
amdomanska Apr 17, 2023
4b37398
Merge branch 'develop' into feature/1529_future_discontinued_date
Steven-Eardley Apr 18, 2023
7341677
Update the cron schedule for discontinued task
Steven-Eardley Apr 18, 2023
edb84fe
Merge branch 'develop' into feature/1529_future_discontinued_date
Steven-Eardley May 2, 2023
ea294dc
Add missing import for new background job
Steven-Eardley May 2, 2023
7259212
Merge branch 'develop' into feature/1529_future_discontinued_date
amdomanska May 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cms/data/notifications.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Journals discontinuing soon found
15 changes: 15 additions & 0 deletions doajtest/testbook/public_site/ToC.yml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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("[email protected]")
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("[email protected]")
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()
77 changes: 77 additions & 0 deletions doajtest/unit/test_task_discontinued_soon.py
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions portality/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,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())


#######################################################

Expand Down
4 changes: 3 additions & 1 deletion portality/bll/services/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -44,7 +45,8 @@ class EventsService(object):
JournalEditorGroupAssignedNotify,
UpdateRequestPublisherAcceptedNotify,
UpdateRequestPublisherAssignedNotify,
UpdateRequestPublisherRejectedNotify
UpdateRequestPublisherRejectedNotify,
JournalDiscontinuingSoonNotify
]

def __init__(self):
Expand Down
2 changes: 2 additions & 0 deletions portality/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
63 changes: 63 additions & 0 deletions portality/events/consumers/journal_discontinuing_soon_notify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# ~~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

app_id = journal.current_application
if app_id is None:
app_id = journal.latest_related_application_id()
if app_id is None:
return

application = models.Application.pull(app_id)

if not application.editor_group:
return

eg = models.EditorGroup.pull_by_key("name", application.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)
19 changes: 19 additions & 0 deletions portality/lib/dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ def before_now(seconds: int) -> datetime:
def after(timestamp, seconds) -> datetime:
return timestamp + timedelta(seconds=seconds)

def seconds_after_now(seconds: int):
return 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()
Expand Down Expand Up @@ -136,3 +145,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

2 changes: 1 addition & 1 deletion portality/models/v2/journal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1126,4 +1126,4 @@ def query(self):
"sort" : [
{"created_date" : {"order" : "desc"}}
]
}
}
4 changes: 4 additions & 0 deletions portality/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,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 = {
Expand Down Expand Up @@ -1380,3 +1381,6 @@
# Pages under maintenance

PRESERVATION_PAGE_UNDER_MAINTENANCE = False

# report journals that discontinue in ... days (eg. 1 = tomorrow)
DISCONTINUED_DATE_DELTA = 0
richard-jones marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 5 additions & 0 deletions portality/static/js/edges/notifications.edge.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ $.extend(true, doaj, {
seen_url: "/dashboard/notifications/{notification_id}/seen",

icons: {
alert: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<path d="M224 0c-17.7 0-32 14.3-32 32V51.2C119 66 64 130.6 64 208v18.8c0 47-17.3 92.4-48.5 127.6l-7.4 8.3c-8.4 9.4-10.4 22.9-5.3 34.4S19.4 416 32 416H416c12.6 0 24-7.4 29.2-18.9s3.1-25-5.3-34.4l-7.4-8.3C401.3 319.2 384 273.9 384 226.8V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32zm45.3 493.3c12-12 18.7-28.3 18.7-45.3H224 160c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7z"/>
</svg>`,
finished: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M6 3.5a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 0-1 0v2A1.5 1.5 0 0 0 6.5 14h8a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-8A1.5 1.5 0 0 0 5 3.5v2a.5.5 0 0 0 1 0v-2z"/>
<path fill-rule="evenodd" d="M11.854 8.354a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5H1.5a.5.5 0 0 0 0 1h8.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3z"/>
Expand All @@ -34,6 +38,7 @@ $.extend(true, doaj, {
},

classifications: {
alert: "Requires attention",
finished: "Task has completed",
status_change: "Application status change",
assign: "Assigned to user"
Expand Down
2 changes: 1 addition & 1 deletion portality/tasks/consumer_long_running.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions portality/tasks/consumer_main_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading