Add more Ruff rules (#891)

* ruff: apply rule F

* ruff: apply rule E

* ruff: apply rule SIM

* ruff: apply rule TCH

* ruff: apply rule ERA

* ruff: apply rule PLW

* ruff: apply rule FLY

* ruff: apply rule PERF

* ruff: apply rules FURB & RUF
This commit is contained in:
thomas girod
2024-10-15 11:36:26 +02:00
committed by GitHub
parent d114b01bcc
commit d16a207a83
82 changed files with 836 additions and 748 deletions

View File

@ -67,5 +67,6 @@ class Command(BaseCommand):
subprocess.run(
[str(Path(__file__).parent / "install_xapian.sh"), desired],
env=dict(os.environ),
).check_returncode()
check=True,
)
self.stdout.write("Installation success")

View File

@ -934,7 +934,7 @@ Welcome to the wiki page!
# Adding subscription for sli
s = Subscription(
member=User.objects.filter(pk=sli.pk).first(),
subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
subscription_type=next(iter(settings.SITH_SUBSCRIPTIONS.keys())),
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0],
)
s.subscription_start = s.compute_start()
@ -947,7 +947,7 @@ Welcome to the wiki page!
# Adding subscription for Krophil
s = Subscription(
member=User.objects.filter(pk=krophil.pk).first(),
subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
subscription_type=next(iter(settings.SITH_SUBSCRIPTIONS.keys())),
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0],
)
s.subscription_start = s.compute_start()

View File

@ -217,9 +217,9 @@ class Command(BaseCommand):
UV.objects.bulk_create(uvs, ignore_conflicts=True)
def create_products(self):
categories = []
for _ in range(10):
categories.append(ProductType(name=self.faker.text(max_nb_chars=30)))
categories = [
ProductType(name=self.faker.text(max_nb_chars=30)) for _ in range(10)
]
ProductType.objects.bulk_create(categories)
categories = list(
ProductType.objects.filter(name__in=[c.name for c in categories])
@ -254,16 +254,16 @@ class Command(BaseCommand):
archived=bool(random.random() > 0.7),
)
products.append(product)
for group in random.sample(groups, k=random.randint(0, 3)):
# there will be products without buying groups
# but there are also such products in the real database
buying_groups.append(
Product.buying_groups.through(product=product, group=group)
)
for counter in random.sample(counters, random.randint(0, 4)):
selling_places.append(
Counter.products.through(counter=counter, product=product)
)
# there will be products without buying groups
# but there are also such products in the real database
buying_groups.extend(
Product.buying_groups.through(product=product, group=group)
for group in random.sample(groups, k=random.randint(0, 3))
)
selling_places.extend(
Counter.products.through(counter=counter, product=product)
for counter in random.sample(counters, random.randint(0, 4))
)
Product.objects.bulk_create(products)
Product.buying_groups.through.objects.bulk_create(buying_groups)
Counter.products.through.objects.bulk_create(selling_places)

View File

