Example #1
0
class InviteThirdPartyAPI(TradeRemediesApiView):
    """
    Invite a 3rd party (e.g., lawyer) to a case, by a customer.
    This invite can encompass multiple people and is tied to a
    submission.
    """

    @staticmethod
    def get(request, case_id, submission_id, *args, **kwargs):
        case = Case.objects.get(id=case_id)
        submission = Submission.objects.get(case=case, id=submission_id)
        invites = Invitation.objects.filter(submission=submission)
        return ResponseSuccess({"results": [invite.to_dict() for invite in invites]})
Example #2
0
 def post(self, request, case_id, contact_id, organisation_id, *args, **kwargs):
     try:
         contact = Contact.objects.select_related("userprofile", "organisation").get(
             id=contact_id
         )
     except Contact.DoesNotExist:
         raise NotFoundApiExceptions("Contact does not exist or access is denied")
     try:
         organisation = Organisation.objects.get(id=organisation_id)
     except Organisation.DoesNotExist:
         raise NotFoundApiExceptions("Organisation does not exist or access is denied")
     contact.set_primary(case=get_case(case_id), organisation=organisation)
     return ResponseSuccess({"result": contact.to_dict()}, http_status=status.HTTP_201_CREATED)
Example #3
0
    def post(request, code: str = None):
        """
        A multipurpose endpoint (for the moment), if code is provided it will verify the code is correct and note the
        email verification in the database.

        If code is not provided, it will send out a verification email to the request.user

        Arguments:
            request: a Django Request object
            code: an email verification code
        Returns:
            ResponseSuccess response if the email was validated / a new link was sent out.
        Raises:
            InvalidRequestParams if the link was incorrect.
        """
        if code:
            user = request.user
            try:
                profile = user.userprofile
            except UserProfile.DoesNotExist:
                profile = UserProfile.objects.filter(
                    email_verify_code=code).first()
                user = profile.user

            serializer = VerifyEmailSerializer(data={"code": code},
                                               context={"profile": profile})
            if serializer.is_valid():
                profile.email_verified_at = timezone.now()
                profile.save()
                user.refresh_from_db()
                return ResponseSuccess({"result": user.to_dict()})
            else:
                raise InvalidRequestParams(serializer.errors)
        elif not request.user.is_anonymous:
            response = request.user.userprofile.verify_email()
            return ResponseSuccess({"result": response})
        else:
            raise InvalidRequestParams("User unknown")
Example #4
0
 def post(self, request, bundle_id, document_id):
     bundle = DocumentBundle.objects.get(id=bundle_id)
     document = Document.objects.get(id=document_id)
     bundle.set_user_context(self.user)
     if bundle.case:
         document.set_case_context(bundle.case)
     document.set_user_context(self.user)
     bundle.documents.add(document)
     document.generic_audit(
         message=f"Attached to bundle {bundle.name}",
         audit_type=AUDIT_TYPE_ATTACH,
         id=str(document.id),
     )
     return ResponseSuccess({"result": bundle.to_dict()})
Example #5
0
 def get(self, request, document_id, submission_id=None, *args, **kwargs):
     document = Document.objects.get(id=document_id)
     if submission_id:
         submission = Submission.objects.get_submission(id=submission_id)
         doc_submission = SubmissionDocument.objects.get(
             submission=submission, document=document)
         doc_submission.downloads += 1
         doc_submission.save()
     return ResponseSuccess({
         "result": {
             "id": str(document.id),
             "download_url": document.download_url
         }
     })
Example #6
0
    def get(self, request, code, organisation_id, *args, **kwargs):
        try:
            organisation = Organisation.objects.get(id=organisation_id)
            invite = Invitation.objects.get(
                code=code, organisation=organisation, deleted_at__isnull=True
            )
            invited_by = invite.created_by
            invited_by_token = invited_by.auth_token.key
        except (Organisation.DoesNotExist, Invitation.DoesNotExist):
            raise NotFoundApiExceptions("Invite not found")
        response = {"organisation": organisation.to_embedded_dict(), "invite": invite.to_dict()}
        response["invite"]["invited_by"] = invited_by_token

        return ResponseSuccess({"result": response}, http_status=status.HTTP_200_OK)
