diff --git a/readthedocs/projects/views/public.py b/readthedocs/projects/views/public.py index fbf98fabc62..dde398af7ea 100644 --- a/readthedocs/projects/views/public.py +++ b/readthedocs/projects/views/public.py @@ -33,7 +33,7 @@ from readthedocs.core.utils.extend import SettingsOverrideObject from readthedocs.projects.models import Project from readthedocs.projects.templatetags.projects_tags import sort_version_aware -from readthedocs.proxito.views.mixins import ServeDocsMixin +from readthedocs.proxito.views.mixins import ServeDocsMixin, ServeDocsPermissionsMixin from readthedocs.proxito.views.utils import _get_project_data_from_request from .base import ProjectOnboardMixin @@ -269,7 +269,7 @@ def project_downloads(request, project_slug): ) -class ProjectDownloadMediaBase(ServeDocsMixin, View): +class ProjectDownloadMediaBase(ServeDocsPermissionsMixin, ServeDocsMixin, View): # Use new-style URLs (same domain as docs) or old-style URLs (dashboard URL) same_domain_url = False @@ -354,6 +354,10 @@ def get( download=True, ) + def allowed_user(self, *args, **kwargs): + # always grant permissions to community users + return True + class ProjectDownloadMedia(SettingsOverrideObject): _default_class = ProjectDownloadMediaBase diff --git a/readthedocs/proxito/views/mixins.py b/readthedocs/proxito/views/mixins.py index 944d6df3df4..4e34c2dfc55 100644 --- a/readthedocs/proxito/views/mixins.py +++ b/readthedocs/proxito/views/mixins.py @@ -120,9 +120,6 @@ def _serve_401(self, request, project): log.debug('Unauthorized access to %s documentation', project.slug) return res - def allowed_user(self, *args, **kwargs): - return True - class ServeRedirectMixin: @@ -175,3 +172,38 @@ def get_redirect_response(self, request, redirect_path, proxito_path, http_statu return HttpResponsePermanentRedirect(new_path) return HttpResponseRedirect(new_path) + + +class ServeDocsPermissionsMixin: + + """ + Mixin to handle documentation permissions. + + To use this mixin, the method that serve the docs should call + ``allowed_user`` first to check if the user requesting to read the page is + allowed. If allowed, the flow should continue. + + On the other hand, if the user is not allowed, the serve docs method MUST + break the flow and return a call to ``get_unauthed_response``. + """ + + def allowed_user(self, request, project, version_slug): + """ + Return whether the user is allowed to read this documentation's version. + + :returns: ``True`` if allowed. ``False`` otherwise. + :rtype: bool + """ + return False + + def get_unauthed_response(self, request, project): + """ + Return response for an unauthed hit at a documentation's version. + + When a user does not have access to read documentation, we need to + return a response showing the proper message. This method produces that + reponse. + + :rtype: django.http.HttpResponse + """ + return self._serve_401(request, project) diff --git a/readthedocs/proxito/views/serve.py b/readthedocs/proxito/views/serve.py index 99a2b321b27..363fcfa0ab7 100644 --- a/readthedocs/proxito/views/serve.py +++ b/readthedocs/proxito/views/serve.py @@ -21,7 +21,7 @@ from readthedocs.projects.templatetags.projects_tags import sort_version_aware from readthedocs.redirects.exceptions import InfiniteRedirectException -from .mixins import ServeDocsMixin, ServeRedirectMixin +from .mixins import ServeDocsMixin, ServeRedirectMixin, ServeDocsPermissionsMixin from .decorators import map_project_slug from .redirects import redirect_project_slug @@ -31,7 +31,12 @@ log = logging.getLogger(__name__) # noqa -class ServeDocsBase(ServeRedirectMixin, ServeDocsMixin, View): +class ServeDocsBase( + ServeRedirectMixin, + ServeDocsPermissionsMixin, + ServeDocsMixin, + View, +): version_type = INTERNAL @@ -143,6 +148,10 @@ def get(self, path=final_url, ) + def allowed_user(self, *args, **kwargs): + # always grant permissions to community users + return True + class ServeDocs(SettingsOverrideObject): _default_class = ServeDocsBase