diff --git a/src/dispatch/auth/permissions.py b/src/dispatch/auth/permissions.py index 98d0262a57bd..2e71742f9b62 100644 --- a/src/dispatch/auth/permissions.py +++ b/src/dispatch/auth/permissions.py @@ -438,6 +438,20 @@ def has_required_permissions( return current_user.email in participant_emails +class CaseJoinPermission(BasePermission): + def has_required_permissions( + self, + request: Request, + ) -> bool: + pk = PrimaryKeyModel(id=request.path_params["case_id"]) + current_case = case_service.get(db_session=request.state.db, case_id=pk.id) + + if current_case.visibility == Visibility.restricted: + return OrganizationAdminPermission(request=request) + + return True + + class FeedbackDeletePermission(BasePermission): def has_required_permissions( self, diff --git a/src/dispatch/case/models.py b/src/dispatch/case/models.py index e45ec42a6477..289cfbc79d04 100644 --- a/src/dispatch/case/models.py +++ b/src/dispatch/case/models.py @@ -2,7 +2,7 @@ from datetime import datetime from typing import Any, ForwardRef, List, Optional -from pydantic import validator +from pydantic import Field, validator from sqlalchemy import ( Boolean, Column, @@ -230,6 +230,7 @@ class ProjectRead(DispatchBase): id: Optional[PrimaryKey] name: NameStr color: Optional[str] + allow_self_join: Optional[bool] = Field(True, nullable=True) # Pydantic models... @@ -281,6 +282,7 @@ class CaseReadMinimal(CaseBase): closed_at: Optional[datetime] = None created_at: Optional[datetime] = None escalated_at: Optional[datetime] = None + dedicated_channel: Optional[bool] name: Optional[NameStr] project: ProjectRead reporter: Optional[ParticipantReadMinimal] diff --git a/src/dispatch/case/views.py b/src/dispatch/case/views.py index 9ca3f1c89ebc..1658ffe212c5 100644 --- a/src/dispatch/case/views.py +++ b/src/dispatch/case/views.py @@ -11,7 +11,7 @@ # NOTE: define permissions before enabling the code block below from dispatch.auth.permissions import ( CaseEditPermission, - # CaseJoinPermission, + CaseJoinPermission, PermissionsDependency, CaseViewPermission, ) @@ -27,6 +27,7 @@ from dispatch.individual.models import IndividualContactRead from .flows import ( + case_add_or_reactivate_participant_flow, case_closed_create_flow, case_delete_flow, case_escalated_create_flow, @@ -338,3 +339,25 @@ def delete_case( } ], ) from None + + +@router.post( + "/{case_id}/join", + summary="Adds an individual to a case.", + dependencies=[Depends(PermissionsDependency([CaseJoinPermission]))], +) +def join_case( + db_session: DbSession, + organization: OrganizationSlug, + case_id: PrimaryKey, + current_case: CurrentCase, + current_user: CurrentUser, + background_tasks: BackgroundTasks, +): + """Adds an individual to a case.""" + background_tasks.add_task( + case_add_or_reactivate_participant_flow, + current_user.email, + case_id=current_case.id, + organization_slug=organization, + ) diff --git a/src/dispatch/static/dispatch/src/case/CaseStatus.vue b/src/dispatch/static/dispatch/src/case/CaseStatus.vue index 44d07d3c2601..d4dd84d67bef 100644 --- a/src/dispatch/static/dispatch/src/case/CaseStatus.vue +++ b/src/dispatch/static/dispatch/src/case/CaseStatus.vue @@ -1,10 +1,28 @@ diff --git a/src/dispatch/static/dispatch/src/case/Table.vue b/src/dispatch/static/dispatch/src/case/Table.vue index 92aeb6a9261c..0452520e4eae 100644 --- a/src/dispatch/static/dispatch/src/case/Table.vue +++ b/src/dispatch/static/dispatch/src/case/Table.vue @@ -72,7 +72,12 @@