def list(self, request, *args, **kwargs): self.object_list = MembersFilterBackend().filter_queryset( request, self.get_queryset(), self) if 'publickey' in request.QUERY_PARAMS: publickey = request.QUERY_PARAMS['publickey'] self.object_list = self.object_list.filter(public_key=publickey) if 'username' in request.QUERY_PARAMS: self.object_list = self.object_list.filter( username=request.QUERY_PARAMS['username']) if 'email' in request.QUERY_PARAMS: self.object_list = self.object_list.filter( email=request.QUERY_PARAMS['email']) if 'threebot_name' in request.QUERY_PARAMS: self.object_list = self.object_list.filter( email=request.QUERY_PARAMS['threebot_name']) page = self.paginate_queryset(self.object_list) if page is not None: serializer = self.get_pagination_serializer(page) else: serializer = self.get_serializer(self.object_list, many=True) return response.Ok(serializer.data)
def list(self, request, *args, **kwargs): self.object_list = MembersFilterBackend().filter_queryset( request, self.get_queryset(), self) page = self.paginate_queryset(self.object_list) if page is not None: serializer = self.get_pagination_serializer(page) else: serializer = self.get_serializer(self.object_list, many=True) return response.Ok(serializer.data)
class UsersViewSet(ModelCrudViewSet): permission_classes = (permissions.UserPermission, ) admin_serializer_class = serializers.UserAdminSerializer serializer_class = serializers.UserSerializer admin_validator_class = validators.UserAdminValidator validator_class = validators.UserValidator filter_backends = (MembersFilterBackend, ) throttle_classes = (UserDetailRateThrottle, UserUpdateRateThrottle) model = models.User def get_serializer_class(self): if self.action in [ "partial_update", "update", "retrieve", "by_username" ]: user = self.object if self.request.user == user or self.request.user.is_superuser: return self.admin_serializer_class return self.serializer_class def get_validator_class(self): if self.action in [ "partial_update", "update", "retrieve", "by_username" ]: user = self.object if self.request.user == user or self.request.user.is_superuser: return self.admin_validator_class return self.validator_class def get_queryset(self): qs = super().get_queryset() qs = qs.prefetch_related("memberships") qs = user_utils.attach_extra_info(qs, user=self.request.user) return qs def create(self, *args, **kwargs): raise exc.NotSupported() def list(self, request, *args, **kwargs): self.object_list = MembersFilterBackend().filter_queryset( request, self.get_queryset(), self) if 'publickey' in request.QUERY_PARAMS: publickey = request.QUERY_PARAMS['publickey'] self.object_list = self.object_list.filter(public_key=publickey) if 'username' in request.QUERY_PARAMS: self.object_list = self.object_list.filter( username=request.QUERY_PARAMS['username']) if 'email' in request.QUERY_PARAMS: self.object_list = self.object_list.filter( email=request.QUERY_PARAMS['email']) if 'threebot_name' in request.QUERY_PARAMS: self.object_list = self.object_list.filter( email=request.QUERY_PARAMS['threebot_name']) page = self.paginate_queryset(self.object_list) if page is not None: serializer = self.get_pagination_serializer(page) else: serializer = self.get_serializer(self.object_list, many=True) return response.Ok(serializer.data) def retrieve(self, request, *args, **kwargs): self.object = get_object_or_404(self.get_queryset(), **kwargs) self.check_permissions(request, 'retrieve', self.object) serializer = self.get_serializer(self.object) return response.Ok(serializer.data) # TODO: commit_on_success 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(_("Invalid 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() github_username = request.DATA.pop('github_username', None) threebot_name = request.DATA.pop('threebot_name', None) public_key = request.DATA.pop('public_key', None) if github_username: request.user.github_username = github_username request.user.save(update_fields=["github_username"]) if threebot_name: request.user.threebot_name = threebot_name request.user.save(update_fields=["threebot_name"]) if public_key: request.user.public_key = public_key request.user.save(update_fields=["public_key"]) return super().partial_update(request, *args, **kwargs) def destroy(self, request, pk=None): user = self.get_object() self.check_permissions(request, "destroy", user) stream = request.stream request_data = stream is not None and stream.GET or None user_cancel_account_signal.send(sender=user.__class__, user=user, request_data=request_data) user.cancel() return response.NoContent() @list_route(methods=["GET"]) def by_username(self, request, *args, **kwargs): username = request.QUERY_PARAMS.get("username", None) return self.retrieve(request, username=username) @list_route(methods=["POST"]) 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!")}) @list_route(methods=["POST"]) 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() @list_route(methods=["POST"]) 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() @list_route(methods=["POST"]) 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) @list_route(methods=["POST"]) def remove_avatar(self, request): """ Remove the avatar of current logged user. """ self.check_permissions(request, "remove_avatar", None) request.user.photo = None request.user.save(update_fields=["photo"]) user_data = self.admin_serializer_class(request.user).data return response.Ok(user_data) @list_route(methods=["POST"]) 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() @list_route(methods=["GET"]) def me(self, request, pk=None): """ Get me. """ self.check_permissions(request, "me", None) user_data = self.admin_serializer_class(request.user).data return response.Ok(user_data) @list_route(methods=["POST"]) 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() @list_route(methods=["POST"]) def export(self, request, pk=None): """ Export user data and photo """ file_url = services.export_profile(request.user) response_data = {"url": file_url} return response.Ok(response_data) @detail_route(methods=["GET"]) def contacts(self, request, *args, **kwargs): user = get_object_or_404(models.User, **kwargs) self.check_permissions(request, 'contacts', user) self.object_list = user_filters.ContactsFilterBackend( ).filter_queryset( user, request, self.get_queryset(), self).extra(select={ "complete_user_name": "concat(full_name, username)" }).order_by("complete_user_name") page = self.paginate_queryset(self.object_list) if page is not None: serializer = self.serializer_class(page.object_list, many=True) else: serializer = self.serializer_class(self.object_list, many=True) return response.Ok(serializer.data) @detail_route(methods=["GET"]) def stats(self, request, *args, **kwargs): user = get_object_or_404(models.User, **kwargs) self.check_permissions(request, "stats", user) return response.Ok(services.get_stats_for_user(user, request.user)) @detail_route(methods=["GET"]) def watched(self, request, *args, **kwargs): for_user = get_object_or_404(models.User, **kwargs) from_user = request.user self.check_permissions(request, 'watched', for_user) filters = { "type": request.GET.get("type", None), "q": request.GET.get("q", None), } self.object_list = services.get_watched_list(for_user, from_user, **filters) page = self.paginate_queryset(self.object_list) elements = page.object_list if page is not None else self.object_list extra_args_liked = { "user_watching": services.get_watched_content_for_user(request.user), "user_likes": services.get_liked_content_for_user(request.user), } extra_args_voted = { "user_watching": services.get_watched_content_for_user(request.user), "user_votes": services.get_voted_content_for_user(request.user), } response_data = [] for elem in elements: if elem["type"] == "project": # projects are liked objects response_data.append( serializers.LikedObjectSerializer(into_namedtuple(elem), **extra_args_liked).data) else: # stories, tasks and issues are voted objects response_data.append( serializers.VotedObjectSerializer(into_namedtuple(elem), **extra_args_voted).data) return response.Ok(response_data) @detail_route(methods=["GET"]) def liked(self, request, *args, **kwargs): for_user = get_object_or_404(models.User, **kwargs) from_user = request.user self.check_permissions(request, 'liked', for_user) filters = { "q": request.GET.get("q", None), } self.object_list = services.get_liked_list(for_user, from_user, **filters) page = self.paginate_queryset(self.object_list) elements = page.object_list if page is not None else self.object_list extra_args = { "user_watching": services.get_watched_content_for_user(request.user), "user_likes": services.get_liked_content_for_user(request.user), } response_data = [ serializers.LikedObjectSerializer(into_namedtuple(elem), **extra_args).data for elem in elements ] return response.Ok(response_data) @detail_route(methods=["GET"]) def voted(self, request, *args, **kwargs): for_user = get_object_or_404(models.User, **kwargs) from_user = request.user self.check_permissions(request, 'liked', for_user) filters = { "type": request.GET.get("type", None), "q": request.GET.get("q", None), } self.object_list = services.get_voted_list(for_user, from_user, **filters) page = self.paginate_queryset(self.object_list) elements = page.object_list if page is not None else self.object_list extra_args = { "user_watching": services.get_watched_content_for_user(request.user), "user_votes": services.get_voted_content_for_user(request.user), } response_data = [ serializers.VotedObjectSerializer(into_namedtuple(elem), **extra_args).data for elem in elements ] return response.Ok(response_data)