Example #7
0
    def get(self,
            request,
            case_type_id=None,
            status=None,
            bundle_id=None,
            *args,
            **kwargs):
        bundle_id = bundle_id or request.query_params.get("bundle_id")
        if bundle_id:
            bundle = DocumentBundle.objects.get(id=bundle_id)
            return ResponseSuccess({"result": bundle.to_dict()})
        case_id = request.query_params.get("case_id")
        status_in_url = status
        status = status or request.query_params.get("status")
        filter_kwargs = {}
        exclude_kwargs = {}
        if case_type_id:
            filter_kwargs["case_type"] = case_type_id
        if status:
            filter_kwargs["status"] = status
        if case_id:
            filter_kwargs["case_id"] = case_id
        else:
            exclude_kwargs["case_id__isnull"] = False
        # if status_in_url:
        #     filter_kwargs['case_type__isnull'] = False

        bundles = (DocumentBundle.objects.filter(**filter_kwargs).exclude(
            status="ARCHIVED").exclude(**exclude_kwargs))
        if status_in_url:
            bundles = bundles.filter(
                Q(case_type__isnull=False) | Q(submission_type__isnull=False))

        bundles = bundles.order_by("case_type__name")
        return ResponseSuccess(
            {"result": bundles[0] and bundles[0].to_dict()} if self.
            single else {"results": [bundle.to_dict() for bundle in bundles]})
Example #8
0
    def get(
        self,
        request,
        note_id=None,
        model_id=None,
        content_type=None,
        case_id=None,
        model_key=None,
        *args,
        **kwargs,
    ):
        if note_id:
            try:
                note = Note.objects.get(id=note_id)
                return ResponseSuccess({"result": note.to_dict()})
            except Note.DoesNotExist:
                raise NotFoundApiExceptions("Invalid note id")
        else:
            notes = Note.objects.filter(deleted_at__isnull=True)
        if case_id:
            notes = notes.filter(case__id=case_id)
        if model_id and content_type:
            _content_type = get_content_type(content_type)
            if model_key:
                notes = notes.filter(model_id=model_id,
                                     content_type=_content_type,
                                     model_key=model_key)
            else:
                notes = notes.filter(model_id=model_id,
                                     content_type=_content_type)

        else:
            raise InvalidRequestParams(
                "A note id, case id or a model identifiers are required")
        notes = notes.order_by("created_at")
        return ResponseSuccess(
            {"results": [_note.to_dict() for _note in notes]})
Example #9
0
 def post(self, request, code=None, short_code=None, case_id=None, *args, **kwargs):
     if not code and not case_id and short_code:
         invitiation, organisation = Invitation.objects.validate_public_invite(
             short_code, user=request.user
         )
         return ResponseSuccess(
             {"result": {"invitation": invitiation.to_dict(), "deviation": None, "diff": None}}
         )
     else:
         invitation = Invitation.objects.get_invite_by_code(code)
         if invitation:
             invitation.process_invitation(request.user, accept=True)
             deviation, diff = invitation.compare_user_contact()
             return ResponseSuccess(
                 {
                     "result": {
                         "invitation": invitation.to_dict(),
                         "deviation": deviation,
                         "diff": diff,
                     }
                 }
             )
         else:
             raise NotFoundApiExceptions("No invitation found for this user")
Example #10
0
    def get(request, case_id=None):
        """Return all unacknowledged notify failures for a case.

        Generates report document with additional detail (if specified in `detail`
        query param).

        :param (HTTPRequest) request: request object.
        :param (str) case_id: case to report on.
        :returns (HTTPResponse): Document containing failed notifications logged
          in the audit trail.
        """
        detail = request.query_params.get("detail")
        case = get_case(case_id)
        report = get_notify_fail_report(case=case, detail=bool(detail))
        return ResponseSuccess({"result": report})
Example #11
0
    def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
        """
        Arguments:
            request: a Django Request object
        Returns:
            ResponseSuccess response with the user's token and user data
            ResponseError response if the user could not be created  #todo - raise an error like the other views
        """
        registration_data = json.loads(request.data["registration_data"])
        serializer = V2RegistrationSerializer(data=registration_data)
        if serializer.is_valid():
            serializer.save()
            return ResponseSuccess({"result": serializer.data},
                                   http_status=status.HTTP_201_CREATED)
        else:
            if "User already exists." in serializer.errors.get("email",
                                                               []).detail:
                # If the email already exists,
                # notify the original user and pretend registration completed ok.
                user = User.objects.get(
                    email__iexact=serializer.initial_data["email"])
                template_id = SystemParameter.get("NOTIFY_EMAIL_EXISTS")
                send_mail(user.email, {"full_name": user.name}, template_id)

                return ResponseSuccess(
                    {
                        "result": {
                            "email": serializer.initial_data["email"],
                            "pk": uuid.uuid4(),  # Give them a random UUID
                        }
                    },
                    http_status=status.HTTP_201_CREATED,
                )
            else:
                raise ValidationAPIException(
                    serializer_errors=serializer.errors)
