Exemplo n.º 1
0
def test_error_and_data():
    with pytest.raises(AttributeError):
        doc = {
            "data": {
                "$type": "article"
            },
            "errors": {
                "status": 200
            }
        }
        json_api_doc.serialize(**doc)
Exemplo n.º 2
0
def test_serialize_object_list():
    data = [{
        "$type": "article",
        "id": "1",
        "title": "Article 1"
    }, {
        "$type": "article",
        "id": "2",
        "title": "Article 2"
    }]

    doc = json_api_doc.serialize(data)
    assert doc == {
        "data": [{
            "type": "article",
            "id": "1",
            "attributes": {
                "title": "Article 1"
            }
        }, {
            "type": "article",
            "id": "2",
            "attributes": {
                "title": "Article 2"
            }
        }]
    }
Exemplo n.º 3
0
def test_serialize_object_embedded():
    data = {
        "$type": "article",
        "id": "1",
        "title": "Article 1",
        "author": {
            "$type": "people",
            "id": "9",
            "name": "Bob"
        }
    }
    doc = json_api_doc.serialize(data)
    assert doc == {
        "data": {
            "type": "article",
            "id": "1",
            "attributes": {
                "title": "Article 1"
            },
            "relationships": {
                "author": {
                    "data": {"type": "people", "id": "9"}
                }
            }
        },
        "included": [{
            "type": "people",
            "id": "9",
            "attributes": {
                "name": "Bob",
            }
        }]
    }
Exemplo n.º 4
0
def test_serialize_object_embedded_json():
    data = {
        "$type": "article",
        "id": "1",
        "title": "Article 1",
        "author": {
            "$type": "people",
            "id": "100"
        },
        "inner": {
            "value": "embedded regular JSON"
        },
        "innerArray": [
            "embedded", "regular", "JSON", "array"
        ],
        "innerObjectArray": [
            {
                "value": "something"
            }, {
                "value": "something_else"
            }
        ]
    }
    doc = json_api_doc.serialize(data)
    assert doc == {
        "data": {
            "type": "article",
            "id": "1",
            "attributes": {
                "title": "Article 1",
                "inner": {
                    "value": "embedded regular JSON"
                },
                "innerArray": [
                    "embedded", "regular", "JSON", "array"
                ],
                "innerObjectArray": [
                    {
                        "value": "something"
                    }, {
                        "value": "something_else"
                    }
                ]
            },
            "relationships": {
                "author": {
                    "data": {
                        "type": "people",
                        "id": "100"
                    }
                }
            }
        },
        "included": [{
            "type": "people",
            "id": "100"
        }]
    }
Exemplo n.º 5
0
def execute(plan_id, app_filter, username, password, env):
    billing_api = config.get_billing_endpoint(env)
    plan_res = network.get(
        *auth.as_admin(env, "{}/v1/plans/{}".format(billing_api, plan_id)))
    plan = json_api_doc.deserialize(plan_res.json())

    if "errors" in plan:
        print(plan["errors"][0]["detail"])
        exit(1)

    print("[{}] Adding plan {} ({} months)".format(env, plan["name"],
                                                   plan["period"]["length"]))

    # get all applications for the provided owner(username, password)
    apps_endpoint = config.get_apps_endpoint(env) + "/v1/apps"
    apps_res = network.get(
        *auth.as_user(username, password, env, apps_endpoint,
                      {"query": {
                          "page[limit]": 99999999
                      }}))
    apps = json_api_doc.deserialize(apps_res.json())

    # filter apps out by those that match the provided regex
    app_re = re.compile(app_filter)
    filtered = list(filter(lambda app: app_re.match(app["name"]), apps))

    apps_name_id = os.linesep.join(
        map(lambda app: "{} ({})".format(app["name"], app["id"]), filtered))
    print("Plan {} will be purchased for following apps: {}{}".format(
        plan_id, os.linesep, apps_name_id))
    if not prompt.yes_no("Do you want to continue?"):
        exit(0)

    for app in filtered:
        purchase_plan_endpoint = "{}/v1/accounts/me/subscriptions/application:{}/actions/recurly/subscribe".format(
            billing_api, app["id"])
        purchase_res = network.post(*auth.as_user(
            username, password, env, purchase_plan_endpoint, {
                "body":
                json_api_doc.serialize(
                    data={
                        "$type": "shoutem.billing.recurly-subscribe-actions",
                        "billingInfoToken": None,
                        "plan": {
                            "$type": "shoutem.billing.plans",
                            "id": plan_id
                        }
                    })
            }))

        purchase = json_api_doc.deserialize(purchase_res.json())

        if "errors" in purchase:
            print(purchase["errors"][0]["detail"]
                  or purchase["errors"][0]["code"])
        else:
            print("Plan purchased for {}".format(app["id"]))
