def validate_public_invite(self, short_code, user): """ Validate a public invite not issued to a specific organisation, but to the general public via a code. Members of this invite will by default go to the awaiting approval group and will not have access to the case while in that group. Returns a tuple of the invite model and the organisation used. Raises an InvitationFailure if the code is not found """ try: invite = self.get(short_code=short_code, deleted_at__isnull=True) organisation_user = invite.process_invitation(user=user, accept=False) organisation = organisation_user.organisation audit_log( audit_type=AUDIT_TYPE_EVENT, user=user, case=self.case, data={ "invite_id": str(invite.id), "accepted_by": str(user.id), "organisation_id": str(organisation.id), }, ) return invite except Invitation.DoesNotExist: raise InvitationFailure(f"Invalid short code: {short_code}")
def save(self, **kwargs): if not self.instance: # This is a new user new_user = User.objects.create_user( contact_country=self.initial_data["mobile_country_code"], contact_address=self.initial_data["address_snippet"], contact_post_code=self.initial_data["post_code"], contact_phone=self.initial_data["mobile"], **self.validated_data) self.instance = new_user organisation = Organisation.objects.create_or_update_organisation( user=new_user, assign_user=True, name=self.initial_data["name"], address=self.initial_data["address_snippet"], country=self.initial_data["country"], post_code=self.initial_data["post_code"], vat_number=self.initial_data["company_vat_number"], eori_number=self.initial_data["company_eori_number"], duns_number=self.initial_data["company_duns_number"], organisation_website=self.initial_data["company_website"], companies_house_id=self.initial_data["company_number"], contact_object=new_user.contact, ) security_group_name = OrganisationUser.objects.user_organisation_security_group( new_user, organisation) new_user.groups.add( security_group_name) # Add the user to same group audit_log(audit_type=AUDIT_TYPE_USER_CREATED, user=new_user) return new_user else: return super().save(**kwargs)
def check_measure_expiry(): """ Check all archived cases which are not already set to Measure Expired stage, and determine if all their meaures are expired. """ cases = Case.objects.filter( initiated_at__isnull=False, archived_at__isnull=False, ).exclude(stage__key="MEASURES_EXPIRED") for case in cases: latest_expiry = case.get_state_key("LATEST_MEASURE_EXPIRY") if latest_expiry and latest_expiry.value: # print( TODO - remove if not needed # timezone.now().date() <= parse(latest_expiry.value).date(), # timezone.now().date(), # parse(latest_expiry.value).date(), # ) if timezone.now().date() >= parse(latest_expiry.value).date(): case.set_stage_by_key("MEASURES_EXPIRED") audit_log( audit_type=AUDIT_TYPE_EVENT, model=case, case=case, milestone=True, data={"message": "Measures expired"}, )
def save(self, **kwargs): if not self.instance.email_verified_at: # If they have already verified their email, we don't want to overwrite the time self.instance.email_verified_at = timezone.now() audit_log(audit_type=AUDIT_TYPE_EMAIL_VERIFIED, user=self.instance.user) return self.instance.save()
def execute(self): value = self.evaluate_rules() if value == "PUBLISHED": self.case.set_user_context(self.kwargs.get("requested_by")) self.case.initiated_at = timezone.now() self.case.save() self.case.set_stage_by_key("CASE_INITIATED") audit_log( audit_type=AUDIT_TYPE_EVENT, model=self.case, case=self.case, milestone=True, data={"message": "Case initiated"}, )
def execute(self): next_stage = self.evaluate_rules() if next_stage: self.case.set_user_context(self.kwargs.get("requested_by")) stage = self.case.set_stage_by_key(next_stage) if stage: stage_name = stage.name if stage else "N/A" # Add to audit audit_log( audit_type=AUDIT_TYPE_EVENT, model=self.case, case=self.case, milestone=True, data={"message": stage_name}, )
def test_custom_audit_log(self): audit_log( audit_type=AUDIT_TYPE_LOGIN, user=self.user, assisted_by=self.caseworker, case=self.assisted_case, model=self.unassisted_case, data={"a": "b"}, milestone=True, ) self.assertEqual(Audit.objects.count(), 1) audit = Audit.objects.first() self.assertEqual(audit.created_by, self.user) self.assertTrue(audit.milestone) self.assertIn("a", audit.data) self.assertEqual(audit.case_id, self.assisted_case.id) self.assertEqual(audit.get_model(), self.unassisted_case) self.assertEqual(audit.created_at, timezone.now())
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()})
def validate(self, attrs): email = attrs.get("email") password = attrs.get("password") request = self.context.get("request") if email and password: try: user = authenticate( request=self.context.get("request"), email=email, password=password ) except AxesLockedOutException: # The user has been locked out after too many incorrect attempts raise CustomValidationError(error_key="login_incorrect_timeout") if not user or user.deleted_at: audit_log(audit_type=AUDIT_TYPE_LOGIN_FAILED, data={"email": email}) raise CustomValidationError(error_key="wrong_email_password_combination") audit_log(audit_type=AUDIT_TYPE_LOGIN, user=user) # ensure the origin of the request is allowed for this user group env_key = request.META.get("HTTP_X_ORIGIN_ENVIRONMENT") if not user.has_groups(groups=ENVIRONMENT_GROUPS[env_key]): if not env_key: logger.error(f"env_key not defined while logging {user.email}") else: logger.error( f"{user.email} does not have access to {ENVIRONMENT_GROUPS[env_key]}" ) raise CustomValidationError(error_key="invalid_access") email_verified = user.is_tra() or user.userprofile.email_verified_at if not email_verified: self.response_dict["needs_verify"] = True self.response_dict["token"] = str(user.get_access_token()) else: raise AuthenticationFailed( _("Email and password are required to log in."), code="authorization" ) attrs["user"] = user return attrs
def execute(self): from cases.models import ArchiveReason from cases.models import CaseWorkflowState next_stage = self.evaluate_rules() if next_stage: archive_reason = ArchiveReason.objects.get(key=next_stage.upper()) self.case.set_user_context(self.kwargs.get("requested_by")) self.case.archive_reason = archive_reason self.case.archived_at = timezone.now() self.case.set_stage_by_key("CASE_CLOSED") self.case.save() CaseWorkflowState.objects.set_next_action( self.case, "", requested_by=self.kwargs.get("requested_by") ) audit_log( audit_type=AUDIT_TYPE_EVENT, model=self.case, case=self.case, milestone=True, data={"message": "Case archived"}, )
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")
def post(self, request, case_id, organisation_id, role_key=None, *args, **kwargs): sampled = request.data.get("sampled", "true") == "true" 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) # Add/update LOA contact if self.post_type == "loa": # Create a contact to store LOA details if present loa_updated = False loa_contact = case_role.auth_contact auth_contact_details = (pluck( request.data, [ "LOA_contact_id", "name", "org_name", "email", "phone", "address" ], ) or {}) contact_id = auth_contact_details.get("LOA_contact_id") email = auth_contact_details.get("email") if not loa_contact or loa_contact.id != contact_id: # If we get an id, stick with that if contact_id: try: loa_contact = Contact.objects.get(id=contact_id) except Exception: pass if email: # No contact so try to find one based on email try: loa_contact = Contact.objects.get(email__iexact=email) except Exception: loa_contact = Contact.objects.create( created_by=request.user) # Create a new org if there isn't one, or it doesn't match supplied name loa_org_name = auth_contact_details.get("org_name") loa_contact.organisation = organisation for field, value in auth_contact_details.items(): if (value and hasattr(loa_contact, field) and getattr(loa_contact, field) != value): setattr(loa_contact, field, value) loa_updated = True if loa_updated: loa_contact.save() # write back case_role.auth_contact = loa_contact case_role.save() return ResponseSuccess( {"result": { "success": case_role.to_dict() }}) # Approve into case and set case role approve = request.data.get("approve") if approve: if approve == "accept": if not case_role.approved_at: case_role.approved_at = timezone.now() case_role.approved_by = request.user case_role.save() elif approve == "reject": role_key = "rejected" if case_role.approved_at: case_role.approved_at = None case_role.approved_by = None case_role.save() if self.verify: case_role.validated_by = request.user case_role.validated_at = timezone.now() case_role.save() return ResponseSuccess( {"result": { "validated_at": case_role.to_dict() }}) role = CaseRole.objects.get(key=role_key) case_role.role = role case_role.sampled = sampled case_role.save() audit_log( audit_type=AUDIT_TYPE_EVENT, user=request.user, model=case, case=case, milestone=True, data={ "message": f"The role of {organisation} was set to {role} in case {case.name}" }, ) return ResponseSuccess({"result": {"new_role": role.to_dict()}})
def post(self, request, case_id, organisation_id, action, *args, **kwargs): values = {key: request.data.get(key) for key in request.data.keys()} contact_id = values.pop("contact_id") organisation = Organisation.objects.get(id=organisation_id) case = Case.objects.get(id=case_id) values["case_number"] = case.reference values["case_name"] = case.name values["login_url"] = public_login_url() values["company_name"] = titlecase(organisation.name) user_granted_access = None if action in ("approve", "change"): role_key = values.pop("organisation_type", None) role = CaseRole.objects.get(key=role_key) values["role"] = role.contributor_or_interested() if action == "change": previous_role = case.organisationcaserole_set.filter( organisation=organisation).first() values[ "previous_role"] = previous_role.role.contributor_or_interested( ) values["new_role"] = values["role"] try: contact = Contact.objects.select_related( "userprofile", "organisation").get(id=contact_id, casecontact__case=case, casecontact__organisation=organisation) except Contact.DoesNotExist: contact = Contact.objects.select_related( "userprofile", "organisation").get(id=contact_id) CaseContact.objects.get_or_create(contact=contact, case=case, organisation=organisation) caserole, created = organisation.assign_case(case, role) user_granted_access = caserole.created_by # assign the user registering access to the case case.assign_user(user_granted_access, created_by=request.user, organisation=organisation) message = f"Organisation {organisation.name} approved as {role.name}" else: role = CaseRole.objects.get(key="rejected") values["new_role"] = "rejected" caserole, created = organisation.assign_case(case, role) user_granted_access = caserole.created_by contact = Contact.objects.select_related( "userprofile", "organisation").get(id=contact_id) message = f"Organisation {organisation.name} was rejected" values["full_name"] = contact.name # Send the message if action == "approve" or values.get("previous_role") != values.get( "new_role"): organisation.notify_approval_status(action, contact, values, case, request.user) if action == "approve": audit_log( audit_type=AUDIT_TYPE_EVENT, user=request.user, model=case, case=case, milestone=True, data={ "action": "assign_user", "message": f"User {user_granted_access} " f"was granted access to the case for {organisation}", }, ) return ResponseSuccess({"result": values})
case = Case.objects.get(id=case_id) organisation = Organisation.objects.get(id=organisation_id) except Case.DoesNotExist: raise NotFoundApiExceptions("Case not found or access denied") except Organisation.DoesNotExist: raise NotFoundApiExceptions( "Organisation not found or access denied") sampled = request.data.get("sampled") org_case_role = OrganisationCaseRole.objects.get( case=case, organisation=organisation) org_case_role.sampled = sampled if sampled is not None else not org_case_role.sampled org_case_role.save() sampled_str = "sampled" if org_case_role.sampled else "non-sampled" audit_log( audit_type=AUDIT_TYPE_EVENT, user=request.user, model=organisation, case=case, milestone=True, data={"message": f"{organisation.name} flagged as {sampled_str}"}, ) return ResponseSuccess( { "result": { "organisation_id": organisation_id, "case_id": case_id, "sampled": org_case_role.sampled, "organisation": organisation.to_embedded_dict(), } }, http_status=status.HTTP_201_CREATED,