Free and open source ticket system written in python

๐Ÿ‘Œ IMPROVE: Update check for google sso when changing email

+118 -4
+18
core/migrations/0004_rename_user_googlessouser_paw_user.py
··· 1 + # Generated by Django 5.0.3 on 2024-03-10 20:43 2 + 3 + from django.db import migrations 4 + 5 + 6 + class Migration(migrations.Migration): 7 + 8 + dependencies = [ 9 + ("core", "0003_googlessouser"), 10 + ] 11 + 12 + operations = [ 13 + migrations.RenameField( 14 + model_name="googlessouser", 15 + old_name="user", 16 + new_name="paw_user", 17 + ), 18 + ]
+29
core/migrations/0005_remove_googlessouser_id_alter_googlessouser_paw_user.py
··· 1 + # Generated by Django 5.0.3 on 2024-03-10 20:43 2 + 3 + import django.db.models.deletion 4 + from django.conf import settings 5 + from django.db import migrations, models 6 + 7 + 8 + class Migration(migrations.Migration): 9 + 10 + dependencies = [ 11 + ("core", "0004_rename_user_googlessouser_paw_user"), 12 + ] 13 + 14 + operations = [ 15 + migrations.RemoveField( 16 + model_name="googlessouser", 17 + name="id", 18 + ), 19 + migrations.AlterField( 20 + model_name="googlessouser", 21 + name="paw_user", 22 + field=models.OneToOneField( 23 + on_delete=django.db.models.deletion.CASCADE, 24 + primary_key=True, 25 + serialize=False, 26 + to=settings.AUTH_USER_MODEL, 27 + ), 28 + ), 29 + ]
+2 -1
core/models.py
··· 15 15 16 16 17 17 class GoogleSSOUser(models.Model): 18 - user = models.OneToOneField(PawUser, on_delete=models.CASCADE) 18 + paw_user = models.OneToOneField( 19 + PawUser, on_delete=models.CASCADE, primary_key=True) 19 20 google_id = models.CharField(max_length=255) 20 21 21 22 def __str__(self):
+9 -2
core/views.py
··· 2 2 from django.contrib.auth import logout, login 3 3 from .forms import UserChangeForm, RegisterForm, AccountFinishForm 4 4 from django.contrib.auth.forms import AuthenticationForm 5 - from .models import PawUser 5 + from .models import PawUser, GoogleSSOUser 6 6 from django.utils import translation 7 7 from django.conf import settings 8 8 from django.contrib.auth.decorators import login_required ··· 90 90 return redirect("login") 91 91 92 92 user, created = PawUser.objects.get_or_create(email=user_info["email"]) 93 + 94 + if created: 95 + GoogleSSOUser.objects.create(user=user, google_id=user_info["id"]) 96 + 93 97 login(request, user) 94 98 if created or not user.username: 95 99 form = AccountFinishForm() ··· 110 114 if request.method == "POST": 111 115 form = UserChangeForm(request.POST, request.FILES) 112 116 if form.is_valid(): 117 + print(form.cleaned_data) 113 118 if form.cleaned_data["language"] != request.user.language: 114 119 translation.activate(form.cleaned_data["language"]) 115 120 changed_user_language = True 116 121 117 - request.user.email = form.cleaned_data["email"] 122 + if not request.user.googlessouser: 123 + request.user.email = form.cleaned_data["email"] 124 + 118 125 request.user.language = form.cleaned_data["language"] 119 126 request.user.telegram_username = form.cleaned_data["telegram_username"] 120 127 request.user.use_darkmode = form.cleaned_data["use_darkmode"]
+1 -1
paw/__init__.py
··· 1 1 from django import get_version 2 2 3 - VERSION = (0, 1, 0, "beta", 11) 3 + VERSION = (0, 1, 0, "beta", 12) 4 4 5 5 __version__ = get_version(VERSION)
+4
paw/settings.py
··· 72 72 "django.contrib.messages.context_processors.messages", 73 73 'paw.templatetags.context_processors.app_version', 74 74 ], 75 + 'libraries': { 76 + 'filters': 'paw.templatetags.filters', 77 + }, 75 78 }, 76 79 }, 77 80 ] ··· 148 151 DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" 149 152 150 153 LOGIN_REDIRECT_URL = "/tickets" 154 + LOGIN_URL = "/login" 151 155 152 156 # Google SSO 153 157 GOOGLE_OAUTH_ENABLED = True
+5
paw/templates/core/settings.html
··· 2 2 {% extends 'dashboard_base.html' %} 3 3 {% block dashboard_content %} 4 4 {% load i18n %} 5 + {% load filters %} 5 6 <div class="w-full max-w-4xl mx-auto p-8"> 6 7 <h1 class="text-2xl font-bold mb-4">{% trans 'Settings' %}</h1> 7 8 <form method="post"> ··· 10 11 <div class="label"> 11 12 <span for="{{ form.email.id_for_label }}" class="label-text font-semibold text-base-content">{% trans 'Mail Address' %}</span> 12 13 </div> 14 + {% if request.user.googlessouser %} 15 + {{ form.email|add_attr:'class:input input-bordered w-full input-disabled,readonly:' }} 16 + {% else %} 13 17 {{ form.email }} 18 + {% endif %} 14 19 </label> 15 20 16 21 <label class="form-control w-full mb-2">
+17
paw/templatetags/filters.py
··· 1 + from django.template import Library 2 + register = Library() 3 + 4 + 5 + @register.filter(name='add_attr') 6 + def add_attr(field, attr_list): 7 + attrs = {} 8 + definition = attr_list.split(',') 9 + 10 + for d in definition: 11 + if ':' not in d: 12 + attrs['class'] = d 13 + else: 14 + key, val = d.split(':') 15 + attrs[key] = val 16 + 17 + return field.as_widget(attrs=attrs)
+33
static/css/paw.css
··· 1108 1108 } 1109 1109 1110 1110 @media (hover: hover) { 1111 + .btm-nav > *.disabled:hover, 1112 + .btm-nav > *[disabled]:hover { 1113 + pointer-events: none; 1114 + --tw-border-opacity: 0; 1115 + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); 1116 + --tw-bg-opacity: 0.1; 1117 + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); 1118 + --tw-text-opacity: 0.2; 1119 + } 1120 + 1111 1121 .btn:hover { 1112 1122 --tw-border-opacity: 1; 1113 1123 border-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity))); ··· 1401 1411 text-decoration-line: underline; 1402 1412 } 1403 1413 1414 + .menu li.disabled { 1415 + cursor: not-allowed; 1416 + -webkit-user-select: none; 1417 + -moz-user-select: none; 1418 + user-select: none; 1419 + color: var(--fallback-bc,oklch(var(--bc)/0.3)); 1420 + } 1421 + 1404 1422 :where(.menu li) .badge { 1405 1423 justify-self: end; 1406 1424 } ··· 1650 1668 .badge-outline.badge-error { 1651 1669 --tw-text-opacity: 1; 1652 1670 color: var(--fallback-er,oklch(var(--er)/var(--tw-text-opacity))); 1671 + } 1672 + 1673 + .btm-nav > *.disabled, 1674 + .btm-nav > *[disabled] { 1675 + pointer-events: none; 1676 + --tw-border-opacity: 0; 1677 + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); 1678 + --tw-bg-opacity: 0.1; 1679 + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); 1680 + --tw-text-opacity: 0.2; 1653 1681 } 1654 1682 1655 1683 .btm-nav > * .label { ··· 3230 3258 .text-white { 3231 3259 --tw-text-opacity: 1; 3232 3260 color: rgb(255 255 255 / var(--tw-text-opacity)); 3261 + } 3262 + 3263 + .text-gray-900 { 3264 + --tw-text-opacity: 1; 3265 + color: rgb(17 24 39 / var(--tw-text-opacity)); 3233 3266 } 3234 3267 3235 3268 .underline {