Exemplo n.º 6
0
def test_serialize_object_without_attributes():
    data = {
        "$type": "article",
        "id": "1"
    }
    doc = json_api_doc.serialize(data)
    assert doc == {
        "data": {
            "type": "article",
            "id": "1"
        }
    }
Exemplo n.º 7
0
def test_serialize_meta():
    meta = {
        "some": "random",
        "silly": "data"
    }
    doc = json_api_doc.serialize(meta=meta)
    assert doc == {
        "meta": {
            "some": "random",
            "silly": "data"
        }
    }
Exemplo n.º 8
0
def test_serialize_object():
    data = {"$type": "article", "id": "1", "title": "Article 1"}
    doc = json_api_doc.serialize(data)
    assert doc == {
        "data": {
            "type": "article",
            "id": "1",
            "attributes": {
                "title": "Article 1"
            }
        }
    }
Exemplo n.º 9
0
def test_serialize_errors():
    errors = {
        "some": "random",
        "silly": "data"
    }
    doc = json_api_doc.serialize(errors=errors)
    assert doc == {
        "errors": {
            "some": "random",
            "silly": "data"
        }
    }
Exemplo n.º 10
0
def test_serialize_object_embedded_list():
    data = {
        "$type":
        "article",
        "id":
        "1",
        "title":
        "Article 1",
        "comments": [{
            "$type": "comment",
            "id": "100",
            "content": "First"
        }, {
            "$type": "comment",
            "id": "101",
            "content": "Second"
        }]
    }
    doc = json_api_doc.serialize(data)
    assert doc == {
        "data": {
            "type": "article",
            "id": "1",
            "attributes": {
                "title": "Article 1"
            },
            "relationships": {
                "comments": {
                    "data": [{
                        "type": "comment",
                        "id": "100"
                    }, {
                        "type": "comment",
                        "id": "101"
                    }]
                }
            }
        },
        "included": [{
            "type": "comment",
            "id": "100",
            "attributes": {
                "content": "First",
            }
        }, {
            "type": "comment",
            "id": "101",
            "attributes": {
                "content": "Second",
            }
        }]
    }
Exemplo n.º 11
0
def _load_user_token(username, password, env, realm):
    realm_part = "realms/externalReference:{}/".format(
        realm) if realm != 0 else ""

    token_endpoint = "{}/v1/{}tokens".format(config.get_auth_endpoint(env),
                                             realm_part)
    creds = base64.b64encode("{}:{}".format(
        username, password).encode("UTF-8")).decode("UTF-8")
    refresh_response = network.post(
        token_endpoint, {
            "headers": {
                "Authorization": "Basic {}".format(creds)
            },
            "body": json_api_doc.serialize({"$type": "shoutem.auth.tokens"})
        })

    parsed_refresh = json_api_doc.deserialize(refresh_response.json())
    errors.exit_if_errors(parsed_refresh)

    access_response = network.post(
        token_endpoint, {
            "headers": {
                "Authorization": "Bearer {}".format(parsed_refresh["token"])
            },
            "body":
            json_api_doc.serialize({
                "$type": "shoutem.auth.tokens",
                "tokenType": "access-token",
                "subjectType": "user",
                "compressionType": "gzip"
            })
        })

    access_parsed = json_api_doc.deserialize(access_response.json())
    errors.exit_if_errors(access_parsed)

    tokens[(username, env)] = access_parsed["token"]
Exemplo n.º 12
0
def execute(username, password, name, count, env):
    print("[{}] Creating {} new app(s) for user {}".format(
        env, count, username))
    if not prompt.yes_no("Do you want to continue?"):
        exit(0)

    # create new apps by cloning the base app
    endpoint = config.get_apps_endpoint(env) + "/v1/apps/base/actions/clone"
    for i in range(count):
        app_name = "{} {}".format(name, i + 1) if count > 1 else name
        body = json_api_doc.serialize({
            "$type": "shoutem.core.application-clones",
            "name": app_name,
            "alias": "base"
        })

        res = network.post(
            *auth.as_user(username, password, env, endpoint, {"body": body}))
        res_parsed = json_api_doc.deserialize(res.json())
        print(res_parsed["id"])
