Route for accepting an application invitation.

- Domain method for enabling an application role.
- Updated ApplicationRole model `history` property so that it serializes
  the `status` correctly
This commit is contained in:
dandds 2019-05-03 06:21:30 -04:00
parent d8771accca
commit a2ebdf78a0
7 changed files with 71 additions and 3 deletions

View File

@ -1,5 +1,5 @@
from atst.database import db
from atst.models.application_role import ApplicationRole
from atst.models import ApplicationRole, ApplicationRoleStatus
from atst.domain.permission_sets import PermissionSets
@ -21,3 +21,10 @@ class ApplicationRoles(object):
db.session.commit()
return application_role
@classmethod
def enable(cls, role):
role.status = ApplicationRoleStatus.ACTIVE
db.session.add(role)
db.session.commit()

View File

@ -62,7 +62,13 @@ class ApplicationRole(
@property
def history(self):
return self.get_changes()
previous_state = self.get_changes()
change_set = {}
if "status" in previous_state:
from_status = previous_state["status"][0].value
to_status = self.status.value
change_set["status"] = [from_status, to_status]
return change_set
def has_permission_set(self, perm_set_name):
return first_or_none(

View File

@ -6,6 +6,7 @@ from . import index
from . import new
from . import settings
from . import team
from . import invitations
from atst.domain.environment_roles import EnvironmentRoles
from atst.domain.exceptions import UnauthorizedError
from atst.domain.authz.decorator import user_can_access_decorator as user_can

View File

@ -0,0 +1,15 @@
from flask import redirect, url_for, g
from . import applications_bp
from atst.domain.invitations import ApplicationInvitations
@applications_bp.route("/applications/invitations/<token>", methods=["GET"])
def accept_invitation(token):
invite = ApplicationInvitations.accept(g.current_user, token)
return redirect(
url_for(
"portfolios.show_portfolio", portfolio_id=invite.application.portfolio_id
)
)

View File

@ -1,6 +1,8 @@
from atst.domain.application_roles import ApplicationRoles
from atst.domain.permission_sets import PermissionSets
from tests.factories import UserFactory, ApplicationFactory
from atst.models import ApplicationRoleStatus
from tests.factories import *
def test_create_application_role():
@ -18,3 +20,16 @@ def test_create_application_role():
)
assert application_role.application == application
assert application_role.user == user
def test_enabled_application_role():
application = ApplicationFactory.create()
user = UserFactory.create()
app_role = ApplicationRoleFactory.create(
application=application, user=user, status=ApplicationRoleStatus.DISABLED
)
assert app_role.status == ApplicationRoleStatus.DISABLED
ApplicationRoles.enable(app_role)
assert app_role.status == ApplicationRoleStatus.ACTIVE

View File

@ -0,0 +1,23 @@
from flask import url_for
from tests.factories import *
def test_accept_application_invitation(client, user_session):
user = UserFactory.create()
application = ApplicationFactory.create()
app_role = ApplicationRoleFactory.create(application=application, user=user)
invite = ApplicationInvitationFactory.create(
role=app_role, user=user, inviter=application.portfolio.owner
)
user_session(user)
response = client.get(url_for("applications.accept_invitation", token=invite.token))
assert response.status_code == 302
expected_location = url_for(
"portfolios.show_portfolio",
portfolio_id=application.portfolio_id,
_external=True,
)
assert response.location == expected_location

View File

@ -35,6 +35,7 @@ _NO_ACCESS_CHECK_REQUIRED = _NO_LOGIN_REQUIRED + [
"users.user", # available to all users
"users.update_user", # available to all users
"portfolios.accept_invitation", # available to all users; access control is built into invitation logic
"applications.accept_invitation", # available to all users; access control is built into invitation logic
"atst.catch_all", # available to all users
"portfolios.portfolios", # the portfolios list is scoped to the user separately
]