Пример #1
0
        def check_advantage(*args, **kwargs):
            if "is_maintenance":
                if strtobool(os.getenv("STORE_MAINTENANCE", "false")):
                    return flask.render_template("advantage/maintenance.html")

            is_test_backend = flask.request.args.get("test_backend", False)

            stripe_publishable_key = os.getenv(
                "STRIPE_LIVE_PUBLISHABLE_KEY",
                "pk_live_68aXqowUeX574aGsVck8eiIE",
            )

            api_url = flask.current_app.config["CONTRACTS_LIVE_API_URL"]

            if is_test_backend:
                stripe_publishable_key = os.getenv(
                    "STRIPE_TEST_PUBLISHABLE_KEY",
                    "pk_test_yndN9H0GcJffPe0W58Nm64cM00riYG4N46",
                )
                api_url = flask.current_app.config["CONTRACTS_TEST_API_URL"]

            user_token = flask.session.get("authentication_token")
            guest_token = flask.session.get("guest_authentication_token")

            kwargs["test_backend"] = is_test_backend
            kwargs["api_url"] = api_url
            kwargs["stripe_publishable_key"] = stripe_publishable_key
            kwargs["token"] = user_token or guest_token
            kwargs["token_type"] = "Macaroon" if user_token else "Bearer"

            if "view_need_user" in check_list and not user_info(flask.session):
                if flask.request.path != "/advantage":
                    return flask.redirect("/advantage")

                return flask.render_template(
                    "advantage/index-no-login.html",
                    is_test_backend=is_test_backend,
                )

            if "need_user" in check_list:
                if not user_info(flask.session):
                    return (
                        flask.jsonify({"error": "authentication required"}),
                        401,
                    )

            if "need_user_or_guest" in check_list:
                if not user_info(flask.session) and not guest_token:
                    return (
                        flask.jsonify({"error": "authentication required"}),
                        401,
                    )

            return func(*args, **kwargs)
Пример #2
0
        def decorated_function(*args, **kwargs):
            # UA under maintenance
            if strtobool(os.getenv("STORE_MAINTENANCE", "false")):
                return flask.render_template("advantage/maintenance.html")

            # if logged in, get rid of guest token
            if user_info(flask.session):
                if flask.session.get("guest_authentication_token"):
                    flask.session.pop("guest_authentication_token")

            test_backend = flask.request.args.get("test_backend", "false")
            is_test_backend = strtobool(test_backend)
            user_token = flask.session.get("authentication_token")
            guest_token = flask.session.get("guest_authentication_token")

            if permission == "user" and response == "html":
                if not user_info(flask.session):
                    if flask.request.path != "/advantage":
                        return flask.redirect(
                            "/advantage?test_backend=true"
                            if is_test_backend else "/advantage")

                    return flask.render_template(
                        "advantage/index-no-login.html",
                        is_test_backend=is_test_backend,
                    )

            if permission == "user" and response == "json":
                if not user_info(flask.session):
                    message = {"error": "authentication required"}

                    return flask.jsonify(message), 401

            if permission == "user_or_guest" and response == "json":
                if not user_info(flask.session) and not guest_token:
                    message = {"error": "authentication required"}

                    return flask.jsonify(message), 401

            # init API instance
            g.api = UAContractsAPI(
                session=session,
                authentication_token=(user_token or guest_token),
                token_type=("Macaroon" if user_token else "Bearer"),
                api_url=get_api_url(is_test_backend),
            )

            if response == "html":
                g.api.set_is_for_view(True)

            return func(*args, **kwargs)
Пример #3
0
def context():
    return {
        "current_year": current_year,
        "descending_years": descending_years,
        "format_date": format_date,
        "get_json_feed": get_json_feed,
        "modify_query": modify_query,
        "month_name": month_name,
        "months_list": months_list,
        "get_navigation": get_navigation,
        "get_stripe_publishable_key": os.getenv(
            "STRIPE_PUBLISHABLE_KEY",
            "pk_live_68aXqowUeX574aGsVck8eiIE",
        ),
        "product": flask.request.args.get("product", ""),
        "request": flask.request,
        "releases": releases(),
        "user_info": user_info(flask.session),
        "utm_campaign": flask.request.args.get("utm_campaign", ""),
        "utm_content": flask.request.args.get("utm_content", ""),
        "utm_medium": flask.request.args.get("utm_medium", ""),
        "utm_source": flask.request.args.get("utm_source", ""),
        "CAPTCHA_TESTING_API_KEY": CAPTCHA_TESTING_API_KEY,
        "http_host": flask.request.host,
    }
