|
|
- from datetime import timedelta as td
-
- from django.db.models import F
- from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse
- from django.utils import timezone
- from django.views.decorators.cache import never_cache
- from django.views.decorators.csrf import csrf_exempt
-
- from hc.api import schemas
- from hc.api.decorators import check_api_key, uuid_or_400, validate_json
- from hc.api.models import Check, Ping
- from hc.lib.badges import check_signature, get_badge_svg
-
-
- @csrf_exempt
- @uuid_or_400
- @never_cache
- def ping(request, code):
- try:
- check = Check.objects.get(code=code)
- except Check.DoesNotExist:
- return HttpResponseBadRequest()
-
- check.n_pings = F("n_pings") + 1
- check.last_ping = timezone.now()
- check.alert_after = check.get_alert_after()
- if check.status in ("new", "paused"):
- check.status = "up"
-
- check.save()
- check.refresh_from_db()
-
- ping = Ping(owner=check)
- headers = request.META
- ping.n = check.n_pings
- remote_addr = headers.get("HTTP_X_FORWARDED_FOR", headers["REMOTE_ADDR"])
- ping.remote_addr = remote_addr.split(",")[0]
- ping.scheme = headers.get("HTTP_X_FORWARDED_PROTO", "http")
- ping.method = headers["REQUEST_METHOD"]
- # If User-Agent is longer than 200 characters, truncate it:
- ping.ua = headers.get("HTTP_USER_AGENT", "")[:200]
- ping.save()
-
- response = HttpResponse("OK")
- response["Access-Control-Allow-Origin"] = "*"
- return response
-
-
- def _create_check(user, spec):
- check = Check(user=user)
- check.name = spec.get("name", "")
- check.tags = spec.get("tags", "")
-
- if "timeout" in spec and "schedule" not in spec:
- check.timeout = td(seconds=spec["timeout"])
-
- if "grace" in spec:
- check.grace = td(seconds=spec["grace"])
-
- if "schedule" in spec:
- check.kind = "cron"
- check.schedule = spec["schedule"]
- if "tz" in spec and "schedule" in spec:
- check.tz = spec["tz"]
-
- unique_fields = spec.get("unique", [])
- if unique_fields:
- existing_checks = Check.objects.filter(user=user)
- if "name" in unique_fields:
- existing_checks = existing_checks.filter(name=check.name)
- if "tags" in unique_fields:
- existing_checks = existing_checks.filter(tags=check.tags)
- if "timeout" in unique_fields:
- existing_checks = existing_checks.filter(timeout=check.timeout)
- if "grace" in unique_fields:
- existing_checks = existing_checks.filter(grace=check.grace)
-
- if existing_checks.count() > 0:
- # There might be more than one matching check, return first
- first_match = existing_checks.first()
- return JsonResponse(first_match.to_dict(), status=200)
-
- check.save()
-
- # This needs to be done after saving the check, because of
- # the M2M relation between checks and channels:
- if spec.get("channels") == "*":
- check.assign_all_channels()
-
- return JsonResponse(check.to_dict(), status=201)
-
-
- @csrf_exempt
- @check_api_key
- @validate_json(schemas.check)
- def checks(request):
- if request.method == "GET":
- q = Check.objects.filter(user=request.user)
- doc = {"checks": [check.to_dict() for check in q]}
- return JsonResponse(doc)
-
- elif request.method == "POST":
- return _create_check(request.user, request.json)
-
- # If request is neither GET nor POST, return "405 Method not allowed"
- return HttpResponse(status=405)
-
-
- @csrf_exempt
- @check_api_key
- def pause(request, code):
- if request.method != "POST":
- # Method not allowed
- return HttpResponse(status=405)
-
- try:
- check = Check.objects.get(code=code, user=request.user)
- except Check.DoesNotExist:
- return HttpResponseBadRequest()
-
- check.status = "paused"
- check.save()
- return JsonResponse(check.to_dict())
-
-
- @never_cache
- def badge(request, username, signature, tag):
- if not check_signature(username, tag, signature):
- return HttpResponseBadRequest()
-
- status = "up"
- q = Check.objects.filter(user__username=username, tags__contains=tag)
- for check in q:
- if tag not in check.tags_list():
- continue
-
- if status == "up" and check.in_grace_period():
- status = "late"
-
- if check.get_status() == "down":
- status = "down"
- break
-
- svg = get_badge_svg(tag, status)
- return HttpResponse(svg, content_type="image/svg+xml")
|