Skip to content

Commit 28fe09b

Browse files
committed
...
1 parent cfcb5be commit 28fe09b

11 files changed

+229
-122
lines changed

migrations/versions/2020-03-01T13-23-07Z_0fb0cd1963f2_.py renamed to migrations/versions/2020-03-01T14-13-03Z_85007e55c035_.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
"""empty message
22
3-
Revision ID: 0fb0cd1963f2
3+
Revision ID: 85007e55c035
44
Revises: f261310e6477
5-
Create Date: 2020-03-01 13:23:07.275774+00:00
5+
Create Date: 2020-03-01 14:13:03.449507+00:00
66
77
"""
88
from alembic import op
99
import sqlalchemy as sa
1010
from sqlalchemy.dialects import postgresql
1111

1212
# revision identifiers, used by Alembic.
13-
revision = '0fb0cd1963f2'
13+
revision = '85007e55c035'
1414
down_revision = 'f261310e6477'
1515
branch_labels = None
1616
depends_on = None
@@ -19,11 +19,11 @@
1919
def upgrade():
2020
# ### commands auto generated by Alembic - please adjust! ###
2121
op.create_table('slack_messages',
22-
sa.Column('id', sa.String(), nullable=False),
23-
sa.Column('send_at', sa.DateTime(), nullable=True),
24-
sa.Column('user', sa.String(), nullable=True),
25-
sa.Column('channel', sa.String(), nullable=True),
26-
sa.Column('message', sa.String(), nullable=True),
22+
sa.Column('id', sa.Text(), nullable=False),
23+
sa.Column('send_at', sa.DateTime(timezone=True), nullable=True),
24+
sa.Column('user', sa.Text(), nullable=True),
25+
sa.Column('channel', sa.Text(), nullable=True),
26+
sa.Column('message', sa.Text(), nullable=True),
2727
sa.Column('raw', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
2828
sa.PrimaryKeyConstraint('id')
2929
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""empty message
2+
3+
Revision ID: 33f70e263391
4+
Revises: 85007e55c035
5+
Create Date: 2020-03-01 14:35:27.438645+00:00
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '33f70e263391'
14+
down_revision = '85007e55c035'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table('slack_channels',
22+
sa.Column('id', sa.Text(), nullable=False),
23+
sa.Column('name', sa.Text(), nullable=True),
24+
sa.Column('created', sa.DateTime(timezone=True), nullable=True),
25+
sa.Column('archived', sa.Boolean(), nullable=True),
26+
sa.Column('members', sa.Integer(), nullable=True),
27+
sa.Column('topic', sa.Text(), nullable=True),
28+
sa.Column('purpose', sa.Text(), nullable=True),
29+
sa.PrimaryKeyConstraint('id'),
30+
sa.UniqueConstraint('name')
31+
)
32+
op.create_index('ix_slack_channels_id', 'slack_channels', ['id'], unique=False)
33+
op.create_index('ix_slack_channels_name', 'slack_channels', ['name'], unique=False)
34+
# ### end Alembic commands ###
35+
36+
37+
def downgrade():
38+
# ### commands auto generated by Alembic - please adjust! ###
39+
op.drop_index('ix_slack_channels_name', table_name='slack_channels')
40+
op.drop_index('ix_slack_channels_id', table_name='slack_channels')
41+
op.drop_table('slack_channels')
42+
# ### end Alembic commands ###
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""empty message
2+
3+
Revision ID: e415343a526e
4+
Revises: 33f70e263391
5+
Create Date: 2020-03-01 15:09:28.019455+00:00
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'e415343a526e'
14+
down_revision = '33f70e263391'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table('slack_users',
22+
sa.Column('id', sa.Text(), nullable=False),
23+
sa.Column('name', sa.Text(), nullable=True),
24+
sa.Column('deleted', sa.Boolean(), nullable=True),
25+
sa.Column('admin', sa.Boolean(), nullable=True),
26+
sa.Column('bot', sa.Boolean(), nullable=True),
27+
sa.Column('timezone', sa.Text(), nullable=True),
28+
sa.Column('first_seen', sa.DateTime(timezone=True), nullable=True),
29+
sa.PrimaryKeyConstraint('id'),
30+
sa.UniqueConstraint('name')
31+
)
32+
op.create_index('ix_slack_users_admin', 'slack_users', ['id', 'admin'], unique=False)
33+
op.create_index('ix_slack_users_id', 'slack_users', ['id'], unique=False)
34+
op.create_index('ix_slack_users_name', 'slack_users', ['id', 'name'], unique=False)
35+
op.create_index('ix_slack_users_timezone', 'slack_users', ['timezone'], unique=False)
36+
# ### end Alembic commands ###
37+
38+
39+
def downgrade():
40+
# ### commands auto generated by Alembic - please adjust! ###
41+
op.drop_index('ix_slack_users_timezone', table_name='slack_users')
42+
op.drop_index('ix_slack_users_name', table_name='slack_users')
43+
op.drop_index('ix_slack_users_id', table_name='slack_users')
44+
op.drop_index('ix_slack_users_admin', table_name='slack_users')
45+
op.drop_table('slack_users')
46+
# ### end Alembic commands ###

pyslackersweb/contexts.py

+28-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
import json
22
import datetime
3+
import logging
34

45
from typing import AsyncGenerator
56

67
import aioredis
78
import asyncpgsa
9+
import asyncpg.pool
810

911
from asyncpgsa.connection import get_dialect
1012
from aiohttp import ClientSession, web
1113
from aioredis.abc import AbcConnection
1214
from apscheduler.schedulers.asyncio import AsyncIOScheduler
1315
from slack.io.aiohttp import SlackAPI
16+
from sqlalchemy import select
1417

15-
from . import tasks
18+
from pyslackersweb.util.log import ContextAwareLoggerAdapter
19+
from . import tasks, models
20+
21+
22+
logger = ContextAwareLoggerAdapter(logging.getLogger(__name__))
1623

1724

1825
def _register_in_app(app: web.Application, name: str, item) -> None:
@@ -66,19 +73,34 @@ async def slack_client(app: web.Application) -> AsyncGenerator[None, None]:
6673

6774
async def background_jobs(app: web.Application) -> AsyncGenerator[None, None]:
6875
scheduler = app["scheduler"]
69-
redis: AbcConnection = app["redis"]
76+
pg: asyncpg.pool.Pool = app["pg"]
7077
slack_client_: SlackAPI = app["slack_client"]
7178

72-
# If redis is empty (new dev environments) run the task in one minute
7379
next_run_time = None
74-
if not await redis.exists(tasks.SLACK_ADMIN_CACHE_KEY):
75-
next_run_time = datetime.datetime.now() + datetime.timedelta(minutes=1)
80+
async with pg.acquire() as conn:
81+
result = await conn.fetchval(select([models.SlackUsers.c.id]).limit(1))
82+
if result is None:
83+
next_run_time = datetime.datetime.now() + datetime.timedelta(minutes=1)
7684

7785
scheduler.add_job(
7886
tasks.sync_slack_users,
7987
"cron",
8088
minute=0,
81-
args=(slack_client_, redis),
89+
args=(slack_client_, pg),
90+
next_run_time=next_run_time,
91+
)
92+
93+
next_run_time = None
94+
async with pg.acquire() as conn:
95+
result = await conn.fetchval(select([models.SlackChannels.c.id]).limit(1))
96+
if result is None:
97+
next_run_time = datetime.datetime.now() + datetime.timedelta(minutes=1)
98+
99+
scheduler.add_job(
100+
tasks.sync_slack_channels,
101+
"cron",
102+
minute=15,
103+
args=(slack_client_, pg),
82104
next_run_time=next_run_time,
83105
)
84106

pyslackersweb/models.py

+30
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,33 @@ class Source(Enum):
3030
),
3131
sa.Index("ix_domain_blocked", "domain", "blocked"),
3232
)
33+
34+
SlackChannels = sa.Table(
35+
"slack_channels",
36+
metadata,
37+
sa.Column("id", sa.Text, primary_key=True),
38+
sa.Column("name", sa.Text, unique=True),
39+
sa.Column("created", sa.DateTime(timezone=True)),
40+
sa.Column("archived", sa.Boolean),
41+
sa.Column("members", sa.Integer),
42+
sa.Column("topic", sa.Text),
43+
sa.Column("purpose", sa.Text),
44+
sa.Index("ix_slack_channels_id", "id"),
45+
sa.Index("ix_slack_channels_name", "name"),
46+
)
47+
48+
SlackUsers = sa.Table(
49+
"slack_users",
50+
metadata,
51+
sa.Column("id", sa.Text, primary_key=True),
52+
sa.Column("name", sa.Text, unique=True),
53+
sa.Column("deleted", sa.Boolean),
54+
sa.Column("admin", sa.Boolean),
55+
sa.Column("bot", sa.Boolean),
56+
sa.Column("timezone", sa.Text),
57+
sa.Column("first_seen", sa.DateTime(timezone=True), default=datetime.now),
58+
sa.Index("ix_slack_users_id", "id"),
59+
sa.Index("ix_slack_users_name", "id", "name"),
60+
sa.Index("ix_slack_users_admin", "id", "admin"),
61+
sa.Index("ix_slack_users_timezone", "timezone"),
62+
)