Example #12
0
 def post(self, request, invitation_id, *args, **kwargs):
     try:
         invitation = Invitation.objects.get(
             id=invitation_id,
             deleted_at__isnull=True,
         )
         invitation.accepted_at = timezone.now()
         invitation.user = request.user
         invitation.save()
         return ResponseSuccess(
             {
                 "result": invitation.to_dict(),
             }
         )
     except Invitation.DoesNotExist:
         raise NotFoundApiExceptions("Invitation not found")
Example #13
0
    def post(self, request, case_id, content_id=None, *args, **kwargs):
        """
        Create or update content
        """
        case = Case.objects.get(id=case_id)

        if content_id:
            content = Content.objects.get(id=content_id, case=case)
        else:
            content = Content(case=case, created_by=request.user)

        update_object_from_request(content, request.data, ["name", "short_name", "content"])
        parent_id = request.data.get("parent_id")
        if parent_id:
            content.parent = Content.objects.get(id=parent_id, case=case)
        content.save()
        return ResponseSuccess({"result": content.to_dict()}, http_status=status.HTTP_201_CREATED)
Example #14
0
 def delete(self, request, organisation_id, case_id=None, *args, **kwargs):
     """
     Delete all org case roles from this org, then mark as deleted
     """
     organisation = Organisation.objects.get(id=organisation_id)
     ocr = OrganisationCaseRole.objects.filter(organisation=organisation)
     casecontacts = organisation.casecontact_set.all()
     invitations = organisation.invitations.all()
     # real-delete any case roles and case contact references
     ocr.delete()
     casecontacts.delete()
     # mark delete all invites
     for invitation in invitations:
         invitation.delete()
     organisation.delete()
     return ResponseSuccess({"result": organisation.to_dict()},
                            http_status=status.HTTP_201_CREATED)
Example #15
0
    def post(request, *args, **kwargs):
        """
        Changes a user's password.

        Arguments:
            request: a Django Request object
        Returns:
            ResponseSuccess response if the password was successfully changed.
        Raises:
            InvalidRequestParams if link is invalid or password is not complex enough.
        """
        token_serializer = PasswordResetRequestSerializerV2(data=request.data)
        password_serializer = PasswordSerializer(data=request.data)
        request_id = request.data.get("request_id")

        if token_serializer.is_valid() and password_serializer.is_valid():
            if PasswordResetRequest.objects.password_reset_v2(
                    token_serializer.initial_data["token"],
                    token_serializer.initial_data["request_id"],
                    token_serializer.initial_data["password"],
            ):
                logger.info(
                    f"Password reset completed for: request {request_id}")
                user_pk = PasswordResetRequest.objects.get(
                    request_id=request_id).user.pk
                user = User.objects.get(pk=user_pk)
                audit_log(audit_type=AUDIT_TYPE_PASSWORD_RESET, user=user)
                return ResponseSuccess({"result": {
                    "reset": True
                }},
                                       http_status=status.HTTP_200_OK)
        elif not password_serializer.is_valid():
            user_pk = PasswordResetRequest.objects.get(
                request_id=request_id).user.pk
            user = User.objects.get(pk=user_pk)
            audit_log(audit_type=AUDIT_TYPE_PASSWORD_RESET_FAILED, user=user)
            raise ValidationAPIException(
                serializer_errors=password_serializer.errors)
        else:
            logger.warning(
                f"Could not reset password for request {request_id}")
            user_pk = PasswordResetRequest.objects.get(
                request_id=request_id).user.pk
            user = User.objects.get(pk=user_pk)
            audit_log(audit_type=AUDIT_TYPE_PASSWORD_RESET_FAILED, user=user)
            raise InvalidRequestParams("Invalid or expired link")
Example #16
0
    def get(request, *args, **kwargs):
        """
        Sends a password reset email.

        Arguments:
            request: a Django Request object
        Returns:
            ResponseSuccess response.
        """
        email = request.GET.get("email")
        serializer = EmailSerializer(data={"email": email})
        logger.info(f"Password reset request for: {email}")
        if serializer.is_valid():
            # Invalidate all previous PasswordResetRequest objects for this user
            PasswordResetRequest.objects.reset_request(email=email)
            return ResponseSuccess({"result": True})
        else:
            raise ValidationAPIException(serializer_errors=serializer.errors)
