Merge remote-tracking branch 'origin/master' into swaggerlikeus

Conflicts:
	data/database.py
	endpoints/api.py
	endpoints/common.py
	templates/base.html
	test/data/test.db
	test/specs.py
This commit is contained in:
jakedt 2014-03-19 15:39:44 -04:00
commit c93c62600d
59 changed files with 4636 additions and 216 deletions

View file

@ -18,9 +18,23 @@ user_files = app.config['USERFILES']
build_logs = app.config['BUILDLOGS']
def get_trigger_config(trigger):
try:
return json.loads(trigger.config)
except:
return {}
def get_job_config(build_obj):
try:
return json.loads(build_obj.job_config)
except:
return None
def trigger_view(trigger):
if trigger and trigger.uuid:
config_dict = json.loads(trigger.config)
config_dict = get_trigger_config(trigger)
build_trigger = BuildTrigger.get_trigger_for_service(trigger.service.name)
return {
'service': trigger.service.name,
@ -42,7 +56,7 @@ def build_status_view(build_obj, can_write=False):
'started': format_date(build_obj.started),
'display_name': build_obj.display_name,
'status': status,
'job_config': json.loads(build_obj.job_config) if can_write else None,
'job_config': get_job_config(build_obj) if can_write else None,
'is_writer': can_write,
'trigger': trigger_view(build_obj.trigger),
'resource_key': build_obj.resource_key,
@ -54,7 +68,7 @@ def build_status_view(build_obj, can_write=False):
return resp
@resource('/v1/repository/<path:repository>/build/')
@resource('/v1/repository/<repopath:repository>/build/')
class RepositoryBuildList(RepositoryParamResource):
""" Resource related to creating and listing repository builds. """
schemas = {
@ -127,7 +141,7 @@ class RepositoryBuildList(RepositoryParamResource):
return resp, 201, headers
@resource('/v1/repository/<path:repository>/build/<build_uuid>/status')
@resource('/v1/repository/<repopath:repository>/build/<build_uuid>/status')
class RepositoryBuildStatus(RepositoryParamResource):
""" Resource for dealing with repository build status. """
@require_repo_read
@ -142,7 +156,7 @@ class RepositoryBuildStatus(RepositoryParamResource):
return build_status_view(build, can_write)
@resource('/v1/repository/<path:repository>/build/<build_uuid>/logs')
@resource('/v1/repository/<repopath:repository>/build/<build_uuid>/logs')
class RepositoryBuildLogs(RepositoryParamResource):
""" Resource for loading repository build logs. """
@require_repo_write

View file

@ -29,7 +29,7 @@ def image_view(image):
}
@resource('/v1/repository/<path:repository>/image/')
@resource('/v1/repository/<repopath:repository>/image/')
class RepositoryImageList(RepositoryParamResource):
""" Resource for listing repository images. """
@require_repo_read
@ -54,7 +54,7 @@ class RepositoryImageList(RepositoryParamResource):
}
@resource('/v1/repository/<path:repository>/image/<image_id>')
@resource('/v1/repository/<repopath:repository>/image/<image_id>')
class RepositoryImage(RepositoryParamResource):
""" Resource for handling repository images. """
@require_repo_read
@ -68,7 +68,7 @@ class RepositoryImage(RepositoryParamResource):
return image_view(image)
@resource('/v1/repository/<path:repository>/image/<image_id>/changes')
@resource('/v1/repository/<repopath:repository>/image/<image_id>/changes')
class RepositoryImageChanges(RepositoryParamResource):
""" Resource for handling repository image change lists. """

View file

@ -63,7 +63,7 @@ def get_logs(namespace, start_time, end_time, performer_name=None,
}
@resource('/v1/repository/<path:repository>/logs')
@resource('/v1/repository/<repopath:repository>/logs')
@internal_only
class RepositoryLogs(RepositoryParamResource):
""" Resource for fetching logs for the specific repository. """

View file

