Skip to content

Commit

Permalink
Email: add function to send email to library if anonymized user has a…
Browse files Browse the repository at this point in the history
…ctive loans
  • Loading branch information
KonstantinaStoikou authored and kpsherva committed Aug 13, 2020
1 parent b2303ec commit 54ecc4c
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def jsonresolver_loader(url_map):
"""Resolve the referred document and patron for an Order Line."""
from flask import current_app

def patron_resolver(order_line, patron_pid):
def order_line_patron_resolver(order_line, patron_pid):
"""Resolve the Patron for the given Order Line."""
patron = get_patron_or_unknown(patron_pid)

Expand Down Expand Up @@ -52,9 +52,9 @@ def order_lines_resolver(order_pid):
continue
patron = get_patron_or_unknown(patron_pid)
if not patron:
patron_resolver(order_line, None)
order_line_patron_resolver(order_line, None)
continue
patron_resolver(order_line, patron_pid)
order_line_patron_resolver(order_line, patron_pid)
return order_lines

url_map.add(
Expand Down
10 changes: 7 additions & 3 deletions invenio_app_ils/anonymization.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
get_patron_or_unknown)

from .acquisition.search import OrderSearch
from .circulation.search import get_loans_by_patron_pid
from .circulation.search import (get_active_loans_by_patron_pid,
get_loans_by_patron_pid)
from .document_requests.search import DocumentRequestSearch
from .ill.search import BorrowingRequestsSearch
from .patrons.indexer import PatronIndexer
Expand Down Expand Up @@ -104,13 +105,16 @@ def anonymize_patron_data(patron_pid, force=False):
# Serialize empty patron values
anonymous_patron_fields = get_anonymous_patron_dict(patron_pid)

patron_loans = get_loans_by_patron_pid(patron_pid).execute()
patron_loans = get_loans_by_patron_pid(patron_pid).scan()

indices = 0

for hit in patron_loans:
loan = Loan.get_record_by_pid(hit.pid)
if loan["state"] == current_app.config["CIRCULATION_STATES_LOAN_REQUEST"]:
if (
loan["state"]
== current_app.config["CIRCULATION_STATES_LOAN_REQUEST"]
):
params = deepcopy(loan)
params.update(
dict(
Expand Down
2 changes: 2 additions & 0 deletions invenio_app_ils/circulation/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
ILS_CIRCULATION_MAIL_MSG_CREATOR = (
"invenio_app_ils.circulation.mail.factory:default_loan_message_creator"
)
#: Loan list message creator class
ILS_CIRCULATION_LOANS_MAIL_MSG_CREATOR = "invenio_app_ils.circulation.mail.factory:default_loan_list_message_creator"
#: Notification email for overdue loan sent automatically every X days
ILS_CIRCULATION_MAIL_OVERDUE_REMINDER_INTERVAL = 3
#: The maximum duration of a loan request
Expand Down
16 changes: 15 additions & 1 deletion invenio_app_ils/circulation/mail/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

from flask import current_app

from invenio_app_ils.circulation.mail.messages import LoanMessage
from invenio_app_ils.circulation.mail.messages import (LoanListMessage,
LoanMessage)
from invenio_app_ils.mail.factory import message_factory


Expand All @@ -22,6 +23,19 @@ def loan_message_creator_factory():
)


def loan_list_message_creator_factory():
"""Loan list message factory creator."""
return partial(
message_factory,
current_app.config["ILS_CIRCULATION_LOANS_MAIL_MSG_CREATOR"],
)


def default_loan_message_creator(loan, action, message_ctx, **kwargs):
"""Loan message creator."""
return LoanMessage(loan, action, message_ctx, **kwargs)


def default_loan_list_message_creator(patron, loans, message_ctx, **kwargs):
"""Loan list message creator."""
return LoanListMessage(patron, loans, message_ctx, **kwargs)
46 changes: 40 additions & 6 deletions invenio_app_ils/circulation/mail/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class LoanMessage(BlockTemplatedMessage):
extend="extend.html",
cancel="cancel.html",
overdue_reminder="overdue_reminder.html",
expiring_reminder="will_expire_in_reminder.html"
expiring_reminder="will_expire_in_reminder.html",
)

