186 lines
6.5 KiB
Python
186 lines
6.5 KiB
Python
# Copyright (c) 2013 Mirantis Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from oslo.config import cfg
|
|
from pecan import expose
|
|
from pecan import request
|
|
from pecan import response
|
|
from pecan import rest
|
|
from pecan.secure import secure
|
|
import six
|
|
from wsme.exc import ClientSideError
|
|
import wsmeext.pecan as wsme_pecan
|
|
|
|
from storyboard.api.auth import authorization_checks as checks
|
|
from storyboard.api.v1.search import search_engine
|
|
from storyboard.api.v1.user_preferences import UserPreferencesController
|
|
from storyboard.api.v1.user_tokens import UserTokensController
|
|
from storyboard.api.v1 import validations
|
|
from storyboard.api.v1 import wmodels
|
|
from storyboard.common import decorators
|
|
from storyboard.db.api import users as users_api
|
|
from storyboard.openstack.common.gettextutils import _ # noqa
|
|
|
|
|
|
CONF = cfg.CONF
|
|
|
|
SEARCH_ENGINE = search_engine.get_engine()
|
|
|
|
|
|
class UsersController(rest.RestController):
|
|
"""Manages users."""
|
|
|
|
# Import the user preferences.
|
|
preferences = UserPreferencesController()
|
|
|
|
# Import user token management.
|
|
tokens = UserTokensController()
|
|
|
|
_custom_actions = {"search": ["GET"]}
|
|
|
|
validation_post_schema = validations.USERS_POST_SCHEMA
|
|
validation_put_schema = validations.USERS_PUT_SCHEMA
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.guest)
|
|
@wsme_pecan.wsexpose([wmodels.User], int, int, unicode, unicode, unicode,
|
|
unicode)
|
|
def get(self, marker=None, limit=None, username=None, full_name=None,
|
|
sort_field='id', sort_dir='asc'):
|
|
"""Page and filter the users in storyboard.
|
|
|
|
:param marker: The resource id where the page should begin.
|
|
:param limit The number of users to retrieve.
|
|
:param username A string of characters to filter the username with.
|
|
:param full_name A string of characters to filter the full_name with.
|
|
:param sort_field: The name of the field to sort on.
|
|
:param sort_dir: sort direction for results (asc, desc).
|
|
"""
|
|
|
|
# Boundary check on limit.
|
|
if limit is None:
|
|
limit = CONF.page_size_default
|
|
limit = min(CONF.page_size_maximum, max(1, limit))
|
|
|
|
# Resolve the marker record.
|
|
marker_user = users_api.user_get(marker)
|
|
|
|
users = users_api.user_get_all(marker=marker_user, limit=limit,
|
|
username=username, full_name=full_name,
|
|
filter_non_public=True,
|
|
sort_field=sort_field,
|
|
sort_dir=sort_dir)
|
|
user_count = users_api.user_get_count(username=username,
|
|
full_name=full_name)
|
|
|
|
# Apply the query response headers.
|
|
response.headers['X-Limit'] = str(limit)
|
|
response.headers['X-Total'] = str(user_count)
|
|
if marker_user:
|
|
response.headers['X-Marker'] = str(marker_user.id)
|
|
|
|
return [wmodels.User.from_db_model(u) for u in users]
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.guest)
|
|
@wsme_pecan.wsexpose(wmodels.User, int)
|
|
def get_one(self, user_id):
|
|
"""Retrieve details about one user.
|
|
|
|
:param user_id: The unique id of this user
|
|
"""
|
|
|
|
filter_non_public = True
|
|
if user_id == request.current_user_id:
|
|
filter_non_public = False
|
|
|
|
user = users_api.user_get(user_id, filter_non_public)
|
|
if not user:
|
|
raise ClientSideError(_("User %s not found") % user_id,
|
|
status_code=404)
|
|
return user
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.superuser)
|
|
@wsme_pecan.wsexpose(wmodels.User, body=wmodels.User)
|
|
def post(self, user):
|
|
"""Create a new user.
|
|
|
|
:param user: a user within the request body.
|
|
"""
|
|
|
|
created_user = users_api.user_create(user.as_dict())
|
|
return wmodels.User.from_db_model(created_user)
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.authenticated)
|
|
@wsme_pecan.wsexpose(wmodels.User, int, body=wmodels.User)
|
|
def put(self, user_id, user):
|
|
"""Modify this user.
|
|
|
|
:param user_id: unique id to identify the user.
|
|
:param user: a user within the request body.
|
|
"""
|
|
current_user = users_api.user_get(request.current_user_id)
|
|
|
|
# Only owners and superadmins are allowed to modify users.
|
|
if request.current_user_id != user_id \
|
|
and not current_user.is_superuser:
|
|
response.status_code = 403
|
|
response.body = _("You are not allowed to update this user.")
|
|
return response
|
|
|
|
# Strip out values that you're not allowed to change.
|
|
user_dict = user.as_dict(omit_unset=True)
|
|
|
|
if not current_user.is_superuser:
|
|
# Only superuser may create superusers or modify login permissions.
|
|
if 'enable_login' in six.iterkeys(user_dict):
|
|
del user_dict['enable_login']
|
|
|
|
if 'is_superuser' in six.iterkeys(user_dict):
|
|
del user_dict['is_superuser']
|
|
|
|
updated_user = users_api.user_update(user_id, user_dict)
|
|
return wmodels.User.from_db_model(updated_user)
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.guest)
|
|
@wsme_pecan.wsexpose([wmodels.User], unicode, int, int)
|
|
def search(self, q="", marker=None, limit=None):
|
|
"""The search endpoint for users.
|
|
|
|
:param q: The query string.
|
|
:return: List of Users matching the query.
|
|
"""
|
|
|
|
users = SEARCH_ENGINE.users_query(q=q, marker=marker, limit=limit)
|
|
|
|
return [wmodels.User.from_db_model(u) for u in users]
|
|
|
|
@expose()
|
|
def _route(self, args, request):
|
|
if request.method == 'GET' and len(args) == 1:
|
|
# It's a request by a name or id
|
|
something = args[0]
|
|
|
|
if something == "search":
|
|
# Request to a search endpoint
|
|
return self.search, args
|
|
else:
|
|
return self.get_one, args
|
|
|
|
return super(UsersController, self)._route(args, request)
|