Merge remote-tracking branch 'origin/autobot'
This commit is contained in:
		
						commit
						3e67e39e61
					
				
					 9 changed files with 590 additions and 320 deletions
				
			
		
							
								
								
									
										138
									
								
								endpoints/api.py
									
										
									
									
									
								
							
							
						
						
									
										138
									
								
								endpoints/api.py
									
										
									
									
									
								
							|  | @ -26,7 +26,7 @@ from auth.permissions import (ReadRepositoryPermission, | |||
|                               OrganizationMemberPermission, | ||||
|                               ViewTeamPermission) | ||||
| from endpoints import registry | ||||
| from endpoints.web import common_login | ||||
| from endpoints.common import common_login | ||||
| from util.cache import cache_control | ||||
| from datetime import datetime, timedelta | ||||
| 
 | ||||
|  | @ -35,6 +35,38 @@ store = app.config['STORAGE'] | |||
| user_files = app.config['USERFILES'] | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
| route_data = None | ||||
| 
 | ||||
| def get_route_data(): | ||||
|   global route_data | ||||
|   if route_data: | ||||
|     return route_data | ||||
| 
 | ||||
|   routes = [] | ||||
|   for rule in app.url_map.iter_rules(): | ||||
|     if rule.rule.startswith('/api/'): | ||||
|       endpoint_method = globals()[rule.endpoint] | ||||
|       is_internal = '__internal_call' in dir(endpoint_method) | ||||
|       is_org_api = '__user_call' in dir(endpoint_method) | ||||
|       methods = list(rule.methods.difference(['HEAD', 'OPTIONS'])) | ||||
| 
 | ||||
|       route = { | ||||
|         'name': rule.endpoint, | ||||
|         'methods': methods, | ||||
|         'path': rule.rule, | ||||
|         'parameters': list(rule.arguments) | ||||
|       } | ||||
| 
 | ||||
|       if is_org_api: | ||||
|         route['user_method'] = endpoint_method.__user_call | ||||
| 
 | ||||
|       routes.append(route) | ||||
|        | ||||
|   route_data = { | ||||
|     'endpoints': routes | ||||
|   } | ||||
|   return route_data | ||||
| 
 | ||||
| 
 | ||||
| def log_action(kind, user_or_orgname, metadata={}, repo=None): | ||||
|   performer = current_user.db_user() | ||||
|  | @ -60,6 +92,26 @@ def api_login_required(f): | |||
|   return decorated_view | ||||
| 
 | ||||
| 
 | ||||
| def internal_api_call(f): | ||||
|   @wraps(f) | ||||
|   def decorated_view(*args, **kwargs): | ||||
|     return f(*args, **kwargs) | ||||
| 
 | ||||
|   decorated_view.__internal_call = True | ||||
|   return decorated_view | ||||
| 
 | ||||
| 
 | ||||
| def org_api_call(user_call_name): | ||||
|   def internal_decorator(f): | ||||
|     @wraps(f) | ||||
|     def decorated_view(*args, **kwargs): | ||||
|       return f(*args, **kwargs) | ||||
|      | ||||
|     decorated_view.__user_call = user_call_name | ||||
|     return decorated_view | ||||
| 
 | ||||
|   return internal_decorator | ||||
| 
 | ||||
| @app.errorhandler(model.DataModelException) | ||||
| def handle_dme(ex): | ||||
|   return make_response(ex.message, 400) | ||||
|  | @ -70,13 +122,19 @@ def handle_dme_key_error(ex): | |||
|   return make_response(ex.message, 400) | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/api/discovery') | ||||
| def discovery(): | ||||
|   return jsonify(get_route_data()) | ||||
| 
 | ||||
|    | ||||
| @app.route('/api/') | ||||
| @internal_api_call | ||||
| def welcome(): | ||||
|   return make_response('welcome', 200) | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/api/plans/') | ||||
| def plans_list(): | ||||
| def list_plans(): | ||||
|   return jsonify({ | ||||
|     'plans': PLANS, | ||||
|   }) | ||||
|  | @ -108,6 +166,7 @@ def user_view(user): | |||
| 
 | ||||
| 
 | ||||
| @app.route('/api/user/', methods=['GET']) | ||||
| @internal_api_call | ||||
| def get_logged_in_user(): | ||||
|   if current_user.is_anonymous(): | ||||
|     return jsonify({'anonymous': True}) | ||||
|  | @ -121,6 +180,7 @@ def get_logged_in_user(): | |||
| 
 | ||||
| @app.route('/api/user/private', methods=['GET']) | ||||
| @api_login_required | ||||
| @internal_api_call | ||||
| def get_user_private_count(): | ||||
|   user = current_user.db_user() | ||||
|   private_repos = model.get_private_repo_count(user.username) | ||||
|  | @ -141,6 +201,7 @@ def get_user_private_count(): | |||
| 
 | ||||
| @app.route('/api/user/convert', methods=['POST']) | ||||
| @api_login_required | ||||
| @internal_api_call | ||||
| def convert_user_to_organization(): | ||||
|   user = current_user.db_user() | ||||
|   convert_data = request.get_json() | ||||
|  | @ -177,6 +238,7 @@ def convert_user_to_organization(): | |||
| 
 | ||||
| @app.route('/api/user/', methods=['PUT']) | ||||
| @api_login_required | ||||
| @internal_api_call | ||||
| def change_user_details(): | ||||
|   user = current_user.db_user() | ||||
| 
 | ||||
|  | @ -203,7 +265,8 @@ def change_user_details(): | |||
| 
 | ||||
| 
 | ||||
| @app.route('/api/user/', methods=['POST']) | ||||
| def create_user_api(): | ||||
| @internal_api_call | ||||
| def create_new_user(): | ||||
|   user_data = request.get_json() | ||||
| 
 | ||||
|   existing_user = model.get_user(user_data['username']) | ||||
|  | @ -229,7 +292,8 @@ def create_user_api(): | |||
| 
 | ||||
| 
 | ||||
| @app.route('/api/signin', methods=['POST']) | ||||
| def signin_api(): | ||||
| @internal_api_call | ||||
| def signin_user(): | ||||
|   signin_data = request.get_json() | ||||
| 
 | ||||
|   username = signin_data['username'] | ||||
|  | @ -263,6 +327,7 @@ def conduct_signin(username, password): | |||
| 
 | ||||
| @app.route("/api/signout", methods=['POST']) | ||||
| @api_login_required | ||||
| @internal_api_call | ||||
| def logout(): | ||||
|   logout_user() | ||||
|   identity_changed.send(app, identity=AnonymousIdentity()) | ||||
|  | @ -270,7 +335,8 @@ def logout(): | |||
| 
 | ||||
| 
 | ||||
| @app.route("/api/recovery", methods=['POST']) | ||||
| def send_recovery(): | ||||
| @internal_api_call | ||||
| def request_recovery_email(): | ||||
|   email = request.get_json()['email'] | ||||
|   code = model.create_reset_password_email_code(email) | ||||
|   send_recovery_email(email, code.code) | ||||
|  | @ -355,7 +421,8 @@ def team_view(orgname, team): | |||
| 
 | ||||
| @app.route('/api/organization/', methods=['POST']) | ||||
| @api_login_required | ||||
| def create_organization_api(): | ||||
| @internal_api_call | ||||
| def create_organization(): | ||||
|   org_data = request.get_json() | ||||
|   existing = None | ||||
| 
 | ||||
|  | @ -419,6 +486,7 @@ def get_organization(orgname): | |||
| 
 | ||||
