From c8d063a4f0675026ec9319ede24cce7d22a8e24a Mon Sep 17 00:00:00 2001
From: Freezed <2160318-free_zed@users.noreply.gitlab.com>
Date: Mon, 21 Mar 2022 10:35:33 +0100
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20activity=20creation=20#1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Define options
Options not passed as argument are prompted;
- if required
- and default value not set

TODO: Response not correctly formated for status and error

        Status:  N/A
        Error:   N/A
---
 Makefile                |   4 +-
 README.md               |  14 ++---
 cli/api.py              |  17 ++++++
 cli/commands.py         | 131 ++++++++++++++++++++++++++++++++++++++++
 cli/{run.py => main.py} |   3 +
 5 files changed, 160 insertions(+), 9 deletions(-)
 create mode 100644 cli/api.py
 create mode 100644 cli/commands.py
 rename cli/{run.py => main.py} (89%)

diff --git a/Makefile b/Makefile
index 7ee58e5..e3c7d96 100644
--- a/Makefile
+++ b/Makefile
@@ -6,10 +6,10 @@ help: # Print help on Makefile
 	expand -t20
 
 open_all: # Open all projects files
-	${EDITOR} ${VIRTUAL_ENV}/bin/activate
+	test -n ${VIRTUAL_ENV} && ${EDITOR} ${VIRTUAL_ENV}/bin/activate
 	${EDITOR} .gitignore .gitlab-ci.yml Makefile README.md requirements.txt requirements-dev.txt setup.cfg
 	${EDITOR} .git/hooks/p*-commit