Example #17
0
 def get(self, request, *args, **kwargs):
     names = request.GET.getlist("name")
     case_summary = request.GET.get("cases",
                                    "false") in TRUTHFUL_INPUT_VALUES
     upper_names = [n.upper() for n in names]
     organisations = Organisation.objects.filter(name__in=upper_names)
     results = []
     for org in organisations:
         _item = org.to_embedded_dict()
         if case_summary:
             cases = Case.objects.filter(
                 organisationcaserole__organisation=org)
             _item["cases"] = [{
                 "id": str(case.id),
                 "name": case.name
             } for case in cases]
         results.append(_item)
     return ResponseSuccess({"results": results})
Example #18
0
class DocumentIssueAPI(TradeRemediesApiView):
    """
    Issue a document to the case.
    If the document is part of a submission, it's issued flag is toggled to
    denote it being issued or removed from the case.
    If the document is standalone, a submisssion of a given type is created
    and assigned to the case. Optional submission name can be provided (or will
    default to the submission type name) as well as an organisation.
    Note: used by the Files page
    """
    @transaction.atomic
    def post(self, request, case_id, *args, **kwargs):
        response = {"submissions": [], "issued": [], "removed": []}
        submissions = set()
        if request.user.is_tra():
            case = Case.objects.get(id=case_id)
            submission_type_id = request.data.get("submission_type_id")
            document_ids = request.data.getlist("document_ids")
            documents = Document.objects.filter(id__in=document_ids)
            if documents:
                if submission_type_id:
                    submission = case.create_submission_for_documents(
                        documents=documents,
                        submission_type=submission_type_id,
                        name=request.data.get("name") or None,
                        organisation=request.data.get("organisation_id")
                        or None,
                        created_by=request.user,
                        issued=True,
                    )
                    submissions.add(submission)
                else:
                    for document in documents:
                        submission_docs = document.submissiondocument_set.filter(
                            submission__case=case)
                        for subdoc in submission_docs:
                            subdoc.issue_to_submission(user=request.user)
                            submissions.add(subdoc.submission)

                for sub in submissions:
                    response["submissions"].append(str(sub.id))
                    case.notify_all_participants(request.user, submission=sub)

        return ResponseSuccess({"result": response})
Example #19
0
 def get(self, request):
     documents = Document.objects.all()
     counts = Document.objects.values("index_state").annotate(
         total=Count("index_state"))
     count_index = key_by(counts, "index_state")
     return ResponseSuccess({
         "result": {
             "total":
             documents.count(),
             "full_index":
             count_index.get(INDEX_STATE_FULL_INDEX, {}).get("total"),
             "unknown_type":
             count_index.get(INDEX_STATE_UNKNOWN_TYPE, {}).get("total"),
             "failed":
             count_index.get(INDEX_STATE_INDEX_FAIL, {}).get("total"),
             "pending":
             count_index.get(INDEX_STATE_NOT_INDEXED, {}).get("total"),
         }
     })
Example #20
0
 def delete(self, request, case_id, organisation_id, *args, **kwargs):
     # Remove from case
     organisation = Organisation.objects.get(id=organisation_id)
     case = Case.objects.get(id=case_id)
     case_role, _ = OrganisationCaseRole.objects.get_or_create(
         case=case, organisation=organisation)
     case_role.delete()
     audit_log(
         audit_type=AUDIT_TYPE_EVENT,
         user=request.user,
         model=case,
         case=case,
         milestone=True,
         data={
             "message":
             f"Organisation {organisation} was removed from case {case.name}"
         },
     )
     return ResponseSuccess({"result": organisation.to_dict()})
Example #21
0
 def post(self, request, case_id, submission_id, contact_id, *args, **kwargs):
     notify_data = request.data.dict()
     case = get_case(case_id)
     submission = Submission.objects.get(id=submission_id, case=case)
     contact = Contact.objects.select_related("userprofile", "organisation").get(id=contact_id)
     try:
         invite = Invitation.objects.get(submission=submission, contact=contact)
     except Invitation.DoesNotExist:
         raise NotFoundApiExceptions("Invite not found")
     send_report = invite.send(
         sent_by=request.user,
         context=notify_data,
         direct=True,
         template_key="NOTIFY_THIRD_PARTY_INVITE",
     )
     invite.email_sent = True
     invite.sent_at = timezone.now()
     invite.approved_by = request.user
     invite.save()
     return ResponseSuccess({"result": invite.to_dict()}, http_status=status.HTTP_201_CREATED)
Example #22
0
    def post(request, *args, **kwargs):
        """
        Verifies a 2fa code provided by a user.

        Arguments:
            request: a Django Request object
        Returns:
            ResponseSuccess response with the user.to_dict() if the 2fa code is valid
        Raises:
            InvalidRequestParams if the code could could not be validated
        """
        twofactorauth_object = request.user.twofactorauth
        serializer = TwoFactorAuthVerifySerializer(
            instance=twofactorauth_object,
            data={"code": request.data.get("2fa_code", None)},
            context={"request": request},
        )
        if serializer.is_valid():
            serializer.save()
            return ResponseSuccess(serializer.data,
                                   http_status=status.HTTP_200_OK)
        else:
            raise ValidationAPIException(serializer_errors=serializer.errors)
