Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/django/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
db.sqlite3
db.sqlite3
db/
16 changes: 16 additions & 0 deletions examples/django/mysql-docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3.9'
services:
db:
image: mysql:8
environment:
MYSQL_DATABASE: slackapp
MYSQL_USER: app
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
#command:
# - '--wait_timeout=3'
volumes:
- './db:/var/lib/mysql'
ports:
- 33306:3306

34 changes: 17 additions & 17 deletions examples/django/slackapp/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 3.1.4 on 2020-12-04 13:07
# Generated by Django 3.1.7 on 2021-04-02 05:53

from django.db import migrations, models

Expand All @@ -22,15 +22,15 @@ class Migration(migrations.Migration):
verbose_name="ID",
),
),
("client_id", models.TextField()),
("app_id", models.TextField()),
("enterprise_id", models.TextField(null=True)),
("client_id", models.CharField(max_length=32)),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For MySQL compatibility, I've changed the database schema for this example app

("app_id", models.CharField(max_length=32)),
("enterprise_id", models.CharField(max_length=32, null=True)),
("enterprise_name", models.TextField(null=True)),
("team_id", models.TextField(null=True)),
("team_id", models.CharField(max_length=32, null=True)),
("team_name", models.TextField(null=True)),
("bot_token", models.TextField(null=True)),
("bot_id", models.TextField(null=True)),
("bot_user_id", models.TextField(null=True)),
("bot_id", models.CharField(max_length=32, null=True)),
("bot_user_id", models.CharField(max_length=32, null=True)),
("bot_scopes", models.TextField(null=True)),
("is_enterprise_install", models.BooleanField(null=True)),
("installed_at", models.DateTimeField()),
Expand All @@ -48,26 +48,26 @@ class Migration(migrations.Migration):
verbose_name="ID",
),
),
("client_id", models.TextField()),
("app_id", models.TextField()),
("enterprise_id", models.TextField(null=True)),
("client_id", models.CharField(max_length=32)),
("app_id", models.CharField(max_length=32)),
("enterprise_id", models.CharField(max_length=32, null=True)),
("enterprise_name", models.TextField(null=True)),
("enterprise_url", models.TextField(null=True)),
("team_id", models.TextField(null=True)),
("team_id", models.CharField(max_length=32, null=True)),
("team_name", models.TextField(null=True)),
("bot_token", models.TextField(null=True)),
("bot_id", models.TextField(null=True)),
("bot_id", models.CharField(max_length=32, null=True)),
("bot_user_id", models.TextField(null=True)),
("bot_scopes", models.TextField(null=True)),
("user_id", models.TextField()),
("user_id", models.CharField(max_length=32)),
("user_token", models.TextField(null=True)),
("user_scopes", models.TextField(null=True)),
("incoming_webhook_url", models.TextField(null=True)),
("incoming_webhook_channel", models.TextField(null=True)),
("incoming_webhook_channel_id", models.TextField(null=True)),
("incoming_webhook_configuration_url", models.TextField(null=True)),
("is_enterprise_install", models.BooleanField(null=True)),
("token_type", models.TextField(null=True)),
("token_type", models.CharField(max_length=32, null=True)),
("installed_at", models.DateTimeField()),
],
),
Expand All @@ -83,7 +83,7 @@ class Migration(migrations.Migration):
verbose_name="ID",
),
),
("state", models.TextField()),
("state", models.CharField(max_length=64)),
("expire_at", models.DateTimeField()),
],
),
Expand All @@ -97,14 +97,14 @@ class Migration(migrations.Migration):
"user_id",
"installed_at",
],
name="bolt_slacki_client__62c411_idx",
name="slackapp_sl_client__9b0d3f_idx",
),
),
migrations.AddIndex(
model_name="slackbot",
index=models.Index(
fields=["client_id", "enterprise_id", "team_id", "installed_at"],
name="bolt_slackb_client__be066b_idx",
name="slackapp_sl_client__d220d6_idx",
),
),
]
67 changes: 47 additions & 20 deletions examples/django/slackapp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@


class SlackBot(models.Model):
client_id = models.TextField(null=False)
app_id = models.TextField(null=False)
enterprise_id = models.TextField(null=True)
client_id = models.CharField(null=False, max_length=32)
app_id = models.CharField(null=False, max_length=32)
enterprise_id = models.CharField(null=True, max_length=32)
enterprise_name = models.TextField(null=True)
team_id = models.TextField(null=True)
team_id = models.CharField(null=True, max_length=32)
team_name = models.TextField(null=True)
bot_token = models.TextField(null=True)
bot_id = models.TextField(null=True)
bot_user_id = models.TextField(null=True)
bot_id = models.CharField(null=True, max_length=32)
bot_user_id = models.CharField(null=True, max_length=32)
bot_scopes = models.TextField(null=True)
is_enterprise_install = models.BooleanField(null=True)
installed_at = models.DateTimeField(null=False)
Expand All @@ -28,26 +28,26 @@ class Meta:


class SlackInstallation(models.Model):
client_id = models.TextField(null=False)
app_id = models.TextField(null=False)
enterprise_id = models.TextField(null=True)
client_id = models.CharField(null=False, max_length=32)
app_id = models.CharField(null=False, max_length=32)
enterprise_id = models.CharField(null=True, max_length=32)
enterprise_name = models.TextField(null=True)
enterprise_url = models.TextField(null=True)
team_id = models.TextField(null=True)
team_id = models.CharField(null=True, max_length=32)
team_name = models.TextField(null=True)
bot_token = models.TextField(null=True)
bot_id = models.TextField(null=True)
bot_id = models.CharField(null=True, max_length=32)
bot_user_id = models.TextField(null=True)
bot_scopes = models.TextField(null=True)
user_id = models.TextField(null=False)
user_id = models.CharField(null=False, max_length=32)
user_token = models.TextField(null=True)
user_scopes = models.TextField(null=True)
incoming_webhook_url = models.TextField(null=True)
incoming_webhook_channel = models.TextField(null=True)
incoming_webhook_channel_id = models.TextField(null=True)
incoming_webhook_configuration_url = models.TextField(null=True)
is_enterprise_install = models.BooleanField(null=True)
token_type = models.TextField(null=True)
token_type = models.CharField(null=True, max_length=32)
installed_at = models.DateTimeField(null=False)

class Meta:
Expand All @@ -65,7 +65,7 @@ class Meta:


class SlackOAuthState(models.Model):
state = models.TextField(null=False)
state = models.CharField(null=False, max_length=64)
expire_at = models.DateTimeField(null=False)


Expand All @@ -81,6 +81,7 @@ class SlackOAuthState(models.Model):
from django.utils import timezone
from slack_sdk.oauth import InstallationStore, OAuthStateStore
from slack_sdk.oauth.installation_store import Bot, Installation
from slack_sdk.webhook import WebhookClient


class DjangoInstallationStore(InstallationStore):
Expand All @@ -100,9 +101,13 @@ def logger(self) -> Logger:

def save(self, installation: Installation):
i = installation.to_dict()
if is_naive(i["installed_at"]):
i["installed_at"] = make_aware(i["installed_at"])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an improvement for MySQL apps.

i["client_id"] = self.client_id
SlackInstallation(**i).save()
b = installation.to_bot().to_dict()
if is_naive(b["installed_at"]):
b["installed_at"] = make_aware(b["installed_at"])
b["client_id"] = self.client_id
SlackBot(**b).save()

Expand Down Expand Up @@ -222,7 +227,7 @@ def consume(self, state: str) -> bool:

import logging
import os
from slack_bolt import App
from slack_bolt import App, BoltContext
from slack_bolt.oauth.oauth_settings import OAuthSettings

logger = logging.getLogger(__name__)
Expand All @@ -249,12 +254,34 @@ def consume(self, state: str) -> bool:
)


@app.event("app_mention")
def event_test(body, say, logger):
def event_test(body, say, context: BoltContext, logger):
logger.info(body)
say("What's up?")
say(":wave: What's up?")

found_rows = list(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no thread-bound database connection when first access to any Django models, Django automatically establishes a new connection and associates it with the thread. This example demonstrates the situation where a listener performs a database query using Django ORM in a different thread (=thread managed by Bolt, not Django).

SlackInstallation.objects.filter(enterprise_id=context.enterprise_id)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no thread-bound database connection when first access to any Django models, Django automatically establishes a new connection and associates it with the thread. This example demonstrates the situation where a listener performs a database query using Django ORM in a different thread (=thread managed by Bolt, not Django).

.filter(team_id=context.team_id)
.filter(incoming_webhook_url__isnull=False)
.order_by(F("installed_at").desc())[:1]
)
if len(found_rows) > 0:
webhook_url = found_rows[0].incoming_webhook_url
logger.info(f"webhook_url: {webhook_url}")
client = WebhookClient(webhook_url)
client.send(text=":wave: This is a message posted using Incoming Webhook!")


# lazy listener example
def noop():
pass


app.event("app_mention")(
ack=event_test,
lazy=[noop],
)


@app.command("/hello-bolt-python")
@app.command("/hello-django-app")
def command(ack):
ack("This is a Django app!")
ack(":wave: Hello from a Django app :smile:")
25 changes: 20 additions & 5 deletions examples/django/slackapp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
},
"root": {
"handlers": ["console"],
"level": "INFO",
"level": "DEBUG",
},
"loggers": {
"django": {
"handlers": ["console"],
"level": os.getenv("DJANGO_LOG_LEVEL", "INFO"),
"propagate": False,
},
"django.db.backends": {
"django.db": {
"level": "DEBUG",
},
"slack_bolt": {
Expand Down Expand Up @@ -105,10 +105,25 @@
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
# python manage.py migrate
# python manage.py runserver 0.0.0.0:3000
# "default": {
# "ENGINE": "django.db.backends.sqlite3",
# "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
# },

# docker-compose -f mysql-docker-compose.yml up --build
# pip install mysqlclient
# python manage.py migrate
# python manage.py runserver 0.0.0.0:3000
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
"ENGINE": "django.db.backends.mysql",
"NAME": "slackapp",
"USER": "app",
"PASSWORD": "password",
"HOST": "127.0.0.1",
"PORT": 33306,
},
}

# Password validation
Expand Down
Loading