Exemplo n.º 13
0
def test_serialize_links():
    links = {
        "some": "random",
        "silly": {
            "href": "random",
            "meta": {
                "silly": "data"
            }
        }
    }
    doc = json_api_doc.serialize(links=links)
    assert doc == {
        "links": {
            "some": "random",
            "silly": {
                "href": "random",
                "meta": {
                    "silly": "data"
                }
            }
        }
    }
Exemplo n.º 14
0
def test_invalid():
    with pytest.raises(AttributeError):
        json_api_doc.serialize({"a": 1})
Exemplo n.º 15
0
def test_serialize_empty_list():
    doc = json_api_doc.serialize([])
    assert doc == {
        "data": []
    }
Exemplo n.º 16
0
def execute(src_id, dest_id, app_filter, recreate_subscription, plan_override,
            env):
    users_endpoint = config.get_auth_endpoint(
        env) + "/v1/realms/alias:default/users/legacyUser:{}"
    # get source and destination users, mostly for the sake of ensuring user inputed the right data
    src_user_res = network.get(
        *auth.as_admin(env, users_endpoint.format(src_id)))
    src_user = json_api_doc.deserialize(src_user_res.json())
    errors.exit_if_errors(src_user)

    dest_user_res = network.get(
        *auth.as_admin(env, users_endpoint.format(dest_id)))
    dest_user = json_api_doc.deserialize(dest_user_res.json())
    errors.exit_if_errors(dest_user)

    print("[{}] Transfering apps from {} to {}".format(env,
                                                       src_user["username"],
                                                       dest_user["username"]))

    # get all applications for the source user
    apps_endpoint = config.get_legacy_endpoint(env) + "/v1/apps"
    apps_res = network.get(*auth.as_admin(
        env, apps_endpoint,
        {"query": {
            "filter[owner.id]": src_id,
            "page[limit]": 99999999
        }}))
    apps = json_api_doc.deserialize(apps_res.json())
    errors.exit_if_errors(apps)

    account_endpoint = config.get_billing_endpoint(
        env) + "/v1/accounts/user:{}"
    src_account_res = network.get(
        *auth.as_admin(env, account_endpoint.format(src_id)))
    src_account = json_api_doc.deserialize(src_account_res.json())
    errors.exit_if_errors(src_account)

    dest_account_res = network.get(
        *auth.as_admin(env, account_endpoint.format(dest_id)))
    dest_account = json_api_doc.deserialize(dest_account_res.json())
    errors.exit_if_errors(dest_account)

    # we don't support different account types because it's too complicated, man
    if src_account["accountType"] != dest_account["accountType"]:
        print("Source and destination account must have the same account type")
        exit(1)

    # some accounts have old application subnscription groups which could cause confusion
    if src_account["applicationPlanGroup"] != dest_account[
            "applicationPlanGroup"]:
        print(
            "Source and destination account must have the same application plan group"
        )
        exit(1)

    subscription_endpoint = config.get_billing_endpoint(
        env) + "/v1/accounts/user:{}/subscriptions"
    src_subscriptions_res = network.get(
        *auth.as_admin(env, subscription_endpoint.format(src_id)))
    src_subscriptions = json_api_doc.deserialize(src_subscriptions_res.json())
    errors.exit_if_errors(src_subscriptions)

    # filter apps out by those that match the provided regex
    app_re = re.compile(app_filter)
    filtered = list(filter(lambda app: app_re.match(app["name"]), apps))

    apps_name_id = os.linesep.join(
        map(lambda app: "{} ({})".format(app["name"], app["id"]), filtered))
    print("Apps from user {} will be transfered to user {}: {}{}".format(
        src_user["username"], dest_user["username"], os.linesep, apps_name_id))
    if not prompt.yes_no("Do you want to continue?"):
        exit(0)

    # we only consider application subscription, agency transfer is not supported, just their apps
    is_valid_subscription = lambda sub, app: (sub[
        "productType"] == "application" and sub["productId"] == app["id"] and
                                              sub["status"] == "subscribed")
    subscribe_endpoint = config.get_billing_endpoint(
        env
    ) + "/v1/accounts/{}/subscriptions/application:{}/actions/recurly/subscribe"
    unsubscribe_endpoint = config.get_billing_endpoint(
        env) + "/v1/accounts/{}/subscriptions/{}/actions/recurly/cancel"
    update_app_endpoint = config.get_legacy_endpoint(env) + "/v1/apps/{}"

    # throttle requests if many apps have to be transfered
    throttle = True if len(filtered) > 10 else False

    for app in filtered:
        existing_subscriptions = list(
            filter(lambda sub: is_valid_subscription(sub, app),
                   src_subscriptions))

        # cancel existing subscription if it exists, we can recreate it later
        # hopefully the app owner thansfer step bellow won't fail
        if existing_subscriptions:
            subscription = existing_subscriptions[0]
            unsubscribe_res = network.post(*auth.as_admin(
                env,
                unsubscribe_endpoint.format(
                    src_account["id"], subscription["id"]), {
                        "body":
                        json_api_doc.serialize(
                            {"$type": "shoutem.billing.subscriptions"})
                    }))
            canceled_subscriptions = json_api_doc.deserialize(
                unsubscribe_res.json())
            errors.exit_if_errors(canceled_subscriptions)
            print("[{}] Canceled subscription for app {} ({})".format(
                env, app["id"], app["name"]))

        # .NET fails to parse included data in POST body, so we create JSON:API doc manually here
        # NodeJS services do not have this issue
        update_app_res = network.patch(*auth.as_admin(
            env, update_app_endpoint.format(app["id"]), {
                "body": {
                    'data': {
                        'type': 'shoutem.core.application',
                        'relationships': {
                            'owner': {
                                'data': {
                                    'id': dest_user["legacyId"],
                                    'type': 'shoutem.core.users'
                                }
                            }
                        }
                    }
                }
            }))
        update_app = json_api_doc.deserialize(update_app_res.json())
        errors.exit_if_errors(update_app)
        print("[{}] Changed owner for app {} ({}) to {}".format(
            env, app["id"], app["name"], dest_user["username"]))

        # create a new subscription if user specified so and the previous owner had a subscription
        # this will cause new invoice on the new account, this probably won't be an issue with agencies
        if recreate_subscription and existing_subscriptions:
            subscription = existing_subscriptions[0]
            purchase_plan_id = subscription["plan"][
                "id"] if plan_override == "" else plan_override
            purchase_res = network.post(*auth.as_admin(
                env, subscribe_endpoint.format(dest_account["id"], app["id"]),
                {
                    "body":
                    json_api_doc.serialize({
                        "$type": "shoutem.billing.recurly-subscribe-actions",
                        "billingInfoToken": None,
                        "plan": {
                            "$type": "shoutem.billing.plans",
                            "id": purchase_plan_id
                        }
                    })
                }))

            purchase = json_api_doc.deserialize(purchase_res.json())
            errors.exit_if_errors(purchase)
            print("[{}] Created subscription for app {} ({}) with plan {}".
                  format(env, app["id"], app["name"],
                         subscription["plan"]["id"]))

        if throttle:
            print("Throttling...")
            time.sleep(10)