| @app.route('/api/organization/<orgname>', methods=['PUT']) | ||||
| @api_login_required | ||||
| @org_api_call('change_user_details') | ||||
| def change_organization_details(orgname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|  | @ -496,6 +564,7 @@ def get_organization_member(orgname, membername): | |||
| 
 | ||||
| @app.route('/api/organization/<orgname>/private', methods=['GET']) | ||||
| @api_login_required | ||||
| @internal_api_call | ||||
| def get_organization_private_allowed(orgname): | ||||
|   permission = CreateRepositoryPermission(orgname) | ||||
|   if permission.can(): | ||||
|  | @ -657,7 +726,7 @@ def delete_organization_team_member(orgname, teamname, membername): | |||
| 
 | ||||
| @app.route('/api/repository', methods=['POST']) | ||||
| @api_login_required | ||||
| def create_repo_api(): | ||||
| def create_repo(): | ||||
|   owner = current_user.db_user() | ||||
|   req = request.get_json() | ||||
|   namespace_name = req['namespace'] if 'namespace' in req else owner.username | ||||
|  | @ -690,7 +759,7 @@ def create_repo_api(): | |||
| 
 | ||||
| 
 | ||||
| @app.route('/api/find/repository', methods=['GET']) | ||||
| def match_repos_api(): | ||||
| def find_repos(): | ||||
|   prefix = request.args.get('query', '') | ||||
| 
 | ||||
|   def repo_view(repo): | ||||
|  | @ -713,7 +782,7 @@ def match_repos_api(): | |||
| 
 | ||||
| 
 | ||||
| @app.route('/api/repository/', methods=['GET']) | ||||
| def list_repos_api(): | ||||
| def list_repos(): | ||||
|   def repo_view(repo_obj): | ||||
|     return { | ||||
|       'namespace': repo_obj.namespace, | ||||
|  | @ -756,7 +825,7 @@ def list_repos_api(): | |||
| @app.route('/api/repository/<path:repository>', methods=['PUT']) | ||||
| @api_login_required | ||||
| @parse_repository_name | ||||
| def update_repo_api(namespace, repository): | ||||
| def update_repo(namespace, repository): | ||||
|   permission = ModifyRepositoryPermission(namespace, repository) | ||||
|   if permission.can(): | ||||
|     repo = model.get_repository(namespace, repository) | ||||
|  | @ -779,7 +848,7 @@ def update_repo_api(namespace, repository): | |||
|            methods=['POST']) | ||||
| @api_login_required | ||||
| @parse_repository_name | ||||
| def change_repo_visibility_api(namespace, repository): | ||||
| def change_repo_visibility(namespace, repository): | ||||
|   permission = AdministerRepositoryPermission(namespace, repository) | ||||
|   if permission.can(): | ||||
|     repo = model.get_repository(namespace, repository) | ||||
|  | @ -823,7 +892,7 @@ def image_view(image): | |||
| 
 | ||||
| @app.route('/api/repository/<path:repository>', methods=['GET']) | ||||
| @parse_repository_name | ||||
| def get_repo_api(namespace, repository): | ||||
| def get_repo(namespace, repository): | ||||
|   logger.debug('Get repo: %s/%s' % (namespace, repository)) | ||||
| 
 | ||||
|   def tag_view(tag): | ||||
|  | @ -1006,6 +1075,7 @@ def delete_webhook(namespace, repository, public_id): | |||
| 
 | ||||
| @app.route('/api/filedrop/', methods=['POST']) | ||||
| @api_login_required | ||||
| @internal_api_call | ||||
| def get_filedrop_url(): | ||||
|   mime_type = request.get_json()['mimeType'] | ||||
|   (url, file_id) = user_files.prepare_for_drop(mime_type) | ||||
|  | @ -1436,14 +1506,17 @@ def subscription_view(stripe_subscription, used_repos): | |||
| 
 | ||||
| @app.route('/api/user/card', methods=['GET']) | ||||
| @api_login_required | ||||
| def get_user_card_api(): | ||||
| @internal_api_call | ||||
| def get_user_card(): | ||||
|   user = current_user.db_user() | ||||
|   return get_card(user) | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/api/organization/<orgname>/card', methods=['GET']) | ||||
| @api_login_required | ||||
| def get_org_card_api(orgname): | ||||
| @internal_api_call | ||||
| @org_api_call('get_user_card') | ||||
| def get_org_card(orgname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|     organization = model.get_organization(orgname) | ||||
|  | @ -1454,7 +1527,8 @@ def get_org_card_api(orgname): | |||
| 
 | ||||
| @app.route('/api/user/card', methods=['POST']) | ||||
| @api_login_required | ||||
| def set_user_card_api(): | ||||
| @internal_api_call | ||||
| def set_user_card(): | ||||
|   user = current_user.db_user() | ||||
|   token = request.get_json()['token'] | ||||
|   response = set_card(user, token) | ||||
|  | @ -1464,7 +1538,8 @@ def set_user_card_api(): | |||
| 
 | ||||
| @app.route('/api/organization/<orgname>/card', methods=['POST']) | ||||
| @api_login_required | ||||
| def set_org_card_api(orgname): | ||||
| @org_api_call('set_user_card') | ||||
| def set_org_card(orgname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|     organization = model.get_organization(orgname) | ||||
|  | @ -1515,7 +1590,8 @@ def get_card(user): | |||
| 
 | ||||
| @app.route('/api/user/plan', methods=['PUT']) | ||||
| @api_login_required | ||||
| def subscribe_api(): | ||||
| @internal_api_call | ||||
| def update_user_subscription(): | ||||
|   request_data = request.get_json() | ||||
|   plan = request_data['plan'] | ||||
|   token = request_data['token'] if 'token' in request_data else None | ||||
|  | @ -1607,7 +1683,7 @@ def subscribe(user, plan, token, require_business_plan): | |||
| 
 | ||||
| @app.route('/api/user/invoices', methods=['GET']) | ||||
| @api_login_required | ||||
| def user_invoices_api(): | ||||
| def list_user_invoices(): | ||||
|   user = current_user.db_user() | ||||
|   if not user.stripe_id: | ||||
|     abort(404) | ||||
|  | @ -1617,7 +1693,8 @@ def user_invoices_api(): | |||
| 
 | ||||
| @app.route('/api/organization/<orgname>/invoices', methods=['GET']) | ||||
| @api_login_required | ||||
| def org_invoices_api(orgname): | ||||
| @org_api_call('list_user_invoices') | ||||
| def list_org_invoices(orgname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|     organization = model.get_organization(orgname) | ||||
|  | @ -1653,7 +1730,9 @@ def get_invoices(customer_id): | |||
| 
 | ||||
| @app.route('/api/organization/<orgname>/plan', methods=['PUT']) | ||||
| @api_login_required | ||||
| def subscribe_org_api(orgname): | ||||
| @internal_api_call | ||||
| @org_api_call('update_user_subscription') | ||||
| def update_org_subscription(orgname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|     request_data = request.get_json() | ||||
|  | @ -1667,7 +1746,8 @@ def subscribe_org_api(orgname): | |||
| 
 | ||||
| @app.route('/api/user/plan', methods=['GET']) | ||||
| @api_login_required | ||||
| def get_subscription(): | ||||
| @internal_api_call | ||||
| def get_user_subscription(): | ||||
|   user = current_user.db_user() | ||||
|   private_repos = model.get_private_repo_count(user.username) | ||||
| 
 | ||||
|  | @ -1685,6 +1765,8 @@ def get_subscription(): | |||
| 
 | ||||
| @app.route('/api/organization/<orgname>/plan', methods=['GET']) | ||||
| @api_login_required | ||||
| @internal_api_call | ||||
| @org_api_call('get_user_subscription') | ||||
| def get_org_subscription(orgname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|  | @ -1723,6 +1805,7 @@ def get_user_robots(): | |||
| 
 | ||||
| @app.route('/api/organization/<orgname>/robots', methods=['GET']) | ||||
| @api_login_required | ||||
| @org_api_call('get_user_robots') | ||||
| def get_org_robots(orgname): | ||||
|   permission = OrganizationMemberPermission(orgname) | ||||
|   if permission.can(): | ||||
|  | @ -1736,7 +1819,7 @@ def get_org_robots(orgname): | |||
| 
 | ||||
| @app.route('/api/user/robots/<robot_shortname>', methods=['PUT']) | ||||
| @api_login_required | ||||
| def create_robot(robot_shortname): | ||||
| def create_user_robot(robot_shortname): | ||||
|   parent = current_user.db_user() | ||||
|   robot, password = model.create_robot(robot_shortname, parent) | ||||
|   resp = jsonify(robot_view(robot.username, password)) | ||||
|  | @ -1748,6 +1831,7 @@ def create_robot(robot_shortname): | |||
| @app.route('/api/organization/<orgname>/robots/<robot_shortname>', | ||||
|            methods=['PUT']) | ||||
| @api_login_required | ||||
| @org_api_call('create_user_robot') | ||||
| def create_org_robot(orgname, robot_shortname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|  | @ -1763,7 +1847,7 @@ def create_org_robot(orgname, robot_shortname): | |||
| 
 | ||||
| @app.route('/api/user/robots/<robot_shortname>', methods=['DELETE']) | ||||
| @api_login_required | ||||
| def delete_robot(robot_shortname): | ||||
| def delete_user_robot(robot_shortname): | ||||
|   parent = current_user.db_user() | ||||
|   model.delete_robot(format_robot_username(parent.username, robot_shortname)) | ||||
|   log_action('delete_robot', parent.username, {'robot': robot_shortname}) | ||||
|  | @ -1773,6 +1857,7 @@ def delete_robot(robot_shortname): | |||
| @app.route('/api/organization/<orgname>/robots/<robot_shortname>', | ||||
|            methods=['DELETE']) | ||||
| @api_login_required | ||||
| @org_api_call('delete_user_robot') | ||||
| def delete_org_robot(orgname, robot_shortname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|  | @ -1804,7 +1889,7 @@ def log_view(log): | |||
| @app.route('/api/repository/<path:repository>/logs', methods=['GET']) | ||||
| @api_login_required | ||||
| @parse_repository_name | ||||
| def repo_logs_api(namespace, repository): | ||||
| def list_repo_logs(namespace, repository): | ||||
|   permission = AdministerRepositoryPermission(namespace, repository) | ||||
|   if permission.can(): | ||||
|     repo = model.get_repository(namespace, repository) | ||||
|  | @ -1820,7 +1905,8 @@ def repo_logs_api(namespace, repository): | |||
| 
 | ||||
| @app.route('/api/organization/<orgname>/logs', methods=['GET']) | ||||
| @api_login_required | ||||
| def org_logs_api(orgname): | ||||
| @org_api_call('list_user_logs') | ||||
| def list_org_logs(orgname): | ||||
|   permission = AdministerOrganizationPermission(orgname) | ||||
|   if permission.can(): | ||||
|     performer_name = request.args.get('performer', None) | ||||
|  | @ -1835,7 +1921,7 @@ def org_logs_api(orgname): | |||
| 
 | ||||
| @app.route('/api/user/logs', methods=['GET']) | ||||
| @api_login_required | ||||
| def user_logs_api(): | ||||
| def list_user_logs(): | ||||
|   performer_name = request.args.get('performer', None) | ||||
|   start_time = request.args.get('starttime', None) | ||||
|   end_time = request.args.get('endtime', None) | ||||
|  |  | |||
							
								
								
									
										48
									
								
								endpoints/common.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								endpoints/common.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| import logging | ||||
| 
 | ||||
| from flask.ext.login import login_user, UserMixin | ||||
| from flask.ext.principal import identity_changed | ||||
| 
 | ||||
| from data import model | ||||
| from app import app, login_manager | ||||
| from auth.permissions import QuayDeferredPermissionUser | ||||
| 
 | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
| 
 | ||||
| @login_manager.user_loader | ||||
| def load_user(username): | ||||
|   logger.debug('Loading user: %s' % username) | ||||
|   return _LoginWrappedDBUser(username) | ||||
| 
 | ||||
| class _LoginWrappedDBUser(UserMixin): | ||||
|   def __init__(self, db_username, db_user=None): | ||||
| 
 | ||||
|     self._db_username = db_username | ||||
|     self._db_user = db_user | ||||
| 
 | ||||
|   def db_user(self): | ||||
|     if not self._db_user: | ||||
|       self._db_user = model.get_user(self._db_username) | ||||
|     return self._db_user | ||||
| 
 | ||||
|   def is_authenticated(self): | ||||
|     return self.db_user() is not None | ||||
| 
 | ||||
|   def is_active(self): | ||||
|     return self.db_user().verified | ||||
| 
 | ||||
|   def get_id(self): | ||||
|     return unicode(self._db_username) | ||||
| 
 | ||||
| 
 | ||||
| def common_login(db_user): | ||||
|   if login_user(_LoginWrappedDBUser(db_user.username, db_user)): | ||||
|     logger.debug('Successfully signed in as: %s' % db_user.username) | ||||
|     new_identity = QuayDeferredPermissionUser(db_user.username, 'username') | ||||
|     identity_changed.send(app, identity=new_identity) | ||||
|     return True | ||||
|   else: | ||||
|     logger.debug('User could not be logged in, inactive?.') | ||||
|     return False | ||||
|  | @ -4,53 +4,30 @@ import stripe | |||
| 
 | ||||
| from flask import (abort, redirect, request, url_for, render_template, | ||||
|                    make_response, Response) | ||||
| from flask.ext.login import login_user, UserMixin, current_user | ||||
| from flask.ext.principal import identity_changed | ||||
| from flask.ext.login import current_user | ||||
| from urlparse import urlparse | ||||
| 
 | ||||
| from data import model | ||||
| from app import app, login_manager, mixpanel | ||||
| from auth.permissions import (QuayDeferredPermissionUser, | ||||
|                               AdministerOrganizationPermission) | ||||
| from app import app, mixpanel | ||||
| from auth.permissions import AdministerOrganizationPermission | ||||
| from util.invoice import renderInvoiceToPdf | ||||
| from util.seo import render_snapshot | ||||
| from endpoints.api import get_route_data | ||||
| from endpoints.common import common_login | ||||
| 
 | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
| 
 | ||||
| class _LoginWrappedDBUser(UserMixin): | ||||
|   def __init__(self, db_username, db_user=None): | ||||
| 
 | ||||
|     self._db_username = db_username | ||||
|     self._db_user = db_user | ||||
| 
 | ||||
|   def db_user(self): | ||||
|     if not self._db_user: | ||||
|       self._db_user = model.get_user(self._db_username) | ||||
|     return self._db_user | ||||
| 
 | ||||
|   def is_authenticated(self): | ||||
|     return self.db_user() is not None | ||||
| 
 | ||||
|   def is_active(self): | ||||
|     return self.db_user().verified | ||||
| 
 | ||||
|   def get_id(self): | ||||
|     return unicode(self._db_username) | ||||
| 
 | ||||
| 
 | ||||
| @login_manager.user_loader | ||||
| def load_user(username): | ||||
|   logger.debug('Loading user: %s' % username) | ||||
|   return _LoginWrappedDBUser(username) | ||||
| def render_page_template(name): | ||||
|   return render_template(name, route_data = get_route_data()) | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/', methods=['GET'], defaults={'path': ''}) | ||||
| @app.route('/repository/<path:path>', methods=['GET']) | ||||
| @app.route('/organization/<path:path>', methods=['GET']) | ||||
| def index(path): | ||||
|   return render_template('index.html') | ||||
|   return render_page_template('index.html') | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/snapshot', methods=['GET']) | ||||
|  | @ -81,6 +58,7 @@ def guide(): | |||
| def organizations(): | ||||
|   return index('') | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/user/') | ||||
| def user(): | ||||
|   return index('') | ||||
|  | @ -119,17 +97,17 @@ def status(): | |||
| 
 | ||||
| @app.route('/tos', methods=['GET']) | ||||
| def tos(): | ||||
|   return render_template('tos.html') | ||||
|   return render_page_template('tos.html') | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/disclaimer', methods=['GET']) | ||||
| def disclaimer(): | ||||
|   return render_template('disclaimer.html') | ||||
|   return render_page_template('disclaimer.html') | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/privacy', methods=['GET']) | ||||
| def privacy(): | ||||
|   return render_template('privacy.html') | ||||
|   return render_page_template('privacy.html') | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/receipt', methods=['GET']) | ||||
|  | @ -162,17 +140,6 @@ def receipt(): | |||
|   abort(404) | ||||
| 
 | ||||
| 
 | ||||
| def common_login(db_user): | ||||
|   if login_user(_LoginWrappedDBUser(db_user.username, db_user)): | ||||
|     logger.debug('Successfully signed in as: %s' % db_user.username) | ||||
|     new_identity = QuayDeferredPermissionUser(db_user.username, 'username') | ||||
|     identity_changed.send(app, identity=new_identity) | ||||
|     return True | ||||
|   else: | ||||
|     logger.debug('User could not be logged in, inactive?.') | ||||
|     return False | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/oauth2/github/callback', methods=['GET']) | ||||
| def github_oauth_callback(): | ||||
|   code = request.args.get('code') | ||||
|  | @ -228,12 +195,12 @@ def github_oauth_callback(): | |||
|         mixpanel.alias(to_login.username, state) | ||||
| 
 | ||||
|     except model.DataModelException, ex: | ||||
|       return render_template('githuberror.html', error_message=ex.message) | ||||
|       return render_page_template('githuberror.html', error_message=ex.message) | ||||
| 
 | ||||
|   if common_login(to_login): | ||||
|     return redirect(url_for('index')) | ||||
| 
 | ||||
|   return render_template('githuberror.html') | ||||
|   return render_page_template('githuberror.html') | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/confirm', methods=['GET']) | ||||
|  |  | |||
							
								
								
									
										330
									
								
								static/js/app.js
									
										
									
									
									
								
							
							
						
						
									
										330
									
								
								static/js/app.js
									
										
									
									
									
								
							|  | @ -1,6 +1,18 @@ | |||
| var TEAM_PATTERN = '^[a-zA-Z][a-zA-Z0-9]+$'; | ||||
| var ROBOT_PATTERN = '^[a-zA-Z][a-zA-Z0-9]+$'; | ||||
| 
 | ||||
| function getRestUrl(args) { | ||||
|   var url = ''; | ||||
|   for (var i = 0; i < arguments.length; ++i) { | ||||
|     if (i > 0) { | ||||
|        url += '/'; | ||||
|     } | ||||
|     url += encodeURI(arguments[i]) | ||||
|   } | ||||
|   return url; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| function getFirstTextLine(commentString) { | ||||
|   if (!commentString) { return ''; } | ||||
|        | ||||
|  | @ -34,11 +46,8 @@ function getFirstTextLine(commentString) { | |||
|   return ''; | ||||
| } | ||||
| 
 | ||||
| function createRobotAccount(Restangular, is_org, orgname, name, callback) { | ||||
|   var url = is_org ? getRestUrl('organization', orgname, 'robots', name) : | ||||
|       getRestUrl('user/robots', name); | ||||
|   var createRobot = Restangular.one(url); | ||||
|   createRobot.customPUT().then(callback, function(resp) { | ||||
| function createRobotAccount(ApiService, is_org, orgname, name, callback) { | ||||
|   ApiService.createRobot(is_org ? orgname : null, null, {'robot_shortname': name}).then(callback, function(resp) { | ||||
|     bootbox.dialog({ | ||||
|       "message": resp.data ? resp.data : 'The robot account could not be created', | ||||
|       "title": "Cannot create robot account", | ||||
|  | @ -52,14 +61,18 @@ function createRobotAccount(Restangular, is_org, orgname, name, callback) { | |||
|   }); | ||||
| } | ||||
| 
 | ||||
| function createOrganizationTeam(Restangular, orgname, teamname, callback) { | ||||
|   var createTeam = Restangular.one(getRestUrl('organization', orgname, 'team', teamname)); | ||||
| function createOrganizationTeam(ApiService, orgname, teamname, callback) { | ||||
|   var data = { | ||||
|     'name': teamname, | ||||
|     'role': 'member' | ||||
|   }; | ||||
| 
 | ||||
|   var params = { | ||||
|     'orgname': orgname, | ||||
|     'teamname': teamname | ||||
|   }; | ||||
|    | ||||
|   createTeam.customPOST(data).then(callback, function() { | ||||
|   ApiService.updateOrganizationTeam(data, params).then(callback, function() { | ||||
|     bootbox.dialog({ | ||||
|       "message": resp.data ? resp.data : 'The team could not be created', | ||||
|       "title": "Cannot create team", | ||||
|  | @ -73,17 +86,6 @@ function createOrganizationTeam(Restangular, orgname, teamname, callback) { | |||
|   }); | ||||
| } | ||||
| 
 | ||||
| function getRestUrl(args) { | ||||
|   var url = ''; | ||||
|   for (var i = 0; i < arguments.length; ++i) { | ||||
|     if (i > 0) { | ||||
|        url += '/'; | ||||
|     } | ||||
|     url += encodeURI(arguments[i]) | ||||
|   } | ||||
|   return url; | ||||
| } | ||||
| 
 | ||||
| function getMarkedDown(string) { | ||||
|   return Markdown.getSanitizingConverter().makeHtml(string || ''); | ||||
| } | ||||
|  | @ -91,6 +93,137 @@ function getMarkedDown(string) { | |||
| // Start the application code itself.
 | ||||
| quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'restangular', 'angularMoment', 'angulartics', /*'angulartics.google.analytics',*/ 'angulartics.mixpanel', '$strap.directives', 'ngCookies'], function($provide, cfpLoadingBarProvider) { | ||||
|     cfpLoadingBarProvider.includeSpinner = false; | ||||
| 
 | ||||
|     $provide.factory('ApiService', ['Restangular', function(Restangular) { | ||||
|       var apiService = {}; | ||||
| 
 | ||||
|       var getResource = function(path) { | ||||
|         var resource = {}; | ||||
|         resource.url = path; | ||||
|         resource.withOptions = function(options) { | ||||
|           this.options = options; | ||||
|           return this; | ||||
|         }; | ||||
| 
 | ||||
|         resource.get = function(processor, opt_errorHandler) { | ||||
|           var options = this.options; | ||||
|           var performer = Restangular.one(this.url); | ||||
| 
 | ||||
|           var result = { | ||||
|             'loading': true, | ||||
|             'value': null, | ||||
|             'hasError': false | ||||
|           }; | ||||
| 
 | ||||
|           performer.get(options).then(function(resp) { | ||||
|             result.value = processor(resp); | ||||
|             result.loading = false; | ||||
|           }, function(resp) { | ||||
|             result.hasError = true; | ||||
|             result.loading = false; | ||||
|             if (opt_errorHandler) { | ||||
|               opt_errorHandler(resp); | ||||
|             } | ||||
|           }); | ||||
| 
 | ||||
|           return result; | ||||
|         }; | ||||
| 
 | ||||
|         return resource; | ||||
|       }; | ||||
| 
 | ||||
|       var formatMethodName = function(endpointName) { | ||||
|         var formatted = ''; | ||||
|         for (var i = 0; i < endpointName.length; ++i) { | ||||
|           var c = endpointName[i]; | ||||
|           if (c == '_') { | ||||
|             c = endpointName[i + 1].toUpperCase(); | ||||
|             i++; | ||||
|           } | ||||
| 
 | ||||
|           formatted += c; | ||||
|         } | ||||
| 
 | ||||
|         return formatted; | ||||
|       }; | ||||
| 
 | ||||
|       var buildUrl = function(path, parameters) { | ||||
|         // We already have /api/ on the URLs, so remove them from the paths.
 | ||||
|         path = path.substr('/api/'.length, path.length); | ||||
| 
 | ||||
|         var url = ''; | ||||
|         for (var i = 0; i < path.length; ++i) { | ||||
|           var c = path[i]; | ||||
|           if (c == '<') { | ||||
|             var end = path.indexOf('>', i); | ||||
|             var varName = path.substr(i + 1, end - i - 1); | ||||
|             var colon = varName.indexOf(':'); | ||||
|             var isPathVar = false; | ||||
|             if (colon > 0) { | ||||
|               isPathVar = true; | ||||
|               varName = varName.substr(colon + 1); | ||||
|             } | ||||
| 
 | ||||
|             if (!parameters[varName]) { | ||||
|               throw new Error('Missing parameter: ' + varName); | ||||
|             } | ||||
| 
 | ||||
|             url += isPathVar ? parameters[varName] : encodeURI(parameters[varName]); | ||||
|             i = end; | ||||
|             continue; | ||||
|           } | ||||
| 
 | ||||
|           url += c; | ||||
|         } | ||||
| 
 | ||||
|         return url; | ||||
|       }; | ||||
| 
 | ||||
|       var getGenericMethodName = function(userMethodName) { | ||||
|         return formatMethodName(userMethodName.replace('_user', '')); | ||||
|       }; | ||||
| 
 | ||||
|       var buildMethodsForEndpoint = function(endpoint) { | ||||
|         var method = endpoint.methods[0].toLowerCase(); | ||||
|         var methodName = formatMethodName(endpoint['name']); | ||||
|         apiService[methodName] = function(opt_options, opt_parameters) { | ||||
|           return Restangular.one(buildUrl(endpoint['path'], opt_parameters))['custom' + method.toUpperCase()](opt_options); | ||||
|         }; | ||||
| 
 | ||||
|         if (method == 'get') { | ||||
|           apiService[methodName + 'AsResource'] = function(opt_parameters) { | ||||
|             return getResource(buildUrl(endpoint['path'], opt_parameters)); | ||||
|           }; | ||||
|         } | ||||
| 
 | ||||
|         if (endpoint['user_method']) { | ||||
|           apiService[getGenericMethodName(endpoint['user_method'])] = function(orgname, opt_options, opt_parameters) { | ||||
|             if (orgname) { | ||||
|               if (orgname.name) { | ||||
|                 orgname = orgname.name; | ||||
|               } | ||||
| 
 | ||||
|               var params = jQuery.extend({'orgname' : orgname}, opt_parameters || {}); | ||||
|               return apiService[methodName](opt_options, params); | ||||
|             } else { | ||||
|               return apiService[formatMethodName(endpoint['user_method'])](opt_options, opt_parameters); | ||||
|             } | ||||
|           }; | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|       // Construct the methods for each API endpoint.
 | ||||
|       if (!window.__endpoints) { | ||||
|         return apiService; | ||||
|       } | ||||
| 
 | ||||
|       for (var i = 0; i < window.__endpoints.length; ++i) { | ||||
|         var endpoint = window.__endpoints[i]; | ||||
|         buildMethodsForEndpoint(endpoint); | ||||
|       } | ||||
| 
 | ||||
|       return apiService; | ||||
|     }]); | ||||
|      | ||||
|     $provide.factory('CookieService', ['$cookies', '$cookieStore', function($cookies, $cookieStore) { | ||||
|       var cookieService = {}; | ||||
|  | @ -113,7 +246,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|       return cookieService; | ||||
|     }]); | ||||
| 
 | ||||
|     $provide.factory('UserService', ['Restangular', 'CookieService', function(Restangular, CookieService) { | ||||
|     $provide.factory('UserService', ['ApiService', 'CookieService', function(ApiService, CookieService) { | ||||
|       var userResponse = { | ||||
|         verified: false, | ||||
|         anonymous: true, | ||||
|  | @ -139,8 +272,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|       }; | ||||
| 
 | ||||
|       userService.load = function(opt_callback) { | ||||
|         var userFetch = Restangular.one('user/'); | ||||
|         userFetch.get().then(function(loadedUser) { | ||||
|         ApiService.getLoggedInUser().then(function(loadedUser) { | ||||
|           userResponse = loadedUser; | ||||
| 
 | ||||
|           if (!userResponse.anonymous) { | ||||
|  | @ -198,48 +330,6 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|       return userService; | ||||
|     }]); | ||||
| 
 | ||||
| 
 | ||||
|     $provide.factory('ApiService', ['Restangular', function(Restangular) { | ||||
|       var apiService = {} | ||||
|       apiService.at = function(locationPieces) { | ||||
|         var location = getRestUrl.apply(this, arguments); | ||||
|         var info = { | ||||
|           'url': location, | ||||
|           'caller': Restangular.one(location), | ||||
|           'withOptions': function(options) { | ||||
|             info.options = options; | ||||
|             return info; | ||||
|           }, | ||||
|             'get': function(processor, opt_errorHandler) { | ||||
|             var options = info.options; | ||||
|             var caller = info.caller; | ||||
|             var result = { | ||||
|               'loading': true, | ||||
|               'value': null, | ||||
|               'hasError': false | ||||
|             }; | ||||
| 
 | ||||
|             caller.get(options).then(function(resp) { | ||||
|               result.value = processor(resp); | ||||
|               result.loading = false; | ||||
|             }, function(resp) { | ||||
|               result.hasError = true; | ||||
|               result.loading = false; | ||||
|               if (opt_errorHandler) { | ||||
|                 opt_errorHandler(resp); | ||||
|               } | ||||
|             }); | ||||
| 
 | ||||
|             return result; | ||||
|           } | ||||
|         }; | ||||
| 
 | ||||
|         return info; | ||||
|       }; | ||||
| 
 | ||||
|       return apiService; | ||||
|     }]); | ||||
| 
 | ||||
|     $provide.factory('KeyService', ['$location', function($location) { | ||||
|       var keyService = {} | ||||
| 
 | ||||
|  | @ -254,8 +344,8 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|       return keyService; | ||||
|     }]); | ||||
| 
 | ||||
|     $provide.factory('PlanService', ['Restangular', 'KeyService', 'UserService', 'CookieService', | ||||
|         function(Restangular, KeyService, UserService, CookieService) { | ||||
|     $provide.factory('PlanService', ['KeyService', 'UserService', 'CookieService', 'ApiService', | ||||
|         function(KeyService, UserService, CookieService, ApiService) { | ||||
|       var plans = null; | ||||
|       var planDict = {}; | ||||
|       var planService = {}; | ||||
|  | @ -353,8 +443,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         var getPlans = Restangular.one('plans'); | ||||
|         getPlans.get().then(function(data) { | ||||
|         ApiService.listPlans().then(function(data) { | ||||
|           var i = 0; | ||||
|           for(i = 0; i < data.plans.length; i++) { | ||||
|             planDict[data.plans[i].stripeId] = data.plans[i]; | ||||
|  | @ -412,13 +501,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|       }; | ||||
| 
 | ||||
|       planService.getSubscription = function(orgname, success, failure) { | ||||
|         var url = planService.getSubscriptionUrl(orgname); | ||||
|         var getSubscription = Restangular.one(url); | ||||
|         getSubscription.get().then(success, failure); | ||||
|       }; | ||||
| 
 | ||||
|       planService.getSubscriptionUrl = function(orgname) { | ||||
|         return orgname ? getRestUrl('organization', orgname, 'plan') : 'user/plan'; | ||||
|          ApiService.getSubscription(orgname).then(success, failure); | ||||
|       }; | ||||
| 
 | ||||
|       planService.setSubscription = function(orgname, planId, success, failure, opt_token) { | ||||
|  | @ -430,9 +513,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|           subscriptionDetails['token'] = opt_token.id; | ||||
|         } | ||||
| 
 | ||||
|         var url = planService.getSubscriptionUrl(orgname); | ||||
|         var createSubscriptionRequest = Restangular.one(url); | ||||
|         createSubscriptionRequest.customPUT(subscriptionDetails).then(function(resp) { | ||||
|         ApiService.updateSubscription(orgname, subscriptionDetails).then(function(resp) { | ||||
|           success(resp); | ||||
|           planService.getPlan(planId, function(plan) { | ||||
|             for (var i = 0; i < listeners.length; ++i) { | ||||
|  | @ -443,9 +524,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|       }; | ||||
| 
 | ||||
|       planService.getCardInfo = function(orgname, callback) { | ||||
|         var url = orgname ? getRestUrl('organization', orgname, 'card') : 'user/card';        | ||||
|         var getCard = Restangular.one(url); | ||||
|         getCard.customGET().then(function(resp) { | ||||
|         ApiService.getCard(orgname).then(function(resp) { | ||||
|           callback(resp.card); | ||||
|         }, function() { | ||||
|           callback({'is_valid': false}); | ||||
|  | @ -492,12 +571,10 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest | |||
|               'token': token.id | ||||
|             }; | ||||
| 
 | ||||
|             var url = orgname ? getRestUrl('organization', orgname, 'card') : 'user/card'; | ||||
|             var changeCardRequest = Restangular.one(url); | ||||
|               changeCardRequest.customPOST(cardInfo).then(callbacks['success'], function(resp) { | ||||
|                 planService.handleCardError(resp); | ||||
|                 callbacks['failure'](resp); | ||||
|               }); | ||||
|             ApiService.setCard(orgname, cardInfo).then(callbacks['success'], function(resp) { | ||||
|               planService.handleCardError(resp); | ||||
|               callbacks['failure'](resp); | ||||
|             }); | ||||
|           }); | ||||
|         }; | ||||
| 
 | ||||
|  | @ -739,10 +816,9 @@ quayApp.directive('userSetup', function () { | |||
|       'signInStarted': '&signInStarted', | ||||
|       'signedIn': '&signedIn' | ||||
|     }, | ||||
|     controller: function($scope, $location, $timeout, Restangular, KeyService, UserService) { | ||||
|     controller: function($scope, $location, $timeout, ApiService, KeyService, UserService) { | ||||
|       $scope.sendRecovery = function() { | ||||
|         var signinPost = Restangular.one('recovery'); | ||||
|         signinPost.customPOST($scope.recovery).then(function() { | ||||
|         ApiService.requestRecoveryEmail($scope.recovery).then(function() { | ||||
|           $scope.invalidEmail = false; | ||||
|           $scope.sent = true; | ||||
|         }, function(result) { | ||||
|  | @ -772,7 +848,7 @@ quayApp.directive('signinForm', function () { | |||
|       'signInStarted': '&signInStarted', | ||||
|       'signedIn': '&signedIn' | ||||
|     }, | ||||
|     controller: function($scope, $location, $timeout, Restangular, KeyService, UserService) { | ||||
|     controller: function($scope, $location, $timeout, ApiService, KeyService, UserService) { | ||||
|       $scope.showGithub = function() { | ||||
|         $scope.markStarted(); | ||||
| 
 | ||||
|  | @ -799,8 +875,7 @@ quayApp.directive('signinForm', function () { | |||
|       $scope.signin = function() { | ||||
|         $scope.markStarted(); | ||||
| 
 | ||||
|         var signinPost = Restangular.one('signin'); | ||||
|         signinPost.customPOST($scope.user).then(function() { | ||||
|         ApiService.signinUser($scope.user).then(function() { | ||||
|           $scope.needsEmailVerification = false; | ||||
|           $scope.invalidCredentials = false; | ||||
| 
 | ||||
|  | @ -840,7 +915,7 @@ quayApp.directive('signupForm', function () { | |||
|     scope: { | ||||
| 
 | ||||
|     }, | ||||
|     controller: function($scope, $location, $timeout, Restangular, KeyService, UserService) {       | ||||
|     controller: function($scope, $location, $timeout, ApiService, KeyService, UserService) {       | ||||
|       $('.form-signup').popover(); | ||||
| 
 | ||||
|       angulartics.waitForVendorApi(mixpanel, 500, function(loadedMixpanel) { | ||||
|  | @ -857,8 +932,7 @@ quayApp.directive('signupForm', function () { | |||
|         $('.form-signup').popover('hide'); | ||||
|         $scope.registering = true; | ||||
| 
 | ||||
|         var newUserPost = Restangular.one('user/'); | ||||
|         newUserPost.customPOST($scope.newUser).then(function() { | ||||
|         ApiService.createNewUser($scope.newUser).then(function() { | ||||
|           $scope.awaitingConfirmation = true; | ||||
|           $scope.registering  = false; | ||||
| 
 | ||||
|  | @ -911,7 +985,7 @@ quayApp.directive('dockerAuthDialog', function () { | |||
|       'shown': '=shown', | ||||
|       'counter': '=counter' | ||||
|     }, | ||||
|     controller: function($scope, $element, Restangular) {      | ||||
|     controller: function($scope, $element) {      | ||||
|       $scope.isDownloadSupported = function() { | ||||
|         try { return !!new Blob(); } catch(e){} | ||||
|         return false; | ||||
|  | @ -981,7 +1055,7 @@ quayApp.directive('billingInvoices', function () { | |||
|       'user': '=user', | ||||
|       'visible': '=visible' | ||||
|     }, | ||||
|     controller: function($scope, $element, $sce, Restangular) { | ||||
|     controller: function($scope, $element, $sce, ApiService) { | ||||
|       $scope.loading = false; | ||||
|       $scope.invoiceExpanded = {}; | ||||
| 
 | ||||
|  | @ -1000,13 +1074,7 @@ quayApp.directive('billingInvoices', function () { | |||
|          | ||||
|         $scope.loading = true; | ||||
| 
 | ||||
|         var url = getRestUrl('user/invoices'); | ||||
|         if ($scope.organization) { | ||||
|           url = getRestUrl('organization', $scope.organization.name, 'invoices'); | ||||
|         } | ||||
| 
 | ||||
|         var getInvoices = Restangular.one(url); | ||||
|         getInvoices.get().then(function(resp) { | ||||
|         ApiService.listInvoices($scope.organization).then(function(resp) { | ||||
|           $scope.invoices = resp.invoices; | ||||
|           $scope.loading = false; | ||||
|         }); | ||||
|  | @ -1036,7 +1104,7 @@ quayApp.directive('logsView', function () { | |||
|       'repository': '=repository', | ||||
|       'performer': '=performer' | ||||
|     }, | ||||
|     controller: function($scope, $element, $sce, Restangular) { | ||||
|     controller: function($scope, $element, $sce, Restangular, ApiService) { | ||||
|       $scope.loading = true; | ||||
|       $scope.logs = null; | ||||
|       $scope.kindsAllowed = null; | ||||
|  | @ -1152,6 +1220,8 @@ quayApp.directive('logsView', function () { | |||
| 
 | ||||
|         $scope.loading = true; | ||||
| 
 | ||||
|         // Note: We construct the URLs here manually because we also use it for the download
 | ||||
|         // path.
 | ||||
|         var url = getRestUrl('user/logs'); | ||||
|         if ($scope.organization) { | ||||
|           url = getRestUrl('organization', $scope.organization.name, 'logs'); | ||||
|  | @ -1255,7 +1325,7 @@ quayApp.directive('robotsManager', function () { | |||
|       'organization': '=organization', | ||||
|       'user': '=user' | ||||
|     }, | ||||
|     controller: function($scope, $element, Restangular) { | ||||
|     controller: function($scope, $element, ApiService) { | ||||
|       $scope.ROBOT_PATTERN = ROBOT_PATTERN; | ||||
|       $scope.robots = null; | ||||
|       $scope.loading = false; | ||||
|  | @ -1280,7 +1350,7 @@ quayApp.directive('robotsManager', function () { | |||
|       $scope.createRobot = function(name) { | ||||
|         if (!name) { return; } | ||||
| 
 | ||||
|         createRobotAccount(Restangular, !!$scope.organization, $scope.organization ? $scope.organization.name : '', name, | ||||
|         createRobotAccount(ApiService, !!$scope.organization, $scope.organization ? $scope.organization.name : '', name, | ||||
|           function(created) { | ||||
|             $scope.robots.push(created); | ||||
|           }); | ||||
|  | @ -1288,11 +1358,7 @@ quayApp.directive('robotsManager', function () { | |||
| 
 | ||||
|       $scope.deleteRobot = function(info) { | ||||
|         var shortName = $scope.getShortenedName(info.name); | ||||
|         var url = $scope.organization ? getRestUrl('organization', $scope.organization.name, 'robots', shortName) : | ||||
|               getRestUrl('user/robots', shortName); | ||||
| 
 | ||||
|         var deleteRobot = Restangular.one(url); | ||||
|         deleteRobot.customDELETE().then(function(resp) { | ||||
|         ApiService.deleteRobot($scope.organization, null, {'robot_shortname': shortName}).then(function(resp) { | ||||
|           for (var i = 0; i < $scope.robots.length; ++i) { | ||||
|             if ($scope.robots[i].name == info.name) { | ||||
|               $scope.robots.splice(i, 1); | ||||
|  | @ -1318,9 +1384,7 @@ quayApp.directive('robotsManager', function () { | |||
|         if ($scope.loading) { return; } | ||||
| 
 | ||||
|         $scope.loading = true; | ||||
|         var url = $scope.organization ? getRestUrl('organization', $scope.organization.name, 'robots') : 'user/robots'; | ||||
|         var getRobots = Restangular.one(url); | ||||
|         getRobots.customGET($scope.obj).then(function(resp) { | ||||
|         ApiService.getRobots($scope.organization).then(function(resp) { | ||||
|           $scope.robots = resp.robots; | ||||
|           $scope.loading = false; | ||||
|         }); | ||||
|  | @ -1553,7 +1617,7 @@ quayApp.directive('headerBar', function () { | |||
|     restrict: 'C', | ||||
|     scope: { | ||||
|     }, | ||||
|     controller: function($scope, $element, $location, UserService, PlanService, Restangular) { | ||||
|     controller: function($scope, $element, $location, UserService, PlanService, ApiService) { | ||||
|       $scope.overPlan = false; | ||||
| 
 | ||||
|       var checkOverPlan = function() { | ||||
|  | @ -1562,8 +1626,7 @@ quayApp.directive('headerBar', function () { | |||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         var checkPrivate = Restangular.one('user/private'); | ||||
|         checkPrivate.customGET().then(function(resp) { | ||||
|         ApiService.getUserPrivateCount().then(function(resp) { | ||||
|           $scope.overPlan = resp.privateCount > resp.reposAllowed; | ||||
|         }); | ||||
|       }; | ||||
|  | @ -1575,10 +1638,9 @@ quayApp.directive('headerBar', function () { | |||
|       PlanService.registerListener(this, checkOverPlan); | ||||
|          | ||||
|       $scope.signout = function() { | ||||
|         var signoutPost = Restangular.one('signout'); | ||||
|         signoutPost.customPOST().then(function() { | ||||
|             UserService.load(); | ||||
|             $location.path('/'); | ||||
|         ApiService.logout().then(function() { | ||||
|           UserService.load(); | ||||
|           $location.path('/'); | ||||
|         }); | ||||
|       }; | ||||
|          | ||||
|  | @ -1609,7 +1671,7 @@ quayApp.directive('entitySearch', function () { | |||
|       'includeTeams': '=includeTeams', | ||||
|       'isOrganization': '=isOrganization' | ||||
|     }, | ||||
|     controller: function($scope, $element, Restangular, UserService) { | ||||
|     controller: function($scope, $element, Restangular, UserService, ApiService) { | ||||
|       $scope.lazyLoading = true; | ||||
|       $scope.isAdmin = false; | ||||
| 
 | ||||
|  | @ -1619,16 +1681,12 @@ quayApp.directive('entitySearch', function () { | |||
|         $scope.isAdmin = UserService.isNamespaceAdmin($scope.namespace); | ||||
| 
 | ||||
|         if ($scope.isOrganization && $scope.includeTeams) { | ||||
|           var url = getRestUrl('organization', $scope.namespace); | ||||
|           var getOrganization = Restangular.one(url); | ||||
|           getOrganization.customGET().then(function(resp) { | ||||
|           ApiService.getOrganization(null, {'orgname': $scope.namespace}).then(function(resp) { | ||||
|             $scope.teams = resp.teams; | ||||
|           }); | ||||
|         } | ||||
| 
 | ||||
|         var url = $scope.isOrganization ? getRestUrl('organization', $scope.namespace, 'robots') : 'user/robots'; | ||||
|         var getRobots = Restangular.one(url); | ||||
|         getRobots.customGET().then(function(resp) { | ||||
|         ApiService.getRobots($scope.isOrganization ? $scope.namespace : null).then(function(resp) { | ||||
|           $scope.robots = resp.robots; | ||||
|           $scope.lazyLoading = false; | ||||
|         }, function() { | ||||
|  | @ -1648,7 +1706,7 @@ quayApp.directive('entitySearch', function () { | |||
|             return; | ||||
|           } | ||||
| 
 | ||||
|           createOrganizationTeam(Restangular, $scope.namespace, teamname, function(created) { | ||||
|           createOrganizationTeam(ApiService, $scope.namespace, teamname, function(created) { | ||||
|             $scope.setEntity(created.name, 'team', false); | ||||
|             $scope.teams[teamname] = created; | ||||
|           });           | ||||
|  | @ -1667,7 +1725,7 @@ quayApp.directive('entitySearch', function () { | |||
|             return; | ||||
|           } | ||||
| 
 | ||||
|           createRobotAccount(Restangular, $scope.isOrganization, $scope.namespace, robotname, function(created) { | ||||
|           createRobotAccount(ApiService, $scope.isOrganization, $scope.namespace, robotname, function(created) { | ||||
|             $scope.setEntity(created.name, 'user', true); | ||||
|             $scope.robots.push(created); | ||||
|           });           | ||||
|  | @ -1793,7 +1851,7 @@ quayApp.directive('billingOptions', function () { | |||
|       'user': '=user', | ||||
|       'organization': '=organization' | ||||
|     }, | ||||
|     controller: function($scope, $element, PlanService, Restangular) { | ||||
|     controller: function($scope, $element, PlanService, ApiService) { | ||||
|       $scope.invoice_email = false; | ||||
|       $scope.currentCard = null; | ||||
| 
 | ||||
|  | @ -1863,9 +1921,7 @@ quayApp.directive('billingOptions', function () { | |||
| 
 | ||||
|       var save = function() { | ||||
|         $scope.working = true; | ||||
|         var url = $scope.organization ? getRestUrl('organization', $scope.organization.name) : 'user/'; | ||||
|         var conductSave = Restangular.one(url); | ||||
|         conductSave.customPUT($scope.obj).then(function(resp) { | ||||
|         ApiService.changeDetails($scope.organization, $scope.obj).then(function(resp) { | ||||
|           $scope.working = false; | ||||
|         }); | ||||
|       }; | ||||
|  | @ -1900,7 +1956,7 @@ quayApp.directive('planManager', function () { | |||
|       'readyForPlan': '&readyForPlan', | ||||
|       'planChanged': '&planChanged' | ||||
|     }, | ||||
|     controller: function($scope, $element, PlanService, Restangular) { | ||||
|     controller: function($scope, $element, PlanService, ApiService) { | ||||
|       var hasSubscription = false; | ||||
|          | ||||
|       $scope.isPlanVisible = function(plan, subscribedPlan) { | ||||
|  |  | |||
							
								
								
									
										13
									
								
								static/js/bootstrap.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								static/js/bootstrap.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
|  $.ajax({ | ||||
|     type: 'GET', | ||||
|     async: false, | ||||
|     url:  '/api/discovery', | ||||
|     success: function(data) { | ||||
|       window.__endpoints = data.endpoints; | ||||
|     }, | ||||
|     error: function() { | ||||
|       setTimeout(function() { | ||||
|         $('#couldnotloadModal').modal({}); | ||||
|       }, 250); | ||||
|     } | ||||
|  }); | ||||
|  | @ -67,14 +67,15 @@ function RepoListCtrl($scope, Restangular, UserService, ApiService) { | |||
|     } | ||||
| 
 | ||||
|     var options = {'public': false, 'sort': true, 'namespace': namespace}; | ||||
|     $scope.user_repositories = ApiService.at('repository').withOptions(options).get(function(resp) { | ||||
|      | ||||
|     $scope.user_repositories = ApiService.listReposAsResource().withOptions(options).get(function(resp) { | ||||
|       return resp.repositories; | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   var loadPublicRepos = function() { | ||||
|     var options = {'public': true, 'private': false, 'sort': true, 'limit': 10}; | ||||
|     $scope.public_repositories = ApiService.at('repository').withOptions(options).get(function(resp) { | ||||
|     $scope.public_repositories = ApiService.listReposAsResource().withOptions(options).get(function(resp) { | ||||
|       return resp.repositories; | ||||
|     }); | ||||
|   }; | ||||
|  | @ -118,7 +119,7 @@ function LandingCtrl($scope, UserService, ApiService) { | |||
|     } | ||||
| 
 | ||||
|     var options = {'limit': 4, 'public': false, 'sort': true, 'namespace': namespace }; | ||||
|     $scope.my_repositories = ApiService.at('repository').withOptions(options).get(function(resp) { | ||||
|     $scope.my_repositories = ApiService.listReposAsResource().withOptions(options).get(function(resp) { | ||||
|       return resp.repositories; | ||||
|     }); | ||||
|   }; | ||||
|  | @ -169,7 +170,8 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo | |||
|   }; | ||||
| 
 | ||||
|   $scope.loadImageChanges = function(image) { | ||||
|     $scope.currentImageChangeResource = ApiService.at('repository', namespace, name, 'image', image.id, 'changes').get(function(ci) { | ||||
|     var params = {'repository': namespace + '/' + name, 'image_id': image.id}; | ||||
|     $scope.currentImageChangeResource = ApiService.getImageChangesAsResource(params).get(function(ci) { | ||||
|       $scope.currentImageChanges = ci; | ||||
|     }); | ||||
|   }; | ||||
|  | @ -240,8 +242,9 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo | |||
|   }; | ||||
| 
 | ||||
|   var fetchRepository = function() { | ||||
|     var params = {'repository': namespace + '/' + name}; | ||||
|     $rootScope.title = 'Loading Repository...'; | ||||
|     $scope.repository = ApiService.at('repository', namespace, name).get(function(repo) { | ||||
|     $scope.repository = ApiService.getRepoAsResource(params).get(function(repo) { | ||||
|       // Set the repository object.
 | ||||
|       $scope.repo = repo; | ||||
| 
 | ||||
|  | @ -283,6 +286,7 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo | |||
|   }; | ||||
| 
 | ||||
|   var getBuildInfo = function(repo) { | ||||
|     // Note: We use restangular manually here because we need to turn off the loading bar.
 | ||||
|     var buildInfo = Restangular.one('repository/' + repo.namespace + '/' + repo.name + '/build/'); | ||||
|     buildInfo.withHttpConfig({ | ||||
|       'ignoreLoadingBar': true | ||||
|  | @ -312,7 +316,8 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo | |||
|   }; | ||||
| 
 | ||||
|   var listImages = function() { | ||||
|     $scope.imageHistory = ApiService.at('repository', namespace, name, 'image').get(function(resp) { | ||||
|     var params = {'repository': namespace + '/' + name};     | ||||
|     $scope.imageHistory = ApiService.listRepositoryImagesAsResource(params).get(function(resp) { | ||||
|       // Dispose of any existing tree.
 | ||||
|       if ($scope.tree) { | ||||
|         $scope.tree.dispose(); | ||||
|  | @ -352,11 +357,6 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo | |||
| } | ||||
| 
 | ||||
| function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope) { | ||||
|   $('.info-icon').popover({ | ||||
|     'trigger': 'hover', | ||||
|     'html': true | ||||
|   }); | ||||
| 
 | ||||
|   var namespace = $routeParams.namespace; | ||||
|   var name = $routeParams.name; | ||||
| 
 | ||||
|  | @ -443,8 +443,8 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|       'friendlyName': $scope.newToken.friendlyName | ||||
|     }; | ||||
| 
 | ||||
|     var permissionPost = Restangular.one('repository/' + namespace + '/' + name + '/tokens/'); | ||||
|     permissionPost.customPOST(friendlyName).then(function(newToken) { | ||||
|     var params = {'repository': namespace + '/' + name}; | ||||
|     ApiService.createToken(friendlyName, params).then(function(newToken) { | ||||
|       $scope.newToken.friendlyName = ''; | ||||
|       $scope.createTokenForm.$setPristine(); | ||||
|       $scope.tokens[newToken.code] = newToken; | ||||
|  | @ -452,8 +452,12 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|   }; | ||||
| 
 | ||||
|   $scope.deleteToken = function(tokenCode) { | ||||
|     var deleteAction = Restangular.one('repository/' + namespace + '/' + name + '/tokens/' + tokenCode); | ||||
|     deleteAction.customDELETE().then(function() { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name, | ||||
|       'code': tokenCode | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.deleteToken(null, params).then(function() { | ||||
|       delete $scope.tokens[tokenCode]; | ||||
|     }); | ||||
|   }; | ||||
|  | @ -463,8 +467,12 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|       'role': newAccess | ||||
|     }; | ||||
| 
 | ||||
|     var deleteAction = Restangular.one('repository/' + namespace + '/' + name + '/tokens/' + tokenCode); | ||||
|     deleteAction.customPUT(role).then(function(updated) { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name, | ||||
|       'code': tokenCode | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.changeToken(role, params).then(function(updated) { | ||||
|       $scope.tokens[updated.code] = updated; | ||||
|     }); | ||||
|   }; | ||||
|  | @ -486,8 +494,12 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|     var visibility = { | ||||
|       'visibility': newAccess | ||||
|     }; | ||||
|     var visibilityPost = Restangular.one('repository/' + namespace + '/' + name + '/changevisibility'); | ||||
|     visibilityPost.customPOST(visibility).then(function() { | ||||
| 
 | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.changeRepoVisibility(visibility, params).then(function() { | ||||
|       $scope.repo.is_public = newAccess == 'public'; | ||||
|     }, function() { | ||||
|       $('#cannotchangeModal').modal({}); | ||||
|  | @ -501,8 +513,11 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|   $scope.deleteRepo = function() { | ||||
|     $('#confirmdeleteModal').modal('hide'); | ||||
| 
 | ||||
|     var deleteAction = Restangular.one('repository/' + namespace + '/' + name); | ||||
|     deleteAction.customDELETE().then(function() { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.deleteRepository(null, params).then(function() { | ||||
|       $scope.repo = null; | ||||
|        | ||||
|       setTimeout(function() { | ||||
|  | @ -514,8 +529,12 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|   }; | ||||
| 
 | ||||
|   $scope.loadWebhooks = function() { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name | ||||
|     }; | ||||
| 
 | ||||
|     $scope.newWebhook = {}; | ||||
|     $scope.webhooksResource = ApiService.at('repository', namespace, name, 'webhook').get(function(resp) { | ||||
|     $scope.webhooksResource = ApiService.listWebhooksAsResource(params).get(function(resp) { | ||||
|       $scope.webhooks = resp.webhooks; | ||||
|       return $scope.webhooks; | ||||
|     }); | ||||
|  | @ -526,8 +545,11 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     var newWebhook = Restangular.one('repository/' + namespace + '/' + name + '/webhook/'); | ||||
|     newWebhook.customPOST($scope.newWebhook).then(function(resp) { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.createWebhook($scope.newWebhook, params).then(function(resp) { | ||||
|       $scope.webhooks.push(resp); | ||||
|       $scope.newWebhook.url = ''; | ||||
|       $scope.createWebhookForm.$setPristine(); | ||||
|  | @ -535,15 +557,22 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|   }; | ||||
| 
 | ||||
|   $scope.deleteWebhook = function(webhook) { | ||||
|     var deleteWebhookReq = Restangular.one('repository/' + namespace + '/' + name + '/webhook/' + webhook.public_id); | ||||
|     deleteWebhookReq.customDELETE().then(function(resp) { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name, | ||||
|       'public_id': webhook.public_id | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.deleteWebhook(null, params).then(function(resp) { | ||||
|       $scope.webhooks.splice($scope.webhooks.indexOf(webhook), 1); | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   var fetchTokens = function() { | ||||
|     var tokensFetch = Restangular.one('repository/' + namespace + '/' + name + '/tokens/'); | ||||
|     tokensFetch.get().then(function(resp) { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.listRepoTokens(null, params).then(function(resp) { | ||||
|       $scope.tokens = resp.tokens; | ||||
|     }, function() { | ||||
|       $scope.tokens = null; | ||||
|  | @ -560,7 +589,11 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|   }; | ||||
| 
 | ||||
|   var fetchRepository = function() { | ||||
|     $scope.repository = ApiService.at('repository', namespace, name).get(function(repo) { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name | ||||
|     }; | ||||
| 
 | ||||
|     $scope.repository = ApiService.getRepoAsResource(params).get(function(repo) { | ||||
|       $scope.repo = repo; | ||||
| 
 | ||||
|       $rootScope.title = 'Settings - ' + namespace + '/' + name; | ||||
|  | @ -572,6 +605,11 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|       fetchPermissions('team'); | ||||
|       fetchTokens(); | ||||
| 
 | ||||
|       $('.info-icon').popover({ | ||||
|         'trigger': 'hover', | ||||
|         'html': true | ||||
|       }); | ||||
| 
 | ||||
|       return $scope.repo; | ||||
|     }); | ||||
|   }; | ||||
|  | @ -580,13 +618,14 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope | |||
|   fetchRepository(); | ||||
| } | ||||
| 
 | ||||
| function UserAdminCtrl($scope, $timeout, $location, Restangular, PlanService, UserService, KeyService, $routeParams) { | ||||
| function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, UserService, KeyService, $routeParams) { | ||||
|   if ($routeParams['migrate']) { | ||||
|     $('#migrateTab').tab('show') | ||||
|   } | ||||
| 
 | ||||
|   UserService.updateUserIn($scope, function(user) { | ||||
|     $scope.askForPassword = user.askForPassword; | ||||
|     $scope.cuser = jQuery.extend({}, user); | ||||
|   }); | ||||
| 
 | ||||
|   $scope.readyForPlan = function() { | ||||
|  | @ -645,8 +684,7 @@ function UserAdminCtrl($scope, $timeout, $location, Restangular, PlanService, Us | |||
|       'plan': $scope.org.plan.stripeId | ||||
|     }; | ||||
| 
 | ||||
|     var convertAccount = Restangular.one('user/convert'); | ||||
|     convertAccount.customPOST(data).then(function(resp) { | ||||
|     ApiService.convertUserToOrganization(data).then(function(resp) { | ||||
|       UserService.load(); | ||||
|       $location.path('/'); | ||||
|     }, function(resp) { | ||||
|  | @ -663,14 +701,14 @@ function UserAdminCtrl($scope, $timeout, $location, Restangular, PlanService, Us | |||
|     $('.form-change-pw').popover('hide'); | ||||
|     $scope.updatingUser = true; | ||||
|     $scope.changePasswordSuccess = false; | ||||
|     var changePasswordPost = Restangular.one('user/'); | ||||
|     changePasswordPost.customPUT($scope.user).then(function() { | ||||
| 
 | ||||
|     ApiService.changeUserDetails($scope.cuser).then(function() { | ||||
|       $scope.updatingUser = false; | ||||
|       $scope.changePasswordSuccess = true; | ||||
| 
 | ||||
|       // Reset the form
 | ||||
|       $scope.user.password = ''; | ||||
|       $scope.user.repeatPassword = ''; | ||||
|       $scope.cuser.password = ''; | ||||
|       $scope.cuser.repeatPassword = ''; | ||||
|       $scope.changePasswordForm.$setPristine(); | ||||
| 
 | ||||
|       // Reload the user.
 | ||||
|  | @ -686,7 +724,7 @@ function UserAdminCtrl($scope, $timeout, $location, Restangular, PlanService, Us | |||
|   }; | ||||
| } | ||||
| 
 | ||||
| function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, Restangular) {   | ||||
| function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService) {   | ||||
|   var namespace = $routeParams.namespace; | ||||
|   var name = $routeParams.name; | ||||
|   var imageid = $routeParams.image; | ||||
|  | @ -742,7 +780,12 @@ function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, R | |||
|   }; | ||||
| 
 | ||||
|   var fetchImage = function() { | ||||
|     $scope.image = ApiService.at('repository', namespace, name, 'image', imageid).get(function(image) { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name, | ||||
|       'image_id': imageid   | ||||
|     }; | ||||
| 
 | ||||
|     $scope.image = ApiService.getImageAsResource(params).get(function(image) { | ||||
|       $scope.repo = { | ||||
|         'name': name, | ||||
|         'namespace': namespace | ||||
|  | @ -762,8 +805,12 @@ function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, R | |||
|   }; | ||||
| 
 | ||||
|   var fetchChanges = function() { | ||||
|     var changesFetch = Restangular.one('repository/' + namespace + '/' + name + '/image/' + imageid + '/changes'); | ||||
|     changesFetch.get().then(function(changes) { | ||||
|     var params = { | ||||
|       'repository': namespace + '/' + name, | ||||
|       'image_id': imageid   | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.getImageChanges(null, params).then(function(changes) { | ||||
|       var combinedChanges = []; | ||||
|       var addCombinedChanges = function(c, kind) { | ||||
|         for (var i = 0;  i < c.length; ++i) { | ||||
|  | @ -791,7 +838,7 @@ function V1Ctrl($scope, $location, UserService) { | |||
|   UserService.updateUserIn($scope); | ||||
| } | ||||
| 
 | ||||
| function NewRepoCtrl($scope, $location, $http, $timeout, UserService, Restangular, PlanService) { | ||||
| function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService, PlanService) { | ||||
|   UserService.updateUserIn($scope); | ||||
| 
 | ||||
|   $scope.repo = { | ||||
|  | @ -822,8 +869,7 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, Restangula | |||
|     if (isUserNamespace) { | ||||
|       // Load the user's subscription information in case they want to create a private
 | ||||
|       // repository.
 | ||||
|       var checkPrivateAllowed = Restangular.one('user/private'); | ||||
|       checkPrivateAllowed.get().then(function(resp) { | ||||
|       ApiService.getUserPrivateCount().then(function(resp) { | ||||
|         if (resp.privateCount + 1 > resp.reposAllowed) { | ||||
|           PlanService.getMinimumPlan(resp.privateCount + 1, false, function(minimum) { | ||||
|             $scope.planRequired = minimum; | ||||
|  | @ -836,8 +882,7 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, Restangula | |||
|         $scope.checkingPlan = false; | ||||
|       }); | ||||
|     } else { | ||||
|       var checkPrivateAllowed = Restangular.one('organization/' + namespace  + '/private'); | ||||
|       checkPrivateAllowed.get().then(function(resp) { | ||||
|       ApiService.getOrganizationPrivateAllowed(null, {'orgname': namespace}).then(function(resp) { | ||||
|         $scope.planRequired = resp.privateAllowed ? null : {}; | ||||
|         $scope.checkingPlan = false; | ||||
|       }, function() { | ||||
|  | @ -868,8 +913,7 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, Restangula | |||
|       'description': repo.description | ||||
|     }; | ||||
| 
 | ||||
|     var createPost = Restangular.one('repository'); | ||||
|     createPost.customPOST(data).then(function(created) { | ||||
|     ApiService.createRepo(data).then(function(created) { | ||||
|       $scope.creating = false; | ||||
|       $scope.created = created; | ||||
| 
 | ||||
|  | @ -912,9 +956,12 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, Restangula | |||
|       'file_id': fileId | ||||
|     }; | ||||
| 
 | ||||
|     var startBuildCall = Restangular.one('repository/' + repo.namespace + '/' + repo.name + '/build/'); | ||||
|     startBuildCall.customPOST(data).then(function(resp) { | ||||
|       $location.path('/repository/' + repo.namespace + '/' + repo.name); | ||||
|     var params = { | ||||
|       'repository': repo.namespace + '/' + repo.name | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.requestRepoBuild(data, params).then(function(resp) { | ||||
|       $location.path('/repository/' + params.repository); | ||||
|     }, function() { | ||||
|       $('#couldnotbuildModal').modal(); | ||||
|     }); | ||||
|  | @ -963,8 +1010,7 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, Restangula | |||
|       'mimeType': mimeType | ||||
|     }; | ||||
| 
 | ||||
|     var getUploadUrl = Restangular.one('filedrop/'); | ||||
|     getUploadUrl.customPOST(data).then(function(resp) { | ||||
|     var getUploadUrl = ApiService.getFiledropUrl(data).then(function(resp) { | ||||
|       conductUpload(repo, file, resp.url, resp.file_id, mimeType); | ||||
|     }, function() {         | ||||
|       $('#couldnotbuildModal').modal(); | ||||
|  | @ -992,7 +1038,7 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, Restangula | |||
|   }; | ||||
| } | ||||
| 
 | ||||
| function OrgViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) { | ||||
| function OrgViewCtrl($rootScope, $scope, ApiService, $routeParams) { | ||||
|   var orgname = $routeParams.orgname; | ||||
| 
 | ||||
|   $scope.TEAM_PATTERN = TEAM_PATTERN; | ||||
|  | @ -1008,10 +1054,14 @@ function OrgViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
|     var previousRole = $scope.organization.teams[teamname].role; | ||||
|     $scope.organization.teams[teamname].role = role; | ||||
| 
 | ||||
|     var updateTeam = Restangular.one(getRestUrl('organization', orgname, 'team', teamname)); | ||||
|     var params = { | ||||
|       'orgname': orgname, | ||||
|       'teamname': teamname | ||||
|     }; | ||||
| 
 | ||||
|     var data = $scope.organization.teams[teamname]; | ||||
| 
 | ||||
|     updateTeam.customPUT(data).then(function(resp) { | ||||
|     ApiService.updateOrganizationTeam(data, params).then(function(resp) { | ||||
|     }, function(resp) {      | ||||
|       $scope.organization.teams[teamname].role = previousRole; | ||||
|       $scope.roleError = resp.data || ''; | ||||
|  | @ -1032,7 +1082,7 @@ function OrgViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     createOrganizationTeam(Restangular, orgname, teamname, function(created) { | ||||
|     createOrganizationTeam(ApiService, orgname, teamname, function(created) { | ||||
|       $scope.organization.teams[teamname] = created; | ||||
|     }); | ||||
|   }; | ||||
|  | @ -1047,8 +1097,12 @@ function OrgViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
|     if (!$scope.currentDeleteTeam) { return; } | ||||
| 
 | ||||
|     var teamname = $scope.currentDeleteTeam; | ||||
|     var deleteAction = Restangular.one(getRestUrl('organization', orgname, 'team', teamname)); | ||||
|     deleteAction.customDELETE().then(function() { | ||||
|     var params = { | ||||
|       'orgname': orgname, | ||||
|       'teamname': teamname | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.deleteOrganizationTeam(null, params).then(function() { | ||||
|       delete $scope.organization.teams[teamname]; | ||||
|       $scope.currentDeleteTeam = null; | ||||
|     }, function() { | ||||
|  | @ -1058,7 +1112,7 @@ function OrgViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
|   }; | ||||
| 
 | ||||
|   var loadOrganization = function() { | ||||
|     $scope.orgResource = ApiService.at('organization', orgname).get(function(org) { | ||||
|     $scope.orgResource = ApiService.getOrganizationAsResource({'orgname': orgname}).get(function(org) { | ||||
|       $scope.organization = org; | ||||
|       $rootScope.title = orgname; | ||||
|       $rootScope.description = 'Viewing organization ' + orgname; | ||||
|  | @ -1109,9 +1163,12 @@ function OrgAdminCtrl($rootScope, $scope, Restangular, $routeParams, UserService | |||
|   $scope.loadMembers = function() { | ||||
|     if ($scope.membersFound) { return; } | ||||
|     $scope.membersLoading = true; | ||||
|      | ||||
|     var getMembers = Restangular.one(getRestUrl('organization', orgname, 'members')); | ||||
|     getMembers.get().then(function(resp) { | ||||
| 
 | ||||
|     var params = { | ||||
|       'orgname': orgname | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.getOrganizationMembers(null, params).then(function(resp) { | ||||
|       var membersArray = []; | ||||
|       for (var key in resp.members) { | ||||
|         if (resp.members.hasOwnProperty(key)) { | ||||
|  | @ -1125,7 +1182,7 @@ function OrgAdminCtrl($rootScope, $scope, Restangular, $routeParams, UserService | |||
|   }; | ||||
| 
 | ||||
|   var loadOrganization = function() { | ||||
|     $scope.orgResource = ApiService.at('organization', orgname).get(function(org) { | ||||
|     $scope.orgResource = ApiService.getOrganizationAsResource({'orgname': orgname}).get(function(org) { | ||||
|       if (org && org.is_admin) { | ||||
|         $scope.organization = org; | ||||
|         $rootScope.title = orgname + ' (Admin)'; | ||||
|  | @ -1139,11 +1196,6 @@ function OrgAdminCtrl($rootScope, $scope, Restangular, $routeParams, UserService | |||
| } | ||||
| 
 | ||||
| function TeamViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) { | ||||
|   $('.info-icon').popover({ | ||||
|     'trigger': 'hover', | ||||
|     'html': true | ||||
|   }); | ||||
| 
 | ||||
|   var teamname = $routeParams.teamname; | ||||
|   var orgname = $routeParams.orgname; | ||||
| 
 | ||||
|  | @ -1155,8 +1207,13 @@ function TeamViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
|   $scope.addNewMember = function(member) { | ||||
|     if ($scope.members[member.name]) { return; } | ||||
| 
 | ||||
|     var addMember = Restangular.one(getRestUrl('organization', $scope.orgname, 'team', teamname, 'members', member.name)); | ||||
|     addMember.customPOST().then(function(resp) { | ||||
|     var params = { | ||||
|       'orgname': orgname, | ||||
|       'teamname': teamname, | ||||
|       'membername': member.name | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.updateOrganizationTeamMember(null, params).then(function(resp) { | ||||
|       $scope.members[member.name] = resp; | ||||
|     }, function() { | ||||
|       $('#cannotChangeMembersModal').modal({}); | ||||
|  | @ -1164,8 +1221,13 @@ function TeamViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
|   }; | ||||
| 
 | ||||
|   $scope.removeMember = function(username) { | ||||
|     var removeMember = Restangular.one(getRestUrl('organization', $scope.orgname, 'team', teamname, 'members', username)); | ||||
|     removeMember.customDELETE().then(function(resp) { | ||||
|     var params = { | ||||
|       'orgname': orgname, | ||||
|       'teamname': teamname, | ||||
|       'membername': username | ||||
|     }; | ||||
| 
 | ||||
|     ApiService.deleteOrganizationTeamMember(null, params).then(function(resp) { | ||||
|       delete $scope.members[username]; | ||||
|     }, function() { | ||||
|       $('#cannotChangeMembersModal').modal({}); | ||||
|  | @ -1175,16 +1237,20 @@ function TeamViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
|   $scope.updateForDescription = function(content) { | ||||
|     $scope.organization.teams[teamname].description = content; | ||||
| 
 | ||||
|     var updateTeam = Restangular.one(getRestUrl('organization', $scope.orgname, 'team', teamname)); | ||||
|     var data = $scope.organization.teams[teamname]; | ||||
|     updateTeam.customPUT(data).then(function(resp) { | ||||
|     var params = { | ||||
|       'orgname': orgname, | ||||
|       'teamname': teamname | ||||
|     }; | ||||
| 
 | ||||
|     var teaminfo = $scope.organization.teams[teamname]; | ||||
|     ApiService.updateOrganizationTeam(teaminfo, params).then(function(resp) { | ||||
|     }, function() { | ||||
|       $('#cannotChangeTeamModal').modal({}); | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   var loadOrganization = function() { | ||||
|     $scope.orgResource = ApiService.at('organization', orgname).get(function(org) { | ||||
|     $scope.orgResource = ApiService.getOrganizationAsResource({'orgname': orgname}).get(function(org) { | ||||
|       $scope.organization = org; | ||||
|       $scope.team = $scope.organization.teams[teamname]; | ||||
|       $rootScope.title = teamname + ' (' + $scope.orgname + ')'; | ||||
|  | @ -1195,11 +1261,22 @@ function TeamViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
|   }; | ||||
| 
 | ||||
|   var loadMembers = function() { | ||||
|     $scope.membersResource = ApiService.at('organization', $scope.orgname, 'team', teamname, 'members').get(function(resp) { | ||||
|     var params = { | ||||
|       'orgname': orgname, | ||||
|       'teamname': teamname | ||||
|     }; | ||||
| 
 | ||||
|     $scope.membersResource = ApiService.getOrganizationTeamMembersAsResource(params).get(function(resp) { | ||||
|       $scope.members = resp.members; | ||||
|       $scope.canEditMembers = resp.can_edit; | ||||
|          | ||||
|       $('.info-icon').popover({ | ||||
|         'trigger': 'hover', | ||||
|         'html': true | ||||
|       }); | ||||
| 
 | ||||
|       return resp.members; | ||||
|     });    | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   // Load the organization.
 | ||||
|  | @ -1208,11 +1285,10 @@ function TeamViewCtrl($rootScope, $scope, Restangular, ApiService, $routeParams) | |||
| 
 | ||||
| function OrgsCtrl($scope, UserService) { | ||||
|   UserService.updateUserIn($scope); | ||||
| 
 | ||||
|   browserchrome.update(); | ||||
| } | ||||
| 
 | ||||
| function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, PlanService, Restangular) { | ||||
| function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, PlanService, ApiService) { | ||||
|   UserService.updateUserIn($scope); | ||||
| 
 | ||||
|   var requested = $routeParams['plan']; | ||||
|  | @ -1252,8 +1328,7 @@ function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, Plan | |||
|       'email': org.email | ||||
|     }; | ||||
| 
 | ||||
|     var createPost = Restangular.one('organization/'); | ||||
|     createPost.customPOST(data).then(function(created) { | ||||
|     ApiService.createOrganization(data).then(function(created) { | ||||
|       $scope.created = created; | ||||
| 
 | ||||
|       // Reset the organizations list.
 | ||||
|  | @ -1300,14 +1375,19 @@ function OrgMemberLogsCtrl($scope, $routeParams, $rootScope, $timeout, Restangul | |||
|   $scope.ready = false; | ||||
| 
 | ||||
|   var loadOrganization = function() { | ||||
|     $scope.orgResource = ApiService.at('organization', orgname).get(function(org) { | ||||
|     $scope.orgResource = ApiService.getOrganizationAsResource({'orgname': orgname}).get(function(org) { | ||||
|       $scope.organization = org; | ||||
|       return org; | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   var loadMemberInfo = function() { | ||||
|     $scope.memberResource = ApiService.at('organization', $scope.orgname, 'members', membername).get(function(resp) { | ||||
|     var params = { | ||||
|       'orgname': orgname, | ||||
|       'membername': membername | ||||
|     }; | ||||
| 
 | ||||
|     $scope.memberResource = ApiService.getOrganizationMemberAsResource(params).get(function(resp) { | ||||
|       $scope.memberInfo = resp.member; | ||||
| 
 | ||||
|       $rootScope.title = 'Logs for ' + $scope.memberInfo.username + ' (' + $scope.orgname + ')'; | ||||
|  |  | |||
|  | @ -60,9 +60,9 @@ | |||
|             <div ng-show="!updatingUser"> | ||||
|               <form class="form-change-pw col-md-6" name="changePasswordForm" ng-submit="changePassword()" data-trigger="manual" | ||||
|                     data-content="{{ changePasswordError }}" data-placement="right" ng-show="!awaitingConfirmation && !registering"> | ||||
|                 <input type="password" class="form-control" placeholder="Your new password" ng-model="user.password" required> | ||||
|                 <input type="password" class="form-control" placeholder="Verify your new password" ng-model="user.repeatPassword" | ||||
|                        match="user.password" required> | ||||
|                 <input type="password" class="form-control" placeholder="Your new password" ng-model="cuser.password" required> | ||||
|                 <input type="password" class="form-control" placeholder="Verify your new password" ng-model="cuser.repeatPassword" | ||||
|                        match="cuser.password" required> | ||||
|                 <button class="btn btn-danger" ng-disabled="changePasswordForm.$invalid" type="submit" | ||||
|                         analytics-on analytics-event="change_pass">Change Password</button> | ||||
|               </form> | ||||
|  |  | |||
|  | @ -65,6 +65,10 @@ | |||
| 
 | ||||
|     {% endblock %} | ||||
| 
 | ||||
|     <script type="text/javascript"> | ||||
|       window.__endpoints = {{ route_data|safe }}.endpoints; | ||||
|     </script> | ||||
| 
 | ||||
|     <script src="static/js/app.js"></script> | ||||
|     <script src="static/js/controllers.js"></script> | ||||
|     <script src="static/js/graphing.js"></script> | ||||
|  | @ -122,6 +126,22 @@ var isProd = document.location.hostname === 'quay.io'; | |||
|       </nav> | ||||
|     </div> | ||||
| 
 | ||||
|     <!-- Modal message dialog --> | ||||
|     <div class="modal fade" id="couldnotloadModal" data-backdrop="static"> | ||||
|       <div class="modal-dialog"> | ||||
|         <div class="modal-content"> | ||||
|           <div class="modal-header"> | ||||
|             <h4 class="modal-title">Uh Oh...</h4> | ||||
|           </div> | ||||
|           <div class="modal-body"> | ||||
|             Something went wrong when trying to load Quay.io! Please report this to <a href="mailto:support@quay.io">support@quay.io</a>. | ||||
|           </div> | ||||
|           <div class="modal-footer"> | ||||
|           </div> | ||||
|         </div><!-- /.modal-content --> | ||||
|       </div><!-- /.modal-dialog --> | ||||
|     </div><!-- /.modal --> | ||||
| 
 | ||||
|     <!-- begin olark code --> | ||||
|     {% if request.host == 'quay.io' %} | ||||
|     <script data-cfasync="false" type='text/javascript'>/*<![CDATA[*/window.olark||(function(c){var f=window,d=document,l=f.location.protocol=="https:"?"https:":"http:",z=c.name,r="load";var nt=function(){ | ||||
|  |  | |||
|  | @ -105,20 +105,20 @@ def build_specs(): | |||
|   return [ | ||||
|     TestSpec(url_for('welcome'), 200, 200, 200, 200), | ||||
| 
 | ||||
|     TestSpec(url_for('plans_list'), 200, 200, 200, 200), | ||||
|     TestSpec(url_for('list_plans'), 200, 200, 200, 200), | ||||
| 
 | ||||
|     TestSpec(url_for('get_logged_in_user'), 200, 200, 200, 200), | ||||
| 
 | ||||
|     TestSpec(url_for('change_user_details'), | ||||
|              401, 200, 200, 200).set_method('PUT'), | ||||
| 
 | ||||
|     TestSpec(url_for('create_user_api'), 201, 201, 201, | ||||
|     TestSpec(url_for('create_new_user'), 201, 201, 201, | ||||
|              201).set_method('POST').set_data_from_obj(NEW_USER_DETAILS), | ||||
| 
 | ||||
|     TestSpec(url_for('signin_api'), 200, 200, 200, | ||||
|     TestSpec(url_for('signin_user'), 200, 200, 200, | ||||
|              200).set_method('POST').set_data_from_obj(SIGNIN_DETAILS), | ||||
| 
 | ||||
|     TestSpec(url_for('send_recovery'), 201, 201, 201, | ||||
|     TestSpec(url_for('request_recovery_email'), 201, 201, 201, | ||||
|              201).set_method('POST').set_data_from_obj(SEND_RECOVERY_DETAILS), | ||||
| 
 | ||||
|     TestSpec(url_for('get_matching_users', prefix='dev'), 401, 200, 200, 200), | ||||
|  | @ -161,29 +161,29 @@ def build_specs(): | |||
|                      teamname=ORG_READERS, membername=ORG_OWNER), | ||||
|              admin_code=400).set_method('DELETE'), | ||||
| 
 | ||||
|     (TestSpec(url_for('create_repo_api')) | ||||
|     (TestSpec(url_for('create_repo')) | ||||
|       .set_method('POST') | ||||
|       .set_data_from_obj(NEW_ORG_REPO_DETAILS)), | ||||
| 
 | ||||
|     TestSpec(url_for('match_repos_api'), 200, 200, 200, 200), | ||||
|     TestSpec(url_for('find_repos'), 200, 200, 200, 200), | ||||
| 
 | ||||
|     TestSpec(url_for('list_repos_api'), 200, 200, 200, 200), | ||||
|     TestSpec(url_for('list_repos'), 200, 200, 200, 200), | ||||
| 
 | ||||
|     TestSpec(url_for('update_repo_api', repository=PUBLIC_REPO), | ||||
|     TestSpec(url_for('update_repo', repository=PUBLIC_REPO), | ||||
|              admin_code=403).set_method('PUT'), | ||||
|     (TestSpec(url_for('update_repo_api', repository=ORG_REPO)) | ||||
|     (TestSpec(url_for('update_repo', repository=ORG_REPO)) | ||||
|       .set_method('PUT') | ||||
|       .set_data_from_obj(UPDATE_REPO_DETAILS)), | ||||
|     (TestSpec(url_for('update_repo_api', repository=PRIVATE_REPO)) | ||||
|     (TestSpec(url_for('update_repo', repository=PRIVATE_REPO)) | ||||
|       .set_method('PUT') | ||||
|       .set_data_from_obj(UPDATE_REPO_DETAILS)), | ||||
| 
 | ||||
|     (TestSpec(url_for('change_repo_visibility_api', repository=PUBLIC_REPO), | ||||
|     (TestSpec(url_for('change_repo_visibility', repository=PUBLIC_REPO), | ||||
|               admin_code=403).set_method('POST') | ||||
|       .set_data_from_obj(CHANGE_VISIBILITY_DETAILS)), | ||||
|     (TestSpec(url_for('change_repo_visibility_api', repository=ORG_REPO)) | ||||
|     (TestSpec(url_for('change_repo_visibility', repository=ORG_REPO)) | ||||
|       .set_method('POST').set_data_from_obj(CHANGE_VISIBILITY_DETAILS)), | ||||
|     (TestSpec(url_for('change_repo_visibility_api', repository=PRIVATE_REPO)) | ||||
|     (TestSpec(url_for('change_repo_visibility', repository=PRIVATE_REPO)) | ||||
|       .set_method('POST').set_data_from_obj(CHANGE_VISIBILITY_DETAILS)), | ||||
| 
 | ||||
|     TestSpec(url_for('delete_repository', repository=PUBLIC_REPO), | ||||
|  | @ -193,11 +193,11 @@ def build_specs(): | |||
|     TestSpec(url_for('delete_repository', repository=PRIVATE_REPO), | ||||
|              admin_code=204).set_method('DELETE'), | ||||
| 
 | ||||
|     TestSpec(url_for('get_repo_api', repository=PUBLIC_REPO), | ||||
|     TestSpec(url_for('get_repo', repository=PUBLIC_REPO), | ||||
|              200, 200, 200,200), | ||||
|     TestSpec(url_for('get_repo_api', repository=ORG_REPO), | ||||
|     TestSpec(url_for('get_repo', repository=ORG_REPO), | ||||
|              403, 403, 200, 200), | ||||
|     TestSpec(url_for('get_repo_api', repository=PRIVATE_REPO), | ||||
|     TestSpec(url_for('get_repo', repository=PRIVATE_REPO), | ||||
|              403, 403, 200, 200), | ||||
| 
 | ||||
|     TestSpec(url_for('get_repo_builds', repository=PUBLIC_REPO), | ||||
|  | @ -403,20 +403,20 @@ def build_specs(): | |||
|     TestSpec(url_for('delete_token', repository=PRIVATE_REPO, | ||||
|                      code=FAKE_TOKEN), admin_code=400).set_method('DELETE'), | ||||
| 
 | ||||
|     TestSpec(url_for('subscribe_api'), 401, 400, 400, 400).set_method('PUT'), | ||||
|     TestSpec(url_for('update_user_subscription'), 401, 400, 400, 400).set_method('PUT'), | ||||
| 
 | ||||
|     TestSpec(url_for('subscribe_org_api', orgname=ORG), | ||||
|     TestSpec(url_for('update_org_subscription', orgname=ORG), | ||||
|              401, 403, 403, 400).set_method('PUT'), | ||||
| 
 | ||||
|     TestSpec(url_for('get_subscription'), 401, 200, 200, 200), | ||||
|     TestSpec(url_for('get_user_subscription'), 401, 200, 200, 200), | ||||
| 
 | ||||
|     TestSpec(url_for('get_org_subscription', orgname=ORG)), | ||||
| 
 | ||||
|     TestSpec(url_for('repo_logs_api', repository=PUBLIC_REPO), admin_code=403), | ||||
|     TestSpec(url_for('repo_logs_api', repository=ORG_REPO)), | ||||
|     TestSpec(url_for('repo_logs_api', repository=PRIVATE_REPO)), | ||||
|     TestSpec(url_for('list_repo_logs', repository=PUBLIC_REPO), admin_code=403), | ||||
|     TestSpec(url_for('list_repo_logs', repository=ORG_REPO)), | ||||
|     TestSpec(url_for('list_repo_logs', repository=PRIVATE_REPO)), | ||||
|      | ||||
|     TestSpec(url_for('org_logs_api', orgname=ORG)), | ||||
|     TestSpec(url_for('list_org_logs', orgname=ORG)), | ||||
|   ] | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Reference in a new issue