Пример #4
0
def post_anonymised_customer_info():
    user_token = flask.session.get("authentication_token")
    guest_token = flask.session.get("guest_authentication_token")
    is_test_backend = flask.request.args.get("test_backend", False)

    api_url = flask.current_app.config["CONTRACTS_LIVE_API_URL"]

    if is_test_backend:
        api_url = flask.current_app.config["CONTRACTS_TEST_API_URL"]

    if user_info(flask.session) or guest_token:
        advantage = AdvantageContracts(
            session,
            user_token or guest_token,
            token_type=("Macaroon" if user_token else "Bearer"),
            api_url=api_url,
        )

        if not flask.request.is_json:
            return flask.jsonify({"error": "JSON required"}), 400

        account_id = flask.request.json.get("account_id")
        if not account_id:
            return flask.jsonify({"error": "account_id required"}), 400

        address = flask.request.json.get("address")
        if not address:
            return flask.jsonify({"error": "address required"}), 400

        tax_id = flask.request.json.get("tax_id")

        return advantage.put_anonymous_customer_info(account_id, address,
                                                     tax_id)
    else:
        return flask.jsonify({"error": "authentication required"}), 401
Пример #5
0
def blender_shop_view(advantage_mapper, **kwargs):
    account = None
    if user_info(flask.session):
        try:
            account = advantage_mapper.get_purchase_account("blender")
        except UAContractsUserHasNoAccount:
            # There is no purchase account yet for this user.
            # One will need to be created later; expected condition.
            pass
        except AccessForbiddenError:
            return flask.render_template("account/forbidden.html")

    all_subscriptions = []
    if account:
        all_subscriptions = advantage_mapper.get_account_subscriptions(
            account_id=account.id,
            marketplace="blender",
        )

    current_subscriptions = [
        subscription
        for subscription in all_subscriptions
        if subscription.status in ["active", "locked"]
    ]

    listings = advantage_mapper.get_product_listings("blender")
    previous_purchase_ids = extract_last_purchase_ids(current_subscriptions)

    return flask.render_template(
        "advantage/subscribe/blender/index.html",
        account=account,
        previous_purchase_ids=previous_purchase_ids,
        product_listings=to_dict(listings),
    )
Пример #6
0
def post_customer_info():
    if user_info(flask.session):
        advantage = AdvantageContracts(
            session,
            flask.session["authentication_token"],
            api_url=flask.current_app.config["CONTRACTS_API_URL"],
        )

        if not flask.request.is_json:
            return flask.jsonify({"error": "JSON required"}), 400

        payment_method_id = flask.request.json.get("payment_method_id")
        if not payment_method_id:
            return flask.jsonify({"error": "payment_method_id required"}), 400

        account_id = flask.request.json.get("account_id")
        if not account_id:
            return flask.jsonify({"error": "account_id required"}), 400

        address = flask.request.json.get("address")
        name = flask.request.json.get("name")
        tax_id = flask.request.json.get("tax_id")

        return advantage.put_customer_info(
            account_id, payment_method_id, address, name, tax_id
        )
    else:
        return flask.jsonify({"error": "authentication required"}), 401
Пример #7
0
def cube_require_login_cube_study():
    if flask.request.path.startswith("/cube/study"):
        user = user_info(flask.session)
        if not user:
            return flask.redirect("/login?next=" + flask.request.path)

        if not is_authorized(user):
            flask.abort(403)
Пример #8
0
def account_query():
    """
    A JSON endpoint to request login status
    """

    return flask.jsonify({
        "account": user_info(flask.session),
    })
Пример #9
0
def ua_contracts_validation_error(error):
    sentry.captureException(
        extra={
            "user_info": user_info(flask.session),
            "request_url": error.request.url,
            "request_body": error.request.json,
            "response_body": error.response.messages,
        })

    return flask.jsonify({"errors": error.response.messages}), 422
Пример #10
0
def advantage_thanks_view(**kwargs):
    email = kwargs.get("email")

    if user_info(flask.session):
        return flask.redirect("/advantage")

    return flask.render_template(
        "advantage/subscribe/thank-you.html",
        email=email,
    )
Пример #11
0
def accept_renewal(renewal_id):
    if user_info(flask.session):
        advantage = AdvantageContracts(
            session,
            flask.session["authentication_token"],
            api_url=flask.current_app.config["CONTRACTS_API_URL"],
        )

        return advantage.accept_renewal(renewal_id)
    else:
        return flask.jsonify({"error": "authentication required"}), 401
Пример #12
0
def get_purchase(purchase_id):
    user_token = flask.session.get("authentication_token")
    guest_token = flask.session.get("guest_authentication_token")

    if user_info(flask.session) or guest_token:
        advantage = AdvantageContracts(
            session,
            user_token or guest_token,
            token_type=("Macaroon" if user_token else "Bearer"),
            api_url=flask.current_app.config["CONTRACTS_API_URL"],
        )

        return advantage.get_purchase(purchase_id)
    else:
        return flask.jsonify({"error": "authentication required"}), 401
Пример #13
0
def ua_contracts_api_error_view(error):
    sentry.captureException(
        extra={
            "user_info": user_info(flask.session),
            "request_url": error.request.url,
            "request_headers": error.request.headers,
            "response_headers": error.response.headers,
            "response_body": error.response.json(),
        })

    if error.response.status_code == 401:
        empty_session(flask.session)

        return flask.redirect(flask.request.url)

    return flask.render_template("500.html"), 500
