diff --git a/Clockify/Clockify_Send_Daily_Activity_Brief_to_Slack.ipynb b/Clockify/Clockify_Send_Daily_Activity_Brief_to_Slack.ipynb
deleted file mode 100644
index 64ca4d4014..0000000000
--- a/Clockify/Clockify_Send_Daily_Activity_Brief_to_Slack.ipynb
+++ /dev/null
@@ -1,274 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "389e6be9-1a6e-4fcb-b091-e31607ec8da6",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "36722081-8746-486c-a539-6a65f45732bb",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "# Clockify - Send Daily Activity Brief to Slack"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "933b1463-8fc8-40a3-ba4f-19db5253599b",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "**Tags:** #clockify #slack #activity #brief #daily #automation"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e0beb301-9271-41a4-b16a-ce2fee7db1c9",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "**Author:** [Florent Ravenel](https://www.linkedin.com/in/florent-ravenel/)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "61596618-5ddf-4f83-8b0a-239e72060930",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "**Last update:** 2023-10-11 (Created: 2023-10-11)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "80cd984b-9345-452c-ad44-72dcdc8b26e1",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "**Description:** This notebook automates the process of sending a daily activity brief from Clockify to Slack. It is usefull for organizations to keep track of their team's daily activities."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "951332ed-d0a6-4930-b9ff-69a66f3bbcfd",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "**References:**\n- [Clockify API Documentation](https://clockify.github.io/clockify_api_docs/)\n- [Slack API Documentation](https://api.slack.com/docs)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "855b70c1-9f73-4cba-bd43-6a8773e494f1",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "## Input"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ce51e72d-4b4a-4a33-8619-cc02cdcf238b",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "### Import libraries"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "5c821e4c-54c3-40a5-b1fe-c8f3d986f9c5",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": "import requests\nimport json",
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "id": "1a6aa89f-f3c1-4d96-8ecc-fa7921ea3ee8",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "### Setup variables\n- `clockify_api_key`: Clockify API key. [Get your API key here](https://clockify.me/user/settings).\n- `slack_token`: Slack token. [Get your token here](https://api.slack.com/custom-integrations/legacy-tokens).\n- `slack_channel`: Slack channel to post the daily activity brief."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "48c0a7d3-cbe8-4508-849c-9aee7bbf9960",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": "clockify_api_key = \"\"\nslack_token = \"\"\nslack_channel = \"\"",
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "id": "851b98ee-d339-4d4d-8eab-1e008e8a2590",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "## Model"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "beb8d3b5-8be3-4a74-9cab-f9466dd0dc8d",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "### Get daily activity brief"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f6fe61c4-4262-4405-a40d-6646bf1362e4",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "Retrieve the daily activity brief from Clockify API and store it in a variable."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f084002a-cd76-4ba9-9c19-b0a527320835",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": "# Set the request headers\nheaders = {\"Content-Type\": \"application/json\", \"X-Api-Key\": clockify_api_key}\n# Set the request parameters\nparams = {\n \"workspace\": \"\",\n \"user\": \"\",\n \"start\": \"\",\n \"end\": \"\",\n}\n# Make the request\nresponse = requests.get(\n \"https://api.clockify.me/api/v1/reports/summary\", headers=headers, params=params\n)\n# Store the response in a variable\ndaily_activity_brief = response.json()",
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "id": "00f4e125-3d1b-450c-9836-b72022b7c9f6",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "### Post daily activity brief to Slack"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4bd2bad1-237f-4a9b-95a9-650a1d141565",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "Post the daily activity brief to Slack."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "2eb3b92c-3ae5-4806-9239-092b72b053ed",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": "# Set the request headers\nheaders = {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Authorization\": \"Bearer \" + slack_token,\n}\n# Set the request body\nbody = {\n \"channel\": slack_channel,\n \"text\": \"Daily activity brief:\",\n \"attachments\": [{\"text\": json.dumps(daily_activity_brief, indent=4)}],\n}\n# Make the request\nresponse = requests.post(\n \"https://slack.com/api/chat.postMessage\", headers=headers, data=json.dumps(body)\n)",
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "id": "d943244f-dc15-44ca-98a9-c00df3976124",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "## Output"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "327dca23-43d6-40e4-a7f1-fda12179c445",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": [
- "### Display result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "3a87fb89-698f-41c0-b2eb-c8d622bc965e",
- "metadata": {
- "papermill": {},
- "tags": []
- },
- "source": "# Print the response\nprint(response.text)",
- "outputs": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.9.6"
- },
- "widgets": {
- "application/vnd.jupyter.widget-state+json": {
- "state": {},
- "version_major": 2,
- "version_minor": 0
- }
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
\ No newline at end of file
diff --git a/Clockify/Clockify_Send_daily_activity_brief_to_Slack.ipynb b/Clockify/Clockify_Send_daily_activity_brief_to_Slack.ipynb
new file mode 100644
index 0000000000..6630344265
--- /dev/null
+++ b/Clockify/Clockify_Send_daily_activity_brief_to_Slack.ipynb
@@ -0,0 +1,585 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "389e6be9-1a6e-4fcb-b091-e31607ec8da6",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "36722081-8746-486c-a539-6a65f45732bb",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "# Clockify - Send daily activity brief to Slack"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "933b1463-8fc8-40a3-ba4f-19db5253599b",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "**Tags:** #clockify #slack #activity #brief #daily #automation"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0beb301-9271-41a4-b16a-ce2fee7db1c9",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "**Author:** [Florent Ravenel](https://www.linkedin.com/in/florent-ravenel/)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "61596618-5ddf-4f83-8b0a-239e72060930",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "**Last update:** 2023-10-11 (Created: 2023-10-11)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "80cd984b-9345-452c-ad44-72dcdc8b26e1",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "**Description:** This notebook automates the process of sending a daily activity brief from Clockify to Slack. It is usefull for organizations to keep track of their team's daily activities."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "951332ed-d0a6-4930-b9ff-69a66f3bbcfd",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "**References:**\n",
+ "- [Clockify API Documentation](https://clockify.github.io/clockify_api_docs/)\n",
+ "- [Slack API Documentation](https://api.slack.com/docs)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00b0e091-c767-46dd-a237-6fc6870db301",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "## Input"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e438858a-f719-4698-93c8-c25bf52964a4",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Import libraries"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "12b0fc1f-a48f-46dc-80c1-a8f93858ede9",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "import requests\n",
+ "import naas\n",
+ "import pandas as pd\n",
+ "from datetime import datetime, date, timedelta, time\n",
+ "from naas_drivers import slack"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7439537e-b364-4c06-a551-1ba2207c0cdc",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Setup variables\n",
+ "**Mandatory**\n",
+ "- `api_key`: [Get your API key](https://clockify.me/user/settings)\n",
+ "- `workspace_id`: ID of the workspace\n",
+ "- `user_id`: ID of the user to get time entries from\n",
+ "- `slack_token`: User Slack token\n",
+ "- `slack_channel`: the channel where you wish to send the message\n",
+ "\n",
+ "**Optional**\n",
+ "- `cron`: This variable represents the CRON syntax used to run the scheduler. More information here: https://crontab.guru/#0_12,18_*_*_1-5\n",
+ "- `start_date`: Start date of the timeframe to create the time entries database\n",
+ "- `end_date`: End date of the timeframe to create the time entries database"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "736cfc94-75e5-4efa-b17e-c164df51dd30",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "# Mandatory\n",
+ "api_key = naas.secret.get(\"CLOCKIFY_API_KEY\") or \"YOUR_API_KEY\"\n",
+ "workspace_id = \"626f9e3b36c2670314c0386e\" #\"\"\n",
+ "user_id = \"626fa819f87fd71e0e1f392c\"\n",
+ "slack_token = naas.secret.get(\"SLACK_USER_TOKEN\")\n",
+ "slack_channel = \"core-team-chat\"\n",
+ "\n",
+ "# Optional\n",
+ "cron = \"0 * * * 2-5\"\n",
+ "start_date = (today - timedelta(days=1)).strftime(\"%Y-%m-%d\")\n",
+ "end_date = (datetime.now().replace(hour=23, minute=59, second=59, microsecond=0).astimezone() - timedelta(days=1)).isoformat()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d746baad-e9ae-4c52-8899-b3ce918f55cc",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "## Model"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "788921c8-02d4-48a6-b22f-13ce210b6988",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Function: Flatten the nested dict"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "539b5ca1-b3ee-4fd4-bb30-6b55965eac3b",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "# Flatten the nested dict\n",
+ "def flatten_dict(d, parent_key='', sep='_'):\n",
+ " \"\"\"\n",
+ " Flattens a nested dictionary into a single level dictionary.\n",
+ "\n",
+ " Args:\n",
+ " d (dict): A nested dictionary.\n",
+ " parent_key (str): Optional string to prefix the keys with.\n",
+ " sep (str): Optional separator to use between parent_key and child_key.\n",
+ "\n",
+ " Returns:\n",
+ " dict: A flattened dictionary.\n",
+ " \"\"\"\n",
+ " items = []\n",
+ " for k, v in d.items():\n",
+ " new_key = f\"{parent_key}{sep}{k}\" if parent_key else k\n",
+ " if isinstance(v, dict):\n",
+ " items.extend(flatten_dict(v, new_key, sep=sep).items())\n",
+ " else:\n",
+ " items.append((new_key, v))\n",
+ " return dict(items)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fea09d38-f442-4255-ad62-fefd51f9f443",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Function: Get referentials from workspace"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c61ded79-99f1-4826-b3ab-81f1ea474c87",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "def get_data(api_key, workspace_id, endpoint):\n",
+ " # Init\n",
+ " page = 1\n",
+ " df = pd.DataFrame()\n",
+ " \n",
+ " while True:\n",
+ " # Requests\n",
+ " url = f\"https://api.clockify.me/api/v1/workspaces/{workspace_id}/{endpoint}\"\n",
+ " headers = {\n",
+ " \"X-Api-Key\": api_key\n",
+ " }\n",
+ " params = {\n",
+ " \"page\": page,\n",
+ " \"page-size\": 100\n",
+ " }\n",
+ " res = requests.get(url, headers=headers, params=params)\n",
+ " data = res.json()\n",
+ " if len(data) > 0:\n",
+ " for d in data:\n",
+ " res = flatten_dict(d)\n",
+ " tmp_df = pd.DataFrame([res])\n",
+ " df = pd.concat([df, tmp_df])\n",
+ " else:\n",
+ " break\n",
+ " page += 1\n",
+ " return df.reset_index(drop=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "440de640-7a97-466a-b305-c960960ed815",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Get time entries"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e03c86de-820a-4bfa-b7ec-9ef24543330f",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "def get_time_entries(\n",
+ " api_key,\n",
+ " workspace_id,\n",
+ " user_id,\n",
+ " start_date,\n",
+ " end_date\n",
+ "):\n",
+ " # Init\n",
+ " start_date = datetime.strptime(start_date, \"%Y-%m-%d\").astimezone().isoformat() # Format date\n",
+ " page = 1\n",
+ " df = pd.DataFrame()\n",
+ " \n",
+ " # Get raw data\n",
+ " while True:\n",
+ " url = f\"https://api.clockify.me/api/v1/workspaces/{workspace_id}/user/{user_id}/time-entries\"\n",
+ " headers = {\"X-Api-Key\": api_key}\n",
+ " params = {\n",
+ " \"start\": start_date,\n",
+ " \"end\": end_date,\n",
+ " \"page\": page,\n",
+ " \"page-size\": 100\n",
+ " }\n",
+ " res = requests.get(url, headers=headers, params=params)\n",
+ " data = res.json()\n",
+ " if len(data) > 0:\n",
+ " for d in data:\n",
+ " res = flatten_dict(d)\n",
+ " tmp_df = pd.DataFrame([res])\n",
+ " df = pd.concat([df, tmp_df]).reset_index(drop=True)\n",
+ " else:\n",
+ " break\n",
+ " page += 1\n",
+ " return df.reset_index(drop=True)\n",
+ "\n",
+ "# Get entries\n",
+ "database = get_time_entries(api_key, workspace_id, user_id, start_date, end_date)\n",
+ "print(\"Time entries fetched:\", len(database))\n",
+ "database#.head(3)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fc522760-7f46-40a7-8973-d66996bc513f",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Get all projects"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9f8225c9-f72e-4cf0-92ed-944a2230c26d",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "df_projects = get_data(api_key, workspace_id, \"projects\")\n",
+ "df_projects = df_projects.rename(columns={\"id\": \"projectId\", \"name\": \"projectName\"})\n",
+ "df_projects = df_projects[[\"projectId\", \"projectName\", \"clientId\"]]\n",
+ "print(\"Projects fetched:\", len(df_projects))\n",
+ "df_projects.head(1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5a387182-8635-420f-85f3-42854c2095a9",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Get all clients"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09d12b5e-074c-43bd-acb3-26cffdedfba8",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "df_clients = get_data(api_key, workspace_id, \"clients\")\n",
+ "df_clients = df_clients.rename(columns={\"id\": \"clientId\", \"name\": \"clientName\"})\n",
+ "df_clients = df_clients[[\"clientId\", \"clientName\"]]\n",
+ "print(\"Clients fetched:\", len(df_clients))\n",
+ "df_clients.head(1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9f56677e-8176-4075-97cf-2f6e79fcac1e",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Create database\n",
+ "Enrich data with referentials from workspace"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4b471447-25bc-435f-9054-e199e6366e2f",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "def create_database(\n",
+ " df_init,\n",
+ " df_projects,\n",
+ " df_clients,\n",
+ " filters=None\n",
+ "):\n",
+ " # Init\n",
+ " df = df_init.copy()\n",
+ " \n",
+ " # Final DB\n",
+ " df = pd.merge(df, df_projects, how=\"left\", on=\"projectId\")\n",
+ " df = pd.merge(df, df_clients, how=\"left\", on=\"clientId\")\n",
+ " df[\"timeduration_Hours\"] = round((pd.to_datetime(df[\"timeInterval_end\"]) - pd.to_datetime(df[\"timeInterval_start\"])).dt.total_seconds() / 3600, 2)\n",
+ "\n",
+ " # Select column\n",
+ " to_group = [\n",
+ " \"clientName\",\n",
+ " \"projectName\",\n",
+ " \"description\",\n",
+ " ]\n",
+ " to_agg = {\n",
+ " \"timeduration_Hours\": \"sum\" \n",
+ " }\n",
+ " df = df.groupby(to_group, as_index=False).agg(to_agg)\n",
+ " return df\n",
+ " \n",
+ "df_slack = create_database(\n",
+ " database,\n",
+ " df_projects,\n",
+ " df_clients,\n",
+ " filters\n",
+ ")\n",
+ "print(df_slack.timeduration_Hours.sum())\n",
+ "df_slack"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "70af6cc5-2dcf-4473-ad45-abdd4463dbf2",
+ "metadata": {},
+ "source": [
+ "### Create Slack blocks"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "474fd1df-43f1-44ce-8a4c-f36f71ee672f",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "blocks = [\n",
+ " {\n",
+ " \"type\": \"section\",\n",
+ " \"text\": {\n",
+ " \"type\": \"mrkdwn\",\n",
+ " \"text\": f\"*Here is my brief of yesterday activity: {start_date}*\",\n",
+ " }\n",
+ " }\n",
+ "]\n",
+ "\n",
+ "clients = df_slack.clientName.unique()\n",
+ "for client in clients:\n",
+ " # Filter on clients\n",
+ " tmp_df = df_slack[df_slack[\"clientName\"] == client].reset_index(drop=True)\n",
+ " total = round(tmp_df.timeduration_Hours.sum())\n",
+ " \n",
+ " # Get clients\n",
+ " blocks.append({\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": f\"*{client} : {total} hours*\"}})\n",
+ " \n",
+ " # Get project details\n",
+ " bullet_points = []\n",
+ " for row in tmp_df.itertuples():\n",
+ " project_name = row.projectName\n",
+ " description = row.description\n",
+ " hours = row.timeduration_Hours\n",
+ " bullet_points.append(f\"• {project_name}: {description} ({hours} hours)\")\n",
+ " \n",
+ " for b in bullet_points:\n",
+ " blocks.append({\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": b}})\n",
+ " \n",
+ "blocks"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3cb6fdc2-6362-40dd-a5e9-91bb23cd500c",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "## Output"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7e25766-2ce9-4f72-a925-ee4bc4c5031b",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Send message to Slack"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5d22aa13-1a2f-45c0-8fac-4f148828c629",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "slack.connect(slack_token).send(slack_channel, text=\"\", blocks=blocks)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7bcec3e2-f77a-4053-9055-e3ffed6de3d9",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "source": [
+ "### Add scheduler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ce43e5fb-323b-47ec-b308-8c320e426280",
+ "metadata": {
+ "papermill": {},
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "naas.scheduler.add(cron=cron)\n",
+ "\n",
+ "# naas.scheduler.delete()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.6"
+ },
+ "widgets": {
+ "application/vnd.jupyter.widget-state+json": {
+ "state": {},
+ "version_major": 2,
+ "version_minor": 0
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}