Skip to content

Commit

Permalink
[MDS-6129] Project Summary emails and notification fixes (#3305)
Browse files Browse the repository at this point in the history
* adjust project summary factory to be able to set the status code, write a single test for emails, send emails and notifications according to status, fix a spelling error, start sending document update emails, and do the saving first before sending emails so that the email info is correct

* fix some typing issues

* Update services/core-api/app/api/projects/project_summary/models/project_summary.py

Co-authored-by: Jason Syrotuck <jasyrotuck@gmail.com>

* declassify project utils, remove console log and unused imports

---------

Co-authored-by: Jason Syrotuck <jasyrotuck@gmail.com>
  • Loading branch information
taraepp and Jsyro authored Nov 14, 2024
1 parent 427868a commit 5c78f1a
Show file tree
Hide file tree
Showing 14 changed files with 481 additions and 292 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from app.api.projects.project_decision_package.models.project_decision_package import ProjectDecisionPackage
from app.api.projects.information_requirements_table.models.information_requirements_table import InformationRequirementsTable

from flask_restx import Resource, reqparse, fields
from flask_restx import Resource, reqparse
from datetime import datetime
from werkzeug.exceptions import BadRequest, NotFound

Expand All @@ -22,7 +22,7 @@
from app.api.mines.response_models import ARCHIVE_MINE_DOCUMENT, MINE_DOCUMENT_MODEL, DOCUMENT_MANAGER_ZIP

from app.api.services.document_manager_service import DocumentManagerService
from app.api.projects.project.project_util import ProjectUtil
from app.api.projects.project.project_util import notify_file_updates

class MineDocumentListResource(Resource, UserMixin):
@api.doc(description='Returns list of documents associated with mines')
Expand Down Expand Up @@ -136,24 +136,26 @@ def patch(self, mine_guid):
project = None
doc = documents[0]
mine_document_guid = doc.mine_document_guid
isNotifiableDoc = False
is_notifiable_doc = False
status_code = None

if doc.major_mine_application_document_xref:
project = MajorMineApplication.find_by_mine_document_guid(mine_document_guid).project
isNotifiableDoc = True
is_notifiable_doc = True
elif doc.project_summary_document_xref:
project = ProjectSummary.find_by_mine_document_guid(mine_document_guid).project
isNotifiableDoc = True
is_notifiable_doc = True
status_code = project.project_summary.status_code
elif doc.project_decision_package_document_xref:
project = ProjectDecisionPackage.find_by_mine_document_guid(mine_document_guid).project
isNotifiableDoc = True
is_notifiable_doc = True
elif doc.information_requirements_table_document_xref:
project = InformationRequirementsTable.find_by_mine_document_guid(mine_document_guid).project
isNotifiableDoc = True
is_notifiable_doc = True

# If one of the *xref value is not None that means the notification should be sent.
if isNotifiableDoc:
ProjectUtil.notifiy_file_updates(project, mine)
if is_notifiable_doc:
notify_file_updates(project, mine, status_code)

return None, 204

Expand Down
3 changes: 2 additions & 1 deletion services/core-api/app/api/parties/party/models/party.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import datetime
from flask import current_app
import re
from typing import Self

from sqlalchemy import func, case, and_
from sqlalchemy.schema import FetchedValue
Expand Down Expand Up @@ -196,7 +197,7 @@ def name(cls):
else_=cls.party_name)

@classmethod
def find_by_party_guid(cls, party_guid):
def find_by_party_guid(cls, party_guid) -> Self:
return cls.query.filter_by(party_guid=party_guid, deleted_ind=False).one_or_none()

@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from app.api.utils.models_mixins import SoftDeleteMixin, AuditMixin, Base

from app.api.mines.mine.models.mine import Mine
from app.api.projects.project.project_util import ProjectUtil
from app.api.projects.project.project_util import notify_file_updates