@ -25,7 +25,7 @@ def wrap_role_view_org(role_json, user, org_members):
return role_json
@resource('/v1/repository/<path:repository>/permissions/team/')
@resource('/v1/repository/<repopath:repository>/permissions/team/')
class RepositoryTeamPermissionList(RepositoryParamResource):
""" Resource for repository team permissions. """
@require_repo_admin
@ -40,7 +40,7 @@ class RepositoryTeamPermissionList(RepositoryParamResource):
}
@resource('/v1/repository/<path:repository>/permissions/user/')
@resource('/v1/repository/<repopath:repository>/permissions/user/')
class RepositoryUserPermissionList(RepositoryParamResource):
""" Resource for repository user permissions. """
@require_repo_admin
@ -79,7 +79,7 @@ class RepositoryUserPermissionList(RepositoryParamResource):
}
@resource('/v1/repository/<path:repository>/permissions/user/<username>')
@resource('/v1/repository/<repopath:repository>/permissions/user/<username>')
class RepositoryUserPermission(RepositoryParamResource):
""" Resource for managing individual user permissions. """
schemas = {
@ -174,7 +174,7 @@ class RepositoryUserPermission(RepositoryParamResource):
return 'Deleted', 204
@resource('/v1/repository/<path:repository>/permissions/team/<teamname>')
@resource('/v1/repository/<repopath:repository>/permissions/team/<teamname>')
class RepositoryTeamPermission(RepositoryParamResource):
""" Resource for managing individual team permissions. """
schemas = {

View file

@ -152,7 +152,7 @@ def image_view(image):
'size': extended_props.image_size,
}
@resource('/v1/repository/<path:repository>')
@resource('/v1/repository/<repopath:repository>')
class Repository(RepositoryParamResource):
"""Operations for managing a specific repository."""
schemas = {
@ -248,7 +248,7 @@ class Repository(RepositoryParamResource):
return 'Deleted', 204
@resource('/v1/repository/<path:repository>/changevisibility')
@resource('/v1/repository/<repopath:repository>/changevisibility')
class RepositoryVisibility(RepositoryParamResource):
""" Custom verb for changing the visibility of the repository. """
schemas = {

View file

@ -18,7 +18,7 @@ def token_view(token_obj):
}
@resource('/v1/repository/<path:repository>/tokens/')
@resource('/v1/repository/<repopath:repository>/tokens/')
class RepositoryTokenList(RepositoryParamResource):
""" Resource for creating and listing repository tokens. """
schemas = {
@ -65,7 +65,7 @@ class RepositoryTokenList(RepositoryParamResource):
return token_view(token), 201
@resource('/v1/repository/<path:repository>/tokens/<code>')
@resource('/v1/repository/<repopath:repository>/tokens/<code>')
class RepositoryToken(RepositoryParamResource):
""" Resource for managing individual tokens. """
schemas = {

View file

@ -2,6 +2,7 @@ import logging
import stripe
from endpoints.api import request_error, log_action, NotFound
from endpoints.common import check_repository_usage
from data import model
from data.plans import PLANS
@ -58,6 +59,7 @@ def subscribe(user, plan, token, require_business_plan):
cus = stripe.Customer.create(email=user.email, plan=plan, card=card)
user.stripe_id = cus.id
user.save()
check_repository_usage(user, plan_found)
log_action('account_change_plan', user.username, {'plan': plan})
except stripe.CardError as e:
return carderror_response(e)
@ -74,6 +76,7 @@ def subscribe(user, plan, token, require_business_plan):
# We only have to cancel the subscription if they actually have one
cus.cancel_subscription()
cus.save()
check_repository_usage(user, plan_found)
log_action('account_change_plan', user.username, {'plan': plan})
else:
@ -89,6 +92,7 @@ def subscribe(user, plan, token, require_business_plan):
return carderror_response(e)
response_json = subscription_view(cus.subscription, private_repos)
check_repository_usage(user, plan_found)
log_action('account_change_plan', user.username, {'plan': plan})
return response_json, status_code

View file

@ -5,7 +5,7 @@ from data import model
from auth.auth_context import get_authenticated_user
@resource('/v1/repository/<path:repository>/tag/<tag>')
@resource('/v1/repository/<repopath:repository>/tag/<tag>')
class RepositoryTag(RepositoryParamResource):
""" Resource for managing repository tags. """
@ -24,7 +24,7 @@ class RepositoryTag(RepositoryParamResource):
return 'Deleted', 204
@resource('/v1/repository/<path:repository>/tag/<tag>/images')
@resource('/v1/repository/<repopath:repository>/tag/<tag>/images')
class RepositoryTagImages(RepositoryParamResource):
""" Resource for listing the images in a specific repository tag. """
@require_repo_read

View file

@ -9,7 +9,8 @@ from app import app
from endpoints.api import (RepositoryParamResource, nickname, resource, require_repo_admin,
log_action, request_error, query_param, parse_args, internal_only,
validate_json_request, api, Unauthorized, NotFound, InvalidRequest)
from endpoints.api.build import build_status_view, trigger_view, RepositoryBuildStatus
from endpoints.api.build import (build_status_view, trigger_view, RepositoryBuildStatus,
get_trigger_config)
from endpoints.common import start_build
from endpoints.trigger import (BuildTrigger as BuildTriggerBase, TriggerDeactivationException,
TriggerActivationException, EmptyRepositoryException)
@ -25,7 +26,7 @@ def _prepare_webhook_url(scheme, username, password, hostname, path):
return urlunparse((scheme, auth_hostname, path, '', '', ''))
@resource('/v1/repository/<path:repository>/trigger/')
@resource('/v1/repository/<repopath:repository>/trigger/')
class BuildTriggerList(RepositoryParamResource):
""" Resource for listing repository build triggers. """
@ -39,7 +40,7 @@ class BuildTriggerList(RepositoryParamResource):
}
@resource('/v1/repository/<path:repository>/trigger/<trigger_uuid>')
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>')
class BuildTrigger(RepositoryParamResource):
""" Resource for managing specific build triggers. """
@ -64,7 +65,7 @@ class BuildTrigger(RepositoryParamResource):
raise NotFound()
handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
config_dict = json.loads(trigger.config)
config_dict = get_trigger_config(trigger)
if handler.is_active(config_dict):
try:
handler.deactivate(trigger.auth_token, config_dict)
@ -81,7 +82,7 @@ class BuildTrigger(RepositoryParamResource):
return 'No Content', 204
@resource('/v1/repository/<path:repository>/trigger/<trigger_uuid>/subdir')
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/subdir')
@internal_only
class BuildTriggerSubdirs(RepositoryParamResource):
""" Custom verb for fetching the subdirs which are buildable for a trigger. """
@ -123,7 +124,7 @@ class BuildTriggerSubdirs(RepositoryParamResource):
raise Unauthorized()
@resource('/v1/repository/<path:repository>/trigger/<trigger_uuid>/activate')
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/activate')
@internal_only
class BuildTriggerActivate(RepositoryParamResource):
""" Custom verb for activating a build trigger once all required information has been collected.
@ -147,7 +148,7 @@ class BuildTriggerActivate(RepositoryParamResource):
raise NotFound()
handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
existing_config_dict = json.loads(trigger.config)
existing_config_dict = get_trigger_config(trigger)
if handler.is_active(existing_config_dict):
raise InvalidRequest('Trigger config is not sufficient for activation.')
@ -191,7 +192,7 @@ class BuildTriggerActivate(RepositoryParamResource):
raise Unauthorized()
@resource('/v1/repository/<path:repository>/trigger/<trigger_uuid>/start')
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/start')
class ActivateBuildTrigger(RepositoryParamResource):
""" Custom verb to manually activate a build trigger. """
@ -205,11 +206,11 @@ class ActivateBuildTrigger(RepositoryParamResource):
raise NotFound()
handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
existing_config_dict = json.loads(trigger.config)
if not handler.is_active(existing_config_dict):
config_dict = get_trigger_config(trigger)
if not handler.is_active(config_dict):
raise InvalidRequest('Trigger is not active.')
specs = handler.manual_start(trigger.auth_token, json.loads(trigger.config))
specs = handler.manual_start(trigger.auth_token, config_dict)
dockerfile_id, tags, name, subdir = specs
repo = model.get_repository(namespace, repository)
@ -225,7 +226,7 @@ class ActivateBuildTrigger(RepositoryParamResource):
return resp, 201, headers
@resource('/v1/repository/<path:repository>/trigger/<trigger_uuid>/builds')
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/builds')
class TriggerBuildList(RepositoryParamResource):
""" Resource to represent builds that were activated from the specified trigger. """
@require_repo_admin
@ -242,7 +243,7 @@ class TriggerBuildList(RepositoryParamResource):
}
@resource('/v1/repository/<path:repository>/trigger/<trigger_uuid>/sources')
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/sources')
@internal_only
class BuildTriggerSources(RepositoryParamResource):
""" Custom verb to fetch the list of build sources for the trigger config. """

View file

@ -1,5 +1,6 @@
import logging
import stripe
import json
from flask import request
from flask.ext.login import logout_user
@ -8,7 +9,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, internal_only, NotFound, Unauthorized, require_user_admin,
require_user_read, InvalidToken, require_scope)
require_user_read, InvalidToken, require_scope, format_date)
from endpoints.api.subscribe import subscribe
from endpoints.common import common_login
from data import model
@ -60,6 +61,15 @@ def user_view(user):
}
def notification_view(notification):
return {
'organization': notification.target.username if notification.target.organization else None,
'kind': notification.kind.name,
'created': format_date(notification.created),
'metadata': json.loads(notification.metadata_json),
}
@resource('/v1/user/')
class User(ApiResource):
""" Operations related to users. """
@ -364,3 +374,15 @@ class Recovery(ApiResource):
code = model.create_reset_password_email_code(email)
send_recovery_email(email, code.code)
return 'Created', 201
@resource('/v1/user/notifications')
@internal_only
class UserNotificationList(ApiResource):
@require_user_admin
@nickname('listUserNotifications')
def get(self):
notifications = model.list_notifications(get_authenticated_user())
return {
'notifications': [notification_view(notification) for notification in notifications]
}

View file

@ -14,7 +14,7 @@ def webhook_view(webhook):
}
@resource('/v1/repository/<path:repository>/webhook/')
@resource('/v1/repository/<repopath:repository>/webhook/')
class WebhookList(RepositoryParamResource):
""" Resource for dealing with listing and creating webhooks. """
schemas = {
@ -52,7 +52,7 @@ class WebhookList(RepositoryParamResource):
}
@resource('/v1/repository/<path:repository>/webhook/<public_id>')
@resource('/v1/repository/<repopath:repository>/webhook/<public_id>')
class Webhook(RepositoryParamResource):
""" Resource for dealing with specific webhooks. """
@require_repo_admin