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 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 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 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 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_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 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
def test_scoped_portfolio_returns_all_applications_for_portfolio_admin( portfolio, portfolio_owner): for _ in range(5): Applications.create( portfolio.owner, portfolio, "My Application", "My application", ["dev", "staging", "prod"], ) admin = UserFactory.create() perm_sets = get_all_portfolio_permission_sets() PortfolioRoleFactory.create(user=admin, portfolio=portfolio, permission_sets=perm_sets) scoped_portfolio = Portfolios.get(admin, portfolio.id) assert len(scoped_portfolio.applications) == 5 assert len(scoped_portfolio.applications[0].environments) == 3
def reports(portfolio_id): portfolio = Portfolios.get(g.current_user, portfolio_id) current_obligated_funds = Reports.obligated_funds_by_JEDI_clin(portfolio) if any(map(lambda clin: clin["remaining"] < 0, current_obligated_funds)): flash("insufficient_funds") # wrapped in str() because the sum of obligated funds returns a Decimal object total_portfolio_value = str( sum(task_order.total_obligated_funds for task_order in portfolio.active_task_orders)) return render_template( "portfolios/reports/index.html", portfolio=portfolio, total_portfolio_value=total_portfolio_value, current_obligated_funds=current_obligated_funds, expired_task_orders=Reports.expired_task_orders(portfolio), monthly_spending=Reports.monthly_spending(portfolio), retrieved=datetime.now(), # mocked datetime of reporting data retrival )
def reports(portfolio_id): portfolio = Portfolios.get(g.current_user, portfolio_id) today = date.today() current_month = date(int(today.year), int(today.month), 15) prev_month = current_month - timedelta(days=28) # wrapped in str() because the sum of obligated funds returns a Decimal object total_portfolio_value = str( sum( task_order.total_obligated_funds for task_order in portfolio.active_task_orders ) ) return render_template( "portfolios/reports/index.html", portfolio=portfolio, total_portfolio_value=total_portfolio_value, current_obligated_funds=Reports.obligated_funds_by_JEDI_clin(portfolio), expired_task_orders=Reports.expired_task_orders(portfolio), monthly_totals=Reports.monthly_totals(portfolio), current_month=current_month, prev_month=prev_month, now=datetime.now(), # mocked datetime of reporting data retrival )
def test_get_nonexistent_portfolio_raises(): with pytest.raises(NotFoundError): Portfolios.get(UserFactory.build(), uuid4())