Merge the plans and mark many as deprecated. Fix a bunch of pylint errors.
This commit is contained in:
parent
2d0a61b6c2
commit
5633c1fc79
3 changed files with 119 additions and 81 deletions
|
@ -1,20 +1,13 @@
|
|||
import json
|
||||
import itertools
|
||||
|
||||
USER_PLANS = [
|
||||
{
|
||||
'title': 'Open Source',
|
||||
'price': 0,
|
||||
'privateRepos': 0,
|
||||
'stripeId': 'free',
|
||||
'audience': 'Share with the world',
|
||||
},
|
||||
PLANS = [
|
||||
# Deprecated Plans
|
||||
{
|
||||
'title': 'Micro',
|
||||
'price': 700,
|
||||
'privateRepos': 5,
|
||||
'stripeId': 'micro',
|
||||
'audience': 'For smaller teams',
|
||||
'bus_features': False,
|
||||
'deprecated': True,
|
||||
},
|
||||
{
|
||||
'title': 'Basic',
|
||||
|
@ -22,6 +15,8 @@ USER_PLANS = [
|
|||
'privateRepos': 10,
|
||||
'stripeId': 'small',
|
||||
'audience': 'For your basic team',
|
||||
'bus_features': False,
|
||||
'deprecated': True,
|
||||
},
|
||||
{
|
||||
'title': 'Medium',
|
||||
|
@ -29,6 +24,8 @@ USER_PLANS = [
|
|||
'privateRepos': 20,
|
||||
'stripeId': 'medium',
|
||||
'audience': 'For medium teams',
|
||||
'bus_features': False,
|
||||
'deprecated': True,
|
||||
},
|
||||
{
|
||||
'title': 'Large',
|
||||
|
@ -36,16 +33,28 @@ USER_PLANS = [
|
|||
'privateRepos': 50,
|
||||
'stripeId': 'large',
|
||||
'audience': 'For larger teams',
|
||||
'bus_features': False,
|
||||
'deprecated': True,
|
||||
},
|
||||
]
|
||||
|
||||
BUSINESS_PLANS = [
|
||||
# Active plans
|
||||
{
|
||||
'title': 'Open Source',
|
||||
'price': 0,
|
||||
'privateRepos': 0,
|
||||
'stripeId': 'bus-free',
|
||||
'stripeId': 'free',
|
||||
'audience': 'Committment to FOSS',
|
||||
'bus_features': False,
|
||||
'deprecated': False,
|
||||
},
|
||||
{
|
||||
'title': 'Personal',
|
||||
'price': 1200,
|
||||
'privateRepos': 5,
|
||||
'stripeId': 'personal',
|
||||
'audience': 'Individuals',
|
||||
'bus_features': False,
|
||||
'deprecated': False,
|
||||
},
|
||||
{
|
||||
'title': 'Skiff',
|
||||
|
@ -53,6 +62,8 @@ BUSINESS_PLANS = [
|
|||
'privateRepos': 10,
|
||||
'stripeId': 'bus-micro',
|
||||
'audience': 'For startups',
|
||||
'bus_features': True,
|
||||
'deprecated': False,
|
||||
},
|
||||
{
|
||||
'title': 'Yacht',
|
||||
|
@ -60,6 +71,8 @@ BUSINESS_PLANS = [
|
|||
'privateRepos': 20,
|
||||
'stripeId': 'bus-small',
|
||||
'audience': 'For small businesses',
|
||||
'bus_features': True,
|
||||
'deprecated': False,
|
||||
},
|
||||
{
|
||||
'title': 'Freighter',
|
||||
|
@ -67,6 +80,8 @@ BUSINESS_PLANS = [
|
|||
'privateRepos': 50,
|
||||
'stripeId': 'bus-medium',
|
||||
'audience': 'For normal businesses',
|
||||
'bus_features': True,
|
||||
'deprecated': False,
|
||||
},
|
||||
{
|
||||
'title': 'Tanker',
|
||||
|
@ -74,14 +89,16 @@ BUSINESS_PLANS = [
|
|||
'privateRepos': 125,
|
||||
'stripeId': 'bus-large',
|
||||
'audience': 'For large businesses',
|
||||
'bus_features': True,
|
||||
'deprecated': False,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def get_plan(id):
|
||||
def get_plan(plan_id):
|
||||
""" Returns the plan with the given ID or None if none. """
|
||||
for plan in itertools.chain(USER_PLANS, BUSINESS_PLANS):
|
||||
if plan['stripeId'] == id:
|
||||
for plan in PLANS:
|
||||
if plan['stripeId'] == plan_id:
|
||||
return plan
|
||||
|
||||
return None
|
||||
|
|
128
endpoints/api.py
128
endpoints/api.py
|
@ -12,7 +12,7 @@ from collections import defaultdict
|
|||
|
||||
from data import model
|
||||
from data.queue import dockerfile_build_queue
|
||||
from data.plans import USER_PLANS, BUSINESS_PLANS, get_plan
|
||||
from data.plans import PLANS, get_plan
|
||||
from app import app
|
||||
from util.email import send_confirmation_email, send_recovery_email
|
||||
from util.names import parse_repository_name, format_robot_username
|
||||
|
@ -30,6 +30,7 @@ from endpoints.web import common_login
|
|||
from util.cache import cache_control
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
store = app.config['STORAGE']
|
||||
user_files = app.config['USERFILES']
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -37,8 +38,9 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
def log_action(kind, user_or_orgname, metadata={}, repo=None):
|
||||
performer = current_user.db_user()
|
||||
model.log_action(kind, user_or_orgname, performer=performer, ip=request.remote_addr,
|
||||
metadata=metadata, repository=repo)
|
||||
model.log_action(kind, user_or_orgname, performer=performer,
|
||||
ip=request.remote_addr, metadata=metadata, repository=repo)
|
||||
|
||||
|
||||
def api_login_required(f):
|
||||
@wraps(f)
|
||||
|
@ -64,7 +66,7 @@ def handle_dme(ex):
|
|||
|
||||
|
||||
@app.errorhandler(KeyError)
|
||||
def handle_dme(ex):
|
||||
def handle_dme_key_error(ex):
|
||||
return make_response(ex.message, 400)
|
||||
|
||||
|
||||
|
@ -76,8 +78,7 @@ def welcome():
|
|||
@app.route('/api/plans/')
|
||||
def plans_list():
|
||||
return jsonify({
|
||||
'user': USER_PLANS,
|
||||
'business': BUSINESS_PLANS,
|
||||
'plans': PLANS,
|
||||
})
|
||||
|
||||
|
||||
|
@ -164,7 +165,7 @@ def convert_user_to_organization():
|
|||
|
||||
# Subscribe the organization to the new plan.
|
||||
plan = convert_data['plan']
|
||||
subscribe(user, plan, None, BUSINESS_PLANS)
|
||||
subscribe(user, plan, None, PLANS)
|
||||
|
||||
# Convert the user to an organization.
|
||||
model.convert_user_to_organization(user, model.get_user(admin_username))
|
||||
|
@ -172,7 +173,6 @@ def convert_user_to_organization():
|
|||
|
||||
# And finally login with the admin credentials.
|
||||
return conduct_signin(admin_username, admin_password)
|
||||
|
||||
|
||||
|
||||
@app.route('/api/user/', methods=['PUT'])
|
||||
|
@ -427,7 +427,7 @@ def change_organization_details(orgname):
|
|||
except model.InvalidOrganizationException:
|
||||
abort(404)
|
||||
|
||||
org_data = request.get_json();
|
||||
org_data = request.get_json()
|
||||
if 'invoice_email' in org_data:
|
||||
logger.debug('Changing invoice_email for organization: %s', org.username)
|
||||
model.change_invoice_email(org, org_data['invoice_email'])
|
||||
|
@ -477,7 +477,7 @@ def get_organization_member(orgname, membername):
|
|||
abort(404)
|
||||
|
||||
member_dict = None
|
||||
member_teams = model.get_organization_members_with_teams(org, membername = membername)
|
||||
member_teams = model.get_organization_members_with_teams(org, membername=membername)
|
||||
for member in member_teams:
|
||||
if not member_dict:
|
||||
member_dict = {'username': member.user.username,
|
||||
|
@ -551,17 +551,20 @@ def update_organization_team(orgname, teamname):
|
|||
log_action('org_create_team', orgname, {'team': teamname})
|
||||
|
||||
if is_existing:
|
||||
if 'description' in details and team.description != details['description']:
|
||||
if ('description' in details and
|
||||
team.description != details['description']):
|
||||
team.description = details['description']
|
||||
team.save()
|
||||
log_action('org_set_team_description', orgname, {'team': teamname, 'description': team.description})
|
||||
log_action('org_set_team_description', orgname,
|
||||
{'team': teamname, 'description': team.description})
|
||||
|
||||
if 'role' in details:
|
||||
role = model.get_team_org_role(team).name
|
||||
if role != details['role']:
|
||||
team = model.set_team_org_permission(team, details['role'],
|
||||
current_user.db_user().username)
|
||||
log_action('org_set_team_role', orgname, {'team': teamname, 'role': details['role']})
|
||||
log_action('org_set_team_role', orgname,
|
||||
{'team': teamname, 'role': details['role']})
|
||||
|
||||
resp = jsonify(team_view(orgname, team))
|
||||
if not is_existing:
|
||||
|
@ -629,7 +632,8 @@ def update_organization_team_member(orgname, teamname, membername):
|
|||
|
||||
# Add the user to the team.
|
||||
model.add_user_to_team(user, team)
|
||||
log_action('org_add_team_member', orgname, {'member': membername, 'team': teamname})
|
||||
log_action('org_add_team_member', orgname,
|
||||
{'member': membername, 'team': teamname})
|
||||
return jsonify(member_view(user))
|
||||
|
||||
abort(403)
|
||||
|
@ -644,7 +648,8 @@ def delete_organization_team_member(orgname, teamname, membername):
|
|||
# Remote the user from the team.
|
||||
invoking_user = current_user.db_user().username
|
||||
model.remove_user_from_team(orgname, teamname, membername, invoking_user)
|
||||
log_action('org_remove_team_member', orgname, {'member': membername, 'team': teamname})
|
||||
log_action('org_remove_team_member', orgname,
|
||||
{'member': membername, 'team': teamname})
|
||||
return make_response('Deleted', 204)
|
||||
|
||||
abort(403)
|
||||
|
@ -673,7 +678,9 @@ def create_repo_api():
|
|||
repo.description = req['description']
|
||||
repo.save()
|
||||
|
||||
log_action('create_repo', namespace_name, {'repo': repository_name, 'namespace': namespace_name}, repo=repo)
|
||||
log_action('create_repo', namespace_name,
|
||||
{'repo': repository_name, 'namespace': namespace_name},
|
||||
repo=repo)
|
||||
return jsonify({
|
||||
'namespace': namespace_name,
|
||||
'name': repository_name
|
||||
|
@ -758,7 +765,8 @@ def update_repo_api(namespace, repository):
|
|||
repo.description = values['description']
|
||||
repo.save()
|
||||
|
||||
log_action('set_repo_description', namespace, {'repo': repository, 'description': values['description']},
|
||||
log_action('set_repo_description', namespace,
|
||||
{'repo': repository, 'description': values['description']},
|
||||
repo=repo)
|
||||
return jsonify({
|
||||
'success': True
|
||||
|
@ -778,7 +786,8 @@ def change_repo_visibility_api(namespace, repository):
|
|||
if repo:
|
||||
values = request.get_json()
|
||||
model.set_repository_visibility(repo, values['visibility'])
|
||||
log_action('change_repo_visibility', namespace, {'repo': repository, 'visibility': values['visibility']},
|
||||
log_action('change_repo_visibility', namespace,
|
||||
{'repo': repository, 'visibility': values['visibility']},
|
||||
repo=repo)
|
||||
return jsonify({
|
||||
'success': True
|
||||
|
@ -795,7 +804,8 @@ def delete_repository(namespace, repository):
|
|||
if permission.can():
|
||||
model.purge_repository(namespace, repository)
|
||||
registry.delete_repository_storage(namespace, repository)
|
||||
log_action('delete_repo', namespace, {'repo': repository, 'namespace': namespace})
|
||||
log_action('delete_repo', namespace,
|
||||
{'repo': repository, 'namespace': namespace})
|
||||
return make_response('Deleted', 204)
|
||||
|
||||
abort(403)
|
||||
|
@ -912,7 +922,8 @@ def request_repo_build(namespace, repository):
|
|||
dockerfile_build_queue.put(json.dumps({'build_id': build_request.id}))
|
||||
|
||||
log_action('build_dockerfile', namespace,
|
||||
{'repo': repository, 'namespace': namespace, 'fileid': dockerfile_id}, repo=repo)
|
||||
{'repo': repository, 'namespace': namespace,
|
||||
'fileid': dockerfile_id}, repo=repo)
|
||||
|
||||
resp = jsonify({
|
||||
'started': True
|
||||
|
@ -943,7 +954,8 @@ def create_webhook(namespace, repository):
|
|||
resp.headers['Location'] = url_for('get_webhook', repository=repo_string,
|
||||
public_id=webhook.public_id)
|
||||
log_action('add_repo_webhook', namespace,
|
||||
{'repo': repository, 'webhook_id': webhook.public_id}, repo=repo)
|
||||
{'repo': repository, 'webhook_id': webhook.public_id},
|
||||
repo=repo)
|
||||
return resp
|
||||
|
||||
abort(403) # Permissions denied
|
||||
|
@ -1143,7 +1155,8 @@ def list_repo_user_permissions(namespace, repository):
|
|||
current_func = role_view_func
|
||||
|
||||
def wrapped_role_org_view(repo_perm):
|
||||
return wrap_role_view_org(current_func(repo_perm), repo_perm.user, org_members)
|
||||
return wrap_role_view_org(current_func(repo_perm), repo_perm.user,
|
||||
org_members)
|
||||
|
||||
role_view_func = wrapped_role_org_view
|
||||
|
||||
|
@ -1228,7 +1241,8 @@ def change_user_permissions(namespace, repository, username):
|
|||
return error_resp
|
||||
|
||||
log_action('change_repo_permission', namespace,
|
||||
{'username': username, 'repo': repository, 'role': new_permission['role']},
|
||||
{'username': username, 'repo': repository,
|
||||
'role': new_permission['role']},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
|
||||
resp = jsonify(perm_view)
|
||||
|
@ -1255,7 +1269,8 @@ def change_team_permissions(namespace, repository, teamname):
|
|||
new_permission['role'])
|
||||
|
||||
log_action('change_repo_permission', namespace,
|
||||
{'team': teamname, 'repo': repository, 'role': new_permission['role']},
|
||||
{'team': teamname, 'repo': repository,
|
||||
'role': new_permission['role']},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
|
||||
resp = jsonify(role_view(perm))
|
||||
|
@ -1282,7 +1297,8 @@ def delete_user_permissions(namespace, repository, username):
|
|||
error_resp.status_code = 400
|
||||
return error_resp
|
||||
|
||||
log_action('delete_repo_permission', namespace, {'username': username, 'repo': repository},
|
||||
log_action('delete_repo_permission', namespace,
|
||||
{'username': username, 'repo': repository},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
|
||||
return make_response('Deleted', 204)
|
||||
|
@ -1299,7 +1315,8 @@ def delete_team_permissions(namespace, repository, teamname):
|
|||
if permission.can():
|
||||
model.delete_team_permission(teamname, namespace, repository)
|
||||
|
||||
log_action('delete_repo_permission', namespace, {'team': teamname, 'repo': repository},
|
||||
log_action('delete_repo_permission', namespace,
|
||||
{'team': teamname, 'repo': repository},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
|
||||
return make_response('Deleted', 204)
|
||||
|
@ -1353,7 +1370,8 @@ def create_token(namespace, repository):
|
|||
token = model.create_delegate_token(namespace, repository,
|
||||
token_params['friendlyName'])
|
||||
|
||||
log_action('add_repo_accesstoken', namespace, {'repo': repository, 'token': token_params['friendlyName']},
|
||||
log_action('add_repo_accesstoken', namespace,
|
||||
{'repo': repository, 'token': token_params['friendlyName']},
|
||||
repo = model.get_repository(namespace, repository))
|
||||
|
||||
resp = jsonify(token_view(token))
|
||||
|
@ -1378,7 +1396,8 @@ def change_token(namespace, repository, code):
|
|||
new_permission['role'])
|
||||
|
||||
log_action('change_repo_permission', namespace,
|
||||
{'repo': repository, 'token': token.friendly_name, 'code': code, 'role': new_permission['role']},
|
||||
{'repo': repository, 'token': token.friendly_name, 'code': code,
|
||||
'role': new_permission['role']},
|
||||
repo = model.get_repository(namespace, repository))
|
||||
|
||||
resp = jsonify(token_view(token))
|
||||
|
@ -1397,7 +1416,8 @@ def delete_token(namespace, repository, code):
|
|||
token = model.delete_delegate_token(namespace, repository, code)
|
||||
|
||||
log_action('delete_repo_accesstoken', namespace,
|
||||
{'repo': repository, 'token': token.friendly_name, 'code': code},
|
||||
{'repo': repository, 'token': token.friendly_name,
|
||||
'code': code},
|
||||
repo = model.get_repository(namespace, repository))
|
||||
|
||||
return make_response('Deleted', 204)
|
||||
|
@ -1486,9 +1506,9 @@ def get_card(user):
|
|||
|
||||
if default_card:
|
||||
card_info = {
|
||||
'owner': card.name,
|
||||
'type': card.type,
|
||||
'last4': card.last4
|
||||
'owner': default_card.name,
|
||||
'type': default_card.type,
|
||||
'last4': default_card.last4
|
||||
}
|
||||
|
||||
return jsonify({'card': card_info})
|
||||
|
@ -1500,7 +1520,7 @@ def subscribe_api():
|
|||
plan = request_data['plan']
|
||||
token = request_data['token'] if 'token' in request_data else None
|
||||
user = current_user.db_user()
|
||||
return subscribe(user, plan, token, USER_PLANS)
|
||||
return subscribe(user, plan, token, PLANS)
|
||||
|
||||
|
||||
def carderror_response(e):
|
||||
|
@ -1511,15 +1531,18 @@ def carderror_response(e):
|
|||
return resp
|
||||
|
||||
|
||||
def subscribe(user, plan, token, accepted_plans):
|
||||
def subscribe(user, plan, token, require_business_plan):
|
||||
plan_found = None
|
||||
for plan_obj in accepted_plans:
|
||||
for plan_obj in PLANS:
|
||||
if plan_obj['stripeId'] == plan:
|
||||
plan_found = plan_obj
|
||||
|
||||
if not plan_found:
|
||||
abort(404)
|
||||
|
||||
if require_business_plan and not plan_found['bus_features']:
|
||||
abort(404)
|
||||
|
||||
private_repos = model.get_private_repo_count(user.username)
|
||||
|
||||
# This is the default response
|
||||
|
@ -1619,7 +1642,7 @@ def subscribe_org_api(orgname):
|
|||
plan = request_data['plan']
|
||||
token = request_data['token'] if 'token' in request_data else None
|
||||
organization = model.get_organization(orgname)
|
||||
return subscribe(organization, plan, token, BUSINESS_PLANS)
|
||||
return subscribe(organization, plan, token, PLANS)
|
||||
|
||||
abort(403)
|
||||
|
||||
|
@ -1743,20 +1766,20 @@ def delete_org_robot(orgname, robot_shortname):
|
|||
|
||||
|
||||
def log_view(log):
|
||||
view = {
|
||||
'kind': log.kind.name,
|
||||
'metadata': json.loads(log.metadata_json),
|
||||
'ip': log.ip,
|
||||
'datetime': log.datetime,
|
||||
view = {
|
||||
'kind': log.kind.name,
|
||||
'metadata': json.loads(log.metadata_json),
|
||||
'ip': log.ip,
|
||||
'datetime': log.datetime,
|
||||
}
|
||||
|
||||
if log.performer:
|
||||
view['performer'] = {
|
||||
'username': log.performer.username,
|
||||
'is_robot': log.performer.robot,
|
||||
}
|
||||
|
||||
if log.performer:
|
||||
view['performer'] = {
|
||||
'username': log.performer.username,
|
||||
'is_robot': log.performer.robot,
|
||||
}
|
||||
|
||||
return view
|
||||
return view
|
||||
|
||||
|
||||
|
||||
|
@ -1786,12 +1809,14 @@ def org_logs_api(orgname):
|
|||
start_time = request.args.get('starttime', None)
|
||||
end_time = request.args.get('endtime', None)
|
||||
|
||||
return get_logs(orgname, start_time, end_time, performer_name=performer_name)
|
||||
return get_logs(orgname, start_time, end_time,
|
||||
performer_name=performer_name)
|
||||
|
||||
abort(403)
|
||||
|
||||
|
||||
def get_logs(namespace, start_time, end_time, performer_name=None, repository=None):
|
||||
def get_logs(namespace, start_time, end_time, performer_name=None,
|
||||
repository=None):
|
||||
performer = None
|
||||
if performer_name:
|
||||
performer = model.get_user(performer_name)
|
||||
|
@ -1815,7 +1840,8 @@ def get_logs(namespace, start_time, end_time, performer_name=None, repository=No
|
|||
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(namespace, start_time, end_time, performer=performer,
|
||||
repository=repository)
|
||||
return jsonify({
|
||||
'start_time': start_time,
|
||||
'end_time': end_time,
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
import logging
|
||||
import requests
|
||||
import stripe
|
||||
|
||||
from flask import (abort, redirect, request, url_for, render_template,
|
||||
make_response)
|
||||
from flask.ext.login import login_user, UserMixin, login_required
|
||||
from flask.ext.principal import identity_changed, Identity, AnonymousIdentity
|
||||
from flask import request, make_response
|
||||
|
||||
from data import model
|
||||
from app import app, login_manager, mixpanel
|
||||
from auth.permissions import QuayDeferredPermissionUser
|
||||
from data.plans import USER_PLANS, BUSINESS_PLANS, get_plan
|
||||
from app import app
|
||||
from util.invoice import renderInvoiceToHtml
|
||||
from util.email import send_invoice_email
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -33,10 +28,10 @@ def stripe_webhook():
|
|||
# Find the user associated with the customer ID.
|
||||
user = model.get_user_or_org_by_customer_id(customer_id)
|
||||
if user and user.invoice_email:
|
||||
# Lookup the invoice.
|
||||
invoice = stripe.Invoice.retrieve(invoice_id)
|
||||
if invoice:
|
||||
invoice_html = renderInvoiceToHtml(invoice, user)
|
||||
send_invoice_email(user.email, invoice_html)
|
||||
# Lookup the invoice.
|
||||
invoice = stripe.Invoice.retrieve(invoice_id)
|
||||
if invoice:
|
||||
invoice_html = renderInvoiceToHtml(invoice, user)
|
||||
send_invoice_email(user.email, invoice_html)
|
||||
|
||||
return make_response('Okay')
|
||||
|
|
Reference in a new issue