Skip to content

Commit 3235d5d

Browse files
committed
...
1 parent 28fe09b commit 3235d5d

File tree

9 files changed

+192
-133
lines changed

9 files changed

+192
-133
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""empty message
2+
3+
Revision ID: 0e1a38cb0c07
4+
Revises: e415343a526e
5+
Create Date: 2020-03-01 15:55:15.785725+00:00
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '0e1a38cb0c07'
14+
down_revision = 'e415343a526e'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.drop_index('ix_slack_users_timezone', table_name='slack_users')
22+
op.create_index('ix_slack_users_timezone', 'slack_users', ['id', 'timezone'], unique=False)
23+
# ### end Alembic commands ###
24+
25+
26+
def downgrade():
27+
# ### commands auto generated by Alembic - please adjust! ###
28+
op.drop_index('ix_slack_users_timezone', table_name='slack_users')
29+
op.create_index('ix_slack_users_timezone', 'slack_users', ['timezone'], unique=False)
30+
# ### end Alembic commands ###

pyslackersweb/contexts.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
import aioredis
88
import asyncpgsa
99
import asyncpg.pool
10+
import sqlalchemy as sa
1011

1112
from asyncpgsa.connection import get_dialect
1213
from aiohttp import ClientSession, web
13-
from aioredis.abc import AbcConnection
1414
from apscheduler.schedulers.asyncio import AsyncIOScheduler
1515
from slack.io.aiohttp import SlackAPI
1616
from sqlalchemy import select
@@ -77,10 +77,8 @@ async def background_jobs(app: web.Application) -> AsyncGenerator[None, None]:
7777
slack_client_: SlackAPI = app["slack_client"]
7878

7979
next_run_time = None
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)
80+
if await _is_empty_table(pg, models.SlackUsers.c.id):
81+
next_run_time = datetime.datetime.now() + datetime.timedelta(minutes=1)
8482

8583
scheduler.add_job(
8684
tasks.sync_slack_users,
@@ -91,10 +89,8 @@ async def background_jobs(app: web.Application) -> AsyncGenerator[None, None]:
9189
)
9290

9391
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)
92+
if await _is_empty_table(pg, models.SlackChannels.c.id):
93+
next_run_time = datetime.datetime.now() + datetime.timedelta(minutes=1)
9894

9995
scheduler.add_job(
10096
tasks.sync_slack_channels,
@@ -105,3 +101,9 @@ async def background_jobs(app: web.Application) -> AsyncGenerator[None, None]:
105101
)
106102

107103
yield
104+
105+
106+
async def _is_empty_table(pg: asyncpg.pool.Pool, column: sa.Column) -> bool:
107+
async with pg.acquire() as conn:
108+
result = await conn.fetchval(select([column]).limit(1))
109+
return result is None

pyslackersweb/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,5 @@ class Source(Enum):
5858
sa.Index("ix_slack_users_id", "id"),
5959
sa.Index("ix_slack_users_name", "id", "name"),
6060
sa.Index("ix_slack_users_admin", "id", "admin"),
61-
sa.Index("ix_slack_users_timezone", "timezone"),
61+
sa.Index("ix_slack_users_timezone", "id", "timezone"),
6262
)

pyslackersweb/sirbot/database.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import logging
2+
3+
import asyncpg
4+
import sqlalchemy as sa
5+
6+
from pyslackersweb import models
7+
from pyslackersweb.util.log import ContextAwareLoggerAdapter
8+
9+
10+
logger = ContextAwareLoggerAdapter(logging.getLogger(__name__))
11+
12+
13+
async def is_admin(conn: asyncpg.connection.Connection, user: str) -> bool:
14+
return await conn.fetchval(sa.select([models.SlackUsers.c.admin]).where(id=user))

pyslackersweb/sirbot/slack/events.py

+46-48
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
from slack import methods
77
from slack.events import Message, Event
88

9-
from pyslackersweb.sirbot import settings
10-
from pyslackersweb.tasks import SLACK_ADMIN_CACHE_KEY
9+
from pyslackersweb.sirbot import settings, database
1110
from pyslackersweb.util.log import ContextAwareLoggerAdapter
1211

1312
logger = ContextAwareLoggerAdapter(logging.getLogger(__name__))
@@ -35,53 +34,52 @@ async def team_join(request: web.Request, event: Event) -> None:
3534

3635

3736
async def pin_added(request: web.Request, event: Event) -> None:
37+
async with request.app["pg"].acquire() as conn:
38+
if database.is_admin(conn, event["user"]):
39+
return
3840

