diff --git a/course/models.py b/course/models.py index 1b43be705..165b452c4 100644 --- a/course/models.py +++ b/course/models.py @@ -16,6 +16,7 @@ from django.db.models.signals import post_save from django.utils import timezone from django.utils.functional import cached_property +from django.utils.text import format_lazy from django.utils.translation import ugettext_lazy as _ from django_colortag.models import ColorTag @@ -450,6 +451,11 @@ def __str__(self): def clean(self): super().clean() errors = {} + RESERVED = ("instances",) + if self.instance_name in RESERVED: + errors['instance_name'] = format_lazy(_("You cannot use word '{}' as an instance name."), self.instance_name) + if self.url in RESERVED: + errors['url'] = format_lazy(_("You cannot use word '{}' in the url."), self.url) if self.ending_time <= self.starting_time: errors['ending_time'] = _("Ending time must be later than starting time.") if self.lifesupport_time and self.lifesupport_time < self.ending_time: diff --git a/course/templates/course/course_instances.html b/course/templates/course/course_instances.html new file mode 100644 index 000000000..63bd7b566 --- /dev/null +++ b/course/templates/course/course_instances.html @@ -0,0 +1,29 @@ +{% extends "base.html" %} +{% load i18n %} +{% load course %} + +{% block title %}{% trans "Course instances" %} | {{ block.super }}{% endblock %} +{% block view_tag %}instances{% endblock %} + +{% block content %} +
+ + {% if instances %} + {% regroup instances by starting_time|date:"Y" as instances_by_year %} + {% for year, year_instances in instances_by_year %} +
+
+

{{ year }}

+
+
+ {% include "course/_course_cards.html" with instances=year_instances condensed=True %} +
+
+ {% endfor %} + {% else %} +

{{ msg }}

+ {% endif %} +
+{% endblock %} diff --git a/course/urls.py b/course/urls.py index 209d9888e..a710051e2 100644 --- a/course/urls.py +++ b/course/urls.py @@ -16,6 +16,12 @@ url(r'^archive/$', views.ArchiveView.as_view(), name="archive"), + url(COURSE_URL_PREFIX + r'instances/$', + views.CourseInstancesView.as_view(), + name="course_instances"), + url(COURSE_URL_PREFIX + r'$', + views.LastInstanceView.as_view(), + name="course_last_instance"), url(INSTANCE_URL_PREFIX + r'$', views.InstanceView.as_view(), name="course"), diff --git a/course/views.py b/course/views.py index 2dcd25e1c..e161d08f7 100644 --- a/course/views.py +++ b/course/views.py @@ -21,13 +21,13 @@ from exercise.cache.hierarchy import NoSuchContent from exercise.models import LearningObject from lib.helpers import settings_text, remove_query_param_from_url -from lib.viewbase import BaseTemplateView, BaseRedirectMixin, BaseFormView, BaseView +from lib.viewbase import BaseTemplateView, BaseRedirectMixin, BaseFormView, BaseView, BaseRedirectView from userprofile.viewbase import UserProfileView from .forms import GroupsForm, GroupSelectForm -from .models import CourseInstance, Enrollment +from .models import CourseInstance, Course, Enrollment from .permissions import EnrollInfoVisiblePermission from .renders import group_info_context -from .viewbase import CourseModuleBaseView, CourseInstanceMixin, EnrollableViewMixin +from .viewbase import CourseModuleBaseView, CourseInstanceMixin, EnrollableViewMixin, CourseMixin class HomeView(UserProfileView): @@ -89,6 +89,38 @@ def get_common_objects(self): self.instances = CourseInstance.objects.get_visible(self.request.user) self.note("instances") +class CourseInstancesView(UserProfileView): + access_mode = ACCESS.ANONYMOUS + template_name = "course/course_instances.html" + + def get_common_objects(self, **kwargs): + course = get_object_or_404(Course, url=self.kwargs['course_slug']) + self.instances = [] + self.msg = "" + if CourseInstance.objects.filter(course=course).count() > 0: + self.instances = CourseInstance.objects.get_visible(self.request.user).filter(course=course).order_by('-starting_time') + self.msg = _("The course instances of this course are not visible to students.") + else: + self.msg = _("There are no course instances for this course.") + + self.note("instances", "msg") + +class LastInstanceView(CourseMixin, BaseRedirectView): + access_mode = ACCESS.STUDENT + + def get_resource_objects(self): + super().get_resource_objects() + course = get_object_or_404(Course, url=self._get_kwarg(self.course_kw)) + course_instances = CourseInstance.objects.filter(course=course).order_by('-starting_time') + + if course_instances: + self.course_instance = course_instances[0] + else: + raise Http404(_("There are no course instances for this course.")) + + def get(self, request, *args, **kwargs): + return self.redirect(self.course_instance.url) + class InstanceView(EnrollableViewMixin, BaseTemplateView): access_mode = ACCESS.STUDENT # ACCESS.STUDENT requires users to log in, but the access mode is dropped diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index 8c8ccc471..cb50c972b 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -223,6 +223,14 @@ msgstr "" "sähköposteihin. Syötä pilkuilla erotettuja sähköpostiosoitteita korvaamaan " "oletusvastaanottajat." +#: course/models.py +msgid "You cannot use word '{}' as an instance name." +msgstr "Et voi käyttää sanaa {} ilmentymän nimenä." + +#: course/models.py +msgid "You cannot use word '{}' in the url." +msgstr "Et voi käyttää sanaa {} URL-osoitteessa." + #: course/models.py msgid "Ending time must be later than starting time." msgstr "Päättymisajan tulee olla alkamisajan jälkeen." @@ -601,6 +609,11 @@ msgstr "Aseta kurssikieleksi %(lang)s" msgid "You can change the language from your profile." msgstr "Voit muuttaa kielivalintaa profiilistasi." +#: course/templates/course/course_instances.html +#: edit_course/templates/edit_course/clone_instance.html +msgid "Course instances" +msgstr "Kurssikerrat" + #: course/templates/course/enroll.html msgid "Enrollment" msgstr "Ilmoittautuminen" @@ -887,6 +900,14 @@ msgstr "Sähköposti" msgid "Tags" msgstr "Merkinnät" +#: course/views.py +msgid "The course instances of this course are not visible to students." +msgstr "Kurssin esiintymät eivät ole opiskelijoiden nähtävissä." + +#: course/views.py +msgid "There are no course instances for this course." +msgstr "Tällä kurssilla ei ole esiintymiä." + #: course/views.py msgid "You cannot enroll, or have already enrolled, in this course." msgstr "Et voi ilmoittautua tai olet jo ilmoittautunut tälle kurssille." @@ -1286,10 +1307,6 @@ msgstr "Käännös kesken" msgid "Instances" msgstr "Kurssikerrat" -#: edit_course/templates/edit_course/clone_instance.html -msgid "Course instances" -msgstr "Kurssikerrat" - #: edit_course/templates/edit_course/clone_instance.html msgid "hidden" msgstr "piilotettu"