diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9898803
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+dist
+package
+.DS_Store
+.slack/apps.dev.json
+.idea
+.slack*
+node_modules
+tests
+keys
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..399e41d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2022 Slack Technologies, LLC
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..76fb77d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,238 @@
+# Welcome Bot
+
+This sample automation creates, stores, and sends friendly welcome messages when
+users join a channel.
+
+**Guide Outline**:
+
+- [Included Workflows](#included-workflows)
+- [Understanding Welcome Bot](#understanding-welcome-bot)
+- [Setup](#setup)
+ - [Install the Slack CLI](#install-the-slack-cli)
+ - [Clone the Sample App](#clone-the-sample-app)
+- [Creating Triggers](#creating-triggers)
+- [Datastores](#datastores)
+- [Testing](#testing)
+- [Deploying Your App](#deploying-your-app)
+- [Viewing Activity Logs](#viewing-activity-logs)
+- [Project Structure](#project-structure)
+- [Resources](#resources)
+
+---
+
+## Included Workflows
+
+- **Welcome Message Setup**: Create and store a welcome message for a specified
+ channel
+- **Send Welcome Message**: Retrieve a stored message and send it when a new
+ user joins the channel
+
+## Understanding Welcome Bot
+
+When working with this app it helps to think about it as two separate series of
+steps.
+
+
+
+### Creating and storing messages
+
+- A link trigger starts the `MessageSetupWorkflow` workflow.
+- The `MessageSetupWorkflow` workflow has three steps, steps are the action
+ components of a workflow.
+ 1. The `OpenForm` Slack function that opens a form.
+ 2. The `SendEphemeralMessage` Slack function that sends a confirmation
+ message.
+ 3. Passes data to the `WelcomeMessageSetupFunction` custom function.
+- When the form is submitted, the `WelcomeMessageSetupFunction` function saves
+ the message to the datastore and creates an event trigger to listen in on
+ `user_joined_channel` events in the specified channel.
+
+### Sending messages
+
+- The `user_joined_channel` event trigger starts the
+ `RenameChannelWorkflow` workflow.
+- The `RenameChannelWorkflow` workflow has one additional step:
+ 1. Pass data to the `RenameChannelFunction` custom function.
+- The `RenameChannelFunction` function retrieves the saved message and
+ sends it to the selected channel.
+
+**⚠️ Note: In order for this automation to send welcome messages, please make
+sure to invite your app to the channel(s) where you are configuring the messages
+once it has been [installed to your workspace](#running-your-project-locally).**
+
+## Setup
+
+Before getting started, first make sure you have a development workspace where
+you have permission to install apps. **Please note that the features in this
+project require that the workspace be part of
+[a Slack paid plan](https://slack.com/pricing).**
+
+### Install the Slack CLI
+
+To use this template, you need to install and configure the Slack CLI.
+Step-by-step instructions can be found in our
+[Quickstart Guide](https://api.slack.com/automation/quickstart).
+
+### Clone the Sample App
+
+Start by cloning this repository:
+
+```zsh
+# Clone this project onto your machine
+$ slack create my-app -t slack-samples/deno-welcome-bot
+
+# Change into the project directory
+$ cd my-app
+```
+
+## Running Your Project Locally
+
+While building your app, you can see your changes appear in your workspace in
+real-time with `slack run`. You'll know an app is the development version if the
+name has the string `(local)` appended.
+
+```zsh
+# Run app locally
+$ slack run
+
+Connected, awaiting events
+```
+
+To stop running locally, press ` + C` to end the process.
+
+## Creating Triggers
+
+[Triggers](https://api.slack.com/automation/triggers) are what cause workflows
+to run. These triggers can be invoked by a user, or automatically as a response
+to an event within Slack.
+
+When you `run` or `deploy` your project for the first time, the CLI will prompt
+you to create a trigger if one is found in the `triggers/` directory. For any
+subsequent triggers added to the application, each must be
+[manually added using the `trigger create` command](#manual-trigger-creation).
+
+When creating triggers, you must select the workspace and environment that you'd
+like to create the trigger in. Each workspace can have a local development
+version (denoted by `(local)`), as well as a deployed version. _Triggers created
+in a local environment will only be available to use when running the
+application locally._
+
+### Link Triggers
+
+A [link trigger](https://api.slack.com/automation/triggers/link) is a type of
+trigger that generates a **Shortcut URL** which, when posted in a channel or
+added as a bookmark, becomes a link. When clicked, the link trigger will run the
+associated workflow.
+
+Link triggers are _unique to each installed version of your app_. This means
+that Shortcut URLs will be different across each workspace, as well as between
+[locally run](#running-your-project-locally) and
+[deployed apps](#deploying-your-app).
+
+With link triggers, after selecting a workspace and environment, the output
+provided will include a Shortcut URL. Copy and paste this URL into a channel as
+a message, or add it as a bookmark in a channel of the workspace you selected.
+Interacting with this link will run the associated workflow.
+
+**Note: triggers won't run the workflow unless the app is either running locally
+or deployed!**
+
+### Manual Trigger Creation
+
+To manually create a trigger, use the following command:
+
+```zsh
+$ slack trigger create --trigger-def triggers/welcome_message_trigger.ts
+```
+
+## Datastores
+
+For storing data related to your app, datastores offer secure storage on Slack
+infrastructure. For an example of a datastore, see
+`datastores/welcome_message_db.ts`. The use of a datastore requires the
+`datastore:write`/`datastore:read` scopes to be present in your manifest.
+
+## Testing
+
+Test filenames should be suffixed with `_test`.
+
+Run all tests with `deno test`:
+
+```zsh
+$ deno test
+```
+
+## Deploying Your App
+
+Once development is complete, deploy the app to Slack infrastructure using
+`slack deploy`:
+
+```zsh
+$ slack deploy
+```
+
+When deploying for the first time, you'll be prompted to
+[create a new link trigger](#creating-triggers) for the deployed version of your
+app. When that trigger is invoked, the workflow should run just as it did when
+developing locally (but without requiring your server to be running).
+
+## Viewing Activity Logs
+
+Activity logs of your application can be viewed live and as they occur with the
+following command:
+
+```zsh
+$ slack activity --tail
+```
+
+## Project Structure
+
+### `.slack/`
+
+Contains `apps.dev.json` and `apps.json`, which include installation details for
+development and deployed apps.
+
+### `datastores/`
+
+[Datastores](https://api.slack.com/automation/datastores) securely store data
+for your application on Slack infrastructure. Required scopes to use datastores
+include `datastore:write` and `datastore:read`.
+
+### `functions/`
+
+[Functions](https://api.slack.com/automation/functions) are reusable building
+blocks of automation that accept inputs, perform calculations, and provide
+outputs. Functions can be used independently or as steps in workflows.
+
+### `triggers/`
+
+[Triggers](https://api.slack.com/automation/triggers) determine when workflows
+are run. A trigger file describes the scenario in which a workflow should be
+run, such as a user pressing a button or when a specific event occurs.
+
+### `workflows/`
+
+A [workflow](https://api.slack.com/automation/workflows) is a set of steps
+(functions) that are executed in order.
+
+Workflows can be configured to run without user input or they can collect input
+by beginning with a [form](https://api.slack.com/automation/forms) before
+continuing to the next step.
+
+### `manifest.ts`
+
+The [app manifest](https://api.slack.com/automation/manifest) contains the app's
+configuration. This file defines attributes like app name and description.
+
+### `slack.json`
+
+Used by the CLI to interact with the project's SDK dependencies. It contains
+script hooks that are executed by the CLI and implemented by the SDK.
+
+## Resources
+
+To learn more about developing automations on Slack, visit the following:
+
+- [Automation Overview](https://api.slack.com/automation)
+- [CLI Quick Reference](https://api.slack.com/automation/cli/quick-reference)
+- [Samples and Templates](https://api.slack.com/automation/samples)
diff --git a/assets/default_new_app_icon.png b/assets/default_new_app_icon.png
new file mode 100644
index 0000000..812445a
Binary files /dev/null and b/assets/default_new_app_icon.png differ
diff --git a/assets/deno-welcome-bot-flow.png b/assets/deno-welcome-bot-flow.png
new file mode 100644
index 0000000..96d4b3f
Binary files /dev/null and b/assets/deno-welcome-bot-flow.png differ
diff --git a/deno.jsonc b/deno.jsonc
new file mode 100644
index 0000000..c52cc99
--- /dev/null
+++ b/deno.jsonc
@@ -0,0 +1,19 @@
+{
+ "$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json",
+ "fmt": {
+ "files": {
+ "include": ["README.md", "datastores", "external_auth", "functions", "manifest.ts", "triggers", "types", "views", "workflows"]
+ }
+ },
+ "importMap": "import_map.json",
+ "lint": {
+ "files": {
+ "include": ["datastores", "external_auth", "functions", "manifest.ts", "triggers", "types", "views", "workflows"]
+ }
+ },
+ "lock": false,
+ "tasks": {
+ "test": "deno fmt --check && deno lint && deno test --allow-read --allow-none"
+ },
+ "lock": false
+}
diff --git a/functions/rename_channel.ts b/functions/rename_channel.ts
new file mode 100644
index 0000000..63a3d67
--- /dev/null
+++ b/functions/rename_channel.ts
@@ -0,0 +1,26 @@
+// deno-lint-ignore-file
+import { ChannelType } from "../helpers/types.ts";
+import { renameChannel } from "../services/rename_channels.ts";
+import { DefineFunction, SlackFunction } from "deno-slack-sdk/mod.ts";
+import { getRecentlyAdded } from "../services/recently_added.ts";
+
+export const RenameChannelFunction = DefineFunction({
+ callback_id: "rename_channel_function",
+ title: "Rename Channel",
+ description: "Renames a channel according to Tikal's naming conventions",
+ source_file: "functions/rename_channel.ts",
+});
+
+export default SlackFunction(RenameChannelFunction, async (
+ { client },
+) => {
+ const recentlyAdded = await getRecentlyAdded(client);
+
+ recentlyAdded.forEach(
+ (channel: ChannelType) => renameChannel(channel, client)
+ );
+
+ return {
+ outputs: {},
+ };
+});
diff --git a/functions/sync_google_groups.ts b/functions/sync_google_groups.ts
new file mode 100644
index 0000000..636728d
--- /dev/null
+++ b/functions/sync_google_groups.ts
@@ -0,0 +1,20 @@
+// deno-lint-ignore-file
+import { syncGoogleGroups } from "../services/sync_google_groups.ts";
+import { DefineFunction, SlackFunction } from "deno-slack-sdk/mod.ts";
+
+export const SyncGoogleGroupsFunction = DefineFunction({
+ callback_id: "sync_google_groups_function",
+ title: "Sync Google Groups",
+ description: "Renames a channel according to Tikal's naming conventions",
+ source_file: "functions/sync_google_groups.ts",
+});
+
+export default SlackFunction(SyncGoogleGroupsFunction, async (
+ { client },
+) => {
+ console.log("syncGoogleGroups call")
+ await syncGoogleGroups(client)
+ return {
+ outputs: {},
+ };
+});
diff --git a/helpers/index.ts b/helpers/index.ts
new file mode 100644
index 0000000..7d8a203
--- /dev/null
+++ b/helpers/index.ts
@@ -0,0 +1,33 @@
+// deno-lint-ignore-file
+import { allowedPrefixes } from "./prefixes.ts";
+import { allowedPrefixesType } from "./types.ts";
+
+export const isLessThanHalfAMinuteAgo = (channel: { created: number; }) => {
+ const timestamp = channel.created
+ const currentTimestamp = Math.floor(Date.now() / 1000);
+ const differenceInSeconds = currentTimestamp - timestamp;
+ return differenceInSeconds < 30;
+}
+
+export const getRenameMessageText = (
+ userRealName: string,
+ channelName: string,
+ allowed: string[],
+ channelType: allowedPrefixesType,
+) => {
+ const prefList =
+ (allowed.length > 1 ? " one of the following prefixes: " : "") +
+ allowed.map((pref) => `"${pref}-"`).join();
+ return `Dear ${userRealName}, \n
+Your channel "${channelName}" was archived as ${channelType} channel names must start with a *${prefList} prefix*. \n
+A new channel was created: *${allowed[0]}-${channelName}*. \n
+Kind regards,\n
+Tikal Slack Bot
+`;
+};
+
+export const isLegalChannelName = (channelName: string, channelType: allowedPrefixesType) => (allowedPrefixes[channelType] as any[]).reduce(
+ (accumulator: boolean, prefix: allowedPrefixesType) => accumulator || channelName.startsWith(prefix),
+ false
+);
+
diff --git a/helpers/prefixes.ts b/helpers/prefixes.ts
new file mode 100644
index 0000000..dd1a8ac
--- /dev/null
+++ b/helpers/prefixes.ts
@@ -0,0 +1,49 @@
+
+export const allowedPrefixes = {
+ public: ["tikal"],
+ private: ["biz","backend-bp","backend-biz","devops-bp",
+ "devops-biz",
+ "frontend-bp",
+ "frontend-biz",
+ "mobile-bp",
+ "mobile-biz",
+ "sb",
+ "strategy",
+ "strategy-bp",
+ "backend-roadmaps",
+ "devops-roadmaps",
+ "eng-academy",
+ "eng-architecture",
+ "eng-innovation-lab",
+ "eng-roadmaps",
+ "frontend-roadmaps",
+ "mobile-roadmaps",
+ "finance",
+ "legal",
+ "infra",
+ "mrkt",
+ "mrkt-campaigns",
+ "mrkt-websites",
+ "backend-collab",
+ "backend-gl",
+ "devops-collab",
+ "devops-gl",
+ "frontend-collab",
+ "frontend-gl",
+ "gl",
+ "groups-bud",
+ "mobile-collab",
+ "mobile-gl",
+ "people",
+ "people-collab",
+ "people-exp",
+ "recrt",
+ "womens-in-tikal",
+ "backend-techradar",
+ "devops-techradar",
+ "frontend-techradar",
+ "mobile-techradar",
+ "prd-techradar",
+ "sales"
+]
+}
\ No newline at end of file
diff --git a/helpers/types.ts b/helpers/types.ts
new file mode 100644
index 0000000..09c6880
--- /dev/null
+++ b/helpers/types.ts
@@ -0,0 +1,13 @@
+// deno-lint-ignore-file
+import { allowedPrefixes } from "./prefixes.ts";
+
+export type ChannelType = {
+ id?: any;
+ name?: any;
+ creator?: any;
+ is_channel: any;
+ is_private: any;
+ is_archived: any;
+};
+
+export type allowedPrefixesType = keyof typeof allowedPrefixes;
diff --git a/import_map.json b/import_map.json
new file mode 100644
index 0000000..12819b8
--- /dev/null
+++ b/import_map.json
@@ -0,0 +1,6 @@
+{
+ "imports": {
+ "deno-slack-sdk/": "https://deno.land/x/deno_slack_sdk@2.2.0/",
+ "deno-slack-api/": "https://deno.land/x/deno_slack_api@2.1.1/"
+ }
+}
diff --git a/manifest.ts b/manifest.ts
new file mode 100644
index 0000000..bbefdd8
--- /dev/null
+++ b/manifest.ts
@@ -0,0 +1,36 @@
+import { Manifest } from "deno-slack-sdk/mod.ts";
+import { RenameChannelWorkflow } from "./workflows/rename_channel.ts";
+import { SyncGoogleGroupsWorkflow } from "./workflows/sync_google_groups.ts";
+import ArchiveCreateWorkflow from "./workflows/archive_create_channel.ts";
+
+export default Manifest({
+ name: "Tikal Bot",
+ description: "Keep channel naming conventions aligned",
+ icon: "assets/default_new_app_icon.png",
+ workflows: [
+ RenameChannelWorkflow,
+ ArchiveCreateWorkflow,
+ SyncGoogleGroupsWorkflow
+ ],
+ outgoingDomains: [],
+ botScopes: [
+ "chat:write",
+ "chat:write.public",
+ "channels:read",
+ "triggers:write",
+ "triggers:read",
+ "groups:read",
+ "groups:write.invites",
+ "im:read",
+ "mpim:read",
+ "mpim:write",
+ "mpim:write.invites",
+ "users:read",
+ "channels:manage",
+ "channels:join",
+ "channels:write.invites",
+ "groups:write",
+ "usergroups:write",
+ "im:write",
+ ],
+});
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..6cb77e1
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,505 @@
+{
+ "name": "welcome-bot-app",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "@google-cloud/local-auth": "^2.1.0",
+ "googleapis": "^105.0.0"
+ }
+ },
+ "node_modules/@google-cloud/local-auth": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@google-cloud/local-auth/-/local-auth-2.1.0.tgz",
+ "integrity": "sha512-ymZ1XuyKcRcro0aiMYz3hVGbZ+QZmN5V1Eyjvw2k1xqq76PwmDer0DIPxdxkLzfW9Inr8+g+MS9t9fZ7dOlTOQ==",
+ "dependencies": {
+ "arrify": "^2.0.1",
+ "google-auth-library": "^8.0.2",
+ "open": "^7.0.3",
+ "server-destroy": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/arrify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/bignumber.js": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
+ "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "node_modules/fast-text-encoding": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz",
+ "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w=="
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "node_modules/gaxios": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz",
+ "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==",
+ "dependencies": {
+ "extend": "^3.0.2",
+ "https-proxy-agent": "^5.0.0",
+ "is-stream": "^2.0.0",
+ "node-fetch": "^2.6.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/gcp-metadata": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz",
+ "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==",
+ "dependencies": {
+ "gaxios": "^5.0.0",
+ "json-bigint": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
+ "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/google-auth-library": {
+ "version": "8.9.0",
+ "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz",
+ "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==",
+ "dependencies": {
+ "arrify": "^2.0.0",
+ "base64-js": "^1.3.0",
+ "ecdsa-sig-formatter": "^1.0.11",
+ "fast-text-encoding": "^1.0.0",
+ "gaxios": "^5.0.0",
+ "gcp-metadata": "^5.3.0",
+ "gtoken": "^6.1.0",
+ "jws": "^4.0.0",
+ "lru-cache": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/google-p12-pem": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz",
+ "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==",
+ "dependencies": {
+ "node-forge": "^1.3.1"
+ },
+ "bin": {
+ "gp12-pem": "build/src/bin/gp12-pem.js"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/googleapis": {
+ "version": "105.0.0",
+ "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-105.0.0.tgz",
+ "integrity": "sha512-wH/jU/6QpqwsjTKj4vfKZz97ne7xT7BBbKwzQEwnbsG8iH9Seyw19P+AuLJcxNNrmgblwLqfr3LORg4Okat1BQ==",
+ "dependencies": {
+ "google-auth-library": "^8.0.2",
+ "googleapis-common": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/googleapis-common": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.4.tgz",
+ "integrity": "sha512-m4ErxGE8unR1z0VajT6AYk3s6a9gIMM6EkDZfkPnES8joeOlEtFEJeF8IyZkb0tjPXkktUfYrE4b3Li1DNyOwA==",
+ "dependencies": {
+ "extend": "^3.0.2",
+ "gaxios": "^5.0.1",
+ "google-auth-library": "^8.0.2",
+ "qs": "^6.7.0",
+ "url-template": "^2.0.8",
+ "uuid": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/gtoken": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz",
+ "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==",
+ "dependencies": {
+ "gaxios": "^5.0.1",
+ "google-p12-pem": "^4.0.0",
+ "jws": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+ "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/json-bigint": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
+ "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
+ "dependencies": {
+ "bignumber.js": "^9.0.0"
+ }
+ },
+ "node_modules/jwa": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
+ "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
+ "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
+ "dependencies": {
+ "jwa": "^2.0.0",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-forge": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+ "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
+ "engines": {
+ "node": ">= 6.13.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/open": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
+ "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
+ "dependencies": {
+ "is-docker": "^2.0.0",
+ "is-wsl": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
+ "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/server-destroy": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
+ "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ=="
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "node_modules/url-template": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
+ "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
+ },
+ "node_modules/uuid": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
+ "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..fd85353
--- /dev/null
+++ b/package.json
@@ -0,0 +1,6 @@
+{
+ "dependencies": {
+ "@google-cloud/local-auth": "^2.1.0",
+ "googleapis": "^105.0.0"
+ }
+}
diff --git a/services/create_rename_trigger.ts b/services/create_rename_trigger.ts
new file mode 100644
index 0000000..1a4ebac
--- /dev/null
+++ b/services/create_rename_trigger.ts
@@ -0,0 +1,42 @@
+import { SlackAPIClient } from "https://deno.land/x/deno_slack_api@2.1.1/types.ts";
+import { TriggerTypes } from "deno-slack-api/mod.ts";
+import { ChannelType } from "../helpers/types.ts";
+
+export const createRenameTrigger = async (channel: ChannelType, client: SlackAPIClient) => {
+
+ const msSchedule = 1000
+ const scheduledTrigger = await client.workflows.triggers.create({
+ name: `Channel Archive Rename Schedule`,
+ workflow: "#/workflows/archive_create_channel",
+ type: TriggerTypes.Scheduled,
+ inputs: {
+ channel_to_archive_id: { value: channel.id },
+ channel_to_create_name: { value: "tikal-" + channel.name },
+ creator: { value: channel.creator },
+ is_private: { value: channel.is_private },
+ },
+ schedule: {
+ // Starts 5 seconds after creation
+ start_time: new Date(new Date().getTime() + msSchedule).toISOString(),
+ timezone: "asia/jerusalem",
+ frequency: {
+ type: "once",
+ },
+ },
+ });
+
+ if (!scheduledTrigger.trigger) {
+ return {
+ error: "Trigger could not be created",
+ };
+ }
+
+ setTimeout(async () => {
+ console.log('Deleting trigger', scheduledTrigger.id);
+ await client.workflows.triggers.delete({
+ trigger_id: scheduledTrigger.id
+ });
+ }, 14000) // Need 15 seconds or less
+
+ console.log("scheduledTrigger has been created");
+}
\ No newline at end of file
diff --git a/services/oauth.js b/services/oauth.js
new file mode 100644
index 0000000..a0a71ef
--- /dev/null
+++ b/services/oauth.js
@@ -0,0 +1,101 @@
+const fs = require('fs').promises;
+const path = require('path');
+const process = require('process');
+const {authenticate} = require('@google-cloud/local-auth');
+const {google} = require('googleapis');
+
+// If modifying these scopes, delete token.json.
+const SCOPES = ['https://www.googleapis.com/auth/admin.directory.user',
+ 'https://www.googleapis.com/auth/admin.directory.group',
+ 'https://www.googleapis.com/auth/admin.directory.group.member',
+ 'https://apps-apis.google.com/a/feeds/groups/',
+ 'https://www.googleapis.com/auth/admin.directory.group.readonly',
+];
+// The file token.json stores the user's access and refresh tokens, and is
+// created automatically when the authorization flow completes for the first
+// time.
+const TOKEN_PATH = path.join(process.cwd(), 'token.json');
+const CREDENTIALS_PATH = path.join(process.cwd(), 'keys/oauth-test.json');
+
+/**
+ * Reads previously authorized credentials from the save file.
+ *
+ * @return {Promise}
+ */
+async function loadSavedCredentialsIfExist() {
+ try {
+ const content = await fs.readFile("/Users/ofer/projects/tikal/slack/welcome-bot-app/tests/token.json");
+ const credentials = JSON.parse(content);
+ return google.auth.fromJSON(credentials);
+ } catch (err) {
+ return null;
+ }
+}
+
+/**
+ * Serializes credentials to a file comptible with GoogleAUth.fromJSON.
+ *
+ * @param {OAuth2Client} client
+ * @return {Promise}
+ */
+async function saveCredentials(client) {
+ const content = await fs.readFile(CREDENTIALS_PATH);
+ const keys = JSON.parse(content);
+ const key = keys.installed || keys.web;
+ const payload = JSON.stringify({
+ type: 'authorized_user',
+ client_id: key.client_id,
+ client_secret: key.client_secret,
+ refresh_token: client.credentials.refresh_token,
+ });
+ await fs.writeFile(TOKEN_PATH, payload);
+}
+
+/**
+ * Load or request or authorization to call APIs.
+ *
+ */
+async function authorize() {
+ let client = await loadSavedCredentialsIfExist();
+ if (client) {
+ return client;
+ }
+ client = await authenticate({
+ scopes: SCOPES,
+ keyfilePath: CREDENTIALS_PATH,
+ });
+ if (client.credentials) {
+ await saveCredentials(client);
+ }
+ return client;
+}
+
+/**
+ * Lists the first 10 users in the domain.
+ *
+ * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
+ */
+async function listUsers(auth) {
+ const service = google.admin({version: 'directory_v1', auth});
+ const res2 = await service.users.list({
+ customer: 'my_customer',
+ maxResults: 10,
+ orderBy: 'email',
+ groupKey: "00zu0gcz2zku8z0"
+ });
+ const res = await service.groups.list({ domain: "tikalk.com" });
+ const res1 = await service.members.list({ domain: "tikalk.com", groupKey: "00zu0gcz2zku8z0", memberKey: "*"});
+ return console.log(res1.data)
+ const users = res.data.users;
+ if (!users || users.length === 0) {
+ console.log('No users found.');
+ return;
+ }
+
+ console.log('Users:');
+ users.forEach((user) => {
+ console.log(`${user.primaryEmail} (${user.name.fullName})`);
+ });
+}
+
+authorize().then(listUsers).catch(console.error);
\ No newline at end of file
diff --git a/services/recently_added.ts b/services/recently_added.ts
new file mode 100644
index 0000000..753a48a
--- /dev/null
+++ b/services/recently_added.ts
@@ -0,0 +1,22 @@
+import { SlackAPIClient } from "https://deno.land/x/deno_slack_sdk@2.1.4/types.ts";
+import { isLessThanHalfAMinuteAgo } from "../helpers/index.ts";
+
+export const getRecentlyAdded = async (client: SlackAPIClient) => {
+ let response;
+ let allChannels: any[] = [];
+
+ // Get all channels
+ while (!response || response.response_metadata?.next_cursor) {
+ response = await client.conversations.list({
+ cursor: response?.response_metadata?.next_cursor,
+ });
+ allChannels = allChannels.concat(response.channels);
+ }
+
+
+ // Filter recent channels
+ const recent = allChannels.filter(isLessThanHalfAMinuteAgo);
+
+
+ return recent;
+}
diff --git a/services/rename_channels.ts b/services/rename_channels.ts
new file mode 100644
index 0000000..b45095c
--- /dev/null
+++ b/services/rename_channels.ts
@@ -0,0 +1,22 @@
+// deno-lint-ignore-file
+import { alertUser } from "./send_message.ts";
+import { ChannelType } from "../helpers/types.ts";
+import { isLegalChannelName } from "../helpers/index.ts"
+import { createRenameTrigger } from "./create_rename_trigger.ts";
+import { SlackAPIClient } from "https://deno.land/x/deno_slack_api@2.1.1/types.ts";
+
+export const renameChannel = async (
+ channel: ChannelType,
+ client: SlackAPIClient,
+) => {
+
+ if (!channel?.is_channel || channel?.is_archived) return;
+
+ const typeOfChannel = channel.is_private ? "private" : "public"
+
+ if (isLegalChannelName(channel.name, typeOfChannel)) return;
+
+ createRenameTrigger(channel, client)
+ await alertUser(channel, typeOfChannel, client)
+
+};
diff --git a/services/send_message.ts b/services/send_message.ts
new file mode 100644
index 0000000..cf2b096
--- /dev/null
+++ b/services/send_message.ts
@@ -0,0 +1,23 @@
+import { SlackAPIClient } from "https://deno.land/x/deno_slack_api@2.1.1/types.ts";
+import { getRenameMessageText } from "../helpers/index.ts"
+import { allowedPrefixes } from "../helpers/prefixes.ts";
+import { ChannelType, allowedPrefixesType } from "../helpers/types.ts";
+
+
+export const alertUser = async (channel: ChannelType, channelType: allowedPrefixesType, client: SlackAPIClient) => {
+
+ const info = await client.users.info({
+ user: channel.creator
+ });
+
+ const text = getRenameMessageText(
+ info.user.real_name,
+ channel.name,
+ allowedPrefixes[channelType],
+ channelType,
+ )
+ await client.chat.postMessage({
+ channel: channel.creator,
+ text
+ });
+}
\ No newline at end of file
diff --git a/services/sync_google_groups.ts b/services/sync_google_groups.ts
new file mode 100644
index 0000000..654bca9
--- /dev/null
+++ b/services/sync_google_groups.ts
@@ -0,0 +1,20 @@
+// deno-lint-ignore-file
+import { SlackAPIClient } from "https://deno.land/x/deno_slack_api@2.1.1/types.ts";
+
+export const syncGoogleGroups = async (client: SlackAPIClient) => {
+ console.log("syncGoogleGroups start")
+
+ // Getting "permission denied" error result
+ const res = await client.usergroups.create({
+ name: `Test User Group`
+ })
+
+ // Same "permission_denied" error for this
+ // const res = await client.usergroups.create({
+ // name: `Test User Group`,
+ // handle: "test-user-group",
+ // team_id: "T02A1ARR8",
+ // channels: "C05R7NMK27R"
+ // })
+ console.log("syncGoogleGroups result: ", res)
+};
diff --git a/slack.json b/slack.json
new file mode 100644
index 0000000..59a554b
--- /dev/null
+++ b/slack.json
@@ -0,0 +1,5 @@
+{
+ "hooks": {
+ "get-hooks": "deno run -q --allow-read --allow-net https://deno.land/x/deno_slack_hooks@1.1.0/mod.ts"
+ }
+}
diff --git a/test b/test
new file mode 100644
index 0000000..e69de29
diff --git a/triggers/channel_created.ts b/triggers/channel_created.ts
new file mode 100644
index 0000000..33d195a
--- /dev/null
+++ b/triggers/channel_created.ts
@@ -0,0 +1,16 @@
+import { Trigger } from "deno-slack-api/types.ts";
+import { TriggerEventTypes, TriggerTypes } from "deno-slack-api/mod.ts";
+import { RenameChannelWorkflow } from "../workflows/rename_channel.ts";
+
+const trigger: Trigger = {
+ type: TriggerTypes.Event,
+ name: "Channel Created",
+ description: "responds to a channel creation",
+ workflow: `#/workflows/${RenameChannelWorkflow.definition.callback_id}`,
+ event: {
+ event_type: TriggerEventTypes.ChannelCreated,
+ },
+ inputs: {},
+};
+
+export default trigger;
diff --git a/triggers/channel_renamed.ts b/triggers/channel_renamed.ts
new file mode 100644
index 0000000..a3f8f9f
--- /dev/null
+++ b/triggers/channel_renamed.ts
@@ -0,0 +1,16 @@
+import { Trigger } from "deno-slack-api/types.ts";
+import { TriggerEventTypes, TriggerTypes } from "deno-slack-api/mod.ts";
+import { RenameChannelWorkflow } from "../workflows/rename_channel.ts";
+
+const trigger: Trigger = {
+ type: TriggerTypes.Event,
+ name: "Channel Created",
+ description: "Responds to a channel renaming",
+ workflow: `#/workflows/${RenameChannelWorkflow.definition.callback_id}`,
+ event: {
+ event_type: TriggerEventTypes.ChannelRenamed,
+ },
+ inputs: {},
+};
+
+export default trigger;
diff --git a/triggers/channel_unarchived.ts b/triggers/channel_unarchived.ts
new file mode 100644
index 0000000..cc85ada
--- /dev/null
+++ b/triggers/channel_unarchived.ts
@@ -0,0 +1,16 @@
+import { Trigger } from "deno-slack-api/types.ts";
+import { TriggerEventTypes, TriggerTypes } from "deno-slack-api/mod.ts";
+import { RenameChannelWorkflow } from "../workflows/rename_channel.ts";
+
+const trigger: Trigger = {
+ type: TriggerTypes.Event,
+ name: "Channel Created",
+ description: "Responds to a channel unarchive",
+ workflow: `#/workflows/${RenameChannelWorkflow.definition.callback_id}`,
+ event: {
+ event_type: TriggerEventTypes.ChannelUnarchived,
+ },
+ inputs: {},
+};
+
+export default trigger;
diff --git a/triggers/google_groups_sync.ts b/triggers/google_groups_sync.ts
new file mode 100644
index 0000000..317973e
--- /dev/null
+++ b/triggers/google_groups_sync.ts
@@ -0,0 +1,24 @@
+// triggers/daily_maintenance_job.ts
+import { Trigger } from "deno-slack-sdk/types.ts";
+import { SyncGoogleGroupsWorkflow } from "../workflows/sync_google_groups.ts";
+import { TriggerTypes } from "deno-slack-api/mod.ts";
+
+const msSchedule = 100
+
+const trigger: Trigger = {
+ type: TriggerTypes.Scheduled,
+ name: "Periodical Google Groups Synce",
+ workflow: `#/workflows/${SyncGoogleGroupsWorkflow.definition.callback_id}`,
+ inputs: {},
+ schedule: {
+ start_time: new Date(new Date().getTime() + msSchedule).toISOString(),
+ end_time: "2037-12-31T23:59:59Z",
+ timezone: "asia/jerusalem",
+ frequency: {
+ type: "hourly",
+ repeats_every: 1,
+ },
+ },
+};
+
+export default trigger;
diff --git a/workflows/archive_create_channel.ts b/workflows/archive_create_channel.ts
new file mode 100644
index 0000000..b9befc0
--- /dev/null
+++ b/workflows/archive_create_channel.ts
@@ -0,0 +1,45 @@
+import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";
+
+// Define a workflow that can pass the parameters for the Slack function
+const ArchiveCreateWorkflow = DefineWorkflow({
+ callback_id: "archive_create_channel",
+ title: "Channel Archiver and Creator",
+ input_parameters: {
+ properties: {
+ channel_to_archive_id: { type: Schema.types.string },
+ channel_to_create_name: { type: Schema.types.string },
+ creator: { type: Schema.types.string },
+ is_private: { type: Schema.types.boolean },
+ },
+ required: [
+ "channel_to_archive_id",
+ "channel_to_create_name",
+ "creator",
+ ],
+ },
+});
+
+ArchiveCreateWorkflow.addStep(
+ Schema.slack.functions.ArchiveChannel,
+ {
+ channel_id: ArchiveCreateWorkflow.inputs.channel_to_archive_id,
+ },
+);
+
+const createChannel = ArchiveCreateWorkflow.addStep(
+ Schema.slack.functions.CreateChannel,
+ {
+ channel_name: ArchiveCreateWorkflow.inputs.channel_to_create_name,
+ is_private: ArchiveCreateWorkflow.inputs.is_private,
+ },
+);
+
+ArchiveCreateWorkflow.addStep(
+ Schema.slack.functions.InviteUserToChannel,
+ {
+ channel_ids: [createChannel.outputs.channel_id],
+ user_ids: [ArchiveCreateWorkflow.inputs.creator],
+ },
+);
+
+export default ArchiveCreateWorkflow;
diff --git a/workflows/rename_channel.ts b/workflows/rename_channel.ts
new file mode 100644
index 0000000..c503161
--- /dev/null
+++ b/workflows/rename_channel.ts
@@ -0,0 +1,14 @@
+import { DefineWorkflow } from "deno-slack-sdk/mod.ts";
+import { RenameChannelFunction } from "../functions/rename_channel.ts";
+
+export const RenameChannelWorkflow = DefineWorkflow({
+ callback_id: "rename_channel",
+ title: "Renames a channel",
+ description: "Renames a channel according to Tikal's naming conventions",
+ input_parameters: {
+ properties: {},
+ required: [],
+ },
+});
+
+RenameChannelWorkflow.addStep(RenameChannelFunction, {});
diff --git a/workflows/sync_google_groups.ts b/workflows/sync_google_groups.ts
new file mode 100644
index 0000000..9659317
--- /dev/null
+++ b/workflows/sync_google_groups.ts
@@ -0,0 +1,14 @@
+import { DefineWorkflow } from "deno-slack-sdk/mod.ts";
+import { SyncGoogleGroupsFunction } from "../functions/sync_google_groups.ts";
+
+export const SyncGoogleGroupsWorkflow = DefineWorkflow({
+ callback_id: "sync_google_groups",
+ title: "Sync Google Groups",
+ description: "Sync google groups with slack groups",
+ input_parameters: {
+ properties: {},
+ required: [],
+ },
+});
+
+SyncGoogleGroupsWorkflow.addStep(SyncGoogleGroupsFunction, {});