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.

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