- Add support for super users

- Add a super user API
- Add a super user interface
This commit is contained in:
Joseph Schorr 2014-04-10 00:26:55 -04:00
parent 4d4f3b1c18
commit 0e320c964f
15 changed files with 524 additions and 33 deletions

View file

@ -302,6 +302,7 @@ import endpoints.api.repository
import endpoints.api.repotoken
import endpoints.api.robot
import endpoints.api.search
import endpoints.api.superuser
import endpoints.api.tag
import endpoints.api.team
import endpoints.api.trigger

View file

@ -29,8 +29,7 @@ def log_view(log):
return view
def get_logs(namespace, start_time, end_time, performer_name=None,
repository=None):
def get_logs(start_time, end_time, performer_name=None, repository=None, namespace=None):
performer = None
if performer_name:
performer = model.get_user(performer_name)
@ -54,8 +53,8 @@ def get_logs(namespace, start_time, end_time, performer_name=None,
if not end_time:
end_time = datetime.today()
logs = model.list_logs(namespace, start_time, end_time, performer=performer,
repository=repository)
logs = model.list_logs(start_time, end_time, performer=performer, repository=repository,
namespace=namespace)
return {
'start_time': format_date(start_time),
'end_time': format_date(end_time),
@ -80,7 +79,7 @@ class RepositoryLogs(RepositoryParamResource):
start_time = args['starttime']
end_time = args['endtime']
return get_logs(namespace, start_time, end_time, repository=repo)
return get_logs(start_time, end_time, repository=repo, namespace=namespace)
@resource('/v1/user/logs')
@ -100,7 +99,7 @@ class UserLogs(ApiResource):
end_time = args['endtime']
user = get_authenticated_user()
return get_logs(user.username, start_time, end_time, performer_name=performer_name)
return get_logs(start_time, end_time, performer_name=performer_name, namespace=user.username)
@resource('/v1/organization/<orgname>/logs')
@ -121,6 +120,6 @@ class OrgLogs(ApiResource):
start_time = args['starttime']
end_time = args['endtime']
return get_logs(orgname, start_time, end_time, performer_name=performer_name)
return get_logs(start_time, end_time, namespace=orgname, performer_name=performer_name)
raise Unauthorized()
raise Unauthorized()

160
endpoints/api/superuser.py Normal file
View file

@ -0,0 +1,160 @@
import logging
import json
from app import app
from flask import request
from endpoints.api import (ApiResource, nickname, resource, validate_json_request, request_error,
log_action, internal_only, NotFound, require_user_admin, format_date,
InvalidToken, require_scope, format_date, hide_if, show_if, parse_args,
query_param, abort)
from endpoints.api.logs import get_logs
from data import model
from auth.permissions import SuperUserPermission
from auth.auth_context import get_authenticated_user
import features
logger = logging.getLogger(__name__)
@resource('/v1/superuser/logs')
@internal_only
@show_if(features.SUPER_USERS)
class SuperUserLogs(ApiResource):
""" Resource for fetching all logs in the system. """
@nickname('listAllLogs')
@parse_args
@query_param('starttime', 'Earliest time from which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('endtime', 'Latest time to which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('performer', 'Username for which to filter logs.', type=str)
def get(self, args):
""" List the logs for the current system. """
if SuperUserPermission().can():
performer_name = args['performer']
start_time = args['starttime']
end_time = args['endtime']
return get_logs(start_time, end_time)
abort(403)
@resource('/v1/superuser/seats')
@internal_only
@show_if(features.SUPER_USERS)
@hide_if(features.BILLING)
class SeatUsage(ApiResource):
""" Resource for managing the seats granted in the license for the system. """
@nickname('getSeatCount')
def get(self):
""" Returns the current number of seats being used in the system. """
if SuperUserPermission().can():
return {
'count': model.get_active_user_count(),
'allowed': app.config.get('LICENSE_SEAT_COUNT', 0)
}
abort(403)
def user_view(user):
return {
'username': user.username,
'email': user.email,
'verified': user.verified,
'super_user': user.username in app.config['SUPER_USERS']
}
@resource('/v1/superuser/users/')
@internal_only
@show_if(features.SUPER_USERS)
class SuperUserList(ApiResource):
""" Resource for listing users in the system. """
@nickname('listAllUsers')
def get(self):
""" Returns a list of all users in the system. """
if SuperUserPermission().can():
users = model.get_active_users()
return {
'users': [user_view(user) for user in users]
}
abort(403)
@resource('/v1/superuser/users/<username>')
@internal_only
@show_if(features.SUPER_USERS)
class SuperUserManagement(ApiResource):
""" Resource for managing users in the system. """
schemas = {
'UpdateUser': {
'id': 'UpdateUser',
'type': 'object',
'description': 'Description of updates for a user',
'properties': {
'password': {
'type': 'string',
'description': 'The new password for the user',
},
'email': {
'type': 'string',
'description': 'The new e-mail address for the user',
}
},
},
}
@nickname('getInstallUser')
def get(self, username):
""" Returns information about the specified user. """
if SuperUserPermission().can():
user = model.get_user(username)
if not user or user.organization or user.robot:
abort(404)
return user_view(user)
abort(403)
@nickname('deleteInstallUser')
def delete(self, username):
""" Deletes the specified user. """
if SuperUserPermission().can():
user = model.get_user(username)
if not user or user.organization or user.robot:
abort(404)
if username in app.config['SUPER_USERS']:
abort(403)
model.delete_user(user)
return 'Deleted', 204
abort(403)
@nickname('changeInstallUser')
@validate_json_request('UpdateUser')
def put(self, username):
""" Updates information about the specified user. """
if SuperUserPermission().can():
user = model.get_user(username)
if not user or user.organization or user.robot:
abort(404)
if username in app.config['SUPER_USERS']:
abort(403)
user_data = request.get_json()
if 'password' in user_data:
model.change_password(user, user_data['password'])
if 'email' in user_data:
model.update_email(user, user_data['email'])
return user_view(user)
abort(403)

View file

@ -15,7 +15,7 @@ from endpoints.common import common_login
from data import model
from data.plans import get_plan
from auth.permissions import (AdministerOrganizationPermission, CreateRepositoryPermission,
UserAdminPermission, UserReadPermission)
UserAdminPermission, UserReadPermission, SuperUserPermission)
from auth.auth_context import get_authenticated_user
from auth import scopes
from util.gravatar import compute_hash
@ -66,6 +66,11 @@ def user_view(user):
'preferred_namespace': not (user.stripe_id is None),
})
if features.SUPER_USERS:
user_response.update({
'super_user': user and user == get_authenticated_user() and SuperUserPermission().can()
})
return user_response