class InformationRequirementsTable(SoftDeleteMixin, AuditMixin, Base):
__tablename__ = "information_requirements_table"
Expand Down Expand Up @@ -159,7 +159,7 @@ def update(self, irt_data, import_file=None, document_guid=None, add_to_session=

if mine_doc and project:
mine = Mine.find_by_mine_guid(mine_doc.mine_guid)
ProjectUtil.notifiy_file_updates(project, mine)
notify_file_updates(project, mine, self.status_code)

return self

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from multiprocessing.sharedctypes import Value
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.dialects.postgresql import UUID

from sqlalchemy.schema import FetchedValue
from werkzeug.exceptions import BadRequest, NotFound
from werkzeug.exceptions import NotFound

from app.api.mines.documents.models.mine_document_bundle import MineDocumentBundle
from app.extensions import db
Expand All @@ -14,7 +13,7 @@
from app.api.projects.major_mine_application.models.major_mine_application_document_xref import MajorMineApplicationDocumentXref
from app.api.mines.documents.models.mine_document import MineDocument
from app.api.mines.mine.models.mine import Mine
from app.api.projects.project.project_util import ProjectUtil
from app.api.projects.project.project_util import notify_file_updates

class MajorMineApplication(SoftDeleteMixin, AuditMixin, Base):
__tablename__ = 'major_mine_application'
Expand Down Expand Up @@ -187,7 +186,7 @@ def update(self,
if not mine:
raise NotFound('Mine not found.')

ProjectUtil.notifiy_file_updates(project, mine)
notify_file_updates(project, mine, status_code)

return self

Expand Down
14 changes: 7 additions & 7 deletions services/core-api/app/api/projects/project/project_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
from app.api.utils.feature_flag import is_feature_enabled, Feature
from app.api.activity.utils import trigger_notification
from app.api.activity.models.activity_notification import ActivityType
from flask import current_app

class ProjectUtil:

def notifiy_file_updates(project, mine):
if is_feature_enabled(Feature.MINE_APPLICATION_FILE_UDPATE_ALERTS):
renotifiy_hours = 24
message = f'File(s) in project {project.project_title} has been updated for mine {mine.mine_name}'
trigger_notification(message, ActivityType.mine_project_documents_updated, mine, 'DocumentManagement', project.project_guid, None, None, ActivityRecipients.core_users, True, renotifiy_hours*60)
def notify_file_updates(project, mine, status_code = None) -> None:
status_codes = ["SUB", "ASG", "CHR"]

if is_feature_enabled(Feature.MINE_APPLICATION_FILE_UDPATE_ALERTS) and status_code in status_codes:
renotifiy_hours = 24
message = f'File(s) in project {project.project_title} has been updated for mine {mine.mine_name}'
trigger_notification(message, ActivityType.mine_project_documents_updated, mine, 'DocumentManagement', project.project_guid, None, None, ActivityRecipients.core_users, True, renotifiy_hours*60)
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
from app.extensions import db

from app.api.utils.models_mixins import SoftDeleteMixin, AuditMixin, Base
from app.api.projects.project.models.project import Project
from app.api.projects.project_decision_package.models.project_decision_package_document_xref import ProjectDecisionPackageDocumentXref
from app.api.mines.documents.models.mine_document import MineDocument

from app.api.mines.mine.models.mine import Mine
from app.api.projects.project.project_util import ProjectUtil
from app.api.projects.project.project_util import notify_file_updates

class ProjectDecisionPackage(SoftDeleteMixin, AuditMixin, Base):
__tablename__ = 'project_decision_package'
Expand Down Expand Up @@ -146,7 +145,7 @@ def update(self,
mine_document_guid = documents[0].mine_document_guid
project = ProjectDecisionPackage.find_by_mine_document_guid(mine_document_guid).project
mine = Mine.find_by_mine_guid(project.mine_guid)
ProjectUtil.notifiy_file_updates(project, mine)
notify_file_updates(project, mine, status_code)

return self

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from sqlalchemy.schema import FetchedValue
from sqlalchemy import case
from werkzeug.exceptions import BadRequest

from app.api.mines.documents.models.mine_document_bundle import MineDocumentBundle
from app.api.parties.party import PartyOrgBookEntity
Expand All @@ -13,20 +12,16 @@
from app.extensions import db

from app.api.utils.models_mixins import SoftDeleteMixin, AuditMixin, Base
from app.api.utils.access_decorators import is_minespace_user
from app.api.projects.project_summary.models.project_summary_document_xref import ProjectSummaryDocumentXref
from app.api.mines.mine.models.mine import Mine
from app.api.mines.documents.models.mine_document import MineDocument
from app.api.projects.project.models.project import Project
from app.api.projects.project_contact.models.project_contact import ProjectContact
from app.api.projects.project_summary.models.project_summary_contact import ProjectSummaryContact
from app.api.projects.project_summary.models.project_summary_authorization import ProjectSummaryAuthorization
from app.api.projects.project_summary.models.project_summary_authorization_document_xref import \
ProjectSummaryAuthorizationDocumentXref
from app.api.projects.project_summary.models.project_summary_permit_type import ProjectSummaryPermitType
from app.api.parties.party.models.party import Party
from app.api.parties.party.models.address import Address
from app.api.constants import PROJECT_SUMMARY_EMAILS, MDS_EMAIL
from app.api.constants import PROJECT_SUMMARY_EMAILS, MDS_EMAIL, PERM_RECL_EMAIL
from app.api.services.email_service import EmailService
from app.config import Config
from cerberus import Validator
Expand Down Expand Up @@ -166,6 +161,11 @@ def project_summary_lead_party_guid(self):
if self.project.project_lead_party_guid:
return self.project.project_lead_party_guid
return None

@hybrid_property
def project_lead_email(self) -> str | None:
project_lead = Party.find_by_party_guid(self.project_summary_lead_party_guid)
return project_lead.email if project_lead else None

@hybrid_property
def mine_guid(self):
Expand Down Expand Up @@ -226,6 +226,29 @@ def find_by_mine_document_guid(cls, mine_document_guid):

except ValueError:
return None

@staticmethod
def has_new_documents(documents, ams_authorizations) -> bool:
new_documents = list(filter(lambda doc: doc.get("mine_document_guid") is None, documents))
has_new_docs = len(new_documents) > 0

amendments = ams_authorizations.get('amendments', [])
new = ams_authorizations.get('new', [])
all_ams_auths = amendments + new
has_new_ams_docs = False

for auth in all_ams_auths:
docs = auth.get('amendment_documents', [])
for doc in docs:
if doc.get('mine_document_guid') is None:
has_new_ams_docs = True
break
else:
continue
break

return has_new_docs or has_new_ams_docs


# will update the existing party and address data if it exists, else create a new one
@classmethod
Expand Down Expand Up @@ -1253,8 +1276,52 @@ def delete(self, commit=True):
doc.mine_document.delete(False)
return super(ProjectSummary, self).delete(commit)

def send_project_summary_email(self, mine):
emli_recipients = PROJECT_SUMMARY_EMAILS
def send_project_summary_document_email(self, mine) -> None:
if is_feature_enabled(Feature.MINE_APPLICATION_FILE_UDPATE_ALERTS):
message = f'File(s) in project {self.project.project_title} has been updated for mine {mine.mine_name}'
project_lead_email = self.project_lead_email

emails = {
'SUB': [PERM_RECL_EMAIL],
'ASG': [PERM_RECL_EMAIL, project_lead_email],
'CHR': [PERM_RECL_EMAIL, project_lead_email]
}
email_recipients = emails.get(self.status_code)

if email_recipients is not None:
emli_body = open("app/templates/email/projects/emli_project_summary_email.html", "r").read()
subject = f'Project Description Documents Notification for {mine.mine_name}'
cc = [MDS_EMAIL]

emli_context = {
"project_summary": {
"project_summary_description": self.project_summary_description,
},
"mine": {
"mine_name": mine.mine_name,
"mine_no": mine.mine_no,
},
"message": message,
"core_project_summary_link": f'{Config.CORE_WEB_URL}/pre-applications/{self.project.project_guid}/overview'
}
EmailService.send_template_email(subject, email_recipients, emli_body, emli_context, cc=cc)


def send_project_summary_email(self, mine, message) -> None:

project_lead_email = self.project_lead_email

emli_emails = {
'SUB': [PERM_RECL_EMAIL] + PROJECT_SUMMARY_EMAILS,
'ASG': [project_lead_email],
'OHD': [PERM_RECL_EMAIL, project_lead_email],
'WDN': [PERM_RECL_EMAIL, project_lead_email],
'COM': [PERM_RECL_EMAIL, project_lead_email]
}

send_ms_email = self.status_code != "DFT"

emli_recipients = emli_emails.get(self.status_code)
cc = [MDS_EMAIL]
minespace_recipients = [contact.email for contact in self.contacts if contact.is_primary]

Expand All @@ -1270,6 +1337,7 @@ def send_project_summary_email(self, mine):
"mine_name": mine.mine_name,
"mine_no": mine.mine_no,
},
"message": message,
"core_project_summary_link": f'{Config.CORE_WEB_URL}/pre-applications/{self.project.project_guid}/overview'
}

Expand All @@ -1278,9 +1346,11 @@ def send_project_summary_email(self, mine):
"mine_name": mine.mine_name,
"mine_no": mine.mine_no,
},
"message": message,
"minespace_project_summary_link": f'{Config.MINESPACE_PROD_URL}/projects/{self.project.project_guid}/overview',
"ema_auth_link": f'{Config.EMA_AUTH_LINK}',
}

EmailService.send_template_email(subject, emli_recipients, emli_body, emli_context, cc=cc)
EmailService.send_template_email(subject, minespace_recipients, minespace_body, minespace_context, cc=cc)
if send_ms_email:
EmailService.send_template_email(subject, minespace_recipients, minespace_body, minespace_context, cc=cc)
Loading

0 comments on commit 5c78f1a

Please sign in to comment.