Exemplo n.º 17
0
def execute(moderator_email, moderator_password, app_filter, username,
            password, env):
    print("[{}] Adding moderator {}".format(env, moderator_email))

    # get the agency for the provided owner
    agency_endpoint = config.get_apps_endpoint(env) + "/v1/agencies/mine"
    agency_res = network.get(
        *auth.as_user(username, password, env, agency_endpoint))
    agency = json_api_doc.deserialize(agency_res.json())
    errors.exit_if_errors(agency)

    # get existing moderators for agency
    moderators_endpoint = config.get_apps_endpoint(env) + "/v1/moderators"
    moderators_res = network.get(*auth.as_user(
        username, password, env, moderators_endpoint,
        {"query": {
            "filter[agency]": agency["id"],
            "page[limit]": 99999999
        }}))
    moderators = json_api_doc.deserialize(moderators_res.json())
    existing_moderator = list(
        filter(lambda mod: mod["user"]["username"] == moderator_email,
               moderators))

    if existing_moderator:
        moderator = existing_moderator[0]
    # ask to create a new moderator for agency if one does not exist already
    elif prompt.yes_no("Moderator does not exist. Do you want to create it?"):
        create_moderator_endpoint = config.get_apps_endpoint(
            env) + "/v1/moderators/actions/create-for-user"
        create_moderator_res = network.post(*auth.as_user(
            username, password, env, create_moderator_endpoint, {
                "body":
                json_api_doc.serialize({
                    "$type": "shoutem.core.moderator-users",
                    "password": moderator_password,
                    "username": moderator_email,
                    "agency": {
                        "$type": "shoutem.core.agencies",
                        "id": agency["id"]
                    }
                })
            }))

        try:
            moderator = json_api_doc.deserialize(create_moderator_res.json())
            errors.exit_if_errors(moderator)
        except AttributeError:
            raise Exception("User with such email/password already exists")
    # exit if no moderators and user refused to create new one
    else:
        exit(0)

    # get all applications for the provided owner(username, password)
    apps_endpoint = config.get_apps_endpoint(env) + "/v1/apps"
    apps_res = network.get(
        *auth.as_user(username, password, env, apps_endpoint,
                      {"query": {
                          "page[limit]": 99999999
                      }}))
    apps = json_api_doc.deserialize(apps_res.json())

    # filter apps out by those that match the provided regex
    app_re = re.compile(app_filter)
    filtered = list(filter(lambda app: app_re.match(app["name"]), apps))

    apps_name_id = os.linesep.join(
        map(lambda app: "{} ({})".format(app["name"], app["id"]), filtered))
    print("Moderator {} will be added to following apps: {}{}".format(
        moderator_email, os.linesep, apps_name_id))
    if not prompt.yes_no("Do you want to continue?"):
        exit(0)

    for app in filtered:
        add_moderator_endpoint = "{}/{}/moderated-applications".format(
            moderators_endpoint, moderator["id"])
        moderator_res = network.post(*auth.as_user(
            username, password, env, add_moderator_endpoint, {
                "body":
                json_api_doc.serialize({
                    "$type": "shoutem.core.moderator-applications",
                    "role": "content-editor",
                    "application": {
                        "$type": "shoutem.core.applications",
                        "id": app["id"]
                    }
                })
            }))

        try:
            json_api_doc.deserialize(moderator_res.json())
            print("Moderator added for {}".format(app["id"]))
        except AttributeError:
            print("Moderator already exists for {}".format(app["id"]))
