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.

145 lines
4.4 KiB

10 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
8 years ago
8 years ago
  1. from datetime import timedelta as td
  2. from django.db.models import F
  3. from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse
  4. from django.utils import timezone
  5. from django.views.decorators.cache import never_cache
  6. from django.views.decorators.csrf import csrf_exempt
  7. from hc.api import schemas
  8. from hc.api.decorators import check_api_key, uuid_or_400, validate_json
  9. from hc.api.models import Check, Ping
  10. from hc.lib.badges import check_signature, get_badge_svg
  11. @csrf_exempt
  12. @uuid_or_400
  13. @never_cache
  14. def ping(request, code):
  15. try:
  16. check = Check.objects.get(code=code)
  17. except Check.DoesNotExist:
  18. return HttpResponseBadRequest()
  19. check.n_pings = F("n_pings") + 1
  20. check.last_ping = timezone.now()
  21. check.alert_after = check.get_alert_after()
  22. if check.status in ("new", "paused"):
  23. check.status = "up"
  24. check.save()
  25. check.refresh_from_db()
  26. ping = Ping(owner=check)
  27. headers = request.META
  28. ping.n = check.n_pings
  29. remote_addr = headers.get("HTTP_X_FORWARDED_FOR", headers["REMOTE_ADDR"])
  30. ping.remote_addr = remote_addr.split(",")[0]
  31. ping.scheme = headers.get("HTTP_X_FORWARDED_PROTO", "http")
  32. ping.method = headers["REQUEST_METHOD"]
  33. # If User-Agent is longer than 200 characters, truncate it:
  34. ping.ua = headers.get("HTTP_USER_AGENT", "")[:200]
  35. ping.save()
  36. response = HttpResponse("OK")
  37. response["Access-Control-Allow-Origin"] = "*"
  38. return response
  39. def _create_check(user, spec):
  40. check = Check(user=user)
  41. check.name = spec.get("name", "")
  42. check.tags = spec.get("tags", "")
  43. if "timeout" in spec and "schedule" not in spec:
  44. check.timeout = td(seconds=spec["timeout"])
  45. if "grace" in spec:
  46. check.grace = td(seconds=spec["grace"])
  47. if "schedule" in spec:
  48. check.kind = "cron"
  49. check.schedule = spec["schedule"]
  50. if "tz" in spec and "schedule" in spec:
  51. check.tz = spec["tz"]
  52. unique_fields = spec.get("unique", [])
  53. if unique_fields:
  54. existing_checks = Check.objects.filter(user=user)
  55. if "name" in unique_fields:
  56. existing_checks = existing_checks.filter(name=check.name)
  57. if "tags" in unique_fields:
  58. existing_checks = existing_checks.filter(tags=check.tags)
  59. if "timeout" in unique_fields:
  60. existing_checks = existing_checks.filter(timeout=check.timeout)
  61. if "grace" in unique_fields:
  62. existing_checks = existing_checks.filter(grace=check.grace)
  63. if existing_checks.count() > 0:
  64. # There might be more than one matching check, return first
  65. first_match = existing_checks.first()
  66. return JsonResponse(first_match.to_dict(), status=200)
  67. check.save()
  68. # This needs to be done after saving the check, because of
  69. # the M2M relation between checks and channels:
  70. if spec.get("channels") == "*":
  71. check.assign_all_channels()
  72. return JsonResponse(check.to_dict(), status=201)
  73. @csrf_exempt
  74. @check_api_key
  75. @validate_json(schemas.check)
  76. def checks(request):
  77. if request.method == "GET":
  78. q = Check.objects.filter(user=request.user)
  79. doc = {"checks": [check.to_dict() for check in q]}
  80. return JsonResponse(doc)
  81. elif request.method == "POST":
  82. return _create_check(request.user, request.json)
  83. # If request is neither GET nor POST, return "405 Method not allowed"
  84. return HttpResponse(status=405)
  85. @csrf_exempt
  86. @check_api_key
  87. def pause(request, code):
  88. if request.method != "POST":
  89. # Method not allowed
  90. return HttpResponse(status=405)
  91. try:
  92. check = Check.objects.get(code=code, user=request.user)
  93. except Check.DoesNotExist:
  94. return HttpResponseBadRequest()
  95. check.status = "paused"
  96. check.save()
  97. return JsonResponse(check.to_dict())
  98. @never_cache
  99. def badge(request, username, signature, tag):
  100. if not check_signature(username, tag, signature):
  101. return HttpResponseBadRequest()
  102. status = "up"
  103. q = Check.objects.filter(user__username=username, tags__contains=tag)
  104. for check in q:
  105. if tag not in check.tags_list():
  106. continue
  107. if status == "up" and check.in_grace_period():
  108. status = "late"
  109. if check.get_status() == "down":
  110. status = "down"
  111. break
  112. svg = get_badge_svg(tag, status)
  113. return HttpResponse(svg, content_type="image/svg+xml")