Merge branch 'master' into comewithmeifyouwanttowork
This commit is contained in:
commit
3b72b26836
62 changed files with 923 additions and 714 deletions
|
@ -4,7 +4,7 @@ from flask import request
|
|||
from app import billing
|
||||
from endpoints.api import (resource, nickname, ApiResource, validate_json_request, log_action,
|
||||
related_user_resource, internal_only, Unauthorized, NotFound,
|
||||
require_user_admin, show_if, hide_if)
|
||||
require_user_admin, show_if, hide_if, abort)
|
||||
from endpoints.api.subscribe import subscribe, subscription_view
|
||||
from auth.permissions import AdministerOrganizationPermission
|
||||
from auth.auth_context import get_authenticated_user
|
||||
|
@ -23,7 +23,11 @@ def get_card(user):
|
|||
}
|
||||
|
||||
if user.stripe_id:
|
||||
cus = billing.Customer.retrieve(user.stripe_id)
|
||||
try:
|
||||
cus = billing.Customer.retrieve(user.stripe_id)
|
||||
except stripe.APIConnectionError as e:
|
||||
abort(503, message='Cannot contact Stripe')
|
||||
|
||||
if cus and cus.default_card:
|
||||
# Find the default card.
|
||||
default_card = None
|
||||
|
@ -46,7 +50,11 @@ def get_card(user):
|
|||
|
||||
def set_card(user, token):
|
||||
if user.stripe_id:
|
||||
cus = billing.Customer.retrieve(user.stripe_id)
|
||||
try:
|
||||
cus = billing.Customer.retrieve(user.stripe_id)
|
||||
except stripe.APIConnectionError as e:
|
||||
abort(503, message='Cannot contact Stripe')
|
||||
|
||||
if cus:
|
||||
try:
|
||||
cus.card = token
|
||||
|
@ -55,6 +63,8 @@ def set_card(user, token):
|
|||
return carderror_response(exc)
|
||||
except stripe.InvalidRequestError as exc:
|
||||
return carderror_response(exc)
|
||||
except stripe.APIConnectionError as e:
|
||||
return carderror_response(e)
|
||||
|
||||
return get_card(user)
|
||||
|
||||
|
@ -75,7 +85,11 @@ def get_invoices(customer_id):
|
|||
'plan': i.lines.data[0].plan.id if i.lines.data[0].plan else None
|
||||
}
|
||||
|
||||
invoices = billing.Invoice.all(customer=customer_id, count=12)
|
||||
try:
|
||||
invoices = billing.Invoice.all(customer=customer_id, count=12)
|
||||
except stripe.APIConnectionError as e:
|
||||
abort(503, message='Cannot contact Stripe')
|
||||
|
||||
return {
|
||||
'invoices': [invoice_view(i) for i in invoices.data]
|
||||
}
|
||||
|
@ -228,7 +242,10 @@ class UserPlan(ApiResource):
|
|||
private_repos = model.get_private_repo_count(user.username)
|
||||
|
||||
if user.stripe_id:
|
||||
cus = billing.Customer.retrieve(user.stripe_id)
|
||||
try:
|
||||
cus = billing.Customer.retrieve(user.stripe_id)
|
||||
except stripe.APIConnectionError as e:
|
||||
abort(503, message='Cannot contact Stripe')
|
||||
|
||||
if cus.subscription:
|
||||
return subscription_view(cus.subscription, private_repos)
|
||||
|
@ -291,7 +308,10 @@ class OrganizationPlan(ApiResource):
|
|||
private_repos = model.get_private_repo_count(orgname)
|
||||
organization = model.get_organization(orgname)
|
||||
if organization.stripe_id:
|
||||
cus = billing.Customer.retrieve(organization.stripe_id)
|
||||
try:
|
||||
cus = billing.Customer.retrieve(organization.stripe_id)
|
||||
except stripe.APIConnectionError as e:
|
||||
abort(503, message='Cannot contact Stripe')
|
||||
|
||||
if cus.subscription:
|
||||
return subscription_view(cus.subscription, private_repos)
|
||||
|
|
|
@ -35,6 +35,14 @@ class UserRobotList(ApiResource):
|
|||
@internal_only
|
||||
class UserRobot(ApiResource):
|
||||
""" Resource for managing a user's robots. """
|
||||
@require_user_admin
|
||||
@nickname('getUserRobot')
|
||||
def get(self, robot_shortname):
|
||||
""" Returns the user's robot with the specified name. """
|
||||
parent = get_authenticated_user()
|
||||
robot, password = model.get_robot(robot_shortname, parent)
|
||||
return robot_view(robot.username, password)
|
||||
|
||||
@require_user_admin
|
||||
@nickname('createUserRobot')
|
||||
def put(self, robot_shortname):
|
||||
|
@ -79,6 +87,18 @@ class OrgRobotList(ApiResource):
|
|||
@related_user_resource(UserRobot)
|
||||
class OrgRobot(ApiResource):
|
||||
""" Resource for managing an organization's robots. """
|
||||
@require_scope(scopes.ORG_ADMIN)
|
||||
@nickname('getOrgRobot')
|
||||
def get(self, orgname, robot_shortname):
|
||||
""" Returns the organization's robot with the specified name. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
parent = model.get_organization(orgname)
|
||||
robot, password = model.get_robot(robot_shortname, parent)
|
||||
return robot_view(robot.username, password)
|
||||
|
||||
raise Unauthorized()
|
||||
|
||||
@require_scope(scopes.ORG_ADMIN)
|
||||
@nickname('createOrgRobot')
|
||||
def put(self, orgname, robot_shortname):
|
||||
|
@ -103,3 +123,38 @@ class OrgRobot(ApiResource):
|
|||
return 'Deleted', 204
|
||||
|
||||
raise Unauthorized()
|
||||
|
||||
|
||||
@resource('/v1/user/robots/<robot_shortname>/regenerate')
|
||||
@path_param('robot_shortname', 'The short name for the robot, without any user or organization prefix')
|
||||
@internal_only
|
||||
class RegenerateUserRobot(ApiResource):
|
||||
""" Resource for regenerate an organization's robot's token. """
|
||||
@require_user_admin
|
||||
@nickname('regenerateUserRobotToken')
|
||||
def post(self, robot_shortname):
|
||||
""" Regenerates the token for a user's robot. """
|
||||
parent = get_authenticated_user()
|
||||
robot, password = model.regenerate_robot_token(robot_shortname, parent)
|
||||
log_action('regenerate_robot_token', parent.username, {'robot': robot_shortname})
|
||||
return robot_view(robot.username, password)
|
||||
|
||||
|
||||
@resource('/v1/organization/<orgname>/robots/<robot_shortname>/regenerate')
|
||||
@path_param('orgname', 'The name of the organization')
|
||||
@path_param('robot_shortname', 'The short name for the robot, without any user or organization prefix')
|
||||
@related_user_resource(RegenerateUserRobot)
|
||||
class RegenerateOrgRobot(ApiResource):
|
||||
""" Resource for regenerate an organization's robot's token. """
|
||||
@require_scope(scopes.ORG_ADMIN)
|
||||
@nickname('regenerateOrgRobotToken')
|
||||
def post(self, orgname, robot_shortname):
|
||||
""" Regenerates the token for an organization robot. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
parent = model.get_organization(orgname)
|
||||
robot, password = model.regenerate_robot_token(robot_shortname, parent)
|
||||
log_action('regenerate_robot_token', orgname, {'robot': robot_shortname})
|
||||
return robot_view(robot.username, password)
|
||||
|
||||
raise Unauthorized()
|
||||
|
|
|
@ -15,6 +15,9 @@ logger = logging.getLogger(__name__)
|
|||
def carderror_response(exc):
|
||||
return {'carderror': exc.message}, 402
|
||||
|
||||
def connection_response(exc):
|
||||
return {'message': 'Could not contact Stripe. Please try again.'}, 503
|
||||
|
||||
|
||||
def subscription_view(stripe_subscription, used_repos):
|
||||
view = {
|
||||
|
@ -74,19 +77,29 @@ def subscribe(user, plan, token, require_business_plan):
|
|||
log_action('account_change_plan', user.username, {'plan': plan})
|
||||
except stripe.CardError as e:
|
||||
return carderror_response(e)
|
||||
except stripe.APIConnectionError as e:
|
||||
return connection_response(e)
|
||||
|
||||
response_json = subscription_view(cus.subscription, private_repos)
|
||||
status_code = 201
|
||||
|
||||
else:
|
||||
# Change the plan
|
||||
cus = billing.Customer.retrieve(user.stripe_id)
|
||||
try:
|
||||
cus = billing.Customer.retrieve(user.stripe_id)
|
||||
except stripe.APIConnectionError as e:
|
||||
return connection_response(e)
|
||||
|
||||
if plan_found['price'] == 0:
|
||||
if cus.subscription is not None:
|
||||
# We only have to cancel the subscription if they actually have one
|
||||
cus.cancel_subscription()
|
||||
cus.save()
|
||||
try:
|
||||
cus.cancel_subscription()
|
||||
cus.save()
|
||||
except stripe.APIConnectionError as e:
|
||||
return connection_response(e)
|
||||
|
||||
|
||||
check_repository_usage(user, plan_found)
|
||||
log_action('account_change_plan', user.username, {'plan': plan})
|
||||
|
||||
|
@ -101,6 +114,8 @@ def subscribe(user, plan, token, require_business_plan):
|
|||
cus.save()
|
||||
except stripe.CardError as e:
|
||||
return carderror_response(e)
|
||||
except stripe.APIConnectionError as e:
|
||||
return connection_response(e)
|
||||
|
||||
response_json = subscription_view(cus.subscription, private_repos)
|
||||
check_repository_usage(user, plan_found)
|
||||
|
|
|
@ -42,24 +42,6 @@ class SuperUserLogs(ApiResource):
|
|||
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_USER_LIMIT', 0)
|
||||
}
|
||||
|
||||
abort(403)
|
||||
|
||||
|
||||
def user_view(user):
|
||||
return {
|
||||
'username': user.username,
|
||||
|
|
|
@ -350,8 +350,8 @@ class BuildTriggerAnalyze(RepositoryParamResource):
|
|||
(robot_namespace, shortname) = parse_robot_username(user.username)
|
||||
return AdministerOrganizationPermission(robot_namespace).can()
|
||||
|
||||
repo_perms = model.get_all_repo_users(base_namespace, base_repository)
|
||||
read_robots = [robot_view(perm.user) for perm in repo_perms if is_valid_robot(perm.user)]
|
||||
repo_users = list(model.get_all_repo_users_transitive(base_namespace, base_repository))
|
||||
read_robots = [robot_view(user) for user in repo_users if is_valid_robot(user)]
|
||||
|
||||
return {
|
||||
'namespace': base_namespace,
|
||||
|
|
|
@ -7,8 +7,9 @@ from flask.ext.principal import identity_changed, AnonymousIdentity
|
|||
|
||||
from app import app, billing as stripe, authentication
|
||||
from endpoints.api import (ApiResource, nickname, resource, validate_json_request, request_error,
|
||||
log_action, internal_only, NotFound, require_user_admin,
|
||||
InvalidToken, require_scope, format_date, hide_if, show_if, license_error)
|
||||
log_action, internal_only, NotFound, require_user_admin, parse_args,
|
||||
query_param, InvalidToken, require_scope, format_date, hide_if, show_if,
|
||||
license_error)
|
||||
from endpoints.api.subscribe import subscribe
|
||||
from endpoints.common import common_login
|
||||
from data import model
|
||||
|
@ -403,11 +404,24 @@ class Recovery(ApiResource):
|
|||
@internal_only
|
||||
class UserNotificationList(ApiResource):
|
||||
@require_user_admin
|
||||
@parse_args
|
||||
@query_param('page', 'Offset page number. (int)', type=int, default=0)
|
||||
@query_param('limit', 'Limit on the number of results (int)', type=int, default=5)
|
||||
@nickname('listUserNotifications')
|
||||
def get(self):
|
||||
notifications = model.list_notifications(get_authenticated_user())
|
||||
def get(self, args):
|
||||
page = args['page']
|
||||
limit = args['limit']
|
||||
|
||||
notifications = list(model.list_notifications(get_authenticated_user(), page=page, limit=limit + 1))
|
||||
has_more = False
|
||||
|
||||
if len(notifications) > limit:
|
||||
has_more = True
|
||||
notifications = notifications[0:limit]
|
||||
|
||||
return {
|
||||
'notifications': [notification_view(notification) for notification in notifications]
|
||||
'notifications': [notification_view(notification) for notification in notifications],
|
||||
'additional': has_more
|
||||
}
|
||||
|
||||
|
||||
|
|
Reference in a new issue