Merge pull request 'Save user language' (#12) from dev into main
Reviewed-on: #12
This commit is contained in:
commit
05ca8ac322
|
@ -14,4 +14,4 @@ class WishAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
@admin.register(PflaenzliUser)
|
@admin.register(PflaenzliUser)
|
||||||
class UserAdmin(admin.ModelAdmin):
|
class UserAdmin(admin.ModelAdmin):
|
||||||
list_display = ['id', 'username', 'email', 'zipcode', 'date_joined']
|
list_display = ['id', 'username', 'email', 'zipcode', 'language_code', 'date_joined']
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Generated by Django 4.1.10 on 2023-07-22 16:52
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("pflaenzli", "0004_offer_category"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="pflaenzliuser",
|
||||||
|
name="language_code",
|
||||||
|
field=models.CharField(default="de", max_length=2),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="offer",
|
||||||
|
name="category",
|
||||||
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("PLNT", "Plant"),
|
||||||
|
("SEED", "Seedling"),
|
||||||
|
("POT", "Pots"),
|
||||||
|
("TOOL", "Tools"),
|
||||||
|
("OTHR", "Other"),
|
||||||
|
],
|
||||||
|
default="PLNT",
|
||||||
|
max_length=4,
|
||||||
|
verbose_name="Category",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -11,6 +11,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
class PflaenzliUser(AbstractUser):
|
class PflaenzliUser(AbstractUser):
|
||||||
email = models.EmailField(max_length=254)
|
email = models.EmailField(max_length=254)
|
||||||
zipcode = models.PositiveIntegerField(blank=True, null=True, verbose_name=_('ZIP code'))
|
zipcode = models.PositiveIntegerField(blank=True, null=True, verbose_name=_('ZIP code'))
|
||||||
|
language_code = models.CharField(max_length=2, default='de')
|
||||||
|
|
||||||
|
|
||||||
class Offer(models.Model):
|
class Offer(models.Model):
|
||||||
|
|
|
@ -20,8 +20,10 @@
|
||||||
const setTheme = function(theme) {
|
const setTheme = function(theme) {
|
||||||
if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
document.documentElement.setAttribute('data-bs-theme', 'dark')
|
document.documentElement.setAttribute('data-bs-theme', 'dark')
|
||||||
|
set_captcha_theme('dark', 0)
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.setAttribute('data-bs-theme', theme)
|
document.documentElement.setAttribute('data-bs-theme', theme)
|
||||||
|
set_captcha_theme(theme, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,3 +62,16 @@
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})()
|
})()
|
||||||
|
|
||||||
|
function set_captcha_theme(theme, set_try) {
|
||||||
|
var captchaDiv = document.getElementById("id_captcha");
|
||||||
|
|
||||||
|
if (captchaDiv) {
|
||||||
|
console.log("Set the theme on try" + set_try)
|
||||||
|
if (theme == 'dark') {
|
||||||
|
captchaDiv.classList.add("dark");
|
||||||
|
} else {
|
||||||
|
captchaDiv.classList.remove("dark");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -46,7 +46,6 @@
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"
|
||||||
integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN"
|
integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
<script src="{% static 'bootstrap-color-toggler.js' %}"></script>
|
|
||||||
{% block head %}{% endblock %}
|
{% block head %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body class="d-flex flex-column h-100 justify-content-between {% block background %}{% endblock background %}">
|
<body class="d-flex flex-column h-100 justify-content-between {% block background %}{% endblock background %}">
|
||||||
|
@ -93,10 +92,10 @@
|
||||||
{% get_language_info_list for LANGUAGES as languages %}
|
{% get_language_info_list for LANGUAGES as languages %}
|
||||||
{% for language in languages %}
|
{% for language in languages %}
|
||||||
<li>
|
<li>
|
||||||
<form method="POST" action="{% url 'set_language' %}">
|
<form method="POST" action="{% url 'save_language' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="language" value="{{ language.code }}" />
|
<input type="hidden" name="language" value="{{ language.code }}" />
|
||||||
<button class="dropdown-item d-flex align-items-center {% if language.code == LANGUAGE_CODE %} active{% endif %}"
|
<button class="dropdown-item d-flex align-items-center {% if language.code == LANGUAGE_CODE %}active{% endif %}"
|
||||||
type="submit">
|
type="submit">
|
||||||
{{ language.name_local }} ({{ language.code }})
|
{{ language.name_local }} ({{ language.code }})
|
||||||
</button>
|
</button>
|
||||||
|
@ -215,5 +214,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
<script src="{% static 'bootstrap-color-toggler.js' %}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -24,7 +24,7 @@ urlpatterns = [
|
||||||
path("accounts/<int:user_id>", views.user_detail, name="user_detail"),
|
path("accounts/<int:user_id>", views.user_detail, name="user_detail"),
|
||||||
path("accounts/<int:user_id>/wishlist/", views.wishlist, name="wishlist"),
|
path("accounts/<int:user_id>/wishlist/", views.wishlist, name="wishlist"),
|
||||||
path('accounts/login/', auth_views.LoginView.as_view(template_name='registration/login.html')),
|
path('accounts/login/', auth_views.LoginView.as_view(template_name='registration/login.html')),
|
||||||
path('accounts/profile/', auth_views.LoginView.as_view(template_name='user/detail.html'), name='user_profile'),
|
path('accounts/profile/', TemplateView.as_view(template_name='user/detail.html'), name='user_profile'),
|
||||||
path('accounts/profile/edit', views.user_edit, name='user_edit'),
|
path('accounts/profile/edit', views.user_edit, name='user_edit'),
|
||||||
path('accounts/register/', views.register_user, name='register_user'),
|
path('accounts/register/', views.register_user, name='register_user'),
|
||||||
path('accounts/password_reset/', auth_views.PasswordResetView.as_view(template_name='registration/verify_email.html',
|
path('accounts/password_reset/', auth_views.PasswordResetView.as_view(template_name='registration/verify_email.html',
|
||||||
|
@ -39,6 +39,8 @@ urlpatterns = [
|
||||||
path("faq/", TemplateView.as_view(template_name='app/faq.html'), name="faq"),
|
path("faq/", TemplateView.as_view(template_name='app/faq.html'), name="faq"),
|
||||||
path("imprint/", TemplateView.as_view(template_name='app/imprint.html'), name="imprint"),
|
path("imprint/", TemplateView.as_view(template_name='app/imprint.html'), name="imprint"),
|
||||||
path("wish/delete/<str:wish_id>", views.delete_wish, name='delete_wish'),
|
path("wish/delete/<str:wish_id>", views.delete_wish, name='delete_wish'),
|
||||||
|
path("save_language/", views.save_language, name="save_language"),
|
||||||
|
path("load_language/", views.load_language, name="load_language"),
|
||||||
path("i18n/", include("django.conf.urls.i18n")),
|
path("i18n/", include("django.conf.urls.i18n")),
|
||||||
path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
|
path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
|
||||||
name='django.contrib.sitemaps.views.sitemap'),
|
name='django.contrib.sitemaps.views.sitemap'),
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
from django.shortcuts import render, get_object_or_404, redirect, reverse
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import login
|
from django.contrib.auth import login
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.http import HttpResponseForbidden
|
||||||
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import activate, get_language
|
||||||
from django.views.decorators.csrf import csrf_protect
|
from django.views.decorators.csrf import csrf_protect
|
||||||
from django.views.decorators.http import require_POST
|
from django.views.decorators.http import require_POST
|
||||||
from django.http import HttpResponseForbidden
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
|
from .forms import CreateOfferForm, FilterForm, RegistrationForm, WishForm
|
||||||
from .forms import CreateOfferForm, RegistrationForm, FilterForm, WishForm
|
|
||||||
|
|
||||||
from .models import PflaenzliUser, Offer, Wish
|
|
||||||
from .mail import send_offer_email
|
from .mail import send_offer_email
|
||||||
|
from .models import Offer, PflaenzliUser, Wish
|
||||||
from .upload import generate_unique_filename
|
from .upload import generate_unique_filename
|
||||||
from .utils.distance import calculate_distance, filter_by_distance
|
|
||||||
from .utils.compress_image import compress_image
|
from .utils.compress_image import compress_image
|
||||||
|
from .utils.distance import calculate_distance, filter_by_distance
|
||||||
|
|
||||||
|
|
||||||
def list_offers(request, filters=None):
|
def list_offers(request, filters=None):
|
||||||
|
@ -184,6 +183,7 @@ def register_user(request):
|
||||||
form = RegistrationForm(request.POST)
|
form = RegistrationForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
user = form.save()
|
user = form.save()
|
||||||
|
user.language_code = get_language()
|
||||||
login(request, user)
|
login(request, user)
|
||||||
return redirect("index")
|
return redirect("index")
|
||||||
else:
|
else:
|
||||||
|
@ -192,6 +192,34 @@ def register_user(request):
|
||||||
return render(request, "basic_form.html", {"form": form, "button_label": _("Register"), "title": _("Registeration"), "umami_event": "User registration"})
|
return render(request, "basic_form.html", {"form": form, "button_label": _("Register"), "title": _("Registeration"), "umami_event": "User registration"})
|
||||||
|
|
||||||
|
|
||||||
|
def save_language(request):
|
||||||
|
referer_url = request.META.get('HTTP_REFERER')
|
||||||
|
response = redirect(referer_url)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
if language_code := request.POST.get('language'):
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
user = request.user
|
||||||
|
user.language_code = language_code
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
activate(language_code)
|
||||||
|
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language_code)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def load_language(request):
|
||||||
|
response = redirect('user_profile')
|
||||||
|
language_code = request.user.language_code
|
||||||
|
|
||||||
|
activate(language_code)
|
||||||
|
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language_code)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def error_404(request, exception):
|
def error_404(request, exception):
|
||||||
return render(request, '404.html')
|
return render(request, '404.html')
|
||||||
|
|
||||||
|
|
|
@ -56,12 +56,12 @@ INSTALLED_APPS = [
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
"django.middleware.security.SecurityMiddleware",
|
"django.middleware.security.SecurityMiddleware",
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
"django.middleware.common.CommonMiddleware",
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
"django.middleware.csrf.CsrfViewMiddleware",
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
"django.middleware.common.CommonMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = "pflaenzli_django.urls"
|
ROOT_URLCONF = "pflaenzli_django.urls"
|
||||||
|
@ -126,6 +126,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
AUTH_USER_MODEL = 'pflaenzli.PflaenzliUser'
|
AUTH_USER_MODEL = 'pflaenzli.PflaenzliUser'
|
||||||
|
LOGIN_REDIRECT_URL = "/load_language"
|
||||||
LOGOUT_REDIRECT_URL = "/"
|
LOGOUT_REDIRECT_URL = "/"
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
crispy-bootstrap5==0.7
|
crispy-bootstrap5==0.7
|
||||||
Django==4.1.10
|
Django==4.1.11
|
||||||
djangoloco==1.0
|
djangoloco==1.0
|
||||||
django-bootstrap5==22.2
|
django-bootstrap5==23.3
|
||||||
django-crispy-forms==2.0
|
django-crispy-forms==2.0
|
||||||
django-jquery==3.1.0
|
django-jquery==3.1.0
|
||||||
django-friendly-captcha==0.1.7
|
django-friendly-captcha==0.1.8
|
||||||
geopy==2.3.0
|
geopy==2.4.0
|
||||||
gunicorn==20.1.0
|
gunicorn==21.2.0
|
||||||
fontawesomefree==6.3.0
|
fontawesomefree==6.4.2
|
||||||
pandas==2.0.0
|
pandas==2.1.0
|
||||||
Pillow==9.4.0
|
Pillow==10.0.0
|
||||||
psycopg2-binary==2.9.5
|
psycopg2-binary==2.9.7
|
||||||
python-dotenv==1.0.0
|
python-dotenv==1.0.0
|
||||||
|
|
Loading…
Reference in a new issue