39-
if event["user"] not in (
40-
await request.app["redis"].get(SLACK_ADMIN_CACHE_KEY, encoding="utf-8")
41-
):
42-
43-
message = Message()
44-
message["channel"] = settings.SLACK_ADMIN_CHANNEL
45-
message["attachments"] = [
46-
{
47-
"fallback": "Pin added notice",
48-
"title": f'Pin added in channel <#{event["channel_id"]}> by <@{event["user"]}>',
49-
"callback_id": "pin_added",
50-
}
51-
]
41+
message = Message()
42+
message["channel"] = settings.SLACK_ADMIN_CHANNEL
43+
message["attachments"] = [
44+
{
45+
"fallback": "Pin added notice",
46+
"title": f'Pin added in channel <#{event["channel_id"]}> by <@{event["user"]}>',
47+
"callback_id": "pin_added",
48+
}
49+
]
5250

53-
if event["item"]["type"] == "message":
54-
message["attachments"][0]["text"] = event["item"]["message"]["text"]
55-
item_id = event["item"]["message"]["ts"]
56-
elif event["item"]["type"] == "file":
57-
file = await request.app["slack_client"].query(
58-
url=methods.FILES_INFO, data={"file": event["item"]["file_id"]}
59-
)
60-
message["attachments"][0]["text"] = f'File: {file["file"]["title"]}'
61-
item_id = event["item"]["file_id"]
62-
elif event["item"]["type"] == "file_comment":
63-
message["attachments"][0]["text"] = event["item"]["comment"]["comment"]
64-
item_id = event["item"]["comment"]["id"]
65-
else:
66-
message["attachments"][0]["text"] = "Unknown pin type"
67-
await request.app["slack_client"].api.query(url=methods.CHAT_POST_MESSAGE, data=message)
68-
return
51+
if event["item"]["type"] == "message":
52+
message["attachments"][0]["text"] = event["item"]["message"]["text"]
53+
item_id = event["item"]["message"]["ts"]
54+
elif event["item"]["type"] == "file":
55+
file = await request.app["slack_client"].query(
56+
url=methods.FILES_INFO, data={"file": event["item"]["file_id"]}
57+
)
58+
message["attachments"][0]["text"] = f'File: {file["file"]["title"]}'
59+
item_id = event["item"]["file_id"]
60+
elif event["item"]["type"] == "file_comment":
61+
message["attachments"][0]["text"] = event["item"]["comment"]["comment"]
62+
item_id = event["item"]["comment"]["id"]
63+
else:
64+
message["attachments"][0]["text"] = "Unknown pin type"
65+
await request.app["slack_client"].api.query(url=methods.CHAT_POST_MESSAGE, data=message)
66+
return
6967

70-
message["attachments"][0]["actions"] = [
71-
{"name": "validate", "text": "Validate", "style": "primary", "type": "button",},
72-
{
73-
"name": "revert",
74-
"text": "Revert",
75-
"style": "danger",
76-
"value": json.dumps(
77-
{
78-
"channel": event["channel_id"],
79-
"item_type": event["item"]["type"],
80-
"item_id": item_id,
81-
}
82-
),
83-
"type": "button",
84-
},
85-
]
68+
message["attachments"][0]["actions"] = [
69+
{"name": "validate", "text": "Validate", "style": "primary", "type": "button",},
70+
{
71+
"name": "revert",
72+
"text": "Revert",
73+
"style": "danger",
74+
"value": json.dumps(
75+
{
76+
"channel": event["channel_id"],
77+
"item_type": event["item"]["type"],
78+
"item_id": item_id,
79+
}
80+
),
81+
"type": "button",
82+
},
83+
]
8684

87-
await request.app["slack_client"].query(url=methods.CHAT_POST_MESSAGE, data=message)
85+
await request.app["slack_client"].query(url=methods.CHAT_POST_MESSAGE, data=message)

pyslackersweb/sirbot/slack/messages.py

+38-40
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
from slack.events import Message
1414
from sqlalchemy.dialects.postgresql import insert as pg_insert
1515

16-
from pyslackersweb.sirbot import settings, models
17-
from pyslackersweb.tasks import SLACK_ADMIN_CACHE_KEY
16+
from pyslackersweb.sirbot import settings, models, database
1817
from pyslackersweb.util.log import ContextAwareLoggerAdapter
1918

2019

@@ -169,47 +168,46 @@ async def mention(request: web.Request, message: Message) -> None:
169168

170169

171170
async def channel_topic(request: web.Request, message: Message) -> None:
172-
173-
if message["user"] not in (
174-
await request.app["redis"].get(SLACK_ADMIN_CACHE_KEY, encoding="utf-8")
175-
):
176-
177-
async with request.app["pg"].connection() as pg_con:
178-
channel = await pg_con.fetchrow(
179-
"""SELECT raw FROM slack.channels WHERE id = $1""", message["channel"]
180-
)
181-
if channel:
182-
old_topic = channel["raw"]["topic"]["value"]
183-
else:
184-
old_topic = "Original topic not found"
185-
186-
response = Message()
187-
response["channel"] = settings.SLACK_ADMIN_CHANNEL
188-
response["attachments"] = [
171+
async with request.app["pg"].acquire() as conn:
172+
if database.is_admin(conn, message["user"]):
173+
return
174+
175+
async with request.app["pg"].connection() as pg_con:
176+
channel = await pg_con.fetchrow(
177+
"""SELECT raw FROM slack.channels WHERE id = $1""", message["channel"]
178+
)
179+
if channel:
180+
old_topic = channel["raw"]["topic"]["value"]
181+
else:
182+
old_topic = "Original topic not found"
183+
184+
response = Message()
185+
response["channel"] = settings.SLACK_ADMIN_CHANNEL
186+
response["attachments"] = [
187+
{
188+
"fallback": "Channel topic changed notice: old topic",
189+
"title": f'<@{message["user"]}> changed <#{message["channel"]}> topic.',
190+
"fields": [
191+
{"title": "Previous topic", "value": old_topic},
192+
{"title": "New topic", "value": message["topic"]},
193+
],
194+
}
195+
]
196+
197+
if channel:
198+
response["attachments"][0]["callback_id"] = "topic_change"
199+
response["attachments"][0]["actions"] = [
200+
{"name": "validate", "text": "Validate", "style": "primary", "type": "button",},
189201
{
190-
"fallback": "Channel topic changed notice: old topic",
191-
"title": f'<@{message["user"]}> changed <#{message["channel"]}> topic.',
192-
"fields": [
193-
{"title": "Previous topic", "value": old_topic},
194-
{"title": "New topic", "value": message["topic"]},
195-
],
196-
}
202+
"name": "revert",
203+
"text": "Revert",
204+
"style": "danger",
205+
"value": json.dumps({"channel": message["channel"], "old_topic": old_topic}),
206+
"type": "button",
207+
},
197208
]
198209

199-
if channel:
200-
response["attachments"][0]["callback_id"] = "topic_change"
201-
response["attachments"][0]["actions"] = [
202-
{"name": "validate", "text": "Validate", "style": "primary", "type": "button",},
203-
{
204-
"name": "revert",
205-
"text": "Revert",
206-
"style": "danger",
207-
"value": json.dumps({"channel": message["channel"], "old_topic": old_topic}),
208-
"type": "button",
209-
},
210-
]
211-
212-
await request.app["slack_client"].query(url=methods.CHAT_POST_MESSAGE, data=response)
210+
await request.app["slack_client"].query(url=methods.CHAT_POST_MESSAGE, data=response)
213211

214212

215213
async def inspect(request: web.Request, message: Message) -> None:

pyslackersweb/tasks.py

-6
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@
1414

1515
logger = ContextAwareLoggerAdapter(logging.getLogger(__name__))
1616

17-
SLACK_COUNT_CACHE_KEY = "slack:users:count"
18-
19-
SLACK_TZ_CACHE_KEY = "slack:users:timezones"
20-
21-
SLACK_ADMIN_CACHE_KEY = "slack:users:admin"
22-
2317

2418
async def sync_slack_users(
2519
slack_client: SlackAPI,

pyslackersweb/website/database.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import logging
2+
3+
import asyncpg
4+
import sqlalchemy as sa
5+
6+
from pyslackersweb import models
7+
from pyslackersweb.util.log import ContextAwareLoggerAdapter
8+
9+
10+
logger = ContextAwareLoggerAdapter(logging.getLogger(__name__))
11+
12+
13+
async def get_user_count(conn: asyncpg.connection.Connection) -> int:
14+
return await conn.fetchval(sa.select([models.SlackUsers]).count())
15+
16+
17+
async def get_timezones(conn: asyncpg.connection.Connection) -> dict:
18+
timezones = {}
19+
rows = await conn.fetch("SELECT timezone, count(id) FROM slack_users GROUP BY timezone")
20+
for row in rows:
21+
timezones[row["timezone"]] = row["count"]
22+
23+
return timezones

0 commit comments

Comments
 (0)