diff --git a/dmoj/settings.py b/dmoj/settings.py index a32740030..3196c5a24 100755 --- a/dmoj/settings.py +++ b/dmoj/settings.py @@ -98,6 +98,9 @@ VNOJ_TAG_PROBLEM_MIN_RATING = 1900 # Minimum rating to be able to tag a problem +# List of subdomain that will be ignored in organization subdomain middleware +VNOJ_IGNORED_ORGANIZATION_SUBDOMAINS = ['oj', 'www', 'localhost'] + # Some problems have a lot of testcases, and each testcase # has about 5~6 fields, so we need to raise this DATA_UPLOAD_MAX_NUMBER_FIELDS = 3000 diff --git a/judge/middleware.py b/judge/middleware.py index 3c76040fd..3d274a74f 100644 --- a/judge/middleware.py +++ b/judge/middleware.py @@ -9,11 +9,12 @@ from django.contrib.sites.shortcuts import get_current_site from django.core.cache import cache from django.http import HttpResponse, HttpResponseRedirect +from django.shortcuts import get_object_or_404 from django.urls import Resolver404, resolve, reverse from django.utils.encoding import force_bytes from requests.exceptions import HTTPError -from judge.models import MiscConfig +from judge.models import MiscConfig, Organization try: import uwsgi @@ -181,3 +182,26 @@ def __call__(self, request): domain = get_current_site(request).domain request.misc_config = MiscConfigDict(language=request.LANGUAGE_CODE, domain=domain) return self.get_response(request) + + +class OrganizationSubdomainMiddleware(object): + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + subdomain: str = request.get_host().split('.')[0] + if subdomain.isnumeric() or subdomain in settings.VNOJ_IGNORED_ORGANIZATION_SUBDOMAINS: + return self.get_response(request) + + request.organization = get_object_or_404(Organization, slug=subdomain) + # if the user is trying to access the home page, redirect to the organization's home page + if request.path == '/': + return HttpResponseRedirect(request.organization.get_absolute_url()) + + return self.get_response(request) + + def process_template_response(self, request, response): + if hasattr(request, 'organization') and 'logo_override_image' not in response.context_data: + # inject the logo override image into the template context + response.context_data['logo_override_image'] = request.organization.logo_override_image + return response diff --git a/judge/views/organization.py b/judge/views/organization.py index 57b56f658..ba26a83c2 100644 --- a/judge/views/organization.py +++ b/judge/views/organization.py @@ -24,6 +24,7 @@ from judge.models import BlogPost, Comment, Contest, Language, Organization, OrganizationRequest, \ Problem, Profile from judge.tasks import on_new_problem +from judge.utils.infinite_paginator import InfinitePaginationMixin from judge.utils.ranker import ranker from judge.utils.views import DiggPaginatorMixin, QueryStringSortMixin, TitleMixin, generic_message from judge.views.blog import BlogPostCreate, PostListBase @@ -57,6 +58,12 @@ def dispatch(self, request, *args, **kwargs): try: self.object = self.organization + + # block the user from viewing other orgs in the subdomain + if self.is_in_organization_subdomain() and self.organization.pk != self.request.organization.pk: + return generic_message(request, _('Cannot view other organizations'), + _('You cannot view other organizations'), status=403) + return super(OrganizationMixin, self).dispatch(request, *args, **kwargs) except Http404: slug = kwargs.get('slug', None) @@ -74,6 +81,9 @@ def can_edit_organization(self, org=None): return False return org.is_admin(self.request.profile) or self.request.user.has_perm('judge.edit_all_organization') + def is_in_organization_subdomain(self): + return hasattr(self.request, 'organization') + # Use this mixin to mark a view is public for all users, including non-members class PublicOrganizationMixin(OrganizationMixin): @@ -151,7 +161,10 @@ def get_queryset(self): def get_context_data(self, **kwargs): context = super(OrganizationUsers, self).get_context_data(**kwargs) - context['title'] = self.object.name + if not self.is_in_organization_subdomain(): + context['title'] = self.organization.name + else: + context['title'] = _('Members') context['users'] = ranker(context['users']) context['partial'] = True context['is_admin'] = self.can_edit_organization() @@ -521,7 +534,8 @@ def get_hot_problems(self): def get_context_data(self, **kwargs): context = super(ProblemListOrganization, self).get_context_data(**kwargs) - context['title'] = self.organization.name + if not self.is_in_organization_subdomain(): + context['title'] = self.organization.name return context def get_filter(self): @@ -562,11 +576,12 @@ def _get_queryset(self): def get_context_data(self, **kwargs): context = super(ContestListOrganization, self).get_context_data(**kwargs) - context['title'] = self.organization.name + if not self.is_in_organization_subdomain(): + context['title'] = self.organization.name return context -class SubmissionListOrganization(PrivateOrganizationMixin, SubmissionsListBase): +class SubmissionListOrganization(InfinitePaginationMixin, PrivateOrganizationMixin, SubmissionsListBase): template_name = 'organization/submission-list.html' permission_bypass = ['judge.view_all_submission'] @@ -577,8 +592,9 @@ def _get_queryset(self): def get_context_data(self, **kwargs): context = super(SubmissionListOrganization, self).get_context_data(**kwargs) - context['title'] = self.organization.name - context['content_title'] = self.organization.name + if not self.is_in_organization_subdomain(): + context['title'] = self.organization.name + context['content_title'] = self.organization.name return context diff --git a/templates/base.html b/templates/base.html index e8710b108..e084e7462 100644 --- a/templates/base.html +++ b/templates/base.html @@ -233,22 +233,39 @@