Пример #14
0
def ua_contracts_api_error(error):
    sentry.captureException(
        extra={
            "user_info": user_info(flask.session),
            "request_url": error.request.url,
            "request_headers": error.request.headers,
            "response_headers": error.response.headers,
            "response_body": error.response.json(),
        })

    if error.response.status_code == 401:
        empty_session(flask.session)

    return (
        flask.jsonify({"errors": error.response.json()["message"]}),
        error.response.status_code or 500,
    )
Пример #15
0
def ensure_purchase_account():
    """
    Returns an object with the ID of an account a user can make
    purchases on. If the user is not logged in, the object also
    contains an auth token required for subsequent calls to the
    contract API.
    """
    is_test_backend = flask.request.args.get("test_backend", False)

    api_url = flask.current_app.config["CONTRACTS_LIVE_API_URL"]

    if is_test_backend:
        api_url = flask.current_app.config["CONTRACTS_TEST_API_URL"]

    if not flask.request.is_json:
        return flask.jsonify({"error": "JSON required"}), 400

    auth_token = None
    if user_info(flask.session):
        auth_token = flask.session["authentication_token"]
    advantage = AdvantageContracts(
        session,
        auth_token,
        api_url=api_url,
    )

    request = flask.request.json
    try:
        account = advantage.ensure_purchase_account(
            email=request.get("email"),
            account_name=request.get("account_name"),
            payment_method_id=request.get("payment_method_id"),
        )
    except UnauthorizedError as err:
        # This kind of errors are handled js side.
        return err.asdict(), 200
    except HTTPError as err:
        flask.current_app.extensions["sentry"].captureException()
        return err.response.content, 500

    # The guest authentication token is included in the response only when the
    # user is not logged in.
    token = account.get("token")
    if token:
        flask.session["guest_authentication_token"] = token
    return flask.jsonify(account), 200
Пример #16
0
def accept_renewal(renewal_id):
    is_test_backend = flask.request.args.get("test_backend", False)

    api_url = flask.current_app.config["CONTRACTS_LIVE_API_URL"]

    if is_test_backend:
        api_url = flask.current_app.config["CONTRACTS_TEST_API_URL"]

    if user_info(flask.session):
        advantage = AdvantageContracts(
            session,
            flask.session["authentication_token"],
            api_url=api_url,
        )

        return advantage.accept_renewal(renewal_id)
    else:
        return flask.jsonify({"error": "authentication required"}), 401
Пример #17
0
def context():
    return {
        "current_year": current_year,
        "descending_years": descending_years,
        "format_date": format_date,
        "get_json_feed": get_json_feed,
        "modify_query": modify_query,
        "month_name": month_name,
        "months_list": months_list,
        "get_navigation": get_navigation,
        "product": flask.request.args.get("product", ""),
        "request": flask.request,
        "releases": releases(),
        "user_info": user_info(flask.session),
        "utm_campaign": flask.request.args.get("utm_campaign", ""),
        "utm_medium": flask.request.args.get("utm_medium", ""),
        "utm_source": flask.request.args.get("utm_source", ""),
        "CAPTCHA_TESTING_API_KEY": CAPTCHA_TESTING_API_KEY,
    }
Пример #18
0
def ensure_purchase_account(**kwargs):
    """
    Returns an object with the ID of an account a user can make
    purchases on. If the user is not logged in, the object also
    contains an auth token required for subsequent calls to the
    contract API.
    """

    api_url = kwargs.get("api_url")
    email = kwargs.get("email")
    account_name = kwargs.get("account_name")
    payment_method_id = kwargs.get("payment_method_id")
    country = kwargs.get("country")

    token = None
    if user_info(flask.session):
        token = flask.session["authentication_token"]

    advantage = UAContractsAPI(session, token, api_url=api_url)

    try:
        account = advantage.ensure_purchase_account(
            email=email,
            account_name=account_name,
            payment_method_id=payment_method_id,
            country=country,
        )
    except UnauthorizedError as err:
        # This kind of errors are handled js side.
        return err.asdict(), 200
    except HTTPError as err:
        flask.current_app.extensions["sentry"].captureException()
        return err.response.content, 500

    # The guest authentication token is included in the response only when the
    # user is not logged in.
    token = account.get("token")

    if token:
        flask.session["guest_authentication_token"] = token

    return flask.jsonify(account), 200
Пример #19
0
def post_stripe_invoice_id(tx_type, tx_id, invoice_id):
    user_token = flask.session.get("authentication_token")
    guest_token = flask.session.get("guest_authentication_token")
    is_test_backend = flask.request.args.get("test_backend", False)

    api_url = flask.current_app.config["CONTRACTS_LIVE_API_URL"]

    if is_test_backend:
        api_url = flask.current_app.config["CONTRACTS_TEST_API_URL"]

    if user_info(flask.session) or guest_token:
        advantage = AdvantageContracts(
            session,
            user_token or guest_token,
            token_type=("Macaroon" if user_token else "Bearer"),
            api_url=api_url,
        )

        return advantage.post_stripe_invoice_id(tx_type, tx_id, invoice_id)
    else:
        return flask.jsonify({"error": "authentication required"}), 401
