diff --git a/apps/admission/api/views.py b/apps/admission/api/views.py index ef718ab12..f58b6f5d4 100644 --- a/apps/admission/api/views.py +++ b/apps/admission/api/views.py @@ -8,6 +8,7 @@ from rest_framework.views import APIView from django.conf import settings +from django.contrib.sites.models import Site from django.db.models import Q from django.http import Http404 @@ -133,7 +134,7 @@ def post(self, request: HttpRequest, *args, **kwargs): send_email_verification_code( email_to=serializer.validated_data["email"], - site=request.site, + site=Site.objects.get(pk=settings.SITE_ID), applicant=acceptance.applicant, ) diff --git a/apps/admission/views.py b/apps/admission/views.py index 776bb8f5a..697a41f1f 100644 --- a/apps/admission/views.py +++ b/apps/admission/views.py @@ -620,18 +620,18 @@ class RegisterApplicantsForOlympiadView(CuratorOnlyMixin, generic.View): """ Register applicants with status PERMIT_TO_OLYMPIAD in the olympiad contest. """ - + def get_campaign(self, campaign_id): """Get campaign by ID.""" return get_object_or_404(Campaign, pk=campaign_id) - + def get_applicants(self, campaign): """Get applicants with status PERMIT_TO_OLYMPIAD.""" return Applicant.objects.filter( campaign=campaign, status=ApplicantStatuses.PERMIT_TO_OLYMPIAD ) - + def create_olympiad_records(self, applicants): """Create Olympiad records for applicants who don't have one.""" created_count = 0 @@ -643,7 +643,7 @@ def create_olympiad_records(self, applicants): Olympiad.objects.create(applicant=applicant) created_count += 1 return created_count - + def register_in_contest(self, api, applicants, request): """Register applicants in the contest.""" registered_count = 0 @@ -661,24 +661,24 @@ def register_in_contest(self, api, applicants, request): f"Error registering applicant {olympiad.applicant_id} in olympiad contest: {e}" ) return registered_count - + def get(self, request, campaign_id): campaign = self.get_campaign(campaign_id) - + # Get applicants and create Olympiad records applicants = self.get_applicants(campaign) created_count = self.create_olympiad_records(applicants) - + # Register applicants in the contest api = YandexContestAPI(access_token=campaign.access_token, refresh_token=campaign.refresh_token) registered_count = self.register_in_contest(api, applicants, request) - + # Add success message messages.success( request, _("Created {} olympiad records and registered {} applicants in the contest.").format(created_count, registered_count) ) - + return redirect("admission:applicants:list") @@ -1124,7 +1124,7 @@ def get_redirect_url(self, *args, **kwargs): class BranchFromURLViewMixin: """ This view mixin sets `branch` attribute to the request object based on - `request.site` and non-empty `branch_code` url named argument + `settings.SITE_ID` and non-empty `branch_code` url named argument """ def setup(self, request, *args, **kwargs): @@ -1135,7 +1135,7 @@ def setup(self, request, *args, **kwargs): f"{self.__class__} is subclass of {self.__class__.__name__} but " f"`branch_code` view keyword argument is not specified or empty" ) - request.branch = Branch.objects.get_by_natural_key(branch_code, request.site.id) + request.branch = Branch.objects.get_by_natural_key(branch_code, settings.SITE_ID) class InterviewResultsView( diff --git a/apps/core/context_processors.py b/apps/core/context_processors.py index 245d53d1f..d2eeeeaed 100644 --- a/apps/core/context_processors.py +++ b/apps/core/context_processors.py @@ -1,4 +1,5 @@ from django.conf import settings +from django.contrib.sites.models import Site def common_context(request): @@ -19,3 +20,10 @@ def js_config(request): "CSRF_COOKIE_NAME": settings.CSRF_COOKIE_NAME, "SENTRY_DSN": settings.SENTRY_DSN, } + + +def site_context(request): + """Add site object to the context for all views.""" + return { + "site": Site.objects.get(pk=settings.SITE_ID) + } diff --git a/apps/core/jinja2/globals.py b/apps/core/jinja2/globals.py index f07abfd97..3b32086c5 100644 --- a/apps/core/jinja2/globals.py +++ b/apps/core/jinja2/globals.py @@ -1,6 +1,8 @@ from crispy_forms.utils import render_crispy_form +from django.conf import settings from django.contrib.messages import DEFAULT_LEVELS, get_messages +from django.contrib.sites.models import Site from core.menu import Menu from jinja2 import pass_context @@ -40,3 +42,8 @@ def generate_menu(menu_name, request, root_id=None): @pass_context def crispy(context, form): return render_crispy_form(form, context=context) + + +def site_context(): + """Returns the site object based on settings.SITE_ID.""" + return Site.objects.get(pk=settings.SITE_ID) diff --git a/apps/core/models.py b/apps/core/models.py index 60b6dfd09..eb691762a 100644 --- a/apps/core/models.py +++ b/apps/core/models.py @@ -12,6 +12,7 @@ from django.utils.encoding import force_bytes, force_str, smart_str from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ +from django.contrib.sites.models import Site from core.db.fields import TimeZoneField from core.db.models import ConfigurationModel @@ -63,7 +64,7 @@ def get_current(self, request=None) -> "SiteConfiguration": """ Return the current site configuration based on the SITE_ID in the project's settings. If SITE_ID isn't defined, return the site - configuration matching ``request.site``. + configuration matching ``settings.SITE_ID``. The ``SiteConfiguration`` object is cached the first time it's retrieved from the database. @@ -71,7 +72,7 @@ def get_current(self, request=None) -> "SiteConfiguration": if getattr(settings, 'SITE_ID', None): site_id = settings.SITE_ID elif request: - site_id = request.site.pk + site_id = settings.SITE_ID else: raise ImproperlyConfigured( "Set the SITE_ID setting or pass a request to " @@ -231,16 +232,16 @@ def for_site(self, site_id: int, all=False) -> List["Branch"]: def get_current(self, request, site_id: int = settings.SITE_ID): """ - Returns the Branch based on the subdomain of the `request.site`, where + Returns the Branch based on the subdomain of the `settings.SITE_ID`, where subdomain is a branch code (e.g. nsk.example.com) If request is not provided, returns the Branch based on the DEFAULT_BRANCH_CODE value in the project's settings. """ - sub_domain = request.get_host().lower().rsplit(request.site.domain, 1)[0][:-1] + sub_domain = request.get_host().lower().rsplit(Site.objects.get(id=settings.SITE_ID).domain, 1)[0][:-1] branch_code = sub_domain or settings.DEFAULT_BRANCH_CODE if branch_code == "www": branch_code = settings.DEFAULT_BRANCH_CODE - key = BranchNaturalKey(code=branch_code, site_id=request.site.id) + key = BranchNaturalKey(code=branch_code, site_id=settings.SITE_ID) if key not in BRANCH_CACHE: BRANCH_CACHE[key] = self.get(code=key.code, site_id=key.site_id) return BRANCH_CACHE[key] diff --git a/apps/core/tests/test_models.py b/apps/core/tests/test_models.py index 410607245..c4ecc1771 100644 --- a/apps/core/tests/test_models.py +++ b/apps/core/tests/test_models.py @@ -47,8 +47,6 @@ def test_manager_site_configuration_get_current(rf, settings): request.path = '/' assert SiteConfiguration.objects.get_current() == site_configuration2 assert SiteConfiguration.objects.get_current(request) == site_configuration2 - settings.SITE_ID = None - assert SiteConfiguration.objects.get_current(request) == site_configuration1 @pytest.mark.django_db diff --git a/apps/courses/views/meta_course.py b/apps/courses/views/meta_course.py index 1f0c88c29..654960bfb 100644 --- a/apps/courses/views/meta_course.py +++ b/apps/courses/views/meta_course.py @@ -1,5 +1,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.views import generic +from django.conf import settings +from django.contrib.sites.models import Site from auth.mixins import PermissionRequiredMixin from courses.forms import MetaCourseForm @@ -17,7 +19,7 @@ class MetaCourseDetailView(LoginRequiredMixin, generic.DetailView): def get_context_data(self, **kwargs): courses = (Course.objects .filter(meta_course=self.object) - .available_on_site(self.request.site) + .available_on_site(Site.objects.get(pk=settings.SITE_ID)) .select_related("meta_course", "semester", "main_branch") .order_by('-semester__index')) context = { diff --git a/apps/courses/views/misc.py b/apps/courses/views/misc.py index b1fb7e17f..9e30208a6 100644 --- a/apps/courses/views/misc.py +++ b/apps/courses/views/misc.py @@ -2,6 +2,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.views import generic +from django.conf import settings from core.models import Branch, Location from courses.models import Course, CourseTeacher @@ -19,7 +20,7 @@ def get_queryset(self, *args, **kwargs): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - branches = Branch.objects.for_site(site_id=self.request.site.pk) + branches = Branch.objects.for_site(site_id=settings.SITE_ID) min_established = min(b.established for b in branches) # FIXME: move to service method and test courses = (Course.objects @@ -32,10 +33,10 @@ def get_context_data(self, **kwargs): teachers=self.object.pk) .select_related('semester', 'meta_course', 'main_branch') .order_by('-semester__index')) - + if not self.request.user.has_permission_to_drafts: courses = courses.is_published() - + context['courses'] = courses return context diff --git a/apps/courses/views/mixins.py b/apps/courses/views/mixins.py index 84abe16a9..71492005d 100644 --- a/apps/courses/views/mixins.py +++ b/apps/courses/views/mixins.py @@ -4,6 +4,7 @@ from django.conf import settings from django.http import Http404 from django.shortcuts import get_object_or_404 +from django.contrib.sites.models import Site from core.exceptions import Redirect from core.urls import reverse @@ -39,7 +40,7 @@ def setup(self, request, *args, **kwargs): meta_course__slug=kwargs['course_slug'], semester__type=kwargs['semester_type'], semester__year=kwargs['semester_year']) - .available_on_site(request.site) + .available_on_site(Site.objects.get(pk=settings.SITE_ID)) .order_by('pk') ) @@ -52,7 +53,7 @@ def get_course_queryset(self): class CoursePublicURLParamsMixin(CourseURLParamsMixinBase): """ This mixin helps to retrieve course made by the current site (where - main branch is related to the `request.site`), `RE_COURSE_PUBLIC_URI` + main branch is related to the `settings.SITE_ID`), `RE_COURSE_PUBLIC_URI` friendly URL prefix contains all the required parameters for this. Returns 404 in case course is not found, otherwise sets `course` attribute to the view instance. @@ -103,7 +104,7 @@ def setup(self, request, *args, **kwargs): courses = list(self.get_course_queryset() .filter(main_branch__code=main_branch_code, main_branch__active=True, - main_branch__site=request.site) + main_branch__site=Site.objects.get(pk=settings.SITE_ID)) .order_by('pk')) if not courses: raise Http404 diff --git a/apps/learning/api/views.py b/apps/learning/api/views.py index 2b4ebdd3b..7ee2b5ea8 100644 --- a/apps/learning/api/views.py +++ b/apps/learning/api/views.py @@ -10,6 +10,8 @@ from rest_framework.response import Response from django.utils.translation import gettext_lazy as _ +from django.conf import settings +from django.contrib.sites.models import Site from api.authentication import TokenAuthentication from api.mixins import ApiErrorsMixin @@ -109,7 +111,7 @@ def get(self, request: AuthenticatedAPIRequest, **kwargs: Any): queryset = (Enrollment.active .select_related('student') .filter(course=self.course, - course__main_branch__site=request.site)) + course__main_branch__site=Site.objects.get(pk=settings.SITE_ID))) data = self.OutputSerializer(queryset, many=True).data return Response(data) diff --git a/apps/learning/gradebook/views.py b/apps/learning/gradebook/views.py index c79596531..c377d2d3d 100644 --- a/apps/learning/gradebook/views.py +++ b/apps/learning/gradebook/views.py @@ -6,6 +6,7 @@ from rest_framework.response import Response from django.contrib import messages +from django.conf import settings from django.core.exceptions import PermissionDenied, ValidationError from django.db.models import Prefetch, Q, Count from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseRedirect @@ -14,6 +15,7 @@ from django.utils.translation import gettext_lazy as _ from django.views import View, generic from django.views.generic.base import TemplateResponseMixin +from django.contrib.sites.models import Site from api.views import APIBaseView from auth.mixins import PermissionRequiredMixin, RolePermissionRequiredMixin @@ -58,7 +60,7 @@ class GradeBookListBaseView(generic.ListView): def get_course_queryset(self): return (Course.objects - .available_on_site(self.request.site) + .available_on_site(Site.objects.get(pk=settings.SITE_ID)) .select_related("meta_course", "main_branch") .order_by("meta_course__name")) @@ -202,7 +204,7 @@ def get_context_data(self, form: BaseGradebookForm, .select_related('semester', 'meta_course', 'main_branch')) context['course_offering_list'] = courses context['user_type'] = self.user_type - + is_recredited_filter = Q(grade=GradeTypes.RE_CREDIT) | Q(is_grade_recredited=True) context.update( Enrollment.active.filter(course=self.course).aggregate( diff --git a/apps/learning/invitation/views.py b/apps/learning/invitation/views.py index c28156606..a924bb476 100644 --- a/apps/learning/invitation/views.py +++ b/apps/learning/invitation/views.py @@ -12,6 +12,7 @@ from django.http import Http404, HttpResponseRedirect, HttpResponseForbidden from django.shortcuts import get_object_or_404 from django.utils.translation import gettext_lazy as _ +from django.contrib.sites.models import Site from courses.models import Semester @@ -95,7 +96,7 @@ def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) elif self.invitation.semester != Semester.get_current(): return HttpResponseForbidden(_("Invitation is outdated")) - elif has_other_active_invited_profile(request.user, request.site, self.invitation): + elif has_other_active_invited_profile(request.user, Site.objects.get(pk=settings.SITE_ID), self.invitation): return HttpResponseForbidden(_("You already have other active invitation in this semester")) return super().dispatch(request, *args, **kwargs) @@ -106,7 +107,7 @@ def get(self, request, *args, **kwargs): kwargs={"token": self.invitation.token}, subdomain=settings.LMS_SUBDOMAIN) return HttpResponseRedirect(redirect_to=login_url) - if not is_student_profile_valid(request.user, request.site): + if not is_student_profile_valid(request.user, Site.objects.get(pk=settings.SITE_ID)): redirect_to = reverse("invitation:complete_profile", kwargs={"token": self.invitation.token}, subdomain=settings.LMS_SUBDOMAIN) @@ -237,7 +238,7 @@ class InvitationCompleteProfileView(InvitationURLParamsMixin, def dispatch(self, request, *args, **kwargs): if not request.user.is_authenticated: return self.handle_no_permission() - if is_student_profile_valid(request.user, request.site): + if is_student_profile_valid(request.user, Site.objects.get(pk=settings.SITE_ID)): return HttpResponseRedirect(self.invitation.get_absolute_url()) return super().dispatch(request, *args, **kwargs) @@ -254,7 +255,7 @@ def get_object(self): def form_valid(self, form): self.object = form.save(commit=False) - complete_student_profile(self.object, self.request.site, self.invitation) + complete_student_profile(self.object, Site.objects.get(pk=settings.SITE_ID), self.invitation) return HttpResponseRedirect(self.invitation.get_absolute_url()) def get_context_data(self, **kwargs): diff --git a/apps/learning/study/views.py b/apps/learning/study/views.py index 43c52b15e..cac6df76e 100644 --- a/apps/learning/study/views.py +++ b/apps/learning/study/views.py @@ -7,11 +7,13 @@ from django.apps import apps from django.contrib import messages +from django.conf import settings from django.db import transaction from django.db.models import Prefetch, Q from django.http import HttpResponseBadRequest, HttpResponseRedirect from django.utils.translation import gettext_lazy as _ from django.views import generic +from django.contrib.sites.models import Site from auth.mixins import PermissionRequiredMixin from core import comment_persistence @@ -62,7 +64,7 @@ class CalendarFullView(PermissionRequiredMixin, MonthEventsCalendarView): def get_events(self, month_period: MonthPeriod, **kwargs) -> Iterable: start_date, end_date = extended_month_date_range(month_period, expand=1) user = self.request.user - student_profile = get_student_profile(user, self.request.site) + student_profile = get_student_profile(user, Site.objects.get(pk=settings.SITE_ID)) branches = [student_profile.branch_id] return get_all_calendar_events(branch_list=branches, start_date=start_date, end_date=end_date, time_zone=user.time_zone) @@ -79,7 +81,7 @@ class CalendarPersonalView(CalendarFullView): def get_events(self, month_period: MonthPeriod, **kwargs) -> Iterable: start_date, end_date = extended_month_date_range(month_period, expand=1) student_profile = get_student_profile(self.request.user, - self.request.site) + Site.objects.get(pk=settings.SITE_ID)) if not student_profile: return [] return get_student_calendar_events(student_profile=student_profile, @@ -301,7 +303,7 @@ def get_context_data(self, **kwargs): # Get current term course offerings available in student branch, # courses in this term available via invitation # and all courses that student enrolled in - student_profile = get_student_profile(auth_user, self.request.site) + student_profile = get_student_profile(auth_user, Site.objects.get(pk=settings.SITE_ID)) current_term = get_current_term_pair(auth_user.time_zone) current_term_index = current_term.index enrolled_in = Q(id__in=list(student_enrollments)) @@ -358,10 +360,15 @@ class UsefulListView(PermissionRequiredMixin, generic.ListView): def get_queryset(self): return (InfoBlock.objects - .for_site(self.request.site) + .for_site(Site.objects.get(pk=settings.SITE_ID)) .with_tag(CurrentInfoBlockTags.USEFUL) .order_by("sort")) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['site'] = Site.objects.get(pk=settings.SITE_ID) + return context + class InternshipListView(PermissionRequiredMixin, generic.ListView): context_object_name = "faq" @@ -371,10 +378,15 @@ class InternshipListView(PermissionRequiredMixin, generic.ListView): def get_queryset(self): return (InfoBlock.objects - .for_site(self.request.site) + .for_site(Site.objects.get(pk=settings.SITE_ID)) .with_tag(CurrentInfoBlockTags.INTERNSHIP) .order_by("sort")) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['site'] = Site.objects.get(pk=settings.SITE_ID) + return context + class HonorCodeView(generic.ListView): context_object_name = "faq" @@ -382,10 +394,15 @@ class HonorCodeView(generic.ListView): def get_queryset(self): return (InfoBlock.objects - .for_site(self.request.site) + .for_site(Site.objects.get(pk=settings.SITE_ID)) .with_tag(CurrentInfoBlockTags.HONOR_CODE) .order_by("sort")) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['site'] = Site.objects.get(pk=settings.SITE_ID) + return context + class ProgramsView(generic.ListView): context_object_name = "faq" @@ -393,6 +410,11 @@ class ProgramsView(generic.ListView): def get_queryset(self): return (InfoBlock.objects - .for_site(self.request.site) + .for_site(Site.objects.get(pk=settings.SITE_ID)) .with_tag(CurrentInfoBlockTags.PROGRAMS) .order_by("sort")) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['site'] = Site.objects.get(pk=settings.SITE_ID) + return context diff --git a/apps/learning/teaching/views/__init__.py b/apps/learning/teaching/views/__init__.py index f8b53733a..8877aa1bb 100644 --- a/apps/learning/teaching/views/__init__.py +++ b/apps/learning/teaching/views/__init__.py @@ -6,6 +6,8 @@ from django.db.models import Prefetch, Q from django.shortcuts import get_object_or_404 from django.views import generic +from django.conf import settings +from django.contrib.sites.models import Site from auth.mixins import PermissionRequiredMixin from core.db.utils import normalize_score @@ -173,6 +175,6 @@ class TeachingUsefulListView(PermissionRequiredMixin, generic.ListView): def get_queryset(self): return (InfoBlock.objects - .for_site(self.request.site) + .for_site(Site.objects.get(pk=settings.SITE_ID)) .with_tag(CurrentInfoBlockTags.TEACHERS_USEFUL) .order_by("sort")) diff --git a/apps/learning/teaching/views/assignments.py b/apps/learning/teaching/views/assignments.py index 92fe77db8..d725cfede 100644 --- a/apps/learning/teaching/views/assignments.py +++ b/apps/learning/teaching/views/assignments.py @@ -20,6 +20,7 @@ from django.views import generic from django.views.generic.edit import BaseUpdateView from django.utils.translation import gettext_lazy as _ +from django.contrib.sites.models import Site from auth.mixins import PermissionRequiredMixin from core import comment_persistence @@ -137,7 +138,7 @@ def __init__(self, courses: List[Course], **kwargs): def get_context_data(self, **kwargs: Any) -> Dict[str, Any]: teacher = self.request.user courses = list(get_teacher_not_spectator_courses(teacher) - .filter(main_branch__site=self.request.site) + .filter(main_branch__site=Site.objects.get(pk=settings.SITE_ID)) .order_by("-semester__index", "meta_course__name")) if not courses: return {} diff --git a/apps/learning/views/enrollment.py b/apps/learning/views/enrollment.py index 410415079..c98afa4b8 100644 --- a/apps/learning/views/enrollment.py +++ b/apps/learning/views/enrollment.py @@ -6,6 +6,8 @@ from django.utils.translation import gettext_lazy as _ from django.views import generic from django.views.generic import FormView +from django.conf import settings +from django.contrib.sites.models import Site from auth.mixins import PermissionRequiredMixin from core.exceptions import Redirect @@ -32,7 +34,7 @@ class CourseEnrollView(CourseURLParamsMixin, PermissionRequiredMixin, FormView): permission_required = EnrollInCourse.name def get_permission_object(self): - site = self.request.site + site = Site.objects.get(pk=settings.SITE_ID) student_profile = self.request.user.get_student_profile(site) return EnrollPermissionObject(self.course, student_profile) @@ -63,7 +65,7 @@ def form_valid(self, form): reason_entry = form.cleaned_data.get("reason", "").strip() type = form.cleaned_data["type"].strip() user = self.request.user - student_profile = user.get_student_profile(self.request.site) + student_profile = user.get_student_profile(Site.objects.get(pk=settings.SITE_ID)) try: student_group = StudentGroupService.resolve(self.course, student_profile=student_profile) @@ -131,7 +133,7 @@ class CourseInvitationEnrollView(PermissionRequiredMixin, permission_required = EnrollInCourseByInvitation.name def get_permission_object(self): - site = self.request.site + site = Site.objects.get(pk=settings.SITE_ID) student_profile = self.request.user.get_student_profile(site) return InvitationEnrollPermissionObject(self.course_invitation, student_profile) @@ -144,7 +146,7 @@ def has_permission(self) -> bool: invitation = self.course_invitation.invitation raise Redirect(to=invitation.get_absolute_url()) return has_perm - + def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs['enrollment_type'] = self.course_invitation.enrollment_type @@ -166,7 +168,7 @@ def form_valid(self, form): type = form.cleaned_data["type"].strip() invitation = self.course_invitation.invitation user = self.request.user - student_profile = user.get_student_profile(self.request.site) + student_profile = user.get_student_profile(Site.objects.get(pk=settings.SITE_ID)) try: resolved_group = StudentGroupService.resolve(self.course, student_profile=student_profile, diff --git a/apps/learning/views/icalendar.py b/apps/learning/views/icalendar.py index 8944e38ec..e97c39794 100644 --- a/apps/learning/views/icalendar.py +++ b/apps/learning/views/icalendar.py @@ -8,6 +8,7 @@ from django.shortcuts import get_object_or_404 from django.utils import timezone from django.views import generic +from django.contrib.sites.models import Site from admission.selectors import get_ongoing_interviews from learning.icalendar import ( @@ -31,7 +32,7 @@ class ICalendarMeta(NamedTuple): class UserICalendarView(generic.base.View): def get(self, request, *args, **kwargs): user = self.get_user() - site = self.request.site + site = Site.objects.get(pk=settings.SITE_ID) url_builder = request.build_absolute_uri product_id = f"-//{site.name} Calendar//{site.domain}//" tz = user.time_zone or settings.DEFAULT_TIMEZONE diff --git a/apps/library/views.py b/apps/library/views.py index 868b37bff..e5b743643 100644 --- a/apps/library/views.py +++ b/apps/library/views.py @@ -1,9 +1,11 @@ from dal import autocomplete from vanilla import DetailView, ListView +from django.conf import settings from auth.mixins import PermissionRequiredMixin from learning.permissions import ViewLibrary from users.mixins import CuratorOnlyMixin +from django.contrib.sites.models import Site from .models import BookTag, Borrow, Stock @@ -27,13 +29,13 @@ class BookListView(PermissionRequiredMixin, ListView): def get_queryset(self): qs = (Stock.objects .select_related("branch", "book") - .filter(branch__site=self.request.site, + .filter(branch__site=Site.objects.get(pk=settings.SITE_ID), branch__active=True) .prefetch_related("borrows", "borrows__student")) # Students can see books from there branch only user = self.request.user if not user.is_curator: - student_profile = user.get_student_profile(self.request.site) + student_profile = user.get_student_profile(Site.objects.get(pk=settings.SITE_ID)) qs = qs.filter(branch_id=student_profile.branch_id) return qs @@ -53,14 +55,14 @@ class BookDetailView(PermissionRequiredMixin, DetailView): def get_queryset(self): qs = (Stock.objects - .filter(branch__site=self.request.site, + .filter(branch__site=Site.objects.get(pk=settings.SITE_ID), branch__active=True) .select_related("book") .prefetch_related("borrows")) # Students can see books from there branch only user = self.request.user if not user.is_curator: - student_profile = user.get_student_profile(self.request.site) + student_profile = user.get_student_profile(Site.objects.get(pk=settings.SITE_ID)) assert student_profile qs = qs.filter(branch_id=student_profile.branch_id) return qs diff --git a/apps/staff/api/views.py b/apps/staff/api/views.py index 927e215c5..f665971e6 100644 --- a/apps/staff/api/views.py +++ b/apps/staff/api/views.py @@ -5,6 +5,8 @@ from rest_framework.generics import ListAPIView from rest_framework.pagination import LimitOffsetPagination from rest_framework.response import Response +from django.conf import settings +from django.contrib.sites.models import Site from api.permissions import CuratorAccessPermission from api.views import APIBaseView @@ -42,7 +44,7 @@ def get_serializer_class(self): def get_queryset(self): return (StudentProfile.objects - .filter(site=self.request.site) + .filter(site=Site.objects.get(id=settings.SITE_ID)) .select_related('user', 'graduate_profile') .only('user__username', 'user__first_name', 'user__last_name', 'user_id') @@ -62,6 +64,6 @@ def post(self, request: HttpRequest, *args: Any, **kwargs: Any): serializer.is_valid(raise_exception=True) graduated_on = serializer.validated_data['graduated_on'] - create_graduate_profiles(request.site, graduated_on, created_by=request.user) + create_graduate_profiles(Site.objects.get(id=settings.SITE_ID), graduated_on, created_by=request.user) return Response(status=status.HTTP_201_CREATED) diff --git a/apps/staff/forms.py b/apps/staff/forms.py index c87870034..963e64ab3 100644 --- a/apps/staff/forms.py +++ b/apps/staff/forms.py @@ -9,6 +9,7 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from django.utils import timezone +from django.contrib.sites.models import Site from core.urls import reverse from core.widgets import DateInputTextWidget @@ -74,7 +75,7 @@ def clean(self): class BadgeNumberFromCSVForm(forms.Form): csv_file = forms.FileField(label=_('CSV file'), required=True) - + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper(self) @@ -93,7 +94,7 @@ def clean_csv_file(self): reader = csv.DictReader(decoded_file) except Exception as e: raise ValidationError(_(f"File read error: {str(e)}")) - + headers = reader.fieldnames required_columns = {"Почта", "Номер пропуска"} if not required_columns.issubset(set(headers)): @@ -109,12 +110,12 @@ def __init__(self, *args, **kwargs): # Get all years where there are graduates self.graduated_years = self.get_graduated_years() year_choices = [(year, str(year)) for year in self.graduated_years] - + self.fields['graduated_year'] = forms.ChoiceField( label=_("Year of Graduation"), choices=year_choices ) - + self.helper = FormHelper(self) self.helper.form_action = reverse("staff:export_for_electronic_diplomas") self.helper.layout = Layout( @@ -131,13 +132,13 @@ def get_graduated_years(self): # Get distinct year_of_curriculum values from StudentProfile # Optimize by only selecting the year_of_curriculum field and filtering by site current_year = timezone.now().year - + curriculum_years = StudentProfile.objects.filter( - site=self.request.site, + site=Site.objects.get(pk=settings.SITE_ID), year_of_curriculum__lte=current_year-2, status="" ).distinct('year_of_curriculum').values_list('year_of_curriculum', flat=True) - + return sorted([year + 2 for year in curriculum_years], reverse=True) def clean(self): @@ -147,7 +148,7 @@ def clean(self): raise ValidationError(_("Not supported graduation year")) except (ValueError, TypeError): raise ValidationError(_("Invalid year format")) - + class ConfirmSendLettersForm(forms.Form): """ @@ -156,13 +157,13 @@ class ConfirmSendLettersForm(forms.Form): """ email_template_id = forms.CharField(widget=forms.HiddenInput()) scheduled_time = forms.CharField(widget=forms.HiddenInput(), required=False) - + # These fields are just for display, not for actual form submission base_info_display = forms.CharField( label="", required=False, widget=forms.TextInput(attrs={ - 'readonly': 'readonly', + 'readonly': 'readonly', 'style': 'border: none; background-color: #f8f9fa; font-weight: bold; font-size: 1.2em; padding: 10px; border-radius: 5px;' }) ) @@ -182,15 +183,15 @@ class ConfirmSendLettersForm(forms.Form): required=False, widget=forms.TextInput(attrs={'readonly': 'readonly', 'style': 'border: none; background-color: #f8f9fa;'}) ) - + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - + self.helper = FormHelper(self) self.helper.form_action = reverse("staff:send_letters") self.helper.layout = Layout( - + Fieldset(_('Confirmation'), Row( Div('base_info_display', css_class="col-xs-12"), @@ -223,7 +224,7 @@ def __init__(self, *args, **kwargs): ), ) ) - + def get_emails(self): """ Get all emails from the form. @@ -287,7 +288,7 @@ class SendLettersForm(forms.Form): widget=forms.HiddenInput(), required=False ) - + def clean_scheduled_time(self): scheduled_time = self.cleaned_data.get('scheduled_time') if scheduled_time: @@ -301,23 +302,23 @@ def clean_scheduled_time(self): scheduled_time = self.tz.localize(naive_dt) else: scheduled_time = timezone.make_aware(scheduled_time, self.tz) - + return scheduled_time - + def clean_status(self): """Convert 'studying' back to empty string.""" statuses = self.cleaned_data.get('status', []) return ["" if s == "studying" else s for s in statuses] - + def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super().__init__(*args, **kwargs) - + self.tz = self.request.user.time_zone if self.request.user.time_zone else settings.DEFAULT_TIMEZONE local_time = timezone.localtime(timezone.now(), self.tz) self.fields['scheduled_time'].initial = local_time.strftime('%d.%m.%Y %H:%M') self.fields['scheduled_time'].help_text = f"Временная зона {getattr(self.tz, 'zone', str(self.tz))} {datetime.now(self.tz).strftime('%z')[:3]}" - + self.helper = FormHelper(self) self.helper.form_action = reverse("staff:confirm_send_letters") self.helper.layout = Layout( diff --git a/apps/staff/views/enrolees_selection.py b/apps/staff/views/enrolees_selection.py index 9b43e89df..b24e8d270 100644 --- a/apps/staff/views/enrolees_selection.py +++ b/apps/staff/views/enrolees_selection.py @@ -6,6 +6,8 @@ from django.utils.translation import gettext_lazy as _ from django.views import generic from django.utils import timezone +from django.conf import settings +from django.contrib.sites.models import Site import core.utils from core.utils import bucketize @@ -24,7 +26,7 @@ class EnroleesSelectionListView(CuratorOnlyMixin, generic.ListView): def get_course_queryset(self): return (Course.objects - .available_on_site(self.request.site) + .available_on_site(Site.objects.get(pk=settings.SITE_ID)) # TODO add selection_avaliable filter .select_related("meta_course", "main_branch") .order_by("meta_course__name")) @@ -32,7 +34,7 @@ def get_course_queryset(self): def get_term_threshold(self): latest_term = Semester.objects.order_by("-index").first() return latest_term.index - + def get_queryset(self): return (Semester.objects .filter(index__lte=self.get_term_threshold()) @@ -68,7 +70,7 @@ def get_context_data(self, **kwargs): "semester_list": semester_list } return context - + class EnroleesSelectionCSVView(CuratorOnlyMixin, CourseURLParamsMixin, generic.base.View): @@ -77,22 +79,22 @@ class EnroleesSelectionCSVView(CuratorOnlyMixin, CourseURLParamsMixin, GradeTypes.GOOD: 4, GradeTypes.EXCELLENT: 5 } - + def calculate_average_grades(self, students): for student in students: enrollments = [enrollment for profile in student.official_profiles for enrollment in profile.enrollment_set.all()] - numeric_satisfactory_grades = [self.grade_to_numeric[enrollment.grade] for enrollment in enrollments + numeric_satisfactory_grades = [self.grade_to_numeric[enrollment.grade] for enrollment in enrollments if enrollment.grade in self.grade_to_numeric and enrollment.course.is_visible_in_certificates] if not numeric_satisfactory_grades: yield student.id, "" else: yield student.id, round(statistics.fmean(numeric_satisfactory_grades), 3) - + def get(self, request, *args, **kwargs): enrollments = Enrollment.active.filter(course=self.course).select_related("student", "student_profile__branch", "student_profile__partner").order_by("student") student_profile_queryset = (StudentProfile.objects - .filter(site=request.site, + .filter(site=Site.objects.get(pk=settings.SITE_ID), type__in=[StudentTypes.REGULAR, StudentTypes.PARTNER], status__ne=StudentStatuses.EXPELLED) .order_by('year_of_admission', '-pk') @@ -101,7 +103,7 @@ def get(self, request, *args, **kwargs): users = (User.objects .filter(pk__in=enrollments.values_list("student__id", flat=True)) .prefetch_related(Prefetch("student_profiles", queryset=student_profile_queryset, to_attr="official_profiles"))) - + average_grades_map = dict(self.calculate_average_grades(users)) response = HttpResponse(content_type='text/csv; charset=utf-8') filename = "{}-{}-{}-enrolees-selection.csv".format(kwargs['course_slug'], @@ -131,4 +133,4 @@ def get(self, request, *args, **kwargs): student_profile.branch.name, student_profile.get_type_display(), student_profile.partner, student_profile.year_of_curriculum, enrollment.get_type_display(), enrollment.reason_entry, average_grades_map[student.id] ]) - return response \ No newline at end of file + return response diff --git a/apps/staff/views/views.py b/apps/staff/views/views.py index 15f47b45e..8ace5006b 100644 --- a/apps/staff/views/views.py +++ b/apps/staff/views/views.py @@ -18,6 +18,7 @@ from django.shortcuts import get_list_or_404, get_object_or_404 from django.utils.translation import gettext_lazy as _ from django.views import View, generic +from django.contrib.sites.models import Site import core.utils from admission.models import Campaign, Interview @@ -108,7 +109,7 @@ def get_context_data(self, **kwargs): "branches": {b.pk: b.name for b in branches}, "curriculum_years": ( StudentProfile.objects.filter( - site=self.request.site, year_of_curriculum__isnull=False + site=Site.objects.get(pk=settings.SITE_ID), year_of_curriculum__isnull=False ) .values_list("year_of_curriculum", flat=True) .order_by("year_of_curriculum") @@ -116,7 +117,7 @@ def get_context_data(self, **kwargs): ), "admission_years": ( StudentProfile.objects.filter( - site=self.request.site, year_of_admission__isnull=False + site=Site.objects.get(pk=settings.SITE_ID), year_of_admission__isnull=False ) .values_list("year_of_admission", flat=True) .order_by("year_of_admission") @@ -130,7 +131,7 @@ def get_context_data(self, **kwargs): "is_paid_basis": [("1", "Да"), ("0", "Нет")], "uni_graduation_year": ( StudentProfile.objects.filter( - site=self.request.site, + site=Site.objects.get(pk=settings.SITE_ID), graduation_year__isnull=False, graduate_without_diploma=True ) @@ -158,7 +159,7 @@ def get_context_data(self, **kwargs): badge_number_from_csv_form = BadgeNumberFromCSVForm() send_letters_form = SendLettersForm(request=self.request) official_diplomas_dates = ( - GraduateProfile.objects.for_site(self.request.site) + GraduateProfile.objects.for_site(Site.objects.get(pk=settings.SITE_ID)) .with_official_diploma() .distinct("diploma_issued_on") .order_by("-diploma_issued_on") @@ -679,7 +680,7 @@ def autofail_ungraded(request): if not request.user.is_curator: return HttpResponseForbidden() try: - graded = call_command("autofail_ungraded", request.site) + graded = call_command("autofail_ungraded", Site.objects.get(pk=settings.SITE_ID)) messages.success( request, f"Операция выполнена успешно.
" f"Выставлено незачетов: {graded}" ) @@ -696,7 +697,7 @@ def create_alumni_profiles(request: HttpRequest): form = GraduationForm(data=request.POST) if form.is_valid(): graduated_on = form.cleaned_data["graduated_on"] - create_graduate_profiles(request.site, graduated_on, created_by=request.user) + create_graduate_profiles(Site.objects.get(pk=settings.SITE_ID), graduated_on, created_by=request.user) messages.success(request, "Операция выполнена успешно") else: messages.error(request, "Неверный формат даты выпуска") @@ -768,7 +769,7 @@ def export_for_electronic_diplomas_view(request: HttpRequest): if form.is_valid(): graduated_year = int(form.cleaned_data["graduated_year"]) - return ElectronicDiplomaExportService.generate_export(request.site, graduated_year) + return ElectronicDiplomaExportService.generate_export(Site.objects.get(pk=settings.SITE_ID), graduated_year) else: for field, error_as_list in form.errors.items(): label = form.fields[field].label if field in form.fields else field @@ -853,7 +854,7 @@ def get_context_data(self, **kwargs): day = int(self.kwargs["day"]) date = datetime.date(year, month, day) graduate_profiles = get_list_or_404( - GraduateProfile.objects.for_site(self.request.site) + GraduateProfile.objects.for_site(Site.objects.get(pk=settings.SITE_ID)) .with_official_diploma() .filter(diploma_issued_on=date) .select_related("student_profile__user") @@ -878,7 +879,7 @@ def get(self, request, year, month, day, *args, **kwargs): diploma_issued_on = datetime.date(int(year), int(month), int(day)) report = OfficialDiplomasReport(diploma_issued_on) site_aware_queryset = report.get_queryset().filter( - branch__site=self.request.site + branch__site_id = settings.SITE_ID ) if not site_aware_queryset.count(): raise Http404 @@ -894,7 +895,7 @@ class OfficialDiplomasTeXView(CuratorOnlyMixin, generic.TemplateView): def get_context_data(self, year, month, day, **kwargs): diploma_issued_on = datetime.date(int(year), int(month), int(day)) report = OfficialDiplomasReport(diploma_issued_on) - student_profiles = report.get_queryset().filter(branch__site=self.request.site) + student_profiles = report.get_queryset().filter(branch__site_id = settings.SITE_ID) students = (sp.user for sp in student_profiles) courses_qs = report.get_courses_queryset(students).annotate( classes_total=Count("courseclass") diff --git a/apps/stats/views.py b/apps/stats/views.py index 3433619f9..9d0997668 100644 --- a/apps/stats/views.py +++ b/apps/stats/views.py @@ -31,7 +31,7 @@ class StatsLearningView(CuratorOnlyMixin, generic.TemplateView): def get_context_data(self, **kwargs): context = super(StatsLearningView, self).get_context_data(**kwargs) # Terms grouped by year - branches = Branch.objects.for_site(site_id=self.request.site.pk) + branches = Branch.objects.for_site(site_id=settings.SITE_ID) min_established = min(b.established for b in branches) term_start = get_term_index(min_established, SemesterTypes.AUTUMN) terms = (Semester.objects.only("pk", "type", "year") @@ -154,7 +154,7 @@ def get_interviewers(self): # TODO: move to learning or users app -# TODO SEEMS LIKE DEPRICATED +# TODO SEEMS LIKE DEPRICATED class AlumniStats(APIView): def get(self, request, graduation_year, format=None): filters = (Q(status=StudentStatuses.GRADUATE) & diff --git a/apps/templates/learning/study/honor_code.html b/apps/templates/learning/study/honor_code.html index 1515cc52b..a307a24fd 100644 --- a/apps/templates/learning/study/honor_code.html +++ b/apps/templates/learning/study/honor_code.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load i18n %} -{% block title %}Кодекс чести студента - {{ request.site.name }}{% endblock title %} +{% block title %}Кодекс чести студента - {{ site.name }}{% endblock title %} {% block content %}
diff --git a/apps/templates/learning/study/internships.html b/apps/templates/learning/study/internships.html index 78ff6c1de..10f9afb93 100644 --- a/apps/templates/learning/study/internships.html +++ b/apps/templates/learning/study/internships.html @@ -3,7 +3,7 @@ {% load static %} {% block body_attrs %} class="gray"{% endblock body_attrs %} {% load markdown from core_tags %} -{% block title %}Проекты организаторов - {{ request.site.name }}{% endblock title %} +{% block title %}Проекты организаторов - {{ site.name }}{% endblock title %} {% block content %}
diff --git a/apps/templates/learning/study/programs.html b/apps/templates/learning/study/programs.html index 5b4b9761d..bff8d6a08 100644 --- a/apps/templates/learning/study/programs.html +++ b/apps/templates/learning/study/programs.html @@ -2,7 +2,7 @@ {% load i18n %} {% load static %} {% block body_attrs %} class="gray"{% endblock body_attrs %} -{% block title %}Программы обучения - {{ request.site.name }}{% endblock title %} +{% block title %}Программы обучения - {{ site.name }}{% endblock title %} {% block content %}
@@ -21,4 +21,3 @@
{% endblock content %} - diff --git a/apps/templates/learning/study/useful.html b/apps/templates/learning/study/useful.html index 651917931..58bdbd18a 100644 --- a/apps/templates/learning/study/useful.html +++ b/apps/templates/learning/study/useful.html @@ -2,7 +2,7 @@ {% load i18n %} {% load static %} {% block body_attrs %} class="gray"{% endblock body_attrs %} -{% block title %}Полезное - {{ request.site.name }}{% endblock title %} +{% block title %}Полезное - {{ site.name }}{% endblock title %} {% block content %}
@@ -21,4 +21,3 @@
{% endblock content %} - diff --git a/apps/users/filters.py b/apps/users/filters.py index 0ef680ba8..d37e9741a 100644 --- a/apps/users/filters.py +++ b/apps/users/filters.py @@ -3,6 +3,8 @@ from django.db.models import Case, Count, F, Q, Value, When from django.forms import SelectMultiple +from django.conf import settings +from django.contrib.sites.models import Site from core.filters import CharInFilter, NumberInFilter from learning.settings import GradeTypes, StudentStatuses @@ -60,22 +62,19 @@ class StudentFilter(FilterSet): is_paid_basis = NumberInFilter(field_name='is_paid_basis') uni_graduation_year = NumberInFilter(label='University graduation year', method='uni_graduation_year_filter') - graduation_years = NumberInFilter(label='Graduation Year', - method='graduation_year_filter') class Meta: model = StudentProfile fields = ("name", "branches", "profile_types", "year_of_curriculum", "year_of_admission", "types", "status", "cnt_enrollments", - "academic_disciplines", "partners", "is_paid_basis", "uni_graduation_year", - "graduation_years") + "academic_disciplines", "partners", "is_paid_basis", "uni_graduation_year") @property def qs(self): if not self.form.changed_data: return self.queryset.none() - return super().qs.filter(site=self.request.site) + return super().qs.filter(site=Site.objects.get(pk=settings.SITE_ID)) def courses_filter(self, queryset, name, value): value_list = value.split(u',') @@ -114,13 +113,6 @@ def uni_graduation_year_filter(self, queryset, name, value): condition |= Q(graduate_without_diploma=True) return queryset.filter(condition) - def graduation_year_filter(self, queryset, name, value): - value_list = [int(v) for v in value if v != 0] - condition = Q(graduate_profile__graduation_year__in=value_list) - if any(year == 0 for year in value): - condition |= Q(graduate_profile__isnull=False) - return queryset.filter(condition) - def status_filter(self, queryset, name, value): value_list = value.split(u',') value_list = [v for v in value_list if v] diff --git a/apps/users/views.py b/apps/users/views.py index 52fb271d0..011967814 100644 --- a/apps/users/views.py +++ b/apps/users/views.py @@ -21,6 +21,7 @@ from django.utils.translation import gettext_lazy as _ from django.views import generic from django.views.decorators.csrf import csrf_exempt, csrf_protect +from django.contrib.sites.models import Site from api.views import APIBaseView from apps.courses.utils import date_to_term_pair @@ -70,7 +71,7 @@ def get_queryset(self, *args, **kwargs): # Limit results on compsciclub.ru if hasattr(self.request, "branch"): filters.append(Q(main_branch=self.request.branch)) - site_courses_queryset = get_site_courses(site=self.request.site, filters=filters) + site_courses_queryset = get_site_courses(site=Site.objects.get(pk=settings.SITE_ID), filters=filters) prefetch_list = [ Prefetch('teaching_set', queryset=site_courses_queryset), Prefetch('shadcourserecord_set', queryset=shad_courses_queryset), @@ -121,7 +122,7 @@ def get_context_data(self, **kwargs): "can_view_assignments": can_view_assignments, "can_view_course_icons": can_view_course_icons, "yandex_oauth_url": reverse('auth:users:yandex_begin'), - "is_yds_site": self.request.site.pk == settings.YDS_SITE_ID + "is_yds_site": settings.SITE_ID == settings.YDS_SITE_ID } enrollments = profile_user.enrollment_set.all().select_related("student_profile__invitation") for enrollment in enrollments: @@ -180,7 +181,7 @@ def get_context_data(self, **kwargs): enrollments=queryset) if can_view_student_profiles: student_profiles = get_student_profiles(user=profile_user, - site=self.request.site, + site=Site.objects.get(pk=settings.SITE_ID), fetch_graduate_profile=True, fetch_status_history=True, fetch_invitation=True, @@ -227,7 +228,7 @@ def is_form_allowed(self, user, obj): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) graduate_profile = get_graduate_profile_compat(self.object, - self.request.site) + Site.objects.get(pk=settings.SITE_ID)) if graduate_profile: context["testimonial_form"] = TestimonialForm( instance=graduate_profile) @@ -238,7 +239,7 @@ def form_valid(self, form): with transaction.atomic(): self.object = form.save() graduate_profile = get_graduate_profile_compat(self.object, - self.request.site) + Site.objects.get(pk=settings.SITE_ID)) if graduate_profile: testimonial_form = TestimonialForm(instance=graduate_profile, data=self.request.POST) @@ -295,7 +296,7 @@ class CertificateOfParticipationCreateView(PermissionRequiredMixin, def form_valid(self, form): user = get_object_or_404(User.objects.filter(pk=self.kwargs['user_id'])) - student_profile = get_student_profile(user=user, site=self.request.site, profile_type=StudentTypes.REGULAR) + student_profile = get_student_profile(user=user, site=Site.objects.get(pk=settings.SITE_ID), profile_type=StudentTypes.REGULAR) if student_profile is None: messages.error(self.request, "Профиль обычного студента не найден.") return redirect(self.get_success_url()) @@ -339,7 +340,7 @@ def get_queryset(self): return (CertificateOfParticipation.objects .filter(student_profile__user_id=self.kwargs['user_id']) .select_related('student_profile')) - + def filter_enrollments(self, enrollments): # Only courses within study period of regular student profile must be included start_term_pair = date_to_term_pair(datetime(day=1, month=9, year=self.object.student_profile.year_of_admission, diff --git a/lms/filters.py b/lms/filters.py index 088922483..a297b1965 100644 --- a/lms/filters.py +++ b/lms/filters.py @@ -6,6 +6,7 @@ from django.core.exceptions import ValidationError from django.forms import SlugField, forms from django.http import QueryDict +from django.contrib.sites.models import Site from core.models import Branch from courses.constants import SemesterTypes @@ -110,15 +111,15 @@ def __init__(self, data=None, queryset=None, request=None, **kwargs): branch_code = data.pop("branch", None) if request.user.is_authenticated and request.user.roles.issubset(student_permission_roles): profiles = get_student_profiles(user=request.user, - site=request.site) + site=Site.objects.get(pk=settings.SITE_ID)) user_branch_ids = [profile.branch_id for profile in profiles] self.user_branches = Branch.objects.filter( active=True, id__in=user_branch_ids, - site_id=request.site.pk + site_id=settings.SITE_ID ) main_branch_code = get_student_profile(user=request.user, - site=request.site).branch.code + site=Site.objects.get(pk=settings.SITE_ID)).branch.code if not branch_code and main_branch_code: branch_code = [main_branch_code] else: @@ -138,7 +139,7 @@ def __init__(self, data=None, queryset=None, request=None, **kwargs): if b.established <= current_term.academic_year] def get_branches(self, request): - return Branch.objects.for_site(request.site.pk) + return Branch.objects.for_site(settings.SITE_ID) @property def form(self): diff --git a/lms/jinja2/lms/admission/confirmation_of_acceptance.html b/lms/jinja2/lms/admission/confirmation_of_acceptance.html index 8e2ff2f0c..23d4a5e44 100644 --- a/lms/jinja2/lms/admission/confirmation_of_acceptance.html +++ b/lms/jinja2/lms/admission/confirmation_of_acceptance.html @@ -35,7 +35,7 @@

