diff --git a/closedverse_main/admin.py b/closedverse_main/admin.py
index ab8b38a..1b91aaf 100644
--- a/closedverse_main/admin.py
+++ b/closedverse_main/admin.py
@@ -1,71 +1,110 @@
+from django.apps import apps
from django.contrib import admin
-#from django.contrib.auth.admin import UserAdmin
-from django.contrib.auth.models import Group
-#from django.forms import ModelForm, PasswordInput
+from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
+from django.contrib.auth.forms import AdminPasswordChangeForm
+from django.contrib.auth.models import Group, Permission
+from django.contrib import messages
+from django.http import HttpResponseRedirect
from django.conf import settings
from . import models
-# Override admin login page
-from closedverse_main.views import login_page
-admin.autodiscover()
-admin.site.login = login_page
-
-"""
-class UserForm(ModelForm):
- class Meta:
- model = models.User
- fields = '__all__'
- widgets = {
- 'password': PasswordInput(),
- }
-"""
-@admin.action(description='Void selected Invites')
+@admin.action(description='Void selected Invites', permissions=["change"])
def Void_invite(modeladmin, request, queryset):
queryset.update(void = True)
-@admin.action(description='Restore selected Invites')
+@admin.action(description='Restore selected Invites', permissions=["change"])
def Restore_invite(modeladmin, request, queryset):
queryset.update(void = False, used = False)
-@admin.action(description='Hide selected items')
+@admin.action(description='Hide selected items', permissions=["change"])
def Hide_content(modeladmin, request, queryset):
queryset.update(is_rm = True)
-@admin.action(description='Show selected items')
+@admin.action(description='Show selected items', permissions=["change"])
def Show_content(modeladmin, request, queryset):
queryset.update(is_rm = False)
-@admin.action(description='Disable comments')
+@admin.action(description='Disable comments', permissions=["change"])
def Disable_comments(modeladmin, request, queryset):
queryset.update(lock_comments = 2)
-@admin.action(description='Enable comments')
+@admin.action(description='Enable comments', permissions=["change"])
def Enable_comments(modeladmin, request, queryset):
queryset.update(lock_comments = 0)
-@admin.action(description='Feature selected communities')
+@admin.action(description='Feature selected communities', permissions=["change"])
def Feature_community(modeladmin, request, queryset):
queryset.update(is_feature = True)
-@admin.action(description='Unfeature selected communities')
+@admin.action(description='Unfeature selected communities', permissions=["change"])
def Unfeature_community(modeladmin, request, queryset):
queryset.update(is_feature = False)
-@admin.action(description='Force login')
+@admin.action(description='Force login', permissions=["change"])
def force_login(modeladmin, request, queryset):
queryset.update(require_auth = True)
-@admin.action(description='Unforce login')
+@admin.action(description='Unforce login', permissions=["change"])
def unforce_login(modeladmin, request, queryset):
queryset.update(require_auth = False)
-@admin.action(description='Disable user')
+@admin.action(description='Disable user', permissions=["change"])
def Disable_user(modeladmin, request, queryset):
- queryset.update(active = False)
-@admin.action(description='Enable user')
+ queryset.update(is_active = False)
+@admin.action(description='Enable user', permissions=["change"])
def Enable_user(modeladmin, request, queryset):
- queryset.update(active = True)
+ queryset.update(is_active = True)
+@admin.action(description='Demote user', permissions=["change"])
+def Demote_user(modeladmin, request, queryset):
+ queryset.update(is_superuser = False)
+ queryset.update(is_staff = False)
+ queryset.update(level = 0)
-class UserAdmin(admin.ModelAdmin):
- search_fields = ('id', 'username', 'nickname', 'email', )
- list_display = ('id', 'username', 'nickname', 'warned', 'level', 'staff', 'active', )
- exclude = ('addr', 'signup_addr', 'password', )
- actions = [Disable_user, Enable_user]
- #exclude = ('staff', )
- # Not yet
- #form = UserForm
+class UserAdmin(BaseUserAdmin):
+ search_fields = ('id', 'username', 'nickname', 'email', 'addr', 'signup_addr')
+ list_display = ('id', 'username', 'nickname', 'level', 'is_active', 'is_staff', 'is_superuser')
+ actions = [Disable_user, Enable_user, Demote_user]
+ raw_id_fields = ('role', )
+ readonly_fields = ('last_login', 'created', )
+ fieldsets = (
+ (None, {'fields': ('nickname', 'username', 'password')}),
+ ('Personal info', {'fields': ('email', ('addr', 'signup_addr'))}),
+ ('Cosmetic', {'fields': (('role', 'avatar', 'has_mh'), 'color', 'theme', 'bg_url',)}),
+ ('Data', {'fields': ('last_login', 'created', 'hide_online')}),
+ ('Permissions', {'fields': (('is_active', 'is_staff', 'is_superuser', 'can_invite'), 'level', 'c_tokens', 'groups', 'user_permissions')}),
+ )
+
+ # yes this is stupid...
+ def get_queryset(self, request):
+ # Filter the list of users displayed based on the current user's level and superuser status.
+ qs = super().get_queryset(request)
+ if request.user.is_superuser:
+ return qs
+ return qs.filter(level__lt=request.user.level)
+
+ def has_change_permission(self, request, obj=None):
+ if not obj:
+ return super().has_change_permission(request, obj)
+ # Superusers can edit anyone
+ if request.user.is_superuser:
+ return True
+ # Users cannot edit superusers or users with a higher level than themselves
+ if obj.is_superuser or obj.level >= request.user.level:
+ return False
+ return super().has_change_permission(request, obj)
+
+ def has_delete_permission(self, request, obj=None):
+ if not obj:
+ return super().has_delete_permission(request, obj)
+ # Superusers can delete anyone
+ if request.user.is_superuser:
+ return True
+ # Users cannot delete superusers or users with a higher level than themselves
+ if obj.is_superuser or obj.level >= request.user.level:
+ return False
+ return super().has_delete_permission(request, obj)
+
+ def get_readonly_fields(self, request, obj=None):
+ # Get the default readonly fields
+ readonly_fields = super().get_readonly_fields(request, obj)
+
+ # If the user is not a superuser, add the fields to the readonly list
+ if not request.user.is_superuser:
+ readonly_fields += ('level', 'is_staff', 'is_superuser', 'groups', 'user_permissions', 'password')
+ return readonly_fields
+
class ProfileAdmin(admin.ModelAdmin):
search_fields = ('id', 'user__username__icontains', 'comment', 'origin_id',)
raw_id_fields = ('user', 'favorite',)
@@ -142,12 +181,30 @@ class RoleAdmin(admin.ModelAdmin):
exclude = ('is_static', )
class BanAdmin(admin.ModelAdmin):
- # Hide that shit for now, Eventually I plan to get rid of the user_tools_meta thing completely and just show IP addresses for staff like any normal site.
- exclude = ('ip_address', )
+ raw_id_fields = ('to', 'by')
+ list_display = ('by', 'to', 'reason', 'expiry_date', 'active')
-#class BlockAdmin(admin.ModelAdmin)
+ def save_model(self, request, obj, form, change):
+ # Set the 'by' field to the currently logged-in user
+ obj.by = request.user
-admin.site.unregister(Group)
+ # Check if the user being banned is a superuser or has a higher level than the user issuing the ban
+ if obj.to.is_superuser or obj.to.level > request.user.level:
+ messages.error(request, "You cannot ban a superuser or a user with a higher level.")
+ return
+
+ super().save_model(request, obj, form, change)
+
+ def response_add(self, request, obj, post_url_continue=None):
+ # If there was an error, redirect back to the 'add' page
+ if messages.get_messages(request):
+ return HttpResponseRedirect(request.path)
+ return super().response_add(request, obj, post_url_continue)
+
+class LoginAdmin(admin.ModelAdmin):
+ raw_id_fields = ('user',)
+ list_display = ('user', 'addr', 'user_agent', )
+ search_fields = ('user__username', 'addr', 'user_agent', )
admin.site.register(models.Role, RoleAdmin)
admin.site.register(models.User, UserAdmin)
@@ -158,24 +215,25 @@ admin.site.register(models.Complaint, ComplaintAdmin)
admin.site.register(models.Message, MessageAdmin)
admin.site.register(models.Conversation, ConversationAdmin)
admin.site.register(models.Notification, NotificationAdmin)
-#admin.site.register(models.LoginAttempt, LoginAdmin)
+admin.site.register(models.LoginAttempt, LoginAdmin)
admin.site.register(models.UserBlock)
admin.site.register(models.AuditLog, AuditAdmin)
admin.site.register(models.ProfileHistory, HistoryAdmin)
-
+admin.site.register(models.Yeah)
+admin.site.register(models.Follow)
+admin.site.register(models.FriendRequest)
admin.site.register(models.Post, PostAdmin)
admin.site.register(models.Comment, CommentAdmin)
-
+admin.site.register(models.Ads, AdsAdmin)
admin.site.register(models.Ban, BanAdmin)
admin.site.register(models.Warning)
-if settings.DEBUG:
- admin.site.register(models.Yeah)
- admin.site.register(models.Follow)
- admin.site.register(models.FriendRequest)
- admin.site.register(models.Friendship, ConversationAdmin)
- #admin.site.register(models.Notification)
- admin.site.register(models.Poll)
- admin.site.register(models.PollVote)
-admin.site.register(models.Ads, AdsAdmin)
+# This will show fucking everything, just don't give other people perms to see content types, sessions, and all that shit.
+# This is so the superuser, owner of the site can see everything.
+app_models = apps.get_models()
+for model in app_models:
+ try:
+ admin.site.register(model)
+ except admin.sites.AlreadyRegistered:
+ pass
\ No newline at end of file
diff --git a/closedverse_main/forms.py b/closedverse_main/forms.py
index 872a591..f1f271f 100644
--- a/closedverse_main/forms.py
+++ b/closedverse_main/forms.py
@@ -125,7 +125,7 @@ class LoginForm(forms.Form):
raise forms.ValidationError("Invalid password.", code='invalid')
elif user[1] == 2:
raise forms.ValidationError("This account's password needs to be reset. Contact an admin or reset by email.", code='required_reset')
- elif not user[0].is_active():
+ elif not user[0].is_active:
raise forms.ValidationError("This account was disabled.", code='disabled')
return cleaned_data
@@ -136,7 +136,7 @@ class User_tools_Form(forms.ModelForm):
class Meta:
model = User
- fields = ['username', 'nickname', 'role', 'c_tokens', 'hide_online', 'active', 'can_invite', 'has_mh', 'avatar']
+ fields = ['username', 'nickname', 'role', 'c_tokens', 'hide_online', 'can_invite', 'has_mh', 'avatar']
def clean_username(self):
username = self.cleaned_data.get('username')
diff --git a/closedverse_main/middleware.py b/closedverse_main/middleware.py
index 05ec211..d3cc4e1 100644
--- a/closedverse_main/middleware.py
+++ b/closedverse_main/middleware.py
@@ -89,7 +89,7 @@ class ClosedMiddleware(object):
"""
if request.user.is_authenticated:
"""
- if not request.user.is_active():
+ if not request.user.is_active:
if request.user.warned_reason:
ban_msg = request.user.warned_reason
else:
@@ -97,7 +97,7 @@ class ClosedMiddleware(object):
return HttpResponseForbidden(ban_msg)
"""
# can just forbid post requests for the time being (but leav our funny logout message :3)
- if not request.user.is_active() and request.method != 'GET' and request.get_full_path() != '/logout/':
+ if not request.user.is_active and request.method != 'GET' and request.get_full_path() != '/logout/':
return HttpResponseForbidden()
response = self.get_response(request)
if request.user.is_authenticated:
diff --git a/closedverse_main/models.py b/closedverse_main/models.py
index 14ca7ff..a2344f2 100644
--- a/closedverse_main/models.py
+++ b/closedverse_main/models.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
from django.db import models
-from django.contrib.auth.base_user import AbstractBaseUser
-from django.contrib.auth.models import BaseUserManager
+from django.contrib.auth.base_user import BaseUserManager
+from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.db.models import Q, Max, F, Count, Exists, OuterRef, Subquery #, QuerySet, Case, When,
from django.utils import timezone
from django.http import Http404
@@ -68,10 +68,12 @@ class UserManager(BaseUserManager):
def create_superuser(self, username, password):
user = self.model(
username=username,
+ nickname=username,
)
user.set_password(password)
- user.staff = True
- user.level = 99 # added because some admin funcs are missing otherwise
+ user.is_staff = True
+ user.is_superuser = True
+ user.level = 999 # added because some admin funcs are missing otherwise
user.save()
profile = Profile.objects.model()
profile.user = user
@@ -134,11 +136,9 @@ class Role(models.Model):
# as of writing, mii-secure is unstable, nintendo please do not f*ck me for this
mii_domain = 'https://s3.us-east-1.amazonaws.com/mii-images.account.nintendo.net/'
-class User(AbstractBaseUser):
+class User(AbstractBaseUser, PermissionsMixin):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=32, unique=True)
- # Todo: Don't allow nickname to be null (once this is fixed, un-str-ify line 357 of views; the one with ogdata description)
- # Also don't let lots of other strings to be null
nickname = models.CharField(max_length=64, null=True)
password = models.CharField(max_length=128)
email = models.EmailField(null=True, blank=True, default='')
@@ -146,7 +146,7 @@ class User(AbstractBaseUser):
avatar = models.CharField(max_length=1200, blank=True, default='')
theme = ColorField(blank=True, null=True)
# LEVEL: 0-1 is default, everything else is just levels
- level = models.SmallIntegerField(default=0, help_text='The rank of the user, \"0\" is by default. Users with a high enough rank will be able to manage users.')
+ level = models.SmallIntegerField(default=0, help_text='This is the level of authority. People with a lower level cannot edit those with a higher level. This also grants additional permissions outside of the Django Admin Panel.')
role = models.ForeignKey(Role, blank=True, null=True, on_delete=models.SET_NULL, help_text='This will show a funny badge and text on this user\'s profile. This does not grant the user any additional power and is only visual.')
addr = models.CharField(max_length=64, null=True, blank=True)
signup_addr = models.CharField(max_length=64, null=True, blank=True)
@@ -157,11 +157,10 @@ class User(AbstractBaseUser):
hide_online = models.BooleanField(default=False, help_text='If this is ticked, the user has opted to hide their online status.')
color = ColorField(default='', null=True, blank=True)
- staff = models.BooleanField(default=False, help_text='Allow this user to access the admin panel you\'re using right now?')
- active = models.BooleanField(default=True, help_text='If this is off, the user is basically banned and can\'t do shit here')
+ is_staff = models.BooleanField(default=False, help_text='Allow this user to access the admin panel you\'re using right now?')
+ is_active = models.BooleanField(default=True, help_text='If this is off, the user is basically banned and can\'t do shit here')
+ is_superuser = models.BooleanField(default=False, help_text='Overrides django groups. This also allows you to change people\'s perms.')
can_invite = models.BooleanField(default=True, help_text='Can this user invite new users? This does not matter unless the invite system is turned on.')
- warned = models.BooleanField(default=False, help_text='Shows an annoying fucking warning box on the front page.')
- warned_reason = models.CharField(blank=True, null=True, max_length=600, help_text='This string will show if the user is banned, or warned.')
bg_url = models.CharField(max_length=300, null=True, blank=True)
is_anonymous = False
@@ -175,6 +174,11 @@ class User(AbstractBaseUser):
objects = UserManager()
+ class Meta:
+ permissions = [
+ ("Can_alter_level_and_Perms", "Allow this user to change Level, Groups and Permissions?"),
+ ]
+
def __str__(self):
return self.username
def get_full_name(self):
@@ -185,16 +189,6 @@ class User(AbstractBaseUser):
return self.username
def has_module_perms(self, a):
return True
- def has_perm(self, a):
- return self.staff
- def is_staff(self):
- return self.staff
- def is_active(self):
- return self.active
- def is_warned(self):
- return self.warned
- def get_warned_reason(self):
- return self.warned_reason
def profile(self, attr=None):
# If attr is specified, that field is retrieved
if attr:
@@ -425,7 +419,7 @@ class User(AbstractBaseUser):
# Admin can-manage
def can_manage(self):
- if self.level >= settings.level_needed_to_man_users or self.staff:
+ if self.level >= settings.level_needed_to_man_users or self.is_staff:
can_manage = True
else:
can_manage = False
@@ -433,7 +427,7 @@ class User(AbstractBaseUser):
# Does self have authority over user?
def has_authority(self, user):
if user.is_authenticated:
- if self.staff and not user.staff:
+ if self.is_staff and not user.is_staff:
return True
if self.level >= user.level:
return True
@@ -761,13 +755,13 @@ class Community(models.Model):
return False
def post_perm(self, request):
- if not request.user.active:
+ if not request.user.is_active:
return False
if self.Community_block(request):
return False
if request.user.level >= self.rank_needed_to_post:
return True
- elif request.user.staff == True:
+ elif request.user.is_staff == True:
return True
# If the community is made by you, you should be able to post in there regardless.
elif request.user == self.creator:
@@ -779,12 +773,12 @@ class Community(models.Model):
if not request.user.is_authenticated:
return False
# If the user is a mod but can't post in one community, the user should not edit it either.
- if not request.user.level >= self.rank_needed_to_post and not request.user.staff == True:
+ if not request.user.level >= self.rank_needed_to_post and not request.user.is_staff == True:
return False
if request.user == self.creator:
return True
- elif request.user.level >= settings.level_needed_to_man_communities or request.user.staff == True:
+ elif request.user.level >= settings.level_needed_to_man_communities or request.user.is_staff == True:
return True
else:
return False
@@ -821,7 +815,7 @@ class Community(models.Model):
return 5
if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen') or request.FILES.get('video')):
return 6
- if not request.user.is_active():
+ if not request.user.is_active:
return 6
if request.user.unread_warning():
return 13
@@ -955,7 +949,7 @@ class Post(models.Model):
def can_yeah(self, request):
if not request.user.is_authenticated:
return False
- if not request.user.is_active():
+ if not request.user.is_active:
return False
if self.community.Community_block(request):
return False
@@ -988,7 +982,7 @@ class Post(models.Model):
def can_comment(self, request):
if self.number_comments() > 500:
return False
- if not request.user.active:
+ if not request.user.is_active:
return False
# yeah this is fucking nuts. It's basically a ban from an entire community.
if self.community.Community_block(request):
@@ -1063,7 +1057,7 @@ class Post(models.Model):
for c in request.POST['body']:
if unicodedata.combining(c):
return 12
- if not request.user.is_active():
+ if not request.user.is_active:
return 6
if len(request.POST['body']) > 2200 or (len(request.POST['body']) < 1 and not request.POST.get('_post_type') == 'painting'):
return 1
@@ -1206,7 +1200,7 @@ class Comment(models.Model):
else:
return False
def can_yeah(self, request):
- if not request.user.is_authenticated or not request.user.is_active():
+ if not request.user.is_authenticated or not request.user.is_active:
return False
if self.is_mine(request.user) or UserBlock.find_block(self.creator, request.user):
return False
diff --git a/closedverse_main/templates/closedverse_main/elements/user-sidebar.html b/closedverse_main/templates/closedverse_main/elements/user-sidebar.html
index c484c0e..13ff610 100644
--- a/closedverse_main/templates/closedverse_main/elements/user-sidebar.html
+++ b/closedverse_main/templates/closedverse_main/elements/user-sidebar.html
@@ -121,6 +121,9 @@
+
diff --git a/closedverse_main/templates/closedverse_main/help/my-data.html b/closedverse_main/templates/closedverse_main/help/my-data.html
index 7ec1943..f9ecbb6 100644
--- a/closedverse_main/templates/closedverse_main/help/my-data.html
+++ b/closedverse_main/templates/closedverse_main/help/my-data.html
@@ -9,7 +9,7 @@
General account information:
IP address: {% if user.addr %}{{ user.addr }}{% else %}Data missing{% endif %}
Signup IP address: {% if user.signup_addr %}{{ user.signup_addr }}{% else %}Data missing{% endif %}
- Rank: {% if user.staff %}You are a staff member.{% elif not user.level <= 0 %}You are a moderator. (Level {{ user.level }}){% else %}You are a regular user.{% endif %}
+ Rank: {% if user.is_staff %}You are a staff member.{% elif not user.level <= 0 %}You are a moderator. (Level {{ user.level }}){% else %}You are a regular user.{% endif %}
My content:
Your account has existed for {{ user.created|timesince }}! During that time, we've collected:
@@ -20,16 +20,12 @@
- My notifications: {{ notifications }}
Restrictions:
- {% if request.user.active %}
- Sending images and creating new accounts: {% if user.has_freedom %}Good standing{% else %}Restricted{% endif %}
- Post limit: {% if request.user.profile.limit_post == 0 %}Good standing{% else %}{{ user.profile.limit_post }}{% endif %}
- Editing your profile: {% if not user.profile.cannot_edit %}Good standing{% else %}Restricted{% endif %}
- Creating invites: {% if user.can_invite %}Good standing{% else %}Restricted{% endif %}
- {% else %}
- You've been fucking banned lmao
- {% endif %}
Collected data:
Account login history:
diff --git a/closedverse_main/templates/closedverse_main/man/usertools.html b/closedverse_main/templates/closedverse_main/man/usertools.html
index 680ef87..21ae084 100644
--- a/closedverse_main/templates/closedverse_main/man/usertools.html
+++ b/closedverse_main/templates/closedverse_main/man/usertools.html
@@ -56,68 +56,23 @@
{{ field.help_text }}
{% endfor %}
-
-
-
{% if accountmatch %}
Account(s) found with the same IP address.
{% endif %}
-
- {% if seen_by %}
-
Account viewed by:
-
-
-
- | Time |
- Seen by |
-
- {% for seen_by in seen_by %}
-
- | {{ seen_by.created }} |
- {{ seen_by.from_user }} |
-
- {% endfor %}
-
-
- {% endif %}
-
- {% if has_seen %}
-
This user has viewed:
-
-
-
- | Time |
- Seen |
-
- {% for has_seen in has_seen %}
-
- | {{ has_seen.created }} |
- {{ has_seen.target_user }} |
-
- {% endfor %}
-
-
- {% endif %}
-
-
{% csrf_token %}