This commit is contained in:
George Drummond
2019-02-28 10:00:18 -05:00
parent 1998bf6600
commit d57b96cf05
10 changed files with 398 additions and 123 deletions

View File

@@ -108,6 +108,11 @@ class Invitations(object):
invite = Invitations._get(token)
return Invitations._update_status(invite, InvitationStatus.REVOKED)
@classmethod
def lookup_by_portfolio_and_user(cls, portfolio, user):
portfolio_role = PortfolioRoles.get(portfolio.id, user.id)
return portfolio_role.latest_invitation
@classmethod
def resend(cls, user, portfolio_id, token):
portfolio = Portfolios.get(user, portfolio_id)

View File

@@ -14,6 +14,10 @@ class TaskOrderError(Exception):
pass
class InvalidOfficerError(Exception):
pass
class TaskOrders(object):
SECTIONS = {
"app_info": [
@@ -145,6 +149,15 @@ class TaskOrders(object):
"security_officer",
]
@classmethod
def remove_officer(cls, task_order, officer_type):
if officer_type in TaskOrders.OFFICERS:
setattr(task_order, officer_type, None)
db.session.add(task_order)
db.session.commit()
else:
raise (InvalidOfficerError)
@classmethod
def add_officer(cls, user, task_order, officer_type, officer_data):
Authorization.check_portfolio_permission(

View File

@@ -4,15 +4,22 @@ from flask import g, redirect, render_template, url_for, request as http_request
from . import portfolios_bp
from atst.database import db
from atst.domain.task_orders import TaskOrders, DD254s
from atst.domain.exceptions import NotFoundError, NoAccessError
from atst.domain.portfolios import Portfolios
from atst.domain.authz import Authorization
from atst.domain.exceptions import NotFoundError, NoAccessError
from atst.domain.invitations import Invitations
from atst.domain.portfolios import Portfolios
from atst.domain.task_orders import TaskOrders, DD254s
from atst.utils.localization import translate
from atst.forms.dd_254 import DD254Form
from atst.forms.ko_review import KOReviewForm
from atst.forms.officers import EditTaskOrderOfficersForm
from atst.models.task_order import Status as TaskOrderStatus
from atst.forms.ko_review import KOReviewForm
from atst.forms.dd_254 import DD254Form
from atst.services.invitation import update_officer_invitations
from atst.utils.flash import formatted_flash as flash
from atst.services.invitation import (
update_officer_invitations,
OFFICER_INVITATIONS,
Invitation as InvitationService,
)
@portfolios_bp.route("/portfolios/<portfolio_id>/task_orders")
@@ -96,6 +103,66 @@ def ko_review(portfolio_id, task_order_id):
raise NoAccessError("task_order")
@portfolios_bp.route(
"/portfolios/<portfolio_id>/task_order/<task_order_id>/resend_invite",
methods=["POST"],
)
def resend_invite(portfolio_id, task_order_id, form=None):
form_data = {**http_request.form}
invite_type = form_data["invite_type"][0]
if invite_type not in dict.keys(OFFICER_INVITATIONS):
raise NotFoundError("invite_type")
invite_type_info = OFFICER_INVITATIONS[invite_type]
task_order = TaskOrders.get(g.current_user, task_order_id)
portfolio = Portfolios.get(g.current_user, portfolio_id)
#
# TODO: Add in authorization check
#
officer = getattr(task_order, invite_type_info["role"])
if not officer:
raise NotFoundError("officer")
invitation = Invitations.lookup_by_portfolio_and_user(portfolio, officer)
if not invitation:
raise NotFoundError("invitation")
Invitations.resend(g.current_user, portfolio.id, invitation.token)
invite_service = InvitationService(
g.current_user,
invitation.portfolio_role,
invitation.email,
subject=invite_type_info["subject"],
email_template=invite_type_info["template"],
)
invite_service.invite()
flash(
"invitation_resent",
officer_type=translate(
"common.officer_helpers.underscore_to_friendly.{}".format(
invite_type_info["role"]
)
),
)
return redirect(
url_for(
"portfolios.task_order_invitations",
portfolio_id=portfolio.id,
task_order_id=task_order.id,
)
)
@portfolios_bp.route(
"/portfolios/<portfolio_id>/task_order/<task_order_id>/review", methods=["POST"]
)
@@ -173,11 +240,14 @@ def edit_task_order_invitations(portfolio_id, task_order_id):
)
)
else:
return render_template(
"portfolios/task_orders/invitations.html",
portfolio=portfolio,
task_order=task_order,
form=form,
return (
render_template(
"portfolios/task_orders/invitations.html",
portfolio=portfolio,
task_order=task_order,
form=form,
),
400,
)

View File

@@ -5,43 +5,43 @@ from atst.queue import queue
from atst.domain.task_orders import TaskOrders
from atst.domain.portfolio_roles import PortfolioRoles
OFFICER_INVITATIONS = [
{
"field": "ko_invite",
OFFICER_INVITATIONS = {
"ko_invite": {
"role": "contracting_officer",
"subject": "Review a task order",
"template": "emails/invitation.txt",
},
{
"field": "cor_invite",
"cor_invite": {
"role": "contracting_officer_representative",
"subject": "Help with a task order",
"template": "emails/invitation.txt",
},
{
"field": "so_invite",
"so_invite": {
"role": "security_officer",
"subject": "Review security for a task order",
"template": "emails/invitation.txt",
},
]
}
def update_officer_invitations(user, task_order):
for officer_type in OFFICER_INVITATIONS:
field = officer_type["field"]
if getattr(task_order, field) and not getattr(task_order, officer_type["role"]):
officer_data = task_order.officer_dictionary(officer_type["role"])
for invite_type in dict.keys(OFFICER_INVITATIONS):
invite_opts = OFFICER_INVITATIONS[invite_type]
if getattr(task_order, invite_type) and not getattr(
task_order, invite_opts["role"]
):
officer_data = task_order.officer_dictionary(invite_opts["role"])
officer = TaskOrders.add_officer(
user, task_order, officer_type["role"], officer_data
user, task_order, invite_opts["role"], officer_data
)
pf_officer_member = PortfolioRoles.get(task_order.portfolio.id, officer.id)
invite_service = Invitation(
user,
pf_officer_member,
officer_data["email"],
subject=officer_type["subject"],
email_template=officer_type["template"],
subject=invite_opts["subject"],
email_template=invite_opts["template"],
)
invite_service.invite()

View File

@@ -2,6 +2,11 @@ from flask import flash, render_template_string
from atst.utils.localization import translate
MESSAGES = {
"invitation_resent": {
"title_template": "The {{ officer_type }} invite has been resent",
"message_template": "Invitation has been resent",
"category": "success",
},
"task_order_draft": {
"title_template": translate("task_orders.form.draft_alert_title"),
"message_template": """