Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Commit

Permalink
Follow the python template (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
wongjas authored Aug 24, 2022
1 parent 5da1237 commit 41bdef2
Show file tree
Hide file tree
Showing 21 changed files with 434 additions and 157 deletions.
6 changes: 6 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Code owners are the default owners for everything in
# this repository. The owners listed below will be requested for
# review when a pull request is opened.
# To add code owner(s), uncomment the line below and
# replace the @global-owner users with their GitHub username(s).
* @wongjas
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "monthly"
labels:
- "pip"
- "dependencies"
30 changes: 30 additions & 0 deletions .github/workflows/black.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Formatting validation using black

on:
push:
branches: [ main ]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
matrix:
python-version: ['3.9']

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install -U pip
# We manually upgrade it to make the builds stable
pip install black==22.3.0
- name: Format with black
run: |
black .
if git status --porcelain | grep .; then git --no-pager diff; exit 1; fi
29 changes: 29 additions & 0 deletions .github/workflows/flake8.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Linting validation using flake8

on:
push:
branches: [ main ]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
matrix:
python-version: ['3.9']

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install -U pip
# We manually upgrade it to make the builds stable
pip install flake8==4.0.1
- name: Lint with flake8
run: |
flake8 *.py && flake8 listeners/
4 changes: 2 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Slack Platform Sample Code
Copyright (c) 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
Expand All @@ -18,4 +18,4 @@ 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.
SOFTWARE.
108 changes: 105 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,108 @@
# news-api-for-slack
A sample Slack app to send news articles into Slack.
# Bolt for Python News API App

For the full details on how this project works, check out the article on the Slack API site: https://api.slack.com/tutorials/news-in-slack.
This is a sample Slack app that sends news articles into Slack.

![news-full-gif](https://user-images.githubusercontent.com/1818355/182757792-53223931-7f8d-4543-a15e-5b7699283d18.gif)

For the full details on how this project works, check out the [tutorial](https://api.slack.com/tutorials/news-in-slack) on the Slack API site. Otherwise, continue reading.

日本の方はこちらの記事をご覧ください:https://qiita.com/hello_jun/items/418cca89c52eea13a3fa

## Installation

#### Creating and setting up your Slack App

1. Open [https://api.slack.com/apps/new](https://api.slack.com/apps/new) and choose "From an app manifest"
2. Choose the workspace you want to install the application to
3. Copy the contents of [manifest.json](./manifest.json) into the text box that says `*Paste your manifest code here*` (within the JSON tab) and click *Next*
4. Review the configuration and click *Create*
6. Click *Install to Workspace* and *Allow* on the screen that follows. You'll then be redirected to the App Configuration dashboard.

#### Environment Variables
Before you can run the app, you'll need to store some environment variables.

1. Open your apps configuration page from this list, click **OAuth & Permissions** in the left hand menu, then copy the Bot User OAuth Token. You will store this in your environment as `SLACK_BOT_TOKEN`.
2. Click ***Basic Information** from the left hand menu and follow the steps in the App-Level Tokens section to create an app-level token with the `connections:write` scope. Copy this token. You will store this in your environment as `SLACK_APP_TOKEN`.
3. Retrieve your News API key, which can be done for free if you are creating an app for development purposes. On the [sign up page](https://newsapi.org/register), fill in your name, e-mail address, and password, then choose "I am an individual" and submit the form. You will be granted an API key. Store this as the `NEWS_API_KEY` environment variable.

```zsh
# Replace the sections in brackets with your tokens and keys
export SLACK_BOT_TOKEN=<your-bot-token>
export SLACK_APP_TOKEN=<your-app-token>
export NEWS_API_KEY=<your-api-key>
```

### Setup Your Local Project
```zsh
# Clone this project onto your machine
git clone https://github.com/slack-samples/bolt-python-news-api-for-slack.git

# Change into this project directory
cd bolt-python-news-api-for-slack

# Setup your python virtual environment
python3 -m venv .venv
source .venv/bin/activate

# Install the dependencies
pip install -r requirements.txt

# Start your local server
python3 app.py
```

#### Linting
```zsh
# Run flake8 from root directory for linting
flake8 *.py && flake8 listeners/
# Run black from root directory for code formatting
black .
```

## Project Structure

### `manifest.json`

`manifest.json` is a configuration for Slack apps. With a manifest, you can create an app with a pre-defined configuration, or adjust the configuration of an existing app.

### `app.py`

`app.py` is the entry point for the application and is the file you'll run to start the server. This project aims to keep this file as thin as possible, primarily using it as a way to route inbound requests.

### `/listeners/steps`

Every incoming request is routed to a "listener". Inside this directory, you'll find the `workflow_step.py` file, which defines all the callback functions required to implement a [Steps from Apps](https://api.slack.com/workflows/steps) step.

### `/utils`

#### `/utils/articles.py`

Contains class definitions that make the rest of the project code cleaner.

#### `/utils/news_fetcher.py`

Utility class that deals with interactions with the NewsAPI

## App Distribution / OAuth

Only implement OAuth if you plan to distribute your application across multiple workspaces. A separate `app-oauth.py` file can be found with relevant OAuth settings.

When using OAuth, Slack requires a public URL where it can send requests. In this template app, we've used [`ngrok`](https://ngrok.com/download). Checkout [this guide](https://ngrok.com/docs#getting-started-expose) for setting it up.

Start `ngrok` to access the app on an external network and create a redirect URL for OAuth.

```
ngrok http 3000
```

This output should include a forwarding address for `http` and `https` (we'll use `https`). It should look something like the following:

```
Forwarding https://3cb89939.ngrok.io -> http://localhost:3000
```

Navigate to **OAuth & Permissions** in your app configuration and click **Add a Redirect URL**. The redirect URL should be set to your `ngrok` forwarding address with the `slack/oauth_redirect` path appended. For example:

```
https://3cb89939.ngrok.io/slack/oauth_redirect
```
20 changes: 11 additions & 9 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import logging
import os
import logging

from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler

from workflow_step import enable_workflow_step

logging.basicConfig(level=logging.DEBUG)

newsapi_api_key = os.environ["NEWS_API_KEY"]
from listeners import register_listeners
from utils.news_fetcher import NewsFetcher

# Initialization
app = App(token=os.environ.get("SLACK_BOT_TOKEN"))
news_api_key = os.environ["NEWS_API_KEY"]
logging.basicConfig(level=logging.DEBUG)

enable_workflow_step(app, newsapi_api_key)

# Register Listeners
register_listeners(app, NewsFetcher(news_api_key))

# Start Bolt app
if __name__ == "__main__":
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
SocketModeHandler(app, os.environ.get("SLACK_APP_TOKEN")).start()
50 changes: 50 additions & 0 deletions app_oauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import logging
import os
from slack_bolt import App, BoltResponse
from slack_bolt.oauth.callback_options import CallbackOptions, SuccessArgs, FailureArgs
from slack_bolt.oauth.oauth_settings import OAuthSettings

from slack_sdk.oauth.installation_store import FileInstallationStore
from slack_sdk.oauth.state_store import FileOAuthStateStore

from listeners import register_listeners

logging.basicConfig(level=logging.DEBUG)


# Callback to run on successful installation
def success(args: SuccessArgs) -> BoltResponse:
# Call default handler to return an HTTP response
return args.default.success(args)
# return BoltResponse(status=200, body="Installation successful!")


# Callback to run on failed installation
def failure(args: FailureArgs) -> BoltResponse:
return args.default.failure(args)
# return BoltResponse(status=args.suggested_status_code, body=args.reason)


# Initialization
app = App(
signing_secret=os.environ.get("SLACK_SIGNING_SECRET"),
installation_store=FileInstallationStore(),
oauth_settings=OAuthSettings(
client_id=os.environ.get("SLACK_CLIENT_ID"),
client_secret=os.environ.get("SLACK_CLIENT_SECRET"),
scopes=["channels:history", "chat:write", "commands"],
user_scopes=[],
redirect_uri=None,
install_path="/slack/install",
redirect_uri_path="/slack/oauth_redirect",
state_store=FileOAuthStateStore(expiration_seconds=600),
callback_options=CallbackOptions(success=success, failure=failure),
),
)

# Register Listeners
register_listeners(app)

# Start Bolt app
if __name__ == "__main__":
app.start(3000)
97 changes: 0 additions & 97 deletions articles.py

This file was deleted.

8 changes: 8 additions & 0 deletions listeners/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from slack_bolt import App

from listeners import steps
from utils.news_fetcher import NewsFetcher


def register_listeners(app: App, news_fetcher: NewsFetcher):
steps.register(app, news_fetcher)
Loading

0 comments on commit 41bdef2

Please sign in to comment.