pyslackersweb/sirbot/models.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ class StockQuote:
3232
SlackMessage = sa.Table(
3333
"slack_messages",
3434
metadata,
35-
sa.Column("id", sa.String, primary_key=True),
35+
sa.Column("id", sa.Text, primary_key=True),
3636
sa.Column("send_at", sa.DateTime),
37-
sa.Column("user", sa.String),
38-
sa.Column("channel", sa.String),
39-
sa.Column("message", sa.String),
37+
sa.Column("user", sa.Text),
38+
sa.Column("channel", sa.Text),
39+
sa.Column("message", sa.Text),
4040
sa.Column("raw", JSONB),
4141
sa.Index("ix_slack_messages_user", "user", "send_at"),
4242
sa.Index("ix_slack_messages_channel", "channel", "send_at"),

pyslackersweb/sirbot/slack/messages.py

+17-11
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
import logging
55
import datetime
66

7-
from decimal import Decimal
7+
import asyncpg
88

99
from aiohttp import web, ClientResponseError
10+
from decimal import Decimal
1011
from slack import methods
1112
from slack.exceptions import SlackAPIError
1213
from slack.events import Message
@@ -120,19 +121,24 @@ async def store(request: web.Request, message: Message) -> None:
120121
timestamp, _ = message["ts"].split(".")
121122
send_at = datetime.datetime.fromtimestamp(int(timestamp))
122123

123-
async with request.app["pg"].acquire() as conn:
124-
await conn.execute(pg_insert(models.SlackMessage).values(
125-
id=message["ts"],
126-
send_at=send_at,
127-
user=message["user"],
128-
channel=message["channel"],
129-
message=message["text"],
130-
raw=dict(message),
131-
))
124+
try:
125+
async with request.app["pg"].acquire() as conn:
126+
await conn.execute(pg_insert(models.SlackMessage).values(
127+
id=message["ts"],
128+
send_at=send_at,
129+
user=message.get("user") or message["bot_id"],
130+
channel=message["channel"],
131+
message=message["text"],
132+
raw=dict(message),
133+
))
134+
except asyncpg.exceptions.UniqueViolationError as e:
135+
if "slack_messages_pkey" not in str(e):
136+
raise
137+
132138

133139
async def tell(request: web.Request, message: Message) -> None:
134140
if message.mention:
135-
match = TELL_REGEX.match(message["text"])
141+
match = TELL_REGEX.search(message["text"])
136142
response = message.response()
137143

138144
if match:

pyslackersweb/sirbot/views/slack.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class SlackEventsView(SlackView):
7474

7575
msg_router = slack.events.MessageRouter()
7676
msg_router.register("hello", messages.hello, flags=re.IGNORECASE)
77-
msg_router.register("^tell", messages.tell, flags=re.IGNORECASE)
77+
msg_router.register(messages.TELL_REGEX.pattern, messages.tell, flags=re.IGNORECASE)
7878
msg_router.register(messages.STOCK_REGEX.pattern, messages.stock_quote)
7979

8080
msg_router.register(".*", messages.mention, flags=re.IGNORECASE)

0 commit comments

Comments
 (0)