def __init__(self, loan, action, message_ctx, **kwargs):
Expand All @@ -35,22 +35,20 @@ def __init__(self, loan, action, message_ctx, **kwargs):

templates = dict(
self.default_templates,
**current_app.config["ILS_CIRCULATION_MAIL_TEMPLATES"]
**current_app.config["ILS_CIRCULATION_MAIL_TEMPLATES"],
)

if not action or action not in templates:
raise KeyError(
"Invalid loan action argument `{0}` or not found in "
"templates `{1}`.".format(
action, list(templates.keys())
)
"templates `{1}`.".format(action, list(templates.keys()))
)

name = self.get_template_name(action)
super(LoanMessage, self).__init__(
template="{}/{}".format(self.templates_base_dir, templates[name]),
ctx=dict(loan=dict(loan), **message_ctx, **kwargs),
**kwargs
**kwargs,
)

def get_template_name(self, action):
Expand All @@ -73,3 +71,39 @@ def dump(self):
data = super().dump()
data["loan_pid"] = self.loan["pid"]
return data


class LoanListMessage(BlockTemplatedMessage):
"""Loan List message."""

templates_base_dir = "invenio_app_ils_circulation/mail"
default_templates = dict(
active_loans="active_loans.html",
librarian_footer="librarian_footer.html",
)

def __init__(
self,
patron,
loans,
message_ctx,
template="active_loans",
footer_template="librarian_footer",
**kwargs,
):
"""Create loan message based on the loan action."""
templates = dict(
self.default_templates,
**current_app.config["ILS_CIRCULATION_MAIL_TEMPLATES"],
)

super(LoanListMessage, self).__init__(
template="{}/{}".format(
self.templates_base_dir, templates[template]
),
footer_template="{}/{}".format(
self.templates_base_dir, templates[footer_template]
),
ctx=dict(patron=patron, loans=loans, **message_ctx, **kwargs),
**kwargs,
)
8 changes: 8 additions & 0 deletions invenio_app_ils/circulation/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,11 @@ def get_loans_by_patron_pid(patron_pid):
"term", patron_pid=patron_pid
)
return search


def get_active_loans_by_patron_pid(patron_pid):
"""Constructs the search object for all the ongoing loans of a given patron."""
search = get_loans_by_patron_pid(patron_pid).filter(
"terms", state=current_app.config["CIRCULATION_STATES_LOAN_ACTIVE"]
)
return search
36 changes: 35 additions & 1 deletion invenio_app_ils/circulation/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@
from invenio_circulation.proxies import current_circulation
from invenio_db import db

from invenio_app_ils.circulation.search import get_all_expired_loans
from invenio_app_ils.circulation.mail.factory import \
loan_list_message_creator_factory
from invenio_app_ils.circulation.search import (get_active_loans_by_patron_pid,
get_all_expired_loans)
from invenio_app_ils.mail.tasks import send_ils_email
from invenio_app_ils.patrons.api import SystemAgent
from invenio_app_ils.proxies import current_app_ils

celery_logger = get_task_logger(__name__)

Expand Down Expand Up @@ -48,3 +53,32 @@ def cancel_expired_loan_requests():
loan.commit()
db.session.commit()
current_circulation.loan_indexer().index(loan)


def send_active_loans_mail(patron_pid, message_ctx={}, **kwargs):
"""Send an email to librarian with on going loans of given patron.
:param patron_pid: the pid of the patron.
:param action: the action performed, if any.
:param message_ctx: any other parameter to be passed as ctx in the msg.
"""
creator = loan_list_message_creator_factory()

Patron = current_app_ils.patron_cls
patron = Patron.get_patron(patron_pid)

loans = [
loan.to_dict()
for loan in get_active_loans_by_patron_pid(patron_pid).scan()
]

if len(loans) > 0: # Email is only sent if there are active loans
recipient = current_app.config["MANAGEMENT_EMAIL"]
msg = creator(
patron,
loans,
message_ctx=message_ctx,
recipients=[recipient],
**kwargs,
)
send_ils_email(msg)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% block subject %}
InvenioILS: Active loans of patron "{{ patron.name }}" with pid "{{ patron.pid }}".
{% endblock %}

{% block body_plain %}
Dear librarians,