Пример #20
0
def cube_study_labs_button(edx_api, **kwargs):
    sso_user = user_info(flask.session)
    study_labs = "course-v1:CUBE+study_labs+2020"
    edx_user = edx_api.get_user(sso_user["email"])
    enrollments = [
        enrollment["course_details"]["course_id"]
        for enrollment in edx_api.get_enrollments(edx_user["username"])
        if enrollment["is_active"]
    ]

    text = "Purchase study labs access"
    redirect_url = "/cube/microcerts"

    if study_labs in enrollments:
        text = "Access study labs"
        prepare_materials_path = quote_plus(f"/courses/{study_labs}/course/")
        redirect_url = (
            f"{edx_api.base_url}/auth/login/tpa-saml/"
            f"?auth_entry=login&idp=ubuntuone&next={prepare_materials_path}")

    return flask.jsonify({"text": text, "redirect_url": redirect_url})
Пример #21
0
def advantage_shop_view():
    g.api.set_convert_response(True)

    account = None
    if user_info(flask.session):
        try:
            account = g.api.get_purchase_account()
        except UAContractsUserHasNoAccount:
            # There is no purchase account yet for this user.
            # One will need to be created later; expected condition.
            pass

    all_subscriptions = []
    if account:
        all_subscriptions = g.api.get_account_subscriptions(
            account_id=account.id,
            marketplace="canonical-ua",
        )

    current_subscriptions = [
        subscription for subscription in all_subscriptions
        if subscription.status in ["active", "locked"]
    ]

    is_trialling = any(subscription for subscription in current_subscriptions
                       if subscription.in_trial)

    listings = g.api.get_product_listings("canonical-ua")

    previous_purchase_ids = extract_last_purchase_ids(current_subscriptions)
    user_listings = set_listings_trial_status(listings, all_subscriptions)

    return flask.render_template(
        "advantage/subscribe/index.html",
        account=account,
        previous_purchase_ids=previous_purchase_ids,
        product_listings=user_listings,
        is_trialling=is_trialling,
    )
Пример #22
0
def post_build():
    """
    Once they submit the build form on /core/build,
    kick off the build with Launchpad
    """

    opt_in = flask.request.values.get("canonicalUpdatesOptIn")
    full_name = flask.request.values.get("FullName")
    names = full_name.split(" ")
    email = flask.request.values.get("Email")
    board = flask.request.values.get("board")
    system = flask.request.values.get("system")
    snaps = flask.request.values.get("snaps", "").split(",")
    arch = flask.request.values.get("arch")

    if not user_info(flask.session):
        flask.abort(401)

    launchpad = Launchpad(
        username=os.environ["LAUNCHPAD_IMAGE_BUILD_USER"],
        token=os.environ["LAUNCHPAD_IMAGE_BUILD_TOKEN"],
        secret=os.environ["LAUNCHPAD_IMAGE_BUILD_SECRET"],
        session=session,
        auth_consumer=os.environ["LAUNCHPAD_IMAGE_BUILD_AUTH_CONSUMER"],
    )

    context = {}

    # Submit user to marketo
    session.post(
        "https://pages.ubuntu.com/index.php/leadCapture/save",
        data={
            "canonicalUpdatesOptIn": opt_in,
            "FirstName": " ".join(names[:-1]),
            "LastName": names[-1] if len(names) > 1 else "",
            "Email": email,
            "formid": "3546",
            "lpId": "2154",
            "subId": "30",
            "munchkinId": "066-EOV-335",
            "imageBuilderStatus": "NULL",
        },
    )

    # Ensure webhook is created
    if flask.request.host == "ubuntu.com":
        launchpad.create_update_system_build_webhook(
            system=system,
            delivery_url="https://ubuntu.com/core/build/notify",
            secret=flask.current_app.config["SECRET_KEY"],
        )

    # Kick off image build
    try:
        response = launchpad.build_image(
            board=board,
            system=system,
            snaps=snaps,
            author_info={"name": full_name, "email": email, "board": board},
            gpg_passphrase=flask.current_app.config["SECRET_KEY"],
            arch=arch,
        )
        context["build_info"] = launchpad.session.get(
            response.headers["Location"]
        ).json()
    except HTTPError as http_error:
        if http_error.response.status_code == 400:
            return (
                flask.render_template(
                    "core/build/error.html",
                    build_error=http_error.response.content.decode(),
                ),
                400,
            )
        else:
            raise http_error

    return flask.render_template("core/build/index.html", **context)
