From e572f997d2a201f5fdc09fa81a0921f5c36cc224 Mon Sep 17 00:00:00 2001 From: some weird guy <120821766+Mistake35@users.noreply.github.com> Date: Fri, 29 Sep 2023 14:41:44 -0700 Subject: [PATCH] pain - Added list_filter in admin.py for more models. - IP bans now work when not signed in - Invites are void if you are banned or disabled. - Removed Discord video support (it was a pointless feature) - Various HTML changes - Made the theme much darker. - Changed the color of the logo and favicon. Too lazy to change the rest of the assets for now. --- README.foreskin | 41 ++- closedverse_main/admin.py | 46 +++- closedverse_main/forms.py | 6 +- closedverse_main/middleware.py | 18 +- closedverse_main/models.py | 33 +-- .../elements/file-button.html | 2 +- .../closedverse_main/elements/post-form.html | 2 +- .../elements/profile-post.html | 10 +- .../elements/user-sidebar.html | 22 +- .../closedverse_main/login_page.html | 2 +- .../templates/closedverse_main/post-view.html | 3 - .../closedverse_main/signup_page.html | 3 +- closedverse_main/views.py | 6 +- static/blueness.css | 122 ++++----- static/closedverse.css | 239 +++++++++--------- static/img/favicon.png | Bin 3466 -> 3212 bytes static/img/menu-logo.svg | 99 +++----- 17 files changed, 315 insertions(+), 339 deletions(-) diff --git a/README.foreskin b/README.foreskin index 97b18d8..8e3bd64 100644 --- a/README.foreskin +++ b/README.foreskin @@ -2,38 +2,33 @@ Stuff that is done: - Disable comments button - Prevent users from posting in communities created by blocked users. - Hide email password reset form if no SMTP server is set up. (done by Arian Kordi) +- We are now using django groups. +- Admins have a better interface. +- Post limit shows publicly, with indication on how many posts are left. Stuff that is in progress - New Warning system. - Warnings are here, And there's an interface for warning users. - When a warning is made, a notification is also made. - Replaced the 5th notification type with warnings instead of announcements. - A check is made to make sure request.user does not have unread warnings before they can post. - There's no javascript for the form page yet. Audit logs are not set up, but the Warning model shows who warned each user. -- User friendly interface for admins - Admins should be able to manage users quickly and effectively without having to worry about a clusterfuck interface. - Primary actions like warning users, banning users, and whatnot should be an easy few clicks away. - -- New Ban system. - Bans are here also with its own interface. - Admins can unban or edit existing bans from the same page. - Instead of entering a datetime field manually, Admins are provided with choises for different ban lengths when using the ban page unless the ban is being edited. - IP bans are here but range bans are not added yet. - IPs are banned automatically when using the ban page. - A proper ban page is not added yet and simply shows a 403 error. - There's no javascript for the form page yet. - -- Removing shitty code. -- moving to forms.py. - The login page, admin tools, and community tools are using forms.py. +Todo: +- Users should not be able to delete warning notifications. +- Refine the invite system. + Make the invite page look better. + When banning someone, add the option to ban or revoke invites for whoever invited that person. +- FIX THE FUCKING CONTACT PAGE (nah not doing that lmao) +- also, CONTINUE MOVING OVER TO FORMS.PY + Profile settings + Email reset form + Post forms + Signup page + A bunch of other forms I haven't thought about. Ideas: +- An account approval system, we really need one. "is_new" exists in the user model, we just have to put that to use. +- "Muting" feature to replace "active" - Image and video file boxes in one. -- A new user metadata page that does not suck. - Make it, so you need to enter your current password to change your email address. -- Ways for mods to view who invited who. +- Ways for mods to view who invited who easily. - Full ImageField integration. - Filefield may have to be used for both photos and videos. - remove the useless feedback thing. (You can just make a bug reporting community) diff --git a/closedverse_main/admin.py b/closedverse_main/admin.py index e2de457..1bd6f16 100644 --- a/closedverse_main/admin.py +++ b/closedverse_main/admin.py @@ -48,10 +48,11 @@ def Enable_user(modeladmin, request, queryset): class UserAdmin(BaseUserAdmin): search_fields = ('id', 'username', 'nickname', ) - list_display = ('id', 'username', 'nickname', 'level', 'is_active', 'is_staff', 'is_superuser') + list_display = ('id', 'created', 'username', 'nickname', 'level', 'is_active', 'is_staff', 'is_superuser') actions = [Disable_user, Enable_user] raw_id_fields = ('role', ) readonly_fields = ('last_login', 'created', ) + list_filter = ('is_active', 'is_staff', 'can_invite', 'role', 'created', ) fieldsets = ( (None, {'fields': ('nickname', 'username', 'password')}), ('Personal info', {'fields': ('email', ('addr', 'signup_addr'))}), @@ -103,27 +104,31 @@ class ProfileAdmin(admin.ModelAdmin): search_fields = ('id', 'user__username__icontains', 'comment', 'origin_id',) raw_id_fields = ('user', 'favorite',) list_display = ('id', 'user', 'comment', 'let_freedom',) + list_filter = ('let_freedom', 'is_new', ) class InvitesAdmin(admin.ModelAdmin): search_fields = ('creator__username', 'used_by__username', 'code', ) raw_id_fields = ('creator', 'used_by', ) - list_display = ('creator', 'used_by', 'code', 'used', 'void', ) + list_display = ('created', 'creator', 'used_by', 'code', 'used', 'void', ) + list_filter = ('used', 'void', 'created', ) actions = [Void_invite, Restore_invite] class ComplaintAdmin(admin.ModelAdmin): search_fields = ('body', 'creator__username', ) raw_id_fields = ('creator', ) - list_display = ('creator', 'type', 'body', ) + list_display = ('created', 'creator', 'type', 'body', ) + list_filter = ('type', 'created', ) class ConversationAdmin(admin.ModelAdmin): search_fields = ('id', 'source__username', 'target__username') raw_id_fields = ('source', 'target', ) - list_display = ('source', 'target', ) + list_display = ('created', 'source', 'target', ) class PostAdmin(admin.ModelAdmin): raw_id_fields = ('creator', 'poll', ) search_fields = ('id', 'body', 'creator__username', ) - list_display = ('id', 'creator', 'body', 'is_rm', ) + list_display = ('id', 'created', 'creator', 'body', 'is_rm', ) + list_filter = ('is_rm', 'created', ) actions = [Hide_content, Show_content, Disable_comments, Enable_comments] def get_queryset(self, request): return models.Post.real.get_queryset() @@ -131,24 +136,26 @@ class PostAdmin(admin.ModelAdmin): class CommentAdmin(admin.ModelAdmin): raw_id_fields = ('creator', 'original_post', ) search_fields = ('id', 'body', 'creator__username', ) - list_display = ('id', 'creator', 'body', 'original_post', 'is_rm', ) + list_display = ('id', 'created', 'creator', 'body', 'original_post', 'is_rm', ) + list_filter = ('is_rm', 'created', ) actions = [Hide_content, Show_content] def get_queryset(self, request): return models.Comment.real.get_queryset() class CommunityAdmin(admin.ModelAdmin): raw_id_fields = ('creator', ) - list_display = ('id', 'name', 'description', 'type', 'creator', 'popularity', 'is_rm', 'is_feature', 'require_auth') + list_display = ('id', 'created', 'name', 'description', 'type', 'creator', 'popularity', 'is_rm', 'is_feature', 'require_auth') search_fields = ('id', 'name', 'description', 'creator__username') actions = [Hide_content, Show_content, Feature_community, Unfeature_community, force_login, unforce_login] - list_filter = ('type', 'is_rm', 'is_feature', 'require_auth') + list_filter = ('type', 'is_rm', 'is_feature', 'require_auth', 'created', ) def get_queryset(self, request): return models.Community.real.get_queryset() class MessageAdmin(admin.ModelAdmin): raw_id_fields = ('creator', 'conversation', ) search_fields = ('id', 'body', 'creator__username', ) - list_display = ('created', 'creator', 'conversation', 'body', 'is_rm', ) + list_display = ('id', 'created', 'creator', 'conversation', 'body', 'read', 'is_rm', ) + list_filter = ('is_rm', 'read', 'created', ) actions = [Hide_content, Show_content] def get_queryset(self, request): return models.Message.real.get_queryset() @@ -167,7 +174,8 @@ class NotificationAdmin(admin.ModelAdmin): combined_display.short_description = 'Content' raw_id_fields = ('to', 'source', 'context_post', 'context_comment',) search_fields = ('to__username', 'source__username', 'context_post__body', 'context_comment__body',) - list_display = ('id', 'to', 'source', 'combined_display',) + list_display = ('id', 'created', 'to', 'source', 'combined_display',) + list_filter = ('read', 'created', ) class AuditAdmin(admin.ModelAdmin): def combined_display(self, obj): @@ -184,10 +192,12 @@ class AuditAdmin(admin.ModelAdmin): raw_id_fields = ('by', 'user', 'post', 'comment', 'community', 'reversed_by', ) list_display = ('by', 'user', 'type', 'combined_display', ) search_fields = ('by__username', 'user__username', 'post__body', 'comment__body', 'community__name', ) + list_filter = ('type', 'created', ) class AdsAdmin(admin.ModelAdmin): - list_display = ('url', 'imageurl', ) + list_display = ('id', 'created', 'url', 'imageurl', ) search_fields = ('url', 'imageurl', ) + list_filter = ('created', ) class YeahAdmin(admin.ModelAdmin): raw_id_fields = ('by', 'post', 'comment', ) @@ -204,6 +214,7 @@ class RoleAdmin(admin.ModelAdmin): class BanAdmin(admin.ModelAdmin): raw_id_fields = ('to', 'by') list_display = ('by', 'to', 'reason', 'expiry_date', 'active') + list_filter = ('expiry_date', 'active', 'created', ) def save_model(self, request, obj, form, change): # Set the 'by' field to the currently logged-in user @@ -224,13 +235,22 @@ class BanAdmin(admin.ModelAdmin): class LoginAdmin(admin.ModelAdmin): raw_id_fields = ('user',) - list_display = ('user', 'addr', 'user_agent', ) + list_display = ('id', 'created', 'user', 'addr', 'user_agent', ) search_fields = ('user__username', 'addr', 'user_agent', ) + list_filter = ('created', ) + class WarningAdmin(admin.ModelAdmin): raw_id_fields = ('by', 'to') list_display = ('by', 'to', 'reason', ) search_fields = ('by__username', 'to__username', 'reason', ) + list_filter = ('created', ) + +class BlockAdmin(admin.ModelAdmin): + raw_id_fields = ('source', 'target') + list_display = ('id', 'created', 'source', 'target', ) + search_fields = ('created__username', 'source__username', ) + list_filter = ('created', ) admin.site.register(models.Role, RoleAdmin) admin.site.register(models.User, UserAdmin) @@ -242,7 +262,7 @@ 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.UserBlock) +admin.site.register(models.UserBlock, BlockAdmin) admin.site.register(models.AuditLog, AuditAdmin) admin.site.register(models.ProfileHistory, HistoryAdmin) diff --git a/closedverse_main/forms.py b/closedverse_main/forms.py index f1f271f..bde2e5b 100644 --- a/closedverse_main/forms.py +++ b/closedverse_main/forms.py @@ -109,7 +109,7 @@ class PurgeForm(forms.Form): restore_all = forms.BooleanField(required=False, label='Restore purged content', help_text='Restore everything that was purged, this will not apply to posts deleted manually.') class LoginForm(forms.Form): - username = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class': 'auth-input', 'placeholder': 'Username'})) + username = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class': 'auth-input', 'placeholder': 'Username / Email'})) password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'auth-input', 'placeholder': 'Password'})) def clean(self): @@ -127,6 +127,10 @@ class LoginForm(forms.Form): 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: raise forms.ValidationError("This account was disabled.", code='disabled') + # Check for active user ban + active_user_ban = Ban.objects.filter(to=user[0], active=True, expiry_date__gte=timezone.now()).first() + if active_user_ban: + raise forms.ValidationError("This account has been banned until {}. Reason: {}".format(active_user_ban.expiry_date, active_user_ban.reason), code='banned') return cleaned_data class User_tools_Form(forms.ModelForm): diff --git a/closedverse_main/middleware.py b/closedverse_main/middleware.py index 5046cd2..c5937d5 100644 --- a/closedverse_main/middleware.py +++ b/closedverse_main/middleware.py @@ -46,6 +46,15 @@ class CheckForBanMiddleware: return response def process_view(self, request, view_func, view_args, view_kwargs): + # Get one active ban that is not expired for the IP address + ip_address = request.META.get('REMOTE_ADDR') + active_ip_ban = Ban.objects.filter( + ip_address=ip_address, + active=True, + expiry_date__gte=timezone.now(),).first() + if active_ip_ban: + context = {'ban': active_ip_ban} + return render(request, 'ban.html', context) if not request.user.is_authenticated: return None # Get one active ban that is not expired for the user @@ -56,15 +65,6 @@ class CheckForBanMiddleware: if active_user_ban: context = {'ban': active_user_ban} return render(request, 'ban.html', context) - # Get one active ban that is not expired for the IP address - ip_address = request.META.get('REMOTE_ADDR') - active_ip_ban = Ban.objects.filter( - ip_address=ip_address, - active=True, - expiry_date__gte=timezone.now(),).first() - if active_ip_ban: - context = {'ban': active_ip_ban} - return render(request, 'ban.html', context) return None class ClosedMiddleware(object): diff --git a/closedverse_main/models.py b/closedverse_main/models.py index 56f60ad..e30d048 100644 --- a/closedverse_main/models.py +++ b/closedverse_main/models.py @@ -130,7 +130,7 @@ class Role(models.Model): organization = models.CharField(max_length=255, blank=True, null=True, help_text='Text that shows above one\'s username') def __str__(self): - return "role \"" + str(self.organization) + "\", name " + str(self.image) + return str(self.organization) #mii_domain = 'https://mii-secure.cdn.nintendo.net' # as of writing, mii-secure is unstable, nintendo please do not f*ck me for this @@ -414,18 +414,17 @@ class User(AbstractBaseUser, PermissionsMixin): # Admin can-manage def can_manage(self): - if self.level >= settings.level_needed_to_man_users or self.is_staff: + if self.level >= settings.level_needed_to_man_users: can_manage = True else: can_manage = False return can_manage # Does self have authority over user? def has_authority(self, user): - if user.is_authenticated: - if self.is_staff and not user.is_staff: - return True - if self.level >= user.level: - return True + if not user.is_authenticated: + return False + if self.level >= user.level: + return True return False def friend_state(self, other): # Todo: return -1 for cannot, 0 for nothing, 1 for my friend pending, 2 for their friend pending, 3 for friends @@ -642,7 +641,9 @@ class Invites(models.Model): def is_valid(self): if self.used or self.void: return False - if not self.creator.can_invite: + if not self.creator.can_invite or not self.creator.is_active: + return False + if self.creator.active_ban(): return False return True @@ -693,13 +694,14 @@ class Community(models.Model): 5: 'PC Game', 6: 'Xbox Game', 7: 'Playstation Game', + 8: 'Cross-platform Game', }.get(self.platform) else: return { 0: "General community", 1: "Game community", 2: "Special community", - 3: "User owned community", + 3: "User-created community", }.get(self.type) def type_platform(self): thing = { @@ -711,7 +713,7 @@ class Community(models.Model): 5: 'pc', 6: 'xbox', 7: 'ps', - 8: 'youre-mom', + 8: 'cross-platform', }.get(self.platform) if not thing: return None @@ -838,7 +840,7 @@ class Community(models.Model): # Check for spam using our OWN ALGO!!!!!!!!! if request.user.has_postspam(body, upload, drawing): return 7 - for keyword in ['faggot', 'fag', 'nigger', 'nigga', 'hitler']: + for keyword in ['faggot', 'fag', 'nigger', 'nigga']: if keyword in body.lower(): return 9 if body.isspace() and not drawing: @@ -906,15 +908,6 @@ class Post(models.Model): except: return False return thing - def discord_vid(self): - try: - thing = re.search('(https?://)?(www\.)?(cdn)?(discordapp)\.(com)/attachments/([a-zA-Z0-9]+)/([a-zA-Z0-9]+)/(.+)', self.url).group(8) - if thing.endswith(".mp4") or thing.endswith(".webm"): - return thing - else: - return False - except: - return False def has_line_trun(self): if self.body and len(self.body.splitlines()) > 10: return True diff --git a/closedverse_main/templates/closedverse_main/elements/file-button.html b/closedverse_main/templates/closedverse_main/elements/file-button.html index 7c9861a..c04f188 100644 --- a/closedverse_main/templates/closedverse_main/elements/file-button.html +++ b/closedverse_main/templates/closedverse_main/elements/file-button.html @@ -7,7 +7,7 @@