Merge pull request #721 from dod-ccpo/app-perms-bug
User can only update apps or revoke invites related to their portfolios
This commit is contained in:
commit
cd999f52ac
@ -5,21 +5,31 @@ from flask import g, current_app as app, request
|
|||||||
from . import user_can_access
|
from . import user_can_access
|
||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
from atst.domain.task_orders import TaskOrders
|
from atst.domain.task_orders import TaskOrders
|
||||||
|
from atst.domain.applications import Applications
|
||||||
|
from atst.domain.invitations import Invitations
|
||||||
from atst.domain.exceptions import UnauthorizedError
|
from atst.domain.exceptions import UnauthorizedError
|
||||||
|
|
||||||
|
|
||||||
def check_access(permission, message, exception, *args, **kwargs):
|
def check_access(permission, message, exception, *args, **kwargs):
|
||||||
access_args = {"message": message}
|
access_args = {"message": message}
|
||||||
|
|
||||||
if "portfolio_id" in kwargs:
|
if "application_id" in kwargs:
|
||||||
|
application = Applications.get(kwargs["application_id"])
|
||||||
|
access_args["portfolio"] = application.portfolio
|
||||||
|
|
||||||
|
elif "task_order_id" in kwargs:
|
||||||
|
task_order = TaskOrders.get(kwargs["task_order_id"])
|
||||||
|
access_args["portfolio"] = task_order.portfolio
|
||||||
|
|
||||||
|
elif "token" in kwargs:
|
||||||
|
invite = Invitations._get(kwargs["token"])
|
||||||
|
access_args["portfolio"] = invite.portfolio_role.portfolio
|
||||||
|
|
||||||
|
elif "portfolio_id" in kwargs:
|
||||||
access_args["portfolio"] = Portfolios.get(
|
access_args["portfolio"] = Portfolios.get(
|
||||||
g.current_user, kwargs["portfolio_id"]
|
g.current_user, kwargs["portfolio_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
if "task_order_id" in kwargs:
|
|
||||||
task_order = TaskOrders.get(kwargs["task_order_id"])
|
|
||||||
access_args["portfolio"] = task_order.portfolio
|
|
||||||
|
|
||||||
if exception is not None and exception(g.current_user, **access_args, **kwargs):
|
if exception is not None and exception(g.current_user, **access_args, **kwargs):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -157,6 +157,54 @@ def test_user_without_permission_cannot_update_application(client, user_session)
|
|||||||
assert application.description == "Cool stuff happening here!"
|
assert application.description == "Cool stuff happening here!"
|
||||||
|
|
||||||
|
|
||||||
|
def test_user_can_only_access_apps_in_their_portfolio(client, user_session):
|
||||||
|
portfolio = PortfolioFactory.create()
|
||||||
|
other_portfolio = PortfolioFactory.create(
|
||||||
|
applications=[
|
||||||
|
{
|
||||||
|
"name": "Awesome Application",
|
||||||
|
"description": "More cool stuff happening here!",
|
||||||
|
"environments": [{"name": "dev"}],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
other_application = other_portfolio.applications[0]
|
||||||
|
user_session(portfolio.owner)
|
||||||
|
|
||||||
|
# user can't view application edit form
|
||||||
|
response = client.get(
|
||||||
|
url_for(
|
||||||
|
"portfolios.edit_application",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
application_id=other_application.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
# user can't post update application form
|
||||||
|
time_updated = other_application.time_updated
|
||||||
|
response = client.post(
|
||||||
|
url_for(
|
||||||
|
"portfolios.update_application",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
application_id=other_application.id,
|
||||||
|
),
|
||||||
|
data={"name": "New Name", "description": "A new description."},
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert time_updated == other_application.time_updated
|
||||||
|
|
||||||
|
# user can't view application members
|
||||||
|
response = client.get(
|
||||||
|
url_for(
|
||||||
|
"portfolios.application_members",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
application_id=other_application.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
def create_environment(user):
|
def create_environment(user):
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=user)
|
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=user)
|
||||||
|
@ -169,6 +169,58 @@ def test_revoke_invitation(client, user_session):
|
|||||||
assert invite.is_revoked
|
assert invite.is_revoked
|
||||||
|
|
||||||
|
|
||||||
|
def test_user_can_only_revoke_invites_in_their_portfolio(client, user_session):
|
||||||
|
portfolio = PortfolioFactory.create()
|
||||||
|
other_portfolio = PortfolioFactory.create()
|
||||||
|
user = UserFactory.create()
|
||||||
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
|
user=user, portfolio=other_portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
|
)
|
||||||
|
invite = InvitationFactory.create(
|
||||||
|
user_id=user.id,
|
||||||
|
portfolio_role=portfolio_role,
|
||||||
|
status=InvitationStatus.REJECTED_EXPIRED,
|
||||||
|
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
||||||
|
)
|
||||||
|
user_session(portfolio.owner)
|
||||||
|
response = client.post(
|
||||||
|
url_for(
|
||||||
|
"portfolios.revoke_invitation",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
token=invite.token,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert not invite.is_revoked
|
||||||
|
|
||||||
|
|
||||||
|
def test_user_can_only_resend_invites_in_their_portfolio(client, user_session, queue):
|
||||||
|
portfolio = PortfolioFactory.create()
|
||||||
|
other_portfolio = PortfolioFactory.create()
|
||||||
|
user = UserFactory.create()
|
||||||
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
|
user=user, portfolio=other_portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
|
)
|
||||||
|
invite = InvitationFactory.create(
|
||||||
|
user_id=user.id,
|
||||||
|
portfolio_role=portfolio_role,
|
||||||
|
status=InvitationStatus.REJECTED_EXPIRED,
|
||||||
|
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
||||||
|
)
|
||||||
|
user_session(portfolio.owner)
|
||||||
|
response = client.post(
|
||||||
|
url_for(
|
||||||
|
"portfolios.resend_invitation",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
token=invite.token,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert len(queue.get_queue()) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_resend_invitation_sends_email(client, user_session, queue):
|
def test_resend_invitation_sends_email(client, user_session, queue):
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
|
@ -128,6 +128,20 @@ class TestPortfolioFunding:
|
|||||||
assert context["funding_end_date"] is expiring_to.end_date
|
assert context["funding_end_date"] is expiring_to.end_date
|
||||||
assert context["funded"] == False
|
assert context["funded"] == False
|
||||||
|
|
||||||
|
def test_user_can_only_access_to_in_their_portfolio(
|
||||||
|
self, app, user_session, portfolio
|
||||||
|
):
|
||||||
|
other_task_order = TaskOrderFactory.create()
|
||||||
|
user_session(portfolio.owner)
|
||||||
|
response = app.test_client().get(
|
||||||
|
url_for(
|
||||||
|
"portfolios.view_task_order",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
task_order_id=other_task_order.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
class TestTaskOrderInvitations:
|
class TestTaskOrderInvitations:
|
||||||
def setup(self):
|
def setup(self):
|
||||||
@ -227,6 +241,54 @@ class TestTaskOrderInvitations:
|
|||||||
assert len(queue.get_queue()) == queue_length
|
assert len(queue.get_queue()) == queue_length
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
def test_user_can_only_invite_to_task_order_in_their_portfolio(
|
||||||
|
self, user_session, client, portfolio
|
||||||
|
):
|
||||||
|
other_task_order = TaskOrderFactory.create()
|
||||||
|
user_session(portfolio.owner)
|
||||||
|
|
||||||
|
# user can't see invites
|
||||||
|
response = client.get(
|
||||||
|
url_for(
|
||||||
|
"portfolios.task_order_invitations",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
task_order_id=other_task_order.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
# user can't send invites
|
||||||
|
time_updated = other_task_order.time_updated
|
||||||
|
response = client.post(
|
||||||
|
url_for(
|
||||||
|
"portfolios.edit_task_order_invitations",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
task_order_id=other_task_order.id,
|
||||||
|
),
|
||||||
|
data={
|
||||||
|
"contracting_officer-first_name": "Luke",
|
||||||
|
"contracting_officer-last_name": "Skywalker",
|
||||||
|
"contracting_officer-dod_id": "0123456789",
|
||||||
|
"contracting_officer-email": "luke@skywalker.mil",
|
||||||
|
"contracting_officer-phone_number": "0123456789",
|
||||||
|
"contracting_officer-invite": "y",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert time_updated == other_task_order.time_updated
|
||||||
|
|
||||||
|
# user can't resend invites
|
||||||
|
response = client.post(
|
||||||
|
url_for(
|
||||||
|
"portfolios.resend_invite",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
task_order_id=other_task_order.id,
|
||||||
|
invite_type="ko_invite",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert time_updated == other_task_order.time_updated
|
||||||
|
|
||||||
|
|
||||||
def test_ko_can_view_task_order(client, user_session, portfolio, user):
|
def test_ko_can_view_task_order(client, user_session, portfolio, user):
|
||||||
PortfolioRoleFactory.create(
|
PortfolioRoleFactory.create(
|
||||||
@ -464,6 +526,57 @@ def test_submit_completed_ko_review_page_as_ko(
|
|||||||
assert task_order.loas == loa_list
|
assert task_order.loas == loa_list
|
||||||
|
|
||||||
|
|
||||||
|
def test_ko_can_only_access_their_to(app, user_session, client, portfolio, pdf_upload):
|
||||||
|
ko = UserFactory.create()
|
||||||
|
|
||||||
|
PortfolioRoleFactory.create(
|
||||||
|
portfolio=portfolio,
|
||||||
|
user=ko,
|
||||||
|
status=PortfolioStatus.ACTIVE,
|
||||||
|
permission_sets=[
|
||||||
|
PermissionSets.get(PermissionSets.VIEW_PORTFOLIO),
|
||||||
|
PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_FUNDING),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
task_order = TaskOrderFactory.create(portfolio=portfolio, contracting_officer=ko)
|
||||||
|
dd_254 = DD254Factory.create()
|
||||||
|
TaskOrders.add_dd_254(task_order, dd_254.to_dictionary())
|
||||||
|
other_task_order = TaskOrderFactory.create()
|
||||||
|
user_session(ko)
|
||||||
|
|
||||||
|
# KO can't see TO
|
||||||
|
response = client.get(
|
||||||
|
url_for(
|
||||||
|
"portfolios.ko_review",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
task_order_id=other_task_order.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
# KO can't submit review for TO
|
||||||
|
form_data = {
|
||||||
|
"start_date": "02/10/2019",
|
||||||
|
"end_date": "03/10/2019",
|
||||||
|
"number": "1938745981",
|
||||||
|
"loas-0": "1231231231",
|
||||||
|
"custom_clauses": "hi im a custom clause",
|
||||||
|
"pdf": pdf_upload,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
url_for(
|
||||||
|
"portfolios.submit_ko_review",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
task_order_id=other_task_order.id,
|
||||||
|
),
|
||||||
|
data=form_data,
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert not TaskOrders.is_signed_by_ko(other_task_order)
|
||||||
|
|
||||||
|
|
||||||
def test_so_review_page(app, client, user_session, portfolio):
|
def test_so_review_page(app, client, user_session, portfolio):
|
||||||
so = UserFactory.create()
|
so = UserFactory.create()
|
||||||
PortfolioRoleFactory.create(
|
PortfolioRoleFactory.create(
|
||||||
@ -541,6 +654,45 @@ def test_submit_so_review(app, client, user_session, portfolio):
|
|||||||
assert task_order.dd_254.certifying_official == dd_254_data["certifying_official"]
|
assert task_order.dd_254.certifying_official == dd_254_data["certifying_official"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_so_can_only_access_their_to(app, client, user_session, portfolio):
|
||||||
|
so = UserFactory.create()
|
||||||
|
PortfolioRoleFactory.create(
|
||||||
|
portfolio=portfolio,
|
||||||
|
user=so,
|
||||||
|
status=PortfolioStatus.ACTIVE,
|
||||||
|
permission_sets=[
|
||||||
|
PermissionSets.get(PermissionSets.VIEW_PORTFOLIO),
|
||||||
|
PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_FUNDING),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
task_order = TaskOrderFactory.create(portfolio=portfolio, security_officer=so)
|
||||||
|
dd_254_data = DD254Factory.dictionary()
|
||||||
|
other_task_order = TaskOrderFactory.create()
|
||||||
|
user_session(so)
|
||||||
|
|
||||||
|
# SO can't view dd254
|
||||||
|
response = client.get(
|
||||||
|
url_for(
|
||||||
|
"portfolios.so_review",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
task_order_id=other_task_order.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
# SO can't submit dd254
|
||||||
|
response = client.post(
|
||||||
|
url_for(
|
||||||
|
"portfolios.submit_so_review",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
task_order_id=other_task_order.id,
|
||||||
|
),
|
||||||
|
data=dd_254_data,
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert not other_task_order.dd_254
|
||||||
|
|
||||||
|
|
||||||
def test_resend_invite_when_invalid_invite_officer(
|
def test_resend_invite_when_invalid_invite_officer(
|
||||||
app, client, user_session, portfolio, user
|
app, client, user_session, portfolio, user
|
||||||
):
|
):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user