Пример #23
0
def advantage_view():
    accounts = None
    personal_account = None
    enterprise_contracts = {}
    entitlements = {}
    open_subscription = flask.request.args.get("subscription", None)
    stripe_publishable_key = os.getenv(
        "STRIPE_PUBLISHABLE_KEY", "pk_live_68aXqowUeX574aGsVck8eiIE"
    )

    if user_info(flask.session):
        advantage = AdvantageContracts(
            session,
            flask.session["authentication_token"],
            api_url=flask.current_app.config["CONTRACTS_API_URL"],
        )

        try:
            accounts = advantage.get_accounts()
        except HTTPError as http_error:
            if http_error.response.status_code == 401:
                # We got an unauthorized request, so we likely
                # need to re-login to refresh the macaroon
                flask.current_app.extensions["sentry"].captureException(
                    extra={
                        "session_keys": flask.session.keys(),
                        "request_url": http_error.request.url,
                        "request_headers": http_error.request.headers,
                        "response_headers": http_error.response.headers,
                        "response_body": http_error.response.json(),
                        "response_code": http_error.response.json()["code"],
                        "response_message": http_error.response.json()[
                            "message"
                        ],
                    }
                )

                empty_session(flask.session)

                return flask.render_template("advantage/index.html")

            raise http_error

        for account in accounts:
            account["contracts"] = advantage.get_account_contracts(account)

            for contract in account["contracts"]:
                contract["token"] = advantage.get_contract_token(contract)

                machines = advantage.get_contract_machines(contract).get(
                    "machines"
                )
                contract["machineCount"] = 0

                if machines:
                    contract["machineCount"] = len(machines)

                if contract["contractInfo"].get("origin", "") == "free":
                    personal_account = account
                    personal_account["free_token"] = contract["token"]
                    for entitlement in contract["contractInfo"][
                        "resourceEntitlements"
                    ]:
                        if entitlement["type"] == "esm-infra":
                            entitlements["esm-infra"] = True
                        elif entitlement["type"] == "esm-apps":
                            entitlements["esm-apps"] = True
                        elif entitlement["type"] == "livepatch":
                            entitlements["livepatch"] = True
                        elif entitlement["type"] == "fips":
                            entitlements["fips"] = True
                        elif entitlement["type"] == "cc-eal":
                            entitlements["cc-eal"] = True
                    personal_account["entitlements"] = entitlements
                else:
                    entitlements = {}
                    for entitlement in contract["contractInfo"][
                        "resourceEntitlements"
                    ]:
                        contract["supportLevel"] = "-"
                        if entitlement["type"] == "esm-infra":
                            entitlements["esm-infra"] = True
                        elif entitlement["type"] == "esm-apps":
                            entitlements["esm-apps"] = True
                        elif entitlement["type"] == "livepatch":
                            entitlements["livepatch"] = True
                        elif entitlement["type"] == "fips":
                            entitlements["fips"] = True
                        elif entitlement["type"] == "cc-eal":
                            entitlements["cc-eal"] = True
                        elif entitlement["type"] == "support":
                            contract["supportLevel"] = entitlement[
                                "affordances"
                            ]["supportLevel"]
                    contract["entitlements"] = entitlements
                    created_at = dateutil.parser.parse(
                        contract["contractInfo"]["createdAt"]
                    )
                    contract["contractInfo"][
                        "createdAtFormatted"
                    ] = created_at.strftime("%d %B %Y")
                    contract["contractInfo"]["status"] = "active"

                    if "effectiveTo" in contract["contractInfo"]:
                        effective_to = dateutil.parser.parse(
                            contract["contractInfo"]["effectiveTo"]
                        )
                        contract["contractInfo"][
                            "effectiveToFormatted"
                        ] = effective_to.strftime("%d %B %Y")

                        time_now = datetime.utcnow().replace(tzinfo=pytz.utc)

                        if effective_to < time_now:
                            contract["contractInfo"]["status"] = "expired"
                            contract["contractInfo"][
                                "expired_restart_date"
                            ] = time_now - timedelta(days=1)

                        date_difference = effective_to - time_now
                        contract["expiring"] = date_difference.days <= 30
                        contract["contractInfo"][
                            "daysTillExpiry"
                        ] = date_difference.days

                    contract["renewal"] = make_renewal(
                        advantage, contract["contractInfo"]
                    )

                    enterprise_contract = enterprise_contracts.setdefault(
                        contract["accountInfo"]["name"], []
                    )
                    # If a subscription id is present and this contract
                    # matches add it to the start of the list
                    if contract["contractInfo"]["id"] == open_subscription:
                        enterprise_contract.insert(0, contract)
                    else:
                        enterprise_contract.append(contract)

    return flask.render_template(
        "advantage/index.html",
        accounts=accounts,
        enterprise_contracts=enterprise_contracts,
        personal_account=personal_account,
        open_subscription=open_subscription,
        stripe_publishable_key=stripe_publishable_key,
    )
