Skip to content

Commit

Permalink
Merge pull request #66 from hso-praktomat/upgrade-django
Browse files Browse the repository at this point in the history
Upgrade Django to version 5.1
  • Loading branch information
skogsbaer authored Sep 11, 2024
2 parents 636ae75 + 3cf8f9b commit 6a63c29
Show file tree
Hide file tree
Showing 132 changed files with 374 additions and 708 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12"]
defaults:
run:
shell: bash -l {0}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ Resources
* Running Checkers for Praktomat with docker: https://github.com/hso-praktomat/praktomat-checkers
* Moderated [mailing list] for Praktomat administrators: [email protected].

Python 3.8
Python 3.10
==========
The Praktomat currently requires at least Python 3.8. Older versions of Python may or may not work. Use them at your own risk.
The Praktomat currently requires at least Python 3.10. Older versions of Python may or may not work. Use them at your own risk.

On Ubuntu 22.04, Python 3.10 is available by default,
but you may need to additionaly install the packages
Expand Down
6 changes: 2 additions & 4 deletions documentation/ExampleChecker.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-

from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy
from checker.models import Checker, CheckerResult, execute
from checker.admin import CheckerInline, AlwaysChangedModelForm
from utilities.file_operations import *
Expand All @@ -12,7 +10,7 @@ class ExampleChecker(Checker):

# Add fields to configure checker instances. You can use any of the Django fields. (See online documentation)
# The fields created, task, public, required and always will be inherited from the abstract base class Checker
configuration_field = models.CharField(max_length=100, blank=True, default="I'm a test.", help_text=_("This text will be displayed under Charfield in the admin."))
configuration_field = models.CharField(max_length=100, blank=True, default="I'm a test.", help_text=gettext_lazy("This text will be displayed under Charfield in the admin."))

def title(self):
""" Return the name of this instance of the checker. This will be shown to the user if the checker is public. """
Expand Down
18 changes: 18 additions & 0 deletions media/styles/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,24 @@ body {
text-decoration: underline;
}

#logout-form {
display: inline;
}

#logout-form button {
background: none;
border: none;
cursor: pointer;
padding: 0;
color: white;
text-decoration: none;
font-size: 12px;
}

#logout-form button:hover {
text-decoration: underline;
}

/* @end */

/* @group Forms */
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
urllib3[secure]
Django~=2.2;python_version>="3.5"
Django~=5.1
# M2Crypto # has been removed by commit "use hashlib+smime for upload verification mails instead of M2Crypto" (19.1.2018)
Markdown
# Warning: updating Pygments currently breaks the syntax highlighting for annotated solution files.
Expand All @@ -11,7 +11,7 @@ django-extensions
# It appears that due to the pull-request https://github.com/aljosa/django-tinymce/pull/103 merged in django-tinymce==2.4.0, jquery is loaded after our onw jquery
# loaded in admin-sites. Using an old version of django-tinymce (2.3.x) is not possible because it uses methods removed between Django 1.8 and 1.11.
# We might want to use the django-admin provieded jquery in our admin-site jquery snippets?!?!?
django-tinymce~=3.0;python_version>="3.6"
django-tinymce~=4.1
django-debug-toolbar
docutils
psycopg2-binary
Expand Down
32 changes: 15 additions & 17 deletions src/accounts/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-