these are the active loans of patron {{ patron.name }} <{{ patron.email }}> (pid: {{ patron.pid }}):
{%- for loan in loans %}
- Pid: {{ loan.pid }}, {{ loan.item.title }}, {{ loan.start_date }}-{{ loan.end_date }}
{% endfor %}
{% endblock %}

{% block body_html %}
Dear librarians,

these are the active loans of patron <a href="{{ spa_routes.HOST }}{{ spa_routes.PATHS['patron'] }}{{ patron.pid }}">{{ patron.name }}</a> <{{ patron.email }}> (pid: {{ patron.pid }}):
<ul>
{% for loan in loans %}
<li>
<a href="{{ spa_routes.HOST }}{{ spa_routes.PATHS['loan']}}{{ loan.pid }}">Pid: {{ loan.pid }}</a>,
{{ loan.item.title }}, {{ loan.start_date }}-{{ loan.end_date }}
</li>
{% endfor %}
</ul>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% block footer_plain %}

Kind regards,
InvenioILS
{% endblock %}

{% block footer_html %}

Kind regards,
InvenioILS
{% endblock %}
30 changes: 15 additions & 15 deletions invenio_app_ils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ def _(x):
###############################################################################
#: Email address for support.
SUPPORT_EMAIL = "info@inveniosoftware.org"
#: Management email for internal notifications.
MANAGEMENT_EMAIL = "internal@inveniosoftware.org"
#: Disable email sending by default.
MAIL_SUPPRESS_SEND = True
#: Email address for email notification sender.
Expand Down Expand Up @@ -230,7 +232,9 @@ def _(x):

#: Single Page Application host and routes, useful in templates/emails
SPA_HOST = "http://localhost:3000"
SPA_PATHS = dict(profile="/profile")
SPA_PATHS = dict(
profile="/profile", loan="/backoffice/loans", patron="/backoffice/patrons",
)

###############################################################################
# OAI-PMH
Expand All @@ -252,9 +256,7 @@ def _(x):
_LOCID_CONVERTER = (
'pid(locid, record_class="invenio_app_ils.locations.api:Location")'
)
_ILOCID_CONVERTER = (
'pid(ilocid, record_class="invenio_app_ils.internal_locations.api:InternalLocation")'
)
_ILOCID_CONVERTER = 'pid(ilocid, record_class="invenio_app_ils.internal_locations.api:InternalLocation")'
_DREQID_CONVERTER = 'pid(dreqid, record_class="invenio_app_ils.document_requests.api:DocumentRequest")'
_SERID_CONVERTER = (
'pid(serid, record_class="invenio_app_ils.series.api:Series")'
Expand Down Expand Up @@ -350,9 +352,7 @@ def _(x):
record_class=EItem,
indexer_class=EItemIndexer,
record_loaders={
"application/json": (
"invenio_app_ils.eitems.loaders:eitem_loader"
)
"application/json": ("invenio_app_ils.eitems.loaders:eitem_loader")
},
record_serializers={
"application/json": (
Expand Down Expand Up @@ -693,8 +693,8 @@ def _(x):
fields=["title.keyword"],
title="Title",
default_order="asc",
order=6
)
order=6,
),
),
eitems=dict( # ItemSearch.Meta.index
mostrecent=dict(
Expand All @@ -710,8 +710,8 @@ def _(x):
fields=["document.title.keyword"],
title="Title",
default_order="asc",
order=3
)
order=3,
),
),
items=dict( # ItemSearch.Meta.index
mostrecent=dict(
Expand All @@ -727,8 +727,8 @@ def _(x):
fields=["document.title.keyword"],
title="Title",
default_order="asc",
order=3
)
order=3,
),
),
patrons=dict( # PatronsSearch.Meta.index
bestmatch=dict(
Expand All @@ -752,8 +752,8 @@ def _(x):
fields=["title.keyword"],
title="Title",
default_order="asc",
order=3
)
order=3,
),
),
)

Expand Down
2 changes: 1 addition & 1 deletion invenio_app_ils/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def init_app(self, app):
)
app.register_blueprint(
Blueprint(
"invenio_app_ils_circulation_ mail",
"invenio_app_ils_circulation_mail",
__name__,
template_folder="circulation/templates",
)
Expand Down
Loading

0 comments on commit 54ecc4c

Please sign in to comment.