Пример #24
0
def advantage_shop_view():
    account = previous_purchase_id = None
    is_test_backend = flask.request.args.get("test_backend", False)

    stripe_publishable_key = os.getenv("STRIPE_LIVE_PUBLISHABLE_KEY",
                                       "pk_live_68aXqowUeX574aGsVck8eiIE")
    api_url = flask.current_app.config["CONTRACTS_LIVE_API_URL"]

    if is_test_backend:
        stripe_publishable_key = os.getenv(
            "STRIPE_TEST_PUBLISHABLE_KEY",
            "pk_test_yndN9H0GcJffPe0W58Nm64cM00riYG4N46",
        )
        api_url = flask.current_app.config["CONTRACTS_TEST_API_URL"]

    if user_info(flask.session):
        advantage = AdvantageContracts(
            session,
            flask.session["authentication_token"],
            api_url=api_url,
        )
        if flask.session.get("guest_authentication_token"):
            flask.session.pop("guest_authentication_token")

        try:
            account = advantage.get_purchase_account()
        except HTTPError as err:
            code = err.response.status_code
            if code == 401:
                # We got an unauthorized request, so we likely
                # need to re-login to refresh the macaroon
                flask.current_app.extensions["sentry"].captureException(
                    extra={
                        "session_keys": flask.session.keys(),
                        "request_url": err.request.url,
                        "request_headers": err.request.headers,
                        "response_headers": err.response.headers,
                        "response_body": err.response.json(),
                        "response_code": err.response.json()["code"],
                        "response_message": err.response.json()["message"],
                    })

                empty_session(flask.session)

                return flask.render_template(
                    "advantage/subscribe/index.html",
                    account=None,
                    previous_purchase_id=None,
                    product_listings=[],
                    stripe_publishable_key=stripe_publishable_key,
                    is_test_backend=is_test_backend,
                )
            if code != 404:
                raise
            # There is no purchase account yet for this user.
            # One will need to be created later, but this is an expected
            # condition.
    else:
        advantage = AdvantageContracts(session, None, api_url=api_url)

    if account is not None:
        resp = advantage.get_account_subscriptions_for_marketplace(
            account["id"], "canonical-ua")
        subs = resp.get("subscriptions")
        if subs:
            previous_purchase_id = subs[0].get("lastPurchaseID")

    listings_response = advantage.get_marketplace_product_listings(
        "canonical-ua")
    product_listings = listings_response.get("productListings")
    if not product_listings:
        # For the time being, no product listings means the shop has not been
        # activated, so fallback to shopify. This should become an error later.
        return flask.redirect("https://buy.ubuntu.com/")

    products = {pr["id"]: pr for pr in listings_response["products"]}
    listings = []
    for listing in product_listings:
        if "price" not in listing:
            continue
        listing["product"] = products[listing["productID"]]
        listings.append(listing)

    return flask.render_template(
        "advantage/subscribe/index.html",
        account=account,
        previous_purchase_id=previous_purchase_id,
        product_listings=listings,
        stripe_publishable_key=stripe_publishable_key,
        is_test_backend=is_test_backend,
    )