from random import randint
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy
from django.contrib import admin, messages
from django.contrib.auth.models import User as UserBase, Group
from django.contrib.auth.admin import UserAdmin as UserBaseAdmin, GroupAdmin as GroupBaseAdmin
Expand Down Expand Up @@ -31,11 +29,11 @@ class UserAdmin(UserBaseAdmin):
# exclude user_permissions
fieldsets = (
(None, {'fields': ('username', 'password', 'useful_links')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'mat_number', 'programme')}),
(_('Permissions'), {'fields': ('is_active', 'accepted_disclaimer', 'is_staff', 'is_superuser',)}),
(_('Groups'), {'fields': ('groups', 'tutorial')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
(_('Custom text'), {'fields': ('user_text',)}),
(gettext_lazy('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'mat_number', 'programme')}),
(gettext_lazy('Permissions'), {'fields': ('is_active', 'accepted_disclaimer', 'is_staff', 'is_superuser',)}),
(gettext_lazy('Groups'), {'fields': ('groups', 'tutorial')}),
(gettext_lazy('Important dates'), {'fields': ('last_login', 'date_joined')}),
(gettext_lazy('Custom text'), {'fields': ('user_text',)}),
)

form = AdminUserChangeForm
Expand Down Expand Up @@ -105,11 +103,11 @@ def export_users(self, request, queryset):
def get_urls(self):
""" Add URL to user import """
urls = super(UserAdmin, self).get_urls()
from django.conf.urls import url
my_urls = [url(r'^import/$', accounts.views.import_user, name='user_import')]
my_urls += [url(r'^import_ldap/$', accounts.views.import_ldap_user, name='ldap_user_import')]
my_urls += [url(r'^import_tutorial_assignment/$', accounts.views.import_tutorial_assignment, name='import_tutorial_assignment')]
my_urls += [url(r'^import_user_texts/$', accounts.views.import_user_texts, name='import_user_texts')]
from django.urls import re_path
my_urls = [re_path(r'^import/$', accounts.views.import_user, name='user_import')]
my_urls += [re_path(r'^import_ldap/$', accounts.views.import_ldap_user, name='ldap_user_import')]
my_urls += [re_path(r'^import_tutorial_assignment/$', accounts.views.import_tutorial_assignment, name='import_tutorial_assignment')]
my_urls += [re_path(r'^import_user_texts/$', accounts.views.import_user_texts, name='import_user_texts')]
return my_urls + urls

def useful_links(self, instance):
Expand Down Expand Up @@ -144,10 +142,10 @@ def save_model(self, request, obj, form, change):
# This should work in Django 1.4 :O
# from django.contrib.admin import SimpleListFilter
# class FailedRegistrationAttempts(admin.SimpleListFilter):
# title = _('Registration')
# title = gettext_lazy('Registration')
#
# def lookups(self,request,model_admin):
# return ( (('failed'), _('failed')), (('successfull'), _('sucessfull')) )
# return ( (('failed'), gettext_lazy('failed')), (('successfull'), gettext_lazy('sucessfull')) )
#
# def queryset(self,request,users):
# failed = User.objects.all().values('mat_number').annotate(failed=Count('mat_number')).filter(failed__gt=1)
Expand All @@ -165,8 +163,8 @@ class GroupAdmin(GroupBaseAdmin):
def get_urls(self):
""" Add URL to user import """
urls = super(GroupAdmin, self).get_urls()
from django.conf.urls import url
my_urls = [url(r'^(\d+)/import_matriculation_list/$', accounts.views.import_matriculation_list, name='import_matriculation_list')]
from django.urls import re_path
my_urls = [re_path(r'^(\d+)/import_matriculation_list/$', accounts.views.import_matriculation_list, name='import_matriculation_list')]
return my_urls + urls

admin.site.unregister(Group)
Expand Down
12 changes: 6 additions & 6 deletions src/accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.conf import settings
from django.db import models, transaction
from django.template import loader
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy
from django.contrib.auth.models import Group
from django import forms
from django.contrib.auth.forms import UserCreationForm as UserBaseCreationForm, UserChangeForm as UserBaseChangeForm
Expand Down Expand Up @@ -60,8 +60,8 @@ def clean_mat_number(self):


@transaction.atomic
def save(self):
user = super(MyRegistrationForm, self).save()
def save(self, *args, **kwargs):
user = super(MyRegistrationForm, self).save(*args, **kwargs)

# default group: user
user.groups.set(Group.objects.filter(name='User'))
Expand Down Expand Up @@ -89,13 +89,13 @@ def save(self):

if get_settings().account_manual_validation:
t = loader.get_template('registration/registration_email_manual_to_staff.html')
send_mail(_("Account activation on %s for %s (%s) ") % (settings.SITE_NAME, user.username, str(user)), t.render(c), None, [staff.email for staff in User.objects.all().filter(is_staff=True)])
send_mail(gettext_lazy("Account activation on %s for %s (%s) ") % (settings.SITE_NAME, user.username, str(user)), t.render(c), None, [staff.email for staff in User.objects.all().filter(is_staff=True)])

t = loader.get_template('registration/registration_email_manual_to_user.html')
send_mail(_("Account activation on %s") % settings.SITE_NAME, t.render(c), None, [user.email])
send_mail(gettext_lazy("Account activation on %s") % settings.SITE_NAME, t.render(c), None, [user.email])
else:
t = loader.get_template('registration/registration_email.html')
send_mail(_("Account activation on %s") % settings.SITE_NAME, t.render(c), None, [user.email])
send_mail(gettext_lazy("Account activation on %s") % settings.SITE_NAME, t.render(c), None, [user.email])

return user

Expand Down
1 change: 0 additions & 1 deletion src/accounts/ldap_auth.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# SB HBRS
from accounts.models import User
from configuration import get_settings
Expand Down
3 changes: 0 additions & 3 deletions src/accounts/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-


from django.db import migrations, models
from django.conf import settings
import django.contrib.auth.models
Expand Down
3 changes: 0 additions & 3 deletions src/accounts/migrations/0002_add_groups.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-


from django.db import migrations, models

def add_groups(apps, schema_editor):
Expand Down
3 changes: 0 additions & 3 deletions src/accounts/migrations/0003_add_coordinator_group.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-


from django.db import migrations, models

def add_coordinator_group(apps, schema_editor):
Expand Down
2 changes: 0 additions & 2 deletions src/accounts/migrations/0005_on_delete_set_null.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-08-12 13:31
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion
Expand Down
23 changes: 9 additions & 14 deletions src/accounts/models.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
# -*- coding: utf-8 -*-

from __future__ import unicode_literals


import datetime
import re
import hashlib
import random

from functools import reduce

from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy
from django.conf import settings
from django.db import models, utils
from django.contrib.auth.models import User as BasicUser, UserManager
Expand All @@ -33,12 +28,12 @@ def validate_mat_number(value):

class User(BasicUser):
# all fields need to be null-able in order to create user
tutorial = models.ForeignKey('Tutorial', on_delete=models.SET_NULL, null=True, blank=True, help_text = _("The tutorial the student belongs to."))
tutorial = models.ForeignKey('Tutorial', on_delete=models.SET_NULL, null=True, blank=True, help_text = gettext_lazy("The tutorial the student belongs to."))
mat_number = models.IntegerField( null=True, blank=True, validators=[validate_mat_number]) # special blank and unique validation in forms
final_grade = models.CharField( null=True, blank=True, max_length=100, help_text = _('The final grade for the whole class.'))
programme = models.CharField(null=True, blank=True, max_length=100, help_text = _('The programme the student is enlisted in.'))
activation_key=models.CharField(_('activation key'), max_length=40, editable=False)
user_text=models.CharField(null=True, blank=True, max_length=500, help_text = _("Custom text which will be shown to this student."))
final_grade = models.CharField( null=True, blank=True, max_length=100, help_text = gettext_lazy('The final grade for the whole class.'))
programme = models.CharField(null=True, blank=True, max_length=100, help_text = gettext_lazy('The programme the student is enlisted in.'))
activation_key=models.CharField(gettext_lazy('activation key'), max_length=40, editable=False)
user_text=models.CharField(null=True, blank=True, max_length=500, help_text = gettext_lazy("Custom text which will be shown to this student."))
accepted_disclaimer=models.BooleanField(default=False, help_text="Whether the user accepted the disclaimer.")

# Use UserManager to get the create_user method, etc.
Expand Down Expand Up @@ -221,13 +216,13 @@ def create_user_for_basicuser(sender, **kwargs):
signals.post_save.connect(create_user_for_basicuser, sender=BasicUser)

class Tutorial(models.Model):
name = models.CharField(max_length=100, blank=True, help_text=_("The name of the tutorial"))
name = models.CharField(max_length=100, blank=True, help_text=gettext_lazy("The name of the tutorial"))
# A Tutorial may have many tutors as well as a Tutor may have multiple tutorials
tutors = models.ManyToManyField('User', limit_choices_to = {'groups__name': 'Tutor'}, related_name='tutored_tutorials', help_text = _("The tutors in charge of the tutorial."))
tutors = models.ManyToManyField('User', limit_choices_to = {'groups__name': 'Tutor'}, related_name='tutored_tutorials', help_text = gettext_lazy("The tutors in charge of the tutorial."))

def tutors_flat(self):
return reduce(lambda x, y: x + ', ' + y.get_full_name(), self.tutors.all(), '')[2:]
tutors_flat.short_description = _('Tutors')
tutors_flat.short_description = gettext_lazy('Tutors')

def __str__(self):
return("%s: %s" % (self.name, self.tutors_flat()))
4 changes: 0 additions & 4 deletions src/accounts/tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# -*- coding: utf-8 -*-

from __future__ import unicode_literals

from utilities.TestSuite import TestCase

from accounts.models import User
Expand Down
46 changes: 23 additions & 23 deletions src/accounts/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.conf.urls import *
from django.urls import *
from django.views.generic.base import TemplateView

from django.conf import settings # for switching via ACCOUNT_CHANGE_POSSIBLE
Expand All @@ -14,31 +14,31 @@

# TODO check if URLS are working after solving merge conflicts
urlpatterns = [
url(r'^shib_login/$', accounts.shib_views.shib_login, name='shib_login'),
url(r'^shib_hello/$', accounts.shib_views.shib_hello, name='shib_hello'),
url(r'^login/$', auth_views.LoginView.as_view(), {'template_name': 'registration/login.html'}, name='login'),
url(r'^logout/$', auth_views.logout_then_login, name='logout'),
#url(r'^change/$', accounts.views.change, name='registration_change'),
url(r'^view/$', accounts.views.view, name='registration_view'),
#url(r'^password/change/$', auth_views.PasswordChangeView.as_view(), name='password_change'),
#url(r'^password/change/done/$', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
#url(r'^password/reset/$', auth_views.PasswordResetView.as_view(), name='password_reset'),
url(r'^accept_disclaimer/$', accounts.views.accept_disclaimer, name='accept_disclaimer'),
re_path(r'^shib_login/$', accounts.shib_views.shib_login, name='shib_login'),
re_path(r'^shib_hello/$', accounts.shib_views.shib_hello, name='shib_hello'),
re_path(r'^login/$', auth_views.LoginView.as_view(), {'template_name': 'registration/login.html'}, name='login'),
re_path(r'^logout/$', auth_views.logout_then_login, name='logout'),
#re_path(r'^change/$', accounts.views.change, name='registration_change'),
re_path(r'^view/$', accounts.views.view, name='registration_view'),
#re_path(r'^password/change/$', auth_views.PasswordChangeView.as_view(), name='password_change'),
#re_path(r'^password/change/done/$', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
#re_path(r'^password/reset/$', auth_views.PasswordResetView.as_view(), name='password_reset'),
re_path(r'^accept_disclaimer/$', accounts.views.accept_disclaimer, name='accept_disclaimer'),
]
if settings.ACCOUNT_CHANGE_POSSIBLE:
urlpatterns += [
url(r'^change/$', accounts.views.change, name='registration_change'),
url(r'^password/change/$', auth_views.PasswordChangeView.as_view(), name='password_change'),
url(r'^password/change/done/$', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
url(r'^password/reset/$', auth_views.PasswordResetView.as_view(), name='password_reset'),
url(r'^password/reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
re_path(r'^change/$', accounts.views.change, name='registration_change'),
re_path(r'^password/change/$', auth_views.PasswordChangeView.as_view(), name='password_change'),
re_path(r'^password/change/done/$', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
re_path(r'^password/reset/$', auth_views.PasswordResetView.as_view(), name='password_reset'),
re_path(r'^password/reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
auth_views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm'),
url(r'^password/reset/complete/$', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
url(r'^password/reset/done/$', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
url(r'^register/$', accounts.views.register, name='registration_register'),
url(r'^register/complete/$', TemplateView.as_view(template_name='registration/registration_complete.html'), name='registration_complete'),
url(r'^register/allow/(?P<user_id>\d+)/$', accounts.views.activation_allow, name='activation_allow'),
url(r'^activate/(?P<activation_key>.+)/$', accounts.views.activate, name='registration_activate'),
url(r'^deactivated/$', accounts.views.deactivated, name='registration_deactivated'),
re_path(r'^password/reset/complete/$', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
re_path(r'^password/reset/done/$', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
re_path(r'^register/$', accounts.views.register, name='registration_register'),
re_path(r'^register/complete/$', TemplateView.as_view(template_name='registration/registration_complete.html'), name='registration_complete'),
re_path(r'^register/allow/(?P<user_id>\d+)/$', accounts.views.activation_allow, name='activation_allow'),
re_path(r'^activate/(?P<activation_key>.+)/$', accounts.views.activate, name='registration_activate'),
re_path(r'^deactivated/$', accounts.views.deactivated, name='registration_deactivated'),
]
6 changes: 3 additions & 3 deletions src/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from django.contrib import messages
from django.utils.http import int_to_base36
from django.core.mail import send_mail
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy
from configuration import get_settings
from accounts.forms import ImportLDAPForm
from accounts.ldap_auth import fetch_ldapuser_dict, create_localuser_from_ldapuser
Expand Down Expand Up @@ -60,7 +60,7 @@ def activation_allow(request, user_id):
'activation_key': user.activation_key,
'expiration_days': get_settings().acount_activation_days,
}
send_mail(_("Account activation on %s") % settings.SITE_NAME, t.render(c), None, [user.email])
send_mail(gettext_lazy("Account activation on %s") % settings.SITE_NAME, t.render(c), None, [user.email])
return render(request, 'registration/registration_activation_allowed.html', { 'new_user': user, })

@local_user_required
Expand Down Expand Up @@ -113,7 +113,7 @@ def import_user(request):
'activation_key': user.activation_key,
'expiration_days': get_settings().acount_activation_days,
}
send_mail(_("Account activation on %s") % settings.SITE_NAME, t.render(c), None, [user.email])
send_mail(gettext_lazy("Account activation on %s") % settings.SITE_NAME, t.render(c), None, [user.email])
return HttpResponseRedirect(reverse('admin:accounts_user_changelist'))
except:
raise
Expand Down
Loading

0 comments on commit 6a63c29

Please sign in to comment.