Пример #1
0
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}
Пример #2
0
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,
    }
Пример #3
0
    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
Пример #4
0
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}
Пример #5
0
    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()
Пример #6
0
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),
    }
Пример #7
0
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
Пример #8
0
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
Пример #9
0
    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)
Пример #10
0
    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
Пример #11
0
    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)
Пример #12
0
    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)
Пример #13
0
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
        ),
    }
Пример #14
0
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)
Пример #15
0
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)
Пример #16
0
    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,
        }
Пример #17
0
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]}
Пример #18
0
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]}
Пример #19
0
    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
Пример #20
0
    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
Пример #21
0
    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