Example #23
0
class CaseDocumentCountAPI(TradeRemediesApiView):
    """
    Return full document count for a case
    """
    def get(self, request, case_id, *args, **kwargs):
        case = Case.objects.get(id=case_id)
        sub_documents = SubmissionDocument.objects.filter(
            submission__case=case,
            submission__deleted_at__isnull=True,
            document__deleted_at__isnull=True,
        ).distinct("document")
        sub_docs_cw = sub_documents.filter(
            document__created_by__groups__name__in=SECURITY_GROUPS_TRA).count(
            )
        sub_docs_pub = (sub_documents.exclude(
            document__created_by__groups__name__in=SECURITY_GROUPS_TRA).
                        exclude(submission__status__default=True).exclude(
                            submission__status__draft=True).count())
        note_documents = Note.objects.filter(
            case=case,
            documents__isnull=False,
            documents__submissiondocument__isnull=True).count()
        return ResponseSuccess(
            {"result": sub_docs_pub + sub_docs_cw + note_documents})
Example #24
0
class DocumentConfidentialAPI(TradeRemediesApiView):
    """
    Change the confidential state of a document, toggling the value.
    This can be performed by a TRA user only and only for documents created BY the TRA.
    """
    def post(self, request, case_id, *args, **kwargs):
        if request.user.is_tra():
            case = Case.objects.get(id=case_id)
            document_ids = request.data.getlist("document_ids")
            documents = Document.objects.filter(
                id__in=document_ids,
                created_by__groups__name__in=SECURITY_GROUPS_TRA)
            report = {}
            for document in documents:
                document.set_case_context(case)
                report[str(document.id)] = {
                    "from": document.confidential,
                    "to": not document.confidential,
                }
                document.confidential = not document.confidential
                document.save()
        return ResponseSuccess({
            "result": report,
        })
Example #25
0
 def get(self, request, invitation_id=None, *args, **kwargs):
     try:
         invitation = Invitation.objects.get(id=invitation_id, user=request.user)
         return ResponseSuccess({"result": invitation.to_dict()})
     except Invitation.DoesNotExist:
         raise NotFoundApiExceptions("Invalid invitation")
Example #26
0
 def get(self, request, code=None, case_id=None, *args, **kwargs):
     try:
         case = Case.objects.get(id=case_id)
         invitation = Invitation.objects.get(code=code, case=case, deleted_at__isnull=True)
         return ResponseSuccess({"result": invitation.to_dict()})
Example #27
0
                contact = Contact.objects.select_related("userprofile", "organisation").get(
                    id=contact_id
                )
            except Contact.DoesNotExist:
                raise NotFoundApiExceptions("Invalid contact id.")
            invitations = invitations.filter(contact=contact)
        if case_id:
            try:
                case = Case.objects.get(id=case_id)
            except Case.DoesNotExist:
                raise InvalidRequestParams("Invalid case id")
            invitations = invitations.filter(case=case)
        if submission_id:
            submission = Submission.objects.get(id=submission_id)
            invitations = invitations.filter(submission=submission)
        return ResponseSuccess({"results": [invitation.to_dict() for invitation in invitations]})

    @transaction.atomic
    def post(
        self, request, contact_id, case_id, case_role_id=None, submission_id=None, *args, **kwargs
    ):
        notify_template_key = None
        try:
            contact = Contact.objects.select_related("userprofile", "organisation").get(
                id=contact_id
            )
            case_role = get_role(case_role_id)
            case = Case.objects.get(id=case_id)
            notify_template_key = case.type.meta.get("invite_notify_template_key")
        except Contact.DoesNotExist:
            raise NotFoundApiExceptions("Invalid contact id.")
Example #28
0
 def post(self, request, organisation_id=None, *args, **kwargs):
     return ResponseSuccess({
         "result":
         request.user.is_representing(get_organisation(organisation_id))
     })
Example #29
0
 def get(self, request, organisation_id=None, *args, **kwargs):
     return ResponseSuccess(
         {"results": [org.to_dict() for org in request.user.representing]})
Example #30
0
 def post(request: HttpRequest, *args, **kwargs) -> HttpResponse:
     serializer = UserDoesNotExistSerializer(data=request.data)
     return ResponseSuccess(
         {"result": {
             "available": serializer.is_valid()
         }})