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
This commit is contained in:
parent
5db4d9bab3
commit
4f304d747e
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 -")]
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -37,7 +37,7 @@
|
||||
v-bind:disabled="invalid"
|
||||
class='action-group__action usa-button'
|
||||
value='Next'>
|
||||
<a class='action-group__action icon-link icon-link--default' v-on:click="closeModal('{{ new_port_mem }}')">Cancel</a>
|
||||
<a class='action-group__action icon-link icon-link--default' v-on:click="closeModal('{{ new_port_mem }}')">{{ "common.cancel" | translate }}</a>
|
||||
</div>
|
||||
{% endset %}
|
||||
{% set step_two %}
|
||||
@ -117,7 +117,7 @@
|
||||
class='action-group__action usa-button'
|
||||
form="add-app-mem"
|
||||
value='Invite member'>
|
||||
<a class='action-group__action icon-link icon-link--default' v-on:click="closeModal('{{ new_port_mem }}')">Cancel</a>
|
||||
<a class='action-group__action icon-link icon-link--default' v-on:click="closeModal('{{ new_port_mem }}')">{{ "common.cancel" | translate }}</a>
|
||||
<input
|
||||
type='button'
|
||||
v-on:click="previous()"
|
||||
|
@ -152,9 +152,9 @@ def test_lookup_by_user_and_portfolio():
|
||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||
invite = PortfolioInvitations.create(portfolio.owner, ws_role, user.email)
|
||||
|
||||
assert PortfolioInvitations.lookup_by_portfolio_and_user(portfolio, user) == invite
|
||||
assert PortfolioInvitations.lookup_by_resource_and_user(portfolio, user) == invite
|
||||
|
||||
with pytest.raises(NotFoundError):
|
||||
PortfolioInvitations.lookup_by_portfolio_and_user(
|
||||
PortfolioInvitations.lookup_by_resource_and_user(
|
||||
portfolio, UserFactory.create()
|
||||
)
|
||||
|
@ -444,7 +444,7 @@ portfolios:
|
||||
manage_perms: 'Manage permissions for {application_name}'
|
||||
manage_envs: 'Allow member to <strong>add</strong> and <strong>rename environments</strong> within the application.'
|
||||
delete_envs: 'Allow member to <strong>delete environments</strong> within the application.'
|
||||
manage_team: 'Allow member to <strong>add, update</strong> and <strong>remove members</strong> from the application team.'
|
||||
manage_team: 'Allow member to <strong>add, update,</strong> and <strong>remove members</strong> from the application team.'
|
||||
index:
|
||||
empty:
|
||||
start_button: Start a new JEDI portfolio
|
||||
|
Loading…
x
Reference in New Issue
Block a user