Remove request-related models
This commit is contained in:
parent
6fb333acb9
commit
2c62f54b83
@ -225,8 +225,6 @@ class MockReportingProvider(ReportingInterface):
|
|||||||
def get_budget(self, portfolio):
|
def get_budget(self, portfolio):
|
||||||
if portfolio.name in self.REPORT_FIXTURE_MAP:
|
if portfolio.name in self.REPORT_FIXTURE_MAP:
|
||||||
return self.REPORT_FIXTURE_MAP[portfolio.name]["budget"]
|
return self.REPORT_FIXTURE_MAP[portfolio.name]["budget"]
|
||||||
elif portfolio.request and portfolio.legacy_task_order:
|
|
||||||
return portfolio.legacy_task_order.budget
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_total_spending(self, portfolio):
|
def get_total_spending(self, portfolio):
|
||||||
|
@ -2,8 +2,6 @@ from sqlalchemy.ext.declarative import declarative_base
|
|||||||
|
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
from .request import Request
|
|
||||||
from .request_status_event import RequestStatusEvent
|
|
||||||
from .permissions import Permissions
|
from .permissions import Permissions
|
||||||
from .role import Role
|
from .role import Role
|
||||||
from .user import User
|
from .user import User
|
||||||
@ -14,9 +12,6 @@ from .portfolio import Portfolio
|
|||||||
from .application import Application
|
from .application import Application
|
||||||
from .environment import Environment
|
from .environment import Environment
|
||||||
from .attachment import Attachment
|
from .attachment import Attachment
|
||||||
from .request_revision import RequestRevision
|
|
||||||
from .request_review import RequestReview
|
|
||||||
from .request_internal_comment import RequestInternalComment
|
|
||||||
from .audit_event import AuditEvent
|
from .audit_event import AuditEvent
|
||||||
from .invitation import Invitation
|
from .invitation import Invitation
|
||||||
from .task_order import TaskOrder
|
from .task_order import TaskOrder
|
||||||
|
@ -17,9 +17,6 @@ class AuditEvent(Base, TimestampsMixin):
|
|||||||
portfolio_id = Column(UUID(as_uuid=True), ForeignKey("portfolios.id"), index=True)
|
portfolio_id = Column(UUID(as_uuid=True), ForeignKey("portfolios.id"), index=True)
|
||||||
portfolio = relationship("Portfolio", backref="audit_events")
|
portfolio = relationship("Portfolio", backref="audit_events")
|
||||||
|
|
||||||
request_id = Column(UUID(as_uuid=True), ForeignKey("requests.id"), index=True)
|
|
||||||
request = relationship("Request", backref="audit_events")
|
|
||||||
|
|
||||||
changed_state = Column(JSONB())
|
changed_state = Column(JSONB())
|
||||||
event_details = Column(JSONB())
|
event_details = Column(JSONB())
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ class AuditableMixin(object):
|
|||||||
def create_audit_event(connection, resource, action):
|
def create_audit_event(connection, resource, action):
|
||||||
user_id = getattr_path(g, "current_user.id")
|
user_id = getattr_path(g, "current_user.id")
|
||||||
portfolio_id = resource.portfolio_id
|
portfolio_id = resource.portfolio_id
|
||||||
request_id = resource.request_id
|
|
||||||
resource_type = resource.resource_type
|
resource_type = resource.resource_type
|
||||||
display_name = resource.displayname
|
display_name = resource.displayname
|
||||||
event_details = resource.event_details
|
event_details = resource.event_details
|
||||||
@ -24,7 +23,6 @@ class AuditableMixin(object):
|
|||||||
audit_event = AuditEvent(
|
audit_event = AuditEvent(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
portfolio_id=portfolio_id,
|
portfolio_id=portfolio_id,
|
||||||
request_id=request_id,
|
|
||||||
resource_type=resource_type,
|
resource_type=resource_type,
|
||||||
resource_id=resource.id,
|
resource_id=resource.id,
|
||||||
display_name=display_name,
|
display_name=display_name,
|
||||||
@ -91,10 +89,6 @@ class AuditableMixin(object):
|
|||||||
def portfolio_id(self):
|
def portfolio_id(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
|
||||||
def request_id(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def displayname(self):
|
def displayname(self):
|
||||||
return None
|
return None
|
||||||
|
@ -13,7 +13,6 @@ class Portfolio(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|||||||
|
|
||||||
id = types.Id()
|
id = types.Id()
|
||||||
name = Column(String)
|
name = Column(String)
|
||||||
request_id = Column(ForeignKey("requests.id"), nullable=True)
|
|
||||||
applications = relationship("Application", back_populates="portfolio")
|
applications = relationship("Application", back_populates="portfolio")
|
||||||
roles = relationship("PortfolioRole")
|
roles = relationship("PortfolioRole")
|
||||||
|
|
||||||
@ -35,10 +34,6 @@ class Portfolio(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|||||||
def user_count(self):
|
def user_count(self):
|
||||||
return len(self.members)
|
return len(self.members)
|
||||||
|
|
||||||
@property
|
|
||||||
def legacy_task_order(self):
|
|
||||||
return self.request.legacy_task_order if self.request else None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def members(self):
|
def members(self):
|
||||||
return (
|
return (
|
||||||
@ -60,6 +55,6 @@ class Portfolio(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Portfolio(name='{}', request='{}', user_count='{}', id='{}')>".format(
|
return "<Portfolio(name='{}', user_count='{}', id='{}')>".format(
|
||||||
self.name, self.request_id, self.user_count, self.id
|
self.name, self.user_count, self.id
|
||||||
)
|
)
|
||||||
|
@ -1,256 +0,0 @@
|
|||||||
from sqlalchemy import Column, func, ForeignKey
|
|
||||||
from sqlalchemy.types import DateTime
|
|
||||||
from sqlalchemy.orm import relationship
|
|
||||||
|
|
||||||
from atst.models import Base, types, mixins
|
|
||||||
from atst.models.request_status_event import RequestStatus
|
|
||||||
from atst.utils import first_or_none
|
|
||||||
from atst.models.request_revision import RequestRevision
|
|
||||||
from atst.models.legacy_task_order import Source as TaskOrderSource
|
|
||||||
|
|
||||||
|
|
||||||
def map_properties_to_dict(properties, instance):
|
|
||||||
return {
|
|
||||||
field: getattr(instance, field)
|
|
||||||
for field in properties
|
|
||||||
if getattr(instance, field) is not None
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def update_dict_with_properties(instance, body, top_level_key, properties):
|
|
||||||
new_properties = map_properties_to_dict(properties, instance)
|
|
||||||
if new_properties:
|
|
||||||
body[top_level_key] = new_properties
|
|
||||||
|
|
||||||
return body
|
|
||||||
|
|
||||||
|
|
||||||
class Request(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|
||||||
__tablename__ = "requests"
|
|
||||||
|
|
||||||
id = types.Id()
|
|
||||||
time_created = Column(DateTime(timezone=True), server_default=func.now())
|
|
||||||
status_events = relationship(
|
|
||||||
"RequestStatusEvent", backref="request", order_by="RequestStatusEvent.sequence"
|
|
||||||
)
|
|
||||||
|
|
||||||
portfolio = relationship("Portfolio", uselist=False, backref="request")
|
|
||||||
|
|
||||||
user_id = Column(ForeignKey("users.id"), nullable=False)
|
|
||||||
creator = relationship("User", backref="owned_requests")
|
|
||||||
|
|
||||||
legacy_task_order_id = Column(ForeignKey("legacy_task_orders.id"))
|
|
||||||
legacy_task_order = relationship("LegacyTaskOrder")
|
|
||||||
|
|
||||||
revisions = relationship(
|
|
||||||
"RequestRevision", back_populates="request", order_by="RequestRevision.sequence"
|
|
||||||
)
|
|
||||||
|
|
||||||
internal_comments = relationship("RequestInternalComment")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def latest_revision(self):
|
|
||||||
if self.revisions:
|
|
||||||
return self.revisions[-1]
|
|
||||||
|
|
||||||
else:
|
|
||||||
return RequestRevision(request=self)
|
|
||||||
|
|
||||||
PRIMARY_POC_FIELDS = ["am_poc", "dodid_poc", "email_poc", "fname_poc", "lname_poc"]
|
|
||||||
DETAILS_OF_USE_FIELDS = [
|
|
||||||
"jedi_usage",
|
|
||||||
"start_date",
|
|
||||||
"cloud_native",
|
|
||||||
"dollar_value",
|
|
||||||
"dod_component",
|
|
||||||
"data_transfers",
|
|
||||||
"expected_completion_date",
|
|
||||||
"jedi_migration",
|
|
||||||
"num_software_systems",
|
|
||||||
"number_user_sessions",
|
|
||||||
"average_daily_traffic",
|
|
||||||
"engineering_assessment",
|
|
||||||
"technical_support_team",
|
|
||||||
"estimated_monthly_spend",
|
|
||||||
"average_daily_traffic_gb",
|
|
||||||
"rationalization_software_systems",
|
|
||||||
"organization_providing_assistance",
|
|
||||||
"name",
|
|
||||||
]
|
|
||||||
INFORMATION_ABOUT_YOU_FIELDS = [
|
|
||||||
"citizenship",
|
|
||||||
"designation",
|
|
||||||
"phone_number",
|
|
||||||
"phone_ext",
|
|
||||||
"email_request",
|
|
||||||
"fname_request",
|
|
||||||
"lname_request",
|
|
||||||
"service_branch",
|
|
||||||
"date_latest_training",
|
|
||||||
]
|
|
||||||
FINANCIAL_VERIFICATION_FIELDS = [
|
|
||||||
"pe_id",
|
|
||||||
"task_order_number",
|
|
||||||
"fname_co",
|
|
||||||
"lname_co",
|
|
||||||
"email_co",
|
|
||||||
"office_co",
|
|
||||||
"fname_cor",
|
|
||||||
"lname_cor",
|
|
||||||
"email_cor",
|
|
||||||
"office_cor",
|
|
||||||
"uii_ids",
|
|
||||||
"treasury_code",
|
|
||||||
"ba_code",
|
|
||||||
]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def body(self):
|
|
||||||
current = self.latest_revision
|
|
||||||
body = {}
|
|
||||||
for top_level_key, properties in [
|
|
||||||
("primary_poc", Request.PRIMARY_POC_FIELDS),
|
|
||||||
("details_of_use", Request.DETAILS_OF_USE_FIELDS),
|
|
||||||
("information_about_you", Request.INFORMATION_ABOUT_YOU_FIELDS),
|
|
||||||
("financial_verification", Request.FINANCIAL_VERIFICATION_FIELDS),
|
|
||||||
]:
|
|
||||||
body = update_dict_with_properties(current, body, top_level_key, properties)
|
|
||||||
|
|
||||||
return body
|
|
||||||
|
|
||||||
@property
|
|
||||||
def latest_status(self):
|
|
||||||
return self.status_events[-1] if self.status_events else None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def status(self):
|
|
||||||
return self.latest_status.new_status if self.latest_status else None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def status_displayname(self):
|
|
||||||
return self.latest_status.displayname
|
|
||||||
|
|
||||||
@property
|
|
||||||
def annual_spend(self):
|
|
||||||
monthly = self.latest_revision.estimated_monthly_spend or 0
|
|
||||||
return monthly * 12
|
|
||||||
|
|
||||||
@property
|
|
||||||
def financial_verification(self):
|
|
||||||
return self.body.get("financial_verification", {})
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_financially_verified(self):
|
|
||||||
if self.legacy_task_order:
|
|
||||||
return self.legacy_task_order.verified
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
|
||||||
def last_submission_timestamp(self):
|
|
||||||
def _is_submission(status_event):
|
|
||||||
return status_event.new_status == RequestStatus.SUBMITTED
|
|
||||||
|
|
||||||
last_submission = first_or_none(_is_submission, reversed(self.status_events))
|
|
||||||
if last_submission:
|
|
||||||
return last_submission.time_created
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def action_required_by(self):
|
|
||||||
return {
|
|
||||||
RequestStatus.PENDING_FINANCIAL_VERIFICATION: "mission_owner",
|
|
||||||
RequestStatus.CHANGES_REQUESTED: "mission_owner",
|
|
||||||
RequestStatus.CHANGES_REQUESTED_TO_FINVER: "mission_owner",
|
|
||||||
RequestStatus.PENDING_CCPO_APPROVAL: "ccpo",
|
|
||||||
RequestStatus.PENDING_CCPO_ACCEPTANCE: "ccpo",
|
|
||||||
}.get(self.status)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def reviews(self):
|
|
||||||
return [status.review for status in self.status_events if status.review]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_pending_financial_verification(self):
|
|
||||||
return self.status == RequestStatus.PENDING_FINANCIAL_VERIFICATION
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_pending_financial_verification_changes(self):
|
|
||||||
return self.status == RequestStatus.CHANGES_REQUESTED_TO_FINVER
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_pending_ccpo_acceptance(self):
|
|
||||||
return self.status == RequestStatus.PENDING_CCPO_ACCEPTANCE
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_pending_ccpo_approval(self):
|
|
||||||
return self.status == RequestStatus.PENDING_CCPO_APPROVAL
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_pending_ccpo_action(self):
|
|
||||||
return self.is_pending_ccpo_acceptance or self.is_pending_ccpo_approval
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_approved(self):
|
|
||||||
return self.status == RequestStatus.APPROVED
|
|
||||||
|
|
||||||
@property
|
|
||||||
def review_comment(self):
|
|
||||||
if (
|
|
||||||
self.status == RequestStatus.CHANGES_REQUESTED
|
|
||||||
or self.status == RequestStatus.CHANGES_REQUESTED_TO_FINVER
|
|
||||||
):
|
|
||||||
review = self.latest_status.review
|
|
||||||
if review: # pragma: no branch
|
|
||||||
return review.comment
|
|
||||||
|
|
||||||
@property
|
|
||||||
def has_financial_data(self):
|
|
||||||
return (
|
|
||||||
self.is_pending_ccpo_approval
|
|
||||||
or self.is_pending_financial_verification_changes
|
|
||||||
or self.is_approved
|
|
||||||
) and self.legacy_task_order
|
|
||||||
|
|
||||||
@property
|
|
||||||
def displayname(self):
|
|
||||||
return self.latest_revision.name or self.id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def contracting_officer_full_name(self):
|
|
||||||
if self.latest_revision.fname_co:
|
|
||||||
return "{} {}".format(
|
|
||||||
self.latest_revision.fname_co, self.latest_revision.lname_co
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def contracting_officer_email(self):
|
|
||||||
return self.latest_revision.email_co
|
|
||||||
|
|
||||||
@property
|
|
||||||
def pe_number(self):
|
|
||||||
return self.body.get("financial_verification", {}).get("pe_id")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def has_manual_task_order(self):
|
|
||||||
return (
|
|
||||||
self.legacy_task_order.source == TaskOrderSource.MANUAL
|
|
||||||
if self.legacy_task_order is not None
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def last_finver_draft_saved_at(self):
|
|
||||||
if self.latest_revision.any_finver_fields_saved:
|
|
||||||
return self.latest_revision.time_updated
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<Request(status='{}', name='{}', creator='{}', is_approved='{}', time_created='{}', id='{}')>".format(
|
|
||||||
self.status_displayname,
|
|
||||||
self.displayname,
|
|
||||||
self.creator.full_name,
|
|
||||||
self.is_approved,
|
|
||||||
self.time_created,
|
|
||||||
self.id,
|
|
||||||
)
|
|
@ -1,22 +0,0 @@
|
|||||||
from sqlalchemy import Column, String, ForeignKey
|
|
||||||
from sqlalchemy.orm import relationship
|
|
||||||
|
|
||||||
from atst.models import Base, types, mixins
|
|
||||||
|
|
||||||
|
|
||||||
class RequestInternalComment(Base, mixins.TimestampsMixin):
|
|
||||||
__tablename__ = "request_internal_comments"
|
|
||||||
|
|
||||||
id = types.Id()
|
|
||||||
text = Column(String(), nullable=False)
|
|
||||||
|
|
||||||
user_id = Column(ForeignKey("users.id"), nullable=False)
|
|
||||||
user = relationship("User")
|
|
||||||
|
|
||||||
request_id = Column(ForeignKey("requests.id", ondelete="CASCADE"), nullable=False)
|
|
||||||
request = relationship("Request")
|
|
||||||
|
|
||||||
def __repr__(self): # pragma: no cover
|
|
||||||
return "<RequestInternalComment(text='{}', user='{}', request='{}', id='{}')>".format(
|
|
||||||
self.text, self.user.full_name, self.request_id, self.id
|
|
||||||
)
|
|
@ -1,43 +0,0 @@
|
|||||||
from sqlalchemy import Column, String, ForeignKey
|
|
||||||
from sqlalchemy.orm import relationship
|
|
||||||
|
|
||||||
from atst.models import Base, mixins, types
|
|
||||||
|
|
||||||
|
|
||||||
class RequestReview(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|
||||||
__tablename__ = "request_reviews"
|
|
||||||
|
|
||||||
id = types.Id()
|
|
||||||
status = relationship("RequestStatusEvent", uselist=False, back_populates="review")
|
|
||||||
|
|
||||||
user_id = Column(ForeignKey("users.id"))
|
|
||||||
reviewer = relationship("User")
|
|
||||||
|
|
||||||
comment = Column(String)
|
|
||||||
fname_mao = Column(String)
|
|
||||||
lname_mao = Column(String)
|
|
||||||
email_mao = Column(String)
|
|
||||||
phone_mao = Column(String)
|
|
||||||
phone_ext_mao = Column(String)
|
|
||||||
fname_ccpo = Column(String)
|
|
||||||
lname_ccpo = Column(String)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def full_name_reviewer(self):
|
|
||||||
if self.reviewer:
|
|
||||||
return self.reviewer.full_name
|
|
||||||
else:
|
|
||||||
return "System"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def full_name_mao(self):
|
|
||||||
return "{} {}".format(self.fname_mao, self.lname_mao)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def full_name_ccpo(self):
|
|
||||||
return "{} {}".format(self.fname_ccpo, self.lname_ccpo)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<RequestReview(status='{}', comment='{}', reviewer='{}', id='{}')>".format(
|
|
||||||
self.status.log_name, self.comment, self.full_name_reviewer, self.id
|
|
||||||
)
|
|
@ -1,106 +0,0 @@
|
|||||||
from sqlalchemy import (
|
|
||||||
Column,
|
|
||||||
ForeignKey,
|
|
||||||
String,
|
|
||||||
Boolean,
|
|
||||||
Integer,
|
|
||||||
Date,
|
|
||||||
BigInteger,
|
|
||||||
Sequence,
|
|
||||||
)
|
|
||||||
from sqlalchemy.orm import relationship
|
|
||||||
from sqlalchemy.dialects.postgresql import ARRAY
|
|
||||||
|
|
||||||
from atst.models import Base
|
|
||||||
from atst.models import mixins
|
|
||||||
from atst.models.types import Id
|
|
||||||
|
|
||||||
|
|
||||||
class RequestRevision(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|
||||||
__tablename__ = "request_revisions"
|
|
||||||
|
|
||||||
id = Id()
|
|
||||||
request_id = Column(ForeignKey("requests.id"), nullable=False)
|
|
||||||
request = relationship("Request", back_populates="revisions")
|
|
||||||
sequence = Column(
|
|
||||||
BigInteger, Sequence("request_revisions_sequence_seq"), nullable=False
|
|
||||||
)
|
|
||||||
|
|
||||||
# primary_poc
|
|
||||||
am_poc = Column(Boolean)
|
|
||||||
dodid_poc = Column(String)
|
|
||||||
email_poc = Column(String)
|
|
||||||
fname_poc = Column(String)
|
|
||||||
lname_poc = Column(String)
|
|
||||||
|
|
||||||
# details_of_use
|
|
||||||
jedi_usage = Column(String)
|
|
||||||
start_date = Column(Date)
|
|
||||||
cloud_native = Column(String)
|
|
||||||
dollar_value = Column(Integer)
|
|
||||||
dod_component = Column(String)
|
|
||||||
data_transfers = Column(String)
|
|
||||||
expected_completion_date = Column(String)
|
|
||||||
jedi_migration = Column(String)
|
|
||||||
num_software_systems = Column(Integer)
|
|
||||||
number_user_sessions = Column(Integer)
|
|
||||||
average_daily_traffic = Column(Integer)
|
|
||||||
engineering_assessment = Column(String)
|
|
||||||
technical_support_team = Column(String)
|
|
||||||
estimated_monthly_spend = Column(Integer)
|
|
||||||
average_daily_traffic_gb = Column(Integer)
|
|
||||||
rationalization_software_systems = Column(String)
|
|
||||||
organization_providing_assistance = Column(String)
|
|
||||||
name = Column(String)
|
|
||||||
|
|
||||||
# information_about_you
|
|
||||||
citizenship = Column(String)
|
|
||||||
designation = Column(String)
|
|
||||||
phone_number = Column(String)
|
|
||||||
phone_ext = Column(String)
|
|
||||||
email_request = Column(String)
|
|
||||||
fname_request = Column(String)
|
|
||||||
lname_request = Column(String)
|
|
||||||
service_branch = Column(String)
|
|
||||||
date_latest_training = Column(Date)
|
|
||||||
|
|
||||||
# financial_verification
|
|
||||||
pe_id = Column(String)
|
|
||||||
task_order_number = Column(String)
|
|
||||||
fname_co = Column(String)
|
|
||||||
lname_co = Column(String)
|
|
||||||
email_co = Column(String)
|
|
||||||
office_co = Column(String)
|
|
||||||
fname_cor = Column(String)
|
|
||||||
lname_cor = Column(String)
|
|
||||||
email_cor = Column(String)
|
|
||||||
office_cor = Column(String)
|
|
||||||
uii_ids = Column(ARRAY(String))
|
|
||||||
treasury_code = Column(String)
|
|
||||||
ba_code = Column(String)
|
|
||||||
|
|
||||||
def __repr__(self): # pragma: no cover
|
|
||||||
return "<RequestRevision(request='{}', id='{}')>".format(
|
|
||||||
self.request_id, self.id
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def any_finver_fields_saved(self):
|
|
||||||
return any(
|
|
||||||
getattr(self, n, None)
|
|
||||||
for n in [
|
|
||||||
"pe_id",
|
|
||||||
"task_order_number",
|
|
||||||
"fname_co",
|
|
||||||
"lname_co",
|
|
||||||
"email_co",
|
|
||||||
"office_co",
|
|
||||||
"fname_cor",
|
|
||||||
"lname_cor",
|
|
||||||
"email_cor",
|
|
||||||
"office_cor",
|
|
||||||
"uii_ids",
|
|
||||||
"treasury_code",
|
|
||||||
"ba_code",
|
|
||||||
]
|
|
||||||
)
|
|
@ -1,62 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
from sqlalchemy import Column, ForeignKey, Enum as SQLAEnum
|
|
||||||
from sqlalchemy.orm import relationship
|
|
||||||
from sqlalchemy.types import BigInteger
|
|
||||||
from sqlalchemy.schema import Sequence
|
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
|
||||||
|
|
||||||
from atst.models import Base, mixins
|
|
||||||
from atst.models.types import Id
|
|
||||||
|
|
||||||
|
|
||||||
class RequestStatus(Enum):
|
|
||||||
STARTED = "Started"
|
|
||||||
SUBMITTED = "Submitted"
|
|
||||||
PENDING_FINANCIAL_VERIFICATION = "Pending Financial Verification"
|
|
||||||
PENDING_CCPO_ACCEPTANCE = "Pending CCPO Acceptance"
|
|
||||||
PENDING_CCPO_APPROVAL = "Pending CCPO Approval"
|
|
||||||
CHANGES_REQUESTED = "Changes Requested"
|
|
||||||
CHANGES_REQUESTED_TO_FINVER = "Change Requested to Financial Verification"
|
|
||||||
APPROVED = "Approved"
|
|
||||||
EXPIRED = "Expired"
|
|
||||||
DELETED = "Deleted"
|
|
||||||
|
|
||||||
|
|
||||||
class RequestStatusEvent(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|
||||||
__tablename__ = "request_status_events"
|
|
||||||
|
|
||||||
id = Id()
|
|
||||||
new_status = Column(SQLAEnum(RequestStatus, native_enum=False))
|
|
||||||
request_id = Column(
|
|
||||||
UUID(as_uuid=True),
|
|
||||||
ForeignKey("requests.id", ondelete="CASCADE"),
|
|
||||||
nullable=False,
|
|
||||||
)
|
|
||||||
sequence = Column(
|
|
||||||
BigInteger, Sequence("request_status_events_sequence_seq"), nullable=False
|
|
||||||
)
|
|
||||||
request_revision_id = Column(ForeignKey("request_revisions.id"), nullable=False)
|
|
||||||
revision = relationship("RequestRevision")
|
|
||||||
|
|
||||||
request_review_id = Column(ForeignKey("request_reviews.id"), nullable=True)
|
|
||||||
review = relationship("RequestReview", back_populates="status")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def displayname(self):
|
|
||||||
return self.new_status.value if self.new_status else None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def log_name(self):
|
|
||||||
if self.new_status == RequestStatus.CHANGES_REQUESTED:
|
|
||||||
return "Denied"
|
|
||||||
if self.new_status == RequestStatus.CHANGES_REQUESTED_TO_FINVER:
|
|
||||||
return "Denied"
|
|
||||||
elif self.new_status == RequestStatus.PENDING_FINANCIAL_VERIFICATION:
|
|
||||||
return "Accepted"
|
|
||||||
else:
|
|
||||||
return self.displayname
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<RequestStatusEvent(log_name='{}', request='{}', id='{}')>".format(
|
|
||||||
self.log_name, self.request_id, self.id
|
|
||||||
)
|
|
@ -6,7 +6,6 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Portfolio Name</th>
|
<th>Portfolio Name</th>
|
||||||
<th>Task Order</th>
|
|
||||||
<th>Users</th>
|
<th>Users</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -16,9 +15,6 @@
|
|||||||
<td>
|
<td>
|
||||||
<a class='icon-link icon-link--large' href="/portfolios/{{ portfolio.id }}/applications">{{ portfolio.name }}</a><br>
|
<a class='icon-link icon-link--large' href="/portfolios/{{ portfolio.id }}/applications">{{ portfolio.name }}</a><br>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
#{{ portfolio.legacy_task_order.number }}
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span class="label">{{ portfolio.user_count }}</span><span class='h6'>Users</span>
|
<span class="label">{{ portfolio.user_count }}</span><span class='h6'>Users</span>
|
||||||
</td>
|
</td>
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
from atst.domain.applications import Applications
|
from atst.domain.applications import Applications
|
||||||
from tests.factories import RequestFactory, UserFactory, PortfolioFactory
|
from tests.factories import UserFactory, PortfolioFactory
|
||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
|
|
||||||
|
|
||||||
def test_create_application_with_multiple_environments():
|
def test_create_application_with_multiple_environments():
|
||||||
request = RequestFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
portfolio = Portfolios.create_from_request(request)
|
|
||||||
application = Applications.create(
|
application = Applications.create(
|
||||||
portfolio.owner, portfolio, "My Test Application", "Test", ["dev", "prod"]
|
portfolio.owner, portfolio, "My Test Application", "Test", ["dev", "prod"]
|
||||||
)
|
)
|
||||||
|
@ -8,12 +8,7 @@ from atst.domain.applications import Applications
|
|||||||
from atst.domain.environments import Environments
|
from atst.domain.environments import Environments
|
||||||
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
||||||
|
|
||||||
from tests.factories import (
|
from tests.factories import UserFactory, PortfolioRoleFactory, PortfolioFactory
|
||||||
RequestFactory,
|
|
||||||
UserFactory,
|
|
||||||
PortfolioRoleFactory,
|
|
||||||
PortfolioFactory,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
@ -22,39 +17,21 @@ def portfolio_owner():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def request_(portfolio_owner):
|
def portfolio(portfolio_owner):
|
||||||
return RequestFactory.create(creator=portfolio_owner)
|
portfolio = PortfolioFactory.create(owner=portfolio_owner)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
|
||||||
def portfolio(request_):
|
|
||||||
portfolio = Portfolios.create_from_request(request_)
|
|
||||||
return portfolio
|
return portfolio
|
||||||
|
|
||||||
|
|
||||||
def test_can_create_portfolio(request_):
|
def test_can_create_portfolio():
|
||||||
portfolio = Portfolios.create_from_request(request_, name="frugal-whale")
|
portfolio = PortfolioFactory.create(name="frugal-whale")
|
||||||
assert portfolio.name == "frugal-whale"
|
assert portfolio.name == "frugal-whale"
|
||||||
|
|
||||||
|
|
||||||
def test_request_is_associated_with_portfolio(portfolio, request_):
|
|
||||||
assert portfolio.request == request_
|
|
||||||
|
|
||||||
|
|
||||||
def test_default_portfolio_name_is_request_name(portfolio, request_):
|
|
||||||
assert portfolio.name == str(request_.displayname)
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_nonexistent_portfolio_raises():
|
def test_get_nonexistent_portfolio_raises():
|
||||||
with pytest.raises(NotFoundError):
|
with pytest.raises(NotFoundError):
|
||||||
Portfolios.get(UserFactory.build(), uuid4())
|
Portfolios.get(UserFactory.build(), uuid4())
|
||||||
|
|
||||||
|
|
||||||
def test_can_get_portfolio_by_request(portfolio):
|
|
||||||
found = Portfolios.get_by_request(portfolio.request)
|
|
||||||
assert portfolio == found
|
|
||||||
|
|
||||||
|
|
||||||
def test_creating_portfolio_adds_owner(portfolio, portfolio_owner):
|
def test_creating_portfolio_adds_owner(portfolio, portfolio_owner):
|
||||||
assert portfolio.roles[0].user == portfolio_owner
|
assert portfolio.roles[0].user == portfolio_owner
|
||||||
|
|
||||||
@ -162,10 +139,6 @@ def test_need_permission_to_update_portfolio_role_role(portfolio, portfolio_owne
|
|||||||
|
|
||||||
|
|
||||||
def test_owner_can_view_portfolio_members(portfolio, portfolio_owner):
|
def test_owner_can_view_portfolio_members(portfolio, portfolio_owner):
|
||||||
portfolio_owner = UserFactory.create()
|
|
||||||
portfolio = Portfolios.create_from_request(
|
|
||||||
RequestFactory.create(creator=portfolio_owner)
|
|
||||||
)
|
|
||||||
portfolio = Portfolios.get_with_members(portfolio_owner, portfolio.id)
|
portfolio = Portfolios.get_with_members(portfolio_owner, portfolio.id)
|
||||||
|
|
||||||
assert portfolio
|
assert portfolio
|
||||||
@ -258,7 +231,7 @@ def test_for_user_returns_active_portfolios_for_user(portfolio, portfolio_owner)
|
|||||||
PortfolioRoleFactory.create(
|
PortfolioRoleFactory.create(
|
||||||
user=bob, portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE
|
user=bob, portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE
|
||||||
)
|
)
|
||||||
Portfolios.create_from_request(RequestFactory.create())
|
PortfolioFactory.create()
|
||||||
|
|
||||||
bobs_portfolios = Portfolios.for_user(bob)
|
bobs_portfolios = Portfolios.for_user(bob)
|
||||||
|
|
||||||
@ -268,7 +241,7 @@ def test_for_user_returns_active_portfolios_for_user(portfolio, portfolio_owner)
|
|||||||
def test_for_user_does_not_return_inactive_portfolios(portfolio, portfolio_owner):
|
def test_for_user_does_not_return_inactive_portfolios(portfolio, portfolio_owner):
|
||||||
bob = UserFactory.from_atat_role("default")
|
bob = UserFactory.from_atat_role("default")
|
||||||
Portfolios.add_member(portfolio, bob, "developer")
|
Portfolios.add_member(portfolio, bob, "developer")
|
||||||
Portfolios.create_from_request(RequestFactory.create())
|
PortfolioFactory.create()
|
||||||
bobs_portfolios = Portfolios.for_user(bob)
|
bobs_portfolios = Portfolios.for_user(bob)
|
||||||
|
|
||||||
assert len(bobs_portfolios) == 0
|
assert len(bobs_portfolios) == 0
|
||||||
@ -276,17 +249,13 @@ def test_for_user_does_not_return_inactive_portfolios(portfolio, portfolio_owner
|
|||||||
|
|
||||||
def test_for_user_returns_all_portfolios_for_ccpo(portfolio, portfolio_owner):
|
def test_for_user_returns_all_portfolios_for_ccpo(portfolio, portfolio_owner):
|
||||||
sam = UserFactory.from_atat_role("ccpo")
|
sam = UserFactory.from_atat_role("ccpo")
|
||||||
Portfolios.create_from_request(RequestFactory.create())
|
PortfolioFactory.create()
|
||||||
|
|
||||||
sams_portfolios = Portfolios.for_user(sam)
|
sams_portfolios = Portfolios.for_user(sam)
|
||||||
assert len(sams_portfolios) == 2
|
assert len(sams_portfolios) == 2
|
||||||
|
|
||||||
|
|
||||||
def test_get_for_update_information():
|
def test_get_for_update_information(portfolio, portfolio_owner):
|
||||||
portfolio_owner = UserFactory.create()
|
|
||||||
portfolio = Portfolios.create_from_request(
|
|
||||||
RequestFactory.create(creator=portfolio_owner)
|
|
||||||
)
|
|
||||||
owner_ws = Portfolios.get_for_update_information(portfolio_owner, portfolio.id)
|
owner_ws = Portfolios.get_for_update_information(portfolio_owner, portfolio.id)
|
||||||
assert portfolio == owner_ws
|
assert portfolio == owner_ws
|
||||||
|
|
||||||
@ -307,8 +276,8 @@ def test_get_for_update_information():
|
|||||||
|
|
||||||
def test_can_create_portfolios_with_matching_names():
|
def test_can_create_portfolios_with_matching_names():
|
||||||
portfolio_name = "Great Portfolio"
|
portfolio_name = "Great Portfolio"
|
||||||
Portfolios.create_from_request(RequestFactory.create(), name=portfolio_name)
|
PortfolioFactory.create(name=portfolio_name)
|
||||||
Portfolios.create_from_request(RequestFactory.create(), name=portfolio_name)
|
PortfolioFactory.create(name=portfolio_name)
|
||||||
|
|
||||||
|
|
||||||
def test_able_to_revoke_portfolio_access_for_active_member():
|
def test_able_to_revoke_portfolio_access_for_active_member():
|
||||||
|
@ -1,27 +1,17 @@
|
|||||||
from atst.domain.reports import Reports
|
from atst.domain.reports import Reports
|
||||||
|
|
||||||
from tests.factories import RequestFactory, LegacyTaskOrderFactory, PortfolioFactory
|
from tests.factories import PortfolioFactory
|
||||||
|
|
||||||
CLIN_NUMS = ["0001", "0003", "1001", "1003", "2001", "2003"]
|
|
||||||
|
|
||||||
|
|
||||||
def test_portfolio_totals():
|
def test_portfolio_totals():
|
||||||
legacy_task_order = LegacyTaskOrderFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
|
|
||||||
for num in CLIN_NUMS:
|
|
||||||
setattr(legacy_task_order, "clin_{}".format(num), 200)
|
|
||||||
|
|
||||||
request = RequestFactory.create(legacy_task_order=legacy_task_order)
|
|
||||||
portfolio = PortfolioFactory.create(request=request)
|
|
||||||
report = Reports.portfolio_totals(portfolio)
|
report = Reports.portfolio_totals(portfolio)
|
||||||
total = 200 * len(CLIN_NUMS)
|
assert report == {"budget": 0, "spent": 0}
|
||||||
assert report == {"budget": total, "spent": 0}
|
|
||||||
|
|
||||||
|
|
||||||
# this is sketched in until we do real reporting
|
# this is sketched in until we do real reporting
|
||||||
def test_monthly_totals():
|
def test_monthly_totals():
|
||||||
request = RequestFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
portfolio = PortfolioFactory.create(request=request)
|
|
||||||
monthly = Reports.monthly_totals(portfolio)
|
monthly = Reports.monthly_totals(portfolio)
|
||||||
|
|
||||||
assert not monthly["environments"]
|
assert not monthly["environments"]
|
||||||
@ -31,8 +21,7 @@ def test_monthly_totals():
|
|||||||
|
|
||||||
# this is sketched in until we do real reporting
|
# this is sketched in until we do real reporting
|
||||||
def test_cumulative_budget():
|
def test_cumulative_budget():
|
||||||
request = RequestFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
portfolio = PortfolioFactory.create(request=request)
|
|
||||||
months = Reports.cumulative_budget(portfolio)
|
months = Reports.cumulative_budget(portfolio)
|
||||||
|
|
||||||
assert len(months["months"]) >= 12
|
assert len(months["months"]) >= 12
|
||||||
|
@ -9,10 +9,6 @@ from faker import Faker as _Faker
|
|||||||
from atst.forms import data
|
from atst.forms import data
|
||||||
from atst.models.attachment import Attachment
|
from atst.models.attachment import Attachment
|
||||||
from atst.models.environment import Environment
|
from atst.models.environment import Environment
|
||||||
from atst.models.request import Request
|
|
||||||
from atst.models.request_revision import RequestRevision
|
|
||||||
from atst.models.request_review import RequestReview
|
|
||||||
from atst.models.request_status_event import RequestStatusEvent, RequestStatus
|
|
||||||
from atst.models.pe_number import PENumber
|
from atst.models.pe_number import PENumber
|
||||||
from atst.models.application import Application
|
from atst.models.application import Application
|
||||||
from atst.models.legacy_task_order import LegacyTaskOrder, Source, FundingType
|
from atst.models.legacy_task_order import LegacyTaskOrder, Source, FundingType
|
||||||
@ -105,142 +101,6 @@ class UserFactory(Base):
|
|||||||
return cls.create(atat_role=role, **kwargs)
|
return cls.create(atat_role=role, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class RequestStatusEventFactory(Base):
|
|
||||||
class Meta:
|
|
||||||
model = RequestStatusEvent
|
|
||||||
|
|
||||||
id = factory.Sequence(lambda x: uuid4())
|
|
||||||
sequence = 1
|
|
||||||
|
|
||||||
|
|
||||||
class RequestRevisionFactory(Base):
|
|
||||||
class Meta:
|
|
||||||
model = RequestRevision
|
|
||||||
|
|
||||||
id = factory.Sequence(lambda x: uuid4())
|
|
||||||
|
|
||||||
|
|
||||||
class RequestReviewFactory(Base):
|
|
||||||
class Meta:
|
|
||||||
model = RequestReview
|
|
||||||
|
|
||||||
comment = factory.Faker("sentence")
|
|
||||||
fname_mao = factory.Faker("first_name")
|
|
||||||
lname_mao = factory.Faker("last_name")
|
|
||||||
email_mao = factory.Faker("email")
|
|
||||||
phone_mao = factory.LazyFunction(
|
|
||||||
lambda: "".join(random.choices(string.digits, k=10))
|
|
||||||
)
|
|
||||||
fname_ccpo = factory.Faker("first_name")
|
|
||||||
lname_ccpo = factory.Faker("last_name")
|
|
||||||
|
|
||||||
|
|
||||||
class RequestFactory(Base):
|
|
||||||
class Meta:
|
|
||||||
model = Request
|
|
||||||
|
|
||||||
id = factory.Sequence(lambda x: uuid4())
|
|
||||||
creator = factory.SubFactory(UserFactory)
|
|
||||||
revisions = factory.LazyAttribute(
|
|
||||||
lambda r: [RequestFactory.create_initial_revision(r)]
|
|
||||||
)
|
|
||||||
status_events = factory.RelatedFactory(
|
|
||||||
RequestStatusEventFactory,
|
|
||||||
"request",
|
|
||||||
new_status=RequestStatus.STARTED,
|
|
||||||
revision=factory.LazyAttribute(lambda se: se.factory_parent.revisions[-1]),
|
|
||||||
)
|
|
||||||
|
|
||||||
class Params:
|
|
||||||
initial_revision = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _adjust_kwargs(cls, **kwargs):
|
|
||||||
if kwargs.pop("with_task_order", False) and "legacy_task_order" not in kwargs:
|
|
||||||
kwargs["legacy_task_order"] = LegacyTaskOrderFactory.build()
|
|
||||||
return kwargs
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create_initial_status_event(cls, request):
|
|
||||||
return RequestStatusEventFactory(
|
|
||||||
request=request,
|
|
||||||
new_status=RequestStatus.STARTED,
|
|
||||||
revision=request.revisions,
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create_initial_revision(cls, request, dollar_value=1_000_000):
|
|
||||||
user = request.creator
|
|
||||||
default_data = dict(
|
|
||||||
name=factory.Faker("domain_word"),
|
|
||||||
am_poc=False,
|
|
||||||
dodid_poc=user.dod_id,
|
|
||||||
email_poc=user.email,
|
|
||||||
fname_poc=user.first_name,
|
|
||||||
lname_poc=user.last_name,
|
|
||||||
jedi_usage="adf",
|
|
||||||
start_date=datetime.date(2050, 1, 1),
|
|
||||||
cloud_native="yes",
|
|
||||||
dollar_value=dollar_value,
|
|
||||||
dod_component=random_service_branch(),
|
|
||||||
data_transfers="Less than 100GB",
|
|
||||||
expected_completion_date="Less than 1 month",
|
|
||||||
jedi_migration="yes",
|
|
||||||
num_software_systems=1,
|
|
||||||
number_user_sessions=2,
|
|
||||||
average_daily_traffic=1,
|
|
||||||
engineering_assessment="yes",
|
|
||||||
technical_support_team="yes",
|
|
||||||
estimated_monthly_spend=100,
|
|
||||||
average_daily_traffic_gb=4,
|
|
||||||
rationalization_software_systems="yes",
|
|
||||||
organization_providing_assistance="In-house staff",
|
|
||||||
citizenship="United States",
|
|
||||||
designation="military",
|
|
||||||
phone_number="1234567890",
|
|
||||||
phone_ext="123",
|
|
||||||
email_request=user.email,
|
|
||||||
fname_request=user.first_name,
|
|
||||||
lname_request=user.last_name,
|
|
||||||
service_branch=random_service_branch(),
|
|
||||||
date_latest_training=datetime.date(2018, 8, 6),
|
|
||||||
)
|
|
||||||
|
|
||||||
data = (
|
|
||||||
request.initial_revision
|
|
||||||
if request.initial_revision is not None
|
|
||||||
else default_data
|
|
||||||
)
|
|
||||||
|
|
||||||
return RequestRevisionFactory.build(**data)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create_with_status(cls, status=RequestStatus.STARTED, **kwargs):
|
|
||||||
request = RequestFactory(**kwargs)
|
|
||||||
RequestStatusEventFactory.create(
|
|
||||||
request=request, revision=request.latest_revision, new_status=status
|
|
||||||
)
|
|
||||||
return request
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def mock_financial_data(cls):
|
|
||||||
fake = _Faker()
|
|
||||||
return {
|
|
||||||
"pe_id": "0101110F",
|
|
||||||
"fname_co": fake.first_name(),
|
|
||||||
"lname_co": fake.last_name(),
|
|
||||||
"email_co": fake.email(),
|
|
||||||
"office_co": fake.phone_number(),
|
|
||||||
"fname_cor": fake.first_name(),
|
|
||||||
"lname_cor": fake.last_name(),
|
|
||||||
"email_cor": fake.email(),
|
|
||||||
"office_cor": fake.phone_number(),
|
|
||||||
"uii_ids": "123abc",
|
|
||||||
"treasury_code": "00123456",
|
|
||||||
"ba_code": "02A",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PENumberFactory(Base):
|
class PENumberFactory(Base):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PENumber
|
model = PENumber
|
||||||
@ -269,9 +129,7 @@ class PortfolioFactory(Base):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Portfolio
|
model = Portfolio
|
||||||
|
|
||||||
request = factory.SubFactory(RequestFactory, with_task_order=True)
|
name = factory.Faker("name")
|
||||||
# name it the same as the request ID by default
|
|
||||||
name = factory.LazyAttribute(lambda w: w.request.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _create(cls, model_class, *args, **kwargs):
|
def _create(cls, model_class, *args, **kwargs):
|
||||||
@ -286,7 +144,6 @@ class PortfolioFactory(Base):
|
|||||||
for p in with_applications
|
for p in with_applications
|
||||||
]
|
]
|
||||||
|
|
||||||
portfolio.request.creator = owner
|
|
||||||
PortfolioRoleFactory.create(
|
PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio,
|
portfolio=portfolio,
|
||||||
role=Roles.get("owner"),
|
role=Roles.get("owner"),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from tests.factories import RequestFactory, UserFactory
|
from tests.factories import UserFactory
|
||||||
|
|
||||||
|
|
||||||
DOD_SDN_INFO = {"first_name": "ART", "last_name": "GARFUNKEL", "dod_id": "5892460358"}
|
DOD_SDN_INFO = {"first_name": "ART", "last_name": "GARFUNKEL", "dod_id": "5892460358"}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
from atst.domain.environments import Environments
|
from atst.domain.environments import Environments
|
||||||
from atst.domain.portfolios import Portfolios
|
|
||||||
from atst.domain.applications import Applications
|
from atst.domain.applications import Applications
|
||||||
from tests.factories import RequestFactory, UserFactory
|
from tests.factories import PortfolioFactory, UserFactory
|
||||||
|
|
||||||
|
|
||||||
def test_add_user_to_environment():
|
def test_add_user_to_environment():
|
||||||
owner = UserFactory.create()
|
owner = UserFactory.create()
|
||||||
developer = UserFactory.from_atat_role("developer")
|
developer = UserFactory.from_atat_role("developer")
|
||||||
|
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
application = Applications.create(
|
application = Applications.create(
|
||||||
owner,
|
owner,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
@ -9,7 +9,6 @@ from atst.models.invitation import Status as InvitationStatus
|
|||||||
from atst.models.audit_event import AuditEvent
|
from atst.models.audit_event import AuditEvent
|
||||||
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
||||||
from tests.factories import (
|
from tests.factories import (
|
||||||
RequestFactory,
|
|
||||||
UserFactory,
|
UserFactory,
|
||||||
InvitationFactory,
|
InvitationFactory,
|
||||||
PortfolioRoleFactory,
|
PortfolioRoleFactory,
|
||||||
@ -25,7 +24,7 @@ def test_has_no_ws_role_history(session):
|
|||||||
owner = UserFactory.create()
|
owner = UserFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
|
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
portfolio_role = PortfolioRoles.add(user, portfolio.id, "developer")
|
portfolio_role = PortfolioRoles.add(user, portfolio.id, "developer")
|
||||||
create_event = (
|
create_event = (
|
||||||
session.query(AuditEvent)
|
session.query(AuditEvent)
|
||||||
@ -42,7 +41,7 @@ def test_has_ws_role_history(session):
|
|||||||
owner = UserFactory.create()
|
owner = UserFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
|
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
role = session.query(Role).filter(Role.name == "developer").one()
|
role = session.query(Role).filter(Role.name == "developer").one()
|
||||||
# in order to get the history, we don't want the PortfolioRoleFactory
|
# in order to get the history, we don't want the PortfolioRoleFactory
|
||||||
# to commit after create()
|
# to commit after create()
|
||||||
@ -67,7 +66,7 @@ def test_has_ws_status_history(session):
|
|||||||
owner = UserFactory.create()
|
owner = UserFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
|
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
# in order to get the history, we don't want the PortfolioRoleFactory
|
# in order to get the history, we don't want the PortfolioRoleFactory
|
||||||
# to commit after create()
|
# to commit after create()
|
||||||
PortfolioRoleFactory._meta.sqlalchemy_session_persistence = "flush"
|
PortfolioRoleFactory._meta.sqlalchemy_session_persistence = "flush"
|
||||||
@ -89,7 +88,7 @@ def test_has_ws_status_history(session):
|
|||||||
def test_has_no_env_role_history(session):
|
def test_has_no_env_role_history(session):
|
||||||
owner = UserFactory.create()
|
owner = UserFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
application = ApplicationFactory.create(portfolio=portfolio)
|
application = ApplicationFactory.create(portfolio=portfolio)
|
||||||
environment = EnvironmentFactory.create(
|
environment = EnvironmentFactory.create(
|
||||||
application=application, name="new environment!"
|
application=application, name="new environment!"
|
||||||
@ -110,7 +109,7 @@ def test_has_no_env_role_history(session):
|
|||||||
def test_has_env_role_history(session):
|
def test_has_env_role_history(session):
|
||||||
owner = UserFactory.create()
|
owner = UserFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=user)
|
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=user)
|
||||||
application = ApplicationFactory.create(portfolio=portfolio)
|
application = ApplicationFactory.create(portfolio=portfolio)
|
||||||
environment = EnvironmentFactory.create(
|
environment = EnvironmentFactory.create(
|
||||||
@ -137,7 +136,7 @@ def test_event_details():
|
|||||||
owner = UserFactory.create()
|
owner = UserFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
|
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
portfolio_role = PortfolioRoles.add(user, portfolio.id, "developer")
|
portfolio_role = PortfolioRoles.add(user, portfolio.id, "developer")
|
||||||
|
|
||||||
assert portfolio_role.event_details["updated_user_name"] == user.displayname
|
assert portfolio_role.event_details["updated_user_name"] == user.displayname
|
||||||
@ -154,7 +153,7 @@ def test_has_no_environment_roles():
|
|||||||
"portfolio_role": "developer",
|
"portfolio_role": "developer",
|
||||||
}
|
}
|
||||||
|
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
portfolio_role = Portfolios.create_member(owner, portfolio, developer_data)
|
portfolio_role = Portfolios.create_member(owner, portfolio, developer_data)
|
||||||
|
|
||||||
assert not portfolio_role.has_environment_roles
|
assert not portfolio_role.has_environment_roles
|
||||||
@ -170,7 +169,7 @@ def test_has_environment_roles():
|
|||||||
"portfolio_role": "developer",
|
"portfolio_role": "developer",
|
||||||
}
|
}
|
||||||
|
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
portfolio_role = Portfolios.create_member(owner, portfolio, developer_data)
|
portfolio_role = Portfolios.create_member(owner, portfolio, developer_data)
|
||||||
application = Applications.create(
|
application = Applications.create(
|
||||||
owner,
|
owner,
|
||||||
@ -195,7 +194,7 @@ def test_role_displayname():
|
|||||||
"portfolio_role": "developer",
|
"portfolio_role": "developer",
|
||||||
}
|
}
|
||||||
|
|
||||||
portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner))
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
portfolio_role = Portfolios.create_member(owner, portfolio, developer_data)
|
portfolio_role = Portfolios.create_member(owner, portfolio, developer_data)
|
||||||
|
|
||||||
assert portfolio_role.role_displayname == "Developer"
|
assert portfolio_role.role_displayname == "Developer"
|
||||||
|
@ -1,28 +1,27 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tests.factories import UserFactory, PortfolioFactory, RequestFactory
|
from tests.factories import UserFactory, PortfolioFactory
|
||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
||||||
|
|
||||||
|
|
||||||
def test_request_owner_with_one_portfolio_redirected_to_reports(client, user_session):
|
def test_portfolio_owner_with_one_portfolio_redirected_to_reports(client, user_session):
|
||||||
request = RequestFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
portfolio = Portfolios.create_from_request(request)
|
|
||||||
|
|
||||||
user_session(request.creator)
|
user_session(portfolio.owner)
|
||||||
response = client.get("/home", follow_redirects=False)
|
response = client.get("/home", follow_redirects=False)
|
||||||
|
|
||||||
assert "/portfolios/{}/reports".format(portfolio.id) in response.location
|
assert "/portfolios/{}/reports".format(portfolio.id) in response.location
|
||||||
|
|
||||||
|
|
||||||
def test_request_owner_with_more_than_one_portfolio_redirected_to_portfolios(
|
def test_portfolio_owner_with_more_than_one_portfolio_redirected_to_portfolios(
|
||||||
client, user_session
|
client, user_session
|
||||||
):
|
):
|
||||||
request_creator = UserFactory.create()
|
owner = UserFactory.create()
|
||||||
Portfolios.create_from_request(RequestFactory.create(creator=request_creator))
|
PortfolioFactory.create(owner=owner)
|
||||||
Portfolios.create_from_request(RequestFactory.create(creator=request_creator))
|
PortfolioFactory.create(owner=owner)
|
||||||
|
|
||||||
user_session(request_creator)
|
user_session(owner)
|
||||||
response = client.get("/home", follow_redirects=False)
|
response = client.get("/home", follow_redirects=False)
|
||||||
|
|
||||||
assert "/portfolios" in response.location
|
assert "/portfolios" in response.location
|
||||||
|
Loading…
x
Reference in New Issue
Block a user