views.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import string
  2. from collections import namedtuple
  3. from django.core.cache import cache
  4. from django.utils.crypto import get_random_string
  5. from rest_framework.response import Response
  6. from rest_framework.throttling import AnonRateThrottle
  7. from rest_framework.views import APIView
  8. from api_tokens.models import APIToken
  9. from projects.models import Project
  10. from .serializers import SetupWizardResultSerializer, SetupWizardSerializer
  11. SETUP_WIZARD_CACHE_KEY = "setup-wizard-keys:v1:"
  12. SETUP_WIZARD_CACHE_TIMEOUT = 600
  13. SETUP_WIZARD_CACHE_EMPTY = "empty"
  14. class SetupWizardView(APIView):
  15. """
  16. First step of @sentry/wizard set up. Generates a unique hash for later.
  17. """
  18. permission_classes = ()
  19. throttle_classes = [AnonRateThrottle]
  20. def delete(self, request, wizard_hash: str = None):
  21. if wizard_hash is not None:
  22. key = SETUP_WIZARD_CACHE_KEY + wizard_hash
  23. cache.delete(key)
  24. return Response()
  25. def get(self, request, wizard_hash: str = None):
  26. if wizard_hash is None:
  27. wizard_hash = get_random_string(
  28. 64, allowed_chars=string.ascii_lowercase + string.digits
  29. )
  30. key = SETUP_WIZARD_CACHE_KEY + wizard_hash
  31. cache.set(key, SETUP_WIZARD_CACHE_EMPTY, SETUP_WIZARD_CACHE_TIMEOUT)
  32. return Response({"hash": wizard_hash})
  33. else:
  34. key = SETUP_WIZARD_CACHE_KEY + wizard_hash
  35. wizard_data = cache.get(key)
  36. if wizard_data is None:
  37. return Response(status=404)
  38. elif wizard_data == SETUP_WIZARD_CACHE_EMPTY:
  39. return Response(status=400)
  40. return Response(wizard_data)
  41. class SetupWizardSetTokenView(APIView):
  42. """
  43. Second step of @sentry/wizard set up
  44. Use existing unique hash to assign an auth token to the hash based cache key
  45. """
  46. serializer_class = SetupWizardSerializer
  47. def post(self, request):
  48. serializer = self.serializer_class(data=request.data)
  49. serializer.is_valid(raise_exception=True)
  50. wizard_hash = serializer.data.get("hash")
  51. key = SETUP_WIZARD_CACHE_KEY + wizard_hash
  52. wizard_data = cache.get(key)
  53. if wizard_data is None:
  54. return Response(status=400)
  55. organizations = request.user.organizations_ext_organization.all()
  56. projects = Project.objects.filter(organization__in=organizations)[:50]
  57. scope = getattr(APIToken.scopes, "project:releases")
  58. tokens = request.user.apitoken_set.filter(scopes=scope)
  59. if not tokens:
  60. token = request.user.apitoken_set.create(scopes=scope)
  61. else:
  62. token = tokens[0]
  63. SetupWizardResult = namedtuple("SetupWizardResult", ("apiKeys", "projects"))
  64. response_serializer = SetupWizardResultSerializer(
  65. SetupWizardResult(apiKeys=token, projects=projects),
  66. context={"request": request},
  67. )
  68. cache.set(key, response_serializer.data, SETUP_WIZARD_CACHE_TIMEOUT)
  69. return Response()