-	${EDITOR} cli/run.py
+	${EDITOR} cli/*.py
 
 pre_commit: # Run the pre-commit hook
 	.git/hooks/pre-commit
diff --git a/README.md b/README.md
index bd2d6dc..37626dd 100644
--- a/README.md
+++ b/README.md
@@ -17,14 +17,14 @@ A python CLI to share data related to physical activities over an API (geo-local
 
 These are imagined with _[Strava](https://developers.strava.com/docs/reference/) in mind_, but any other service will be nice too :
 
-* [Create manual activity](https://lab.frogg.it/fcode/geostrapy/-/issues/1)
-* From a GPX track: [get characteristics](https://lab.frogg.it/fcode/geostrapy/-/issues/2)
-    * and [create an activity](https://lab.frogg.it/fcode/geostrapy/-/issues/3)
+* [ ] [Create manual activity](https://lab.frogg.it/fcode/geostrapy/-/issues/1)
+* [ ] From a GPX track: [get characteristics](https://lab.frogg.it/fcode/geostrapy/-/issues/2)
+    * [ ] and [create an activity](https://lab.frogg.it/fcode/geostrapy/-/issues/3)
 * Sanitise a GPX track:
-    * [crop start, end & stop points](https://lab.frogg.it/fcode/geostrapy/-/issues/4)
-    * [change start-time](https://lab.frogg.it/fcode/geostrapy/-/issues/5)
-* [Post GPX file as activity](https://lab.frogg.it/fcode/geostrapy/-/issues/6)
-* [Process GPX multi-track file](https://lab.frogg.it/fcode/geostrapy/-/issues/7)
+    * [ ] [crop start, end & stop points](https://lab.frogg.it/fcode/geostrapy/-/issues/4)
+    * [ ] [change start-time](https://lab.frogg.it/fcode/geostrapy/-/issues/5)
+* [ ] [Post GPX file as activity](https://lab.frogg.it/fcode/geostrapy/-/issues/6)
+* [ ] [Process GPX multi-track file](https://lab.frogg.it/fcode/geostrapy/-/issues/7)
 * and [maybe more](https://lab.frogg.it/fcode/geostrapy/-/boards)…
 
 
diff --git a/cli/api.py b/cli/api.py
new file mode 100644
index 0000000..22b11f1
--- /dev/null
+++ b/cli/api.py
@@ -0,0 +1,17 @@
+"""
+API utilities
+"""
+
+from requests import HTTPError
+
+from strava.api._helpers import client, url, json
+
+
+def post_activity(xargs):
+    """API call to create an activity"""
+
+    response = client.post(url=url("/activities"), data=xargs)
+    try:
+        return json(response)
+    except HTTPError:
+        return response
diff --git a/cli/commands.py b/cli/commands.py
new file mode 100644
index 0000000..b4451e9
--- /dev/null
+++ b/cli/commands.py
@@ -0,0 +1,131 @@
+"""
+CLI commands
+"""
+
+import datetime
+
+import click
+from strava.decorators import (
+    output_option,
+    login_required,
+    format_result,
+    TableFormat,
+    OutputType,
+)
+from strava.formatters import (
+    humanize,
+    apply_formatters,
+)
+
+from api import post_activity
+
+_ACTIVITY_COLUMNS = ("key", "value")
+
+
+@click.option(
+    "-n",
+    "--name",
+    prompt=True,
+    type=str,
+    required=True,
+    default="Activity",
+    help="The name of the activity",
+)
+@click.option(
+    "-a",
+    "--activity_type",
+    prompt=True,
+    type=str,
+    required=True,
+    default="run",
+    help="Type of activity",
+)
+@click.option(
+    "-s",
+    "--start",
+    prompt=True,
+    type=str,
+    required=True,
+    default=datetime.datetime.now().isoformat(),
+    help="ISO 8601 formatted date time",
+)
+@click.option("-t", "--time", prompt=True, type=int, required=True, help="In seconds")
+@click.option("-d", "--desc", prompt=True, type=str, help="Description of the activity")
+@click.option("-D", "--dist", prompt=True, type=int, help="In meters")
+@click.option(
+    "-c",
+    "--commute",
+    prompt=True,
+    type=int,
+    default="0",
+    prompt_required=False,
+    help="Set to 1 to mark as commute",
+)
+@click.option(
+    "-T",
+    "--trainer",
+    prompt=True,
+    type=int,
+    default="0",
+    prompt_required=False,
+    help="Set to 1 to mark as a trainer activity",
+)
+@click.option(
+    "-h",
+    "--hide",
+    prompt=True,
+    type=int,
+    default="0",
+    prompt_required=False,
+    help="Set to true to mute activity",
+)
+@click.command("create")
+@output_option()
+@login_required
+def post_create(**kwargs):
+    """Create an activity"""
+    xargs = {
+        "name": kwargs["name"],
+        "type": kwargs["activity_type"],
+        "trainer": kwargs["trainer"],
+        "commute": kwargs["commute"],
+        "distance": kwargs["dist"],
+        "description": kwargs["desc"],
+        "elapsed_time": kwargs["time"],
+        "hide_from_home": kwargs["hide"],
+        "start_date_local": kwargs["start"],
+    }
+    result = post_activity(xargs)
+    _format_upload(result, output=kwargs["output"])
+
+
+@format_result(
+    table_columns=_ACTIVITY_COLUMNS,
+    show_table_headers=False,
+    table_format=TableFormat.PLAIN,
+)
+def _format_upload(result, output=None):
+    return result if output == OutputType.JSON.value else _as_table(result)
+
+
+def _as_table(upload_result):
+    def format_id(upload_id):
+        return f"{upload_id}"
+
+    def format_error(upload_error):
+        return f"{upload_error}"
+
+    def format_property(name):
+        return click.style(f"{humanize(name)}:", bold=True)
+
+    formatters = {
+        "id": format_id,
+        "errors": format_error,
+    }
+
+    basic_data = [
+        {"key": format_property(k), "value": v}
+        for k, v in apply_formatters(upload_result, formatters).items()
+    ]
+
+    return [*basic_data]
diff --git a/cli/run.py b/cli/main.py
similarity index 89%
rename from cli/run.py
rename to cli/main.py
index 60778ff..9a98d1d 100644
--- a/cli/run.py
+++ b/cli/main.py
@@ -15,6 +15,8 @@ from strava.commands import (
     set_config,
 )
 
+from commands import post_create
+
 
 @click.group()
 def cli():
@@ -26,6 +28,7 @@ def cli():
 
 cli.add_command(login)
 cli.add_command(logout)
+cli.add_command(post_create)
 cli.add_command(set_config)
 
 if __name__ == "__main__":
-- 
GitLab