Compare commits

...

3 Commits

Author SHA1 Message Date
Victor Andersson
65b249f2f8 fix: show edit button and translations 2025-11-11 21:09:59 +01:00
Victor Andersson
3d8e5ed410 feat: allow editing user profile info via modal 2025-11-11 21:04:33 +01:00
Victor Andersson
73ff0a9d45 fix: use precomputed permission flags in template 2025-11-11 20:48:12 +01:00
8 changed files with 380 additions and 141 deletions

View File

@@ -160,6 +160,42 @@ class UserPermissionForm(forms.Form):
grant_change = forms.BooleanField(required=False, label=_("Får besluta utlägg")) grant_change = forms.BooleanField(required=False, label=_("Får besluta utlägg"))
grant_edit = forms.BooleanField(required=False, label=_("Får redigera utlägg")) grant_edit = forms.BooleanField(required=False, label=_("Får redigera utlägg"))
grant_pay = forms.BooleanField(required=False, label=_("Får markera betalningar")) grant_pay = forms.BooleanField(required=False, label=_("Får markera betalningar"))
first_name = forms.CharField(
max_length=150,
required=False,
label=_("Förnamn"),
widget=forms.TextInput(attrs={"class": INPUT_CLASSES}),
)
last_name = forms.CharField(
max_length=150,
required=False,
label=_("Efternamn"),
widget=forms.TextInput(attrs={"class": INPUT_CLASSES}),
)
email = forms.EmailField(
required=False,
label=_("E-post"),
widget=forms.EmailInput(attrs={"class": INPUT_CLASSES}),
)
new_password1 = forms.CharField(
required=False,
label=_("Nytt lösenord"),
widget=forms.PasswordInput(attrs={"class": INPUT_CLASSES}),
)
new_password2 = forms.CharField(
required=False,
label=_("Bekräfta nytt lösenord"),
widget=forms.PasswordInput(attrs={"class": INPUT_CLASSES}),
)
def clean(self):
cleaned = super().clean()
pwd1 = cleaned.get("new_password1")
pwd2 = cleaned.get("new_password2")
if pwd1 or pwd2:
if pwd1 != pwd2:
self.add_error("new_password2", _("Lösenorden matchar inte."))
return cleaned
class DeleteUserForm(forms.Form): class DeleteUserForm(forms.Form):

View File

