{"id":18326843,"url":"https://github.com/franzdiebold/where-is-rudi","last_synced_at":"2025-06-15T21:32:49.905Z","repository":{"id":109041722,"uuid":"208615619","full_name":"FranzDiebold/where-is-rudi","owner":"FranzDiebold","description":"WhereIsRudi 🐶 is an interactive Slack app to inform your colleagues whether your dog@work is in the office today! 🎉","archived":false,"fork":false,"pushed_at":"2020-02-24T06:41:32.000Z","size":2934,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-06T01:32:17.587Z","etag":null,"topics":["github-actions","google-cloud-datastore","google-cloud-function","google-cloud-platform","google-cloud-scheduler","python3","slack","slack-api","slack-app","slack-slash-command","terraform"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FranzDiebold.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-15T15:35:43.000Z","updated_at":"2025-02-12T14:43:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"4fa7de32-03f2-4c22-9551-c42da2225552","html_url":"https://github.com/FranzDiebold/where-is-rudi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/FranzDiebold/where-is-rudi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzDiebold%2Fwhere-is-rudi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzDiebold%2Fwhere-is-rudi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzDiebold%2Fwhere-is-rudi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzDiebold%2Fwhere-is-rudi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FranzDiebold","download_url":"https://codeload.github.com/FranzDiebold/where-is-rudi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzDiebold%2Fwhere-is-rudi/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260053191,"owners_count":22951832,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github-actions","google-cloud-datastore","google-cloud-function","google-cloud-platform","google-cloud-scheduler","python3","slack","slack-api","slack-app","slack-slash-command","terraform"],"created_at":"2024-11-05T19:08:23.202Z","updated_at":"2025-06-15T21:32:49.883Z","avatar_url":"https://github.com/FranzDiebold.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WhereIsRudi :dog:\n\n[![app:slack](https://img.shields.io/badge/app-Slack-611f69.svg)](https://slack.com)\n[![technology: Google Cloud Platform](https://img.shields.io/badge/technology-Google_Cloud_Platform-1a73e8.svg)](https://cloud.google.com)\n[![IaC: Terraform](https://img.shields.io/badge/IaC-Terraform-5c4ee5.svg)](./deployment/main.tf)\n[![Lint Status](https://github.com/FranzDiebold/where-is-rudi/workflows/Lint/badge.svg)](https://github.com/FranzDiebold/where-is-rudi/actions?query=workflow%3A%22Lint%22)\n[![license: MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](./LICENSE.md)\n\n\u003cimg src=\"./design/WhereIsRudi_logo.png\" width=\"300px\"\u003e\n\n*WhereIsRudi* is an interactive [Slack](https://slack.com) app to inform your colleagues whether your dog@work is in the office today! :tada:\n\n\n## Usage\n\n### Colleagues\n\n![Slack Example Colleagues](./images/slack-example-colleagues.gif)\n\nUse the [Slash Command](https://api.slack.com/slash-commands) `\\whereisrudi` in any channel, direct message or any other slack conversation. That's it!\n\n### Dog Owner\n\n![Slack Example Dog Owner](./images/slack-example-dog-owner.png)\n\nYou will get a message every (working day) morning to ask you whether you bring your dog to the office today. Just answer with one tap or click via the actions in the message. It's that easy!\n\n\n## Architecture \u0026 Sequence\n\n![WhereIsRudi architecture](./images/WhereIsRudi_architecture.jpg)\n\n\n## Linting\n\nLocal linting may be done using the Makefile:\n\n```shell\nmake install\nmake lint\n```\n\n\n## Deployment\n\nFor easier deployment, the *infrastructure as code* (IaC) software tool [Terraform](https://www.terraform.io/) is used.\n\n#### Preparations\n\n1. Install Terraform: [https://learn.hashicorp.com/terraform/getting-started/install.html](https://learn.hashicorp.com/terraform/getting-started/install.html)\n2. Define a Google Cloud Platform (GCP) project id, i.e. `whereisrudi-\u003crandom_number\u003e` and enter it in:\n    - [`deployment/prepare_gcp.sh`](./deployment/prepare_gcp.sh)\n    - [`deployment/variables.tf`](./deployment/variables.tf)\n3. Run preparation script:\n    1. Run `prepare_gcp.sh`: `bash prepare_gcp.sh`. You may run this in the [Google Cloud Shell editor](https://ssh.cloud.google.com/cloudshell/editor). This will:\n        - Create a Google Cloud Platform project.\n        - Create Service Account and bind the roles `roles/owner`, `roles/iam.serviceAccountUser`, `roles/storage.admin`, `roles/appengine.appAdmin`, `roles/cloudscheduler.admin`, `roles/pubsub.editor` and `roles/cloudfunctions.developer`.\n        - Create new private key for the Service Account and save in the file `account.json`.\n        - Enable the Google Cloud Platform APIs `appengine`, `cloudfunctions`, `cloudscheduler` and `datastore`.\n        - You will be asked to enable billing for the created project when running the script.\n    2. Copy the file `account.json` into the `deployment` folder.\n\n#### Deployment\n\n1. Commands need to be run in `deployment` folder: `cd /deployment`\n2. Initialize the Terraform working directory: `terraform init`\n3. Generate and show the Terraform execution plan: `terraform plan`\n4. Build the infrastructure: `terraform apply` and confirm with `yes`. This step will output the endpoint URLs `slack_actions_function_url` and `slack_slash_commands_function_url` that you need to enter in the Slack API console.\n\nTo destroy/delete the infrastructure: `terraform destroy` and confirm with `yes`\n\n### Google Cloud Platform Resources\n\nThe following [Google Cloud Platform](https://console.cloud.google.com) resources are created via Terraform:\n\n#### Google Cloud Function\n\n![Google Cloud Functions](./images/google-cloud-functions.png)\n\nThree cloud functions with environment variables:\n- `gather-information` (triggered by Google Pub/Sub topic `gather-information-schedule`)\n    - `SLACK_API_TOKEN`: Slack App *OAuth Access Token* (starting with `xoxp-`)\n    - `USER_ID`: Slack user id of dog owner.\n- `slack-actions` (triggered by HTTP)\n    - `SLACK_API_VERIFICATION_TOKEN`: Slack App Verification Token\n- `slack-slash-commands` (triggered by HTTP)\n    - `SLACK_API_VERIFICATION_TOKEN`: Slack App Verification Token\n\n#### Google Cloud Scheduler\n\n![Google Cloud Scheduler](./images/google-cloud-scheduler.png)\n\nGoogle Pub/Sub topic `gather-information-schedule` should be triggered every working day (monday - friday) at 7:30 AM.\n\nTherefore the frequency is set to `30 7 * * 1-5`.\n\n#### Google Cloud Datastore / Google Cloud Firestore Datastore Mode\n\n![Google Cloud Datastore](./images/google-cloud-datastore.png)\n\nThe cloud functions create a entities of kind `days`. The entity id is the day string (i.e. `2019-09-14`). The entities only have one boolean field `in_office`, which is not indexed.\n\n### Slack API/App\n\n#### Slack App\n\nCreate a new Slack app in the Slack API console: [https://api.slack.com/apps](https://api.slack.com/apps).\n\n#### Bot User\n\n![Slack API Bot User](./images/slack-api-bot-user.png)\n\nCreate a Bot User, i.e. `WhereIsRudi`.\n\n#### OAuth \u0026 Permissions\n\n![Slack API Permissions](./images/slack-api-permissions.png)\n\nIn OAuth \u0026 Permissions in Scopes, add permission scope `chat:write:bot` and `incoming-webhook` to *Conversations* and `bot` and `commands` to *Interactivity*.\n\n#### Interactive Components\n\n![Slack API Actions](./images/slack-api-actions.png)\n\nAdd Interactivity request URL pointing to your Google Cloud Function `slack-actions`. You got this URL as output from the `terraform apply` step before, named `slack_actions_function_url`.\n\n#### Slash Commands\n\n![Slack API Slash Commands 1](./images/slack-api-slash-commands-1.png)\n\n![Slack API Slash Commands 2](./images/slack-api-slash-commands-2.png)\n\nCreate new Slash command `/whereisrudi` with request URL pointing to your Google Cloud Function `slack-slash-commands`. You got this URL as output from the `terraform apply` step before, named `slack_slash_commands_function_url`.\n\n\n## Design\n\nSee [/design](./design/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranzdiebold%2Fwhere-is-rudi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffranzdiebold%2Fwhere-is-rudi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranzdiebold%2Fwhere-is-rudi/lists"}