From 60015f0ae094ec030ac3fbcbf467705043fc0b3b Mon Sep 17 00:00:00 2001 From: jakedt Date: Fri, 14 Mar 2014 18:07:03 -0400 Subject: [PATCH] Add internal API filtering. --- endpoints/api/__init__.py | 1 + endpoints/api/billing.py | 6 +++++- endpoints/api/build.py | 3 ++- endpoints/api/discovery.py | 28 +++++++++++++++++++++------- endpoints/api/organization.py | 3 ++- endpoints/api/user.py | 8 +++++++- 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/endpoints/api/__init__.py b/endpoints/api/__init__.py index cedddab59..1a70c566d 100644 --- a/endpoints/api/__init__.py +++ b/endpoints/api/__init__.py @@ -59,6 +59,7 @@ def method_metadata(func, name): nickname = partial(add_method_metadata, 'nickname') related_user_resource = partial(add_method_metadata, 'related_user_resource') +internal_only = add_method_metadata('internal', True) def query_param(name, help_str, type=reqparse.text_type, default=None, diff --git a/endpoints/api/billing.py b/endpoints/api/billing.py index 650dd1792..a9be91200 100644 --- a/endpoints/api/billing.py +++ b/endpoints/api/billing.py @@ -5,7 +5,7 @@ from flask import request from flask.ext.restful import abort from endpoints.api import (resource, nickname, ApiResource, validate_json_request, log_action, - related_user_resource) + related_user_resource, internal_only) from endpoints.api.subscribe import subscribe, subscription_view from auth.permissions import AdministerOrganizationPermission from auth.auth_context import get_authenticated_user @@ -91,6 +91,7 @@ class ListPlans(ApiResource): @resource('/v1/user/card') +@internal_only class UserCard(ApiResource): """ Resource for managing a user's credit card. """ schemas = { @@ -127,6 +128,7 @@ class UserCard(ApiResource): @resource('/v1/organization//card') +@internal_only @related_user_resource(UserCard) class OrganizationCard(ApiResource): """ Resource for managing an organization's credit card. """ @@ -172,6 +174,7 @@ class OrganizationCard(ApiResource): @resource('/v1/user/plan') +@internal_only class UserPlan(ApiResource): """ Resource for managing a user's subscription. """ schemas = { @@ -223,6 +226,7 @@ class UserPlan(ApiResource): @resource('/v1/organization//plan') +@internal_only @related_user_resource(UserPlan) class OrganizationPlan(ApiResource): """ Resource for managing a org's subscription. """ diff --git a/endpoints/api/build.py b/endpoints/api/build.py index eed2d3325..8cf0af485 100644 --- a/endpoints/api/build.py +++ b/endpoints/api/build.py @@ -7,7 +7,7 @@ from flask.ext.restful import abort from app import app from endpoints.api import (RepositoryParamResource, parse_args, query_param, nickname, resource, require_repo_read, require_repo_write, validate_json_request, - ApiResource) + ApiResource, internal_only) from endpoints.common import start_build from data import model from auth.permissions import ModifyRepositoryPermission @@ -152,6 +152,7 @@ class RepositoryBuildLogs(RepositoryParamResource): @resource('/v1/filedrop/') +@internal_only class FileDropResource(ApiResource): """ Custom verb for setting up a client side file transfer. """ schemas = { diff --git a/endpoints/api/discovery.py b/endpoints/api/discovery.py index b46f425a7..d345fa0ca 100644 --- a/endpoints/api/discovery.py +++ b/endpoints/api/discovery.py @@ -3,7 +3,8 @@ import logging from flask.ext.restful import reqparse -from endpoints.api import ApiResource, resource, method_metadata, nickname, truthy_bool +from endpoints.api import (ApiResource, resource, method_metadata, nickname, truthy_bool, + parse_args, query_param) from app import app from auth import scopes @@ -28,7 +29,7 @@ def fully_qualified_name(method_view_class): return '%s.%s' % (inst.__module__, inst.__class__.__name__) -def swagger_route_data(): +def swagger_route_data(include_internal): apis = [] models = {} for rule in app.url_map.iter_rules(): @@ -94,10 +95,15 @@ def swagger_route_data(): scope = method_metadata(method, 'oauth2_scope') if scope: new_operation['authorizations'] = { - 'oauth2': [scope] + 'oauth2': [scope], } - operations.append(new_operation) + internal = method_metadata(method, 'internal') + if internal is not None: + new_operation['internal'] = True + + if not internal or (internal and include_internal): + operations.append(new_operation) swagger_path = PARAM_REGEX.sub(r'{\2}', rule.rule) new_resource = { @@ -106,11 +112,17 @@ def swagger_route_data(): 'operations': operations, 'name': fully_qualified_name(view_class), } + related_user_res = method_metadata(view_class, 'related_user_resource') if related_user_res is not None: new_resource['quayUserRelated'] = fully_qualified_name(related_user_res) - apis.append(new_resource) + internal = method_metadata(view_class, 'internal') + if internal is not None: + new_resource['internal'] = True + + if not internal or (internal and include_internal): + apis.append(new_resource) swagger_data = { 'apiVersion': 'v1', @@ -146,7 +158,9 @@ def swagger_route_data(): @resource('/v1/discovery') class DiscoveryResource(ApiResource): """Ability to inspect the API for usage information and documentation.""" + @parse_args + @query_param('internal', 'Whether to include internal APIs.', type=truthy_bool, default=False) @nickname('discovery') - def get(self): + def get(self, args): """ List all of the API endpoints available in the swagger API format.""" - return swagger_route_data() + return swagger_route_data(args['internal']) diff --git a/endpoints/api/organization.py b/endpoints/api/organization.py index d683be039..d271309e3 100644 --- a/endpoints/api/organization.py +++ b/endpoints/api/organization.py @@ -5,7 +5,7 @@ from flask import request from flask.ext.restful import abort from endpoints.api import (resource, nickname, ApiResource, validate_json_request, request_error, - related_user_resource) + related_user_resource, internal_only) from endpoints.api.team import team_view from endpoints.api.user import User, PrivateRepositories from auth.permissions import (AdministerOrganizationPermission, OrganizationMemberPermission, @@ -38,6 +38,7 @@ def org_view(o, teams): @resource('/v1/organization/') +@internal_only class OrganizationList(ApiResource): """ Resource for creating organizations. """ schemas = { diff --git a/endpoints/api/user.py b/endpoints/api/user.py index abbf62dca..e7f4e58f1 100644 --- a/endpoints/api/user.py +++ b/endpoints/api/user.py @@ -8,7 +8,7 @@ from flask.ext.principal import identity_changed, AnonymousIdentity from app import app from endpoints.api import (ApiResource, nickname, resource, validate_json_request, request_error, - log_action) + log_action, internal_only) from endpoints.api.subscribe import subscribe from endpoints.common import common_login from data import model @@ -121,6 +121,7 @@ class User(ApiResource): return user_view(user) @nickname('changeUserDetails') + @internal_only @validate_json_request('UpdateUser') def put(self): """ Update a users details such as password or email. """ @@ -154,6 +155,7 @@ class User(ApiResource): return user_view(user) @nickname('createNewUser') + @internal_only @validate_json_request('NewUser') def post(self): """ Create a new user. """ @@ -218,6 +220,7 @@ def conduct_signin(username_or_email, password): @resource('/v1/user/convert') +@internal_only class ConvertToOrganization(ApiResource): """ Operations for converting a user to an organization. """ schemas = { @@ -278,6 +281,7 @@ class ConvertToOrganization(ApiResource): @resource('/v1/signin') +@internal_only class Signin(ApiResource): """ Operations for signing in the user. """ schemas = { @@ -316,6 +320,7 @@ class Signin(ApiResource): @resource('/v1/signout') +@internal_only class Signout(ApiResource): """ Resource for signing out users. """ @nickname('logout') @@ -327,6 +332,7 @@ class Signout(ApiResource): @resource("/v1/recovery") +@internal_only class Recovery(ApiResource): """ Resource for requesting a password recovery email. """ schemas = {