def invite_member(portfolio_id): portfolio = Portfolios.get(g.current_user, portfolio_id) form = member_forms.NewForm(http_request.form) if form.validate(): try: invite = Portfolios.invite(portfolio, g.current_user, form.data) send_portfolio_invitation( invitee_email=invite.email, inviter_name=g.current_user.full_name, token=invite.token, ) flash("new_portfolio_member", user_name=invite.user_name, portfolio=portfolio) except AlreadyExistsError: return render_template( "error.html", message="There was an error processing your request.") else: pass # TODO: flash error message return redirect( url_for( "portfolios.admin", portfolio_id=portfolio_id, fragment="portfolio-members", _anchor="portfolio-members", ))
def test_delete_success(): portfolio = PortfolioFactory.create() assert not portfolio.deleted Portfolios.delete(portfolio=portfolio) assert portfolio.deleted
def test_for_user_does_not_return_inactive_portfolios(portfolio, portfolio_owner): bob = UserFactory.create() Portfolios.add_member(portfolio, bob) PortfolioFactory.create() bobs_portfolios = Portfolios.for_user(bob) assert len(bobs_portfolios) == 0
def test_delete_failure_with_applications(): portfolio = PortfolioFactory.create() application = ApplicationFactory.create(portfolio=portfolio) assert not portfolio.deleted with pytest.raises(PortfolioDeletionApplicationsExistError): Portfolios.delete(portfolio=portfolio) assert not portfolio.deleted
def edit(portfolio_id): portfolio = Portfolios.get_for_update(portfolio_id) form = PortfolioForm(http_request.form) if form.validate(): Portfolios.update(portfolio, form.data) return redirect( url_for("applications.portfolio_applications", portfolio_id=portfolio.id)) else: # rerender portfolio admin page return render_admin_page(portfolio, form)
def test_delete_portfolio_failure(no_debug_client, user_session): portfolio = PortfolioFactory.create() application = ApplicationFactory.create(portfolio=portfolio) owner = portfolio.owner user_session(owner) assert len(Portfolios.for_user(user=owner)) == 1 response = no_debug_client.post( url_for("portfolios.delete_portfolio", portfolio_id=portfolio.id)) assert response.status_code == 500 assert len(Portfolios.for_user(user=owner)) == 1
def test_delete_portfolio_success(client, user_session): portfolio = PortfolioFactory.create() owner = portfolio.owner user_session(owner) assert len(Portfolios.for_user(user=owner)) == 1 response = client.post( url_for("portfolios.delete_portfolio", portfolio_id=portfolio.id)) assert response.status_code == 302 assert url_for("atst.home") in response.location assert len(Portfolios.for_user(user=owner)) == 0
def test_for_user_does_not_include_deleted_application_roles(): user1 = UserFactory.create() user2 = UserFactory.create() portfolio = PortfolioFactory.create() app = ApplicationFactory.create(portfolio=portfolio) ApplicationRoleFactory.create(status=ApplicationRoleStatus.ACTIVE, user=user1, application=app) assert len(Portfolios.for_user(user1)) == 1 ApplicationRoleFactory.create(status=ApplicationRoleStatus.ACTIVE, user=user2, application=app, deleted=True) assert len(Portfolios.for_user(user2)) == 0
def remove_member(portfolio_id, portfolio_role_id): portfolio_role = PortfolioRoles.get_by_id(portfolio_role_id) if g.current_user.id == portfolio_role.user_id: raise UnauthorizedError( g.current_user, "you cant remove yourself from the portfolio" ) portfolio = Portfolios.get(user=g.current_user, portfolio_id=portfolio_id) if portfolio_role.user_id == portfolio.owner.id: raise UnauthorizedError( g.current_user, "you can't delete the portfolios PPoC from the portfolio" ) # TODO: should this cascade and disable any application and environment # roles they might have? PortfolioRoles.disable(portfolio_role=portfolio_role) flash("portfolio_member_removed", member_name=portfolio_role.full_name) return redirect( url_for( "portfolios.admin", portfolio_id=portfolio_id, _anchor="portfolio-members", fragment="portfolio-members", ) )
def create_or_update_new_application_step_1(portfolio_id=None, application_id=None): form = get_new_application_form({**http_request.form}, NameAndDescriptionForm, application_id) if form.validate(): application = None if application_id: application = Applications.get(application_id) application = Applications.update(application, form.data) flash("application_updated", application_name=application.name) else: portfolio = Portfolios.get_for_update(portfolio_id) application = Applications.create(g.current_user, portfolio, **form.data) flash("application_created", application_name=application.name) return redirect( url_for( "applications.update_new_application_step_2", application_id=application.id, )) else: return ( render_new_application_form( "applications/new/step_1.html", NameAndDescriptionForm, portfolio_id, application_id, form, ), 400, )
def create_demo_portfolio(name, data): try: portfolio_owner = Users.get_or_create_by_dod_id("2345678901") # Amanda # auditor = Users.get_by_dod_id("3453453453") # Sally except NotFoundError: print("Could not find demo users; will not create demo portfolio {}". format(name)) return portfolio = Portfolios.create( user=portfolio_owner, portfolio_attrs={ "name": name, "defense_component": random_service_branch() }, ) add_task_orders_to_portfolio(portfolio) add_members_to_portfolio(portfolio) for mock_application in data["applications"]: application = Application(portfolio=portfolio, name=mock_application.name, description="") env_names = [env.name for env in mock_application.environments] envs = Environments.create_many(portfolio.owner, application, env_names) db.session.add(application) db.session.commit()
def portfolios(): portfolios = Portfolios.for_user(g.current_user) if portfolios: return render_template("portfolios/index.html", page=5, portfolios=portfolios) else: return render_template("portfolios/blank_slate.html")
def remove_member(portfolio_id, portfolio_role_id): portfolio_role = PortfolioRoles.get_by_id(portfolio_role_id) if g.current_user.id == portfolio_role.user_id: raise UnauthorizedError(g.current_user, "you cant remove yourself from the portfolio") portfolio = Portfolios.get(user=g.current_user, portfolio_id=portfolio_id) if portfolio_role.user_id == portfolio.owner.id: raise UnauthorizedError( g.current_user, "you can't delete the portfolios PPoC from the portfolio") if (portfolio_role.latest_invitation and portfolio_role.status == PortfolioRoleStatus.PENDING): PortfolioInvitations.revoke(portfolio_role.latest_invitation.token) else: PortfolioRoles.disable(portfolio_role=portfolio_role) flash("portfolio_member_removed", member_name=portfolio_role.full_name) return redirect( url_for( "portfolios.admin", portfolio_id=portfolio_id, _anchor="portfolio-members", fragment="portfolio-members", ))
def test_create_portfolio_success(client, user_session): user = UserFactory.create() user_session(user) original_portfolio_count = len(PortfoliosQuery.get_all()) response = client.post( url_for("portfolios.create_portfolio"), data={ "name": "My project name", "description": "My project description", "defense_component": "Air Force, Department of the", }, ) assert response.status_code == 302 assert len(PortfoliosQuery.get_all()) == original_portfolio_count + 1 new_portfolio = Portfolios.for_user(user=user)[-1] assert ( url_for("applications.portfolio_applications", portfolio_id=new_portfolio.id) in response.location ) assert new_portfolio.owner == user
def seed_db(): get_users() amanda = Users.get_by_dod_id("2345678901") # Create Portfolios for Amanda with mocked reporting data create_demo_portfolio("A-Wing", MockReportingProvider.FIXTURE_SPEND_DATA["A-Wing"]) create_demo_portfolio("B-Wing", MockReportingProvider.FIXTURE_SPEND_DATA["B-Wing"]) tie_interceptor = Portfolios.create( user=amanda, portfolio_attrs={ "name": "TIE Interceptor", "defense_component": random_service_branch(), }, ) add_task_orders_to_portfolio(tie_interceptor) add_members_to_portfolio(tie_interceptor) add_applications_to_portfolio(tie_interceptor) tie_fighter = Portfolios.create( user=amanda, portfolio_attrs={ "name": "TIE Fighter", "defense_component": random_service_branch(), }, ) add_task_orders_to_portfolio(tie_fighter) add_members_to_portfolio(tie_fighter) add_applications_to_portfolio(tie_fighter) # create a portfolio for each user ships = SHIP_NAMES.copy() for user in get_users(): ship = random.choice(ships) ships.remove(ship) portfolio = Portfolios.create( user=user, portfolio_attrs={ "name": ship, "defense_component": random_service_branch(), }, ) add_task_orders_to_portfolio(portfolio) add_members_to_portfolio(portfolio) add_applications_to_portfolio(portfolio)
def portfolio_funding(portfolio_id): portfolio = Portfolios.get(g.current_user, portfolio_id) task_orders = TaskOrders.sort_by_status(portfolio.task_orders) to_count = len(portfolio.task_orders) # TODO: Get expended amount from the CSP return render_template("task_orders/index.html", task_orders=task_orders, to_count=to_count)
def test_for_user_returns_portfolios_for_applications_user_invited_to(): bob = UserFactory.create() portfolio = PortfolioFactory.create() application = ApplicationFactory.create(portfolio=portfolio) ApplicationRoleFactory.create(application=application, user=bob, status=ApplicationRoleStatus.ACTIVE) assert portfolio in Portfolios.for_user(user=bob)
def add_members_to_portfolio(portfolio): for user_data in PORTFOLIO_USERS: invite = Portfolios.invite(portfolio, portfolio.owner, {"user_data": user_data}) profile = { k: user_data[k] for k in user_data if k not in ["dod_id", "permission_sets"] } user = Users.get_or_create_by_dod_id(user_data["dod_id"], **profile) PortfolioRoles.enable(invite.role, user) db.session.commit()
def create_portfolio(): form = PortfolioCreationForm(http_request.form) if form.validate(): portfolio = Portfolios.create(user=g.current_user, portfolio_attrs=form.data) return redirect( url_for("applications.portfolio_applications", portfolio_id=portfolio.id) ) else: return render_template("portfolios/new.html", form=form), 400
def test_invite(): portfolio = PortfolioFactory.create() inviter = UserFactory.create() member_data = UserFactory.dictionary() invitation = Portfolios.invite(portfolio, inviter, member_data) assert invitation.role assert invitation.role.portfolio == portfolio assert invitation.role.user is None assert invitation.dod_id == member_data["dod_id"]
def test_for_user_returns_active_portfolios_for_user(portfolio, portfolio_owner): bob = UserFactory.create() PortfolioRoleFactory.create(user=bob, portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE) PortfolioFactory.create() bobs_portfolios = Portfolios.for_user(bob) assert len(bobs_portfolios) == 1
def test_get_application_events(): # add in some portfolio level events portfolio = PortfolioFactory.create() Portfolios.update(portfolio, {"name": "New Name"}) # add app level events application = ApplicationFactory.create(portfolio=portfolio) Applications.update(application, {"name": "Star Cruiser"}) app_role = ApplicationRoleFactory.create(application=application) app_invite = ApplicationInvitationFactory.create(role=app_role) env = EnvironmentFactory.create(application=application) env_role = EnvironmentRoleFactory.create(environment=env, application_role=app_role) # add rando app rando_app = ApplicationFactory.create(portfolio=portfolio) events = AuditLog.get_application_events(application) for event in events: assert event.application_id == application.id assert not event.application_id == rando_app.id resource_types = [event.resource_type for event in events] assert "portfolio" not in resource_types
def portfolio_funding(portfolio_id): portfolio = Portfolios.get(g.current_user, portfolio_id) task_orders = TaskOrders.sort(portfolio.task_orders) label_colors = { TaskOrderStatus.DRAFT: "warning", TaskOrderStatus.ACTIVE: "success", TaskOrderStatus.UPCOMING: "info", TaskOrderStatus.EXPIRED: "error", TaskOrderStatus.UNSIGNED: "purple", } return render_template( "task_orders/index.html", task_orders=task_orders, label_colors=label_colors )
def test_update_ppoc_when_ppoc(client, user_session): portfolio = PortfolioFactory.create() original_ppoc = portfolio.owner_role new_ppoc = Portfolios.add_member( member=UserFactory.create(), portfolio=portfolio, permission_sets=[PermissionSets.VIEW_PORTFOLIO], ) user_session(original_ppoc.user) updating_ppoc_successfully( client=client, new_ppoc=new_ppoc, old_ppoc=original_ppoc, portfolio=portfolio )
def test_existing_member_accepts_valid_invite(client, user_session): portfolio = PortfolioFactory.create() user = UserFactory.create() role = PortfolioRoleFactory.create(portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING) invite = PortfolioInvitationFactory.create(dod_id=user.dod_id, role=role) # the user does not have access to the portfolio before accepting the invite assert len(Portfolios.for_user(user)) == 0 user_session(user) response = client.get( url_for("portfolios.accept_invitation", portfolio_token=invite.token)) # user is redirected to the portfolio view assert response.status_code == 302 assert (url_for("applications.portfolio_applications", portfolio_id=invite.portfolio.id) in response.headers["Location"]) # the one-time use invite is no longer usable assert invite.is_accepted # the user has access to the portfolio assert len(Portfolios.for_user(user)) == 1
def test_scoped_portfolio_returns_all_applications_for_portfolio_owner( portfolio, portfolio_owner): for _ in range(5): Applications.create( portfolio.owner, portfolio, "My Application", "My application", ["dev", "staging", "prod"], ) scoped_portfolio = Portfolios.get(portfolio_owner, portfolio.id) assert len(scoped_portfolio.applications) == 5 assert len(scoped_portfolio.applications[0].environments) == 3
def test_update_portfolio_role_role(portfolio, portfolio_owner): user_data = { "first_name": "New", "last_name": "User", "email": "*****@*****.**", "portfolio_role": "developer", "dod_id": "1234567890", } PortfolioRoleFactory._meta.sqlalchemy_session_persistence = "flush" member = PortfolioRoleFactory.create(portfolio=portfolio) permission_sets = [PermissionSets.EDIT_PORTFOLIO_FUNDING] updated_member = Portfolios.update_member(member, permission_sets=permission_sets) assert updated_member.portfolio == portfolio
def create_demo_portfolio(name, data): try: portfolio_owner = Users.get_or_create_by_dod_id( "2345678901", **pick( [ "permission_sets", "first_name", "last_name", "email", "service_branch", "phone_number", "citizenship", "designation", "date_latest_training", ], DEV_USERS["amanda"], ), ) # Amanda # auditor = Users.get_by_dod_id("3453453453") # Sally except NotFoundError: print("Could not find demo users; will not create demo portfolio {}". format(name)) return portfolio = Portfolios.create( user=portfolio_owner, portfolio_attrs={ "name": name, "defense_component": random_service_branch() }, ) add_task_orders_to_portfolio(portfolio) add_members_to_portfolio(portfolio) for mock_application in data["applications"]: application = Application(portfolio=portfolio, name=mock_application["name"], description="") env_names = [env["name"] for env in mock_application["environments"]] envs = Environments.create_many(portfolio.owner, application, env_names) db.session.add(application) db.session.commit()
def update_ppoc(portfolio_id): role_id = http_request.form.get("role_id") portfolio = Portfolios.get(g.current_user, portfolio_id) new_ppoc_role = PortfolioRoles.get_by_id(role_id) PortfolioRoles.make_ppoc(portfolio_role=new_ppoc_role) flash("primary_point_of_contact_changed", ppoc_name=new_ppoc_role.full_name) return redirect( url_for( "portfolios.admin", portfolio_id=portfolio.id, fragment="primary-point-of-contact", _anchor="primary-point-of-contact", ))
def test_scoped_portfolio_for_admin_missing_view_apps_perms( portfolio_owner, portfolio): Applications.create( portfolio.owner, portfolio, "My Application 2", "My application 2", ["dev", "staging", "prod"], ) restricted_admin = UserFactory.create() PortfolioRoleFactory.create( portfolio=portfolio, user=restricted_admin, permission_sets=[PermissionSets.get(PermissionSets.VIEW_PORTFOLIO)], ) scoped_portfolio = Portfolios.get(restricted_admin, portfolio.id) assert scoped_portfolio.id == portfolio.id assert len(portfolio.applications) == 1 assert len(scoped_portfolio.applications) == 0