Exemplo n.º 18
0
def execute(extensions_with_version, app_filter, user, env):
    apps_res = network.get(*auth.as_admin(
        env, "{}/v1/apps/".format(config.get_legacy_endpoint(env)),
        {"query": {
            "filter[owner.id]": user,
        }}))
    apps = json_api_doc.deserialize(apps_res.json())
    errors.exit_if_errors(apps)

    # filter apps out by those that match the provided regex
    app_re = re.compile(app_filter)
    filtered = list(filter(lambda app: app_re.match(app["name"]), apps))

    apps_name_id = os.linesep.join(
        map(lambda app: "{} ({})".format(app["name"], app["id"]), filtered))
    print("[{}] Updating for following apps: {}{}".format(
        env, os.linesep, apps_name_id))
    if not prompt.yes_no("Do you want to continue?"):
        exit(0)

    extension_re = re.compile("(.*)@(.*)")
    extension_name_ids = []
    extensions_endpoint = config.get_extension_endpoint(env)
    for extension in extensions_with_version:
        match_res = extension_re.match(extension)
        if len(match_res.groups()) != 2:
            print("Invalid extension name@version: {}".format(extension))
            exit(1)

        extension_name = match_res.group(1)
        extension_version = match_res.group(2)
        extension_res = network.get(*auth.as_admin(
            env, "{}/v1/extensions".format(extensions_endpoint), {
                "query": {
                    "filter[canonicalName]": extension_name,
                    "filter[version]": extension_version,
                }
            }))
        extensions = json_api_doc.deserialize(extension_res.json())
        errors.exit_if_errors(extensions)

        if len(extensions) == 0:
            print("No extension {}".format(extension))
            exit(1)

        extension_name_ids += [(extension_name, extensions[0]["id"])]

    apps_endpoint = config.get_apps_endpoint(env)
    for app in filtered:
        app_installations_res = network.get(*auth.as_admin(
            env, "{}/v1/apps/{}/installations".format(apps_endpoint,
                                                      app["id"])))
        app_installations = json_api_doc.deserialize(
            app_installations_res.json())
        errors.exit_if_errors(app_installations)

        for extension_name, extension_id in extension_name_ids:
            current_installations = list(
                filter(lambda i: i["canonicalName"] == extension_name,
                       app_installations))
            if len(current_installations) == 0:
                print(
                    "SKIPPING extension installation {} for app {}. {}".format(
                        extension_name, app["id"],
                        "Extension must be installed"))
                continue

            current_installation = current_installations[0]

            update_extension_endpoint = "{}/v1/apps/{}/installations/{}".format(
                apps_endpoint, app["id"], current_installation["id"])
            update_res = network.patch(*auth.as_admin(
                env, update_extension_endpoint, {
                    "body":
                    json_api_doc.serialize(
                        data={
                            "$type": "shoutem.core.installations",
                            "id": current_installation["id"],
                            "extension": extension_id
                        })
                }))

            update_res = json_api_doc.deserialize(update_res.json())
            errors.exit_if_errors(update_res)

            print("Extension installation {} updated for app {}".format(
                extension_name, app["id"]))