diff --git a/platformio/clients/account.py b/platformio/account/client.py similarity index 100% rename from platformio/clients/account.py rename to platformio/account/client.py diff --git a/platformio/account/commands/__init__.py b/platformio/account/commands/__init__.py new file mode 100644 index 00000000..b0514903 --- /dev/null +++ b/platformio/account/commands/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/platformio/account/commands/destroy.py b/platformio/account/commands/destroy.py new file mode 100644 index 00000000..5a4f4dd6 --- /dev/null +++ b/platformio/account/commands/destroy.py @@ -0,0 +1,37 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click + +from platformio.account.client import AccountClient, AccountNotAuthorized + + +@click.command("destroy", short_help="Destroy account") +def account_destroy_cmd(): + client = AccountClient() + click.confirm( + "Are you sure you want to delete the %s user account?\n" + "Warning! All linked data will be permanently removed and can not be restored." + % client.get_logged_username(), + abort=True, + ) + client.destroy_account() + try: + client.logout() + except AccountNotAuthorized: + pass + click.secho( + "User account has been destroyed.", + fg="green", + ) diff --git a/platformio/account/commands/forgot.py b/platformio/account/commands/forgot.py new file mode 100644 index 00000000..4af8f5fa --- /dev/null +++ b/platformio/account/commands/forgot.py @@ -0,0 +1,29 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click + +from platformio.account.client import AccountClient + + +@click.command("forgot", short_help="Forgot password") +@click.option("--username", prompt="Username or email") +def account_forgot_cmd(username): + client = AccountClient() + client.forgot_password(username) + click.secho( + "If this account is registered, we will send the " + "further instructions to your email.", + fg="green", + ) diff --git a/platformio/account/commands/login.py b/platformio/account/commands/login.py new file mode 100644 index 00000000..b9471bfd --- /dev/null +++ b/platformio/account/commands/login.py @@ -0,0 +1,26 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click + +from platformio.account.client import AccountClient + + +@click.command("login", short_help="Log in to PlatformIO Account") +@click.option("-u", "--username", prompt="Username or email") +@click.option("-p", "--password", prompt=True, hide_input=True) +def account_login_cmd(username, password): + client = AccountClient() + client.login(username, password) + click.secho("Successfully logged in!", fg="green") diff --git a/platformio/account/commands/logout.py b/platformio/account/commands/logout.py new file mode 100644 index 00000000..243a7f14 --- /dev/null +++ b/platformio/account/commands/logout.py @@ -0,0 +1,24 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click + +from platformio.account.client import AccountClient + + +@click.command("logout", short_help="Log out of PlatformIO Account") +def account_logout_cmd(): + client = AccountClient() + client.logout() + click.secho("Successfully logged out!", fg="green") diff --git a/platformio/account/commands/password.py b/platformio/account/commands/password.py new file mode 100644 index 00000000..4f129c08 --- /dev/null +++ b/platformio/account/commands/password.py @@ -0,0 +1,26 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click + +from platformio.account.client import AccountClient + + +@click.command("password", short_help="Change password") +@click.option("--old-password", prompt=True, hide_input=True) +@click.option("--new-password", prompt=True, hide_input=True, confirmation_prompt=True) +def account_password_cmd(old_password, new_password): + client = AccountClient() + client.change_password(old_password, new_password) + click.secho("Password successfully changed!", fg="green") diff --git a/platformio/account/commands/register.py b/platformio/account/commands/register.py new file mode 100644 index 00000000..b5ec532d --- /dev/null +++ b/platformio/account/commands/register.py @@ -0,0 +1,52 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click + +from platformio.account.client import AccountClient +from platformio.account.helpers import ( + validate_email, + validate_password, + validate_username, +) + + +@click.command("register", short_help="Create new PlatformIO Account") +@click.option( + "-u", + "--username", + prompt=True, + callback=lambda _, __, value: validate_username(value), +) +@click.option( + "-e", "--email", prompt=True, callback=lambda _, __, value: validate_email(value) +) +@click.option( + "-p", + "--password", + prompt=True, + hide_input=True, + confirmation_prompt=True, + callback=lambda _, __, value: validate_password(value), +) +@click.option("--firstname", prompt=True) +@click.option("--lastname", prompt=True) +def account_register_cmd(username, email, password, firstname, lastname): + client = AccountClient() + client.registration(username, email, password, firstname, lastname) + click.secho( + "An account has been successfully created. " + "Please check your mail to activate your account and verify your email address.", + fg="green", + ) diff --git a/platformio/account/commands/show.py b/platformio/account/commands/show.py new file mode 100644 index 00000000..f107f4f5 --- /dev/null +++ b/platformio/account/commands/show.py @@ -0,0 +1,116 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json + +import click +from tabulate import tabulate + +from platformio import util +from platformio.account.client import AccountClient + + +@click.command("show", short_help="PlatformIO Account information") +@click.option("--offline", is_flag=True) +@click.option("--json-output", is_flag=True) +def account_show_cmd(offline, json_output): + client = AccountClient() + info = client.get_account_info(offline) + if json_output: + click.echo(json.dumps(info)) + return + click.echo() + if info.get("profile"): + print_profile(info["profile"]) + if info.get("packages"): + print_packages(info["packages"]) + if info.get("subscriptions"): + print_subscriptions(info["subscriptions"]) + click.echo() + + +def print_profile(profile): + click.secho("Profile", fg="cyan", bold=True) + click.echo("=" * len("Profile")) + data = [] + if profile.get("username"): + data.append(("Username:", profile["username"])) + if profile.get("email"): + data.append(("Email:", profile["email"])) + if profile.get("firstname"): + data.append(("First name:", profile["firstname"])) + if profile.get("lastname"): + data.append(("Last name:", profile["lastname"])) + click.echo(tabulate(data, tablefmt="plain")) + + +def print_packages(packages): + click.echo() + click.secho("Packages", fg="cyan") + click.echo("=" * len("Packages")) + for package in packages: + click.echo() + click.secho(package.get("name"), bold=True) + click.echo("-" * len(package.get("name"))) + if package.get("description"): + click.echo(package.get("description")) + data = [] + expire = "-" + if "subscription" in package: + expire = util.parse_datetime( + package["subscription"].get("end_at") + or package["subscription"].get("next_bill_at") + ).strftime("%Y-%m-%d") + data.append(("Expire:", expire)) + services = [] + for key in package: + if not key.startswith("service."): + continue + if isinstance(package[key], dict): + services.append(package[key].get("title")) + else: + services.append(package[key]) + if services: + data.append(("Services:", ", ".join(services))) + click.echo(tabulate(data, tablefmt="plain")) + + +def print_subscriptions(subscriptions): + click.echo() + click.secho("Subscriptions", fg="cyan") + click.echo("=" * len("Subscriptions")) + for subscription in subscriptions: + click.echo() + click.secho(subscription.get("product_name"), bold=True) + click.echo("-" * len(subscription.get("product_name"))) + data = [("State:", subscription.get("status"))] + begin_at = util.parse_datetime(subscription.get("begin_at")).strftime("%c") + data.append(("Start date:", begin_at or "-")) + end_at = subscription.get("end_at") + if end_at: + end_at = util.parse_datetime(subscription.get("end_at")).strftime("%c") + data.append(("End date:", end_at or "-")) + next_bill_at = subscription.get("next_bill_at") + if next_bill_at: + next_bill_at = util.parse_datetime( + subscription.get("next_bill_at") + ).strftime("%c") + data.append(("Next payment:", next_bill_at or "-")) + data.append( + ("Edit:", click.style(subscription.get("update_url"), fg="blue") or "-") + ) + data.append( + ("Cancel:", click.style(subscription.get("cancel_url"), fg="blue") or "-") + ) + click.echo(tabulate(data, tablefmt="plain")) diff --git a/platformio/account/commands/token.py b/platformio/account/commands/token.py new file mode 100644 index 00000000..0f06e367 --- /dev/null +++ b/platformio/account/commands/token.py @@ -0,0 +1,32 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json + +import click + +from platformio.account.client import AccountClient + + +@click.command("token", short_help="Get or regenerate Authentication Token") +@click.option("-p", "--password", prompt=True, hide_input=True) +@click.option("--regenerate", is_flag=True) +@click.option("--json-output", is_flag=True) +def account_token_cmd(password, regenerate, json_output): + client = AccountClient() + auth_token = client.auth_token(password, regenerate) + if json_output: + click.echo(json.dumps({"status": "success", "result": auth_token})) + return + click.secho("Personal Authentication Token: %s" % auth_token, fg="green") diff --git a/platformio/account/commands/update.py b/platformio/account/commands/update.py new file mode 100644 index 00000000..e198867d --- /dev/null +++ b/platformio/account/commands/update.py @@ -0,0 +1,59 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click + +from platformio.account.client import AccountClient, AccountNotAuthorized +from platformio.account.helpers import validate_email, validate_username + + +@click.command("update", short_help="Update profile information") +@click.option("--current-password", prompt=True, hide_input=True) +@click.option("--username") +@click.option("--email") +@click.option("--firstname") +@click.option("--lastname") +def account_update_cmd(current_password, **kwargs): + client = AccountClient() + profile = client.get_profile() + new_profile = profile.copy() + if not any(kwargs.values()): + for field in profile: + new_profile[field] = click.prompt( + field.replace("_", " ").capitalize(), default=profile[field] + ) + if field == "email": + validate_email(new_profile[field]) + if field == "username": + validate_username(new_profile[field]) + else: + new_profile.update({key: value for key, value in kwargs.items() if value}) + client.update_profile(new_profile, current_password) + click.secho("Profile successfully updated!", fg="green") + username_changed = new_profile["username"] != profile["username"] + email_changed = new_profile["email"] != profile["email"] + if not username_changed and not email_changed: + return None + try: + client.logout() + except AccountNotAuthorized: + pass + if email_changed: + click.secho( + "Please check your mail to verify your new email address and re-login. ", + fg="yellow", + ) + return None + click.secho("Please re-login.", fg="yellow") + return None diff --git a/platformio/account/helpers.py b/platformio/account/helpers.py new file mode 100644 index 00000000..adf9413e --- /dev/null +++ b/platformio/account/helpers.py @@ -0,0 +1,48 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re + +import click + + +def validate_username(value, field="username"): + value = str(value).strip() + if not re.match(r"^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,37}$", value, flags=re.I): + raise click.BadParameter( + "Invalid %s format. " + "%s must contain only alphanumeric characters " + "or single hyphens, cannot begin or end with a hyphen, " + "and must not be longer than 38 characters." + % (field.lower(), field.capitalize()) + ) + return value + + +def validate_email(value): + value = str(value).strip() + if not re.match(r"^[a-z\d_.+-]+@[a-z\d\-]+\.[a-z\d\-.]+$", value, flags=re.I): + raise click.BadParameter("Invalid email address") + return value + + +def validate_password(value): + value = str(value).strip() + if not re.match(r"^(?=.*[a-z])(?=.*\d).{8,}$", value): + raise click.BadParameter( + "Invalid password format. " + "Password must contain at least 8 characters" + " including a number and a lowercase letter" + ) + return value diff --git a/platformio/commands/access.py b/platformio/commands/access.py index ccd4150a..6337c0f4 100644 --- a/platformio/commands/access.py +++ b/platformio/commands/access.py @@ -20,7 +20,7 @@ import re import click from tabulate import tabulate -from platformio.commands.account import validate_username +from platformio.account.helpers import validate_username from platformio.commands.team import validate_orgname_teamname from platformio.package.registry import RegistryClient diff --git a/platformio/commands/account.py b/platformio/commands/account.py index 6e17fa40..135445d4 100644 --- a/platformio/commands/account.py +++ b/platformio/commands/account.py @@ -12,285 +12,33 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=unused-argument - -import json -import re - import click -from tabulate import tabulate -from platformio import util -from platformio.clients.account import AccountClient, AccountNotAuthorized +from platformio.account.commands.destroy import account_destroy_cmd +from platformio.account.commands.forgot import account_forgot_cmd +from platformio.account.commands.login import account_login_cmd +from platformio.account.commands.logout import account_logout_cmd +from platformio.account.commands.password import account_password_cmd +from platformio.account.commands.register import account_register_cmd +from platformio.account.commands.show import account_show_cmd +from platformio.account.commands.token import account_token_cmd +from platformio.account.commands.update import account_update_cmd -@click.group("account", short_help="Manage PlatformIO account") +@click.group( + "account", + commands=[ + account_destroy_cmd, + account_forgot_cmd, + account_login_cmd, + account_logout_cmd, + account_password_cmd, + account_register_cmd, + account_show_cmd, + account_token_cmd, + account_update_cmd, + ], + short_help="Manage PlatformIO account", +) def cli(): pass - - -def validate_username(value, field="username"): - value = str(value).strip() - if not re.match(r"^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,37}$", value, flags=re.I): - raise click.BadParameter( - "Invalid %s format. " - "%s must contain only alphanumeric characters " - "or single hyphens, cannot begin or end with a hyphen, " - "and must not be longer than 38 characters." - % (field.lower(), field.capitalize()) - ) - return value - - -def validate_email(value): - value = str(value).strip() - if not re.match(r"^[a-z\d_.+-]+@[a-z\d\-]+\.[a-z\d\-.]+$", value, flags=re.I): - raise click.BadParameter("Invalid email address") - return value - - -def validate_password(value): - value = str(value).strip() - if not re.match(r"^(?=.*[a-z])(?=.*\d).{8,}$", value): - raise click.BadParameter( - "Invalid password format. " - "Password must contain at least 8 characters" - " including a number and a lowercase letter" - ) - return value - - -@cli.command("register", short_help="Create new PlatformIO Account") -@click.option( - "-u", - "--username", - prompt=True, - callback=lambda _, __, value: validate_username(value), -) -@click.option( - "-e", "--email", prompt=True, callback=lambda _, __, value: validate_email(value) -) -@click.option( - "-p", - "--password", - prompt=True, - hide_input=True, - confirmation_prompt=True, - callback=lambda _, __, value: validate_password(value), -) -@click.option("--firstname", prompt=True) -@click.option("--lastname", prompt=True) -def account_register(username, email, password, firstname, lastname): - client = AccountClient() - client.registration(username, email, password, firstname, lastname) - click.secho( - "An account has been successfully created. " - "Please check your mail to activate your account and verify your email address.", - fg="green", - ) - - -@cli.command("login", short_help="Log in to PlatformIO Account") -@click.option("-u", "--username", prompt="Username or email") -@click.option("-p", "--password", prompt=True, hide_input=True) -def account_login(username, password): - client = AccountClient() - client.login(username, password) - click.secho("Successfully logged in!", fg="green") - - -@cli.command("logout", short_help="Log out of PlatformIO Account") -def account_logout(): - client = AccountClient() - client.logout() - click.secho("Successfully logged out!", fg="green") - - -@cli.command("password", short_help="Change password") -@click.option("--old-password", prompt=True, hide_input=True) -@click.option("--new-password", prompt=True, hide_input=True, confirmation_prompt=True) -def account_password(old_password, new_password): - client = AccountClient() - client.change_password(old_password, new_password) - click.secho("Password successfully changed!", fg="green") - - -@cli.command("token", short_help="Get or regenerate Authentication Token") -@click.option("-p", "--password", prompt=True, hide_input=True) -@click.option("--regenerate", is_flag=True) -@click.option("--json-output", is_flag=True) -def account_token(password, regenerate, json_output): - client = AccountClient() - auth_token = client.auth_token(password, regenerate) - if json_output: - click.echo(json.dumps({"status": "success", "result": auth_token})) - return - click.secho("Personal Authentication Token: %s" % auth_token, fg="green") - - -@cli.command("forgot", short_help="Forgot password") -@click.option("--username", prompt="Username or email") -def account_forgot(username): - client = AccountClient() - client.forgot_password(username) - click.secho( - "If this account is registered, we will send the " - "further instructions to your email.", - fg="green", - ) - - -@cli.command("update", short_help="Update profile information") -@click.option("--current-password", prompt=True, hide_input=True) -@click.option("--username") -@click.option("--email") -@click.option("--firstname") -@click.option("--lastname") -def account_update(current_password, **kwargs): - client = AccountClient() - profile = client.get_profile() - new_profile = profile.copy() - if not any(kwargs.values()): - for field in profile: - new_profile[field] = click.prompt( - field.replace("_", " ").capitalize(), default=profile[field] - ) - if field == "email": - validate_email(new_profile[field]) - if field == "username": - validate_username(new_profile[field]) - else: - new_profile.update({key: value for key, value in kwargs.items() if value}) - client.update_profile(new_profile, current_password) - click.secho("Profile successfully updated!", fg="green") - username_changed = new_profile["username"] != profile["username"] - email_changed = new_profile["email"] != profile["email"] - if not username_changed and not email_changed: - return None - try: - client.logout() - except AccountNotAuthorized: - pass - if email_changed: - click.secho( - "Please check your mail to verify your new email address and re-login. ", - fg="yellow", - ) - return None - click.secho("Please re-login.", fg="yellow") - return None - - -@cli.command("destroy", short_help="Destroy account") -def account_destroy(): - client = AccountClient() - click.confirm( - "Are you sure you want to delete the %s user account?\n" - "Warning! All linked data will be permanently removed and can not be restored." - % client.get_logged_username(), - abort=True, - ) - client.destroy_account() - try: - client.logout() - except AccountNotAuthorized: - pass - click.secho( - "User account has been destroyed.", - fg="green", - ) - - -@cli.command("show", short_help="PlatformIO Account information") -@click.option("--offline", is_flag=True) -@click.option("--json-output", is_flag=True) -def account_show(offline, json_output): - client = AccountClient() - info = client.get_account_info(offline) - if json_output: - click.echo(json.dumps(info)) - return - click.echo() - if info.get("profile"): - print_profile(info["profile"]) - if info.get("packages"): - print_packages(info["packages"]) - if info.get("subscriptions"): - print_subscriptions(info["subscriptions"]) - click.echo() - - -def print_profile(profile): - click.secho("Profile", fg="cyan", bold=True) - click.echo("=" * len("Profile")) - data = [] - if profile.get("username"): - data.append(("Username:", profile["username"])) - if profile.get("email"): - data.append(("Email:", profile["email"])) - if profile.get("firstname"): - data.append(("First name:", profile["firstname"])) - if profile.get("lastname"): - data.append(("Last name:", profile["lastname"])) - click.echo(tabulate(data, tablefmt="plain")) - - -def print_packages(packages): - click.echo() - click.secho("Packages", fg="cyan") - click.echo("=" * len("Packages")) - for package in packages: - click.echo() - click.secho(package.get("name"), bold=True) - click.echo("-" * len(package.get("name"))) - if package.get("description"): - click.echo(package.get("description")) - data = [] - expire = "-" - if "subscription" in package: - expire = util.parse_datetime( - package["subscription"].get("end_at") - or package["subscription"].get("next_bill_at") - ).strftime("%Y-%m-%d") - data.append(("Expire:", expire)) - services = [] - for key in package: - if not key.startswith("service."): - continue - if isinstance(package[key], dict): - services.append(package[key].get("title")) - else: - services.append(package[key]) - if services: - data.append(("Services:", ", ".join(services))) - click.echo(tabulate(data, tablefmt="plain")) - - -def print_subscriptions(subscriptions): - click.echo() - click.secho("Subscriptions", fg="cyan") - click.echo("=" * len("Subscriptions")) - for subscription in subscriptions: - click.echo() - click.secho(subscription.get("product_name"), bold=True) - click.echo("-" * len(subscription.get("product_name"))) - data = [("State:", subscription.get("status"))] - begin_at = util.parse_datetime(subscription.get("begin_at")).strftime("%c") - data.append(("Start date:", begin_at or "-")) - end_at = subscription.get("end_at") - if end_at: - end_at = util.parse_datetime(subscription.get("end_at")).strftime("%c") - data.append(("End date:", end_at or "-")) - next_bill_at = subscription.get("next_bill_at") - if next_bill_at: - next_bill_at = util.parse_datetime( - subscription.get("next_bill_at") - ).strftime("%c") - data.append(("Next payment:", next_bill_at or "-")) - data.append( - ("Edit:", click.style(subscription.get("update_url"), fg="blue") or "-") - ) - data.append( - ("Cancel:", click.style(subscription.get("cancel_url"), fg="blue") or "-") - ) - click.echo(tabulate(data, tablefmt="plain")) diff --git a/platformio/commands/home/rpc/handlers/account.py b/platformio/commands/home/rpc/handlers/account.py index 5336d600..23777437 100644 --- a/platformio/commands/home/rpc/handlers/account.py +++ b/platformio/commands/home/rpc/handlers/account.py @@ -14,7 +14,7 @@ from ajsonrpc.core import JSONRPC20DispatchException -from platformio.clients.account import AccountClient +from platformio.account.client import AccountClient class AccountRPC: diff --git a/platformio/commands/org.py b/platformio/commands/org.py index 7f003cb0..bd569e76 100644 --- a/platformio/commands/org.py +++ b/platformio/commands/org.py @@ -19,8 +19,8 @@ import json import click from tabulate import tabulate -from platformio.clients.account import AccountClient -from platformio.commands.account import validate_email, validate_username +from platformio.account.client import AccountClient +from platformio.account.helpers import validate_email, validate_username @click.group("org", short_help="Manage organizations") diff --git a/platformio/commands/remote/factory/client.py b/platformio/commands/remote/factory/client.py index 712449d5..2565e6ad 100644 --- a/platformio/commands/remote/factory/client.py +++ b/platformio/commands/remote/factory/client.py @@ -16,8 +16,8 @@ from twisted.cred import credentials # pylint: disable=import-error from twisted.internet import defer, protocol, reactor # pylint: disable=import-error from twisted.spread import pb # pylint: disable=import-error +from platformio.account.client import AccountClient from platformio.app import get_host_id -from platformio.clients.account import AccountClient class RemoteClientFactory(pb.PBClientFactory, protocol.ReconnectingClientFactory): diff --git a/platformio/commands/team.py b/platformio/commands/team.py index 6733a420..aac68d1e 100644 --- a/platformio/commands/team.py +++ b/platformio/commands/team.py @@ -20,7 +20,7 @@ import re import click from tabulate import tabulate -from platformio.clients.account import AccountClient +from platformio.account.client import AccountClient def validate_orgname_teamname(value, teamname_validate=False): diff --git a/platformio/http.py b/platformio/http.py index 86fb8cae..5f5fbdd2 100644 --- a/platformio/http.py +++ b/platformio/http.py @@ -115,7 +115,7 @@ class HTTPClient(object): ) if with_authorization and "Authorization" not in headers: # pylint: disable=import-outside-toplevel - from platformio.clients.account import AccountClient + from platformio.account.client import AccountClient headers["Authorization"] = ( "Bearer %s" % AccountClient().fetch_authentication_token() diff --git a/platformio/package/commands/publish.py b/platformio/package/commands/publish.py index 89cc5c01..dfa3e371 100644 --- a/platformio/package/commands/publish.py +++ b/platformio/package/commands/publish.py @@ -21,7 +21,7 @@ import click from tabulate import tabulate from platformio import fs -from platformio.clients.account import AccountClient +from platformio.account.client import AccountClient from platformio.exception import UserSideException from platformio.package.manifest.parser import ManifestParserFactory from platformio.package.manifest.schema import ManifestSchema diff --git a/platformio/package/commands/unpublish.py b/platformio/package/commands/unpublish.py index 88646095..b1194b9e 100644 --- a/platformio/package/commands/unpublish.py +++ b/platformio/package/commands/unpublish.py @@ -14,7 +14,7 @@ import click -from platformio.clients.account import AccountClient +from platformio.account.client import AccountClient from platformio.package.meta import PackageSpec, PackageType from platformio.package.registry import RegistryClient diff --git a/platformio/package/registry.py b/platformio/package/registry.py index 1682f7b1..2c465e0c 100644 --- a/platformio/package/registry.py +++ b/platformio/package/registry.py @@ -15,7 +15,7 @@ # pylint: disable=too-many-arguments from platformio import __registry_mirror_hosts__, fs -from platformio.clients.account import AccountClient, AccountError +from platformio.account.client import AccountClient, AccountError from platformio.http import HTTPClient, HTTPClientError