Source code for RestAuth.Users.views

# -*- coding: utf-8 -*-
#
# This file is part of RestAuth (https://restauth.net).
#
# RestAuth is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# RestAuth is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with RestAuth.  If not, see <http://www.gnu.org/licenses/>.

"""
This module implements all HTTP queries to ``/user/*``.
"""

from __future__ import unicode_literals

import logging

from django.conf import settings
from django.http import HttpResponseForbidden
from django.utils import six

from RestAuthCommon import resource_validator
from RestAuthCommon.error import PreconditionFailed

from RestAuth.Users.validators import validate_username
from RestAuth.backends import property_backend
from RestAuth.backends import user_backend
from RestAuth.common.errors import PasswordInvalid
from RestAuth.common.errors import UserNotFound
from RestAuth.common.responses import HttpResponseCreated
from RestAuth.common.responses import HttpResponseNoContent
from RestAuth.common.responses import HttpRestAuthResponse
from RestAuth.common.types import parse_dict
from RestAuth.common.views import RestAuthResourceView
from RestAuth.common.views import RestAuthSubResourceView
from RestAuth.common.views import RestAuthView


[docs]class UsersView(RestAuthView): """ Handle requests to ``/users/``. """ http_method_names = ['get', 'post'] log = logging.getLogger('users') post_format = { 'mandatory': (('user', six.string_types),), 'optional': (('password', six.string_types), ('properties', dict), ) } post_required = (('user', six.string_types),) post_optional = (('password', six.string_types), ('properties', dict))
[docs] def get(self, request, largs, *args, **kwargs): """ Get all users. """ if not request.user.has_perm('Users.users_list'): return HttpResponseForbidden() names = user_backend.list() return HttpRestAuthResponse(request, names)
[docs] def post(self, request, largs, dry=False): """ Create a new user. """ if not request.user.has_perm('Users.user_create'): return HttpResponseForbidden() name, password, properties = self._parse_post(request) # check username: if not resource_validator(name): raise PreconditionFailed("Username contains invalid characters") # If UsernameInvalid: 412 Precondition Failed validate_username(name) # check password: if password is not None and password != '': if len(password) < settings.MIN_PASSWORD_LENGTH: raise PasswordInvalid("Password too short") # check properties: if properties is not None: for key in six.iterkeys(properties): if not resource_validator(key): raise PreconditionFailed( "Property contains invalid characters") # If ResourceExists: 409 Conflict # If PasswordInvalid: 412 Precondition Failed user = user_backend.create(username=name, password=password, properties=properties, property_backend=property_backend, dry=dry) self.log.info('%s: Created user', user.username, extra=largs) return HttpResponseCreated(request, 'users.user', name=user.username)
[docs]class UserHandlerView(RestAuthResourceView): """ Handle requests to ``/users/<user>/``. """ http_method_names = ['get', 'post', 'put', 'delete'] log = logging.getLogger('users.user') post_required = (('password', six.string_types),) put_optional = (('password', six.string_types),)
[docs] def get(self, request, largs, name): """ Verify that a user exists. """ if not request.user.has_perm('Users.user_exists'): return HttpResponseForbidden() if user_backend.exists(username=name): return HttpResponseNoContent() else: raise UserNotFound(name) # 404 Not Found
[docs] def post(self, request, largs, name): """ Verify a users password. """ if not request.user.has_perm('Users.user_verify_password'): return HttpResponseForbidden() # If BadRequest: 400 Bad Request password = self._parse_post(request) if user_backend.check_password(username=name, password=password): return HttpResponseNoContent() else: raise UserNotFound(name)
[docs] def put(self, request, largs, name): """ Change a users password. """ if not request.user.has_perm('Users.user_change_password'): return HttpResponseForbidden() # If BadRequest: 400 Bad Request password = self._parse_put(request) if password is not None and password != '': if len(password) < settings.MIN_PASSWORD_LENGTH: raise PasswordInvalid("Password too short") user_backend.set_password(username=name, password=password) return HttpResponseNoContent()
[docs] def delete(self, request, largs, name): """ Delete a user. """ if not request.user.has_perm('Users.user_delete'): return HttpResponseForbidden() user_backend.remove(username=name) return HttpResponseNoContent()
[docs]class UserPropsIndex(RestAuthResourceView): """ Handle requests to ``/users/<user>/props/``. """ log = logging.getLogger('users.user.props') http_method_names = ['get', 'post', 'put'] post_required = (('prop', six.string_types), ('value', six.string_types),)
[docs] def get(self, request, largs, name): """ Get all properties of a user. """ if not request.user.has_perm('Users.props_list'): return HttpResponseForbidden() # If UserNotFound: 404 Not Found user = user_backend.get(username=name) props = property_backend.list(user=user) return HttpRestAuthResponse(request, props)
[docs] def post(self, request, largs, name, dry=False): """ Create a new property. """ if not request.user.has_perm('Users.prop_create'): return HttpResponseForbidden() # If AssertionError: 400 Bad Request key, value = self._parse_post(request) if not resource_validator(key): raise PreconditionFailed("Property contains invalid characters") # If UserNotFound: 404 Not Found user = user_backend.get(username=name) # If PropertyExists: 409 Conflict key, value = property_backend.create(user=user, key=key, value=value, dry=dry) self.log.info( 'Created property "%s" as "%s"', key, value, extra=largs) return HttpResponseCreated(request, 'users.user.props.prop', name=name, subname=key)
[docs] def put(self, request, largs, name): """ Set multiple properties. """ if not request.user.has_perm('Users.prop_create'): return HttpResponseForbidden() # If UserNotFound: 404 Not Found user = user_backend.get(username=name) properties = parse_dict(request) for key in six.iterkeys(properties): if not resource_validator(key): raise PreconditionFailed( "Property contains invalid characters") property_backend.set_multiple(user=user, props=properties) return HttpResponseNoContent()
[docs]class UserPropHandler(RestAuthSubResourceView): """ Handle requests to ``/users/<user>/props/<prop>/``. """ log = logging.getLogger('users.user.props.prop') http_method_names = ['get', 'put', 'delete'] put_required = (('value', six.string_types),)
[docs] def get(self, request, largs, name, subname): """ Get value of a single property. """ if not request.user.has_perm('Users.prop_get'): return HttpResponseForbidden() # If UserNotFound: 404 Not Found user = user_backend.get(username=name) value = property_backend.get(user=user, key=subname) return HttpRestAuthResponse(request, value)
[docs] def put(self, request, largs, name, subname): """ Set value of a single property. """ if not request.user.has_perm('Users.prop_set'): return HttpResponseForbidden() # If BadRequest: 400 Bad Request value = self._parse_put(request) # If UserNotFound: 404 Not Found user = user_backend.get(username=name) key, old_value = property_backend.set(user=user, key=subname, value=value) if old_value is None: # new property self.log.info('Set to "%s"', value, extra=largs) return HttpResponseCreated(request, 'users.user.props.prop', name=name, subname=key) else: # existing property self.log.info('Changed from "%s" to "%s"', old_value, value, extra=largs) return HttpRestAuthResponse(request, old_value)
[docs] def delete(self, request, largs, name, subname): """ Delete a property. """ if not request.user.has_perm('Users.prop_delete'): return HttpResponseForbidden() # If UserNotFound: 404 Not Found user = user_backend.get(username=name) property_backend.remove(user=user, key=subname) return HttpResponseNoContent()