def list_users(self, request, *args, **kwargs): self.check_permissions(request, "list_users", None) url = request.DATA.get('url', None) token = self._get_token(request) project_id = request.DATA.get('project', None) if not project_id: raise exc.WrongArguments(_("The project param is needed")) if not url: raise exc.WrongArguments(_("The url param is needed")) importer = JiraNormalImporter(request.user, url, token) users = importer.list_users() for user in users: user['user'] = None if not user['email']: continue try: tuesmon_user = User.objects.get(email=user['email']) except User.DoesNotExist: continue user['user'] = { 'id': tuesmon_user.id, 'full_name': tuesmon_user.get_full_name(), 'gravatar_id': get_user_gravatar_id(tuesmon_user), 'photo': get_user_photo_url(tuesmon_user), } return response.Ok(users)
def change_email(self, request, pk=None): """ Verify the email change to current logged user. """ validator = validators.ChangeEmailValidator(data=request.DATA, many=False) if not validator.is_valid(): raise exc.WrongArguments( _("Invalid, are you sure the token is correct and you " "didn't use it before?")) try: user = models.User.objects.get( email_token=validator.data["email_token"]) except models.User.DoesNotExist: raise exc.WrongArguments( _("Invalid, are you sure the token is correct and you " "didn't use it before?")) self.check_permissions(request, "change_email", user) old_email = user.email new_email = user.new_email user.email = new_email user.new_email = None user.email_token = None user.save(update_fields=["email", "new_email", "email_token"]) user_change_email_signal.send(sender=user.__class__, user=user, old_email=old_email, new_email=new_email) return response.NoContent()
def cancel(self, request, pk=None): """ Cancel an account via token """ validator = validators.CancelAccountValidator(data=request.DATA, many=False) if not validator.is_valid(): raise exc.WrongArguments( _("Invalid, are you sure the token is correct?")) try: max_age_cancel_account = getattr(settings, "MAX_AGE_CANCEL_ACCOUNT", None) user = get_user_for_token(validator.data["cancel_token"], "cancel_account", max_age=max_age_cancel_account) except exc.NotAuthenticated: raise exc.WrongArguments( _("Invalid, are you sure the token is correct?")) if not user.is_active: raise exc.WrongArguments( _("Invalid, are you sure the token is correct?")) user.cancel() return response.NoContent()
def change_password(self, request, pk=None): """ Change password to current logged user. """ self.check_permissions(request, "change_password", None) current_password = request.DATA.get("current_password") password = request.DATA.get("password") # NOTE: GitHub users have no password yet (request.user.passwor == '') so # current_password can be None if not current_password and request.user.password: raise exc.WrongArguments(_("Current password parameter needed")) if not password: raise exc.WrongArguments(_("New password parameter needed")) if len(password) < 6: raise exc.WrongArguments( _("Invalid password length at least 6 charaters needed")) if current_password and not request.user.check_password( current_password): raise exc.WrongArguments(_("Invalid current password")) request.user.set_password(password) request.user.save(update_fields=["password"]) return response.NoContent()
def private_register_for_new_user(token:str, username:str, email:str, full_name:str, password:str): """ Given a inviation token, try register new user matching the invitation token. """ is_registered, reason = is_user_already_registered(username=username, email=email) if is_registered: raise exc.WrongArguments(reason) user_model = get_user_model() user = user_model(username=username, email=email, full_name=full_name) user.set_password(password) try: user.save() except IntegrityError: raise exc.WrongArguments(_("Error on creating new user.")) membership = get_membership_by_token(token) membership.user = user membership.save(update_fields=["user"]) send_register_email(user) user_registered_signal.send(sender=user.__class__, user=user) return user
def public_register(username:str, password:str, email:str, full_name:str): """ Given a parsed parameters, try register a new user knowing that it follows a public register flow. This can raise `exc.IntegrityError` exceptions in case of conflics found. :returns: User """ is_registered, reason = is_user_already_registered(username=username, email=email) if is_registered: raise exc.WrongArguments(reason) user_model = get_user_model() user = user_model(username=username, email=email, full_name=full_name, read_new_terms=True) user.set_password(password) try: user.save() except IntegrityError: raise exc.WrongArguments(_("User is already registered.")) send_register_email(user) user_registered_signal.send(sender=user.__class__, user=user) return user
def _validate_and_update_version(self, obj): current_version = None if obj.id: current_version = type(obj).objects.model.objects.get( id=obj.id).version # Extract param version param_version = self._extract_param_version() if not self._validate_param_version(param_version, current_version): raise exc.WrongArguments( {"version": _("The version parameter is not valid")}) if current_version != param_version: diff_versions = current_version - param_version modifying_fields = set(self.request.DATA.keys()) if "version" in modifying_fields: modifying_fields.remove("version") modified_fields = set(get_modified_fields(obj, diff_versions)) if "version" in modifying_fields: modified_fields.remove("version") both_modified = modifying_fields & modified_fields if both_modified: raise exc.WrongArguments({ "version": _("The version doesn't match with the current one") }) obj.version = models.F('version') + 1
def validate_project_transfer_token(token, project, user): signer = signing.TimestampSigner() if project.transfer_token != token: raise exc.WrongArguments(_("Token is invalid")) try: value = signer.unsign(token, max_age=datetime.timedelta(days=7)) except signing.SignatureExpired: raise exc.WrongArguments(_("Token has expired")) except signing.BadSignature: raise exc.WrongArguments(_("Token is invalid")) if str(value) != str(user.id): raise exc.WrongArguments(_("Token is invalid"))
def pre_save(self, obj): if not obj.id: obj.content_type = self.get_content_type() obj.owner = self.request.user obj.size = obj.attached_file.size obj.name = path.basename(obj.attached_file.name) if obj.content_object is None: raise exc.WrongArguments(_("Object id issue isn't exists")) if obj.project_id != obj.content_object.project_id: raise exc.WrongArguments( _("Project ID not matches between object and project")) super().pre_save(obj)
def authorize(self, request, *args, **kwargs): self.check_permissions(request, "authorize", None) try: oauth_data = request.user.auth_data.get(key="jira-oauth") oauth_verifier = request.DATA.get("oauth_verifier", None) oauth_token = oauth_data.extra['oauth_token'] oauth_secret = oauth_data.extra['oauth_secret'] server_url = oauth_data.extra['url'] oauth_data.delete() jira_token = JiraNormalImporter.get_access_token( server_url, settings.IMPORTERS.get('jira', {}).get('consumer_key', None), settings.IMPORTERS.get('jira', {}).get('cert', None), oauth_token, oauth_secret, oauth_verifier, False) except Exception as e: raise exc.WrongArguments(_("Invalid or expired auth token")) return response.Ok({ "token": jira_token['access_token'] + "." + jira_token['access_token_secret'], "url": server_url })
def auth_url(self, request, *args, **kwargs): self.check_permissions(request, "auth_url", None) jira_url = request.QUERY_PARAMS.get('url', None) if not jira_url: raise exc.WrongArguments(_("The url param is needed")) try: (oauth_token, oauth_secret, url) = JiraNormalImporter.get_auth_url( jira_url, settings.IMPORTERS.get('jira', {}).get('consumer_key', None), settings.IMPORTERS.get('jira', {}).get('cert', None), True) except exceptions.InvalidServiceConfiguration: raise exc.BadRequest(_("Invalid Jira server configuration.")) (auth_data, created) = AuthData.objects.get_or_create(user=request.user, key="jira-oauth", defaults={ "value": uuid.uuid4().hex, "extra": {}, }) auth_data.extra = { "oauth_token": oauth_token, "oauth_secret": oauth_secret, "url": jira_url, } auth_data.save() return response.Ok({"url": url})
def pre_conditions_on_save(self, obj): super().pre_conditions_on_save(obj) if obj.status and obj.status.project != obj.project: raise exc.WrongArguments( _("You don't have permissions to set this status to this epic." ))
def remove_user_from_all_my_projects(self, request, **kwargs): private_only = request.DATA.get('private_only', False) user_id = request.DATA.get('user', None) if user_id is None: raise exc.WrongArguments(_("Invalid user id")) user_model = apps.get_model("users", "User") try: user = user_model.objects.get(id=user_id) except user_model.DoesNotExist: return response.BadRequest(_("The user doesn't exist")) memberships = models.Membership.objects.filter( project__owner=request.user, user=user) if private_only: memberships = memberships.filter(project__is_private=True) errors = [] for membership in memberships: if not services.can_user_leave_project(user, membership.project): errors.append(membership.project.name) if len(errors) > 0: error = _( "This user can't be removed from the following projects, because would " "leave them without any active admin: {}.".format( ", ".join(errors))) return response.BadRequest(error) memberships.delete() return response.NoContent()
def import_project(self, request, *args, **kwargs): self.check_permissions(request, "import_project", None) token = request.DATA.get('token', None) project_id = request.DATA.get('project', None) if not project_id: raise exc.WrongArguments(_("The project param is needed")) options = { "template": request.DATA.get('template', "kanban"), "users_bindings": request.DATA.get("users_bindings", {}), "keep_external_reference": request.DATA.get("keep_external_reference", False), "is_private": request.DATA.get("is_private", False), } if settings.CELERY_ENABLED: task = tasks.import_project.delay(request.user.id, token, project_id, options) return response.Accepted({"pivotal_import_id": task.id}) importer = PivotalImporter(request.user, token) project = importer.import_project(project_id, options) project_data = { "slug": project.slug, "my_permissions": ["view_us"], "is_backlog_activated": project.is_backlog_activated, "is_kanban_activated": project.is_kanban_activated, } return response.Ok(project_data)
def list_users(self, request, *args, **kwargs): self.check_permissions(request, "list_users", None) token = request.DATA.get('token', None) project_id = request.DATA.get('project', None) if not project_id: raise exc.WrongArguments(_("The project param is needed")) importer = AsanaImporter(request.user, token) try: users = importer.list_users(project_id) except exceptions.InvalidRequest: raise exc.BadRequest(_('Invalid Asana API request')) except exceptions.FailedRequest: raise exc.BadRequest(_('Failed to make the request to Asana API')) for user in users: if user['detected_user']: user['user'] = { 'id': user['detected_user'].id, 'full_name': user['detected_user'].get_full_name(), 'gravatar_id': get_user_gravatar_id(user['detected_user']), 'photo': get_user_photo_url(user['detected_user']), } del (user['detected_user']) return response.Ok(users)
def render(self, request, **kwargs): content = request.DATA.get("content", None) project_id = request.DATA.get("project_id", None) if not content: raise exc.WrongArguments( {"content": _("'content' parameter is mandatory")}) if not project_id: raise exc.WrongArguments( {"project_id": _("'project_id' parameter is mandatory")}) project = get_object_or_404(Project, pk=project_id) self.check_permissions(request, "render", project) data = mdrender(project, content) return response.Ok({"data": data})
def _extract_param_version(self): param_version = self.request.DATA.get('version', None) try: param_version = param_version and int(param_version) except (ValueError, TypeError): raise exc.WrongArguments( {"version": _("The version must be an integer")}) return param_version
def transfer_reject(self, request, pk=None): token = request.DATA.get('token', None) if token is None: raise exc.WrongArguments(_("Invalid token")) project = self.get_object() self.check_permissions(request, "transfer_reject", project) reason = request.DATA.get('reason', None) services.reject_project_transfer(project, request.user, token, reason) return response.Ok()
def change_password_from_recovery(self, request, pk=None): """ Change password with token (from password recovery step). """ self.check_permissions(request, "change_password_from_recovery", None) validator = validators.RecoveryValidator(data=request.DATA, many=False) if not validator.is_valid(): raise exc.WrongArguments(_("Token is invalid")) try: user = models.User.objects.get(token=validator.data["token"]) except models.User.DoesNotExist: raise exc.WrongArguments(_("Token is invalid")) user.set_password(validator.data["password"]) user.token = None user.save(update_fields=["password", "token"]) return response.NoContent()
def change_avatar(self, request): """ Change avatar to current logged user. """ self.check_permissions(request, "change_avatar", None) avatar = request.FILES.get('avatar', None) if not avatar: raise exc.WrongArguments(_("Incomplete arguments")) try: pil_image(avatar) except Exception: raise exc.WrongArguments(_("Invalid image format")) request.user.photo = avatar request.user.save(update_fields=["photo"]) user_data = self.admin_serializer_class(request.user).data return response.Ok(user_data)
def list_projects(self, request, *args, **kwargs): self.check_permissions(request, "list_projects", None) url = request.DATA.get('url', None) if not url: raise exc.WrongArguments(_("The url param is needed")) token = self._get_token(request) importer = JiraNormalImporter(request.user, url, token) agile_importer = JiraAgileImporter(request.user, url, token) projects = importer.list_projects() boards = agile_importer.list_projects() return response.Ok(sorted(projects + boards, key=lambda x: x['name']))
def partial_update(self, request, *args, **kwargs): """ We must detect if the user is trying to change his email so we can save that value and generate a token that allows him to validate it in the new email account """ user = self.get_object() self.check_permissions(request, "update", user) new_email = request.DATA.pop('email', None) if new_email is not None: valid_new_email = True duplicated_email = models.User.objects.filter( email=new_email).exists() try: validate_email(new_email) validate_user_email_allowed_domains(new_email) except ValidationError: valid_new_email = False valid_new_email = valid_new_email and new_email != request.user.email if duplicated_email: raise exc.WrongArguments(_("Duplicated email")) elif not valid_new_email: raise exc.WrongArguments(_("Not valid email")) # We need to generate a token for the email request.user.email_token = str(uuid.uuid4()) request.user.new_email = new_email request.user.save(update_fields=["email_token", "new_email"]) email = mail_builder.change_email(request.user.new_email, { "user": request.user, "lang": request.user.lang }) email.send() return super().partial_update(request, *args, **kwargs)
def pre_conditions_on_save(self, obj): super().pre_conditions_on_save(obj) if obj.milestone and obj.milestone.project != obj.project: raise exc.WrongArguments( _("You don't have permissions to set this sprint to this task." )) if obj.user_story and obj.user_story.project != obj.project: raise exc.WrongArguments( _("You don't have permissions to set this user story to this task." )) if obj.status and obj.status.project != obj.project: raise exc.WrongArguments( _("You don't have permissions to set this status to this task." )) if obj.milestone and obj.user_story and obj.milestone != obj.user_story.milestone: raise exc.WrongArguments( _("You don't have permissions to set this sprint to this task." ))
def change_logo(self, request, *args, **kwargs): """ Change logo to this project. """ self.object = get_object_or_404(self.get_queryset(), **kwargs) self.check_permissions(request, "change_logo", self.object) logo = request.FILES.get('logo', None) if not logo: raise exc.WrongArguments(_("Incomplete arguments")) try: pil_image(logo) except Exception: raise exc.WrongArguments(_("Invalid image format")) self.pre_conditions_on_save(self.object) self.object.logo = logo self.object.save(update_fields=["logo"]) serializer = self.get_serializer(self.object) return response.Ok(serializer.data)
def get_and_validate_user(*, username: str, password: str) -> bool: """ Check if user with username/email exists and specified password matchs well with existing user password. if user is valid, user is returned else, corresponding exception is raised. """ user = get_user_by_username_or_email(username) if not user.check_password(password): raise exc.WrongArguments(_("Username or password does not matches user.")) return user
def get_user_by_username_or_email(username_or_email): user_model = get_user_model() qs = user_model.objects.filter(Q(username__iexact=username_or_email) | Q(email__iexact=username_or_email)) if len(qs) > 1: qs = qs.filter(Q(username=username_or_email) | Q(email=username_or_email)) if len(qs) == 0: raise exc.WrongArguments(_("Username or password does not matches user.")) user = qs[0] return user
def get(self, uri_path, query_params=None): headers = {'Accept': 'application/json'} if query_params is None: query_params = {} if uri_path[0] == '/': uri_path = uri_path[1:] url = 'https://api.trello.com/1/%s' % uri_path response = requests.get(url, params=query_params, headers=headers, auth=self.oauth) if response.status_code == 400: raise exc.WrongArguments(_("Invalid Request: %s at %s") % (response.text, url)) if response.status_code == 401: raise exc.AuthenticationFailed(_("Unauthorized: %s at %s") % (response.text, url)) if response.status_code == 403: raise exc.PermissionDenied(_("Unauthorized: %s at %s") % (response.text, url)) if response.status_code == 404: raise exc.NotFound(_("Resource Unavailable: %s at %s") % (response.text, url)) if response.status_code != 200: raise exc.WrongArguments(_("Resource Unavailable: %s at %s") % (response.text, url)) return response.json()
def authorize(self, request, *args, **kwargs): self.check_permissions(request, "authorize", None) try: oauth_data = request.user.auth_data.get(key="pivotal-oauth") oauth_token = oauth_data.extra['oauth_token'] oauth_secret = oauth_data.extra['oauth_secret'] oauth_verifier = request.DATA.get('code') oauth_data.delete() pivotal_token = PivotalImporter.get_access_token( oauth_token, oauth_secret, oauth_verifier)['oauth_token'] except Exception as e: raise exc.WrongArguments(_("Invalid or expired auth token")) return response.Ok({"token": pivotal_token})
def test_import_trello_list_projects_with_problem_on_request(client, settings): user = f.UserFactory.create() client.login(user) url = reverse("importers-trello-list-projects") with mock.patch('tuesmon.importers.trello.importer.TrelloClient' ) as TrelloClientMock: instance = mock.Mock() instance.get.side_effect = exc.WrongArguments("Invalid Request") TrelloClientMock.return_value = instance response = client.post(url, content_type="application/json", data=json.dumps({"token": "token"})) assert response.status_code == 400
def password_recovery(self, request, pk=None): username_or_email = request.DATA.get('username', None) self.check_permissions(request, "password_recovery", None) if not username_or_email: raise exc.WrongArguments(_("Invalid username or email")) user = get_user_by_username_or_email(username_or_email) user.token = str(uuid.uuid4()) user.save(update_fields=["token"]) email = mail_builder.password_recovery(user, {"user": user}) email.send() return response.Ok({"detail": _("Mail sended successful!")})