def post(self, namespace_name, repo_name, trigger_uuid): """ List the subdirectories available for the specified build trigger and source. """ trigger = get_trigger(trigger_uuid) user_permission = UserAdminPermission(trigger.connected_user.username) if user_permission.can(): new_config_dict = request.get_json() handler = BuildTriggerHandler.get_handler(trigger, new_config_dict) try: subdirs = handler.list_build_subdirs() context_map = {} for file in subdirs: context_map = handler.get_parent_directory_mappings(file, context_map) return { "dockerfile_paths": ["/" + subdir for subdir in subdirs], "contextMap": context_map, "status": "success", } except EmptyRepositoryException as exc: return { "status": "success", "contextMap": {}, "dockerfile_paths": [], } except TriggerException as exc: return { "status": "error", "message": exc.message, } else: raise Unauthorized()
def get(self, namespace_name, repo_name, trigger_uuid): """ List the build sources for the trigger configuration thus far. """ trigger = get_trigger(trigger_uuid) user_permission = UserAdminPermission(trigger.connected_user.username) if user_permission.can(): handler = BuildTriggerHandler.get_handler(trigger) try: return {"namespaces": handler.list_build_source_namespaces()} except TriggerException as rre: raise InvalidRequest(rre.message) else: raise Unauthorized()
def update_user(username): permission = UserAdminPermission(username) if permission.can(): update_request = request.get_json() if "password" in update_request: logger.debug("Updating user password") model.user.change_password(get_authenticated_user(), update_request["password"]) return jsonify({ "username": get_authenticated_user().username, "email": get_authenticated_user().email, }) abort(403)
def update_user(username): permission = UserAdminPermission(username) if permission.can(): update_request = request.get_json() if 'password' in update_request: logger.debug('Updating user password') model.user.change_password(get_authenticated_user(), update_request['password']) return jsonify({ 'username': get_authenticated_user().username, 'email': get_authenticated_user().email, }) abort(403)
def post(self, namespace_name, repo_name, trigger_uuid): """ List the build sources for the trigger configuration thus far. """ namespace = request.get_json().get("namespace") if namespace is None: raise InvalidRequest() trigger = get_trigger(trigger_uuid) user_permission = UserAdminPermission(trigger.connected_user.username) if user_permission.can(): handler = BuildTriggerHandler.get_handler(trigger) try: return {"sources": handler.list_build_sources_for_namespace(namespace)} except TriggerException as rre: raise InvalidRequest(str(rre)) from rre else: raise Unauthorized()
def get(self, prefix, parsed_args): """ Get a list of entities that match the specified prefix. """ # Ensure we don't have any unicode characters in the search, as it breaks the search. Nothing # being searched can have unicode in it anyway, so this is a safe operation. prefix = prefix.encode("unidecode", "ignore").replace(" ", "").lower() teams = [] org_data = [] namespace_name = parsed_args["namespace"] robot_namespace = None organization = None try: organization = model.organization.get_organization(namespace_name) # namespace name was an org permission = OrganizationMemberPermission(namespace_name) if permission.can(): robot_namespace = namespace_name if parsed_args["includeTeams"]: teams = model.team.get_matching_teams(prefix, organization) if (parsed_args["includeOrgs"] and AdministerOrganizationPermission(namespace_name) and namespace_name.startswith(prefix)): org_data = [{ "name": namespace_name, "kind": "org", "is_org_member": True, "avatar": avatar.get_data_for_org(organization), }] except model.organization.InvalidOrganizationException: # namespace name was a user user = get_authenticated_user() if user and user.username == namespace_name: # Check if there is admin user permissions (login only) admin_permission = UserAdminPermission(user.username) if admin_permission.can(): robot_namespace = namespace_name # Lookup users in the database for the prefix query. users = model.user.get_matching_users( prefix, robot_namespace, organization, limit=10, exact_matches_only=not features.PARTIAL_USER_AUTOCOMPLETE, ) # Lookup users via the user system for the prefix query. We'll filter out any users that # already exist in the database. external_users, federated_id, _ = authentication.query_users(prefix, limit=10) filtered_external_users = [] if external_users and federated_id is not None: users = list(users) user_ids = [user.id for user in users] # Filter the users if any are already found via the database. We do so by looking up all # the found users in the federated user system. federated_query = model.user.get_federated_logins( user_ids, federated_id) found = {result.service_ident for result in federated_query} filtered_external_users = [ user for user in external_users if not user.username in found ] def entity_team_view(team): result = { "name": team.name, "kind": "team", "is_org_member": True, "avatar": avatar.get_data_for_team(team), } return result def user_view(user): user_json = { "name": user.username, "kind": "user", "is_robot": user.robot, "avatar": avatar.get_data_for_user(user), } if organization is not None: user_json["is_org_member"] = user.robot or user.is_org_member return user_json def external_view(user): result = { "name": user.username, "kind": "external", "title": user.email or "", "avatar": avatar.get_data_for_external_user(user), } return result team_data = [entity_team_view(team) for team in teams] user_data = [user_view(user) for user in users] external_data = [ external_view(user) for user in filtered_external_users ] return {"results": team_data + user_data + org_data + external_data}
def post(self, namespace_name, repo_name, trigger_uuid): """ Activate the specified build trigger. """ trigger = get_trigger(trigger_uuid) handler = BuildTriggerHandler.get_handler(trigger) if handler.is_active(): raise InvalidRequest("Trigger config is not sufficient for activation.") user_permission = UserAdminPermission(trigger.connected_user.username) if user_permission.can(): # Update the pull robot (if any). pull_robot_name = request.get_json().get("pull_robot", None) if pull_robot_name: try: pull_robot = model.user.lookup_robot(pull_robot_name) except model.InvalidRobotException: raise NotFound() # Make sure the user has administer permissions for the robot's namespace. (robot_namespace, _) = parse_robot_username(pull_robot_name) if not AdministerOrganizationPermission(robot_namespace).can(): raise Unauthorized() # Make sure the namespace matches that of the trigger. if robot_namespace != namespace_name: raise Unauthorized() # Set the pull robot. trigger.pull_robot = pull_robot # Update the config. new_config_dict = request.get_json()["config"] write_token_name = "Build Trigger: %s" % trigger.service.name write_token = model.token.create_delegate_token( namespace_name, repo_name, write_token_name, "write" ) try: path = url_for("webhooks.build_trigger_webhook", trigger_uuid=trigger.uuid) authed_url = _prepare_webhook_url( app.config["PREFERRED_URL_SCHEME"], "$token", write_token.get_code(), app.config["SERVER_HOSTNAME"], path, ) handler = BuildTriggerHandler.get_handler(trigger, new_config_dict) final_config, private_config = handler.activate(authed_url) if "private_key" in private_config: trigger.secure_private_key = DecryptedValue(private_config["private_key"]) except TriggerException as exc: write_token.delete_instance() raise request_error(message=exc.message) # Save the updated config. update_build_trigger(trigger, final_config, write_token=write_token) # Log the trigger setup. repo = model.repository.get_repository(namespace_name, repo_name) log_action( "setup_repo_trigger", namespace_name, { "repo": repo_name, "namespace": namespace_name, "trigger_id": trigger.uuid, "service": trigger.service.name, "pull_robot": trigger.pull_robot.username if trigger.pull_robot else None, "config": final_config, }, repo=repo, ) return trigger_view(trigger, can_admin=True) else: raise Unauthorized()
def user_view(user, previous_username=None): def org_view(o, user_admin=True): admin_org = AdministerOrganizationPermission(o.username) org_response = { "name": o.username, "avatar": avatar.get_data_for_org(o), "can_create_repo": CreateRepositoryPermission(o.username).can(), "public": o.username in app.config.get("PUBLIC_NAMESPACES", []), } if user_admin: org_response.update( { "is_org_admin": admin_org.can(), "preferred_namespace": not (o.stripe_id is None), } ) return org_response # Retrieve the organizations for the user. organizations = { o.username: o for o in model.organization.get_user_organizations(user.username) } # Add any public namespaces. public_namespaces = app.config.get("PUBLIC_NAMESPACES", []) if public_namespaces: organizations.update({ns: model.user.get_namespace_user(ns) for ns in public_namespaces}) def login_view(login): try: metadata = json.loads(login.metadata_json) except: metadata = {} return { "service": login.service.name, "service_identifier": login.service_ident, "metadata": metadata, } logins = model.user.list_federated_logins(user) user_response = { "anonymous": False, "username": user.username, "avatar": avatar.get_data_for_user(user), } user_admin = UserAdminPermission(previous_username if previous_username else user.username) if user_admin.can(): user_response.update( { "can_create_repo": True, "is_me": True, "verified": user.verified, "email": user.email, "logins": [login_view(login) for login in logins], "invoice_email": user.invoice_email, "invoice_email_address": user.invoice_email_address, "preferred_namespace": not (user.stripe_id is None), "tag_expiration_s": user.removed_tag_expiration_s, "prompts": model.user.get_user_prompts(user), "company": user.company, "family_name": user.family_name, "given_name": user.given_name, "location": user.location, "is_free_account": user.stripe_id is None, "has_password_set": authentication.has_password_set(user.username), } ) if features.QUOTA_MANAGEMENT: quotas = model.namespacequota.get_namespace_quota_list(user.username) user_response["quotas"] = [quota_view(quota) for quota in quotas] if quotas else [] user_response["quota_report"] = model.namespacequota.get_quota_for_view(user.username) user_view_perm = UserReadPermission(user.username) if user_view_perm.can(): user_response.update( { "organizations": [ org_view(o, user_admin=user_admin.can()) for o in list(organizations.values()) ], } ) if features.SUPER_USERS and SuperUserPermission().can(): user_response.update( { "super_user": user and user == get_authenticated_user() and SuperUserPermission().can() } ) return user_response
def post(self, namespace_name, repo_name, trigger_uuid): """ Activate the specified build trigger. """ trigger = get_trigger(trigger_uuid) handler = BuildTriggerHandler.get_handler(trigger) if handler.is_active(): raise InvalidRequest('Trigger config is not sufficient for activation.') user_permission = UserAdminPermission(trigger.connected_user.username) if user_permission.can(): # Update the pull robot (if any). pull_robot_name = request.get_json().get('pull_robot', None) if pull_robot_name: try: pull_robot = model.user.lookup_robot(pull_robot_name) except model.InvalidRobotException: raise NotFound() # Make sure the user has administer permissions for the robot's namespace. (robot_namespace, _) = parse_robot_username(pull_robot_name) if not AdministerOrganizationPermission(robot_namespace).can(): raise Unauthorized() # Make sure the namespace matches that of the trigger. if robot_namespace != namespace_name: raise Unauthorized() # Set the pull robot. trigger.pull_robot = pull_robot # Update the config. new_config_dict = request.get_json()['config'] write_token_name = 'Build Trigger: %s' % trigger.service.name write_token = model.token.create_delegate_token(namespace_name, repo_name, write_token_name, 'write') try: path = url_for('webhooks.build_trigger_webhook', trigger_uuid=trigger.uuid) authed_url = _prepare_webhook_url(app.config['PREFERRED_URL_SCHEME'], '$token', write_token.get_code(), app.config['SERVER_HOSTNAME'], path) handler = BuildTriggerHandler.get_handler(trigger, new_config_dict) final_config, private_config = handler.activate(authed_url) if 'private_key' in private_config: trigger.secure_private_key = DecryptedValue(private_config['private_key']) # TODO(remove-unenc): Remove legacy field. if ActiveDataMigration.has_flag(ERTMigrationFlags.WRITE_OLD_FIELDS): trigger.private_key = private_config['private_key'] except TriggerException as exc: write_token.delete_instance() raise request_error(message=exc.message) # Save the updated config. update_build_trigger(trigger, final_config, write_token=write_token) # Log the trigger setup. repo = model.repository.get_repository(namespace_name, repo_name) log_action('setup_repo_trigger', namespace_name, {'repo': repo_name, 'namespace': namespace_name, 'trigger_id': trigger.uuid, 'service': trigger.service.name, 'pull_robot': trigger.pull_robot.username if trigger.pull_robot else None, 'config': final_config}, repo=repo) return trigger_view(trigger, can_admin=True) else: raise Unauthorized()
def user_view(user, previous_username=None): def org_view(o, user_admin=True): admin_org = AdministerOrganizationPermission(o.username) org_response = { 'name': o.username, 'avatar': avatar.get_data_for_org(o), 'can_create_repo': CreateRepositoryPermission(o.username).can(), 'public': o.username in app.config.get('PUBLIC_NAMESPACES', []), } if user_admin: org_response.update({ 'is_org_admin': admin_org.can(), 'preferred_namespace': not (o.stripe_id is None), }) return org_response # Retrieve the organizations for the user. organizations = { o.username: o for o in model.organization.get_user_organizations(user.username) } # Add any public namespaces. public_namespaces = app.config.get('PUBLIC_NAMESPACES', []) if public_namespaces: organizations.update({ ns: model.user.get_namespace_user(ns) for ns in public_namespaces }) def login_view(login): try: metadata = json.loads(login.metadata_json) except: metadata = {} return { 'service': login.service.name, 'service_identifier': login.service_ident, 'metadata': metadata } logins = model.user.list_federated_logins(user) user_response = { 'anonymous': False, 'username': user.username, 'avatar': avatar.get_data_for_user(user), } user_admin = UserAdminPermission( previous_username if previous_username else user.username) if user_admin.can(): user_response.update({ 'can_create_repo': True, 'is_me': True, 'verified': user.verified, 'email': user.email, 'logins': [login_view(login) for login in logins], 'invoice_email': user.invoice_email, 'invoice_email_address': user.invoice_email_address, 'preferred_namespace': not (user.stripe_id is None), 'tag_expiration_s': user.removed_tag_expiration_s, 'prompts': model.user.get_user_prompts(user), 'company': user.company, 'family_name': user.family_name, 'given_name': user.given_name, 'location': user.location, 'is_free_account': user.stripe_id is None, 'has_password_set': authentication.has_password_set(user.username), }) analytics_metadata = user_analytics.get_user_analytics_metadata(user) # This is a sync call, but goes through the async wrapper interface and # returns a Future. By calling with timeout 0 immediately after the method # call, we ensure that if it ever accidentally becomes async it will raise # a TimeoutError. user_response.update(analytics_metadata.result(timeout=0)) user_view_perm = UserReadPermission(user.username) if user_view_perm.can(): user_response.update({ 'organizations': [ org_view(o, user_admin=user_admin.can()) for o in organizations.values() ], }) if features.SUPER_USERS and SuperUserPermission().can(): user_response.update({ 'super_user': user and user == get_authenticated_user() and SuperUserPermission().can() }) return user_response