@ -174,7 +174,7 @@ def validate_promo(value: int) -> None:
)
def get_group(*, pk: int = None, name: str = None) -> Group | None:
def get_group(*, pk: int | None = None, name: str | None = None) -> Group | None:
"""Search for a group by its primary key or its name.
Either one of the two must be set.
@ -445,7 +445,7 @@ class User(AbstractBaseUser):
else:
return 0
def is_in_group(self, *, pk: int = None, name: str = None) -> bool:
def is_in_group(self, *, pk: int | None = None, name: str | None = None) -> bool:
"""Check if this user is in the given group.
Either a group id or a group name must be provided.
If both are passed, only the id will be considered.
@ -649,7 +649,7 @@ class User(AbstractBaseUser):
continue
links = list(User.godfathers.through.objects.filter(**{key: self.id}))
res.extend(links)
for _ in range(1, depth):
for _ in range(1, depth): # noqa: F402 we don't care about gettext here
ids = [getattr(c, reverse_key) for c in links]
links = list(
User.godfathers.through.objects.filter(
@ -703,9 +703,7 @@ class User(AbstractBaseUser):
return True
if hasattr(obj, "owner_group") and self.is_in_group(pk=obj.owner_group.id):
return True
if self.is_root:
return True
return False
return self.is_root
def can_edit(self, obj):
"""Determine if the object can be edited by the user."""
@ -717,9 +715,7 @@ class User(AbstractBaseUser):
return True
if isinstance(obj, User) and obj == self:
return True
if self.is_owner(obj):
return True
return False
return self.is_owner(obj)
def can_view(self, obj):
"""Determine if the object can be viewed by the user."""
@ -729,9 +725,7 @@ class User(AbstractBaseUser):
for pk in obj.view_groups.values_list("pk", flat=True):
if self.is_in_group(pk=pk):
return True
if self.can_edit(obj):
return True
return False
return self.can_edit(obj)
def can_be_edited_by(self, user):
return user.is_root or user.is_board_member
@ -759,23 +753,17 @@ class User(AbstractBaseUser):
@cached_property
def preferences(self):
try:
if hasattr(self, "_preferences"):
return self._preferences
except:
prefs = Preferences(user=self)
prefs.save()
return prefs
return Preferences.objects.create(user=self)
@cached_property
def forum_infos(self):
try:
if hasattr(self, "_forum_infos"):
return self._forum_infos
except:
from forum.models import ForumUserInfo
from forum.models import ForumUserInfo
infos = ForumUserInfo(user=self)
infos.save()
return infos
return ForumUserInfo.objects.create(user=self)
@cached_property
def clubs_with_rights(self) -> list[Club]:
@ -840,7 +828,7 @@ class AnonymousUser(AuthAnonymousUser):
def favorite_topics(self):
raise PermissionDenied
def is_in_group(self, *, pk: int = None, name: str = None) -> bool:
def is_in_group(self, *, pk: int | None = None, name: str | None = None) -> bool:
"""The anonymous user is only in the public group."""
allowed_id = settings.SITH_GROUP_PUBLIC_ID
if pk is not None:
@ -867,9 +855,7 @@ class AnonymousUser(AuthAnonymousUser):
and obj.view_groups.filter(id=settings.SITH_GROUP_PUBLIC_ID).exists()
):
return True
if hasattr(obj, "can_be_viewed_by") and obj.can_be_viewed_by(self):
return True
return False
return hasattr(obj, "can_be_viewed_by") and obj.can_be_viewed_by(self)
def get_display_name(self):
return _("Visitor")
@ -1070,7 +1056,7 @@ class SithFile(models.Model):
]:
self.file.delete()
self.file = None
except:
except: # noqa E722 I don't know the exception that can be raised
self.file = None
self.mime_type = "inode/directory"
if self.is_file and (self.file is None or self.file == ""):
@ -1196,12 +1182,12 @@ class SithFile(models.Model):
return Album.objects.filter(id=self.id).first()
def get_parent_list(self):
l = []
p = self.parent
while p is not None:
l.append(p)
p = p.parent
return l
parents = []
current = self.parent
while current is not None:
parents.append(current)
current = current.parent
return parents
def get_parent_path(self):
return "/" + "/".join([p.name for p in self.get_parent_list()[::-1]])
@ -1359,22 +1345,18 @@ class Page(models.Model):
if hasattr(self, "club") and self.club.can_be_edited_by(user):
# Override normal behavior for clubs
return True
if self.name == settings.SITH_CLUB_ROOT_PAGE and user.is_board_member:
return True
return False
return self.name == settings.SITH_CLUB_ROOT_PAGE and user.is_board_member
def can_be_viewed_by(self, user):
if self.is_club_page:
return True
return False
return self.is_club_page
def get_parent_list(self):
l = []
p = self.parent
while p is not None:
l.append(p)
p = p.parent
return l
parents = []
current = self.parent
while current is not None:
parents.append(current)
current = current.parent
return parents
def is_locked(self):
"""Is True if the page is locked, False otherwise.
@ -1386,7 +1368,6 @@ class Page(models.Model):
if self.lock_timeout and (
timezone.now() - self.lock_timeout > timedelta(minutes=5)
):
# print("Lock timed out")
self.unset_lock()
return (
self.lock_user
@ -1401,7 +1382,6 @@ class Page(models.Model):
self.lock_user = user
self.lock_timeout = timezone.now()
super().save()
# print("Locking page")
def set_lock_recursive(self, user):
"""Locks recursively all the child pages for editing properties."""
@ -1420,7 +1400,6 @@ class Page(models.Model):
self.lock_user = None
self.lock_timeout = None
super().save()
# print("Unlocking page")
def get_lock(self):
"""Returns the page's mutex containing the time and the user in a dict."""
@ -1435,13 +1414,11 @@ class Page(models.Model):
"""
if self.parent is None:
return self.name
return "/".join([self.parent.get_full_name(), self.name])
return f"{self.parent.get_full_name()}/{self.name}"
def get_display_name(self):
try:
return self.revisions.last().title
except:
return self.name
rev = self.revisions.last()
return rev.title if rev is not None else self.name
@cached_property
def is_club_page(self):

View File

@ -50,7 +50,7 @@ def phonenumber(
try:
parsed = phonenumbers.parse(value, country)
return phonenumbers.format_number(parsed, number_format)
except phonenumbers.NumberParseException as e:
except phonenumbers.NumberParseException:
return value

View File

@ -343,7 +343,7 @@ class TestUserTools:
response = client.get(reverse("core:user_tools"))
assertRedirects(
response,
expected_url=f"/login?next=%2Fuser%2Ftools%2F",
expected_url="/login?next=%2Fuser%2Ftools%2F",
target_status_code=301,
)

View File

@ -73,7 +73,7 @@ class TestFetchFamilyApi(TestCase):
self.client.force_login(self.main_user)
response = self.client.get(
reverse("api:family_graph", args=[self.main_user.id])
+ f"?godfathers_depth=0&godchildren_depth=0"
+ "?godfathers_depth=0&godchildren_depth=0"
)
assert response.status_code == 200
assert [u["id"] for u in response.json()["users"]] == [self.main_user.id]
@ -91,7 +91,7 @@ class TestFetchFamilyApi(TestCase):
self.client.force_login(self.main_user)
response = self.client.get(
reverse("api:family_graph", args=[self.main_user.id])
+ f"?godfathers_depth=10&godchildren_depth=10"
+ "?godfathers_depth=10&godchildren_depth=10"
)
assert response.status_code == 200
assert [u["id"] for u in response.json()["users"]] == [
@ -126,7 +126,7 @@ class TestFetchFamilyApi(TestCase):
self.client.force_login(self.main_user)
response = self.client.get(
reverse("api:family_graph", args=[self.main_user.id])
+ f"?godfathers_depth=1&godchildren_depth=1"
+ "?godfathers_depth=1&godchildren_depth=1"
)
assert response.status_code == 200
assert [u["id"] for u in response.json()["users"]] == [
@ -150,7 +150,7 @@ class TestFetchFamilyApi(TestCase):
self.client.force_login(self.main_user)
response = self.client.get(
reverse("api:family_graph", args=[self.main_user.id])
+ f"?godfathers_depth=10&godchildren_depth=0"
+ "?godfathers_depth=10&godchildren_depth=0"
)
assert response.status_code == 200
assert [u["id"] for u in response.json()["users"]] == [

View File

@ -29,13 +29,67 @@ from core.converters import (
FourDigitYearConverter,
TwoDigitMonthConverter,
)
from core.views import *
from core.views import (
FileDeleteView,
FileEditPropView,
FileEditView,
FileListView,
FileModerateView,
FileModerationView,
FileView,
GiftCreateView,
GiftDeleteView,
GroupCreateView,
GroupDeleteView,
GroupEditView,
GroupListView,
GroupTemplateView,
NotificationList,
PageCreateView,
PageDeleteView,
PageEditView,
PageHistView,
PageListView,
PagePropView,
PageRevView,
PageView,
SithLoginView,
SithPasswordChangeDoneView,
SithPasswordChangeView,
SithPasswordResetCompleteView,
SithPasswordResetConfirmView,
SithPasswordResetDoneView,
SithPasswordResetView,
UserAccountDetailView,
UserAccountView,
UserClubView,
UserCreationView,
UserGodfathersTreeView,
UserGodfathersView,
UserListView,
UserMiniView,
UserPicturesView,
UserPreferencesView,
UserStatsView,
UserToolsView,
UserUpdateGroupView,
UserUpdateProfileView,
UserView,
delete_user_godfather,
index,
logout,
notification,
password_root_change,
search_json,
search_user_json,
search_view,
send_file,
)
register_converter(FourDigitYearConverter, "yyyy")
register_converter(TwoDigitMonthConverter, "mm")
register_converter(BooleanStringConverter, "bool")
urlpatterns = [
path("", index, name="index"),
path("notifications/", NotificationList.as_view(), name="notification_list"),
@ -80,27 +134,17 @@ urlpatterns = [
path("group/new/", GroupCreateView.as_view(), name="group_new"),
path("group/<int:group_id>/", GroupEditView.as_view(), name="group_edit"),
path(
"group/<int:group_id>/delete/",
GroupDeleteView.as_view(),
name="group_delete",
"group/<int:group_id>/delete/", GroupDeleteView.as_view(), name="group_delete"
),
path(
"group/<int:group_id>/detail/",
GroupTemplateView.as_view(),
name="group_detail",
"group/<int:group_id>/detail/", GroupTemplateView.as_view(), name="group_detail"
),
# User views
path("user/", UserListView.as_view(), name="user_list"),
path(
"user/<int:user_id>/mini/",
UserMiniView.as_view(),
name="user_profile_mini",
),
path("user/<int:user_id>/mini/", UserMiniView.as_view(), name="user_profile_mini"),
path("user/<int:user_id>/", UserView.as_view(), name="user_profile"),
path(
"user/<int:user_id>/pictures/",
UserPicturesView.as_view(),
name="user_pictures",
"user/<int:user_id>/pictures/", UserPicturesView.as_view(), name="user_pictures"
),
path(
"user/<int:user_id>/godfathers/",
@ -117,28 +161,14 @@ urlpatterns = [
delete_user_godfather,
name="user_godfathers_delete",
),
path(
"user/<int:user_id>/edit/",
UserUpdateProfileView.as_view(),
name="user_edit",
),
path("user/<int:user_id>/edit/", UserUpdateProfileView.as_view(), name="user_edit"),
path("user/<int:user_id>/clubs/", UserClubView.as_view(), name="user_clubs"),
path("user/<int:user_id>/prefs/", UserPreferencesView.as_view(), name="user_prefs"),
path(
"user/<int:user_id>/prefs/",
UserPreferencesView.as_view(),
name="user_prefs",
),
path(
"user/<int:user_id>/groups/",
UserUpdateGroupView.as_view(),
name="user_groups",
"user/<int:user_id>/groups/", UserUpdateGroupView.as_view(), name="user_groups"
),
path("user/tools/", UserToolsView.as_view(), name="user_tools"),
path(
"user/<int:user_id>/account/",
UserAccountView.as_view(),
name="user_account",
),
path("user/<int:user_id>/account/", UserAccountView.as_view(), name="user_account"),
path(
"user/<int:user_id>/account/<yyyy:year>/<mm:month>/",
UserAccountDetailView.as_view(),
@ -179,42 +209,18 @@ urlpatterns = [
),
path("file/moderation/", FileModerationView.as_view(), name="file_moderation"),
path(
"file/<int:file_id>/moderate/",
FileModerateView.as_view(),
name="file_moderate",
"file/<int:file_id>/moderate/", FileModerateView.as_view(), name="file_moderate"
),
path("file/<int:file_id>/download/", send_file, name="download"),
# Page views
path("page/", PageListView.as_view(), name="page_list"),
path("page/create/", PageCreateView.as_view(), name="page_new"),
path("page/<int:page_id>/delete/", PageDeleteView.as_view(), name="page_delete"),
path("page/<path:page_name>/edit/", PageEditView.as_view(), name="page_edit"),
path("page/<path:page_name>/prop/", PagePropView.as_view(), name="page_prop"),
path("page/<path:page_name>/hist/", PageHistView.as_view(), name="page_hist"),
path(
"page/<int:page_id>/delete/",
PageDeleteView.as_view(),
name="page_delete",
),
path(
"page/<path:page_name>/edit/",
PageEditView.as_view(),
name="page_edit",
),
path(
"page/<path:page_name>/prop/",
PagePropView.as_view(),
name="page_prop",
),
path(
"page/<path:page_name>/hist/",
PageHistView.as_view(),
name="page_hist",
),
path(
"page/<path:page_name>/rev/<int:rev>/",
PageRevView.as_view(),
name="page_rev",
),
path(
"page/<path:page_name>/",
PageView.as_view(),
name="page",
"page/<path:page_name>/rev/<int:rev>/", PageRevView.as_view(), name="page_rev"
),
path("page/<path:page_name>/", PageView.as_view(), name="page"),
]

View File

@ -127,7 +127,7 @@ def resize_image_explicit(
def exif_auto_rotate(image):
for orientation in ExifTags.TAGS.keys():
for orientation in ExifTags.TAGS:
if ExifTags.TAGS[orientation] == "Orientation":
break
exif = dict(image._getexif().items())

View File

@ -25,6 +25,7 @@
import types
from typing import Any
from django.conf import settings
from django.contrib.auth.mixins import AccessMixin
from django.core.exceptions import (
ImproperlyConfigured,
@ -35,6 +36,7 @@ from django.http import (
HttpResponseNotFound,
HttpResponseServerError,
)
from django.shortcuts import render
from django.utils.functional import cached_property
from django.views.generic.base import View
from django.views.generic.detail import SingleObjectMixin
@ -79,9 +81,7 @@ def can_edit_prop(obj: Any, user: User) -> bool:
raise PermissionDenied
```
"""
if obj is None or user.is_owner(obj):
return True
return False
return obj is None or user.is_owner(obj)
def can_edit(obj: Any, user: User) -> bool:
@ -232,7 +232,9 @@ class UserIsRootMixin(GenericContentPermissionMixinBuilder):
PermissionDenied: if the user isn't root
"""
permission_function = lambda obj, user: user.is_root
@staticmethod
def permission_function(obj: Any, user: User):
return user.is_root
class FormerSubscriberMixin(AccessMixin):
@ -304,10 +306,10 @@ class QuickNotifMixin:
kwargs["quick_notifs"] = []
for n in self.quick_notif_list:
kwargs["quick_notifs"].append(settings.SITH_QUICK_NOTIF[n])
for k, v in settings.SITH_QUICK_NOTIF.items():
for gk in self.request.GET.keys():
if k == gk:
kwargs["quick_notifs"].append(v)
for key, val in settings.SITH_QUICK_NOTIF.items():
for gk in self.request.GET:
if key == gk:
kwargs["quick_notifs"].append(val)
return kwargs
@ -324,8 +326,10 @@ class DetailFormView(SingleObjectMixin, FormView):
return super().get_object()
from .files import *
from .group import *
from .page import *
from .site import *
from .user import *
# F403: those star-imports would be hellish to refactor
# E402: putting those import at the top of the file would also be difficult
from .files import * # noqa: F403 E402
from .group import * # noqa: F403 E402
from .page import * # noqa: F403 E402
from .site import * # noqa: F403 E402
from .user import * # noqa: F403 E402

View File

@ -193,7 +193,7 @@ class FileEditView(CanEditMixin, UpdateView):
def get_form_class(self):
fields = ["name", "is_moderated"]
if self.object.is_file:
fields = ["file"] + fields
fields = ["file", *fields]
return modelform_factory(SithFile, fields=fields)
def get_success_url(self):
@ -283,38 +283,38 @@ class FileView(CanViewMixin, DetailView, FormMixin):
`obj` is the SithFile object you want to put in the clipboard, or
where you want to paste the clipboard
"""
if "delete" in request.POST.keys():
if "delete" in request.POST:
for f_id in request.POST.getlist("file_list"):
sf = SithFile.objects.filter(id=f_id).first()
if sf:
sf.delete()
if "clear" in request.POST.keys():
file = SithFile.objects.filter(id=f_id).first()
if file:
file.delete()
if "clear" in request.POST:
request.session["clipboard"] = []
if "cut" in request.POST.keys():
for f_id in request.POST.getlist("file_list"):
f_id = int(f_id)
if "cut" in request.POST:
for f_id_str in request.POST.getlist("file_list"):
f_id = int(f_id_str)
if (
f_id in [c.id for c in obj.children.all()]
and f_id not in request.session["clipboard"]
):
request.session["clipboard"].append(f_id)
if "paste" in request.POST.keys():
if "paste" in request.POST:
for f_id in request.session["clipboard"]:
sf = SithFile.objects.filter(id=f_id).first()
if sf:
sf.move_to(obj)
file = SithFile.objects.filter(id=f_id).first()
if file:
file.move_to(obj)
request.session["clipboard"] = []
request.session.modified = True
def get(self, request, *args, **kwargs):
self.form = self.get_form()
if "clipboard" not in request.session.keys():
if "clipboard" not in request.session:
request.session["clipboard"] = []
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
if "clipboard" not in request.session.keys():
if "clipboard" not in request.session:
request.session["clipboard"] = []
if request.user.can_edit(self.object):
# XXX this call can fail!
@ -398,6 +398,6 @@ class FileModerateView(CanEditPropMixin, SingleObjectMixin):
self.object.is_moderated = True
self.object.moderator = request.user
self.object.save()
if "next" in self.request.GET.keys():
if "next" in self.request.GET:
return redirect(self.request.GET["next"])
return redirect("core:file_moderation")