@@ -105,23 +105,47 @@
{{ user.get_full_name|default:_("Saknar namn") }} · {{ user.email|default:_("Ingen e-post") }} {{ user.get_full_name|default:_("Saknar namn") }} · {{ user.email|default:_("Ingen e-post") }}
</p> </p>
</div> </div>
<p class="text-xs uppercase tracking-wide text-gray-400">ID: {{ user.id }}</p> <div class="flex items-center gap-3">
<p class="text-xs uppercase tracking-wide text-gray-400">ID: {{ user.id }}</p>
{% if can_change_users %}
<button type="button"
data-open-permission-edit="{{ user.id }}"
class="inline-flex items-center gap-2 rounded-full border border-gray-200 px-3 py-1 text-xs font-semibold text-gray-700 transition hover:bg-gray-100">
{% trans "Redigera användare" %}
</button>
{% endif %}
</div>
</div> </div>
<div class="mt-4 grid gap-6 lg:grid-cols-[2fr,1fr]"> <div class="mt-4 grid gap-6 lg:grid-cols-[2fr,1fr]">
<div class="rounded-2xl bg-slate-50 p-4"> <div class="rounded-2xl bg-slate-50 p-4">
<p class="text-sm font-semibold text-gray-700">{% trans "Behörigheter" %}</p> <p class="text-sm font-semibold text-gray-700">{% trans "Behörigheter" %}</p>
<div class="mt-3 flex flex-wrap gap-2 text-xs"> <div class="mt-3 flex flex-wrap gap-2 text-xs">
<span class="rounded-full px-3 py-1 {% if user.is_staff %}bg-emerald-100 text-emerald-800{% else %}bg-slate-200 text-slate-600{% endif %}">{% trans "Admin/staff" %}</span> {% if row.permission_flags.is_staff %}
<span class="rounded-full px-3 py-1 {% if user.has_perm('claims.view_claim') %}bg-blue-100 text-blue-800{% else %}bg-slate-200 text-slate-600{% endif %}">{% trans "Får se utlägg" %}</span> <span class="rounded-full px-3 py-1 bg-emerald-100 text-emerald-800">{% trans "Admin/staff" %}</span>
<span class="rounded-full px-3 py-1 {% if user.has_perm('claims.change_claim') %}bg-indigo-100 text-indigo-800{% else %}bg-slate-200 text-slate-600{% endif %}">{% trans "Får besluta utlägg" %}</span> {% endif %}
<span class="rounded-full px-3 py-1 {% if user.has_perm('claims.edit_claim_details') %}bg-purple-100 text-purple-800{% else %}bg-slate-200 text-slate-600{% endif %}">{% trans "Får redigera utlägg" %}</span> {% if row.permission_flags.view %}
<span class="rounded-full px-3 py-1 {% if user.has_perm('claims.mark_claim_paid') %}bg-amber-100 text-amber-800{% else %}bg-slate-200 text-slate-600{% endif %}">{% trans "Får markera betalningar" %}</span> <span class="rounded-full px-3 py-1 bg-blue-100 text-blue-800">{% trans "Får se utlägg" %}</span>
{% endif %}
{% if row.permission_flags.change %}
<span class="rounded-full px-3 py-1 bg-indigo-100 text-indigo-800">{% trans "Får besluta utlägg" %}</span>
{% endif %}
{% if row.permission_flags.edit %}
<span class="rounded-full px-3 py-1 bg-purple-100 text-purple-800">{% trans "Får redigera utlägg" %}</span>
{% endif %}
{% if row.permission_flags.pay %}
<span class="rounded-full px-3 py-1 bg-amber-100 text-amber-800">{% trans "Får markera betalningar" %}</span>
{% endif %}
{% if not row.permission_flags.is_staff and not row.permission_flags.view and not row.permission_flags.change and not row.permission_flags.edit and not row.permission_flags.pay %}
<span class="rounded-full bg-slate-200 px-3 py-1 text-slate-600">{% trans "Inga behörigheter tilldelade" %}</span>
{% endif %}
</div> </div>
<button type="button" {% if can_change_users %}
data-open-permission-edit="{{ user.id }}" <button type="button"
class="mt-4 inline-flex items-center gap-2 rounded-full bg-brand-600 px-4 py-2 text-sm font-semibold text-white transition hover:bg-brand-700"> data-open-permission-edit="{{ user.id }}"
{% trans "Redigera behörigheter" %} class="mt-4 inline-flex items-center gap-2 rounded-full bg-brand-600 px-4 py-2 text-sm font-semibold text-white transition hover:bg-brand-700">
</button> {% trans "Redigera behörigheter" %}
</button>
{% endif %}
</div> </div>
<div class="rounded-2xl border border-red-100 bg-red-50 p-4 text-sm text-red-800"> <div class="rounded-2xl border border-red-100 bg-red-50 p-4 text-sm text-red-800">
<p class="font-semibold">{% trans "Ta bort konto" %}</p> <p class="font-semibold">{% trans "Ta bort konto" %}</p>
@@ -155,8 +179,9 @@
{% block modals %} {% block modals %}
{{ block.super }} {{ block.super }}
{% for row in user_rows %} {% if can_change_users %}
{% with user=row.user form=row.permission_form %} {% for row in user_rows %}
{% with user=row.user form=row.permission_form %}
<div class="fixed inset-0 z-40 hidden items-center justify-center bg-slate-900/80 p-4" <div class="fixed inset-0 z-40 hidden items-center justify-center bg-slate-900/80 p-4"
data-permission-modal="{{ user.id }}" data-permission-modal="{{ user.id }}"
aria-hidden="true" aria-hidden="true"
@@ -178,7 +203,55 @@
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="action" value="update"> <input type="hidden" name="action" value="update">
{{ form.user_id }} {{ form.user_id }}
<div class="space-y-3 text-sm text-gray-800"> <div class="space-y-5 text-sm text-gray-800">
<div>
<p class="text-xs font-semibold uppercase tracking-wide text-gray-500">{% trans "Kontaktuppgifter" %}</p>
<div class="mt-3 grid gap-3 md:grid-cols-2">
<div>
<label class="text-xs font-semibold text-gray-600" for="{{ form.first_name.id_for_label }}">{{ form.first_name.label }}</label>
{{ form.first_name }}
{% for error in form.first_name.errors %}
<p class="text-xs text-rose-600">{{ error }}</p>
{% endfor %}
</div>
<div>
<label class="text-xs font-semibold text-gray-600" for="{{ form.last_name.id_for_label }}">{{ form.last_name.label }}</label>
{{ form.last_name }}
{% for error in form.last_name.errors %}
<p class="text-xs text-rose-600">{{ error }}</p>
{% endfor %}
</div>
<div class="md:col-span-2">
<label class="text-xs font-semibold text-gray-600" for="{{ form.email.id_for_label }}">{{ form.email.label }}</label>
{{ form.email }}
{% for error in form.email.errors %}
<p class="text-xs text-rose-600">{{ error }}</p>
{% endfor %}
</div>
</div>
</div>
<div>
<p class="text-xs font-semibold uppercase tracking-wide text-gray-500">{% trans "Lösenord" %}</p>
<div class="mt-3 grid gap-3 md:grid-cols-2">
<div>
<label class="text-xs font-semibold text-gray-600" for="{{ form.new_password1.id_for_label }}">{{ form.new_password1.label }}</label>
{{ form.new_password1 }}
{% for error in form.new_password1.errors %}
<p class="text-xs text-rose-600">{{ error }}</p>
{% endfor %}
</div>
<div>
<label class="text-xs font-semibold text-gray-600" for="{{ form.new_password2.id_for_label }}">{{ form.new_password2.label }}</label>
{{ form.new_password2 }}
{% for error in form.new_password2.errors %}
<p class="text-xs text-rose-600">{{ error }}</p>
{% endfor %}
</div>
</div>
<p class="mt-1 text-xs text-gray-500">{% trans "Lämna fälten tomma för att behålla nuvarande lösenord." %}</p>
</div>
<div class="space-y-3">
<p class="text-xs font-semibold uppercase tracking-wide text-gray-500">{% trans "Behörigheter" %}</p>
<label class="flex items-center gap-3" for="{{ form.is_staff.id_for_label }}"> <label class="flex items-center gap-3" for="{{ form.is_staff.id_for_label }}">
{{ form.is_staff }} {{ form.is_staff }}
<span>{% trans "Admin/staff" %}</span> <span>{% trans "Admin/staff" %}</span>
@@ -199,6 +272,7 @@
{{ form.grant_pay }} {{ form.grant_pay }}
<span>{% trans "Får markera betalningar" %}</span> <span>{% trans "Får markera betalningar" %}</span>
</label> </label>
</div>
</div> </div>
<div class="flex items-center justify-end gap-3"> <div class="flex items-center justify-end gap-3">
<button type="button" <button type="button"
@@ -213,12 +287,14 @@
</form> </form>
</div> </div>
</div> </div>
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}
{% endif %}
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}
{{ block.super }} {{ block.super }}
{% if can_change_users %}
<script> <script>
(function () { (function () {
function lockScroll() { function lockScroll() {
@@ -286,4 +362,5 @@
}); });
})(); })();
</script> </script>
{% endif %}
{% endblock %} {% endblock %}

View File

