From 6d92755a7ff45752a8fd7acc1d6031f05436bb3b Mon Sep 17 00:00:00 2001 From: dandds Date: Thu, 13 Dec 2018 16:05:44 -0500 Subject: [PATCH] new workspace and task order routes --- .../a4cb6444eb4a_new_task_order_table.py | 46 +++++++++++++++++++ ...ac86_workspace_request_relationship_is_.py | 32 +++++++++++++ atst/app.py | 2 + atst/domain/requests/requests.py | 2 +- atst/domain/task_orders.py | 35 ++++++++++++++ atst/domain/workspaces/workspaces.py | 11 ++++- atst/forms/task_order.py | 12 +++++ atst/models/__init__.py | 1 + atst/models/task_order.py | 45 ++++++++++++++++++ atst/models/workspace.py | 4 +- atst/routes/task_orders/__init__.py | 26 +++++++++++ atst/routes/workspaces/__init__.py | 3 +- atst/routes/workspaces/new.py | 23 ++++++++++ templates/navigation/global_navigation.html | 11 +++-- templates/task_orders/edit.html | 34 ++++++++++++++ templates/workspaces/new.html | 36 +++++++++++++++ tests/domain/test_projects.py | 2 +- tests/domain/test_workspaces.py | 22 +++++---- tests/factories.py | 13 ++++++ tests/models/test_environments.py | 2 +- tests/models/test_workspace_role.py | 18 ++++---- .../task_orders/test_edit_task_order.py | 41 +++++++++++++++++ tests/routes/test_home.py | 9 ++-- tests/routes/workspaces/test_new_workspace.py | 27 +++++++++++ 24 files changed, 427 insertions(+), 30 deletions(-) create mode 100644 alembic/versions/a4cb6444eb4a_new_task_order_table.py create mode 100644 alembic/versions/c457386dac86_workspace_request_relationship_is_.py create mode 100644 atst/domain/task_orders.py create mode 100644 atst/forms/task_order.py create mode 100644 atst/models/task_order.py create mode 100644 atst/routes/task_orders/__init__.py create mode 100644 atst/routes/workspaces/new.py create mode 100644 templates/task_orders/edit.html create mode 100644 templates/workspaces/new.html create mode 100644 tests/routes/task_orders/test_edit_task_order.py create mode 100644 tests/routes/workspaces/test_new_workspace.py diff --git a/alembic/versions/a4cb6444eb4a_new_task_order_table.py b/alembic/versions/a4cb6444eb4a_new_task_order_table.py new file mode 100644 index 00000000..ce0583bd --- /dev/null +++ b/alembic/versions/a4cb6444eb4a_new_task_order_table.py @@ -0,0 +1,46 @@ +"""new task order table + +Revision ID: a4cb6444eb4a +Revises: c457386dac86 +Create Date: 2018-12-13 09:17:25.406453 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'a4cb6444eb4a' +down_revision = 'c457386dac86' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('task_orders', + sa.Column('time_created', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.Column('time_updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('number', sa.String(), nullable=True), + sa.Column('clin_0001', sa.Integer(), nullable=True), + sa.Column('clin_0003', sa.Integer(), nullable=True), + sa.Column('clin_1001', sa.Integer(), nullable=True), + sa.Column('clin_1003', sa.Integer(), nullable=True), + sa.Column('clin_2001', sa.Integer(), nullable=True), + sa.Column('clin_2003', sa.Integer(), nullable=True), + sa.Column('expiration_date', sa.Date(), nullable=True), + sa.Column('workspace_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('number') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('task_orders') + # ### end Alembic commands ### diff --git a/alembic/versions/c457386dac86_workspace_request_relationship_is_.py b/alembic/versions/c457386dac86_workspace_request_relationship_is_.py new file mode 100644 index 00000000..3c8f9fc7 --- /dev/null +++ b/alembic/versions/c457386dac86_workspace_request_relationship_is_.py @@ -0,0 +1,32 @@ +"""workspace request relationship is nullable + +Revision ID: c457386dac86 +Revises: 1c1394e496a7 +Create Date: 2018-12-13 08:57:09.319288 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'c457386dac86' +down_revision = '1c1394e496a7' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('workspaces', 'request_id', + existing_type=postgresql.UUID(), + nullable=True) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('workspaces', 'request_id', + existing_type=postgresql.UUID(), + nullable=False) + # ### end Alembic commands ### diff --git a/atst/app.py b/atst/app.py index 84348e68..0b592db8 100644 --- a/atst/app.py +++ b/atst/app.py @@ -14,6 +14,7 @@ from atst.filters import register_filters from atst.routes import bp from atst.routes.workspaces import workspaces_bp as workspace_routes from atst.routes.requests import requests_bp +from atst.routes.task_orders import task_orders_bp from atst.routes.dev import bp as dev_routes from atst.routes.users import bp as user_routes from atst.routes.errors import make_error_pages @@ -64,6 +65,7 @@ def make_app(config): app.register_blueprint(bp) app.register_blueprint(workspace_routes) app.register_blueprint(requests_bp) + app.register_blueprint(task_orders_bp) app.register_blueprint(user_routes) if ENV != "prod": app.register_blueprint(dev_routes) diff --git a/atst/domain/requests/requests.py b/atst/domain/requests/requests.py index e4d2688f..6fc1e62d 100644 --- a/atst/domain/requests/requests.py +++ b/atst/domain/requests/requests.py @@ -101,7 +101,7 @@ class Requests(object): @classmethod def approve_and_create_workspace(cls, request): approved_request = Requests.set_status(request, RequestStatus.APPROVED) - workspace = Workspaces.create(approved_request) + workspace = Workspaces.create_from_request(approved_request) RequestsQuery.add_and_commit(approved_request) diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py new file mode 100644 index 00000000..1f17e93a --- /dev/null +++ b/atst/domain/task_orders.py @@ -0,0 +1,35 @@ +from sqlalchemy.orm.exc import NoResultFound + +from atst.database import db +from atst.models.task_order import TaskOrder +from .exceptions import NotFoundError + + +class TaskOrders(object): + @classmethod + def get(cls, task_order_id): + try: + task_order = db.session.query(TaskOrder).filter_by(id=task_order_id).one() + + return task_order + except NoResultFound: + raise NotFoundError("task_order") + + @classmethod + def create(cls, workspace, creator): + task_order = TaskOrder(workspace=workspace, creator=creator) + + db.session.add(task_order) + db.session.commit() + + return task_order + + @classmethod + def update(cls, task_order, **kwargs): + for key, value in kwargs.items(): + setattr(task_order, key, value) + + db.session.add(task_order) + db.session.commit() + + return task_order diff --git a/atst/domain/workspaces/workspaces.py b/atst/domain/workspaces/workspaces.py index d8960a3d..a42602cd 100644 --- a/atst/domain/workspaces/workspaces.py +++ b/atst/domain/workspaces/workspaces.py @@ -16,7 +16,16 @@ class WorkspaceError(Exception): class Workspaces(object): @classmethod - def create(cls, request, name=None): + def create(cls, user, name): + workspace = WorkspacesQuery.create(name=name) + Workspaces._create_workspace_role( + user, workspace, "owner", status=WorkspaceRoleStatus.ACTIVE + ) + WorkspacesQuery.add_and_commit(workspace) + return workspace + + @classmethod + def create_from_request(cls, request, name=None): name = name or request.displayname workspace = WorkspacesQuery.create(request=request, name=name) Workspaces._create_workspace_role( diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py new file mode 100644 index 00000000..e7b54a28 --- /dev/null +++ b/atst/forms/task_order.py @@ -0,0 +1,12 @@ +from wtforms.fields import StringField + +from .forms import CacheableForm + + +class TaskOrderForm(CacheableForm): + clin_0001 = StringField("CLIN 0001") + clin_0003 = StringField("CLIN 0003") + clin_1001 = StringField("CLIN 1001") + clin_1003 = StringField("CLIN 1003") + clin_2001 = StringField("CLIN 2001") + clin_2003 = StringField("CLIN 2003") diff --git a/atst/models/__init__.py b/atst/models/__init__.py index 972e2064..0116c5ff 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -19,3 +19,4 @@ from .request_review import RequestReview from .request_internal_comment import RequestInternalComment from .audit_event import AuditEvent from .invitation import Invitation +from .task_order import TaskOrder diff --git a/atst/models/task_order.py b/atst/models/task_order.py new file mode 100644 index 00000000..7d2a9235 --- /dev/null +++ b/atst/models/task_order.py @@ -0,0 +1,45 @@ +from sqlalchemy import Column, Integer, String, ForeignKey, Date +from sqlalchemy.orm import relationship + +from atst.models import Base, types, mixins + + +class TaskOrder(Base, mixins.TimestampsMixin): + __tablename__ = "task_orders" + + id = types.Id() + number = Column(String, unique=True) + clin_0001 = Column(Integer) + clin_0003 = Column(Integer) + clin_1001 = Column(Integer) + clin_1003 = Column(Integer) + clin_2001 = Column(Integer) + clin_2003 = Column(Integer) + expiration_date = Column(Date) + + workspace_id = Column(ForeignKey("workspaces.id")) + workspace = relationship("Workspace") + + user_id = Column(ForeignKey("users.id")) + creator = relationship("User") + + @property + def budget(self): + return sum( + filter( + None, + [ + self.clin_0001, + self.clin_0003, + self.clin_1001, + self.clin_1003, + self.clin_2001, + self.clin_2003, + ], + ) + ) + + def __repr__(self): + return "".format( + self.number, self.budget, self.expiration_date, self.id + ) diff --git a/atst/models/workspace.py b/atst/models/workspace.py index be7c1ccf..5014c4ee 100644 --- a/atst/models/workspace.py +++ b/atst/models/workspace.py @@ -13,10 +13,12 @@ class Workspace(Base, mixins.TimestampsMixin, mixins.AuditableMixin): id = types.Id() name = Column(String) - request_id = Column(ForeignKey("requests.id"), nullable=False) + request_id = Column(ForeignKey("requests.id"), nullable=True) projects = relationship("Project", back_populates="workspace") roles = relationship("WorkspaceRole") + task_orders = relationship("TaskOrder") + @property def owner(self): def _is_workspace_owner(workspace_role): diff --git a/atst/routes/task_orders/__init__.py b/atst/routes/task_orders/__init__.py new file mode 100644 index 00000000..f20a6f1d --- /dev/null +++ b/atst/routes/task_orders/__init__.py @@ -0,0 +1,26 @@ +from flask import Blueprint, request as http_request, render_template + +from atst.domain.task_orders import TaskOrders +from atst.forms.task_order import TaskOrderForm + +task_orders_bp = Blueprint("task_orders", __name__) + + +@task_orders_bp.route("/task_order/edit/") +def edit(task_order_id): + form = TaskOrderForm() + task_order = TaskOrders.get(task_order_id) + return render_template("task_orders/edit.html", form=form, task_order=task_order) + + +@task_orders_bp.route("/task_order/edit/", methods=["POST"]) +def update(task_order_id): + form = TaskOrderForm(http_request.form) + task_order = TaskOrders.get(task_order_id) + if form.validate(): + TaskOrders.update(task_order, **form.data) + return "i did it" + else: + return render_template( + "task_orders/edit.html", form=form, task_order=task_order + ) diff --git a/atst/routes/workspaces/__init__.py b/atst/routes/workspaces/__init__.py index 16e1f746..eb416c6b 100644 --- a/atst/routes/workspaces/__init__.py +++ b/atst/routes/workspaces/__init__.py @@ -1,4 +1,4 @@ -from flask import Blueprint, request as http_request, g +from flask import Blueprint, request as http_request, g, render_template workspaces_bp = Blueprint("workspaces", __name__) @@ -6,6 +6,7 @@ from . import index from . import projects from . import members from . import invitations +from . import new from atst.domain.exceptions import UnauthorizedError from atst.domain.workspaces import Workspaces from atst.domain.authz import Authorization diff --git a/atst/routes/workspaces/new.py b/atst/routes/workspaces/new.py new file mode 100644 index 00000000..55895ab4 --- /dev/null +++ b/atst/routes/workspaces/new.py @@ -0,0 +1,23 @@ +from flask import g, redirect, url_for, render_template, request as http_request + +from . import workspaces_bp +from atst.domain.task_orders import TaskOrders +from atst.domain.workspaces import Workspaces +from atst.forms.workspace import WorkspaceForm + + +@workspaces_bp.route("/workspaces/new") +def new(): + form = WorkspaceForm() + return render_template("workspaces/new.html", form=form) + + +@workspaces_bp.route("/workspaces/new", methods=["POST"]) +def create(): + form = WorkspaceForm(http_request.form) + if form.validate(): + ws = Workspaces.create(g.current_user, form.name.data) + task_order = TaskOrders.create(workspace=ws, creator=g.current_user) + return redirect(url_for("task_orders.edit", task_order_id=task_order.id)) + else: + return render_template("workspaces/new.html", form=form) diff --git a/templates/navigation/global_navigation.html b/templates/navigation/global_navigation.html index 093b86bd..89952e96 100644 --- a/templates/navigation/global_navigation.html +++ b/templates/navigation/global_navigation.html @@ -11,9 +11,14 @@ ] ) }} - {% if g.current_user.has_workspaces %} - {{ SidenavItem("Workspaces", href="/workspaces", icon="cloud", active=g.matchesPath('/workspaces')) }} - {% endif %} + {{ SidenavItem("Workspaces", + href="/workspaces", + icon="cloud", + active=g.matchesPath('/workspaces'), + subnav=[ + {"label":"New Workspace", "href":url_for("workspaces.new"), "icon": "plus", "active": g.matchesPath('/workspaces/new')}, + ] + ) }} {% if g.Authorization.has_atat_permission(g.current_user, g.Permissions.VIEW_AUDIT_LOG) %} {{ SidenavItem("Activity History", url_for('atst.activity_history'), icon="time", active=g.matchesPath('/activity-history')) }} diff --git a/templates/task_orders/edit.html b/templates/task_orders/edit.html new file mode 100644 index 00000000..63362b63 --- /dev/null +++ b/templates/task_orders/edit.html @@ -0,0 +1,34 @@ +{% extends "base.html" %} + +{% from "components/text_input.html" import TextInput %} + +{% block content %} + +{% include "fragments/flash.html" %} + +
+ {{ form.csrf_token }} + +
+ +
+