Форма авторизации

Создание профиля студента ШАД

Поздравляем вас с поступлением в Школу анализа данных и приглашаем создать профиль на сайте {{ - request.site.name }}.

+ site.name }}.

Подтвердите почту, проверьте информацию из анкеты и добавьте ту, которой не хватает. Обратите внимание, что все данные, которые вы здесь укажете, будут использоваться для зачисления в ШАД и для выдачи справок/диплома.

Если какие-то из неизменяемых полей заполнены неверно, то напишите на почту {{ contact_email }}

diff --git a/lms/jinja2/lms/layouts/_top_menu.html b/lms/jinja2/lms/layouts/_top_menu.html index 37f7b541d..df4105be3 100644 --- a/lms/jinja2/lms/layouts/_top_menu.html +++ b/lms/jinja2/lms/layouts/_top_menu.html @@ -10,7 +10,7 @@
- {{ request.site.name }} + {{ site().name }}
8 %} class="__narrow"{% endif %}> {% for menu_item in menu %} diff --git a/lms/jinja2/lms/layouts/_v2_top_menu.html b/lms/jinja2/lms/layouts/_v2_top_menu.html index 3ce487de8..0ad2413f5 100644 --- a/lms/jinja2/lms/layouts/_v2_top_menu.html +++ b/lms/jinja2/lms/layouts/_v2_top_menu.html @@ -14,7 +14,7 @@ aria-expanded="false" aria-label="Toggle navigation"> - diff --git a/lms/jinja2/lms/layouts/v1_base.html b/lms/jinja2/lms/layouts/v1_base.html index 85864b135..cd3e83224 100644 --- a/lms/jinja2/lms/layouts/v1_base.html +++ b/lms/jinja2/lms/layouts/v1_base.html @@ -5,7 +5,7 @@ - {% block title %}{{ request.site.name }}{% endblock title %} + {% block title %}{{ site().name }}{% endblock title %} @@ -63,7 +63,7 @@ diff --git a/lms/jinja2/lms/layouts/v2_base.html b/lms/jinja2/lms/layouts/v2_base.html index 696d3d674..21ad076aa 100644 --- a/lms/jinja2/lms/layouts/v2_base.html +++ b/lms/jinja2/lms/layouts/v2_base.html @@ -3,7 +3,7 @@ - {% block title %}{{ request.site.name }}{% endblock title %} + {% block title %}{{ site().name }}{% endblock title %} diff --git a/lms/jinja2/lms/study/course_list.html b/lms/jinja2/lms/study/course_list.html index 9e93d7ecd..6517ab133 100644 --- a/lms/jinja2/lms/study/course_list.html +++ b/lms/jinja2/lms/study/course_list.html @@ -43,7 +43,7 @@ {% if course.duration == CourseDurations.SECOND_HALF %} {% endif %} - {%- if request.site.pk != course.main_branch.site_id and course.is_club_course -%} + {%- if site.pk != course.main_branch.site_id and course.is_club_course -%} , курс CS клуба{% endif %}    @@ -90,7 +90,7 @@ {{ course.meta_course.name }} - {%- if request.site.pk != course.main_branch.site_id and course.is_club_course -%} + {%- if site.pk != course.main_branch.site_id and course.is_club_course -%} , курс CS клуба{% endif %} {% if course.duration == CourseDurations.FIRST_HALF %} diff --git a/lms/jinja2/lms/user_profile/user_detail.html b/lms/jinja2/lms/user_profile/user_detail.html index cd2a1a432..79814d382 100644 --- a/lms/jinja2/lms/user_profile/user_detail.html +++ b/lms/jinja2/lms/user_profile/user_detail.html @@ -3,7 +3,7 @@ {% set request_user = request.user %} {% block title -%} - {{ profile_user.get_short_name() }} - {% trans %}Profile{% endtrans %} {% trans %}on site{% endtrans %} {{ request.site.name }} + {{ profile_user.get_short_name() }} - {% trans %}Profile{% endtrans %} {% trans %}on site{% endtrans %} {{ site().name }} {%- endblock title %} {% block body_attrs %} data-init-sections="profile"{% endblock body_attrs %} diff --git a/lms/settings/base.py b/lms/settings/base.py index c5f9d6844..cc1b3011c 100644 --- a/lms/settings/base.py +++ b/lms/settings/base.py @@ -242,6 +242,7 @@ "messages": "core.jinja2.globals.messages", "get_menu": "core.jinja2.globals.generate_menu", "crispy": "core.jinja2.globals.crispy", + "site": "core.jinja2.globals.site_context", # FIXME: move from django template tags "can_enroll_in_course": "core.templatetags.core_tags.can_enroll_in_course", }, @@ -294,6 +295,7 @@ "core.context_processors.subdomain", "core.context_processors.common_context", "core.context_processors.js_config", + "core.context_processors.site_context", "django_admin_env_notice.context_processors.from_settings", ), "debug": DEBUG, diff --git a/lms/templates/_top_menu.html b/lms/templates/_top_menu.html index 8b56d78be..d40a8a0f4 100644 --- a/lms/templates/_top_menu.html +++ b/lms/templates/_top_menu.html @@ -13,7 +13,7 @@
- {{ request.site.name }} + {{ site.name }}
8 %} class="__narrow"{% endif %}> {% for menu_item in menu %} diff --git a/lms/templates/base.html b/lms/templates/base.html index ad9c5ee27..a1b39db3d 100644 --- a/lms/templates/base.html +++ b/lms/templates/base.html @@ -4,7 +4,7 @@ - {% block title %}{{ request.site.name }}{% endblock title %} + {% block title %}{{ site.name }}{% endblock title %} @@ -58,7 +58,7 @@ diff --git a/lms/views.py b/lms/views.py index 206f8e193..1ec58589f 100644 --- a/lms/views.py +++ b/lms/views.py @@ -10,6 +10,8 @@ from django.http import HttpResponseRedirect from django.utils.translation import pgettext_lazy from django.views import View +from django.conf import settings +from django.contrib.sites.models import Site from core.exceptions import Redirect from core.urls import reverse @@ -64,7 +66,7 @@ def get_queryset(self): )) courses = Course.objects - student_profile = user.get_student_profile(site=self.request.site) + student_profile = user.get_student_profile(site=Site.objects.get(pk=settings.SITE_ID)) if not user.is_curator and not user.is_teacher: if student_profile is None: courses = courses.none()