@@ -239,3 +239,40 @@ class DashboardViewTests(TestCase):
claim.refresh_from_db() claim.refresh_from_db()
self.assertIsNone(claim.paid_at) self.assertIsNone(claim.paid_at)
self.assertFalse(claim.logs.filter(action=ClaimLog.Action.MARKED_PAID).exists()) self.assertFalse(claim.logs.filter(action=ClaimLog.Action.MARKED_PAID).exists())
class UserManagementViewTests(TestCase):
def setUp(self):
User = get_user_model()
self.admin = User.objects.create_user(username="manager", password="test123", email="manager@example.com")
perms = Permission.objects.filter(codename__in=["view_user", "change_user"])
self.admin.user_permissions.add(*perms)
self.client.force_login(self.admin)
self.target = User.objects.create_user(username="editor", password="oldpass123", email="old@example.com")
def test_admin_can_update_profile_and_password(self):
response = self.client.post(
reverse("claims:user-manage"),
{
"action": "update",
"user_id": self.target.id,
"is_staff": "on",
"grant_view": "on",
"grant_change": "",
"grant_edit": "on",
"grant_pay": "on",
"first_name": "New",
"last_name": "Name",
"email": "new@example.com",
"new_password1": "StrongPass123!",
"new_password2": "StrongPass123!",
},
follow=True,
)
self.assertEqual(response.status_code, 200)
target = get_user_model().objects.get(pk=self.target.pk)
self.assertEqual(target.first_name, "New")
self.assertEqual(target.last_name, "Name")
self.assertEqual(target.email, "new@example.com")
self.assertTrue(target.is_staff)
self.assertTrue(target.check_password("StrongPass123!"))

View File