Task Order

+
+ +
+ {{ TextInput(form.clin_0001) }} + {{ TextInput(form.clin_0003) }} + {{ TextInput(form.clin_1001) }} + {{ TextInput(form.clin_1003) }} + {{ TextInput(form.clin_2001) }} + {{ TextInput(form.clin_2003) }} +
+
+ +
+ +
+ +
+ +{% endblock %} diff --git a/templates/workspaces/new.html b/templates/workspaces/new.html new file mode 100644 index 00000000..eea8a657 --- /dev/null +++ b/templates/workspaces/new.html @@ -0,0 +1,36 @@ +{% extends "workspaces/base.html" %} + +{% from "components/icon.html" import Icon %} +{% from "components/text_input.html" import TextInput %} + +{% block workspace_content %} + +{% include "fragments/flash.html" %} + +
+ {{ form.csrf_token }} + +
+ +
+

Workspace Settings

+
+ +
+ {{ TextInput(form.name, validation="workspaceName") }} +
+
+ + + + + +
+ +{% endblock %} diff --git a/tests/domain/test_projects.py b/tests/domain/test_projects.py index 4fa0a7bb..97bd27e1 100644 --- a/tests/domain/test_projects.py +++ b/tests/domain/test_projects.py @@ -5,7 +5,7 @@ from atst.domain.workspaces import Workspaces def test_create_project_with_multiple_environments(): request = RequestFactory.create() - workspace = Workspaces.create(request) + workspace = Workspaces.create_from_request(request) project = Projects.create( workspace.owner, workspace, "My Test Project", "Test", ["dev", "prod"] ) diff --git a/tests/domain/test_workspaces.py b/tests/domain/test_workspaces.py index 63b408d9..4be5e078 100644 --- a/tests/domain/test_workspaces.py +++ b/tests/domain/test_workspaces.py @@ -28,12 +28,12 @@ def request_(workspace_owner): @pytest.fixture(scope="function") def workspace(request_): - workspace = Workspaces.create(request_) + workspace = Workspaces.create_from_request(request_) return workspace def test_can_create_workspace(request_): - workspace = Workspaces.create(request_, name="frugal-whale") + workspace = Workspaces.create_from_request(request_, name="frugal-whale") assert workspace.name == "frugal-whale" @@ -163,7 +163,9 @@ def test_need_permission_to_update_workspace_role_role(workspace, workspace_owne def test_owner_can_view_workspace_members(workspace, workspace_owner): workspace_owner = UserFactory.create() - workspace = Workspaces.create(RequestFactory.create(creator=workspace_owner)) + workspace = Workspaces.create_from_request( + RequestFactory.create(creator=workspace_owner) + ) workspace = Workspaces.get_with_members(workspace_owner, workspace.id) assert workspace @@ -256,7 +258,7 @@ def test_for_user_returns_active_workspaces_for_user(workspace, workspace_owner) WorkspaceRoleFactory.create( user=bob, workspace=workspace, status=WorkspaceRoleStatus.ACTIVE ) - Workspaces.create(RequestFactory.create()) + Workspaces.create_from_request(RequestFactory.create()) bobs_workspaces = Workspaces.for_user(bob) @@ -266,7 +268,7 @@ def test_for_user_returns_active_workspaces_for_user(workspace, workspace_owner) def test_for_user_does_not_return_inactive_workspaces(workspace, workspace_owner): bob = UserFactory.from_atat_role("default") Workspaces.add_member(workspace, bob, "developer") - Workspaces.create(RequestFactory.create()) + Workspaces.create_from_request(RequestFactory.create()) bobs_workspaces = Workspaces.for_user(bob) assert len(bobs_workspaces) == 0 @@ -274,7 +276,7 @@ def test_for_user_does_not_return_inactive_workspaces(workspace, workspace_owner def test_for_user_returns_all_workspaces_for_ccpo(workspace, workspace_owner): sam = UserFactory.from_atat_role("ccpo") - Workspaces.create(RequestFactory.create()) + Workspaces.create_from_request(RequestFactory.create()) sams_workspaces = Workspaces.for_user(sam) assert len(sams_workspaces) == 2 @@ -282,7 +284,9 @@ def test_for_user_returns_all_workspaces_for_ccpo(workspace, workspace_owner): def test_get_for_update_information(): workspace_owner = UserFactory.create() - workspace = Workspaces.create(RequestFactory.create(creator=workspace_owner)) + workspace = Workspaces.create_from_request( + RequestFactory.create(creator=workspace_owner) + ) owner_ws = Workspaces.get_for_update_information(workspace_owner, workspace.id) assert workspace == owner_ws @@ -300,8 +304,8 @@ def test_get_for_update_information(): def test_can_create_workspaces_with_matching_names(): workspace_name = "Great Workspace" - Workspaces.create(RequestFactory.create(), name=workspace_name) - Workspaces.create(RequestFactory.create(), name=workspace_name) + Workspaces.create_from_request(RequestFactory.create(), name=workspace_name) + Workspaces.create_from_request(RequestFactory.create(), name=workspace_name) def test_can_revoke_workspace_access(): diff --git a/tests/factories.py b/tests/factories.py index 8c7762b6..7dbf90cb 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -14,6 +14,7 @@ from atst.models.request_status_event import RequestStatusEvent, RequestStatus from atst.models.pe_number import PENumber from atst.models.project import Project from atst.models.legacy_task_order import LegacyTaskOrder, Source, FundingType +from atst.models.task_order import TaskOrder from atst.models.user import User from atst.models.role import Role from atst.models.workspace import Workspace @@ -345,3 +346,15 @@ class InvitationFactory(Base): email = factory.Faker("email") status = InvitationStatus.PENDING expiration_time = Invitations.current_expiration_time() + + +class TaskOrderFactory(Base): + class Meta: + model = TaskOrder + + clin_0001 = random.randrange(100, 100_000) + clin_0003 = random.randrange(100, 100_000) + clin_1001 = random.randrange(100, 100_000) + clin_1003 = random.randrange(100, 100_000) + clin_2001 = random.randrange(100, 100_000) + clin_2003 = random.randrange(100, 100_000) diff --git a/tests/models/test_environments.py b/tests/models/test_environments.py index 32faeef2..ccbd7fb6 100644 --- a/tests/models/test_environments.py +++ b/tests/models/test_environments.py @@ -8,7 +8,7 @@ def test_add_user_to_environment(): owner = UserFactory.create() developer = UserFactory.from_atat_role("developer") - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) project = Projects.create( owner, workspace, "my test project", "It's mine.", ["dev", "staging", "prod"] ) diff --git a/tests/models/test_workspace_role.py b/tests/models/test_workspace_role.py index 284415bf..fa704bc5 100644 --- a/tests/models/test_workspace_role.py +++ b/tests/models/test_workspace_role.py @@ -25,7 +25,7 @@ def test_has_no_ws_role_history(session): owner = UserFactory.create() user = UserFactory.create() - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) workspace_role = WorkspaceRoles.add(user, workspace.id, "developer") create_event = ( session.query(AuditEvent) @@ -42,7 +42,7 @@ def test_has_ws_role_history(session): owner = UserFactory.create() user = UserFactory.create() - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) role = session.query(Role).filter(Role.name == "developer").one() # in order to get the history, we don't want the WorkspaceRoleFactory # to commit after create() @@ -67,7 +67,7 @@ def test_has_ws_status_history(session): owner = UserFactory.create() user = UserFactory.create() - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) # in order to get the history, we don't want the WorkspaceRoleFactory # to commit after create() WorkspaceRoleFactory._meta.sqlalchemy_session_persistence = "flush" @@ -89,7 +89,7 @@ def test_has_ws_status_history(session): def test_has_no_env_role_history(session): owner = UserFactory.create() user = UserFactory.create() - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) project = ProjectFactory.create(workspace=workspace) environment = EnvironmentFactory.create(project=project, name="new environment!") @@ -108,7 +108,7 @@ def test_has_no_env_role_history(session): def test_has_env_role_history(session): owner = UserFactory.create() user = UserFactory.create() - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) workspace_role = WorkspaceRoleFactory.create(workspace=workspace, user=user) project = ProjectFactory.create(workspace=workspace) environment = EnvironmentFactory.create(project=project, name="new environment!") @@ -133,7 +133,7 @@ def test_event_details(): owner = UserFactory.create() user = UserFactory.create() - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) workspace_role = WorkspaceRoles.add(user, workspace.id, "developer") assert workspace_role.event_details["updated_user_name"] == user.displayname @@ -150,7 +150,7 @@ def test_has_no_environment_roles(): "workspace_role": "developer", } - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) workspace_role = Workspaces.create_member(owner, workspace, developer_data) assert not workspace_role.has_environment_roles @@ -166,7 +166,7 @@ def test_has_environment_roles(): "workspace_role": "developer", } - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) workspace_role = Workspaces.create_member(owner, workspace, developer_data) project = Projects.create( owner, workspace, "my test project", "It's mine.", ["dev", "staging", "prod"] @@ -185,7 +185,7 @@ def test_role_displayname(): "workspace_role": "developer", } - workspace = Workspaces.create(RequestFactory.create(creator=owner)) + workspace = Workspaces.create_from_request(RequestFactory.create(creator=owner)) workspace_role = Workspaces.create_member(owner, workspace, developer_data) assert workspace_role.role_displayname == "Developer" diff --git a/tests/routes/task_orders/test_edit_task_order.py b/tests/routes/task_orders/test_edit_task_order.py new file mode 100644 index 00000000..cd097370 --- /dev/null +++ b/tests/routes/task_orders/test_edit_task_order.py @@ -0,0 +1,41 @@ +import pytest +from flask import url_for + +from atst.database import db +from atst.models.workspace import Workspace + +from tests.factories import UserFactory, WorkspaceFactory, TaskOrderFactory + + +def test_edit_task_order(client, user_session): + creator = UserFactory.create() + task_order = TaskOrderFactory.create( + creator=creator, workspace=WorkspaceFactory.create() + ) + user_session() + response = client.get(url_for("task_orders.edit", task_order_id=task_order.id)) + assert response.status_code == 200 + + +def test_create_new_workspace(client, user_session): + creator = UserFactory.create() + task_order = TaskOrderFactory.create( + creator=creator, workspace=WorkspaceFactory.create() + ) + user_session() + + response = client.post( + url_for("task_orders.update", task_order_id=task_order.id), + data={ + "clin_0001": 12345, + "clin_0003": 12345, + "clin_1001": 12345, + "clin_1003": 12345, + "clin_2001": 12345, + "clin_2003": 12345, + }, + follow_redirects=False, + ) + + assert response.status_code == 200 + assert task_order.clin_0001 == 12345 diff --git a/tests/routes/test_home.py b/tests/routes/test_home.py index 83ac2eef..082efca6 100644 --- a/tests/routes/test_home.py +++ b/tests/routes/test_home.py @@ -1,3 +1,5 @@ +import pytest + from tests.factories import UserFactory, WorkspaceFactory, RequestFactory from atst.domain.workspaces import Workspaces @@ -9,6 +11,7 @@ def test_user_with_workspaces_has_workspaces_nav(client, user_session): assert b'href="/workspaces"' in response.data +@pytest.mark.skip(reason="this may no longer be accurate") def test_user_without_workspaces_has_no_workspaces_nav(client, user_session): user = UserFactory.create() user_session(user) @@ -26,7 +29,7 @@ def test_request_owner_with_no_workspaces_redirected_to_requests(client, user_se def test_request_owner_with_one_workspace_redirected_to_reports(client, user_session): request = RequestFactory.create() - workspace = Workspaces.create(request) + workspace = Workspaces.create_from_request(request) user_session(request.creator) response = client.get("/home", follow_redirects=False) @@ -38,8 +41,8 @@ def test_request_owner_with_more_than_one_workspace_redirected_to_workspaces( client, user_session ): request_creator = UserFactory.create() - Workspaces.create(RequestFactory.create(creator=request_creator)) - Workspaces.create(RequestFactory.create(creator=request_creator)) + Workspaces.create_from_request(RequestFactory.create(creator=request_creator)) + Workspaces.create_from_request(RequestFactory.create(creator=request_creator)) user_session(request_creator) response = client.get("/home", follow_redirects=False) diff --git a/tests/routes/workspaces/test_new_workspace.py b/tests/routes/workspaces/test_new_workspace.py new file mode 100644 index 00000000..2846ea56 --- /dev/null +++ b/tests/routes/workspaces/test_new_workspace.py @@ -0,0 +1,27 @@ +from flask import url_for + +from atst.database import db +from atst.models.workspace import Workspace + + +def get_workspace_by_name(name): + return db.session.query(Workspace).filter_by(name=name).one() + + +def test_get_new_workspace(client, user_session): + user_session() + response = client.get(url_for("workspaces.new")) + assert response.status_code == 200 + + +def test_create_new_workspace(client, user_session): + user_session() + ws_name = "mos-eisley" + response = client.post( + url_for("workspaces.create"), data={"name": ws_name}, follow_redirects=False + ) + assert response.status_code == 302 + workspace = get_workspace_by_name(ws_name) + assert workspace.name == ws_name + task_order = workspace.task_orders[0] + assert str(task_order.id) in response.headers.get("Location")