From 4f304d747e3993d105a3857416c14c278f5b858b Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 30 Apr 2019 14:49:53 -0400 Subject: [PATCH] Small tweaks for adding a new application member: - raise specific invitation type if invite not found in invitation domain classes - more terse assignments of defaults in invitation service, smh - terser margin expression for inline input fields - sass formatting - use translation for cancel link - oxford comma for app team management permission explanation - do not format environment roles with hyphens for role selection - generalize some additional methods in the invitation domain base class - use plain atst.models import path --- atst/domain/invitations.py | 14 +++++++++----- atst/forms/application_member.py | 2 +- atst/forms/data.py | 3 --- atst/routes/applications/team.py | 2 +- atst/routes/task_orders/invitations.py | 2 +- atst/services/invitation.py | 16 ++++------------ styles/components/_forms.scss | 4 ++-- .../applications/add_new_application_member.html | 4 ++-- tests/domain/test_invitations.py | 4 ++-- translations.yaml | 2 +- 10 files changed, 23 insertions(+), 30 deletions(-) diff --git a/atst/domain/invitations.py b/atst/domain/invitations.py index 209cd4d1..c38e88d8 100644 --- a/atst/domain/invitations.py +++ b/atst/domain/invitations.py @@ -4,6 +4,7 @@ from sqlalchemy.orm.exc import NoResultFound from atst.database import db from atst.models import ApplicationInvitation, InvitationStatus, PortfolioInvitation from atst.domain.portfolio_roles import PortfolioRoles +from atst.domain.application_roles import ApplicationRoles from .exceptions import NotFoundError @@ -40,6 +41,7 @@ class InvitationError(Exception): class BaseInvitations(object): model = None + role_domain_class = None # number of minutes a given invitation is considered valid EXPIRATION_LIMIT_MINUTES = 360 @@ -48,7 +50,7 @@ class BaseInvitations(object): try: invite = db.session.query(cls.model).filter_by(token=token).one() except NoResultFound: - raise NotFoundError("invite") + raise NotFoundError(cls.model.__tablename__) return invite @@ -86,7 +88,7 @@ class BaseInvitations(object): elif invite.is_pending: # pragma: no branch cls._update_status(invite, InvitationStatus.ACCEPTED) - PortfolioRoles.enable(invite.role) + cls.role_domain_class.enable(invite.role) return invite @classmethod @@ -109,11 +111,11 @@ class BaseInvitations(object): return cls._update_status(invite, InvitationStatus.REVOKED) @classmethod - def lookup_by_portfolio_and_user(cls, portfolio, user): - role = PortfolioRoles.get(portfolio.id, user.id) + def lookup_by_resource_and_user(cls, resource, user): + role = cls.role_domain_class.get(resource.id, user.id) if role.latest_invitation is None: - raise NotFoundError("invitation") + raise NotFoundError(cls.model.__tablename__) return role.latest_invitation @@ -127,7 +129,9 @@ class BaseInvitations(object): class PortfolioInvitations(BaseInvitations): model = PortfolioInvitation + role_domain_class = PortfolioRoles class ApplicationInvitations(BaseInvitations): model = ApplicationInvitation + role_domain_class = ApplicationRoles diff --git a/atst/forms/application_member.py b/atst/forms/application_member.py index 12e71873..1e13d896 100644 --- a/atst/forms/application_member.py +++ b/atst/forms/application_member.py @@ -3,7 +3,7 @@ from wtforms.fields import FormField, FieldList, HiddenField, BooleanField from .forms import BaseForm from .member import NewForm as BaseNewMemberForm -from .data import FORMATTED_ENV_ROLES as ENV_ROLES +from .data import ENV_ROLES from atst.forms.fields import SelectField from atst.domain.permission_sets import PermissionSets from atst.utils.localization import translate diff --git a/atst/forms/data.py b/atst/forms/data.py index 26f23547..2e0b689d 100644 --- a/atst/forms/data.py +++ b/atst/forms/data.py @@ -218,6 +218,3 @@ REQUIRED_DISTRIBUTIONS = [ ] ENV_ROLES = [(role.value, role.value) for role in CSPRole] + [(None, "No access")] -FORMATTED_ENV_ROLES = [ - (role.value, "- {} -".format(role.value)) for role in CSPRole -] + [(None, "- No Access -")] diff --git a/atst/routes/applications/team.py b/atst/routes/applications/team.py index 5bfbfaf5..57994a3c 100644 --- a/atst/routes/applications/team.py +++ b/atst/routes/applications/team.py @@ -8,7 +8,7 @@ from atst.domain.authz.decorator import user_can_access_decorator as user_can from atst.domain.permission_sets import PermissionSets from atst.domain.exceptions import AlreadyExistsError from atst.forms.application_member import NewForm as NewMemberForm -from atst.models.permissions import Permissions +from atst.models import Permissions from atst.services.invitation import Invitation as InvitationService from atst.utils.flash import formatted_flash as flash from atst.utils.localization import translate diff --git a/atst/routes/task_orders/invitations.py b/atst/routes/task_orders/invitations.py index b89d6be2..8819859c 100644 --- a/atst/routes/task_orders/invitations.py +++ b/atst/routes/task_orders/invitations.py @@ -57,7 +57,7 @@ def resend_invite(task_order_id): if not officer: raise NotFoundError("officer") - invitation = PortfolioInvitations.lookup_by_portfolio_and_user(portfolio, officer) + invitation = PortfolioInvitations.lookup_by_resource_and_user(portfolio, officer) if not invitation: raise NotFoundError("invitation") diff --git a/atst/services/invitation.py b/atst/services/invitation.py index 877a3ab7..e9dec252 100644 --- a/atst/services/invitation.py +++ b/atst/services/invitation.py @@ -57,26 +57,18 @@ class Invitation: if isinstance(member, PortfolioRole): self.email_template = ( - "emails/portfolio/invitation.txt" - if self.email_template is None - else self.email_template + self.email_template or "emails/portfolio/invitation.txt" ) self.subject = ( - "{} has invited you to a JEDI cloud portfolio" - if self.subject is None - else self.subject + self.subject or "{} has invited you to a JEDI cloud portfolio" ) self.domain_class = PortfolioInvitations elif isinstance(member, ApplicationRole): self.email_template = ( - "emails/application/invitation.txt" - if self.email_template is None - else self.email_template + self.email_template or "emails/application/invitation.txt" ) self.subject = ( - "{} has invited you to a JEDI cloud application" - if self.subject is None - else self.subject + self.subject or "{} has invited you to a JEDI cloud application" ) self.domain_class = ApplicationInvitations diff --git a/styles/components/_forms.scss b/styles/components/_forms.scss index 5c30f1aa..3d91ca5e 100644 --- a/styles/components/_forms.scss +++ b/styles/components/_forms.scss @@ -180,10 +180,10 @@ } .input__inline-fields { - margin: 1rem 0 1rem 0; + margin: 1rem 0; &.input__inline-fields--indented { - margin-left: 4*$gap; + margin-left: $gap*4; } &> fieldset.usa-input__choices label { diff --git a/templates/fragments/applications/add_new_application_member.html b/templates/fragments/applications/add_new_application_member.html index d65d34e2..cbe18c9a 100644 --- a/templates/fragments/applications/add_new_application_member.html +++ b/templates/fragments/applications/add_new_application_member.html @@ -37,7 +37,7 @@ v-bind:disabled="invalid" class='action-group__action usa-button' value='Next'> - Cancel + {{ "common.cancel" | translate }} {% endset %} {% set step_two %} @@ -117,7 +117,7 @@ class='action-group__action usa-button' form="add-app-mem" value='Invite member'> - Cancel + {{ "common.cancel" | translate }} add and rename environments within the application.' delete_envs: 'Allow member to delete environments within the application.' - manage_team: 'Allow member to add, update and remove members from the application team.' + manage_team: 'Allow member to add, update, and remove members from the application team.' index: empty: start_button: Start a new JEDI portfolio