@@ -3,7 +3,7 @@ from decimal import Decimal
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model, password_validation, update_session_auth_hash
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.db.models import Sum from django.db.models import Sum
@@ -14,6 +14,7 @@ from django.utils import timezone
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.views import View from django.views import View
from django.views.generic import ListView, TemplateView from django.views.generic import ListView, TemplateView
from django.core.exceptions import ValidationError
from .forms import ( from .forms import (
ClaimDecisionForm, ClaimDecisionForm,
@@ -377,19 +378,30 @@ class UserManagementView(LoginRequiredMixin, PermissionRequiredMixin, TemplateVi
users = User.objects.order_by("username") users = User.objects.order_by("username")
rows = [] rows = []
for user in users: for user in users:
perms = {
"is_staff": user.is_staff,
"view": user.has_perm("claims.view_claim"),
"change": user.has_perm("claims.change_claim"),
"edit": user.has_perm("claims.edit_claim_details"),
"pay": user.has_perm("claims.mark_claim_paid"),
}
rows.append( rows.append(
{ {
"user": user, "user": user,
"permission_form": UserPermissionForm( "permission_form": UserPermissionForm(
initial={ initial={
"user_id": user.id, "user_id": user.id,
"is_staff": user.is_staff, "is_staff": perms["is_staff"],
"grant_view": user.has_perm("claims.view_claim"), "grant_view": perms["view"],
"grant_change": user.has_perm("claims.change_claim"), "grant_change": perms["change"],
"grant_edit": user.has_perm("claims.edit_claim_details"), "grant_edit": perms["edit"],
"grant_pay": user.has_perm("claims.mark_claim_paid"), "grant_pay": perms["pay"],
"first_name": user.first_name,
"last_name": user.last_name,
"email": user.email,
} }
), ),
"permission_flags": perms,
"delete_form": None "delete_form": None
if user == self.request.user or user.is_superuser if user == self.request.user or user.is_superuser
else DeleteUserForm(initial={"user_id": user.id}), else DeleteUserForm(initial={"user_id": user.id}),
@@ -397,6 +409,7 @@ class UserManagementView(LoginRequiredMixin, PermissionRequiredMixin, TemplateVi
) )
context["user_rows"] = rows context["user_rows"] = rows
context["create_form"] = kwargs.get("create_form") or UserManagementForm() context["create_form"] = kwargs.get("create_form") or UserManagementForm()
context["can_change_users"] = self.request.user.has_perm("auth.change_user")
return context return context
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@@ -429,11 +442,35 @@ class UserManagementView(LoginRequiredMixin, PermissionRequiredMixin, TemplateVi
form = UserPermissionForm(request.POST) form = UserPermissionForm(request.POST)
if form.is_valid(): if form.is_valid():
user = get_object_or_404(User, pk=form.cleaned_data["user_id"]) user = get_object_or_404(User, pk=form.cleaned_data["user_id"])
if user == request.user and not form.cleaned_data["is_staff"]: new_is_staff = form.cleaned_data["is_staff"]
if user == request.user and not new_is_staff:
messages.error(request, _("Du kan inte ta bort din egen staff-status.")) messages.error(request, _("Du kan inte ta bort din egen staff-status."))
return redirect(request.path) return redirect(request.path)
user.is_staff = form.cleaned_data["is_staff"] update_fields = set()
user.save(update_fields=["is_staff"]) if user.is_staff != new_is_staff:
user.is_staff = new_is_staff
update_fields.add("is_staff")
for attr in ("first_name", "last_name", "email"):
new_value = form.cleaned_data.get(attr)
if new_value is None:
continue
if getattr(user, attr) != new_value:
setattr(user, attr, new_value)
update_fields.add(attr)
new_password = form.cleaned_data.get("new_password1")
if new_password:
try:
password_validation.validate_password(new_password, user)
except ValidationError as exc:
for error in exc:
messages.error(request, error)
return redirect(request.path)
user.set_password(new_password)
update_fields.add("password")
if update_fields:
user.save(update_fields=list(update_fields))
if new_password and user == request.user:
update_session_auth_hash(request, user)
self._set_perm(user, "claims.view_claim", form.cleaned_data["grant_view"]) self._set_perm(user, "claims.view_claim", form.cleaned_data["grant_view"])
self._set_perm(user, "claims.change_claim", form.cleaned_data["grant_change"]) self._set_perm(user, "claims.change_claim", form.cleaned_data["grant_change"])
self._set_perm(user, "claims.edit_claim_details", form.cleaned_data["grant_edit"]) self._set_perm(user, "claims.edit_claim_details", form.cleaned_data["grant_edit"])

Binary file not shown.

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: claims-system 0.1\n" "Project-Id-Version: claims-system 0.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-11 19:43+0000\n" "POT-Creation-Date: 2025-11-11 20:06+0000\n"
"PO-Revision-Date: 2025-11-08 23:40+0100\n" "PO-Revision-Date: 2025-11-08 23:40+0100\n"
"Last-Translator: ChatGPT <noreply@example.com>\n" "Last-Translator: ChatGPT <noreply@example.com>\n"
"Language-Team: English\n" "Language-Team: English\n"
@@ -18,7 +18,7 @@ msgid "Namn"
msgstr "Name" msgstr "Name"
#: claims/forms.py:23 claims/forms.py:101 claims/forms.py:112 #: claims/forms.py:23 claims/forms.py:101 claims/forms.py:112
#: claims/templates/claims/dashboard.html:176 #: claims/forms.py:177 claims/templates/claims/dashboard.html:176
#: claims/templates/claims/dashboard.html:526 #: claims/templates/claims/dashboard.html:526
msgid "E-post" msgid "E-post"
msgstr "Email" msgstr "Email"
@@ -82,15 +82,15 @@ msgstr "A comment is required when you reject an expense."
msgid "Användarnamn" msgid "Användarnamn"
msgstr "Username" msgstr "Username"
#: claims/forms.py:113 #: claims/forms.py:113 claims/forms.py:166
msgid "Förnamn" msgid "Förnamn"
msgstr "First name" msgstr "First name"
#: claims/forms.py:114 #: claims/forms.py:114 claims/forms.py:172
msgid "Efternamn" msgid "Efternamn"
msgstr "Last name" msgstr "Last name"
#: claims/forms.py:115 #: claims/forms.py:115 claims/templates/claims/user_management.html:234
msgid "Lösenord" msgid "Lösenord"
msgstr "Password" msgstr "Password"
@@ -122,35 +122,47 @@ msgstr "Allow marking payments"
msgid "Användarnamnet är upptaget." msgid "Användarnamnet är upptaget."
msgstr "That username is already taken." msgstr "That username is already taken."
#: claims/forms.py:140 #: claims/forms.py:140 claims/forms.py:197
msgid "Lösenorden matchar inte." msgid "Lösenorden matchar inte."
msgstr "Passwords do not match." msgstr "Passwords do not match."
#: claims/forms.py:158 claims/templates/claims/user_management.html:114 #: claims/forms.py:158 claims/templates/claims/user_management.html:124
#: claims/templates/claims/user_management.html:184 #: claims/templates/claims/user_management.html:257
msgid "Admin/staff" msgid "Admin/staff"
msgstr "Admin/staff" msgstr "Admin/staff"
#: claims/forms.py:159 claims/templates/claims/user_management.html:115 #: claims/forms.py:159 claims/templates/claims/user_management.html:127
#: claims/templates/claims/user_management.html:188 #: claims/templates/claims/user_management.html:261
msgid "Får se utlägg" msgid "Får se utlägg"
msgstr "May view claims" msgstr "May view claims"
#: claims/forms.py:160 claims/templates/claims/user_management.html:116 #: claims/forms.py:160 claims/templates/claims/user_management.html:130
#: claims/templates/claims/user_management.html:192 #: claims/templates/claims/user_management.html:265
msgid "Får besluta utlägg" msgid "Får besluta utlägg"
msgstr "May decide claims" msgstr "May decide claims"
#: claims/forms.py:161 claims/templates/claims/user_management.html:117 #: claims/forms.py:161 claims/templates/claims/user_management.html:133
#: claims/templates/claims/user_management.html:196 #: claims/templates/claims/user_management.html:269
msgid "Får redigera utlägg" msgid "Får redigera utlägg"
msgstr "May edit claims" msgstr "May edit claims"
#: claims/forms.py:162 claims/templates/claims/user_management.html:118 #: claims/forms.py:162 claims/templates/claims/user_management.html:136
#: claims/templates/claims/user_management.html:200 #: claims/templates/claims/user_management.html:273
msgid "Får markera betalningar" msgid "Får markera betalningar"
msgstr "May mark payments" msgstr "May mark payments"
#: claims/forms.py:182
#, fuzzy
#| msgid "Lösenord"
msgid "Nytt lösenord"
msgstr "Password"
#: claims/forms.py:187
#, fuzzy
#| msgid "Bekräfta lösenord"
msgid "Bekräfta nytt lösenord"
msgstr "Confirm password"
#: claims/models.py:30 claims/templates/claims/dashboard.html:342 #: claims/models.py:30 claims/templates/claims/dashboard.html:342
msgid "Approved" msgid "Approved"
msgstr "Approved" msgstr "Approved"
@@ -538,7 +550,7 @@ msgid "Redigera utlägg"
msgstr "Edit claim" msgstr "Edit claim"
#: claims/templates/claims/dashboard.html:513 #: claims/templates/claims/dashboard.html:513
#: claims/templates/claims/user_management.html:174 #: claims/templates/claims/user_management.html:199
msgid "Stäng" msgid "Stäng"
msgstr "Close" msgstr "Close"
@@ -547,7 +559,7 @@ msgid "Ingen"
msgstr "None" msgstr "None"
#: claims/templates/claims/dashboard.html:563 #: claims/templates/claims/dashboard.html:563
#: claims/templates/claims/user_management.html:207 #: claims/templates/claims/user_management.html:281
msgid "Avbryt" msgid "Avbryt"
msgstr "Cancel" msgstr "Cancel"
@@ -851,45 +863,62 @@ msgstr "No name"
msgid "Ingen e-post" msgid "Ingen e-post"
msgstr "No email" msgstr "No email"
#: claims/templates/claims/user_management.html:112 #: claims/templates/claims/user_management.html:114
msgid "Redigera användare"
msgstr "Edit user"
#: claims/templates/claims/user_management.html:121
#: claims/templates/claims/user_management.html:254
msgid "Behörigheter" msgid "Behörigheter"
msgstr "Permissions" msgstr "Permissions"
#: claims/templates/claims/user_management.html:123 #: claims/templates/claims/user_management.html:139
#: claims/templates/claims/user_management.html:168 msgid "Inga behörigheter tilldelade"
msgstr "No permissions assigned"
#: claims/templates/claims/user_management.html:146
#: claims/templates/claims/user_management.html:193
msgid "Redigera behörigheter" msgid "Redigera behörigheter"
msgstr "Edit permissions" msgstr "Edit permissions"
#: claims/templates/claims/user_management.html:127 #: claims/templates/claims/user_management.html:151
msgid "Ta bort konto" msgid "Ta bort konto"
msgstr "Remove account" msgstr "Remove account"
#: claims/templates/claims/user_management.html:129 #: claims/templates/claims/user_management.html:153
msgid "Åtgärden går inte att ångra. Användaren förlorar omedelbart åtkomst." msgid "Åtgärden går inte att ångra. Användaren förlorar omedelbart åtkomst."
msgstr "This action cannot be undone. The user loses access immediately." msgstr "This action cannot be undone. The user loses access immediately."
#: claims/templates/claims/user_management.html:130 #: claims/templates/claims/user_management.html:154
#, python-format #, python-format
msgid "Ta bort %(user.username)s?" msgid "Ta bort %(user.username)s?"
msgstr "Delete %(user.username)s?" msgstr "Delete %(user.username)s?"
#: claims/templates/claims/user_management.html:135 #: claims/templates/claims/user_management.html:159
msgid "Ta bort användare" msgid "Ta bort användare"
msgstr "Delete user" msgstr "Delete user"
#: claims/templates/claims/user_management.html:139 #: claims/templates/claims/user_management.html:163
msgid "Kan inte tas bort (antingen du själv eller superuser)." msgid "Kan inte tas bort (antingen du själv eller superuser)."
msgstr "Cannot be removed (either yourself or a superuser)." msgstr "Cannot be removed (either yourself or a superuser)."
#: claims/templates/claims/user_management.html:147 #: claims/templates/claims/user_management.html:171
msgid "Inga användare upplagda." msgid "Inga användare upplagda."
msgstr "No users yet." msgstr "No users yet."
#: claims/templates/claims/user_management.html:148 #: claims/templates/claims/user_management.html:172
msgid "Skapa det första kontot via formuläret ovan." msgid "Skapa det första kontot via formuläret ovan."
msgstr "Create the first account using the form above." msgstr "Create the first account using the form above."
#: claims/templates/claims/user_management.html:210 #: claims/templates/claims/user_management.html:208
msgid "Kontaktuppgifter"
msgstr "Contact details"
#: claims/templates/claims/user_management.html:251
msgid "Lämna fälten tomma för att behålla nuvarande lösenord."
msgstr "Leave the fields blank to keep the current password."
#: claims/templates/claims/user_management.html:284
msgid "Spara behörigheter" msgid "Spara behörigheter"
msgstr "Save permissions" msgstr "Save permissions"
@@ -912,125 +941,123 @@ msgstr ""
msgid "Filens innehåll matchar inte förväntat format." msgid "Filens innehåll matchar inte förväntat format."
msgstr "" msgstr ""
#: claims/views.py:127 #: claims/views.py:128
#, python-brace-format #, python-brace-format
msgid "{} utlägg skickade in." msgid "{} utlägg skickade in."
msgstr "" msgstr ""
#: claims/views.py:130 #: claims/views.py:131
msgid "Inga utlägg kunde sparas. Fyll i minst en rad." msgid "Inga utlägg kunde sparas. Fyll i minst en rad."
msgstr "" msgstr ""
#: claims/views.py:132 #: claims/views.py:133
msgid "Kunde inte spara utläggen. Kontrollera formuläret." msgid "Kunde inte spara utläggen. Kontrollera formuläret."
msgstr "" msgstr ""
#: claims/views.py:188 #: claims/views.py:189
#, fuzzy
#| msgid "Ge behörighet att besluta utlägg"
msgid "Du har inte behörighet att uppdatera utlägg." msgid "Du har inte behörighet att uppdatera utlägg."
msgstr "Allow deciding claims" msgstr "You do not have permission to update claims."
#: claims/views.py:202 #: claims/views.py:203
msgid "Utlägget är redan markerat som betalt och kan inte ändras." msgid "Utlägget är redan markerat som betalt och kan inte ändras."
msgstr "This claim is already marked as paid and cannot be changed." msgstr "This claim is already marked as paid and cannot be changed."
#: claims/views.py:209 #: claims/views.py:210
#, python-format #, python-format
msgid "%(claim)s markerades som godkänd." msgid "%(claim)s markerades som godkänd."
msgstr "%(claim)s was marked as approved." msgstr "%(claim)s was marked as approved."
#: claims/views.py:213 #: claims/views.py:214
#, python-format #, python-format
msgid "%(claim)s markerades som nekad." msgid "%(claim)s markerades som nekad."
msgstr "%(claim)s was marked as rejected." msgstr "%(claim)s was marked as rejected."
#: claims/views.py:217 #: claims/views.py:218
#, python-format #, python-format
msgid "%(claim)s återställdes till väntande status." msgid "%(claim)s återställdes till väntande status."
msgstr "%(claim)s was reset to pending status." msgstr "%(claim)s was reset to pending status."
#: claims/views.py:237 #: claims/views.py:238
msgid "Betalningshantering är inte aktiverad." msgid "Betalningshantering är inte aktiverad."
msgstr "Payment handling is not enabled." msgstr "Payment handling is not enabled."
#: claims/views.py:240 #: claims/views.py:241
msgid "Du har inte behörighet att markera betalningar i systemet." msgid "Du har inte behörighet att markera betalningar i systemet."
msgstr "You do not have permission to mark payments in the system." msgstr "You do not have permission to mark payments in the system."
#: claims/views.py:245 #: claims/views.py:246
msgid "Endast godkända utlägg kan markeras som betalda." msgid "Endast godkända utlägg kan markeras som betalda."
msgstr "Only approved claims can be marked as paid." msgstr "Only approved claims can be marked as paid."
#: claims/views.py:248 #: claims/views.py:249
msgid "Detta utlägg är redan markerat som betalt." msgid "Detta utlägg är redan markerat som betalt."
msgstr "This claim is already marked as paid." msgstr "This claim is already marked as paid."
#: claims/views.py:259 #: claims/views.py:260
#, python-format #, python-format
msgid "%(claim)s markerades som betald." msgid "%(claim)s markerades som betald."
msgstr "%(claim)s was marked as paid." msgstr "%(claim)s was marked as paid."
#: claims/views.py:264 #: claims/views.py:265
msgid "Du har inte behörighet att redigera utlägg." msgid "Du har inte behörighet att redigera utlägg."
msgstr "You do not have permission to edit claims." msgstr "You do not have permission to edit claims."
#: claims/views.py:268 #: claims/views.py:269
msgid "Endast väntande utlägg kan redigeras via panelen." msgid "Endast väntande utlägg kan redigeras via panelen."
msgstr "Only pending claims can be edited via the panel." msgstr "Only pending claims can be edited via the panel."
#: claims/views.py:297 #: claims/views.py:298
#, python-format #, python-format
msgid "Följande fält uppdaterades: %(fields)s" msgid "Följande fält uppdaterades: %(fields)s"
msgstr "The following fields were updated: %(fields)s" msgstr "The following fields were updated: %(fields)s"
#: claims/views.py:303 #: claims/views.py:304
msgid "Informationen uppdaterades." msgid "Informationen uppdaterades."
msgstr "Information updated." msgstr "Information updated."
#: claims/views.py:305 #: claims/views.py:306
msgid "Inga förändringar att spara." msgid "Inga förändringar att spara."
msgstr "No changes to save." msgstr "No changes to save."
#: claims/views.py:371 #: claims/views.py:372
msgid "Du saknar behörighet för åtgärden." msgid "Du saknar behörighet för åtgärden."
msgstr "You do not have permission to perform this action." msgstr "You do not have permission to perform this action."
#: claims/views.py:422 #: claims/views.py:435
#, python-format #, python-format
msgid "Användaren %(user)s skapades." msgid "Användaren %(user)s skapades."
msgstr "" msgstr ""
#: claims/views.py:433 #: claims/views.py:447
msgid "Du kan inte ta bort din egen staff-status." msgid "Du kan inte ta bort din egen staff-status."
msgstr "" msgstr ""
#: claims/views.py:441 #: claims/views.py:478
#, python-format #, python-format
msgid "Behörigheter uppdaterades för %(user)s." msgid "Behörigheter uppdaterades för %(user)s."
msgstr "" msgstr ""
#: claims/views.py:443 #: claims/views.py:480
#, fuzzy #, fuzzy
#| msgid "Justera behörigheter" #| msgid "Justera behörigheter"
msgid "Kunde inte uppdatera behörigheter." msgid "Kunde inte uppdatera behörigheter."
msgstr "Adjust permissions" msgstr "Adjust permissions"
#: claims/views.py:453 #: claims/views.py:490
msgid "Du kan inte ta bort ditt eget konto." msgid "Du kan inte ta bort ditt eget konto."
msgstr "" msgstr ""
#: claims/views.py:455 #: claims/views.py:492
msgid "Du kan inte ta bort en superuser via detta gränssnitt." msgid "Du kan inte ta bort en superuser via detta gränssnitt."
msgstr "" msgstr ""
#: claims/views.py:458 #: claims/views.py:495
#, fuzzy #, fuzzy
#| msgid "Användare" #| msgid "Användare"
msgid "Användaren togs bort." msgid "Användaren togs bort."
msgstr "Users" msgstr "Users"
#: claims/views.py:461 #: claims/views.py:498
msgid "Okänd åtgärd." msgid "Okänd åtgärd."
msgstr "" msgstr ""

Binary file not shown.

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-11 19:43+0000\n" "POT-Creation-Date: 2025-11-11 20:06+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -24,7 +24,7 @@ msgid "Namn"
msgstr "" msgstr ""
#: claims/forms.py:23 claims/forms.py:101 claims/forms.py:112 #: claims/forms.py:23 claims/forms.py:101 claims/forms.py:112
#: claims/templates/claims/dashboard.html:176 #: claims/forms.py:177 claims/templates/claims/dashboard.html:176
#: claims/templates/claims/dashboard.html:526 #: claims/templates/claims/dashboard.html:526
msgid "E-post" msgid "E-post"
msgstr "" msgstr ""
@@ -88,15 +88,15 @@ msgstr ""
msgid "Användarnamn" msgid "Användarnamn"
msgstr "" msgstr ""
#: claims/forms.py:113 #: claims/forms.py:113 claims/forms.py:166
msgid "Förnamn" msgid "Förnamn"
msgstr "" msgstr ""
#: claims/forms.py:114 #: claims/forms.py:114 claims/forms.py:172
msgid "Efternamn" msgid "Efternamn"
msgstr "" msgstr ""
#: claims/forms.py:115 #: claims/forms.py:115 claims/templates/claims/user_management.html:234
msgid "Lösenord" msgid "Lösenord"
msgstr "" msgstr ""
@@ -128,35 +128,43 @@ msgstr ""
msgid "Användarnamnet är upptaget." msgid "Användarnamnet är upptaget."
msgstr "" msgstr ""
#: claims/forms.py:140 #: claims/forms.py:140 claims/forms.py:197
msgid "Lösenorden matchar inte." msgid "Lösenorden matchar inte."
msgstr "" msgstr ""
#: claims/forms.py:158 claims/templates/claims/user_management.html:114 #: claims/forms.py:158 claims/templates/claims/user_management.html:124
#: claims/templates/claims/user_management.html:184 #: claims/templates/claims/user_management.html:257
msgid "Admin/staff" msgid "Admin/staff"
msgstr "" msgstr ""
#: claims/forms.py:159 claims/templates/claims/user_management.html:115 #: claims/forms.py:159 claims/templates/claims/user_management.html:127
#: claims/templates/claims/user_management.html:188 #: claims/templates/claims/user_management.html:261
msgid "Får se utlägg" msgid "Får se utlägg"
msgstr "" msgstr ""
#: claims/forms.py:160 claims/templates/claims/user_management.html:116 #: claims/forms.py:160 claims/templates/claims/user_management.html:130
#: claims/templates/claims/user_management.html:192 #: claims/templates/claims/user_management.html:265
msgid "Får besluta utlägg" msgid "Får besluta utlägg"
msgstr "" msgstr ""
#: claims/forms.py:161 claims/templates/claims/user_management.html:117 #: claims/forms.py:161 claims/templates/claims/user_management.html:133
#: claims/templates/claims/user_management.html:196 #: claims/templates/claims/user_management.html:269
msgid "Får redigera utlägg" msgid "Får redigera utlägg"
msgstr "" msgstr ""
#: claims/forms.py:162 claims/templates/claims/user_management.html:118 #: claims/forms.py:162 claims/templates/claims/user_management.html:136
#: claims/templates/claims/user_management.html:200 #: claims/templates/claims/user_management.html:273
msgid "Får markera betalningar" msgid "Får markera betalningar"
msgstr "" msgstr ""
#: claims/forms.py:182
msgid "Nytt lösenord"
msgstr ""
#: claims/forms.py:187
msgid "Bekräfta nytt lösenord"
msgstr ""
#: claims/models.py:30 claims/templates/claims/dashboard.html:342 #: claims/models.py:30 claims/templates/claims/dashboard.html:342
msgid "Approved" msgid "Approved"
msgstr "Godkänd" msgstr "Godkänd"
@@ -536,7 +544,7 @@ msgid "Redigera utlägg"
msgstr "" msgstr ""
#: claims/templates/claims/dashboard.html:513 #: claims/templates/claims/dashboard.html:513
#: claims/templates/claims/user_management.html:174 #: claims/templates/claims/user_management.html:199
msgid "Stäng" msgid "Stäng"
msgstr "" msgstr ""
@@ -545,7 +553,7 @@ msgid "Ingen"
msgstr "" msgstr ""
#: claims/templates/claims/dashboard.html:563 #: claims/templates/claims/dashboard.html:563
#: claims/templates/claims/user_management.html:207 #: claims/templates/claims/user_management.html:281
msgid "Avbryt" msgid "Avbryt"
msgstr "" msgstr ""
@@ -823,45 +831,62 @@ msgstr ""
msgid "Ingen e-post" msgid "Ingen e-post"
msgstr "Ingen e-post" msgstr "Ingen e-post"
#: claims/templates/claims/user_management.html:112 #: claims/templates/claims/user_management.html:114
msgid "Redigera användare"
msgstr "Redigera användare"
#: claims/templates/claims/user_management.html:121
#: claims/templates/claims/user_management.html:254
msgid "Behörigheter" msgid "Behörigheter"
msgstr "Behörigheter" msgstr "Behörigheter"
#: claims/templates/claims/user_management.html:123 #: claims/templates/claims/user_management.html:139
#: claims/templates/claims/user_management.html:168 msgid "Inga behörigheter tilldelade"
msgstr "Inga behörigheter tilldelade"
#: claims/templates/claims/user_management.html:146
#: claims/templates/claims/user_management.html:193
msgid "Redigera behörigheter" msgid "Redigera behörigheter"
msgstr "Redigera behörigheter" msgstr "Redigera behörigheter"
#: claims/templates/claims/user_management.html:127 #: claims/templates/claims/user_management.html:151
msgid "Ta bort konto" msgid "Ta bort konto"
msgstr "Ta bort konto" msgstr "Ta bort konto"
#: claims/templates/claims/user_management.html:129 #: claims/templates/claims/user_management.html:153
msgid "Åtgärden går inte att ångra. Användaren förlorar omedelbart åtkomst." msgid "Åtgärden går inte att ångra. Användaren förlorar omedelbart åtkomst."
msgstr "Åtgärden går inte att ångra. Användaren förlorar omedelbart åtkomst." msgstr "Åtgärden går inte att ångra. Användaren förlorar omedelbart åtkomst."
#: claims/templates/claims/user_management.html:130 #: claims/templates/claims/user_management.html:154
#, python-format #, python-format
msgid "Ta bort %(user.username)s?" msgid "Ta bort %(user.username)s?"
msgstr "Ta bort %(user.username)s?" msgstr "Ta bort %(user.username)s?"
#: claims/templates/claims/user_management.html:135 #: claims/templates/claims/user_management.html:159
msgid "Ta bort användare" msgid "Ta bort användare"
msgstr "Ta bort användare" msgstr "Ta bort användare"
#: claims/templates/claims/user_management.html:139 #: claims/templates/claims/user_management.html:163
msgid "Kan inte tas bort (antingen du själv eller superuser)." msgid "Kan inte tas bort (antingen du själv eller superuser)."
msgstr "Kan inte tas bort (antingen du själv eller superuser)." msgstr "Kan inte tas bort (antingen du själv eller superuser)."
#: claims/templates/claims/user_management.html:147 #: claims/templates/claims/user_management.html:171
msgid "Inga användare upplagda." msgid "Inga användare upplagda."
msgstr "Inga användare upplagda." msgstr "Inga användare upplagda."
#: claims/templates/claims/user_management.html:148 #: claims/templates/claims/user_management.html:172
msgid "Skapa det första kontot via formuläret ovan." msgid "Skapa det första kontot via formuläret ovan."
msgstr "Skapa det första kontot via formuläret ovan." msgstr "Skapa det första kontot via formuläret ovan."
#: claims/templates/claims/user_management.html:210 #: claims/templates/claims/user_management.html:208
msgid "Kontaktuppgifter"
msgstr "Kontaktuppgifter"
#: claims/templates/claims/user_management.html:251
msgid "Lämna fälten tomma för att behålla nuvarande lösenord."
msgstr "Lämna fälten tomma för att behålla nuvarande lösenord."
#: claims/templates/claims/user_management.html:284
msgid "Spara behörigheter" msgid "Spara behörigheter"
msgstr "Spara behörigheter" msgstr "Spara behörigheter"
@@ -884,119 +909,119 @@ msgstr ""
msgid "Filens innehåll matchar inte förväntat format." msgid "Filens innehåll matchar inte förväntat format."
msgstr "" msgstr ""
#: claims/views.py:127 #: claims/views.py:128
#, python-brace-format #, python-brace-format
msgid "{} utlägg skickade in." msgid "{} utlägg skickade in."
msgstr "" msgstr ""
#: claims/views.py:130 #: claims/views.py:131
msgid "Inga utlägg kunde sparas. Fyll i minst en rad." msgid "Inga utlägg kunde sparas. Fyll i minst en rad."
msgstr "" msgstr ""
#: claims/views.py:132 #: claims/views.py:133
msgid "Kunde inte spara utläggen. Kontrollera formuläret." msgid "Kunde inte spara utläggen. Kontrollera formuläret."
msgstr "" msgstr ""
#: claims/views.py:188 #: claims/views.py:189
msgid "Du har inte behörighet att uppdatera utlägg." msgid "Du har inte behörighet att uppdatera utlägg."
msgstr "" msgstr "Du har inte behörighet att uppdatera utlägg."
#: claims/views.py:202 #: claims/views.py:203
msgid "Utlägget är redan markerat som betalt och kan inte ändras." msgid "Utlägget är redan markerat som betalt och kan inte ändras."
msgstr "" msgstr ""
#: claims/views.py:209 #: claims/views.py:210
#, python-format #, python-format
msgid "%(claim)s markerades som godkänd." msgid "%(claim)s markerades som godkänd."
msgstr "" msgstr ""
#: claims/views.py:213 #: claims/views.py:214
#, python-format #, python-format
msgid "%(claim)s markerades som nekad." msgid "%(claim)s markerades som nekad."
msgstr "" msgstr ""
#: claims/views.py:217 #: claims/views.py:218
#, python-format #, python-format
msgid "%(claim)s återställdes till väntande status." msgid "%(claim)s återställdes till väntande status."
msgstr "" msgstr ""
#: claims/views.py:237 #: claims/views.py:238
msgid "Betalningshantering är inte aktiverad." msgid "Betalningshantering är inte aktiverad."
msgstr "" msgstr ""
#: claims/views.py:240 #: claims/views.py:241
msgid "Du har inte behörighet att markera betalningar i systemet." msgid "Du har inte behörighet att markera betalningar i systemet."
msgstr "" msgstr ""
#: claims/views.py:245 #: claims/views.py:246
msgid "Endast godkända utlägg kan markeras som betalda." msgid "Endast godkända utlägg kan markeras som betalda."
msgstr "" msgstr ""
#: claims/views.py:248 #: claims/views.py:249
msgid "Detta utlägg är redan markerat som betalt." msgid "Detta utlägg är redan markerat som betalt."
msgstr "Detta utlägg är redan markerat som betalt." msgstr "Detta utlägg är redan markerat som betalt."
#: claims/views.py:259 #: claims/views.py:260
#, python-format #, python-format
msgid "%(claim)s markerades som betald." msgid "%(claim)s markerades som betald."
msgstr "%(claim)s markerades som betald." msgstr "%(claim)s markerades som betald."
#: claims/views.py:264 #: claims/views.py:265
msgid "Du har inte behörighet att redigera utlägg." msgid "Du har inte behörighet att redigera utlägg."
msgstr "" msgstr ""
#: claims/views.py:268 #: claims/views.py:269
msgid "Endast väntande utlägg kan redigeras via panelen." msgid "Endast väntande utlägg kan redigeras via panelen."
msgstr "Endast väntande utlägg kan redigeras via panelen." msgstr "Endast väntande utlägg kan redigeras via panelen."
#: claims/views.py:297 #: claims/views.py:298
#, python-format #, python-format
msgid "Följande fält uppdaterades: %(fields)s" msgid "Följande fält uppdaterades: %(fields)s"
msgstr "Följande fält uppdaterades: %(fields)s" msgstr "Följande fält uppdaterades: %(fields)s"
#: claims/views.py:303 #: claims/views.py:304
msgid "Informationen uppdaterades." msgid "Informationen uppdaterades."
msgstr "Informationen uppdaterades." msgstr "Informationen uppdaterades."
#: claims/views.py:305 #: claims/views.py:306
msgid "Inga förändringar att spara." msgid "Inga förändringar att spara."
msgstr "Inga förändringar att spara." msgstr "Inga förändringar att spara."
#: claims/views.py:371 #: claims/views.py:372
msgid "Du saknar behörighet för åtgärden." msgid "Du saknar behörighet för åtgärden."
msgstr "Du saknar behörighet för åtgärden." msgstr "Du saknar behörighet för åtgärden."
#: claims/views.py:422 #: claims/views.py:435
#, python-format #, python-format
msgid "Användaren %(user)s skapades." msgid "Användaren %(user)s skapades."
msgstr "" msgstr ""
#: claims/views.py:433 #: claims/views.py:447
msgid "Du kan inte ta bort din egen staff-status." msgid "Du kan inte ta bort din egen staff-status."
msgstr "" msgstr ""
#: claims/views.py:441 #: claims/views.py:478
#, python-format #, python-format
msgid "Behörigheter uppdaterades för %(user)s." msgid "Behörigheter uppdaterades för %(user)s."
msgstr "" msgstr ""
#: claims/views.py:443 #: claims/views.py:480
msgid "Kunde inte uppdatera behörigheter." msgid "Kunde inte uppdatera behörigheter."
msgstr "" msgstr ""
#: claims/views.py:453 #: claims/views.py:490
msgid "Du kan inte ta bort ditt eget konto." msgid "Du kan inte ta bort ditt eget konto."
msgstr "" msgstr ""
#: claims/views.py:455 #: claims/views.py:492
msgid "Du kan inte ta bort en superuser via detta gränssnitt." msgid "Du kan inte ta bort en superuser via detta gränssnitt."
msgstr "" msgstr ""
#: claims/views.py:458 #: claims/views.py:495
msgid "Användaren togs bort." msgid "Användaren togs bort."
msgstr "" msgstr ""
#: claims/views.py:461 #: claims/views.py:498
msgid "Okänd åtgärd." msgid "Okänd åtgärd."
msgstr "" msgstr ""