readthedocs.org/readthedocs/projects/querysets.py

190 lines
5.7 KiB
Python

# -*- coding: utf-8 -*-
"""Project model QuerySet classes."""
from django.db import models
from django.db.models import Q
from guardian.shortcuts import get_objects_for_user
from readthedocs.core.utils.extend import SettingsOverrideObject
from . import constants
class ProjectQuerySetBase(models.QuerySet):
"""Projects take into account their own privacy_level setting."""
use_for_related_fields = True
def _add_user_repos(self, queryset, user):
if user.has_perm('projects.view_project'):
return self.all().distinct()
if user.is_authenticated:
user_queryset = get_objects_for_user(user, 'projects.view_project')
queryset = user_queryset | queryset
return queryset.distinct()
def for_user_and_viewer(self, user, viewer):
"""Show projects that a user owns, that another user can see."""
queryset = self.filter(privacy_level=constants.PUBLIC)
queryset = self._add_user_repos(queryset, viewer)
queryset = queryset.filter(users__in=[user])
return queryset
def for_admin_user(self, user):
if user.is_authenticated:
return self.filter(users__in=[user])
return self.none()
def public(self, user=None):
queryset = self.filter(privacy_level=constants.PUBLIC)
if user:
return self._add_user_repos(queryset, user)
return queryset
def protected(self, user=None):
queryset = self.filter(
privacy_level__in=[constants.PUBLIC, constants.PROTECTED],
)
if user:
return self._add_user_repos(queryset, user)
return queryset
def private(self, user=None):
queryset = self.filter(privacy_level=constants.PRIVATE)
if user:
return self._add_user_repos(queryset, user)
return queryset
def is_active(self, project):
"""
Check if the project is active.
The check consists on,
* the Project shouldn't be marked as skipped.
* any of the project's owners is banned.
:param project: project to be checked
:type project: readthedocs.projects.models.Project
:returns: whether or not the project is active
:rtype: bool
"""
any_owner_banned = any(u.profile.banned for u in project.users.all())
if project.skip or any_owner_banned:
return False
return True
# Aliases
def dashboard(self, user=None):
return self.for_admin_user(user)
def api(self, user=None):
return self.public(user)
class ProjectQuerySet(SettingsOverrideObject):
_default_class = ProjectQuerySetBase
_override_setting = 'PROJECT_MANAGER'
class RelatedProjectQuerySetBase(models.QuerySet):
"""
Useful for objects that relate to Project and its permissions.
Objects get the permissions from the project itself.
..note:: This shouldn't be used as a subclass.
"""
use_for_related_fields = True
project_field = 'project'
def _add_user_repos(self, queryset, user=None):
# Hack around get_objects_for_user not supporting global perms
if user.has_perm('projects.view_project'):
return self.all().distinct()
if user.is_authenticated:
# Add in possible user-specific views
project_qs = get_objects_for_user(user, 'projects.view_project')
pks = project_qs.values_list('pk', flat=True)
kwargs = {'%s__pk__in' % self.project_field: pks}
queryset = self.filter(**kwargs) | queryset
return queryset.distinct()
def public(self, user=None, project=None):
kwargs = {'%s__privacy_level' % self.project_field: constants.PUBLIC}
queryset = self.filter(**kwargs)
if user:
queryset = self._add_user_repos(queryset, user)
if project:
queryset = queryset.filter(project=project)
return queryset
def protected(self, user=None, project=None):
kwargs = {
'%s__privacy_level__in' % self.project_field: [
constants.PUBLIC,
constants.PROTECTED,
],
}
queryset = self.filter(**kwargs)
if user:
queryset = self._add_user_repos(queryset, user)
if project:
queryset = queryset.filter(project=project)
return queryset
def private(self, user=None, project=None):
kwargs = {
'%s__privacy_level' % self.project_field: constants.PRIVATE,
}
queryset = self.filter(**kwargs)
if user:
queryset = self._add_user_repos(queryset, user)
if project:
queryset = queryset.filter(project=project)
return queryset
def api(self, user=None):
return self.public(user)
class RelatedProjectQuerySet(SettingsOverrideObject):
_default_class = RelatedProjectQuerySetBase
_override_setting = 'RELATED_PROJECT_MANAGER'
class ParentRelatedProjectQuerySetBase(RelatedProjectQuerySetBase):
project_field = 'parent'
use_for_related_fields = True
class ParentRelatedProjectQuerySet(SettingsOverrideObject):
_default_class = ParentRelatedProjectQuerySetBase
_override_setting = 'RELATED_PROJECT_MANAGER'
class ChildRelatedProjectQuerySetBase(RelatedProjectQuerySetBase):
project_field = 'child'
use_for_related_fields = True
class ChildRelatedProjectQuerySet(SettingsOverrideObject):
_default_class = ChildRelatedProjectQuerySetBase
_override_setting = 'RELATED_PROJECT_MANAGER'
class FeatureQuerySet(models.QuerySet):
use_for_related_fields = True
def for_project(self, project):
return self.filter(
Q(projects=project) |
Q(default_true=True, add_date__gt=project.pub_date),
).distinct()