Add full application management API, UI and test cases
This commit is contained in:
parent
a3eff7a2e8
commit
f7c27f250b
16 changed files with 904 additions and 15 deletions
|
@ -5,7 +5,7 @@ from flask import request
|
|||
|
||||
from endpoints.api import (resource, nickname, ApiResource, validate_json_request, request_error,
|
||||
related_user_resource, internal_only, Unauthorized, NotFound,
|
||||
require_user_admin)
|
||||
require_user_admin, log_action)
|
||||
from endpoints.api.team import team_view
|
||||
from endpoints.api.user import User, PrivateRepositories
|
||||
from auth.permissions import (AdministerOrganizationPermission, OrganizationMemberPermission,
|
||||
|
@ -271,9 +271,248 @@ class ApplicationInformation(ApiResource):
|
|||
if not application:
|
||||
raise NotFound()
|
||||
|
||||
org_hash = compute_hash(application.organization.email)
|
||||
gravatar = compute_hash(application.gravatar_email) if application.gravatar_email else org_hash
|
||||
|
||||
return {
|
||||
'name': application.name,
|
||||
'description': application.description,
|
||||
'uri': application.application_uri,
|
||||
'gravatar': gravatar,
|
||||
'organization': org_view(application.organization, [])
|
||||
}
|
||||
|
||||
|
||||
def app_view(application):
|
||||
is_admin = AdministerOrganizationPermission(application.organization.username).can()
|
||||
|
||||
return {
|
||||
'name': application.name,
|
||||
'description': application.description,
|
||||
'application_uri': application.application_uri,
|
||||
|
||||
'client_id': application.client_id,
|
||||
'client_secret': application.client_secret if is_admin else None,
|
||||
'redirect_uri': application.redirect_uri if is_admin else None,
|
||||
'gravatar_email': application.gravatar_email if is_admin else None,
|
||||
}
|
||||
|
||||
|
||||
@resource('/v1/organization/<orgname>/applications')
|
||||
class OrganizationApplications(ApiResource):
|
||||
""" Resource for managing applications defined by an organizations. """
|
||||
schemas = {
|
||||
'NewApp': {
|
||||
'id': 'NewApp',
|
||||
'type': 'object',
|
||||
'description': 'Description of a new organization application.',
|
||||
'required': [
|
||||
'name',
|
||||
],
|
||||
'properties': {
|
||||
'name': {
|
||||
'type': 'string',
|
||||
'description': 'The name of the application',
|
||||
},
|
||||
'redirect_uri': {
|
||||
'type': 'string',
|
||||
'description': 'The URI for the application\'s OAuth redirect',
|
||||
},
|
||||
'application_uri': {
|
||||
'type': 'string',
|
||||
'description': 'The URI for the application\'s homepage',
|
||||
},
|
||||
'description': {
|
||||
'type': ['string', 'null'],
|
||||
'description': 'The human-readable description for the application',
|
||||
},
|
||||
'gravatar_email': {
|
||||
'type': ['string', 'null'],
|
||||
'description': 'The e-mail address of the gravatar to use for the application',
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@nickname('getOrganizationApplications')
|
||||
def get(self, orgname):
|
||||
""" List the applications for the specified organization """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
applications = model.oauth.list_applications_for_org(org)
|
||||
return {'applications': [app_view(application) for application in applications]}
|
||||
|
||||
raise Unauthorized()
|
||||
|
||||
@nickname('createOrganizationApplication')
|
||||
@validate_json_request('NewApp')
|
||||
def post(self, orgname):
|
||||
""" Creates a new application under this organization. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
app_data = request.get_json()
|
||||
application = model.oauth.create_application(
|
||||
org, app_data['name'],
|
||||
app_data.get('application_uri', ''),
|
||||
app_data.get('redirect_uri', ''),
|
||||
description = app_data.get('description', ''),
|
||||
gravatar_email = app_data.get('gravatar_email', None),)
|
||||
|
||||
|
||||
app_data.update({
|
||||
'application_name': application.name,
|
||||
'client_id': application.client_id
|
||||
})
|
||||
|
||||
log_action('create_application', orgname, app_data)
|
||||
|
||||
return app_view(application)
|
||||
raise Unauthorized()
|
||||
|
||||
|
||||
@resource('/v1/organization/<orgname>/applications/<client_id>')
|
||||
class OrganizationApplicationResource(ApiResource):
|
||||
""" Resource for managing an application defined by an organizations. """
|
||||
schemas = {
|
||||
'UpdateApp': {
|
||||
'id': 'UpdateApp',
|
||||
'type': 'object',
|
||||
'description': 'Description of an updated application.',
|
||||
'required': [
|
||||
'name',
|
||||
'redirect_uri',
|
||||
'application_uri'
|
||||
],
|
||||
'properties': {
|
||||
'name': {
|
||||
'type': 'string',
|
||||
'description': 'The name of the application',
|
||||
},
|
||||
'redirect_uri': {
|
||||
'type': 'string',
|
||||
'description': 'The URI for the application\'s OAuth redirect',
|
||||
},
|
||||
'application_uri': {
|
||||
'type': 'string',
|
||||
'description': 'The URI for the application\'s homepage',
|
||||
},
|
||||
'description': {
|
||||
'type': ['string', 'null'],
|
||||
'description': 'The human-readable description for the application',
|
||||
},
|
||||
'gravatar_email': {
|
||||
'type': ['string', 'null'],
|
||||
'description': 'The e-mail address of the gravatar to use for the application',
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@nickname('getOrganizationApplication')
|
||||
def get(self, orgname, client_id):
|
||||
""" Retrieves the application with the specified client_id under the specified organization """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
application = model.oauth.lookup_application(org, client_id)
|
||||
if not application:
|
||||
raise NotFound()
|
||||
|
||||
return app_view(application)
|
||||
|
||||
raise Unauthorized()
|
||||
|
||||
@nickname('updateOrganizationApplication')
|
||||
@validate_json_request('UpdateApp')
|
||||
def put(self, orgname, client_id):
|
||||
""" Updates an application under this organization. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
application = model.oauth.lookup_application(org, client_id)
|
||||
if not application:
|
||||
raise NotFound()
|
||||
|
||||
app_data = request.get_json()
|
||||
application.name = app_data['name']
|
||||
application.application_uri = app_data['application_uri']
|
||||
application.redirect_uri = app_data['redirect_uri']
|
||||
application.description = app_data.get('description', '')
|
||||
application.gravatar_email = app_data.get('gravatar_email', None)
|
||||
application.save()
|
||||
|
||||
app_data.update({
|
||||
'application_name': application.name,
|
||||
'client_id': application.client_id
|
||||
})
|
||||
|
||||
log_action('update_application', orgname, app_data)
|
||||
|
||||
return app_view(application)
|
||||
raise Unauthorized()
|
||||
|
||||
|
||||
@nickname('deleteOrganizationApplication')
|
||||
def delete(self, orgname, client_id):
|
||||
""" Deletes the application under this organization. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
application = model.oauth.delete_application(org, client_id)
|
||||
if not application:
|
||||
raise NotFound()
|
||||
|
||||
log_action('delete_application', orgname,
|
||||
{'application_name': application.name, 'client_id': client_id})
|
||||
|
||||
return 'Deleted', 204
|
||||
raise Unauthorized()
|
||||
|
||||
|
||||
@resource('/v1/organization/<orgname>/applications/<client_id>/resetclientsecret')
|
||||
@internal_only
|
||||
class OrganizationApplicationResetClientSecret(ApiResource):
|
||||
""" Custom verb for resetting the client secret of an application. """
|
||||
@nickname('resetOrganizationApplicationClientSecret')
|
||||
def post(self, orgname, client_id):
|
||||
""" Resets the client secret of the application. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
application = model.oauth.lookup_application(org, client_id)
|
||||
if not application:
|
||||
raise NotFound()
|
||||
|
||||
application = model.oauth.reset_client_secret(application)
|
||||
log_action('reset_application_client_secret', orgname,
|
||||
{'application_name': application.name, 'client_id': client_id})
|
||||
|
||||
return app_view(application)
|
||||
raise Unauthorized()
|
||||
|
|
Reference in a new issue