View File

@ -140,7 +140,7 @@ class SelectUser(TextInput):
class LoginForm(AuthenticationForm):
def __init__(self, *arg, **kwargs):
if "data" in kwargs.keys():
if "data" in kwargs:
from counter.models import Customer
data = kwargs["data"].copy()
@ -157,7 +157,7 @@ class LoginForm(AuthenticationForm):
else:
user = User.objects.filter(username=data["username"]).first()
data["username"] = user.username
except:
except: # noqa E722 I don't know what error is supposed to be raised here
pass
kwargs["data"] = data
super().__init__(*arg, **kwargs)

View File

@ -55,7 +55,7 @@ class PageView(CanViewMixin, DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if "page" not in context.keys():
if "page" not in context:
context["new_page"] = self.kwargs["page_name"]
return context
@ -92,22 +92,16 @@ class PageRevView(CanViewMixin, DetailView):
)
return res
def get_object(self):
def get_object(self, *args, **kwargs):
self.page = Page.get_page_by_full_name(self.kwargs["page_name"])
return self.page
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.page is not None:
context["page"] = self.page
try:
rev = self.page.revisions.get(id=self.kwargs["rev"])
context["rev"] = rev
except:
# By passing, the template will just display the normal page without taking revision into account
pass
else:
context["new_page"] = self.kwargs["page_name"]
if not self.page:
return context | {"new_page": self.kwargs["page_name"]}
context["page"] = self.page
context["rev"] = self.page.revisions.filter(id=self.kwargs["rev"]).first()
return context
@ -118,7 +112,7 @@ class PageCreateView(CanCreateMixin, CreateView):
def get_initial(self):
init = {}
if "page" in self.request.GET.keys():
if "page" in self.request.GET:
page_name = self.request.GET["page"]
parent_name = "/".join(page_name.split("/")[:-1])
parent = Page.get_page_by_full_name(parent_name)
@ -145,18 +139,8 @@ class PagePropView(CanEditPagePropMixin, UpdateView):
slug_field = "_full_name"
slug_url_kwarg = "page_name"
def get_object(self):
o = super().get_object()
# Create the page if it does not exists
# if p == None:
# parent_name = '/'.join(page_name.split('/')[:-1])
# name = page_name.split('/')[-1]
# if parent_name == "":
# p = Page(name=name)
# else:
# parent = Page.get_page_by_full_name(parent_name)
# p = Page(name=name, parent=parent)
self.page = o
def get_object(self, queryset=None):
self.page = super().get_object()
try:
self.page.set_lock_recursive(self.request.user)
except LockError as e:

View File

@ -53,11 +53,8 @@ class NotificationList(ListView):
if self.request.user.is_anonymous:
return Notification.objects.none()
# TODO: Bulk update in django 2.2
if "see_all" in self.request.GET.keys():
for n in self.request.user.notifications.filter(viewed=False):
n.viewed = True
n.save()
if "see_all" in self.request.GET:
self.request.user.notifications.filter(viewed=False).update(viewed=True)
return self.request.user.notifications.order_by("-date")[:20]

View File

@ -255,8 +255,10 @@ class UserTabsMixin(TabedViewMixin):
"name": _("Groups"),
}
)
try:
if user.customer and (
if (
hasattr(user, "customer")
and user.customer
and (
user == self.request.user
or self.request.user.is_in_group(
pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID
@ -266,25 +268,22 @@ class UserTabsMixin(TabedViewMixin):
+ settings.SITH_BOARD_SUFFIX
)
or self.request.user.is_root
):
tab_list.append(
{
"url": reverse("core:user_stats", kwargs={"user_id": user.id}),
"slug": "stats",
"name": _("Stats"),
}
)
tab_list.append(
{
"url": reverse(
"core:user_account", kwargs={"user_id": user.id}
),
"slug": "account",
"name": _("Account") + " (%s €)" % user.customer.amount,
}
)
except:
pass
)
):
tab_list.append(
{
"url": reverse("core:user_stats", kwargs={"user_id": user.id}),
"slug": "stats",
"name": _("Stats"),
}
)
tab_list.append(
{
"url": reverse("core:user_account", kwargs={"user_id": user.id}),
"slug": "account",
"name": _("Account") + " (%s €)" % user.customer.amount,
}
)
return tab_list