Пример #25
0
def post_advantage_subscriptions(preview, **kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    token_type = kwargs.get("token_type")
    account_id = kwargs.get("account_id")
    previous_purchase_id = kwargs.get("previous_purchase_id")
    period = kwargs.get("period")
    products = kwargs.get("products")
    resizing = kwargs.get("resizing", False)

    advantage = UAContractsAPI(
        session, token, token_type=token_type, api_url=api_url
    )

    current_subscription = {}
    if user_info(flask.session):
        subscriptions = advantage.get_account_subscriptions(
            account_id=account_id,
            marketplace="canonical-ua",
            filters={"status": "active"},
        )

        for subscription in subscriptions:
            if subscription["subscription"]["period"] == period:
                current_subscription = subscription

    # If there is a subscription we get the current metric
    # value for each product listing so we can generate a
    # purchase request with updated quantities later.
    # If we resize we want to override the existing value
    subscribed_quantities = {}
    if not resizing and current_subscription:
        for item in current_subscription["purchasedProductListings"]:
            product_listing_id = item["productListing"]["id"]
            subscribed_quantities[product_listing_id] = item["value"]

    purchase_items = []
    for product in products:
        product_listing_id = product["product_listing_id"]
        metric_value = product["quantity"] + subscribed_quantities.get(
            product_listing_id, 0
        )

        purchase_items.append(
            {
                "productListingID": product_listing_id,
                "metric": "active-machines",
                "value": metric_value,
            }
        )

    purchase_request = {
        "accountID": account_id,
        "purchaseItems": purchase_items,
        "previousPurchaseID": previous_purchase_id,
    }

    try:
        if not preview:
            purchase = advantage.purchase_from_marketplace(
                marketplace="canonical-ua", purchase_request=purchase_request
            )
        else:
            purchase = advantage.preview_purchase_from_marketplace(
                marketplace="canonical-ua", purchase_request=purchase_request
            )
    except CannotCancelLastContractError as error:
        raise UAContractsAPIError(error)

    return flask.jsonify(purchase), 200
Пример #26
0
def cube_microcerts():
    assertions = {}
    enrollments = []
    passed_courses = 0

    sso_user = user_info(flask.session)

    edx_url = (f"{edx_api.base_url}/auth/login/tpa-saml/"
               "?auth_entry=login&idp=ubuntuone&next=")

    edx_user = edx_api.get_user(sso_user["email"]) if sso_user else None
    if edx_user:
        assertions = {
            assertion["badgeclass"]: assertion
            for assertion in badgr_api.get_assertions(
                CUBE_CONTENT["badgr-issuer"], edx_user["email"])["result"]
        }

        enrollments = [
            enrollment["course_details"]["course_id"]
            for enrollment in edx_api.get_enrollments(edx_user["username"])
            if enrollment["is_active"]
        ]

    certified_badge = {}
    if CUBE_CONTENT["certified-badge"] in assertions:
        assertion = assertions.pop(CUBE_CONTENT["certified-badge"])
        if not assertion["revoked"]:
            certified_badge["image"] = assertion["image"]
            certified_badge["share_url"] = assertion["openBadgeId"]

    study_labs = CUBE_CONTENT["study-labs"]
    courses = copy.deepcopy(CUBE_CONTENT["courses"])
    for course in courses:
        attempts = []

        if edx_user:
            attempts = edx_api.get_course_attempts(
                course["id"], edx_user["username"])["proctored_exam_attempts"]

        assertion = assertions.get(course["badge"]["class"])
        course["status"] = "not-enrolled"
        if assertion and not assertion["revoked"]:
            course["badge"]["url"] = assertion["image"]
            course["status"] = "passed"
            passed_courses += 1
        elif attempts:
            course["status"] = ("in-progress" if
                                not attempts[0]["completed_at"] else "failed")
        elif course["id"] in enrollments:
            course["status"] = "enrolled"

        course_id = course["id"]
        courseware_name = course_id.split("+")[1]

        course["take_url"] = edx_url + quote_plus(
            f"/courses/{course_id}/courseware/2020/start/?child=first")

        course["study_lab"] = edx_url + quote_plus(
            f"/courses/{study_labs}/courseware/{courseware_name}/?child=first")

    study_labs_url = edx_url + quote_plus(f"/courses/{study_labs}/course/")

    return flask.render_template(
        "cube/microcerts.html",
        **{
            "edx_user": edx_user,
            "edx_register_url": f"{edx_url}%2F",
            "sso_user": sso_user,
            "certified_badge": certified_badge,
            "modules": courses,
            "passed_courses": passed_courses,
            "has_enrollments": len(enrollments) > 0,
            "has_study_labs": study_labs in enrollments,
            "study_labs_url": study_labs_url,
        },
    )
Пример #27
0
def advantage_shop_view(**kwargs):
    is_test_backend = kwargs.get("test_backend")
    api_url = kwargs.get("api_url")
    stripe_publishable_key = kwargs.get("stripe_publishable_key")
    token = kwargs.get("token")

    account = None
    previous_purchase_ids = {"monthly": "", "yearly": ""}
    advantage = UAContractsAPI(
        session, None, api_url=api_url, is_for_view=True
    )

    if user_info(flask.session):
        advantage = UAContractsAPI(
            session, token, api_url=api_url, is_for_view=True
        )

        if flask.session.get("guest_authentication_token"):
            flask.session.pop("guest_authentication_token")

        try:
            account = advantage.get_purchase_account()
        except UAContractsUserHasNoAccount:
            # There is no purchase account yet for this user.
            # One will need to be created later, but this is an expected
            # condition.

            pass

        if account:
            subscriptions = advantage.get_account_subscriptions(
                account_id=account["id"],
                marketplace="canonical-ua",
                filters={"status": "active"},
            )

            for subscription in subscriptions:
                period = subscription["subscription"]["period"]
                previous_purchase_ids[period] = subscription["lastPurchaseID"]

    listings = advantage.get_product_listings("canonical-ua")
    product_listings = listings.get("productListings")
    if not product_listings:
        # For the time being, no product listings means the shop has not been
        # activated, so fallback to shopify. This should become an error later.
        return flask.redirect("https://buy.ubuntu.com/")

    products = {product["id"]: product for product in listings["products"]}

    website_listing = []
    for listing in product_listings:
        if "price" not in listing:
            continue

        listing["product"] = products[listing["productID"]]

        website_listing.append(listing)

    return flask.render_template(
        "advantage/subscribe/index.html",
        is_test_backend=is_test_backend,
        stripe_publishable_key=stripe_publishable_key,
        account=account,
        previous_purchase_ids=previous_purchase_ids,
        product_listings=website_listing,
    )
Пример #28
0
def cube_microcerts():
    assertions = {}
    enrollments = []
    passed_courses = 0

    sso_user = user_info(flask.session)
    if not is_authorized(sso_user):
        flask.abort(403)

    edx_user = edx_api.get_user(sso_user["email"]) if sso_user else None
    if edx_user:
        assertions = {
            assertion["badgeclass"]: assertion
            for assertion in badgr_api.get_assertions(
                CUBE_CONTENT["badgr-issuer"], edx_user["email"])["result"]
        }

        enrollments = [
            enrollment["course_details"]["course_id"]
            for enrollment in edx_api.get_enrollments(edx_user["username"])
            if enrollment["is_active"]
        ]

    certified_badge = {}
    if CUBE_CONTENT["certified-badge"] in assertions:
        assertion = assertions.pop(CUBE_CONTENT["certified-badge"])
        if not assertion["revoked"]:
            certified_badge["image"] = assertion["image"]
            certified_badge["share_url"] = assertion["openBadgeId"]

    courses = copy.deepcopy(CUBE_CONTENT["courses"])
    for course in courses:
        attempts = []

        if edx_user:
            attempts = edx_api.get_course_attempts(
                course["id"], edx_user["username"])["proctored_exam_attempts"]

        assertion = assertions.get(course["badge"]["class"])
        course["status"] = "not-enrolled"
        if assertion and not assertion["revoked"]:
            course["badge"]["url"] = assertion["image"]
            course["status"] = "passed"
            passed_courses += 1
        elif attempts:
            course["status"] = ("in-progress" if
                                not attempts[0]["completed_at"] else "failed")
        elif course["id"] in enrollments:
            course["status"] = "enrolled"

        course["take_url"] = (f"{edx_api.base_url}/courses/{course['id']}"
                              "/courseware/2020/start/?child=first")

        course["prepare_url"] = (f"{edx_api.base_url}/courses/"
                                 f"{CUBE_CONTENT['prepare-course']}/course/")

    has_prepare_material = CUBE_CONTENT["prepare-course"] in enrollments
    prepare_material_url = (
        f"{edx_api.base_url}/courses/{CUBE_CONTENT['prepare-course']}/course/")

    return flask.render_template(
        "cube/microcerts.html",
        **{
            "user": sso_user,
            "certified_badge": certified_badge,
            "modules": courses,
            "passed_courses": passed_courses,
            "has_enrollments": len(enrollments) > 0,
            "has_prepare_material": has_prepare_material,
            "prepare_material_url": prepare_material_url,
        },
    )
Пример #29
0
def post_advantage_subscriptions(preview):
    is_test_backend = flask.request.args.get("test_backend", False)

    api_url = flask.current_app.config["CONTRACTS_LIVE_API_URL"]

    if is_test_backend:
        api_url = flask.current_app.config["CONTRACTS_TEST_API_URL"]

    user_token = flask.session.get("authentication_token")
    guest_token = flask.session.get("guest_authentication_token")

    if user_info(flask.session) or guest_token:
        advantage = AdvantageContracts(
            session,
            user_token or guest_token,
            token_type=("Macaroon" if user_token else "Bearer"),
            api_url=api_url,
        )
    else:
        return flask.jsonify({"error": "authentication required"}), 401

    payload = flask.request.json
    if not payload:
        return flask.jsonify({}), 400

    account_id = payload.get("account_id")
    previous_purchase_id = payload.get("previous_purchase_id")
    last_subscription = {}

    if not guest_token:
        try:
            subscriptions = (
                advantage.get_account_subscriptions_for_marketplace(
                    account_id=account_id, marketplace="canonical-ua"))
        except HTTPError:
            flask.current_app.extensions["sentry"].captureException(
                extra={"payload": payload})
            return (
                flask.jsonify(
                    {"error": "could not retrieve account subscriptions"}),
                500,
            )

        if subscriptions:
            last_subscription = subscriptions["subscriptions"][0]

    # If there is a subscription we get the current metric
    # value for each product listing so we can generate a
    # purchase request with updated quantities later.
    subscribed_quantities = {}
    if "purchasedProductListings" in last_subscription:
        for item in last_subscription["purchasedProductListings"]:
            product_listing_id = item["productListing"]["id"]
            subscribed_quantities[product_listing_id] = item["value"]

    purchase_items = []
    for product in payload.get("products"):
        product_listing_id = product["product_listing_id"]
        metric_value = product["quantity"] + subscribed_quantities.get(
            product_listing_id, 0)

        purchase_items.append({
            "productListingID": product_listing_id,
            "metric": "active-machines",
            "value": metric_value,
        })

    purchase_request = {
        "accountID": account_id,
        "purchaseItems": purchase_items,
        "previousPurchaseID": previous_purchase_id,
    }

    try:
        if not preview:
            purchase = advantage.purchase_from_marketplace(
                marketplace="canonical-ua", purchase_request=purchase_request)
        else:
            purchase = advantage.preview_purchase_from_marketplace(
                marketplace="canonical-ua", purchase_request=purchase_request)
    except HTTPError as http_error:
        flask.current_app.extensions["sentry"].captureException(
            extra={
                "purchase_request": purchase_request,
                "api_response": http_error.response.json(),
            })
        return (
            flask.jsonify({"error": "could not complete this purchase"}),
            500,
        )

    return flask.jsonify(purchase), 200
Пример #30
0
def cube_home():
    sso_user = user_info(flask.session)
    if not is_authorized(sso_user):
        flask.abort(403)

    return flask.render_template("cube/index.html")