def get_card(user): card_info = {"is_valid": False} if user.stripe_id: try: cus = billing.Customer.retrieve(user.stripe_id) except stripe.error.APIConnectionError as e: abort(503, message="Cannot contact Stripe") if cus and cus.default_card: # Find the default card. default_card = None for card in cus.cards.data: if card.id == cus.default_card: default_card = card break if default_card: card_info = { "owner": default_card.name, "type": default_card.type, "last4": default_card.last4, "exp_month": default_card.exp_month, "exp_year": default_card.exp_year, } return {"card": card_info}
def _manifest_dict(manifest): layers = None if not manifest.is_manifest_list: layers = registry_model.list_manifest_layers(manifest, storage) if layers is None: logger.debug("Missing layers for manifest `%s`", manifest.digest) abort(404) image = None if manifest.legacy_image_root_id: # NOTE: This is replicating our older response for this endpoint, but # returns empty for the metadata fields. This is to ensure back-compat # for callers still using the deprecated API. image = { "id": manifest.legacy_image_root_id, "created": format_date(datetime.utcnow()), "comment": "", "command": "", "size": 0, "uploading": False, "sort_index": 0, "ancestors": "", } return { "digest": manifest.digest, "is_manifest_list": manifest.is_manifest_list, "manifest_data": manifest.internal_manifest_bytes.as_unicode(), "config_media_type": manifest.config_media_type, "layers": ( [_layer_dict(lyr.layer_info, idx) for idx, lyr in enumerate(layers)] if layers else None ), "image": image, }
def post(self, namespace_name, repo_name, trigger_uuid): """ Manually start a build from the specified trigger. """ trigger = get_trigger(trigger_uuid) if not trigger.enabled: raise InvalidRequest("Trigger is not enabled.") handler = BuildTriggerHandler.get_handler(trigger) if not handler.is_active(): raise InvalidRequest("Trigger is not active.") try: repo = model.repository.get_repository(namespace_name, repo_name) pull_robot_name = model.build.get_pull_robot_name(trigger) run_parameters = request.get_json() prepared = handler.manual_start(run_parameters=run_parameters) build_request = start_build(repo, prepared, pull_robot_name=pull_robot_name) except TriggerException as tse: raise InvalidRequest(tse.message) except MaximumBuildsQueuedException: abort(429, message="Maximum queued build rate exceeded.") except BuildTriggerDisabledException: abort(400, message="Build trigger is disabled") resp = build_status_view(build_request) repo_string = "%s/%s" % (namespace_name, repo_name) headers = { "Location": api.url_for( RepositoryBuildStatus, repository=repo_string, build_uuid=build_request.uuid ), } return resp, 201, headers
def get_card(user): card_info = {'is_valid': False} if user.stripe_id: try: cus = billing.Customer.retrieve(user.stripe_id) except stripe.error.APIConnectionError as e: abort(503, message='Cannot contact Stripe') if cus and cus.default_card: # Find the default card. default_card = None for card in cus.cards.data: if card.id == cus.default_card: default_card = card break if default_card: card_info = { 'owner': default_card.name, 'type': default_card.type, 'last4': default_card.last4, 'exp_month': default_card.exp_month, 'exp_year': default_card.exp_year } return {'card': card_info}
def get(self, orgname): """ Fetch any existing subscription for the org. """ cus = None permission = AdministerOrganizationPermission(orgname) if permission.can(): private_repos = model.user.get_private_repo_count(orgname) organization = model.organization.get_organization(orgname) if organization.stripe_id: try: cus = billing.Customer.retrieve(organization.stripe_id) except stripe.error.APIConnectionError as e: abort(503, message="Cannot contact Stripe") if cus.subscription: return subscription_view(cus.subscription, private_repos) return { "hasSubscription": False, "isExistingCustomer": cus is not None, "plan": "free", "usedPrivateRepos": private_repos, } raise Unauthorized()
def _manifest_dict(manifest): image = None if manifest.legacy_image_if_present is not None: image = image_dict(manifest.legacy_image, with_history=True) layers = None if not manifest.is_manifest_list: layers = registry_model.list_manifest_layers(manifest, storage) if layers is None: logger.debug('Missing layers for manifest `%s`', manifest.digest) abort(404) return { 'digest': manifest.digest, 'is_manifest_list': manifest.is_manifest_list, 'manifest_data': manifest.internal_manifest_bytes.as_unicode(), 'image': image, 'layers': ([_layer_dict(lyr.layer_info, idx) for idx, lyr in enumerate(layers)] if layers else None), }
def get_invoice_fields(user): try: cus = billing.Customer.retrieve(user.stripe_id) except stripe.error.APIConnectionError: abort(503, message="Cannot contact Stripe") if not "metadata" in cus: cus.metadata = {} return json.loads(cus.metadata.get("invoice_fields") or "[]"), cus
def get_invoice_fields(user): try: cus = billing.Customer.retrieve(user.stripe_id) except stripe.error.APIConnectionError: abort(503, message='Cannot contact Stripe') if not 'metadata' in cus: cus.metadata = {} return json.loads(cus.metadata.get('invoice_fields') or '[]'), cus
def get(self, orgname): """ List the invoice fields for the organization. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): organization = model.organization.get_organization(orgname) if not organization.stripe_id: raise NotFound() return {'fields': get_invoice_fields(organization)[0]} abort(403)
def delete(self, field_uuid): """ Deletes the invoice field for the current user. """ user = get_authenticated_user() if not user.stripe_id: raise NotFound() result = delete_billing_invoice_field(user, field_uuid) if not result: abort(404) return 'Okay', 201
def post(self, orgname): """ Creates a new invoice field. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): organization = model.organization.get_organization(orgname) if not organization.stripe_id: raise NotFound() data = request.get_json() created_field = create_billing_invoice_field( organization, data['title'], data['value']) return created_field abort(403)
def delete(self, orgname, field_uuid): """ Deletes the invoice field for the current user. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): organization = model.organization.get_organization(orgname) if not organization.stripe_id: raise NotFound() result = delete_billing_invoice_field(organization, field_uuid) if not result: abort(404) return 'Okay', 201 abort(403)
def _manifest_dict(manifest): layers = None if not manifest.is_manifest_list: layers = registry_model.list_manifest_layers(manifest, storage) if layers is None: logger.debug("Missing layers for manifest `%s`", manifest.digest) abort(404) return { "digest": manifest.digest, "is_manifest_list": manifest.is_manifest_list, "manifest_data": manifest.internal_manifest_bytes.as_unicode(), "config_media_type": manifest.config_media_type, "layers": ( [_layer_dict(lyr.layer_info, idx) for idx, lyr in enumerate(layers)] if layers else None ), }
def set_card(user, token): if user.stripe_id: try: cus = billing.Customer.retrieve(user.stripe_id) except stripe.error.APIConnectionError as e: abort(503, message="Cannot contact Stripe") if cus: try: cus.card = token cus.save() except stripe.error.CardError as exc: return carderror_response(exc) except stripe.error.InvalidRequestError as exc: return carderror_response(exc) except stripe.error.APIConnectionError as e: return carderror_response(e) return get_card(user)
def get_namespace_plan(namespace): """ Returns the plan of the given namespace. """ namespace_user = model.user.get_namespace_user(namespace) if namespace_user is None: return None if not namespace_user.stripe_id: return None # Ask Stripe for the subscribed plan. # TODO: Can we cache this or make it faster somehow? try: cus = billing.Customer.retrieve(namespace_user.stripe_id) except stripe.error.APIConnectionError: abort(503, message='Cannot contact Stripe') if not cus.subscription: return None return get_plan(cus.subscription.plan.id)
def get(self): """ Fetch any existing subscription for the user. """ cus = None user = get_authenticated_user() private_repos = model.user.get_private_repo_count(user.username) if user.stripe_id: try: cus = billing.Customer.retrieve(user.stripe_id) except stripe.error.APIConnectionError as e: abort(503, message='Cannot contact Stripe') if cus.subscription: return subscription_view(cus.subscription, private_repos) return { 'hasSubscription': False, 'isExistingCustomer': cus is not None, 'plan': 'free', 'usedPrivateRepos': private_repos, }
def get_invoices(customer_id): def invoice_view(i): return { 'id': i.id, 'date': i.date, 'period_start': i.period_start, 'period_end': i.period_end, 'paid': i.paid, 'amount_due': i.amount_due, 'next_payment_attempt': i.next_payment_attempt, 'attempted': i.attempted, 'closed': i.closed, 'total': i.total, 'plan': i.lines.data[0].plan.id if i.lines.data[0].plan else None } try: invoices = billing.Invoice.list(customer=customer_id, count=12) except stripe.error.APIConnectionError as e: abort(503, message='Cannot contact Stripe') return {'invoices': [invoice_view(i) for i in invoices.data]}
def get_invoices(customer_id): def invoice_view(i): return { "id": i.id, "date": i.date, "period_start": i.period_start, "period_end": i.period_end, "paid": i.paid, "amount_due": i.amount_due, "next_payment_attempt": i.next_payment_attempt, "attempted": i.attempted, "closed": i.closed, "total": i.total, "plan": i.lines.data[0].plan.id if i.lines.data[0].plan else None, } try: invoices = billing.Invoice.list(customer=customer_id, count=12) except stripe.error.APIConnectionError as e: abort(503, message="Cannot contact Stripe") return {"invoices": [invoice_view(i) for i in invoices.data]}
def post(self, namespace_name, repository_name, manifestref): """ Adds a new label into the tag manifest. """ label_data = request.get_json() # Check for any reserved prefixes. if label_validator.has_reserved_prefix(label_data['key']): abort(400, message='Label has a reserved prefix') repo_ref = registry_model.lookup_repository(namespace_name, repository_name) if repo_ref is None: raise NotFound() manifest = registry_model.lookup_manifest_by_digest( repo_ref, manifestref) if manifest is None: raise NotFound() label = None try: label = registry_model.create_manifest_label( manifest, label_data['key'], label_data['value'], 'api', label_data['media_type']) except InvalidLabelKeyException: message = ('Label is of an invalid format or missing please ' + 'use %s format for labels' % VALID_LABEL_KEY_REGEX) abort(400, message=message) except InvalidMediaTypeException: message = 'Media type is invalid please use a valid media type: text/plain, application/json' abort(400, message=message) if label is None: raise NotFound() metadata = { 'id': label.uuid, 'key': label.key, 'value': label.value, 'manifest_digest': manifestref, 'media_type': label.media_type_name, 'namespace': namespace_name, 'repo': repository_name, } log_action('manifest_label_add', namespace_name, metadata, repo_name=repository_name) resp = {'label': _label_dict(label)} repo_string = '%s/%s' % (namespace_name, repository_name) headers = { 'Location': api.url_for(ManageRepositoryManifestLabel, repository=repo_string, manifestref=manifestref, labelid=label.uuid), } return resp, 201, headers
def post(self, namespace_name, repository_name, manifestref): """ Adds a new label into the tag manifest. """ label_data = request.get_json() # Check for any reserved prefixes. if label_validator.has_reserved_prefix(label_data["key"]): abort(400, message="Label has a reserved prefix") repo_ref = registry_model.lookup_repository(namespace_name, repository_name) if repo_ref is None: raise NotFound() manifest = registry_model.lookup_manifest_by_digest(repo_ref, manifestref) if manifest is None: raise NotFound() label = None try: label = registry_model.create_manifest_label( manifest, label_data["key"], label_data["value"], "api", label_data["media_type"] ) except InvalidLabelKeyException: message = ( "Label is of an invalid format or missing please " + "use %s format for labels" % VALID_LABEL_KEY_REGEX ) abort(400, message=message) except InvalidMediaTypeException: message = ( "Media type is invalid please use a valid media type: text/plain, application/json" ) abort(400, message=message) if label is None: raise NotFound() metadata = { "id": label.uuid, "key": label.key, "value": label.value, "manifest_digest": manifestref, "media_type": label.media_type_name, "namespace": namespace_name, "repo": repository_name, } log_action("manifest_label_add", namespace_name, metadata, repo_name=repository_name) resp = {"label": _label_dict(label)} repo_string = "%s/%s" % (namespace_name, repository_name) headers = { "Location": api.url_for( ManageRepositoryManifestLabel, repository=repo_string, manifestref=manifestref, labelid=label.uuid, ), } return resp, 201, headers
def post(self, namespace, repository): """ Request that a repository be built and pushed from the specified input. """ logger.debug("User requested repository initialization.") request_json = request.get_json() dockerfile_id = request_json.get("file_id", None) archive_url = request_json.get("archive_url", None) if not dockerfile_id and not archive_url: raise InvalidRequest("file_id or archive_url required") if archive_url: archive_match = None try: archive_match = urlparse(archive_url) except ValueError: pass if not archive_match: raise InvalidRequest( "Invalid Archive URL: Must be a valid URI") scheme = archive_match.scheme if scheme != "http" and scheme != "https": raise InvalidRequest( "Invalid Archive URL: Must be http or https") context, subdir = self.get_dockerfile_context(request_json) tags = request_json.get("docker_tags", ["latest"]) pull_robot_name = request_json.get("pull_robot", None) # Verify the security behind the pull robot. if pull_robot_name: result = parse_robot_username(pull_robot_name) if result: try: 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, _) = result if not AdministerOrganizationPermission(robot_namespace).can(): raise Unauthorized() else: raise Unauthorized() # Check if the dockerfile resource has already been used. If so, then it # can only be reused if the user has access to the repository in which the # dockerfile was previously built. if dockerfile_id: associated_repository = model.build.get_repository_for_resource( dockerfile_id) if associated_repository: if not ModifyRepositoryPermission( associated_repository.namespace_user.username, associated_repository.name): raise Unauthorized() # Start the build. repo = model.repository.get_repository(namespace, repository) if repo is None: raise NotFound() try: build_name = (user_files.get_file_checksum(dockerfile_id) if dockerfile_id else hashlib.sha224( archive_url.encode("ascii")).hexdigest()[0:7]) except IOError: raise InvalidRequest("File %s could not be found or is invalid" % dockerfile_id) prepared = PreparedBuild() prepared.build_name = build_name prepared.dockerfile_id = dockerfile_id prepared.archive_url = archive_url prepared.tags = tags prepared.subdirectory = subdir prepared.context = context prepared.is_manual = True prepared.metadata = {} try: build_request = start_build(repo, prepared, pull_robot_name=pull_robot_name) except MaximumBuildsQueuedException: abort(429, message="Maximum queued build rate exceeded.") except BuildTriggerDisabledException: abort(400, message="Build trigger is disabled") resp = build_status_view(build_request) repo_string = "%s/%s" % (namespace, repository) headers = { "Location": api.url_for(RepositoryBuildStatus, repository=repo_string, build_uuid=build_request.uuid), } return resp, 201, headers