Skip to content

Commit c718913

Browse files
authored
Merge pull request #286 from ctrlh/slack-integration
Thanks! Add Slack integration
2 parents 0f6c0a3 + 078c74a commit c718913

File tree

11 files changed

+288
-8
lines changed

11 files changed

+288
-8
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 3.2.25 on 2024-12-07 23:36
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("access", "0019_auto_20240603_2150"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="accesscontrolleddevice",
15+
name="post_to_slack",
16+
field=models.BooleanField(
17+
default=True, verbose_name="Post to slack on swipe"
18+
),
19+
),
20+
]

memberportal/access/models.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import logging
2-
from services.discord import post_door_swipe_to_discord, post_interlock_swipe_to_discord
2+
from services.discord import (
3+
post_door_swipe_to_discord,
4+
post_interlock_swipe_to_discord,
5+
post_door_bump_to_discord,
6+
)
7+
from services.slack import (
8+
post_door_swipe_to_slack,
9+
post_door_bump_to_slack,
10+
post_interlock_swipe_to_slack,
11+
)
312
from services import sms
413
from profile.models import Profile, log_event
514
from memberbucks.models import MemberBucks
@@ -67,6 +76,7 @@ class AccessControlledDevice(
6776
locked_out = models.BooleanField("Maintenance lockout enabled", default=False)
6877
play_theme = models.BooleanField("Play theme on successful swipe", default=False)
6978
post_to_discord = models.BooleanField("Post to discord on swipe", default=True)
79+
post_to_slack = models.BooleanField("Post to slack on swipe", default=True)
7080
exempt_signin = models.BooleanField(
7181
"Exempt this device from requiring a sign in", default=False
7282
)
@@ -299,6 +309,12 @@ def bump(self, request=None):
299309
)
300310

301311
if request:
312+
# notify messaging apps of bump
313+
profile = request.user.profile
314+
if self.post_to_slack:
315+
post_door_bump_to_slack(profile.get_full_name(), self.name)
316+
if self.post_to_discord:
317+
post_door_bump_to_discord(profile.get_full_name(), self.name)
302318
self.log_access(request.user.id)
303319
request.user.log_event(
304320
f"Bumped the {self.name} {self._meta.verbose_name}.",
@@ -310,6 +326,10 @@ def bump(self, request=None):
310326
f"Unknown user (system) bumped the {self.name} {self._meta.verbose_name}.",
311327
"admin",
312328
)
329+
if self.post_to_slack:
330+
post_door_bump_to_slack("unknown", self.name)
331+
if self.post_to_discord:
332+
post_door_bump_to_discord("unknown", self.name)
313333

314334
return True
315335

@@ -331,14 +351,27 @@ def log_access(self, member_id, success=True):
331351
metrics.device_access_successes_total.labels(
332352
**self.get_metrics_labels()
333353
).inc()
354+
355+
# TODO replace with generic post_to_messengers
334356
if self.post_to_discord:
335357
post_door_swipe_to_discord(profile.get_full_name(), self.name, success)
358+
if self.post_to_slack:
359+
post_door_swipe_to_slack(profile.get_full_name(), self.name, success)
336360

337361
elif success == "locked_out":
338362
metrics.device_access_failures_total.labels(
339363
**self.get_metrics_labels()
340364
).inc()
341-
post_door_swipe_to_discord(profile.get_full_name(), self.name, "locked_out")
365+
366+
# TODO replace with generic post_to_messengers
367+
if self.post_to_discord:
368+
post_door_swipe_to_discord(
369+
profile.get_full_name(), self.name, "locked_out"
370+
)
371+
if self.post_to_slack:
372+
post_door_swipe_to_slack(
373+
profile.get_full_name(), self.name, "locked_out"
374+
)
342375

343376
sms_message = sms.SMS()
344377
sms_message.send_locked_out_swipe_alert(profile.phone)
@@ -347,10 +380,15 @@ def log_access(self, member_id, success=True):
347380
metrics.device_access_failures_total.labels(
348381
**self.get_metrics_labels()
349382
).inc()
383+
384+
# TODO replace with generic post_to_messengers
350385
if self.post_to_discord:
351386
post_door_swipe_to_discord(
352387
profile.get_full_name(), self.name, "rejected"
353388
)
389+
if self.post_to_slack:
390+
post_door_swipe_to_slack(profile.get_full_name(), self.name, "rejected")
391+
354392
sms_message = sms.SMS()
355393
sms_message.send_inactive_swipe_alert(profile.phone)
356394

memberportal/api_access/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def post(self, request, door_id):
255255
# BUT we still need to check if the API is enabled or it's a user making the request
256256
if config.ENABLE_DOOR_BUMP_API or request.user.is_authenticated:
257257
door = Doors.objects.get(pk=door_id)
258-
bumped = door.bump()
258+
bumped = door.bump(request)
259259
door.log_force_bump()
260260
return Response({"success": bumped})
261261
else:

memberportal/api_admin_tools/views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ def get_door(door):
199199
"maintenanceLockout": door.locked_out,
200200
"playThemeOnSwipe": door.play_theme,
201201
"postDiscordOnSwipe": door.post_to_discord,
202+
"postSlackOnSwipe": door.post_to_slack,
202203
"exemptFromSignin": door.exempt_signin,
203204
"hiddenToMembers": door.hidden,
204205
"totalSwipes": logs.count(),
@@ -231,6 +232,7 @@ def put(self, request, door_id):
231232
door.locked_out = data.get("maintenanceLockout")
232233
door.play_theme = data.get("playThemeOnSwipe")
233234
door.post_to_discord = data.get("postDiscordOnSwipe")
235+
door.post_to_slack = data.get("postSlackOnSwipe")
234236
door.exempt_signin = data.get("exemptFromSignin")
235237
door.hidden = data.get("hiddenToMembers")
236238
door.save()

memberportal/api_general/views.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from rest_framework.views import APIView
1818
from .models import Kiosk, SiteSession, EmailVerificationToken
1919
from services.discord import post_kiosk_swipe_to_discord
20+
from services.slack import post_kiosk_swipe_to_slack
2021
import base64
2122
from urllib.parse import parse_qs, urlencode
2223
import hmac
@@ -591,7 +592,8 @@ def put(self, request):
591592
)
592593
for session in sessions:
593594
session.signout()
594-
post_kiosk_swipe_to_discord(request.user.profile.get_full_name(), False)
595+
if config.ENABLE_DISCORD_INTEGRATION and config.SLACK_DOOR_WEBHOOK:
596+
post_kiosk_swipe_to_discord(request.user.profile.get_full_name(), False)
595597

596598
for door in request.user.profile.doors.all():
597599
door.sync()

memberportal/membermatters/constance_config.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,26 @@
339339
"",
340340
"The auth token (not an api token) to use for the twilio integration.",
341341
),
342+
"ENABLE_SLACK_INTEGRATION": (
343+
False,
344+
"Enable posting a notification to the slack channel on a card swipe.",
345+
),
346+
"SLACK_DOOR_WEBHOOK": (
347+
"https://hooks.slack.com/services/T00000000/B00000000/<token>",
348+
"Slack URL to send webhook notifications to.",
349+
),
350+
"SLACK_INTERLOCK_WEBHOOK": (
351+
"https://hooks.slack.com/services/T00000000/B00000000/<token>",
352+
"Slack URL to send webhook notifications to.",
353+
),
354+
"SLACK_MEMBERBUCKS_PURCHASE_WEBHOOK": (
355+
"https://hooks.slack.com/services/T00000000/B00000000/<token>",
356+
"Slack URL to send webhook notifications to for vending/memberbucks purchases.",
357+
),
358+
"SLACK_REPORT_ISSUE_WEBHOOK": (
359+
"https://hooks.slack.com/services/T00000000/B00000000/<token>",
360+
"Slack URL to send webhook notifications to when reporting issues.",
361+
),
342362
"SMS_ENABLE": (
343363
False,
344364
"If SMS functionality should be enabled (please configure below).",
@@ -396,6 +416,7 @@
396416
"ENABLE_MEMBERBUCKS",
397417
"ENABLE_DISCOURSE_SSO_PROTOCOL",
398418
"ENABLE_DISCORD_INTEGRATION",
419+
"ENABLE_SLACK_INTEGRATION",
399420
"ENABLE_SPACE_DIRECTORY",
400421
"ENABLE_THEME_SWIPE",
401422
"ENABLE_PORTAL_SITE_SIGN_IN",
@@ -558,5 +579,14 @@
558579
"DISCORD_REPORT_ISSUE_WEBHOOK",
559580
),
560581
),
582+
(
583+
"Slack Integration",
584+
(
585+
"SLACK_DOOR_WEBHOOK",
586+
"SLACK_INTERLOCK_WEBHOOK",
587+
"SLACK_MEMBERBUCKS_PURCHASE_WEBHOOK",
588+
"SLACK_REPORT_ISSUE_WEBHOOK",
589+
),
590+
),
561591
]
562592
)

memberportal/membermatters/settings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@
243243
"level": os.environ.get("MM_LOG_LEVEL_DISCORD", "INFO"),
244244
"propagate": False,
245245
},
246+
"slack": {
247+
"handlers": ["console", "file"],
248+
"level": os.environ.get("MM_LOG_LEVEL_SLACK", "INFO"),
249+
"propagate": False,
250+
},
246251
"emails": {
247252
"handlers": ["console", "file"],
248253
"level": os.environ.get("MM_LOG_LEVEL_EMAILS", "INFO"),

memberportal/services/discord.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,25 @@ def post_reported_issue_to_discord(
214214
return True
215215

216216
return True
217+
218+
219+
def post_door_bump_to_discord(name, door):
220+
if config.ENABLE_DISCORD_INTEGRATION and config.DISCORD_DOOR_WEBHOOK:
221+
logger.debug("Posting door bump to Discord!")
222+
223+
url = config.DISCORD_DOOR_WEBHOOK
224+
225+
json_message = {"description": "", "embeds": []}
226+
json_message["embeds"].append(
227+
{
228+
"description": ":unlock: {} just bumped at {}.".format(name, door),
229+
"color": 5025616,
230+
}
231+
)
232+
233+
try:
234+
requests.post(url, json=json_message, timeout=settings.REQUEST_TIMEOUT)
235+
except requests.exceptions.ReadTimeout:
236+
return True
237+
238+
return True

0 commit comments

Comments
 (0)