You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

851 lines
25 KiB

9 years ago
9 years ago
8 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
8 years ago
  1. from collections import Counter
  2. from datetime import datetime, timedelta as td
  3. from itertools import tee
  4. import json
  5. from croniter import croniter
  6. from django.conf import settings
  7. from django.contrib import messages
  8. from django.contrib.auth.decorators import login_required
  9. from django.core import signing
  10. from django.db.models import Count
  11. from django.http import (Http404, HttpResponse, HttpResponseBadRequest,
  12. HttpResponseForbidden)
  13. from django.shortcuts import get_object_or_404, redirect, render
  14. from django.template.loader import render_to_string
  15. from django.urls import reverse
  16. from django.utils import timezone
  17. from django.utils.crypto import get_random_string
  18. from django.utils.six.moves.urllib.parse import urlencode
  19. from django.views.decorators.csrf import csrf_exempt
  20. from django.views.decorators.http import require_POST
  21. from hc.api.decorators import uuid_or_400
  22. from hc.api.models import (DEFAULT_GRACE, DEFAULT_TIMEOUT, Channel, Check,
  23. Ping, Notification)
  24. from hc.api.transports import Telegram
  25. from hc.front.forms import (AddWebhookForm, NameTagsForm,
  26. TimeoutForm, AddUrlForm, AddPdForm, AddEmailForm,
  27. AddOpsGenieForm, CronForm, AddSmsForm)
  28. from hc.front.schemas import telegram_callback
  29. from hc.lib import jsonschema
  30. from pytz import all_timezones
  31. from pytz.exceptions import UnknownTimeZoneError
  32. import requests
  33. # from itertools recipes:
  34. def pairwise(iterable):
  35. "s -> (s0,s1), (s1,s2), (s2, s3), ..."
  36. a, b = tee(iterable)
  37. next(b, None)
  38. return zip(a, b)
  39. @login_required
  40. def my_checks(request):
  41. q = Check.objects.filter(user=request.team.user).order_by("created")
  42. checks = list(q)
  43. counter = Counter()
  44. down_tags, grace_tags = set(), set()
  45. for check in checks:
  46. status = check.get_status()
  47. for tag in check.tags_list():
  48. if tag == "":
  49. continue
  50. counter[tag] += 1
  51. if status == "down":
  52. down_tags.add(tag)
  53. elif check.in_grace_period():
  54. grace_tags.add(tag)
  55. can_add_more = len(checks) < request.team.check_limit
  56. ctx = {
  57. "page": "checks",
  58. "checks": checks,
  59. "now": timezone.now(),
  60. "tags": counter.most_common(),
  61. "down_tags": down_tags,
  62. "grace_tags": grace_tags,
  63. "ping_endpoint": settings.PING_ENDPOINT,
  64. "timezones": all_timezones,
  65. "can_add_more": can_add_more
  66. }
  67. return render(request, "front/my_checks.html", ctx)
  68. def _welcome_check(request):
  69. check = None
  70. if "welcome_code" in request.session:
  71. code = request.session["welcome_code"]
  72. check = Check.objects.filter(code=code).first()
  73. if check is None:
  74. check = Check()
  75. check.save()
  76. request.session["welcome_code"] = str(check.code)
  77. return check
  78. def index(request):
  79. if request.user.is_authenticated:
  80. return redirect("hc-checks")
  81. check = _welcome_check(request)
  82. ctx = {
  83. "page": "welcome",
  84. "check": check,
  85. "ping_url": check.url(),
  86. "enable_pushbullet": settings.PUSHBULLET_CLIENT_ID is not None,
  87. "enable_pushover": settings.PUSHOVER_API_TOKEN is not None,
  88. "enable_discord": settings.DISCORD_CLIENT_ID is not None,
  89. "enable_telegram": settings.TELEGRAM_TOKEN is not None,
  90. "enable_sms": settings.TWILIO_AUTH is not None,
  91. "registration_open": settings.REGISTRATION_OPEN
  92. }
  93. return render(request, "front/welcome.html", ctx)
  94. def docs(request):
  95. check = _welcome_check(request)
  96. ctx = {
  97. "page": "docs",
  98. "section": "home",
  99. "ping_endpoint": settings.PING_ENDPOINT,
  100. "check": check,
  101. "ping_url": check.url()
  102. }
  103. return render(request, "front/docs.html", ctx)
  104. def docs_api(request):
  105. ctx = {
  106. "page": "docs",
  107. "section": "api",
  108. "SITE_ROOT": settings.SITE_ROOT,
  109. "PING_ENDPOINT": settings.PING_ENDPOINT,
  110. "default_timeout": int(DEFAULT_TIMEOUT.total_seconds()),
  111. "default_grace": int(DEFAULT_GRACE.total_seconds())
  112. }
  113. return render(request, "front/docs_api.html", ctx)
  114. def docs_cron(request):
  115. ctx = {"page": "docs", "section": "cron"}
  116. return render(request, "front/docs_cron.html", ctx)
  117. def about(request):
  118. return render(request, "front/about.html", {"page": "about"})
  119. @require_POST
  120. @login_required
  121. def add_check(request):
  122. num_checks = Check.objects.filter(user=request.team.user).count()
  123. if num_checks >= request.team.check_limit:
  124. return HttpResponseBadRequest()
  125. check = Check(user=request.team.user)
  126. check.save()
  127. check.assign_all_channels()
  128. return redirect("hc-checks")
  129. @require_POST
  130. @login_required
  131. @uuid_or_400
  132. def update_name(request, code):
  133. check = get_object_or_404(Check, code=code)
  134. if check.user_id != request.team.user.id:
  135. return HttpResponseForbidden()
  136. form = NameTagsForm(request.POST)
  137. if form.is_valid():
  138. check.name = form.cleaned_data["name"]
  139. check.tags = form.cleaned_data["tags"]
  140. check.save()
  141. return redirect("hc-checks")
  142. @require_POST
  143. @login_required
  144. @uuid_or_400
  145. def update_timeout(request, code):
  146. check = get_object_or_404(Check, code=code)
  147. if check.user != request.team.user:
  148. return HttpResponseForbidden()
  149. kind = request.POST.get("kind")
  150. if kind == "simple":
  151. form = TimeoutForm(request.POST)
  152. if not form.is_valid():
  153. return HttpResponseBadRequest()
  154. check.kind = "simple"
  155. check.timeout = td(seconds=form.cleaned_data["timeout"])
  156. check.grace = td(seconds=form.cleaned_data["grace"])
  157. elif kind == "cron":
  158. form = CronForm(request.POST)
  159. if not form.is_valid():
  160. return HttpResponseBadRequest()
  161. check.kind = "cron"
  162. check.schedule = form.cleaned_data["schedule"]
  163. check.tz = form.cleaned_data["tz"]
  164. check.grace = td(minutes=form.cleaned_data["grace"])
  165. if check.last_ping:
  166. check.alert_after = check.get_alert_after()
  167. check.save()
  168. return redirect("hc-checks")
  169. @require_POST
  170. def cron_preview(request):
  171. schedule = request.POST.get("schedule")
  172. tz = request.POST.get("tz")
  173. ctx = {"tz": tz, "dates": []}
  174. try:
  175. with timezone.override(tz):
  176. now_naive = timezone.make_naive(timezone.now())
  177. it = croniter(schedule, now_naive)
  178. for i in range(0, 6):
  179. naive = it.get_next(datetime)
  180. aware = timezone.make_aware(naive)
  181. ctx["dates"].append((naive, aware))
  182. except UnknownTimeZoneError:
  183. ctx["bad_tz"] = True
  184. except:
  185. ctx["bad_schedule"] = True
  186. return render(request, "front/cron_preview.html", ctx)
  187. @require_POST
  188. def last_ping(request, code):
  189. if not request.user.is_authenticated:
  190. return HttpResponseForbidden()
  191. check = get_object_or_404(Check, code=code)
  192. if check.user_id != request.team.user.id:
  193. return HttpResponseForbidden()
  194. ping = Ping.objects.filter(owner=check).latest("created")
  195. ctx = {
  196. "check": check,
  197. "ping": ping
  198. }
  199. return render(request, "front/last_ping.html", ctx)
  200. @require_POST
  201. @login_required
  202. @uuid_or_400
  203. def pause(request, code):
  204. check = get_object_or_404(Check, code=code)
  205. if check.user_id != request.team.user.id:
  206. return HttpResponseForbidden()
  207. check.status = "paused"
  208. check.save()
  209. return redirect("hc-checks")
  210. @require_POST
  211. @login_required
  212. @uuid_or_400
  213. def remove_check(request, code):
  214. check = get_object_or_404(Check, code=code)
  215. if check.user != request.team.user:
  216. return HttpResponseForbidden()
  217. check.delete()
  218. return redirect("hc-checks")
  219. @login_required
  220. @uuid_or_400
  221. def log(request, code):
  222. check = get_object_or_404(Check, code=code)
  223. if check.user != request.team.user:
  224. return HttpResponseForbidden()
  225. limit = request.team.ping_log_limit
  226. pings = Ping.objects.filter(owner=check).order_by("-id")[:limit + 1]
  227. pings = list(pings)
  228. num_pings = len(pings)
  229. pings = pings[:limit]
  230. alerts = []
  231. if len(pings):
  232. cutoff = pings[-1].created
  233. alerts = Notification.objects \
  234. .select_related("channel") \
  235. .filter(owner=check, check_status="down", created__gt=cutoff)
  236. events = pings + list(alerts)
  237. events.sort(key=lambda el: el.created, reverse=True)
  238. ctx = {
  239. "check": check,
  240. "events": events,
  241. "num_pings": min(num_pings, limit),
  242. "limit": limit,
  243. "show_limit_notice": num_pings > limit and settings.USE_PAYMENTS
  244. }
  245. return render(request, "front/log.html", ctx)
  246. @login_required
  247. def channels(request):
  248. if request.method == "POST":
  249. code = request.POST["channel"]
  250. try:
  251. channel = Channel.objects.get(code=code)
  252. except Channel.DoesNotExist:
  253. return HttpResponseBadRequest()
  254. if channel.user_id != request.team.user.id:
  255. return HttpResponseForbidden()
  256. new_checks = []
  257. for key in request.POST:
  258. if key.startswith("check-"):
  259. code = key[6:]
  260. try:
  261. check = Check.objects.get(code=code)
  262. except Check.DoesNotExist:
  263. return HttpResponseBadRequest()
  264. if check.user_id != request.team.user.id:
  265. return HttpResponseForbidden()
  266. new_checks.append(check)
  267. channel.checks.set(new_checks)
  268. return redirect("hc-channels")
  269. channels = Channel.objects.filter(user=request.team.user)
  270. channels = channels.order_by("created")
  271. channels = channels.annotate(n_checks=Count("checks"))
  272. num_checks = Check.objects.filter(user=request.team.user).count()
  273. ctx = {
  274. "page": "channels",
  275. "profile": request.team,
  276. "channels": channels,
  277. "num_checks": num_checks,
  278. "enable_pushbullet": settings.PUSHBULLET_CLIENT_ID is not None,
  279. "enable_pushover": settings.PUSHOVER_API_TOKEN is not None,
  280. "enable_discord": settings.DISCORD_CLIENT_ID is not None,
  281. "enable_telegram": settings.TELEGRAM_TOKEN is not None,
  282. "enable_sms": settings.TWILIO_AUTH is not None
  283. }
  284. return render(request, "front/channels.html", ctx)
  285. @login_required
  286. @uuid_or_400
  287. def channel_checks(request, code):
  288. channel = get_object_or_404(Channel, code=code)
  289. if channel.user_id != request.team.user.id:
  290. return HttpResponseForbidden()
  291. assigned = set(channel.checks.values_list('code', flat=True).distinct())
  292. checks = Check.objects.filter(user=request.team.user).order_by("created")
  293. ctx = {
  294. "checks": checks,
  295. "assigned": assigned,
  296. "channel": channel
  297. }
  298. return render(request, "front/channel_checks.html", ctx)
  299. @uuid_or_400
  300. def verify_email(request, code, token):
  301. channel = get_object_or_404(Channel, code=code)
  302. if channel.make_token() == token:
  303. channel.email_verified = True
  304. channel.save()
  305. return render(request, "front/verify_email_success.html")
  306. return render(request, "bad_link.html")
  307. @uuid_or_400
  308. def unsubscribe_email(request, code, token):
  309. channel = get_object_or_404(Channel, code=code)
  310. if channel.make_token() != token:
  311. return render(request, "bad_link.html")
  312. if channel.kind != "email":
  313. return HttpResponseBadRequest()
  314. channel.delete()
  315. return render(request, "front/unsubscribe_success.html")
  316. @require_POST
  317. @login_required
  318. @uuid_or_400
  319. def remove_channel(request, code):
  320. # user may refresh the page during POST and cause two deletion attempts
  321. channel = Channel.objects.filter(code=code).first()
  322. if channel:
  323. if channel.user != request.team.user:
  324. return HttpResponseForbidden()
  325. channel.delete()
  326. return redirect("hc-channels")
  327. @login_required
  328. def add_email(request):
  329. if request.method == "POST":
  330. form = AddEmailForm(request.POST)
  331. if form.is_valid():
  332. channel = Channel(user=request.team.user, kind="email")
  333. channel.value = form.cleaned_data["value"]
  334. channel.save()
  335. channel.assign_all_checks()
  336. channel.send_verify_link()
  337. return redirect("hc-channels")
  338. else:
  339. form = AddEmailForm()
  340. ctx = {"page": "channels", "form": form}
  341. return render(request, "integrations/add_email.html", ctx)
  342. @login_required
  343. def add_webhook(request):
  344. if request.method == "POST":
  345. form = AddWebhookForm(request.POST)
  346. if form.is_valid():
  347. channel = Channel(user=request.team.user, kind="webhook")
  348. channel.value = form.get_value()
  349. channel.save()
  350. channel.assign_all_checks()
  351. return redirect("hc-channels")
  352. else:
  353. form = AddWebhookForm()
  354. ctx = {
  355. "page": "channels",
  356. "form": form,
  357. "now": timezone.now().replace(microsecond=0).isoformat()
  358. }
  359. return render(request, "integrations/add_webhook.html", ctx)
  360. @login_required
  361. def add_pd(request):
  362. if request.method == "POST":
  363. form = AddPdForm(request.POST)
  364. if form.is_valid():
  365. channel = Channel(user=request.team.user, kind="pd")
  366. channel.value = form.cleaned_data["value"]
  367. channel.save()
  368. channel.assign_all_checks()
  369. return redirect("hc-channels")
  370. else:
  371. form = AddPdForm()
  372. ctx = {"page": "channels", "form": form}
  373. return render(request, "integrations/add_pd.html", ctx)
  374. def _prepare_state(request, session_key):
  375. state = get_random_string()
  376. request.session[session_key] = state
  377. return state
  378. def _get_validated_code(request, session_key):
  379. if session_key not in request.session:
  380. return None
  381. session_state = request.session.pop(session_key)
  382. request_state = request.GET.get("state")
  383. if session_state is None or session_state != request_state:
  384. return None
  385. return request.GET.get("code")
  386. def add_slack(request):
  387. if not settings.SLACK_CLIENT_ID and not request.user.is_authenticated:
  388. return redirect("hc-login")
  389. if request.method == "POST":
  390. form = AddUrlForm(request.POST)
  391. if form.is_valid():
  392. channel = Channel(user=request.team.user, kind="slack")
  393. channel.value = form.cleaned_data["value"]
  394. channel.save()
  395. channel.assign_all_checks()
  396. return redirect("hc-channels")
  397. else:
  398. form = AddUrlForm()
  399. ctx = {
  400. "page": "channels",
  401. "form": form,
  402. "slack_client_id": settings.SLACK_CLIENT_ID
  403. }
  404. if settings.SLACK_CLIENT_ID:
  405. ctx["state"] = _prepare_state(request, "slack")
  406. return render(request, "integrations/add_slack.html", ctx)
  407. @login_required
  408. def add_slack_btn(request):
  409. code = _get_validated_code(request, "slack")
  410. if code is None:
  411. return HttpResponseBadRequest()
  412. result = requests.post("https://slack.com/api/oauth.access", {
  413. "client_id": settings.SLACK_CLIENT_ID,
  414. "client_secret": settings.SLACK_CLIENT_SECRET,
  415. "code": code
  416. })
  417. doc = result.json()
  418. if doc.get("ok"):
  419. channel = Channel()
  420. channel.user = request.team.user
  421. channel.kind = "slack"
  422. channel.value = result.text
  423. channel.save()
  424. channel.assign_all_checks()
  425. messages.success(request, "The Slack integration has been added!")
  426. else:
  427. s = doc.get("error")
  428. messages.warning(request, "Error message from slack: %s" % s)
  429. return redirect("hc-channels")
  430. @login_required
  431. def add_hipchat(request):
  432. if request.method == "POST":
  433. form = AddUrlForm(request.POST)
  434. if form.is_valid():
  435. channel = Channel(user=request.team.user, kind="hipchat")
  436. channel.value = form.cleaned_data["value"]
  437. channel.save()
  438. channel.assign_all_checks()
  439. return redirect("hc-channels")
  440. else:
  441. form = AddUrlForm()
  442. ctx = {"page": "channels", "form": form}
  443. return render(request, "integrations/add_hipchat.html", ctx)
  444. @login_required
  445. def add_pushbullet(request):
  446. if settings.PUSHBULLET_CLIENT_ID is None:
  447. raise Http404("pushbullet integration is not available")
  448. if "code" in request.GET:
  449. code = _get_validated_code(request, "pushbullet")
  450. if code is None:
  451. return HttpResponseBadRequest()
  452. result = requests.post("https://api.pushbullet.com/oauth2/token", {
  453. "client_id": settings.PUSHBULLET_CLIENT_ID,
  454. "client_secret": settings.PUSHBULLET_CLIENT_SECRET,
  455. "code": code,
  456. "grant_type": "authorization_code"
  457. })
  458. doc = result.json()
  459. if "access_token" in doc:
  460. channel = Channel(kind="pushbullet")
  461. channel.user = request.team.user
  462. channel.value = doc["access_token"]
  463. channel.save()
  464. channel.assign_all_checks()
  465. messages.success(request,
  466. "The Pushbullet integration has been added!")
  467. else:
  468. messages.warning(request, "Something went wrong")
  469. return redirect("hc-channels")
  470. redirect_uri = settings.SITE_ROOT + reverse("hc-add-pushbullet")
  471. authorize_url = "https://www.pushbullet.com/authorize?" + urlencode({
  472. "client_id": settings.PUSHBULLET_CLIENT_ID,
  473. "redirect_uri": redirect_uri,
  474. "response_type": "code",
  475. "state": _prepare_state(request, "pushbullet")
  476. })
  477. ctx = {
  478. "page": "channels",
  479. "authorize_url": authorize_url
  480. }
  481. return render(request, "integrations/add_pushbullet.html", ctx)
  482. @login_required
  483. def add_discord(request):
  484. if settings.DISCORD_CLIENT_ID is None:
  485. raise Http404("discord integration is not available")
  486. redirect_uri = settings.SITE_ROOT + reverse("hc-add-discord")
  487. if "code" in request.GET:
  488. code = _get_validated_code(request, "discord")
  489. if code is None:
  490. return HttpResponseBadRequest()
  491. result = requests.post("https://discordapp.com/api/oauth2/token", {
  492. "client_id": settings.DISCORD_CLIENT_ID,
  493. "client_secret": settings.DISCORD_CLIENT_SECRET,
  494. "code": code,
  495. "grant_type": "authorization_code",
  496. "redirect_uri": redirect_uri
  497. })
  498. doc = result.json()
  499. if "access_token" in doc:
  500. channel = Channel(kind="discord")
  501. channel.user = request.team.user
  502. channel.value = result.text
  503. channel.save()
  504. channel.assign_all_checks()
  505. messages.success(request,
  506. "The Discord integration has been added!")
  507. else:
  508. messages.warning(request, "Something went wrong")
  509. return redirect("hc-channels")
  510. auth_url = "https://discordapp.com/api/oauth2/authorize?" + urlencode({
  511. "client_id": settings.DISCORD_CLIENT_ID,
  512. "scope": "webhook.incoming",
  513. "redirect_uri": redirect_uri,
  514. "response_type": "code",
  515. "state": _prepare_state(request, "discord")
  516. })
  517. ctx = {
  518. "page": "channels",
  519. "authorize_url": auth_url
  520. }
  521. return render(request, "integrations/add_discord.html", ctx)
  522. @login_required
  523. def add_pushover(request):
  524. if settings.PUSHOVER_API_TOKEN is None or settings.PUSHOVER_SUBSCRIPTION_URL is None:
  525. raise Http404("pushover integration is not available")
  526. if request.method == "POST":
  527. # Initiate the subscription
  528. nonce = get_random_string()
  529. request.session["po_nonce"] = nonce
  530. failure_url = settings.SITE_ROOT + reverse("hc-channels")
  531. success_url = settings.SITE_ROOT + reverse("hc-add-pushover") + "?" + urlencode({
  532. "nonce": nonce,
  533. "prio": request.POST.get("po_priority", "0"),
  534. })
  535. subscription_url = settings.PUSHOVER_SUBSCRIPTION_URL + "?" + urlencode({
  536. "success": success_url,
  537. "failure": failure_url,
  538. })
  539. return redirect(subscription_url)
  540. # Handle successful subscriptions
  541. if "pushover_user_key" in request.GET:
  542. if "nonce" not in request.GET or "prio" not in request.GET:
  543. return HttpResponseBadRequest()
  544. # Validate nonce
  545. if request.GET["nonce"] != request.session.get("po_nonce"):
  546. return HttpResponseForbidden()
  547. # Validate priority
  548. if request.GET["prio"] not in ("-2", "-1", "0", "1", "2"):
  549. return HttpResponseBadRequest()
  550. # All looks well--
  551. del request.session["po_nonce"]
  552. if request.GET.get("pushover_unsubscribed") == "1":
  553. # Unsubscription: delete all Pushover channels for this user
  554. Channel.objects.filter(user=request.user, kind="po").delete()
  555. return redirect("hc-channels")
  556. else:
  557. # Subscription
  558. user_key = request.GET["pushover_user_key"]
  559. priority = int(request.GET["prio"])
  560. channel = Channel(user=request.team.user, kind="po")
  561. channel.value = "%s|%d" % (user_key, priority)
  562. channel.save()
  563. channel.assign_all_checks()
  564. return redirect("hc-channels")
  565. # Show Integration Settings form
  566. ctx = {
  567. "page": "channels",
  568. "po_retry_delay": td(seconds=settings.PUSHOVER_EMERGENCY_RETRY_DELAY),
  569. "po_expiration": td(seconds=settings.PUSHOVER_EMERGENCY_EXPIRATION),
  570. }
  571. return render(request, "integrations/add_pushover.html", ctx)
  572. @login_required
  573. def add_opsgenie(request):
  574. if request.method == "POST":
  575. form = AddOpsGenieForm(request.POST)
  576. if form.is_valid():
  577. channel = Channel(user=request.team.user, kind="opsgenie")
  578. channel.value = form.cleaned_data["value"]
  579. channel.save()
  580. channel.assign_all_checks()
  581. return redirect("hc-channels")
  582. else:
  583. form = AddUrlForm()
  584. ctx = {"page": "channels", "form": form}
  585. return render(request, "integrations/add_opsgenie.html", ctx)
  586. @login_required
  587. def add_victorops(request):
  588. if request.method == "POST":
  589. form = AddUrlForm(request.POST)
  590. if form.is_valid():
  591. channel = Channel(user=request.team.user, kind="victorops")
  592. channel.value = form.cleaned_data["value"]
  593. channel.save()
  594. channel.assign_all_checks()
  595. return redirect("hc-channels")
  596. else:
  597. form = AddUrlForm()
  598. ctx = {"page": "channels", "form": form}
  599. return render(request, "integrations/add_victorops.html", ctx)
  600. @csrf_exempt
  601. @require_POST
  602. def telegram_bot(request):
  603. try:
  604. doc = json.loads(request.body.decode("utf-8"))
  605. jsonschema.validate(doc, telegram_callback)
  606. except ValueError:
  607. return HttpResponseBadRequest()
  608. except jsonschema.ValidationError:
  609. return HttpResponseBadRequest()
  610. if "/start" not in doc["message"]["text"]:
  611. return HttpResponse()
  612. chat = doc["message"]["chat"]
  613. name = max(chat.get("title", ""), chat.get("username", ""))
  614. invite = render_to_string("integrations/telegram_invite.html", {
  615. "qs": signing.dumps((chat["id"], chat["type"], name))
  616. })
  617. Telegram.send(chat["id"], invite)
  618. return HttpResponse()
  619. @login_required
  620. def add_telegram(request):
  621. chat_id, chat_type, chat_name = None, None, None
  622. qs = request.META["QUERY_STRING"]
  623. if qs:
  624. chat_id, chat_type, chat_name = signing.loads(qs, max_age=600)
  625. if request.method == "POST":
  626. channel = Channel(user=request.team.user, kind="telegram")
  627. channel.value = json.dumps({
  628. "id": chat_id,
  629. "type": chat_type,
  630. "name": chat_name
  631. })
  632. channel.save()
  633. channel.assign_all_checks()
  634. messages.success(request, "The Telegram integration has been added!")
  635. return redirect("hc-channels")
  636. ctx = {
  637. "chat_id": chat_id,
  638. "chat_type": chat_type,
  639. "chat_name": chat_name,
  640. "bot_name": settings.TELEGRAM_BOT_NAME
  641. }
  642. return render(request, "integrations/add_telegram.html", ctx)
  643. @login_required
  644. def add_sms(request):
  645. if settings.TWILIO_AUTH is None:
  646. raise Http404("sms integration is not available")
  647. if request.method == "POST":
  648. form = AddSmsForm(request.POST)
  649. if form.is_valid():
  650. channel = Channel(user=request.team.user, kind="sms")
  651. channel.value = form.cleaned_data["value"]
  652. channel.save()
  653. channel.assign_all_checks()
  654. return redirect("hc-channels")
  655. else:
  656. form = AddSmsForm()
  657. ctx = {
  658. "page": "channels",
  659. "form": form,
  660. "profile": request.team
  661. }
  662. return render(request, "integrations/add_sms.html", ctx)
  663. def privacy(request):
  664. return render(request, "front/privacy.html", {})
  665. def terms(request):
  666. return render(request, "front/terms.html", {})