views.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. # coding: utf-8
  2. # nm.debian.org website API
  3. #
  4. # Copyright (C) 2012--2014 Enrico Zini <enrico@debian.org>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU Affero General Public License as
  8. # published by the Free Software Foundation, either version 3 of the
  9. # License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU Affero General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU Affero General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. from __future__ import print_function
  19. from __future__ import absolute_import
  20. from __future__ import division
  21. from __future__ import unicode_literals
  22. from django import http
  23. from django.core.exceptions import PermissionDenied
  24. from django.utils.translation import ugettext as _
  25. from django.forms.models import model_to_dict
  26. from django.views.generic import View
  27. from django.views.decorators.csrf import csrf_exempt
  28. import backend.models as bmodels
  29. from apikeys.mixins import APIVisitorMixin
  30. from backend import const
  31. import datetime
  32. import json
  33. class Serializer(json.JSONEncoder):
  34. def default(self, o):
  35. if hasattr(o, "strftime"):
  36. return o.strftime("%s")
  37. #return o.strftime("%Y-%m-%d %H:%M:%S")
  38. return json.JSONEncoder.default(self, o)
  39. def json_response(val, status_code=200):
  40. res = http.HttpResponse(content_type="application/json")
  41. res.status_code = status_code
  42. json.dump(val, res, cls=Serializer, indent=1)
  43. return res
  44. def person_to_json(p, **kw):
  45. res = model_to_dict(p, **kw)
  46. res["fullname"] = p.fullname
  47. res["url"] = p.get_absolute_url()
  48. res["fpr"] = p.fpr
  49. return res
  50. class People(APIVisitorMixin, View):
  51. def get(self, request, *args, **kw):
  52. # Pick what to include in the result based on auth status
  53. fields = ["cn", "mn", "sn", "uid", "fpr", "status", "status_changed", "created"]
  54. if self.visitor and self.visitor.is_dd:
  55. fields.append("email")
  56. if self.visitor.is_admin:
  57. fields.append("fd_comment")
  58. try:
  59. res = []
  60. # Build query
  61. people = bmodels.Person.objects.all()
  62. for arg in "cn", "mn", "sn", "email", "uid":
  63. val = request.GET.get(arg, None)
  64. if val is None: continue
  65. if val.startswith("/") and val.endswith("/"):
  66. args = { arg + "__regex": val.strip("/") }
  67. else:
  68. args = { arg + "__iexact": val }
  69. people = people.filter(**args)
  70. val = request.GET.get("fpr", None)
  71. if val is not None:
  72. people = people.filter(fprs__fpr__endswith=val)
  73. val = request.GET.get("status", None)
  74. if val is not None: people = people.filter(status=val)
  75. if self.visitor and self.visitor.is_admin:
  76. val = request.GET.get("fd_comment", "")
  77. if val: people = people.filter(fd_comment__icontains=val)
  78. for p in people.order_by("cn", "sn"):
  79. res.append(person_to_json(p, fields=fields))
  80. return json_response(dict(r=res))
  81. except Exception as e:
  82. #import traceback
  83. #traceback.print_exc()
  84. return json_response(dict(e=str(e)), status_code=500)
  85. class Status(APIVisitorMixin, View):
  86. def _serialize_people(self, people):
  87. res = {}
  88. for p in people:
  89. perms = p.perms
  90. rp = {
  91. "status": p.status,
  92. }
  93. if "am" in perms: rp["is_am"] = True
  94. processes = [x.applying_for for x in p.active_processes]
  95. if processes: rp["applying_for"] = processes
  96. res[p.username] = rp
  97. return json_response(dict(people=res))
  98. def get(self, request, *args, **kw):
  99. q_status = request.GET.get("status", None)
  100. q_person = request.GET.get("person", None)
  101. q_all = not any(bool(x) for x in (q_status, q_person))
  102. # Ensure that we got only one query
  103. if sum(bool(x) for x in (q_status, q_person)) > 1:
  104. return http.HttpResponseBadRequest("only one of status, person can be specified")
  105. # Enforce access restrictions
  106. if (q_status or q_all) and not self.visitor:
  107. raise PermissionDenied
  108. # Get a QuerySet with the people to return
  109. persons = bmodels.Person.objects.all()
  110. if q_status:
  111. persons = persons.filter(status__in=q_status.split(","))
  112. elif q_person:
  113. persons = persons.filter(username__in=q_person.split(","))
  114. elif q_all:
  115. pass
  116. else:
  117. return http.HttpResponseServerError("request cannot be understood")
  118. return self._serialize_people(persons)
  119. def post(self, request, *args, **kw):
  120. names = [str(x) for x in json.loads(request.body)]
  121. persons = bmodels.Person.objects.filter(username__in=names)
  122. return self._serialize_people(persons)
  123. @csrf_exempt
  124. def dispatch(self, *args, **kwargs):
  125. return super(Status, self).dispatch(*args, **kwargs)
  126. class Whoami(APIVisitorMixin, View):
  127. """
  128. Return a JSON with information on the currently logged in user
  129. """
  130. def get(self, request, *args, **kw):
  131. if request.user.is_authenticated():
  132. data = model_to_dict(self.visitor, fields=["username", "cn", "mn", "sn", "email", "uid", "status", "status_changed"])
  133. data["fpr"] = self.visitor.fpr
  134. else:
  135. data = {}
  136. res = http.HttpResponse(content_type="application/json")
  137. json.dump(data, res, indent=1, cls=Serializer)
  138. return res