Commit 1971d88c authored by Daniele Venzano's avatar Daniele Venzano

Finish implementing REST API for users

parent 69777235
......@@ -17,6 +17,7 @@
import logging
import os
from typing import List
import zoe_api.exceptions
import zoe_api.master_api
......@@ -202,7 +203,7 @@ class APIEndpoint:
"""Finds a user in the database looking it up by its username."""
if user.id == user_id:
return user
if not user.role.can_operate_others:
if not user.role.can_change_config:
raise zoe_api.exceptions.ZoeAuthException()
return self.sql.user.select(only_one=True, id=user_id)
......@@ -213,3 +214,59 @@ class APIEndpoint:
raise zoe_api.exceptions.ZoeAuthException()
self.sql.user.delete(user_id)
def user_list(self, user: zoe_lib.state.User, **filters) -> List[zoe_lib.state.User]:
"""Generate a optionally filtered list of executions."""
if not user.role.can_change_config:
raise zoe_api.exceptions.ZoeAuthException()
users = self.sql.user.select(**filters)
return users
def user_new(self, user: zoe_lib.state.User, username: str, fs_uid: int, role: str, quota: str, auth_source: str) -> int:
"""Creates a new user."""
if not user.role.can_change_config:
raise zoe_api.exceptions.ZoeAuthException()
return self.sql.user.insert(username, fs_uid, role, quota, auth_source)
def user_update(self, user: zoe_lib.state.User, **user_data):
"""Update a user."""
if 'id' not in user_data:
raise KeyError
self.user_by_id(user, user_data['id'])
update_fields = {}
if not user.role.can_change_config:
if 'email' in user_data:
update_fields['email'] = user_data['email']
else:
if 'email' in user_data:
update_fields['email'] = user_data['email']
if 'priority' in user_data:
update_fields['priority'] = user_data['priority']
if 'enabled' in user_data:
update_fields['enabled'] = user_data['enabled']
if 'auth_source' in user_data:
update_fields['auth_source'] = user_data['auth_source']
if 'quota' in user_data:
quota = self.quota_by_name(user_data['quota'])
if quota is None:
raise zoe_api.exceptions.ZoeRestAPIException('No quota called {}'.format(user_data['quota']))
update_fields['quota_id'] = quota.id
if 'role' in user_data:
role = self.role_by_name(user_data['role'])
if role is None:
raise zoe_api.exceptions.ZoeRestAPIException('No role called {}'.format(user_data['role']))
update_fields['role_id'] = role.id
self.sql.user.update(user_data['id'], **update_fields)
def quota_by_name(self, quota) -> zoe_lib.state.Quota:
"""Finds a quota in the database looking it up by its name."""
return self.sql.quota.select(only_one=True, **{'name': quota})
def role_by_name(self, role) -> zoe_lib.state.Role:
"""Finds a role in the database looking it up by its name."""
return self.sql.role.select(only_one=True, **{'name': role})
......@@ -39,7 +39,7 @@ class ZoeAuthException(ZoeException):
class ZoeNotFoundException(ZoeException):
"""Th euser is looking for an object that does not exist."""
"""The user is looking for an object that does not exist."""
pass
......
......@@ -21,7 +21,7 @@ import tornado.web
from zoe_api.rest_api.execution import ExecutionAPI, ExecutionCollectionAPI, ExecutionDeleteAPI, ExecutionEndpointsAPI
from zoe_api.rest_api.info import InfoAPI
from zoe_api.rest_api.userinfo import UserAPI, UserCollectionAPI
from zoe_api.rest_api.user import UserAPI, UserCollectionAPI
from zoe_api.rest_api.service import ServiceAPI, ServiceLogsAPI
from zoe_api.rest_api.discovery import DiscoveryAPI
from zoe_api.rest_api.statistics import SchedulerStatsAPI
......
......@@ -15,8 +15,10 @@
"""The User API endpoints."""
import tornado.escape
from zoe_api.rest_api.request_handler import ZoeAPIRequestHandler
from zoe_api.exceptions import ZoeAuthException
from zoe_api.exceptions import ZoeAuthException, ZoeRestAPIException
class UserAPI(ZoeAPIRequestHandler):
......@@ -40,10 +42,27 @@ class UserAPI(ZoeAPIRequestHandler):
self.write(ret)
def post(self, user_id):
"""HTTP POST method."""
"""HTTP POST method, to edit a user."""
if self.current_user is None:
return
try:
data = tornado.escape.json_decode(self.request.body)
except ValueError:
self.set_status(400, 'Error decoding JSON data')
return
try:
self.api_endpoint.user_update(self.current_user, **data)
except KeyError:
self.set_status(400, 'Error decoding JSON data')
return
except ZoeAuthException as e:
self.set_status(401, e.message)
return
self.set_status(201)
def delete(self, user_id: int):
"""HTTP DELETE method."""
if self.current_user is None:
......@@ -53,6 +72,7 @@ class UserAPI(ZoeAPIRequestHandler):
self.api_endpoint.user_delete(self.current_user, user_id)
except ZoeAuthException as e:
self.set_status(401, e.message)
return
self.set_status(204)
......@@ -64,7 +84,51 @@ class UserCollectionAPI(ZoeAPIRequestHandler):
if self.current_user is None:
return
filter_dict = {}
filters = [
('username', str),
('email', str),
('priority', int),
('enabled', bool),
('auth_source', str),
('role_id', int),
('quota_id', int)
]
for filter in filters:
if filter[0] in self.request.arguments:
if filter[1] == str:
filter_dict[filter[0]] = self.request.arguments[filter[0]][0].decode('utf-8')
else:
filter_dict[filter[0]] = filter[1](self.request.arguments[filter[0]][0])
try:
users = self.api_endpoint.user_list(self.current_user, **filter_dict)
except ZoeAuthException as e:
self.set_status(401, e.message)
return
self.write(dict([(u.id, u.serialize()) for u in users]))
def post(self):
"""HTTP POST method."""
if self.current_user is None:
return
try:
data = tornado.escape.json_decode(self.request.body)
except ValueError:
self.set_status(400, 'Error decoding JSON data')
return
try:
new_id = self.api_endpoint.user_new(self.current_user, data['username'], data['fs_uid'], data['role'], data['quota'], data['auth_source'])
except KeyError:
self.set_status(400, 'Error decoding JSON data')
return
except ZoeAuthException as e:
self.set_status(401, e.message)
return
self.set_status(201)
self.write({'user_id': new_id})
......@@ -138,9 +138,9 @@ class UserTable(BaseTable):
else:
return [User(x, self.sql_manager) for x in self.cursor]
def insert(self, username, fs_uid, role, auth_source):
def insert(self, username, fs_uid, role, quota, auth_source):
"""Adds a new user to the state."""
query = self.cursor.mogrify('INSERT INTO "user" (id, username, fs_uid, email, priority, enabled, auth_source, role_id, quota_id) VALUES (DEFAULT, %s, %s, NULL, DEFAULT, DEFAULT, %s, (SELECT id FROM role WHERE name=%s), (SELECT id FROM quota WHERE name=\'default\')) RETURNING id', (username, fs_uid, auth_source, role))
query = self.cursor.mogrify('INSERT INTO "user" (id, username, fs_uid, email, priority, enabled, auth_source, role_id, quota_id) VALUES (DEFAULT, %s, %s, NULL, DEFAULT, DEFAULT, %s, (SELECT id FROM role WHERE name=%s), (SELECT id FROM quota WHERE name=%s)) RETURNING id', (username, fs_uid, auth_source, role, quota))
self.cursor.execute(query)
self.sql_manager.commit()
return self.cursor.fetchone()[0]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment