diff --git a/closedverse/settings.py b/closedverse/settings.py index 103cd9a..80309f4 100644 --- a/closedverse/settings.py +++ b/closedverse/settings.py @@ -189,12 +189,18 @@ MARKDOWN_DEUX_STYLES = { # allow sign ups. allow_signups = True +# Whatever the reason may be, you have the option to make your clone invite only. +invite_only = True + # Minimum level required to view IP addresses and user agents. (default: 10) # Mods under this level will still be able to manage users, however will not be able to view any sensitive data. -min_lvl_metadata_perms = 10 +min_lvl_metadata_perms = 100 -# if someone's level is equal or above this, they can edit any community on your clone. -level_needed_to_man_communities = 5 +# if someone's level is equal or above this, they can edit most community on your clone. +level_needed_to_man_communities = 10 + +# if someone's level is equal or above this, they can edit any user with a lower level on your clone. +level_needed_to_man_users = 10 # file size limits in megabytes! only applies when using the community tools. max_icon_size = .5 @@ -209,7 +215,9 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 15728640 # Set the default theme here! Set this to None to use the normal Closedverse theme. # TODO, make this work for users who aren't logged in. -site_wide_theme_hex = "#ff00cd" +# Example: site_wide_theme_hex = "#ff4159" +# The site wide global theme cannot be deactivated by your users. +site_wide_theme_hex = 'ff4159' # The location to redirect to if a user's status is set to 2 (Redirect) (rickroll) inactive_redirect = "https://www.youtube.com/watch?v=dQw4w9WgXcQ" @@ -219,4 +227,4 @@ inactive_redirect = "https://www.youtube.com/watch?v=dQw4w9WgXcQ" image_delete_opt = 0 # age (minimal 13 due to C.O.P.P.A) -age_allowed = "16" +age_allowed = "13" diff --git a/closedverse_main/admin.py b/closedverse_main/admin.py index be79a2c..09fa7e1 100644 --- a/closedverse_main/admin.py +++ b/closedverse_main/admin.py @@ -112,11 +112,9 @@ class AuditAdmin(admin.ModelAdmin): class AdsAdmin(admin.ModelAdmin): raw_id_fileds = ('id', 'created', 'url', 'imageurl') - -class MOTDAdmin(admin.ModelAdmin): - raw_id_fileds = ('id', 'created', 'message', ) - list_display = ('message', 'show', 'order', 'created', ) - actions = [Hide_Memo, Show_Memo] + +class InvitesAdmin(admin.ModelAdmin): + raw_id_fileds = ('id', 'created', 'creator') class WelcomemsgAdmin(admin.ModelAdmin): raw_id_fileds = ('id', 'created', 'message', ) @@ -151,11 +149,11 @@ admin.site.register(models.ProfileHistory, HistoryAdmin) admin.site.register(models.Post, PostAdmin) admin.site.register(models.Comment, CommentAdmin) admin.site.register(models.Ads, AdsAdmin) -admin.site.register(models.Motd, MOTDAdmin) admin.site.register(models.welcomemsg, WelcomemsgAdmin) admin.site.register(models.Yeah, YeahAdmin) admin.site.register(models.Follow) admin.site.register(models.FriendRequest) admin.site.register(models.Friendship, ConversationAdmin) +admin.site.register(models.Invites, InvitesAdmin) admin.site.register(models.Poll) admin.site.register(models.PollVote) diff --git a/closedverse_main/middleware.py b/closedverse_main/middleware.py index 880d444..c42a1e8 100644 --- a/closedverse_main/middleware.py +++ b/closedverse_main/middleware.py @@ -1,72 +1,48 @@ -from django.http import HttpResponseForbidden, HttpResponseBadRequest +from django.http import HttpResponseForbidden from closedverse import settings -from django.shortcuts import render from django.shortcuts import redirect from django.contrib.auth import logout from re import compile -class ClosedMiddleware(object): - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - response = self.get_response(request) - if request.user.is_authenticated: - if not request.user.profile(): - return HttpResponseForbidden('So, Somehow your profile is completely gone. Your account itself still exists, but your profile does not. Please contact an admin, and ask them to make a profile for you. If you are unable to contact someone, you should make a new account.') - else: - return response - ''' - for keyword in ['24.61.157.95', ]: - if keyword in request.META['HTTP_CF_CONNECTING_IP']: - return redirect('https://file.garden/Xbo5elapeDSxWf1x/adam.mp4') - - for keyword in ['PlayStation', 'Switch', '3DS', ]: - if keyword in request.META['HTTP_USER_AGENT']: - return HttpResponseForbidden('Error code 403') - ''' - else: - return response - # Taken from https://python-programming.com/recipes/django-require-authentication-pages/ -''' +if settings.FORCE_LOGIN: + EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))] + if hasattr(settings, 'LOGIN_EXEMPT_URLS'): + EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS] + class ClosedMiddleware(object): - def __init__(self, get_response): - self.get_response = get_response + def __init__(self, get_response): + self.get_response = get_response - def __call__(self, request): - # Force logins if it's set - if settings.force_login and not request.user.is_authenticated: - if not any(m.match(request.path_info.lstrip('/')) for m in EXEMPT_URLS): - if request.is_ajax(): - return HttpResponseForbidden("Login is required") - return redirect(settings.LOGIN_REDIRECT_URL) - # Fix this ; put something in settings signifying if the server supports HTTPS or not - if not request.is_secure() and (not settings.DEBUG) and settings.PROD: - # Let's try to redirect to HTTPS for non-Nintendo stuff. - if not request.META.get('HTTP_USER_AGENT'): - return HttpResponseForbidden("You need a user agent.", content_type='text/plain') - if not request.is_secure() and not 'Nintendo' in request.META['HTTP_USER_AGENT']: - return redirect('https://{0}{1}'.format(request.get_host(), request.get_full_path())) - if request.user.is_authenticated: - # User active; this doesn't work at the moment due to Postgres not being able to change bools to ints - if request.user.is_active() == 0: - return HttpResponseForbidden() - elif request.user.is_active() == 2: - return redirect(settings.inactive_redirect) - - if not request.user.is_active: - return HttpResponseForbidden() - # If there isn't a request.session - if not request.session.get('passwd'): - request.session['passwd'] = request.user.password - else: - if request.session['passwd'] != request.user.password: - logout(request) - response = self.get_response(request) + def __call__(self, request): + # Force logins if it's set + if settings.FORCE_LOGIN and not request.user.is_authenticated: + if not any(m.match(request.path_info.lstrip('/')) for m in EXEMPT_URLS): + if request.headers.get('x-requested-with') == 'XMLHttpRequest': + return HttpResponseForbidden("Login is required") + return redirect(settings.LOGIN_REDIRECT_URL) + # Fix this ; put something in settings signifying if the server supports HTTPS or not + #if not request.is_secure() and (not settings.DEBUG) and settings.CLOSEDVERSE_PROD: + # Let's try to redirect to HTTPS for non-Nintendo stuff. + """ + if not request.META.get('HTTP_USER_AGENT'): + return HttpResponseForbidden("You need a user agent.", content_type='text/plain') + if settings.CLOSEDVERSE_PROD not request.is_secure() and not 'Nintendo' in request.META['HTTP_USER_AGENT']: + return redirect('https://{0}{1}'.format(request.get_host(), request.get_full_path())) + """ + if request.user.is_authenticated: + if not request.user.is_active(): + if request.user.warned_reason: + ban_msg = request.user.warned_reason + else: + ban_msg = 'You are banned.' + return HttpResponseForbidden(ban_msg) + # If there isn't a request.session + if not request.session.get('passwd'): + request.session['passwd'] = request.user.password + else: + if request.session['passwd'] != request.user.password: + logout(request) + response = self.get_response(request) - return response - ''' - -""" -return HttpResponseForbidden("You're one sick fuck. I would never suggest removing an Inkling girl's clothes and licking her tiny body all over, nibbling her neck and kissing her adorable little nipples. Only a heartless monster would think about her cute girlish mouth and tongue wrapped around a thick cock slick with her saliva, pumping in and out of her mouth until it erupts, the cum more than her little throat can swallow. The idea of thick viscous semen overflowing, dribbling down her chin over her flat chest, her tiny hands scooping it all up and watching her suck it off her fingertips is just horrible. You're all a bunch of sick perverts, thinking of spreading her smooth slender thighs, cock poised at the entrance to her pure, tight, virginal pussy, and thrusting in deep as a whimper escapes her lips which are slippery with cum, while her small body shudders from having her cherry taken in one quick stroke. I am disgusted at how you'd get even more excited as you lean over her, listening to her quickening breath, her girlish moans and gasps while you hasten your strokes, her sweet pants warm and moist on your face and her flat chest, shiny with a sheen of fresh sweat, rising and falling rapidly to meet yours. It is truly nasty how you'd run your hands all over her tiny body while you violate her, feeling her nipples hardening against your tongue as you lick her chest, her neck and her armpits, savoring the scent of her skin and sweat while she trembles from the stimulation and as she reaches her climax, hearing her cry out softly as she has her first orgasm while that cock is buried impossibly deep inside her, pulsing violently as an intense amount of hot cum spurts forth and floods through her freshly-deflowered pussy for the first time, filling her womb only to spill out of her with a sickening squelch. And as you lie atop her flushed body, she murmurs breathlessly, \"You came so much inside of me,\" then her fingers dig into your back as she feels your cock hardening inside again.", content_type='text/plain')""" + return response diff --git a/closedverse_main/models.py b/closedverse_main/models.py index ca82fac..58c6312 100644 --- a/closedverse_main/models.py +++ b/closedverse_main/models.py @@ -117,10 +117,14 @@ class CommunityFavoriteManager(models.Manager): color_re = re.compile('^#([A-Fa-f0-9]{6})$') validate_color = RegexValidator(color_re, "Enter a valid color", 'invalid') class ColorField(models.CharField): - default_validators = [validate_color] - def __init__(self, *args, **kwargs): - kwargs['max_length'] = 18 - super(ColorField, self).__init__(*args, **kwargs) + default_validators = [validate_color] + def __init__(self, *args, **kwargs): + kwargs['max_length'] = 18 + super(ColorField, self).__init__(*args, **kwargs) + +#mii_domain = 'https://mii-secure.cdn.nintendo.net' +# 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(models.Model): unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) @@ -151,6 +155,7 @@ class User(models.Model): staff = models.BooleanField(default=False) #active = models.SmallIntegerField(default=1, choices=((0, 'Redirect'), (1, 'Good'), (2, 'Disabled'))) active = models.BooleanField(default=True) + can_invite = models.BooleanField(default=True) warned = models.BooleanField(default=False) warned_reason = models.CharField(blank=True, null=True, max_length=600) bg_url = models.CharField(max_length=300, null=True, blank=True) @@ -168,19 +173,6 @@ class User(models.Model): def __str__(self): return self.username - def ColorTheme(self): - # if the user set a theme, display that. - if self.theme: - the_theme = self.theme - the_theme = the_theme.strip("#") - # if there's no theme set by the user, use the site's picked theme. - elif settings.site_wide_theme_hex: - the_theme = settings.site_wide_theme_hex - the_theme = the_theme.strip("#") - # If there's no theme set in settings.py, return None. - else: - the_theme = None - return the_theme def get_full_name(self): return self.username def get_short_name(self): @@ -315,7 +307,7 @@ class User(models.Model): 4: 'frustrated', 5: 'puzzled', }.get(feeling, "normal") - url = 'https://mii-secure.cdn.nintendo.net/{0}_{1}_face.png'.format(self.avatar, feeling) + url = '{2}{0}_{1}_face.png'.format(self.avatar, feeling, mii_domain) return url elif not self.avatar: return settings.STATIC_URL + 'img/anonymous-mii.png' @@ -427,15 +419,18 @@ class User(models.Model): # Admin can-manage def can_manage(self): - if (self.level >= 2) or self.is_staff(): - return True - return False - # Does user have authority over self? + if self.level >= settings.level_needed_to_man_users or self.staff: + can_manage = True + else: + can_manage = False + return can_manage + # Does self have authority over user? def has_authority(self, user): - if self.is_staff(): - return False - if (self.level < user.level): - return True + if user.is_authenticated: + if self.staff and not user.staff: + return True + 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 @@ -596,6 +591,26 @@ class User(models.Model): except: return False return user + +# An invite system, for closed off communities or for whatever reason. +class Invites(models.Model): + id = models.AutoField(primary_key=True) + created = models.DateTimeField(auto_now_add=True) + creator = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE, related_name='invite_creator') + code = models.CharField(max_length=36, default=uuid.uuid4) + used = models.BooleanField(default=False) + void = models.BooleanField(default=False) + used_by = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE, related_name='invited_user') + + def is_valid(self): + if self.used or self.void: + return False + if not self.creator.can_invite: + return False + return True + + def __str__(self): + return "invite by " + str(self.creator) class Community(models.Model): unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) @@ -869,8 +884,8 @@ class Post(models.Model): return False def can_rm(self, request): if self.creator.has_authority(request.user): - return True - return False + return False + return True def give_yeah(self, request): if not request.user.has_freedom() and Yeah.objects.filter(by=request.user, created__gt=timezone.now() - timedelta(seconds=5)).exists(): return False @@ -1083,10 +1098,10 @@ class Comment(models.Model): # return False def can_rm(self, request): if self.creator.has_authority(request.user): - return True + return False #if self.original_post.is_mine(request.user): # return True - return False + return True def give_yeah(self, request): if not request.user.has_freedom() and Yeah.objects.filter(by=request.user, created__gt=timezone.now() - timedelta(seconds=5)).exists(): return False @@ -1641,7 +1656,7 @@ class LoginAttempt(models.Model): user_agent = models.TextField(null=True, blank=True) def __str__(self): - return 'A login attempt to ' + str(self.user) + ' from ' + self.addr + ', ' + str(self.success) + return 'A login attempt to ' + str(self.user) + ' from ' + str(self.addr) + ', ' + str(self.success) class MetaViews(models.Model): id = models.AutoField(primary_key=True) diff --git a/closedverse_main/templates/closedverse_main/community_all.html b/closedverse_main/templates/closedverse_main/community_all.html index bb7deeb..5f92d44 100644 --- a/closedverse_main/templates/closedverse_main/community_all.html +++ b/closedverse_main/templates/closedverse_main/community_all.html @@ -19,29 +19,20 @@

- General - Game - Special - User + General + Game + Special + User
-
- {% community_page_element general "General Communities" %} -
-
- {% community_page_element game "Game Communities" %} -
-
- {% community_page_element special "Special Communities" %} -
-
- {% community_page_element user_communities "User Communities" %} +
+ {% community_page_element communities text %}
{% if has_next %} - Next + Next {% endif %} {% if has_back %}

 

- Back + Back {% endif %}
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/closedverse_main/templates/closedverse_main/community_list.html b/closedverse_main/templates/closedverse_main/community_list.html index 1722f81..61d6aae 100644 --- a/closedverse_main/templates/closedverse_main/community_list.html +++ b/closedverse_main/templates/closedverse_main/community_list.html @@ -23,7 +23,7 @@
{% for announcements in announcements %}
- {% user_icon_container announcements.creator post.feeling %} + {% user_icon_container announcements.creator announcements.feeling %} {{ announcements.creator }} - {{ announcements.created }}

{{ announcements.body|linebreaksbr|urlize }}

{% if announcements.screenshot %}{% endif %} @@ -32,13 +32,13 @@
{% endif %} - {% if welmes and not request.user.is_authenticated %} + {% if WelcomeMSG and not request.user.is_authenticated %}

Welcome to Cedar!

- {% for welmes in welmes %} -

{{ welmes.Title }}

-

{{ welmes.message|linebreaksbr|urlize }}

- {% if welmes.image %}{% endif %} + {% for WelcomeMSG in WelcomeMSG %} +

{{ WelcomeMSG.Title }}

+

{{ WelcomeMSG.message|linebreaksbr|urlize }}

+ {% if WelcomeMSG.image %}{% endif %} {% endfor %}
{% endif %} @@ -78,17 +78,18 @@ {% community_page_element game "Game Communities" %} {% community_page_element special "Special Communities" %} {% community_page_element user_communities "User owned Communities" %} - Show more + Show more
{% endblock %} diff --git a/closedverse_main/templates/closedverse_main/elements/community_post.html b/closedverse_main/templates/closedverse_main/elements/community_post.html index dfe3fd1..ad435ad 100644 --- a/closedverse_main/templates/closedverse_main/elements/community_post.html +++ b/closedverse_main/templates/closedverse_main/elements/community_post.html @@ -32,9 +32,7 @@ {% if post.yt_vid %} {% elif post.discord_vid %} -
- -
+
{% endif %} {% if post.drawing %}

diff --git a/closedverse_main/templates/closedverse_main/elements/user-sidebar.html b/closedverse_main/templates/closedverse_main/elements/user-sidebar.html index ec8d6a3..bf61af4 100644 --- a/closedverse_main/templates/closedverse_main/elements/user-sidebar.html +++ b/closedverse_main/templates/closedverse_main/elements/user-sidebar.html @@ -48,7 +48,7 @@ {% endif %} {% endif %} - {% if request.user.can_manage %} + {% if not has_authority and request.user.can_manage %} {% endif %}
diff --git a/closedverse_main/templates/closedverse_main/invites.html b/closedverse_main/templates/closedverse_main/invites.html new file mode 100644 index 0000000..3df8350 --- /dev/null +++ b/closedverse_main/templates/closedverse_main/invites.html @@ -0,0 +1,35 @@ +{% extends "closedverse_main/layout.html" %} +{% block main-body %}{% load closedverse_user %} +{% user_sidebar request user user.profile 0 True %} +
+
+

My invites

+
+

You can create invite keys here. Simply copy a key and send it to whoever you want to invite.

+ {% if invites %} +

Invites you've created:

+ + + + + + {% for invites in invites %} + + + + + {% endfor %} +
Date createdCode
{{ invites.created }}{{ invites.code }}
+ {% else %} +

No invites to show.

+ {% endif %} +
+ {% csrf_token %} +
+ +
+
+
+
+
+{% endblock %} diff --git a/closedverse_main/templates/closedverse_main/layout.html b/closedverse_main/templates/closedverse_main/layout.html index f568c50..fe570bd 100644 --- a/closedverse_main/templates/closedverse_main/layout.html +++ b/closedverse_main/templates/closedverse_main/layout.html @@ -27,8 +27,9 @@ - {% if request.user.ColorTheme %}{% endif %} @@ -114,6 +115,7 @@