diff --git a/closedverse/settings.py b/closedverse/settings.py index 80309f4..f2ecfe8 100644 --- a/closedverse/settings.py +++ b/closedverse/settings.py @@ -171,11 +171,26 @@ nnid_forbiddens = BASE_DIR + '/forbidden.json' # Client key to use for iphub.email, because we're using that # None for no IP checking (recommended since this is so slow) -iphub_key = "" +IPHUB_KEY = "" # If IP can be checked, then use this to disallow any proxies disallow_proxy = False +# Setting this to True forces every user to log in/ +# sign up for the site to view any content. +FORCE_LOGIN = False +# A list of URLs that are always accessible +# whether the above value is set or not. +LOGIN_EXEMPT_URLS = { + r'^login/$', + r'^signup/$', + r'^logout/$', + r'^reset/$', + r'^help/rules$', + r'^help/contact$', + r'^help/login$', +} + # MD MARKDOWN_DEUX_STYLES = { "default": { @@ -190,17 +205,17 @@ MARKDOWN_DEUX_STYLES = { allow_signups = True # Whatever the reason may be, you have the option to make your clone invite only. -invite_only = True +invite_only = False # 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 = 100 # if someone's level is equal or above this, they can edit most community on your clone. -level_needed_to_man_communities = 10 +level_needed_to_man_communities = 5 # 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 +level_needed_to_man_users = 5 # file size limits in megabytes! only applies when using the community tools. max_icon_size = .5 diff --git a/closedverse_main/admin.py b/closedverse_main/admin.py index 09fa7e1..2008a50 100644 --- a/closedverse_main/admin.py +++ b/closedverse_main/admin.py @@ -14,121 +14,121 @@ admin.site.login = login_page """ class UserForm(ModelForm): - class Meta: - model = models.User - fields = '__all__' - widgets = { - 'password': PasswordInput(), - } + class Meta: + model = models.User + fields = '__all__' + widgets = { + 'password': PasswordInput(), + } """ @admin.action(description='Hide selected items') def Hide_Memo(modeladmin, request, queryset): - queryset.update(show = False) + queryset.update(show = False) @admin.action(description='Show selected items') def Show_Memo(modeladmin, request, queryset): - queryset.update(show = True) + queryset.update(show = True) @admin.action(description='Hide selected items') def Hide_content(modeladmin, request, queryset): - queryset.update(is_rm = True) + queryset.update(is_rm = True) @admin.action(description='Show selected items') def Show_content(modeladmin, request, queryset): - queryset.update(is_rm = False) + queryset.update(is_rm = False) @admin.action(description='Feature selected communities') def Feature_community(modeladmin, request, queryset): - queryset.update(is_feature = True) + queryset.update(is_feature = True) @admin.action(description='Unfeature selected communities') def Unfeature_community(modeladmin, request, queryset): - queryset.update(is_feature = False) + queryset.update(is_feature = False) @admin.action(description='Force login') def force_login(modeladmin, request, queryset): - queryset.update(require_auth = True) + queryset.update(require_auth = True) @admin.action(description='Unforce login') def unforce_login(modeladmin, request, queryset): - queryset.update(require_auth = False) + queryset.update(require_auth = False) @admin.action(description='Disable user') def Disable_user(modeladmin, request, queryset): - queryset.update(active = False) + queryset.update(active = False) class UserAdmin(admin.ModelAdmin): - search_fields = ('id', 'unique_id', 'username', 'nickname', 'email', ) - list_display = ('id', 'username', 'nickname', 'warned', 'level', 'staff', 'active', ) - exclude = ('addr', 'signup_addr', 'password', ) - actions = [Disable_user] - #exclude = ('staff', ) - # Not yet - #form = UserForm + search_fields = ('id', 'unique_id', 'username', 'nickname', 'email', ) + list_display = ('id', 'username', 'nickname', 'warned', 'level', 'staff', 'active', ) + exclude = ('addr', 'signup_addr', 'password', ) + actions = [Disable_user] + #exclude = ('staff', ) + # Not yet + #form = UserForm class ProfileAdmin(admin.ModelAdmin): - search_fields = ('id', 'unique_id', 'origin_id', ) - raw_id_fields = ('user', 'favorite', 'adopted', ) - list_display = ('id', 'user', 'comment', 'let_freedom', ) + search_fields = ('id', 'unique_id', 'origin_id', ) + raw_id_fields = ('user', 'favorite', ) + list_display = ('id', 'user', 'comment', 'let_freedom', ) class ComplaintAdmin(admin.ModelAdmin): - search_fields = ('id', 'unique_id', 'body', ) - raw_id_fields = ('creator', ) + search_fields = ('id', 'unique_id', 'body', ) + raw_id_fields = ('creator', ) class ConversationAdmin(admin.ModelAdmin): - search_fields = ('id', 'unique_id', ) - raw_id_fields = ('source', 'target', ) + search_fields = ('id', 'unique_id', ) + raw_id_fields = ('source', 'target', ) class PostAdmin(admin.ModelAdmin): - raw_id_fields = ('creator', 'poll', ) - search_fields = ('id', 'unique_id', 'body', 'creator__username', ) - list_display = ('id', 'creator', 'body', 'is_rm', ) - actions = [Hide_content, Show_content] - def get_queryset(self, request): - return models.Post.real.get_queryset() + raw_id_fields = ('creator', 'poll', ) + search_fields = ('id', 'unique_id', 'body', 'creator__username', ) + list_display = ('id', 'creator', 'body', 'is_rm', ) + actions = [Hide_content, Show_content] + def get_queryset(self, request): + return models.Post.real.get_queryset() class CommentAdmin(admin.ModelAdmin): - raw_id_fields = ('creator', 'original_post', ) - search_fields = ('id', 'unique_id', 'body', 'creator__username', ) - list_display = ('id', 'creator', 'body', 'original_post', 'is_rm', ) - actions = [Hide_content, Show_content] - def get_queryset(self, request): - return models.Comment.real.get_queryset() + raw_id_fields = ('creator', 'original_post', ) + search_fields = ('id', 'unique_id', 'body', 'creator__username', ) + list_display = ('id', 'creator', 'body', 'original_post', 'is_rm', ) + 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', 'is_rm', 'is_feature', 'require_auth') - search_fields = ('id', 'unique_id', 'name', 'description', ) - actions = [Hide_content, Show_content, Feature_community, Unfeature_community, force_login, unforce_login] - def get_queryset(self, request): - return models.Community.real.get_queryset() + raw_id_fields = ('creator', ) + list_display = ('id', 'name', 'description', 'type', 'creator', 'is_rm', 'is_feature', 'require_auth') + search_fields = ('id', 'unique_id', 'name', 'description', ) + actions = [Hide_content, Show_content, Feature_community, Unfeature_community, force_login, unforce_login] + def get_queryset(self, request): + return models.Community.real.get_queryset() class MessageAdmin(admin.ModelAdmin): - raw_id_fields = ('creator', 'conversation', ) - search_fields = ('id', 'unique_id', 'body', 'creator__username', ) - list_display = ('id', 'creator', 'conversation', 'body', ) - actions = [Hide_content, Show_content] - def get_queryset(self, request): - return models.Message.real.get_queryset() + raw_id_fields = ('creator', 'conversation', ) + search_fields = ('id', 'unique_id', 'body', 'creator__username', ) + list_display = ('id', 'creator', 'conversation', 'body', ) + actions = [Hide_content, Show_content] + def get_queryset(self, request): + return models.Message.real.get_queryset() class NotificationAdmin(admin.ModelAdmin): - raw_id_fields = ('to', 'source', 'context_post', 'context_comment', ) - search_fields = ('unique_id', ) - list_display = ('id', 'to', 'source', 'context_post', 'context_comment', ) + raw_id_fields = ('to', 'source', 'context_post', 'context_comment', ) + search_fields = ('unique_id', ) + list_display = ('id', 'to', 'source', 'context_post', 'context_comment', ) class AuditAdmin(admin.ModelAdmin): - raw_id_fields = ('by', 'user', 'post', 'comment', 'reversed_by', ) - search_fields = ('by__username', 'user__username', ) + raw_id_fields = ('by', 'user', 'post', 'comment', 'reversed_by', ) + search_fields = ('by__username', 'user__username', ) class AdsAdmin(admin.ModelAdmin): - raw_id_fileds = ('id', 'created', 'url', 'imageurl') - + raw_id_fileds = ('id', 'created', 'url', 'imageurl') + class InvitesAdmin(admin.ModelAdmin): - raw_id_fileds = ('id', 'created', 'creator') + raw_id_fileds = ('id', 'created', 'creator') class WelcomemsgAdmin(admin.ModelAdmin): - raw_id_fileds = ('id', 'created', 'message', ) - list_display = ('Title', 'message', 'show', 'order', 'created', ) - actions = [Hide_Memo, Show_Memo] + raw_id_fileds = ('id', 'created', 'message', ) + list_display = ('Title', 'message', 'show', 'order', 'created', ) + actions = [Hide_Memo, Show_Memo] class YeahAdmin(admin.ModelAdmin): - raw_id_fields = ('by', 'post', 'comment', ) - list_display = ('by', 'post', 'comment', ) - search_fields = ('by__username', 'post__body', 'comment__body', ) - + raw_id_fields = ('by', 'post', 'comment', ) + list_display = ('by', 'post', 'comment', ) + search_fields = ('by__username', 'post__body', 'comment__body', ) + class HistoryAdmin(admin.ModelAdmin): - raw_id_fields = ('user',) - list_display = ('id', 'user') + raw_id_fields = ('user',) + list_display = ('id', 'user') #class BlockAdmin(admin.ModelAdmin) diff --git a/closedverse_main/models.py b/closedverse_main/models.py index 58c6312..b0dd713 100644 --- a/closedverse_main/models.py +++ b/closedverse_main/models.py @@ -1,8 +1,7 @@ from __future__ import unicode_literals -from colorfield.fields import ColorField from django.db import models from django.contrib.auth.models import BaseUserManager -from django.db.models import Q, QuerySet, Max, F, Count, Case, When, Exists, OuterRef +from django.db.models import Q, QuerySet, Max, F, Count, Case, When, Exists, OuterRef, Subquery from django.utils import timezone from django.forms.models import model_to_dict from django.utils.dateformat import format @@ -28,90 +27,86 @@ visibility = ((0, 'show'), (1, 'friends only'), (2, 'hide'), ) # Like set() but orders def organ(seq): - seen = set() - seen_add = seen.add - return [x for x in seq if not (x in seen or seen_add(x))] + seen = set() + seen_add = seen.add + return [x for x in seq if not (x in seen or seen_add(x))] class UserManager(BaseUserManager): - # idk why this is even here - def create_user(self, username, password): - user = self.model( - username=username, - ) - user.set_password(password) - user.save(using=self._db) - return user + # idk why this is even here + def create_user(self, username, password): + user = self.model( + username=username, + ) + user.set_password(password) + user.save(using=self._db) + return user - def closed_create_user(self, username, password, email, addr, signup_addr, user_agent, nick, nn, gravatar): - user = self.model( - username = username, - nickname = util.filterchars(nick), - addr = addr, - signup_addr = signup_addr, - user_agent = user_agent, - email = email, - ) - spamuser = True - profile = Profile.objects.model() - if nn: - user.avatar = nn[0] - profile.origin_id = nn[2] - profile.origin_info = json.dumps(nn) - user.has_mh = True - else: - user.avatar = util.get_gravatar(email) or ('s' if getrandbits(1) else '') - - user.has_mh = False - user.set_password(password) - user.save(using=self._db) - if spamuser: - profile.let_freedom = True - else: - profile.let_freedom = True - profile.user = user - profile.save() - return user - def create_superuser(self, username, password): - user = self.model( - username=username, - ) - user.set_password(password) - user.staff = True - user.save() - profile = Profile.objects.model() - profile.user = user - profile.save() - return user - def authenticate(self, username, password): - if not username or username.isspace(): - return None - user = self.filter(Q(username__iexact=username.replace(' ', '')) | Q(username__iexact=username) | Q(email=username)) - if not user.exists(): - return None - user = user.first() - # If the user is an admin, say that they don't exist, actually no... - # Or, if the user doesn't want username login, don't let them if they didn't enter their email - if user.profile('email_login') == 2 and not user.email == username: - return None - elif user.profile('email_login') == 0 and user.email == username: - return None - try: - passwd = user.check_password(password) - # Check if the password is a valid bcrypt - except ValueError: - return (user, 2) - else: - if not passwd: - return (user, False) - return (user, True) + def closed_create_user(self, username, password, email, addr, signup_addr, user_agent, nick, nn, gravatar): + user = self.model( + username = username, + nickname = util.filterchars(nick), + addr = addr, + signup_addr = signup_addr, + user_agent = user_agent, + email = email, + ) + profile = Profile.objects.model() + if nn: + user.avatar = nn[0] + profile.origin_id = nn[2] + profile.origin_info = json.dumps(nn) + user.has_mh = True + else: + user.avatar = util.get_gravatar(email) or ('s' if getrandbits(1) else '') + + user.has_mh = False + user.set_password(password) + user.save(using=self._db) + profile.user = user + profile.save() + return user + def create_superuser(self, username, password): + user = self.model( + username=username, + ) + user.set_password(password) + user.staff = True + user.level = 99 # added because some admin funcs are missing otherwise + user.save() + profile = Profile.objects.model() + profile.user = user + profile.save() + return user + def authenticate(self, username, password): + if not username or username.isspace(): + return None + user = self.filter(Q(username__iexact=username.replace(' ', '')) | Q(username__iexact=username) | Q(email=username)) + if not user.exists(): + return None + user = user.first() + # If the user is an admin, say that they don't exist, actually no... + # Or, if the user doesn't want username login, don't let them if they didn't enter their email + if user.profile('email_login') == 2 and not user.email == username: + return None + elif user.profile('email_login') == 0 and user.email == username: + return None + try: + passwd = user.check_password(password) + # Check if the password is a valid bcrypt + except ValueError: + return (user, 2) + else: + if not passwd: + return (user, False) + return (user, True) class PostManager(models.Manager): - def get_queryset(self): - return super(PostManager, self).get_queryset().filter(is_rm=False) + def get_queryset(self): + return super(PostManager, self).get_queryset().filter(is_rm=False) class CommunityFavoriteManager(models.Manager): - def get_queryset(self): - return super(CommunityFavoriteManager, self).get_queryset().filter(community__is_rm=False).exclude(community__type=4) + def get_queryset(self): + return super(CommunityFavoriteManager, self).get_queryset().filter(community__is_rm=False).exclude(community__type=4) # Taken from https://github.com/jaredly/django-colorfield/blob/master/colorfield/fields.py color_re = re.compile('^#([A-Fa-f0-9]{6})$') @@ -125,1661 +120,1668 @@ class ColorField(models.CharField): #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) - 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='') - has_mh = models.BooleanField(default=False) - 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) - # ROLE: This doesn't have anything - role = models.SmallIntegerField(default=0, choices=((0, 'normal'), (1, 'Bot'), (2, 'Administrator'), (3, 'Moderator'), (4, 'NO'), (5, 'Donator'), (6, 'Tester'), (7, 'Cools'), (8, 'Developer'), (9, 'SMF9-Django'), (10, 'Staff'), (11, 'GAY DOGWATER' ), ( 12, 'DUMB SNAIL' ), (13, 'Russian ADRIAN'), (14, 'Contest'), (15, 'Gamecon'), (16, 'Cedar'), )) - addr = models.CharField(max_length=64, null=True, blank=True) - signup_addr = models.CharField(max_length=64, null=True, blank=True) - user_agent = models.TextField(null=True, blank=True) - # C Tokens are things that let you make communities and shit. - c_tokens = models.IntegerField(default=1) - - # Things that don't have to do with auth lol - hide_online = models.BooleanField(default=False) - color = ColorField(default='', null=True, blank=True) - - 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) - - is_anonymous = False - is_authenticated = True - - last_login = models.DateTimeField(auto_now=True) - created = models.DateTimeField(auto_now_add=True) - USERNAME_FIELD = 'username' - EMAIL_FIELD = 'email' - REQUIRED_FIELDS = [] - - objects = UserManager() - - def __str__(self): - return self.username - def get_full_name(self): - return self.username - def get_short_name(self): - return self.nickname - def get_username(self): - 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 set_password(self, raw_password): - self.password = bcrypt_sha256.using(rounds=13).hash(raw_password) - def check_password(self, raw_password): - return bcrypt_sha256.using(rounds=13).verify(raw_password, hash=self.password) - def profile(self, thing=None): - # If thing is specified, that field is retrieved - if thing: - return self.profile_set.all().values_list(thing, flat=True).first() - # Otherwise just get full profile - return self.profile_set.filter(user=self).first() - def gravatar(self): - g = util.get_gravatar(self.email) - if not g: - return settings.STATIC_URL + 'img/anonymous-mii.png' - return g - def mh(self): - origin_info = self.profile('origin_info') - if not origin_info: - return None - try: - infodecode = json.loads(origin_info) - except: - return None - return infodecode[0] - def has_plain_avatar(self): - if not self.has_mh and 'http' in self.avatar and not 'gravatar.com' in self.avatar: - return True - def has_avatar(self): - if not self.avatar or len(self.avatar) == 1: - return False - return True - def let_yeahnotifs(self): - return self.profile('let_yeahnotifs') - def limit_remaining(self): - limit = self.profile('limit_post') - # If False is returned, no post limit is assumed. - if limit == 0: - return False - today_min = timezone.datetime.combine(timezone.datetime.today(), time.min) - today_max = timezone.datetime.combine(timezone.datetime.today(), time.max) - # recent_posts = - # Posts made by the user today + posts made by the IP today + - # same thing except with comments - recent_posts = Post.real.filter(Q(creator=self.id, created__range=(today_min, today_max)) | Q(creator__addr=self.addr, created__range=(today_min, today_max))).count() + Comment.real.filter(Q(creator=self.id, created__range=(today_min, today_max)) | Q(creator__addr=self.addr, created__range=(today_min, today_max))).count() - - # Posts remaining - return int(limit) - recent_posts - - def get_class(self): - first = { - 1: 'tester', - 2: 'administrator', - 3: 'moderator', - 4: 'openverse', - 5: 'donator', - 6: 'tester', - 7: 'urapp', - 8: 'developer', - 9: 'pipinstalldjango', - 10: 'staff', - 11: 'kanna', - 12: 'verified', - 13: 'artcon', - 14: 'contest', - 15: 'gamecom', - 16: 'mp', - }.get(self.role, '') - second = { - 1: "Bot", - 2: "Administrator", - 3: "Moderator", - 4: "No", - 5: "Donator", - 6: "Tester", - 7: "Cool Dude", - 8: "Wii U still best console.", - 9: "Rixy Installed Django!", - 10: "Staff", - 11: "GAY DOGWATER ETC", - 12: "THE STUPIDEST ROLE IN THE WORLD", - 13: "A D R I A N", - 14: "Contest Winner", - 15: "Game Contest Winner", - 16: "Cedar Inc.", - }.get(self.role, '') - if first: - first = 'official ' + first - return [first, second] - def is_me(self, request): - if request.user.is_authenticated: - return (self == request.user) - else: - return False - def has_freedom(self): - return self.profile('let_freedom') - # This is the coolest one - def online_status(self, force=False): - # Okay so this returns True if the user's online, 2 if they're AFK, False if they're offline and None if they hide it - if self.hide_online: - return None - if (timezone.now() - timedelta(seconds=50)) > self.last_login: - return False - elif (timezone.now() - timedelta(seconds=48)) > self.last_login: - return 2 - else: - return True - def do_avatar(self, feeling=0): - if self.has_mh and self.avatar: - feeling = { - 0: 'normal', - 1: 'happy', - 2: 'like', - 3: 'surprised', - 4: 'frustrated', - 5: 'puzzled', - }.get(feeling, "normal") - 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' - elif self.avatar == 's': - return settings.STATIC_URL + 'img/anonymous-mii-sad.png' - else: - return self.avatar + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + 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='') + has_mh = models.BooleanField(default=False) + 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) + # ROLE: This doesn't have anything + role = models.SmallIntegerField(default=0, choices=((0, 'normal'), (1, 'Bot'), (2, 'Administrator'), (3, 'Moderator'), (4, 'NO'), (5, 'Donator'), (6, 'Tester'), (7, 'Cools'), (8, 'Developer'), (9, 'SMF9-Django'), (10, 'Staff'), (11, 'GAY DOGWATER' ), ( 12, 'DUMB SNAIL' ), (13, 'Russian ADRIAN'), (14, 'Contest'), (15, 'Gamecon'), (16, 'Cedar'), )) + addr = models.CharField(max_length=64, null=True, blank=True) + signup_addr = models.CharField(max_length=64, null=True, blank=True) + user_agent = models.TextField(null=True, blank=True) + # C Tokens are things that let you make communities and shit. + c_tokens = models.IntegerField(default=1) + + # Things that don't have to do with auth lol + hide_online = models.BooleanField(default=False) + color = ColorField(default='', null=True, blank=True) + + 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) + + is_anonymous = False + is_authenticated = True + + last_login = models.DateTimeField(auto_now=True) + created = models.DateTimeField(auto_now_add=True) + USERNAME_FIELD = 'username' + EMAIL_FIELD = 'email' + REQUIRED_FIELDS = [] + + objects = UserManager() + + def __str__(self): + return self.username + def get_full_name(self): + return self.username + def get_short_name(self): + return self.nickname + def get_username(self): + 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 set_password(self, raw_password): + self.password = bcrypt_sha256.using(rounds=13).hash(raw_password) + def check_password(self, raw_password): + return bcrypt_sha256.using(rounds=13).verify(raw_password, hash=self.password) + def profile(self, thing=None): + # If thing is specified, that field is retrieved + if thing: + return self.profile_set.all().values_list(thing, flat=True).first() + # Otherwise just get full profile + return self.profile_set.filter(user=self).first() + def gravatar(self): + g = util.get_gravatar(self.email) + if not g: + return settings.STATIC_URL + 'img/anonymous-mii.png' + return g + def mh(self): + origin_info = self.profile('origin_info') + if not origin_info: + return None + try: + infodecode = json.loads(origin_info) + except: + return None + return infodecode[0] + def has_plain_avatar(self): + if not self.has_mh and '/' in self.avatar and not 'gravatar.com' in self.avatar: + return True + def has_avatar(self): + if not self.avatar or len(self.avatar) == 1: + return False + return True + def let_yeahnotifs(self): + return self.profile('let_yeahnotifs') + def limit_remaining(self): + limit = self.profile('limit_post') + # If False is returned, no post limit is assumed. + if limit == 0: + return False + today_min = timezone.datetime.combine(timezone.datetime.today(), time.min) + today_max = timezone.datetime.combine(timezone.datetime.today(), time.max) + # recent_posts = + # Posts made by the user today + posts made by the IP today + + # same thing except with comments + recent_posts = Post.real.filter(Q(creator=self.id, created__range=(today_min, today_max)) | Q(creator__addr=self.addr, created__range=(today_min, today_max))).count() + Comment.real.filter(Q(creator=self.id, created__range=(today_min, today_max)) | Q(creator__addr=self.addr, created__range=(today_min, today_max))).count() + + # Posts remaining + return int(limit) - recent_posts + + def get_class(self): + first = { + 1: 'tester', + 2: 'administrator', + 3: 'moderator', + 4: 'openverse', + 5: 'donator', + 6: 'tester', + 7: 'urapp', + 8: 'developer', + 9: 'pipinstalldjango', + 10: 'staff', + 11: 'kanna', + 12: 'verified', + 13: 'artcon', + 14: 'contest', + 15: 'gamecom', + 16: 'mp', + }.get(self.role, '') + second = { + 1: "Bot", + 2: "Administrator", + 3: "Moderator", + 4: "No", + 5: "Donator", + 6: "Tester", + 7: "Cool Dude", + 8: "Wii U still best console.", + 9: "Rixy Installed Django!", + 10: "Staff", + 11: "GAY DOGWATER ETC", + 12: "THE STUPIDEST ROLE IN THE WORLD", + 13: "A D R I A N", + 14: "Contest Winner", + 15: "Game Contest Winner", + 16: "Cedar Inc.", + }.get(self.role, '') + if first: + first = 'official ' + first + return [first, second] + def is_me(self, request): + if request.user.is_authenticated: + return (self == request.user) + else: + return False + def has_freedom(self): + return self.profile('let_freedom') + # This is the coolest one + def online_status(self, force=False): + # Okay so this returns True if the user's online, 2 if they're AFK, False if they're offline and None if they hide it + if self.hide_online: + return None + if (timezone.now() - timedelta(seconds=80)) > self.last_login: + return False + elif (timezone.now() - timedelta(seconds=50)) > self.last_login: # + return 2 + else: + return True + def do_avatar(self, feeling=0): + if self.has_mh and self.avatar: + feeling = { + 0: 'normal', + 1: 'happy', + 2: 'like', + 3: 'surprised', + 4: 'frustrated', + 5: 'puzzled', + }.get(feeling, "normal") + 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' + elif self.avatar == 's': + return settings.STATIC_URL + 'img/anonymous-mii-sad.png' + else: + return self.avatar - def num_yeahs(self): - return self.yeah_set.filter(by=self).count() - def num_posts(self): - return self.post_set.filter(creator=self).count() - def num_comments(self): - return self.comment_set.filter().count() - def num_following(self): - return self.follow_source.filter().count() - def num_followers(self): - return self.follow_target.filter().count() - def num_friends(self): - return self.friend_source.filter().count() + self.friend_target.filter().count() - def can_follow(self, user): - #if UserBlock.find_block(self, user): - # return False - return True - def can_view(self, user): - #if UserBlock.find_block(self, user, full=True): - # return False - return True - def is_following(self, me): - if not me.is_authenticated: - return False - if self == me: - return True - #if hasattr(self, 'has_follow'): - # return self.has_follow - return self.follow_target.filter(source=me).count() > 0 - def follow(self, source): - if self.is_following(source) or source == self: - return False - if not self.can_follow(source): - return False - # Todo: put a follow limit here - return self.follow_target.create(source=source, target=self) - def unfollow(self, source): - if not self.is_following(source) or source == self: - return False - return self.follow_target.filter(source=source, target=self).delete() - def can_block(self, source): - if self.can_manage(): - return False - #if source.profile('moyenne'): - # return False - return True - # BLOCK this user from SOURCE - def make_block(self, source, full=False): - if find_block(source, self): - return False - return UserBlock.objects.create(source=source, target=self, full=full) - def get_posts(self, limit=50, offset=0, request=None): - if request.user.is_authenticated: - has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id) - posts = self.post_set.select_related('community').select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).filter().order_by('-created')[offset:offset + limit] - else: - posts = self.post_set.select_related('community').select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True)).filter().order_by('-created').exclude(community__require_auth=True)[offset:offset + limit] - if request: - for post in posts: - post.setup(request) - post.recent_comment = post.recent_comment() - return posts - def get_comments(self, limit=50, offset=0, request=None): - if request.user.is_authenticated: - has_yeah = Yeah.objects.filter(comment=OuterRef('id'), by=request.user.id) - posts = self.comment_set.select_related('original_post').select_related('creator').select_related('original_post__creator').annotate(num_yeahs=Count('yeah', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).filter().order_by('-created')[offset:offset + limit] - else: - posts = self.comment_set.select_related('original_post').select_related('original_post__creator').select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True)).filter().order_by('-created').exclude(original_post__community__require_auth=True)[offset:offset + limit] - if request: - for post in posts: - post.setup(request) - return posts - def get_yeahed(self, type=0, limit=20, offset=0): - # 0 - post, 1 - comment, 2 - any - if type == 2: - yeahs = self.yeah_set.select_related('post').select_related('comment').select_related('comment__original_post').select_related('comment__original_post__creator').annotate(num_yeahs_post=Count('post__yeah', distinct=True), num_yeahs_comment=Count('comment__yeah', distinct=True), num_comments=Count('post__comment', distinct=True)).filter().order_by('-created')[offset:offset + limit] - else: - yeahs = self.yeah_set.select_related('post').select_related('post__creator').annotate(num_yeahs_post=Count('post__yeah', distinct=True), num_comments=Count('post__comment', distinct=True)).filter(type=type, post__is_rm=False).order_by('-created')[offset:offset + limit] - for thing in yeahs: - if thing.post: - thing.post.num_yeahs = thing.num_yeahs_post - thing.post.num_comments = thing.num_comments - elif thing.comment: - thing.comment.num_yeahs = thing.num_yeahs_comment - return yeahs - def get_following(self, limit=50, offset=0, request=None): - return self.follow_source.select_related('target').filter().order_by('-created')[offset:offset + limit] - def get_followers(self, limit=50, offset=0, request=None): - return self.follow_target.select_related('source').filter().order_by('-created')[offset:offset + limit] - def notification_count(self): - return self.notification_to.filter(read=False).count() - def notification_read(self): - return self.notification_to.filter(read=False).update(read=True) - def get_notifications(self): - return self.notification_to.select_related('context_post').select_related('context_comment').select_related('source').filter().order_by('-latest')[0:64] - def notifications_clean(self): - """ Broken - gives OperationError on MySQL - notif_get = self.notification_to.all().values_list('id', flat=True) - if notif_get.count() > 64: - self.notification_to.filter().exclude(id__in=notif_get).delete() - """ - - # Admin can-manage - def can_manage(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 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 - query1 = other.fr_source.filter(target=self, finished=False).exists() - if query1: - return 1 - query2 = self.fr_source.filter(target=other, finished=False).exists() - if query2: - return 2 - query3 = Friendship.find_friendship(self, other) - if query3: - return 3 - return 0 - def get_fr(self, other): - return FriendRequest.objects.filter(Q(source=self) & Q(target=other) | Q(target=self) & Q(source=other)).exclude(finished=True) - def get_frs_target(self): - return FriendRequest.objects.filter(target=self, finished=False).order_by('-created') - def get_frs_notif(self): - return FriendRequest.objects.filter(target=self, finished=False, read=False).count() - def reject_fr(self, target): - fr = self.get_fr(target) - if fr: - try: - fr.first().finish() - except: - pass - def send_fr(self, source, body=None): - if not self.get_fr(source): - return FriendRequest.objects.create(source=source, target=self, body=body) - def accept_fr(self, target): - fr = self.get_fr(target) - if fr: - try: - fr.first().finish() - except: - pass - return Friendship.objects.create(source=self, target=target) - def cancel_fr(self, target): - fr = target.get_fr(self) - if fr: - try: - fr.first().finish() - except: - pass - def read_fr(self): - return self.get_frs_target().update(read=True) - def delete_friend(self, target): - fr = Friendship.find_friendship(self, target) - if fr: - fr.conversation().all_read() - fr.delete() - def get_activity(self, limit=20, offset=0, distinct=False, friends_only=False, request=None): - #Todo: make distinct work; combine friends and following, but then get posts from them - friends = Friendship.get_friendships(self, 0) - friend_ids = [] - for friend in friends: - friend_ids.append(friend.other(self)) - follows = self.follow_source.filter().values_list('target', flat=True) - if not friends_only: - friend_ids.append(self.id) - for thing in follows: - friend_ids.append(thing) - if request.user.is_authenticated: - has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id) - if distinct: - posts = Post.objects.select_related('creator').select_related('community').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).annotate(max_created=Max('creator__post__created')).filter(created=F('max_created')).filter(creator__in=friend_ids).order_by('-created')[offset:offset + limit] - else: - posts = Post.objects.select_related('creator').select_related('community').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).filter(creator__in=friend_ids).order_by('-created')[offset:offset + limit] - if request: - for post in posts: - post.setup(request) - post.recent_comment = post.recent_comment() - return posts - def community_favorites(self, all=False): - if not all: - favorites = self.communityfavorite_set.order_by('-created').filter(community__is_rm=False)[:8] - else: - favorites = self.communityfavorite_set.order_by('-created').filter(community__is_rm=False) - communities = [] - for fav in favorites: - communities.append(fav.community) - del(favorites) - return communities - def wake(self, addr=None): - if addr and not addr == self.addr: - self.addr = addr - return self.save(update_fields=['addr', 'last_login']) - return self.save(update_fields=['last_login']) + def num_yeahs(self): + return self.yeah_set.filter(by=self).count() + def num_posts(self): + return self.post_set.filter(creator=self).count() + def num_comments(self): + return self.comment_set.filter().count() + def num_following(self): + return self.follow_source.filter().count() + def num_followers(self): + return self.follow_target.filter().count() + def num_friends(self): + return self.friend_source.filter().count() + self.friend_target.filter().count() + def can_follow(self, user): + if UserBlock.find_block(self, user): + return False + return True + def can_view(self, user): + block = UserBlock.find_block(self, user) + if block and block.target == user: + return False + return True + def is_following(self, me): + if not me.is_authenticated: + return False + if self == me: + return True + #if hasattr(self, 'has_follow'): + # return self.has_follow + return self.follow_target.filter(source=me).count() > 0 + def follow(self, source): + if self.is_following(source) or source == self: + return False + if not self.can_follow(source): + return False + # Todo: put a follow limit here + return self.follow_target.create(source=source, target=self) + def unfollow(self, source): + if not self.is_following(source) or source == self: + return False + return self.follow_target.filter(source=source, target=self).delete() + def can_block(self, source): + if self.can_manage() or self.level > source.level: + return False + #if source.profile('moyenne'): + # return False + return True + # BLOCK this user from SOURCE + def make_block(self, source): + # trailing + block = UserBlock.find_block(self, source) + if block and block.source == source: + return block.delete() + fs = Friendship.find_friendship(self, source) + if fs: + fs.delete() + # delete any mutual follows + Follow.objects.filter(Q(source=self) & Q(target=source) | Q(target=self) & Q(source=source)).delete() + return UserBlock.objects.create(source=source, target=self) + def get_posts(self, limit, offset, request, offset_time): + if request.user.is_authenticated: + has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id) + posts = self.post_set.select_related('community').select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).filter(created__lte=offset_time).order_by('-created')[offset:offset + limit] + else: + posts = self.post_set.select_related('community').select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True)).filter(created__lte=offset_time).order_by('-created').exclude(community__require_auth=True)[offset:offset + limit] + if request: + for post in posts: + post.setup(request) + post.recent_comment = post.recent_comment() + return posts + def get_comments(self, limit, offset, request, offset_time): + if request.user.is_authenticated: + has_yeah = Yeah.objects.filter(comment=OuterRef('id'), by=request.user.id) + posts = self.comment_set.select_related('original_post').select_related('creator').select_related('original_post__creator').annotate(num_yeahs=Count('yeah', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).filter(created__lte=offset_time).order_by('-created')[offset:offset + limit] + else: + posts = self.comment_set.select_related('original_post').select_related('original_post__creator').select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True)).filter(created__lte=offset_time).order_by('-created').exclude(original_post__community__require_auth=True)[offset:offset + limit] + if request: + for post in posts: + post.setup(request) + return posts + def get_yeahed(self, type=0, limit=20, offset=0): + # 0 - post, 1 - comment, 2 - any + if type == 2: + yeahs = self.yeah_set.select_related('post').select_related('comment').select_related('comment__original_post').select_related('comment__original_post__creator').annotate(num_yeahs_post=Count('post__yeah', distinct=True), num_yeahs_comment=Count('comment__yeah', distinct=True), num_comments=Count('post__comment', distinct=True)).filter().order_by('-created')[offset:offset + limit] + else: + yeahs = self.yeah_set.select_related('post').select_related('post__creator').annotate(num_yeahs_post=Count('post__yeah', distinct=True), num_comments=Count('post__comment', distinct=True)).filter(type=type, post__is_rm=False).order_by('-created')[offset:offset + limit] + for thing in yeahs: + if thing.post: + thing.post.num_yeahs = thing.num_yeahs_post + thing.post.num_comments = thing.num_comments + elif thing.comment: + thing.comment.num_yeahs = thing.num_yeahs_comment + return yeahs + def get_following(self, limit=50, offset=0, request=None): + return self.follow_source.select_related('target').filter().order_by('-created')[offset:offset + limit] + def get_followers(self, limit=50, offset=0, request=None): + return self.follow_target.select_related('source').filter().order_by('-created')[offset:offset + limit] + def notification_count(self): + return self.notification_to.filter(read=False).count() + def notification_read(self): + return self.notification_to.filter(read=False).update(read=True) + def get_notifications(self): + return self.notification_to.select_related('context_post').select_related('context_comment').select_related('source').filter().order_by('-latest')[0:64] + def notifications_clean(self): + """ Broken - gives OperationError on MySQL + notif_get = self.notification_to.all().values_list('id', flat=True) + if notif_get.count() > 64: + self.notification_to.filter().exclude(id__in=notif_get).delete() + """ + + # Admin can-manage + def can_manage(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 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 + query1 = other.fr_source.filter(target=self, finished=False).exists() + if query1: + return 1 + query2 = self.fr_source.filter(target=other, finished=False).exists() + if query2: + return 2 + query3 = Friendship.find_friendship(self, other) + if query3: + return 3 + return 0 + def get_fr(self, other): + return FriendRequest.objects.filter(Q(source=self) & Q(target=other) | Q(target=self) & Q(source=other)).exclude(finished=True) + def get_frs_target(self): + return FriendRequest.objects.filter(target=self, finished=False).order_by('-created') + def get_frs_notif(self): + return FriendRequest.objects.filter(target=self, finished=False, read=False).count() + def reject_fr(self, target): + fr = self.get_fr(target) + if fr: + try: + fr.first().finish() + except: + pass + def send_fr(self, source, body=None): + if not self.get_fr(source): + return FriendRequest.objects.create(source=source, target=self, body=body) + def accept_fr(self, target): + fr = self.get_fr(target) + if fr: + try: + fr.first().finish() + except: + pass + return Friendship.objects.create(source=self, target=target) + def cancel_fr(self, target): + fr = target.get_fr(self) + if fr: + try: + fr.first().finish() + except: + pass + def read_fr(self): + return self.get_frs_target().update(read=True) + def delete_friend(self, target): + fr = Friendship.find_friendship(self, target) + if fr: + fr.conversation().all_read() + fr.delete() + def get_activity(self, limit=20, offset=0, distinct=False, friends_only=False, request=None): + #Todo: make distinct work; combine friends and following, but then get posts from them + friends = Friendship.get_friendships(self, 0) + friend_ids = [] + for friend in friends: + friend_ids.append(friend.other(self)) + follows = self.follow_source.filter().values_list('target', flat=True) + if not friends_only: + friend_ids.append(self.id) + for thing in follows: + friend_ids.append(thing) + if request.user.is_authenticated: + has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id) + if distinct: + posts = Post.objects.select_related('creator').select_related('community').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).annotate(max_created=Max('creator__post__created')).filter(created=F('max_created')).filter(creator__in=friend_ids).order_by('-created')[offset:offset + limit] + else: + posts = Post.objects.select_related('creator').select_related('community').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).filter(creator__in=friend_ids).order_by('-created')[offset:offset + limit] + if request: + for post in posts: + post.setup(request) + post.recent_comment = post.recent_comment() + return posts + def community_favorites(self, all=False): + if not all: + favorites = self.communityfavorite_set.order_by('-created').filter(community__is_rm=False)[:8] + else: + favorites = self.communityfavorite_set.order_by('-created').filter(community__is_rm=False) + communities = [] + for fav in favorites: + communities.append(fav.community) + del(favorites) + return communities + def wake(self, addr=None): + if addr and not addr == self.addr: + self.addr = addr + return self.save(update_fields=['addr', 'last_login']) + return self.save(update_fields=['last_login']) - def has_postspam(self, body, screenshot=None, drawing=None): - latest_post = self.post_set.filter().order_by('-created')[:1] - if not latest_post: - return False - latest_post = latest_post.first() - if drawing and latest_post.drawing: - if drawing == latest_post.drawing: - return True - elif latest_post.screenshot and screenshot and not drawing: - if latest_post.screenshot == screenshot and latest_post.body == body: - return True - elif latest_post.body and body and not latest_post.screenshot and not latest_post.drawing: - if latest_post.body == body: - return True - return False - - def get_latest_msg(self, me): - conversation = Conversation.objects.filter(Q(source=self) & Q(target=me) | Q(target=self) & Q(source=me)).order_by('-created')[:1].first() - if not conversation: - return False - return conversation.latest_message(me) - def conversations(self): - return Conversation.objects.filter(Q(source=self) | Q(target=self)).order_by('-created') - def msg_count(self): - # Gets messages with conversations I am involved in, then looks for those unread and not by me, gets count and returns it - messages = Message.objects.filter(Q(conversation__source=self.id) | Q(conversation__target=self.id)).filter(read=False).exclude(creator=self.id).count() - return messages - def password_reset_email(self, request): - htmlmsg = render_to_string('closedverse_main/help/email.html', { - 'menulogo': request.build_absolute_uri(settings.STATIC_URL + 'img/menu-logo.png'), - 'contact': 'something', - 'link': request.build_absolute_uri(reverse('main:forgot-passwd')) + "?token=" + base64.urlsafe_b64encode(bytes(self.password, 'utf-8')).decode(), - }) - subj = 'Closedverse password reset for "{0}"'.format(self.username) - return send_mail( - subject='Reset password', - html_message=htmlmsg, - message=htmlmsg, - from_email="noreply@" + settings.YOUR_DOMAIN, - recipient_list=[self.email], - fail_silently=False) - def find_related(self): - return User.objects.filter(id__in=LoginAttempt.objects.filter(Q(addr=self.addr), Q(user=self.id)).values_list('user', flat=True)).exclude(id=self.id) - @staticmethod - def search(query='', limit=50, offset=0, request=None): - return User.objects.filter(Q(username__icontains=query) | Q(nickname__icontains=query)).order_by('-created')[offset:offset + limit] - @staticmethod - def email_in_use(addr, request=None): - if not addr: - return False - if request: - return User.objects.filter(email__iexact=addr).exclude(id=request.user.id).exists() - else: - return User.objects.filter(email__iexact=addr).exists() - @staticmethod - def nnid_in_use(id, request=None): - if not id: - return False - if request: - nnid_real = id.lower().replace('-', '').replace('.', '') - return Profile.objects.filter(origin_id__iexact=nnid_real).exclude(user__id=request.user.id).exists() - else: - return Profile.objects.filter(origin_id=id).exists() - @staticmethod - def get_from_passwd(passwd): - try: - user = User.objects.get(password=base64.urlsafe_b64decode(passwd).decode()) - # Too lazy to make except cases - except: - return False - return user - + def has_postspam(self, body, screenshot=None, drawing=None): + latest_post = self.post_set.filter().order_by('-created')[:1] + if not latest_post: + return False + latest_post = latest_post.first() + if drawing and latest_post.drawing: + if drawing == latest_post.drawing: + return True + elif latest_post.screenshot and screenshot and not drawing: + if latest_post.screenshot == screenshot and latest_post.body == body: + return True + elif latest_post.body and body and not latest_post.screenshot and not latest_post.drawing: + if latest_post.body == body: + return True + return False + + def get_latest_msg(self, me): + conversation = Conversation.objects.filter(Q(source=self) & Q(target=me) | Q(target=self) & Q(source=me)).order_by('-created')[:1].first() + if not conversation: + return False + return conversation.latest_message(me) + def conversations(self): + return Conversation.objects.filter(Q(source=self) | Q(target=self)).order_by('-created') + def msg_count(self): + # Gets messages with conversations I am involved in, then looks for those unread and not by me, gets count and returns it + messages = Message.objects.filter(Q(conversation__source=self.id) | Q(conversation__target=self.id)).filter(read=False).exclude(creator=self.id).count() + return messages + def password_reset_email(self, request): + htmlmsg = render_to_string('closedverse_main/help/email.html', { + 'menulogo': request.build_absolute_uri(settings.STATIC_URL + 'img/menu-logo.png'), + 'contact': 'something', + 'link': request.build_absolute_uri(reverse('main:forgot-passwd')) + "?token=" + base64.urlsafe_b64encode(bytes(self.password, 'utf-8')).decode(), + }) + subj = 'Closedverse password reset for "{0}"'.format(self.username) + return send_mail( + subject='Reset password', + html_message=htmlmsg, + message=htmlmsg, + from_email="noreply@" + settings.YOUR_DOMAIN, + recipient_list=[self.email], + fail_silently=False) + def find_related(self): + return User.objects.filter(id__in=LoginAttempt.objects.filter(Q(addr=self.addr), Q(user=self.id)).values_list('user', flat=True)).exclude(id=self.id) + @staticmethod + def search(query='', limit=50, offset=0, request=None): + return User.objects.filter(Q(username__icontains=query) | Q(nickname__icontains=query)).order_by('-created')[offset:offset + limit] + @staticmethod + def email_in_use(addr, request=None): + if not addr: + return False + if request: + return User.objects.filter(email__iexact=addr).exclude(id=request.user.id).exists() + else: + return User.objects.filter(email__iexact=addr).exists() + @staticmethod + def nnid_in_use(id, request=None): + if not id: + return False + if request: + nnid_real = id.lower().replace('-', '').replace('.', '') + return Profile.objects.filter(origin_id__iexact=nnid_real).exclude(user__id=request.user.id).exists() + else: + return Profile.objects.filter(origin_id=id).exists() + @staticmethod + def get_from_passwd(passwd): + try: + user = User.objects.get(password=base64.urlsafe_b64decode(passwd).decode()) + # Too lazy to make except cases + 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) + 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) - id = models.AutoField(primary_key=True) - name = models.CharField(max_length=255) - description = models.TextField(blank=True, default='') - ico = models.ImageField(upload_to='icon/%y/%m/%d/', max_length=100, blank=True, null=True) - banner = models.ImageField(upload_to='banner/%y/%m/%d/', max_length=100, blank=True, null=True) - # Type: 0 - general, 1 - game, 2 - special - type = models.SmallIntegerField(default=0, choices=((0, 'General'), (1, 'Game'), (2, 'Special'), (3, 'User Community'), (4, 'Hide'))) - # Platform - 0/none, 1/3DS, 2/Wii U, 3/both - platform = models.SmallIntegerField(default=0, choices=((0, 'none'), (1, '3ds'), (2, 'wii u'), (3, 'switch'), (4, 'both'), (5, 'PC'), (6, 'Xbox'), (7, 'Playstation'))) - tags = models.CharField(blank=True, null=True, max_length=255, choices=(('announcements', 'main announcement community'), ('changelog', 'main changelog'), ('activity', 'Activity Feed posting community'), ('general', 'General Discussion Community'))) - created = models.DateTimeField(auto_now_add=True) - updated = models.DateTimeField(auto_now=True) - is_rm = models.BooleanField(default=False) - is_feature = models.BooleanField(default=False) - require_auth = models.BooleanField(default=False) - rank_needed_to_post = models.IntegerField(default=0) - creator = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + name = models.CharField(max_length=255) + description = models.TextField(blank=True, default='') + ico = models.ImageField(upload_to='icon/%y/%m/%d/', max_length=100, blank=True, null=True) + banner = models.ImageField(upload_to='banner/%y/%m/%d/', max_length=100, blank=True, null=True) + # Type: 0 - general, 1 - game, 2 - special + type = models.SmallIntegerField(default=0, choices=((0, 'General'), (1, 'Game'), (2, 'Special'), (3, 'User Community'), (4, 'Hide'))) + # Platform - 0/none, 1/3DS, 2/Wii U, 3/both + platform = models.SmallIntegerField(default=0, choices=((0, 'none'), (1, '3ds'), (2, 'wii u'), (3, 'switch'), (4, 'both'), (5, 'PC'), (6, 'Xbox'), (7, 'Playstation'))) + tags = models.CharField(blank=True, null=True, max_length=255, choices=(('announcements', 'main announcement community'), ('changelog', 'main changelog'), ('activity', 'Activity Feed posting community'), ('general', 'General Discussion Community'))) + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + is_rm = models.BooleanField(default=False) + is_feature = models.BooleanField(default=False) + require_auth = models.BooleanField(default=False) + rank_needed_to_post = models.IntegerField(default=0) + creator = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) - objects = PostManager() - real = models.Manager() - def popularity(self): - popularity = Post.objects.filter(community=self).count() - return popularity - def __str__(self): - return self.name - def icon(self): - if self.ico and hasattr(self.ico, 'url'): - return self.ico.url - else: - return settings.STATIC_URL + "img/title-icon-default.png" - def type_txt(self): - if self.type == 1: - return { - 0: "", - 1: "3DS Game", - 2: "Wii U Game", - 3: "Switch Game", - 4: "Wii U / 3DS Game", - 5: 'PC Game', - 6: 'Xbox Game', - 7: 'Playstation Game', - }.get(self.platform) - else: - return { - 0: "General community", - 1: "Game community", - 2: "Special community", - 3: "User owned community", - }.get(self.type) - def type_platform(self): - thing = { - 0: "", - 1: "3ds", - 2: "wiiu", - 3: "switch", - 4: "wiiu-3ds", - 5: 'pc', - 6: 'xbox', - 7: 'ps', - }.get(self.platform) - if thing == "": - return None - return "img/platform-tag-" + thing + ".png" - def is_activity(self): - return self.tags == 'activity' - def clickable(self): - return not self.is_activity() and not self.type == 4 - def get_posts(self, limit=50, offset=0, request=None, favorite=False): - if request.user.is_authenticated: - has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id) - posts = Post.objects.select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).filter(community_id=self.id).order_by('-created')[offset:offset + limit] - else: - posts = Post.objects.select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True)).filter(community_id=self.id).order_by('-created').exclude(community__require_auth=True)[offset:offset + limit] - if request: - for post in posts: - post.setup(request) - post.recent_comment = post.recent_comment() - return posts - def post_perm(self, request): - if request.user.level >= self.rank_needed_to_post: - return True - elif request.user.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: - return True - else: - return False - def can_edit_community(self, request): - # yanderedev moment - 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: - return False - - if request.user == self.creator: - return True - elif request.user.level >= settings.level_needed_to_man_communities or request.user.staff == True: - return True - else: - return False - def has_favorite(self, request): - if request.user.communityfavorite_set.filter(community=self).exists(): - return True - return False - def favorite_add(self, request): - if not self.has_favorite(request): - return request.user.communityfavorite_set.create(community=self) - def favorite_rm(self, request): - if self.has_favorite(request): - return request.user.communityfavorite_set.filter(community=self).delete() + objects = PostManager() + real = models.Manager() + def popularity(self): + popularity = Post.objects.filter(community=self).count() + return popularity + def __str__(self): + return self.name + def icon(self): + if self.ico and hasattr(self.ico, 'url'): + return self.ico.url + else: + return settings.STATIC_URL + "img/title-icon-default.png" + def type_txt(self): + if self.type == 1: + return { + 0: "", + 1: "3DS Game", + 2: "Wii U Game", + 3: "Switch Game", + 4: "Wii U / 3DS Game", + 5: 'PC Game', + 6: 'Xbox Game', + 7: 'Playstation Game', + }.get(self.platform) + else: + return { + 0: "General community", + 1: "Game community", + 2: "Special community", + 3: "User owned community", + }.get(self.type) + def type_platform(self): + thing = { + 0: "", + 1: "3ds", + 2: "wiiu", + 3: "switch", + 4: "wiiu-3ds", + 5: 'pc', + 6: 'xbox', + 7: 'ps', + }.get(self.platform) + if not thing: + return None + return "img/platform-tag-" + thing + ".png" + def is_activity(self): + return self.tags == 'activity' + def clickable(self): + return not self.is_activity() and not self.type == 4 + # have yet to see a usage of this without all of these params so sure, offset_time is default + #def get_posts(self, limit=50, offset=0, request=None, favorite=False): + def get_posts(self, limit, offset, request, offset_time): + if request.user.is_authenticated: + # get users who blocked you + blocked_me = request.user.block_target.filter().values('source') + + has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id) + posts = Post.objects.select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True) + ).exclude(creator__id__in=Subquery(blocked_me)).filter(community_id=self.id, created__lte=offset_time).order_by('-created')[offset:offset + limit] + else: + posts = Post.objects.select_related('creator').annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True)).filter(community_id=self.id, created__lte=offset_time).order_by('-created').exclude(community__require_auth=True)[offset:offset + limit] + if request: + for post in posts: + post.setup(request) + # THE TRUE METHOD + if request.user.is_authenticated: + post.user_is_blocked = UserBlock.find_block(post.creator, request.user) + #print(str(post) + ' to ' + str(self.creator) + ':' + str(post.user_is_blocked)) + post.recent_comment = post.recent_comment() + return posts + def post_perm(self, request): + if request.user.level >= self.rank_needed_to_post: + return True + elif request.user.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: + return True + else: + return False + def can_edit_community(self, request): + # yanderedev moment + 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: + return False + + if request.user == self.creator: + return True + elif request.user.level >= settings.level_needed_to_man_communities or request.user.staff == True: + return True + else: + return False + def has_favorite(self, request): + if request.user.communityfavorite_set.filter(community=self).exists(): + return True + return False + def favorite_add(self, request): + if not self.has_favorite(request): + return request.user.communityfavorite_set.create(community=self) + def favorite_rm(self, request): + if self.has_favorite(request): + return request.user.communityfavorite_set.filter(community=self).delete() - def setup(self, request): - if request.user.is_authenticated: - self.post_perm = self.post_perm(request) - self.has_favorite = self.has_favorite(request) + def setup(self, request): + if request.user.is_authenticated: + self.post_perm = self.post_perm(request) + self.has_favorite = self.has_favorite(request) - def create_post(self, request): - if not self.post_perm(request): - return 4 - limit = request.user.limit_remaining() - if not limit is False and not limit > 0: - return 8 - del(limit) - if Post.real.filter(Q(creator=request.user) | Q(creator__addr=request.user.addr), created__gt=timezone.now() - timedelta(seconds=10)).exists(): - return 3 - if request.POST.get('url'): - try: - URLValidator()(value=request.POST['url']) - except ValidationError: - return 5 - if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')): - return 6 - 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 - upload = None - drawing = None - if request.FILES.get('screen'): - upload = util.image_upload(request.FILES['screen'], True) - if upload == 1: - return 2 - if request.POST.get('_post_type') == 'painting': - if not request.POST.get('painting'): - return 2 - drawing = util.image_upload(request.POST['painting'], False, True) - if drawing == 1: - return 2 - # Check for spam using our OWN ALGO!!!!!!!!! - if request.user.has_postspam(request.POST.get('body'), upload, drawing): - return 7 - new_post = self.post_set.create(body=request.POST.get('body'), creator=request.user, community=self, feeling=int(request.POST.get('feeling_id', 0)), spoils=bool(request.POST.get('is_spoiler')), screenshot=upload, drawing=drawing, url=request.POST.get('url')) - new_post.is_mine = True - return new_post + def create_post(self, request): + if not self.post_perm(request): + return 4 + limit = request.user.limit_remaining() + if not limit is False and not limit > 0: + return 8 + del(limit) + #if Post.real.filter(Q(creator=request.user) | Q(creator__addr=request.user.addr), created__gt=timezone.now() - timedelta(seconds=10)).exists(): + # return 3 + if request.POST.get('url'): + try: + URLValidator()(value=request.POST['url']) + except ValidationError: + return 5 + if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')): + return 6 + 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 + upload = None + drawing = None + body = request.POST.get('body') + if request.FILES.get('screen'): + upload = util.image_upload(request.FILES['screen'], True) + if upload == 1: + return 2 + if request.POST.get('_post_type') == 'painting': + if not request.POST.get('painting'): + return 2 + drawing = util.image_upload(request.POST['painting'], False, True) + if drawing == 1: + return 2 + # 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']: + if keyword in body.lower(): + return 9 + if body.isspace() and not drawing: + return 10 + new_post = self.post_set.create(body=body, creator=request.user, community=self, feeling=int(request.POST.get('feeling_id', 0)), spoils=bool(request.POST.get('is_spoiler')), screenshot=upload, drawing=drawing, url=request.POST.get('url')) + new_post.is_mine = True + return new_post - def search(query='', limit=50, offset=0, request=None): - return Community.objects.filter(Q(name__icontains=query) | Q(description__contains=query)).exclude(type=4).order_by('-created')[offset:offset + limit] + def search(query='', limit=50, offset=0, request=None): + return Community.objects.filter(Q(name__icontains=query) | Q(description__contains=query)).exclude(type=4).order_by('-created')[offset:offset + limit] - def get_all(type=0, offset=0, limit=12): - return Community.objects.filter(type=type).order_by('-created')[offset:offset + limit] - - class Meta: - verbose_name_plural = "communities" + def get_all(type=0, offset=0, limit=12): + return Community.objects.filter(type=type).order_by('-created')[offset:offset + limit] + + class Meta: + verbose_name_plural = "communities" -# Links between communities for "related" communities -class CommunityClink(models.Model): - # root/also order doesn't matter, time does though - root = models.ForeignKey(Community, related_name='one', on_delete=models.CASCADE) - also = models.ForeignKey(Community, related_name='two', on_delete=models.CASCADE) - created = models.DateTimeField(auto_now_add=True) - # type: related (f) / sub (t) - kind = models.BooleanField(default=False) - - objects = CommunityFavoriteManager() - -# Do this, or not class CommunityFavorite(models.Model): - id = models.AutoField(primary_key=True) - by = models.ForeignKey(User, on_delete=models.CASCADE) - community = models.ForeignKey(Community, on_delete=models.CASCADE) - created = models.DateTimeField(auto_now_add=True) - - def __str__(self): - return "Community favorite by " + str(self.by) + " for " + str(self.community) + id = models.AutoField(primary_key=True) + by = models.ForeignKey(User, on_delete=models.CASCADE) + community = models.ForeignKey(Community, on_delete=models.CASCADE) + created = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return "Community favorite by " + str(self.by) + " for " + str(self.community) class Post(models.Model): - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - community = models.ForeignKey(Community, null=True, on_delete=models.CASCADE) - feeling = models.SmallIntegerField(default=0, choices=feelings) - body = models.TextField(null=True) - drawing = models.CharField(max_length=200, null=True, blank=True) - screenshot = models.CharField(max_length=1200, null=True, blank=True, default='') - url = models.URLField(max_length=1200, null=True, blank=True, default='') - spoils = models.BooleanField(default=False) - disable_yeah = models.BooleanField(default=False) - created = models.DateTimeField(auto_now_add=True) - edited = models.DateTimeField(auto_now=True) - befores = models.TextField(null=True, blank=True) - poll = models.ForeignKey('Poll', null=True, blank=True, on_delete=models.CASCADE) - has_edit = models.BooleanField(default=False) - is_rm = models.BooleanField(default=False) - status = models.SmallIntegerField(default=0, choices=post_status) - creator = models.ForeignKey(User, on_delete=models.CASCADE) + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + community = models.ForeignKey(Community, null=True, on_delete=models.CASCADE) + feeling = models.SmallIntegerField(default=0, choices=feelings) + body = models.TextField(null=True) + drawing = models.CharField(max_length=200, null=True, blank=True) + screenshot = models.CharField(max_length=1200, null=True, blank=True, default='') + url = models.URLField(max_length=1200, null=True, blank=True, default='') + spoils = models.BooleanField(default=False) + disable_yeah = models.BooleanField(default=False) + created = models.DateTimeField(auto_now_add=True) + edited = models.DateTimeField(auto_now=True) + befores = models.TextField(null=True, blank=True) + poll = models.ForeignKey('Poll', null=True, blank=True, on_delete=models.CASCADE) + has_edit = models.BooleanField(default=False) + is_rm = models.BooleanField(default=False) + status = models.SmallIntegerField(default=0, choices=post_status) + creator = models.ForeignKey(User, on_delete=models.CASCADE) - objects = PostManager() - real = models.Manager() + objects = PostManager() + real = models.Manager() - def __str__(self): - return self.body[:250] - def is_reply(self): - return False - def trun(self): - if self.is_rm: - return 'deleted' - if self.drawing: - return 'drawing' - else: - return self.body - def yt_vid(self): - try: - thing = re.search('(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})', self.url).group(6) - 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 - return False - def is_mine(self, user): - if user.is_authenticated: - return (self.creator == user) - else: - return False - #def yeah_notification(self, request): - # ???? What is this - #Notification.give_notification - def number_yeahs(self): - if hasattr(self, 'num_yeahs'): - return self.num_yeahs - return self.yeah_set.filter(post=self).count() - def has_yeah(self, request): - if request.user.is_authenticated: - if hasattr(self, 'yeah_given'): - return self.yeah_given - else: - return self.yeah_set.filter(post=self, by=request.user).exists() - else: - return False - def can_yeah(self, request): - if request.user.is_authenticated: - #if UserBlock.find_block(self.creator, request.user): - # return False - return True - else: - return False - def can_rm(self, request): - if self.creator.has_authority(request.user): - 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 - if self.has_yeah(request): - return True - if not self.can_yeah(request): - return False - return self.yeah_set.create(by=request.user, post=self) - def remove_yeah(self, request): - if not self.has_yeah(request): - return True - return self.yeah_set.filter(post=self, by=request.user).delete() - def number_comments(self): - # Number of comments cannot be accurate due to comment deleting - #if hasattr(self, 'num_comments'): - # return self.num_comments - return self.comment_set.filter(original_post=self).count() - def get_yeahs(self, request): - return Yeah.objects.filter(type=0, post=self).order_by('-created')[0:30] - def can_comment(self, request): - # TODO: Make this so that if a post's comments exceeds 100, make the user able to close the comments section - if self.number_comments() > 500: - return False - #if UserBlock.find_block(self.creator, request.user): - # return False - return True - def get_comments(self, request=None, limit=0, offset=0): - if request.user.is_authenticated: - has_yeah = Yeah.objects.filter(comment=OuterRef('id'), by=request.user.id) - if limit: - comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah'), yeah_given=Exists(has_yeah)).filter(original_post=self).order_by('created')[offset:offset + limit] - elif offset: - comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah'), yeah_given=Exists(has_yeah)).filter(original_post=self).order_by('created')[offset:] - else: - comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah'), yeah_given=Exists(has_yeah)).filter(original_post=self).order_by('created') - else: - if limit: - comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah')).filter(original_post=self).order_by('created').exclude(original_post__community__require_auth=True)[offset:offset + limit] - elif offset: - comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah')).filter(original_post=self).order_by('created').exclude(original_post__community__require_auth=True)[offset:] - else: - comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah')).filter(original_post=self).order_by('created').exclude(original_post__community__require_auth=True) - if request: - for post in comments: - post.setup(request) - return comments - def create_comment(self, request): - if not self.can_comment(request): - return False - limit = request.user.limit_remaining() - if not limit is False and not limit > 0: - return 8 - del(limit) - if self.is_mine(request.user) and Comment.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=2)).exists(): - return 3 - elif not self.is_mine(request.user) and Comment.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=10)).exists(): - return 3 - if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')): - return 6 - 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 - upload = None - drawing = None - if request.FILES.get('screen'): - upload = util.image_upload(request.FILES['screen'], True) - if upload == 1: - return 2 - if request.POST.get('_post_type') == 'painting': - if not request.POST.get('painting'): - return 2 - drawing = util.image_upload(request.POST['painting'], False, True) - if drawing == 1: - return 2 - new_post = self.comment_set.create(body=request.POST.get('body'), creator=request.user, community=self.community, original_post=self, feeling=int(request.POST.get('feeling_id', 0)), spoils=bool(request.POST.get('is_spoiler')), drawing=drawing, screenshot=upload) - new_post.is_mine = True - return new_post - def recent_comment(self): - if self.number_comments() < 1: - return False - comments = self.comment_set.filter(spoils=False).exclude(creator=self.creator).order_by('-created')[:1] - return comments.first() - def change(self, request): - if not self.is_mine(request.user) or self.has_edit: - return 1 - if len(request.POST['body']) > 2200 or len(request.POST['body']) < 1: - return 1 - if not self.befores: - befores_json = [] - else: - befores_json = json.loads(self.befores) - befores_json.append(self.body) - self.befores = json.dumps(befores_json) - self.body = request.POST['body'] - self.spoils = request.POST.get('is_spoiler', False) - self.feeling = request.POST.get('feeling_id', 0) - if not timezone.now() < self.created + timezone.timedelta(minutes=2): - self.has_edit = True - return self.save() - def is_favorite(self, user): - profile = user.profile() - if profile.favorite == self: - return True - else: - return False - def favorite(self, user): - if not self.is_mine(user): - return False - profile = user.profile() - if profile.favorite == self: - return False - profile.favorite = self - return profile.save() - def unfavorite(self, user): - if not self.is_mine(user): - return False - profile = user.profile() - if profile.favorite == self: - profile.favorite = None - return profile.save() - def rm(self, request): - if request and not self.is_mine(request.user) and not self.can_rm(request): - return False - if self.is_favorite(self.creator): - self.unfavorite(self.creator) - self.is_rm = True - if self.is_mine(request.user): - self.status = 1 - else: - self.status = 2 - AuditLog.objects.create(type=0, post=self, user=self.creator, by=request.user) - if self.screenshot: - util.image_rm(self.screenshot) - self.screenshot = None - if self.drawing: - util.image_rm(self.drawing) - self.drawing = None - self.save() - def setup(self, request): - self.has_yeah = self.has_yeah(request) - self.can_yeah = self.can_yeah(request) - self.is_mine = self.is_mine(request.user) - - - - def max_yeahs(): - try: - max_yeahs_post = Post.objects.annotate(num_yeahs=Count('yeah')).aggregate(max_yeahs=Max('num_yeahs'))['max_yeahs'] - except: - return None - the_post = Post.objects.annotate(num_yeahs=Count('yeah')).filter(num_yeahs=max_yeahs_post).order_by('-created') - return the_post.first() - + def __str__(self): + return self.body[:250] + def is_reply(self): + return False + def trun(self): + if self.is_rm: + return 'deleted' + if self.drawing: + return 'drawing' + else: + return self.body + def yt_vid(self): + try: + thing = re.search('(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})', self.url).group(6) + 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 + return False + def is_mine(self, user): + if user.is_authenticated: + return (self.creator == user) + else: + return False + #def yeah_notification(self, request): + # ???? What is this + #Notification.give_notification + def number_yeahs(self): + if hasattr(self, 'num_yeahs'): + return self.num_yeahs + return self.yeah_set.filter(post=self).count() + def has_yeah(self, request): + if request.user.is_authenticated: + if hasattr(self, 'yeah_given'): + return self.yeah_given + else: + return self.yeah_set.filter(post=self, by=request.user).exists() + else: + return False + def can_yeah(self, request): + if not request.user.is_authenticated or not request.user.is_active(): + return False + # why did cedar-django do this? god knows + #return True + if self.is_mine(request.user) or UserBlock.find_block(self.creator, request.user): + return False + return True + def can_rm(self, request): + if self.creator.has_authority(request.user): + 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 + if self.has_yeah(request): + return True + if not self.can_yeah(request): + return False + return self.yeah_set.create(by=request.user, post=self) + def remove_yeah(self, request): + if not self.has_yeah(request): + return True + return self.yeah_set.filter(post=self, by=request.user).delete() + def number_comments(self): + # Number of comments cannot be accurate due to comment deleting + #if hasattr(self, 'num_comments'): + # return self.num_comments + return self.comment_set.filter(original_post=self).count() + def get_yeahs(self, request): + return Yeah.objects.filter(type=0, post=self).order_by('-created')[0:30] + def can_comment(self, request): + # TODO: Make this so that if a post's comments exceeds 100, make the user able to close the comments section + if self.number_comments() > 500: + return False + if UserBlock.find_block(self.creator, request.user): + return False + return True + def get_comments(self, request=None, limit=0, offset=0): + if request.user.is_authenticated: + blocked_me = request.user.block_target.filter().values('source') + + has_yeah = Yeah.objects.filter(comment=OuterRef('id'), by=request.user.id) + comments_pre = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah'), yeah_given=Exists(has_yeah) + ).exclude(creator__id__in=Subquery(blocked_me)).filter(original_post=self).order_by('created') + comments = comments_pre + if limit: + comments = comments_pre[offset:offset + limit] + elif offset: + comments = comments_pre[offset:] + else: + comments_pre = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah')).filter(original_post=self).order_by('created').exclude(original_post__community__require_auth=True) + comments = comments_pre + if limit: + comments = comments_pre[offset:offset + limit] + elif offset: + comments = comments_pre[offset:] + if request: + for post in comments: + post.setup(request) + return comments + def create_comment(self, request): + if not self.can_comment(request): + return False + limit = request.user.limit_remaining() + if not limit is False and not limit > 0: + return 8 + del(limit) + if self.is_mine(request.user) and Comment.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=2)).exists(): + return 3 + elif not self.is_mine(request.user) and Comment.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=10)).exists(): + return 3 + if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')): + return 6 + 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 + upload = None + drawing = None + if request.FILES.get('screen'): + upload = util.image_upload(request.FILES['screen'], True) + if upload == 1: + return 2 + if request.POST.get('_post_type') == 'painting': + if not request.POST.get('painting'): + return 2 + drawing = util.image_upload(request.POST['painting'], False, True) + if drawing == 1: + return 2 + new_post = self.comment_set.create(body=request.POST.get('body'), creator=request.user, community=self.community, original_post=self, feeling=int(request.POST.get('feeling_id', 0)), spoils=bool(request.POST.get('is_spoiler')), drawing=drawing, screenshot=upload) + new_post.is_mine = True + return new_post + def recent_comment(self): + if self.number_comments() < 1: + return False + comments = self.comment_set.filter(spoils=False).exclude(creator=self.creator).order_by('-created')[:1] + return comments.first() + def change(self, request): + if not self.is_mine(request.user) or self.has_edit: + return 1 + if len(request.POST['body']) > 2200 or len(request.POST['body']) < 1: + return 1 + if not self.befores: + befores_json = [] + else: + befores_json = json.loads(self.befores) + befores_json.append(self.body) + self.befores = json.dumps(befores_json) + self.body = request.POST['body'] + self.spoils = request.POST.get('is_spoiler', False) + self.feeling = request.POST.get('feeling_id', 0) + if not timezone.now() < self.created + timezone.timedelta(minutes=2): + self.has_edit = True + return self.save() + def is_favorite(self, user): + profile = user.profile() + if profile.favorite == self: + return True + else: + return False + def favorite(self, user): + if not self.is_mine(user): + return False + profile = user.profile() + if profile.favorite == self: + return False + profile.favorite = self + return profile.save() + def unfavorite(self, user): + if not self.is_mine(user): + return False + profile = user.profile() + if profile.favorite == self: + profile.favorite = None + return profile.save() + def rm(self, request): + if request and not self.is_mine(request.user) and not self.can_rm(request): + return False + if self.is_favorite(self.creator): + self.unfavorite(self.creator) + self.is_rm = True + if self.is_mine(request.user): + self.status = 1 + else: + self.status = 2 + AuditLog.objects.create(type=0, post=self, user=self.creator, by=request.user) + if self.screenshot: + util.image_rm(self.screenshot) + self.screenshot = None + if self.drawing: + util.image_rm(self.drawing) + self.drawing = None + self.save() + def setup(self, request): + self.has_yeah = self.has_yeah(request) + self.can_yeah = self.can_yeah(request) + self.is_mine = self.is_mine(request.user) + def max_yeahs(): + try: + max_yeahs_post = Post.objects.annotate(num_yeahs=Count('yeah')).aggregate(max_yeahs=Max('num_yeahs'))['max_yeahs'] + except: + return None + the_post = Post.objects.annotate(num_yeahs=Count('yeah')).filter(num_yeahs=max_yeahs_post).order_by('-created') + return the_post.first() + class Comment(models.Model): - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - original_post = models.ForeignKey(Post, on_delete=models.CASCADE) - community = models.ForeignKey(Community, on_delete=models.CASCADE) - feeling = models.SmallIntegerField(default=0, choices=feelings) - body = models.TextField(null=True) - screenshot = models.CharField(max_length=1200, null=True, blank=True, default='') - drawing = models.CharField(max_length=200, null=True, blank=True) - spoils = models.BooleanField(default=False) - created = models.DateTimeField(auto_now_add=True) - edited = models.DateTimeField(auto_now=True) - befores = models.TextField(null=True, blank=True) - has_edit = models.BooleanField(default=False) - is_rm = models.BooleanField(default=False) - status = models.SmallIntegerField(default=0, choices=post_status) - creator = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + original_post = models.ForeignKey(Post, on_delete=models.CASCADE) + community = models.ForeignKey(Community, on_delete=models.CASCADE) + feeling = models.SmallIntegerField(default=0, choices=feelings) + body = models.TextField(null=True) + screenshot = models.CharField(max_length=1200, null=True, blank=True, default='') + drawing = models.CharField(max_length=200, null=True, blank=True) + spoils = models.BooleanField(default=False) + created = models.DateTimeField(auto_now_add=True) + edited = models.DateTimeField(auto_now=True) + befores = models.TextField(null=True, blank=True) + has_edit = models.BooleanField(default=False) + is_rm = models.BooleanField(default=False) + status = models.SmallIntegerField(default=0, choices=post_status) + creator = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) - objects = PostManager() - real = models.Manager() + objects = PostManager() + real = models.Manager() - def __str__(self): - return self.body[:250] - def is_reply(self): - return True - def trun(self): - if self.is_rm: - return 'deleted' - if self.drawing: - return '(drawing)' - else: - return self.body - def is_mine(self, user): - if user.is_authenticated: - return (self.creator == user) - else: - return False - def number_yeahs(self): - if hasattr(self, 'num_yeahs'): - return self.num_yeahs - return self.yeah_set.filter(comment=self, type=1).count() - def has_yeah(self, request): - if request.user.is_authenticated: - if hasattr(self, 'yeah_given'): - return self.yeah_given - else: - return self.yeah_set.filter(comment=self, type=1, by=request.user).exists() - else: - return False - def can_yeah(self, request): - if request.user.is_authenticated: - return True - else: - return False - #if UserBlock.find_block(self.creator, request.user): - # return False - def can_rm(self, request): - if self.creator.has_authority(request.user): - return False - #if self.original_post.is_mine(request.user): - # return True - 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 - if self.has_yeah(request): - return True - if not self.can_yeah(request): - return False - return self.yeah_set.create(by=request.user, type=1, comment=self) - def remove_yeah(self, request): - if not self.has_yeah(request): - return True - return self.yeah_set.filter(comment=self, type=1, by=request.user).delete() - def get_yeahs(self, request): - return Yeah.objects.filter(type=1, comment=self).order_by('-created')[0:30] - def owner_post(self): - return (self.creator == self.original_post.creator) - def change(self, request): - if not self.is_mine(request.user) or self.has_edit: - return 1 - if len(request.POST['body']) > 2200 or len(request.POST['body']) < 1: - return 1 - if not self.befores: - befores_json = [] - else: - befores_json = json.loads(self.befores) - befores_json.append(self.body) - self.befores = json.dumps(befores_json) - self.body = request.POST['body'] - self.spoils = request.POST.get('is_spoiler', False) - self.feeling = request.POST.get('feeling_id', 0) - if not timezone.now() < self.created + timezone.timedelta(minutes=2): - self.has_edit = True - return self.save() - def rm(self, request): - if request and not self.is_mine(request.user) and not self.can_rm(request): - return False - self.is_rm = True - if self.is_mine(request.user): - self.status = 1 - else: - self.status = 2 - AuditLog.objects.create(type=1, comment=self, user=self.creator, by=request.user) - if self.screenshot: - util.image_rm(self.screenshot) - self.screenshot = None - if self.drawing: - util.image_rm(self.drawing) - self.drawing = None - self.save() - def setup(self, request): - self.has_yeah = self.has_yeah(request) - self.can_yeah = self.can_yeah(request) - self.is_mine = self.is_mine(request.user) + def __str__(self): + return self.body[:250] + def is_reply(self): + return True + def trun(self): + if self.is_rm: + return 'deleted' + if self.drawing: + return '(drawing)' + else: + return self.body + def is_mine(self, user): + if user.is_authenticated: + return (self.creator == user) + else: + return False + def number_yeahs(self): + if hasattr(self, 'num_yeahs'): + return self.num_yeahs + return self.yeah_set.filter(comment=self, type=1).count() + def has_yeah(self, request): + if request.user.is_authenticated: + if hasattr(self, 'yeah_given'): + return self.yeah_given + else: + return self.yeah_set.filter(comment=self, type=1, by=request.user).exists() + else: + return False + def can_yeah(self, request): + 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 + return True + def can_rm(self, request): + # if the creator of the post does not have authority, you can remove it. + if not self.creator.has_authority(request.user): + return True + return False + 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 + if self.has_yeah(request): + return True + if not self.can_yeah(request): + return False + return self.yeah_set.create(by=request.user, type=1, comment=self) + def remove_yeah(self, request): + if not self.has_yeah(request): + return True + return self.yeah_set.filter(comment=self, type=1, by=request.user).delete() + def get_yeahs(self, request): + return Yeah.objects.filter(type=1, comment=self).order_by('-created')[0:30] + def owner_post(self): + return (self.creator == self.original_post.creator) + def change(self, request): + if not self.is_mine(request.user) or self.has_edit: + return 1 + if len(request.POST['body']) > 2200 or len(request.POST['body']) < 1: + return 1 + if not self.befores: + befores_json = [] + else: + befores_json = json.loads(self.befores) + befores_json.append(self.body) + self.befores = json.dumps(befores_json) + self.body = request.POST['body'] + self.spoils = request.POST.get('is_spoiler', False) + self.feeling = request.POST.get('feeling_id', 0) + if not timezone.now() < self.created + timezone.timedelta(minutes=2): + self.has_edit = True + return self.save() + def rm(self, request): + if request and not self.is_mine(request.user) and not self.can_rm(request): + return False + self.is_rm = True + if self.is_mine(request.user): + self.status = 1 + else: + self.status = 2 + AuditLog.objects.create(type=1, comment=self, user=self.creator, by=request.user) + if self.screenshot: + util.image_rm(self.screenshot) + self.screenshot = None + if self.drawing: + util.image_rm(self.drawing) + self.drawing = None + self.save() + def setup(self, request): + self.has_yeah = self.has_yeah(request) + self.can_yeah = self.can_yeah(request) + self.is_mine = self.is_mine(request.user) class Yeah(models.Model): - # Todo: make this a plain int at some point - id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True) - by = models.ForeignKey(User, on_delete=models.CASCADE) - type = models.SmallIntegerField(default=0, choices=((0, 'post'), (1, 'comment'), )) - post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE) - # kldsjfldsfsdfd - #spam = models.BooleanField(default=False) - comment = models.ForeignKey(Comment, null=True, blank=True, on_delete=models.CASCADE) - created = models.DateTimeField(auto_now_add=True) + # Todo: make this a plain int at some point + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True) + by = models.ForeignKey(User, on_delete=models.CASCADE) + type = models.SmallIntegerField(default=0, choices=((0, 'post'), (1, 'comment'), )) + post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE) + # kldsjfldsfsdfd + #spam = models.BooleanField(default=False) + comment = models.ForeignKey(Comment, null=True, blank=True, on_delete=models.CASCADE) + created = models.DateTimeField(auto_now_add=True) - def __str__(self): - a = "from " + self.by.username + " to " - if self.post: - a += str(self.post.unique_id) - elif self.comment: - a += str(self.comment.unique_id) - return a + def __str__(self): + a = "from " + self.by.username + " to " + if self.post: + a += str(self.post.unique_id) + elif self.comment: + a += str(self.comment.unique_id) + return a class Profile(models.Model): - is_new = models.BooleanField(default=True) - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - user = models.ForeignKey(User, on_delete=models.CASCADE) + is_new = models.BooleanField(default=True) + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + user = models.ForeignKey(User, on_delete=models.CASCADE) - origin_id = models.CharField(max_length=16, null=True, blank=True) - origin_info = models.CharField(max_length=255, null=True, blank=True) + origin_id = models.CharField(max_length=16, null=True, blank=True) + origin_info = models.CharField(max_length=255, null=True, blank=True) - comment = models.TextField(blank=True, default='') - country = models.CharField(max_length=120, blank=True, default='') - whatareyou = models.CharField(max_length=120, blank=True, default='') - #birthday = models.DateField(null=True, blank=True) - id_visibility = models.SmallIntegerField(default=0, choices=visibility) - - pronoun_is = models.IntegerField(default=0, choices=( - (0, "I don't know"), (1, "He/him"), (2, "She/her"), (3, "He/she"), (4, "It"), (5, "They/Them") - )) + comment = models.TextField(blank=True, default='') + country = models.CharField(max_length=120, blank=True, default='') + whatareyou = models.CharField(max_length=120, blank=True, default='') + #birthday = models.DateField(null=True, blank=True) + id_visibility = models.SmallIntegerField(default=0, choices=visibility) + + pronoun_is = models.IntegerField(default=0, choices=( + (0, "I don't know"), (1, "He/him"), (2, "She/her"), (3, "He/she"), (4, "It"), (5, "They/Them") + )) - let_friendrequest = models.SmallIntegerField(default=0, choices=visibility) - yeahs_visibility = models.SmallIntegerField(default=0, choices=visibility) - comments_visibility = models.SmallIntegerField(default=2, choices=visibility) - #relationship_visibility = models.SmallIntegerField(default=0, choices=visibility) - weblink = models.CharField(max_length=1200, blank=True, default='') - #gameskill = models.SmallIntegerField(default=0) - external = models.CharField(max_length=255, blank=True, default='') - favorite = models.ForeignKey(Post, blank=True, null=True, on_delete=models.SET_NULL) + let_friendrequest = models.SmallIntegerField(default=0, choices=visibility) + yeahs_visibility = models.SmallIntegerField(default=0, choices=visibility) + comments_visibility = models.SmallIntegerField(default=2, choices=visibility) + #relationship_visibility = models.SmallIntegerField(default=0, choices=visibility) + weblink = models.CharField(max_length=1200, blank=True, default='') + #gameskill = models.SmallIntegerField(default=0) + external = models.CharField(max_length=255, blank=True, default='') + favorite = models.ForeignKey(Post, blank=True, null=True, on_delete=models.SET_NULL) - let_yeahnotifs = models.BooleanField(default=True) - let_freedom = models.BooleanField(default=True) - # Todo: When you see this, implement it; make it a bool that determines whether the user should be able to edit their avatar; if this is true and - #let_avatar = models.BooleanField(default=False) - adopted = models.ForeignKey(User, null=True, blank=True, related_name='children', on_delete=models.CASCADE) - # Post limit, 0 for none - limit_post = models.SmallIntegerField(default=0) - # If this is true, the user can't change their avatar or nickname - cannot_edit = models.BooleanField(default=False) - email_login = models.SmallIntegerField(default=1, choices=((0, 'Do not allow'), (1, 'Okay'), (2, 'Only allow'))) - - def __str__(self): - return "profile " + str(self.unique_id) + " for " + self.user.username - def origin_id_public(self, user=None): - if user == self.user: - return self.origin_id - if self.id_visibility == 2: - return 1 - elif self.id_visibility == 1: - if not user.is_authenticated or not Friendship.find_friendship(self.user, user): - return 1 - return self.origin_id - elif not self.origin_id: - return None - return self.origin_id - def yeahs_visible(self, user=None): - if user == self.user: - return True - if self.yeahs_visibility == 2: - return False - elif self.yeahs_visibility == 1: - if not user.is_authenticated or not Friendship.find_friendship(self.user, user): - return False - return True - return True - def comments_visible(self, user=None): - if user == self.user: - return True - if self.comments_visibility == 2: - return False - elif self.comments_visibility == 1: - if not user.is_authenticated or not Friendship.find_friendship(self.user, user): - return False - return True - return True - def can_friend(self, user=None): - if self.let_friendrequest == 2: - return False - #if user.is_authenticated and UserBlock.find_block(self.user, user): - # return False - elif self.let_friendrequest == 1: - if not user.is_following(self.user): - return False - return True - return True - def got_fullurl(self): - if self.weblink: - try: - URLValidator()(value=self.weblink) - except ValidationError: - return False - return True - return False - def setup(self, request): - self.origin_id_public = self.origin_id_public(request.user) - self.yeahs_visible = self.yeahs_visible(request.user) - self.comments_visible = self.comments_visible(request.user) + let_yeahnotifs = models.BooleanField(default=True) + let_freedom = models.BooleanField(default=True) + # Todo: When you see this, implement it; make it a bool that determines whether the user should be able to edit their avatar; if this is true and + #let_avatar = models.BooleanField(default=False) + # Post limit, 0 for none + limit_post = models.SmallIntegerField(default=0) + # If this is true, the user can't change their avatar or nickname + cannot_edit = models.BooleanField(default=False) + email_login = models.SmallIntegerField(default=1, choices=((0, 'Do not allow'), (1, 'Okay'), (2, 'Only allow'))) + + def __str__(self): + return "profile " + str(self.unique_id) + " for " + self.user.username + def origin_id_public(self, user=None): + if user == self.user: + return self.origin_id + if self.id_visibility == 2: + return 1 + elif self.id_visibility == 1: + if not user.is_authenticated or not Friendship.find_friendship(self.user, user): + return 1 + return self.origin_id + elif not self.origin_id: + return None + return self.origin_id + def yeahs_visible(self, user=None): + if user == self.user: + return True + if self.yeahs_visibility == 2: + return False + elif self.yeahs_visibility == 1: + if not user.is_authenticated or not Friendship.find_friendship(self.user, user): + return False + return True + return True + def comments_visible(self, user=None): + if user == self.user: + return True + if self.comments_visibility == 2: + return False + elif self.comments_visibility == 1: + if not user.is_authenticated or not Friendship.find_friendship(self.user, user): + return False + return True + return True + def can_friend(self, user=None): + if self.let_friendrequest == 2: + return False + #if user.is_authenticated and UserBlock.find_block(self.user, user): + # return False + elif self.let_friendrequest == 1: + if not user.is_following(self.user): + return False + return True + return True + def got_fullurl(self): + if self.weblink: + try: + URLValidator()(value=self.weblink) + except ValidationError: + return False + return True + return False + def setup(self, request): + self.origin_id_public = self.origin_id_public(request.user) + self.yeahs_visible = self.yeahs_visible(request.user) + self.comments_visible = self.comments_visible(request.user) + if request.user.is_authenticated and request.user != self.user: + # these aren't on the user object so arguably these should not be here + # but at this point i do not care just throw away this whole codebase please + self.can_follow = self.user.can_follow(request.user) + self.can_block = self.user.can_block(request.user) + # we will use hasattr + if UserBlock.objects.filter(source=request.user, target=self.user).exists(): + self.is_blocked = True class Follow(models.Model): - # Todo: remove this - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - source = models.ForeignKey(User, related_name='follow_source', on_delete=models.CASCADE) - target = models.ForeignKey(User, related_name='follow_target', on_delete=models.CASCADE) - created = models.DateTimeField(auto_now_add=True) - - def __str__(self): - return "follow: from " + self.source.username + " to " + self.target.username + # Todo: remove this + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + source = models.ForeignKey(User, related_name='follow_source', on_delete=models.CASCADE) + target = models.ForeignKey(User, related_name='follow_target', on_delete=models.CASCADE) + created = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return "follow: from " + self.source.username + " to " + self.target.username class Notification(models.Model): - # Todo: make this a plain int at some point - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - - to = models.ForeignKey(User, related_name='notification_to', on_delete=models.CASCADE) - source = models.ForeignKey(User, related_name='notification_sender', on_delete=models.CASCADE) - read = models.BooleanField(default=False) - type = models.SmallIntegerField(choices=( - (0, 'Yeah on post'), - (1, 'Yeah on comment'), - (2, 'Comment on my post'), - (3, 'Comment on others\' post'), - (4, 'Follow to me'), - )) - merges = models.TextField(blank=True, default='') - context_post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE) - context_comment = models.ForeignKey(Comment, null=True, blank=True, on_delete=models.CASCADE) - - created = models.DateTimeField(auto_now_add=True) - latest = models.DateTimeField(auto_now=True) + # Todo: make this a plain int at some point + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + + to = models.ForeignKey(User, related_name='notification_to', on_delete=models.CASCADE) + source = models.ForeignKey(User, related_name='notification_sender', on_delete=models.CASCADE) + read = models.BooleanField(default=False) + type = models.SmallIntegerField(choices=( + (0, 'Yeah on post'), + (1, 'Yeah on comment'), + (2, 'Comment on my post'), + (3, 'Comment on others\' post'), + (4, 'Follow to me'), + (5, 'New Announcement'), + )) + merges = models.TextField(blank=True, default='') + context_post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE) + context_comment = models.ForeignKey(Comment, null=True, blank=True, on_delete=models.CASCADE) + + created = models.DateTimeField(auto_now_add=True) + latest = models.DateTimeField(auto_now=True) - def __str__(self): - return "Notification from " + str(self.source) + " to " + str(self.to) + " with type \"" + self.get_type_display() + "\"" - def url(self): - what_type = { - 0: 'main:post-view', - 1: 'main:comment-view', - 2: 'main:post-view', - 3: 'main:post-view', - 4: 'main:user-followers', - }.get(self.type) - if self.type == 0 or self.type == 2 or self.type == 3: - what_id = self.context_post_id - elif self.type == 1: - what_id = self.context_comment_id - elif self.type == 4: - what_id = self.to.username - return reverse(what_type, args=[what_id]) - def merge(self, user): - self.latest = timezone.now() - self.read = False - if not self.merges: - u = [] - else: - u = json.loads(self.merges) - u.append(user.id) - self.merges = json.dumps(u) - self.save() - #return self.merged.create(source=user, to=self.to, type=self.type, context_post=self.context_post, context_comment=self.context_comment) - def set_unread(self): - self.read = False - self.latest = timezone.now() - return self.save() - def all_users(self): - if not self.merges: - u = [] - else: - u = organ(json.loads(self.merges)) - arr = [] - arr.append(self.source) - for user in u: - # Todo: Clean this up and make this block better - if not u in arr: - try: - arr.append(User.objects.get(id=user)) - except: - pass - del(u) - return arr - """ - arr = [] - arr.append(self.source) - merges = self.merged.filter().order_by('created') - for merge in merges: - arr.append(merge.source) - return arr - """ - def setup(self, user): - # Only have is_following if the type is a follow; save SQL queries - if self.type == 4: - self.source.is_following = self.source.is_following(user) - else: - self.source.is_following = False - # In the future, please put giving notifications for classes into their respective classes (right now they're in views) - @staticmethod - def give_notification(user, type, to, post=None, comment=None): - # Just keeping this simple for now, might want to make it better later - # If the user sent a notification to this user at least 5 seconds ago, return False - # Or if user is to - # Or if yeah notifications are off and this is a yeah notification - user_is_self_unk = (not type == 3 and user == to) - is_notification_too_fast = (user.notification_sender.filter(created__gt=timezone.now() - timedelta(seconds=5), type=type).exclude(type=4) and not type == 3) - user_no_yeahnotif = (not to.let_yeahnotifs() and (type == 0 or type == 1)) - if user_is_self_unk or is_notification_too_fast or user_no_yeahnotif: - return False - # Search for my own notifiaction. If it exists, set it as unread. - merge_own = user.notification_sender.filter(created__gt=timezone.now() - timedelta(hours=8), to=to, type=type, context_post=post, context_comment=comment) - if merge_own: - # If it's merged, don't unread that one, but unread what it's merging. - return merge_own.first().set_unread() - # Search for a notification already there so we can merge with it if it exists - merge_s = Notification.objects.filter(created__gt=timezone.now() - timedelta(hours=8), to=to, type=type, context_post=post, context_comment=comment) - # If it exists, merge with it. Else, create a new notification. - if merge_s: - return merge_s.first().merge(user) - else: - return user.notification_sender.create(source=user, type=type, to=to, context_post=post, context_comment=comment) + def __str__(self): + return "Notification from " + str(self.source) + " to " + str(self.to) + " with type \"" + self.get_type_display() + "\"" + def url(self): + what_type = { + 0: 'main:post-view', + 1: 'main:comment-view', + 2: 'main:post-view', + 3: 'main:post-view', + 4: 'main:user-followers', + }.get(self.type) + if self.type == 0 or self.type == 2 or self.type == 3: + what_id = self.context_post_id + elif self.type == 1: + what_id = self.context_comment_id + elif self.type == 4: + what_id = self.to.username + return reverse(what_type, args=[what_id]) + def merge(self, user): + self.latest = timezone.now() + self.read = False + if not self.merges: + u = [] + else: + u = json.loads(self.merges) + u.append(user.id) + self.merges = json.dumps(u) + self.save() + #return self.merged.create(source=user, to=self.to, type=self.type, context_post=self.context_post, context_comment=self.context_comment) + def set_unread(self): + self.read = False + self.latest = timezone.now() + return self.save() + def all_users(self): + if not self.merges: + u = [] + else: + u = organ(json.loads(self.merges)) + arr = [] + arr.append(self.source) + for user in u: + # Todo: Clean this up and make this block better + if not u in arr: + try: + arr.append(User.objects.get(id=user)) + except: + pass + del(u) + return arr + """ + arr = [] + arr.append(self.source) + merges = self.merged.filter().order_by('created') + for merge in merges: + arr.append(merge.source) + return arr + """ + def setup(self, user): + # Only have is_following if the type is a follow; save SQL queries + if self.type == 4: + self.source.is_following = self.source.is_following(user) + else: + self.source.is_following = False + # In the future, please put giving notifications for classes into their respective classes (right now they're in views) + @staticmethod + def give_notification(user, type, to, post=None, comment=None): + # Just keeping this simple for now, might want to make it better later + # If the user sent a notification to this user at least 5 seconds ago, return False + # Or if user is to + # Or if yeah notifications are off and this is a yeah notification + user_is_self_unk = (not type == 3 and user == to) + is_notification_too_fast = (user.notification_sender.filter(created__gt=timezone.now() - timedelta(seconds=5), type=type).exclude(type=4) and not type == 3) + user_no_yeahnotif = (not to.let_yeahnotifs() and (type == 0 or type == 1)) + if user_is_self_unk or is_notification_too_fast or user_no_yeahnotif: + return False + # Search for my own notifiaction. If it exists, set it as unread. + merge_own = user.notification_sender.filter(created__gt=timezone.now() - timedelta(hours=8), to=to, type=type, context_post=post, context_comment=comment) + if merge_own: + # If it's merged, don't unread that one, but unread what it's merging. + return merge_own.first().set_unread() + # Search for a notification already there so we can merge with it if it exists + merge_s = Notification.objects.filter(created__gt=timezone.now() - timedelta(hours=8), to=to, type=type, context_post=post, context_comment=comment) + # If it exists, merge with it. Else, create a new notification. + if merge_s: + return merge_s.first().merge(user) + else: + return user.notification_sender.create(source=user, type=type, to=to, context_post=post, context_comment=comment) class Complaint(models.Model): - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - creator = models.ForeignKey(User, on_delete=models.CASCADE) - type = models.SmallIntegerField(choices=( - (0, 'Bug report'), - (1, 'Suggestion'), - (2, 'Want'), - )) - body = models.TextField(blank=True, default='') - sex = models.SmallIntegerField(null=True, choices=((0, 'girl'), (1, 'privileged one'), (2, '(none)'), - )) - created = models.DateTimeField(auto_now_add=True) - - def __str__(self): - return "\"" + str(self.body) + "\" from " + str(self.creator) + " as a " + str(self.get_sex_display()) - def has_past_sent(user): - return user.complaint_set.filter(created__gt=timezone.now() - timedelta(minutes=5)).exists() + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + creator = models.ForeignKey(User, on_delete=models.CASCADE) + type = models.SmallIntegerField(choices=( + (0, 'Bug report'), + (1, 'Suggestion'), + (2, 'Want'), + )) + body = models.TextField(blank=True, default='') + sex = models.SmallIntegerField(null=True, choices=((0, 'girl'), (1, 'privileged one'), (2, '(none)'), + )) + created = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return "\"" + str(self.body) + "\" from " + str(self.creator) + " as a " + str(self.get_sex_display()) + def has_past_sent(user): + return user.complaint_set.filter(created__gt=timezone.now() - timedelta(minutes=5)).exists() class FriendRequest(models.Model): - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - source = models.ForeignKey(User, related_name='fr_source', on_delete=models.CASCADE) - target = models.ForeignKey(User, related_name='fr_target', on_delete=models.CASCADE) - body = models.TextField(blank=True, null=True, default='') - read = models.BooleanField(default=False) - finished = models.BooleanField(default=False) - created = models.DateTimeField(auto_now_add=True) - - def __str__(self): - return "friend request ("+str(self.finished)+"): from " + str(self.source) + " to " + str(self.target) - def finish(self): - self.finished = True - self.save() + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + source = models.ForeignKey(User, related_name='fr_source', on_delete=models.CASCADE) + target = models.ForeignKey(User, related_name='fr_target', on_delete=models.CASCADE) + body = models.TextField(blank=True, null=True, default='') + read = models.BooleanField(default=False) + finished = models.BooleanField(default=False) + created = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return "friend request ("+str(self.finished)+"): from " + str(self.source) + " to " + str(self.target) + def finish(self): + self.finished = True + self.save() class Friendship(models.Model): - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - source = models.ForeignKey(User, related_name='friend_source', on_delete=models.CASCADE) - target = models.ForeignKey(User, related_name='friend_target', on_delete=models.CASCADE) - created = models.DateTimeField(auto_now_add=True) - latest = models.DateTimeField(auto_now=True) - - def __str__(self): - return "friendship with " + str(self.source) + " and " + str(self.target) - def update(self): - return self.save(update_fields=['latest']) - def other(self, user): - if self.source == user: - return self.target - return self.source - def conversation(self): - conv = Conversation.objects.filter(Q(source=self.source) & Q(target=self.target) | Q(target=self.source) & Q(source=self.target)).order_by('-created') - if not conv: - return Conversation.objects.create(source=self.source, target=self.target) - return conv.first() - @staticmethod - def get_friendships(user, limit=50, offset=0, latest=False, online_only=False): - if not limit: - return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-created') - if latest: - if online_only: - delta = timezone.now() - timedelta(seconds=48) - awman = [] - for friend in Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-latest')[offset:offset + limit]: - if friend.other(user).last_login > delta: - awman.append(friend) - return awman + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + source = models.ForeignKey(User, related_name='friend_source', on_delete=models.CASCADE) + target = models.ForeignKey(User, related_name='friend_target', on_delete=models.CASCADE) + created = models.DateTimeField(auto_now_add=True) + latest = models.DateTimeField(auto_now=True) + + def __str__(self): + return "friendship with " + str(self.source) + " and " + str(self.target) + def update(self): + return self.save(update_fields=['latest']) + def other(self, user): + if self.source == user: + return self.target + return self.source + def conversation(self): + conv = Conversation.objects.filter(Q(source=self.source) & Q(target=self.target) | Q(target=self.source) & Q(source=self.target)).order_by('-created') + if not conv: + return Conversation.objects.create(source=self.source, target=self.target) + return conv.first() + @staticmethod + def get_friendships(user, limit=50, offset=0, latest=False, online_only=False): + if not limit: + return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-created') + if latest: + if online_only: + delta = timezone.now() - timedelta(seconds=48) + awman = [] + for friend in Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-latest')[offset:offset + limit]: + if friend.other(user).last_login > delta: + awman.append(friend) + return awman # Fix all of this at some point -# return Friendship.objects.filter( +# return Friendship.objects.filter( #source=When(source__ne=user, source__last_login__gt=delta), #target=When(target__ne=user, target__last_login__gt=delta) #).order_by('-latest')[offset:offset + limit] - else: - return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-latest')[offset:offset + limit] - else: - return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-created')[offset:offset + limit] - @staticmethod - def find_friendship(first, second): - return Friendship.objects.filter(Q(source=first) & Q(target=second) | Q(target=first) & Q(source=second)).order_by('-created').first() - @staticmethod - def get_friendships_message(user, limit=20, offset=0, online_only=False): - friends_list = Friendship.get_friendships(user, limit, offset, True, online_only) - friends = [] - for friend in friends_list: - friends.append(friend.other(user)) - del(friends_list) - for friend in friends: - friend.get_latest_msg = friend.get_latest_msg(user) - return friends + else: + return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-latest')[offset:offset + limit] + else: + return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-created')[offset:offset + limit] + @staticmethod + def find_friendship(first, second): + return Friendship.objects.filter(Q(source=first) & Q(target=second) | Q(target=first) & Q(source=second)).order_by('-created').first() + @staticmethod + def get_friendships_message(user, limit=20, offset=0, online_only=False): + friends_list = Friendship.get_friendships(user, limit, offset, True, online_only) + friends = [] + for friend in friends_list: + friends.append(friend.other(user)) + del(friends_list) + for friend in friends: + friend.get_latest_msg = friend.get_latest_msg(user) + return friends class Conversation(models.Model): - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - source = models.ForeignKey(User, related_name='conv_source', on_delete=models.CASCADE) - target = models.ForeignKey(User, related_name='conv_target', on_delete=models.CASCADE) - created = models.DateTimeField(auto_now_add=True) - - def __str__(self): - return "conversation with " + str(self.source) + " and " + str(self.target) - def latest_message(self, user): - msgs = Message.objects.filter(conversation=self).order_by('-created')[:5] - if not msgs: - return False - message = msgs.first() - message.mine = message.mine(user) - return message - def unread(self, user): - return self.message_set.filter(read=False).exclude(creator=user).order_by('-created') - def set_read(self, user): - return self.unread(user).update(read=True) - def all_read(self): - return self.message_set.filter().update(read=True) - def messages(self, request, limit=50, offset=0): - msgs = self.message_set.filter().order_by('-created')[offset:offset + limit] - for msg in msgs: - msg.mine = msg.mine(request.user) - return msgs - def make_message(self, request): - if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')): - return 6 - if Message.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=2)).exists(): - return 3 - if len(request.POST['body']) > 50000 or (len(request.POST['body']) < 1 and not request.POST.get('_post_type') == 'painting'): - return 1 - upload = None - drawing = None - if request.FILES.get('screen'): - upload = util.image_upload(request.FILES['screen'], True) - if upload == 1: - return 2 - if request.POST.get('_post_type') == 'painting': - if not request.POST.get('painting'): - return 2 - drawing = util.image_upload(request.POST['painting'], False, True) - if drawing == 1: - return 2 - new_post = self.message_set.create(body=request.POST.get('body'), creator=request.user, feeling=int(request.POST.get('feeling_id', 0)), drawing=drawing, screenshot=upload) - new_post.mine = True - return new_post + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + source = models.ForeignKey(User, related_name='conv_source', on_delete=models.CASCADE) + target = models.ForeignKey(User, related_name='conv_target', on_delete=models.CASCADE) + created = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return "conversation with " + str(self.source) + " and " + str(self.target) + def latest_message(self, user): + msgs = Message.objects.filter(conversation=self).order_by('-created')[:5] + if not msgs: + return False + message = msgs.first() + message.mine = message.mine(user) + return message + def unread(self, user): + return self.message_set.filter(read=False).exclude(creator=user).order_by('-created') + def set_read(self, user): + return self.unread(user).update(read=True) + def all_read(self): + return self.message_set.filter().update(read=True) + def messages(self, request, limit=50, offset=0): + msgs = self.message_set.filter().order_by('-created')[offset:offset + limit] + for msg in msgs: + msg.mine = msg.mine(request.user) + return msgs + def make_message(self, request): + if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')): + return 6 + if Message.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=2)).exists(): + return 3 + if len(request.POST['body']) > 50000 or (len(request.POST['body']) < 1 and not request.POST.get('_post_type') == 'painting'): + return 1 + upload = None + drawing = None + if request.FILES.get('screen'): + upload = util.image_upload(request.FILES['screen'], True) + if upload == 1: + return 2 + if request.POST.get('_post_type') == 'painting': + if not request.POST.get('painting'): + return 2 + drawing = util.image_upload(request.POST['painting'], False, True) + if drawing == 1: + return 2 + new_post = self.message_set.create(body=request.POST.get('body'), creator=request.user, feeling=int(request.POST.get('feeling_id', 0)), drawing=drawing, screenshot=upload) + new_post.mine = True + return new_post class Message(models.Model): - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE) - feeling = models.SmallIntegerField(default=0, choices=feelings) - body = models.TextField(null=True) - drawing = models.CharField(max_length=200, null=True, blank=True) - screenshot = models.CharField(max_length=1200, null=True, blank=True, default='') - url = models.URLField(max_length=1200, null=True, blank=True, default='') - created = models.DateTimeField(auto_now_add=True) - read = models.BooleanField(default=False) - is_rm = models.BooleanField(default=False) - creator = models.ForeignKey(User, on_delete=models.CASCADE) + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE) + feeling = models.SmallIntegerField(default=0, choices=feelings) + body = models.TextField(null=True) + drawing = models.CharField(max_length=200, null=True, blank=True) + screenshot = models.CharField(max_length=1200, null=True, blank=True, default='') + url = models.URLField(max_length=1200, null=True, blank=True, default='') + created = models.DateTimeField(auto_now_add=True) + read = models.BooleanField(default=False) + is_rm = models.BooleanField(default=False) + creator = models.ForeignKey(User, on_delete=models.CASCADE) - objects = PostManager() - real = models.Manager() + objects = PostManager() + real = models.Manager() - def __str__(self): - return self.body[:250] - def trun(self): - if self.is_rm: - return 'deleted' - if self.drawing: - return '(drawing)' - else: - return self.body - def mine(self, user): - if self.creator == user: - return True - return False - def rm(self, request): - if self.conversation.source == request.user or self.conversation.target == request.user: - self.is_rm = True - if self.screenshot: - util.image_rm(self.screenshot) - self.screenshot = None - if self.drawing: - util.image_rm(self.drawing) - self.drawing = None - self.save() + def __str__(self): + return self.body[:250] + def trun(self): + if self.is_rm: + return 'deleted' + if self.drawing: + return '(drawing)' + else: + return self.body + def mine(self, user): + if self.creator == user: + return True + return False + def rm(self, request): + if self.conversation.source == request.user or self.conversation.target == request.user: + self.is_rm = True + if self.screenshot: + util.image_rm(self.screenshot) + self.screenshot = None + if self.drawing: + util.image_rm(self.drawing) + self.drawing = None + self.save() - def makeopt(ls): - if len(ls) < 1: - raise ValueError - return json.dumps(ls) + def makeopt(ls): + if len(ls) < 1: + raise ValueError + return json.dumps(ls) class ConversationInvite(models.Model): - id = models.AutoField(primary_key=True) - conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE) - source = models.ForeignKey(User, related_name='convinvite_source', on_delete=models.CASCADE) - target = models.ForeignKey(User, related_name='convinvite_target', on_delete=models.CASCADE) - body = models.TextField(blank=True, null=True, default='') - read = models.BooleanField(default=False) - finished = models.BooleanField(default=False) - created = models.DateTimeField(auto_now_add=True) - - def __str__(self): - return "Invite to conversation " + str(self.conversation) + " from " + str(self.source) + " to " + str(self.target) + id = models.AutoField(primary_key=True) + conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE) + source = models.ForeignKey(User, related_name='convinvite_source', on_delete=models.CASCADE) + target = models.ForeignKey(User, related_name='convinvite_target', on_delete=models.CASCADE) + body = models.TextField(blank=True, null=True, default='') + read = models.BooleanField(default=False) + finished = models.BooleanField(default=False) + created = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return "Invite to conversation " + str(self.conversation) + " from " + str(self.source) + " to " + str(self.target) class Poll(models.Model): - # Todo: make this a plain int at some point - unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - id = models.AutoField(primary_key=True) - able_vote = models.BooleanField(default=True) - choices = models.TextField(default="[]") - created = models.DateTimeField(auto_now_add=True) + # Todo: make this a plain int at some point + unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + id = models.AutoField(primary_key=True) + able_vote = models.BooleanField(default=True) + choices = models.TextField(default="[]") + created = models.DateTimeField(auto_now_add=True) - def __str__(self): - return "A poll created at " + str(self.created) - def num_votes(self): - return self.pollvote_set.count() - def vote(self, user, opt): - ex_query = self.pollvote_set.filter(by=user) - if ex_query.exists(): - ex_query.first().delete() - self.pollvote_set.create(by=user, choice=opt) - def unvote(self, user): - vote = self.pollvote_set.filter(by=user).first() - if vote: - vote.delete() - def has_vote(self, user): - if not user.is_authenticated: - return False - vote = self.pollvote_set.filter(by=user) - if vote: - return (True, self.choices[vote.first().choice]) - return False - def setup(self, user): - self.choices = json.loads(self.choices) - self.num_votes = self.num_votes() - self.has_vote = self.has_vote(user) + def __str__(self): + return "A poll created at " + str(self.created) + def num_votes(self): + return self.pollvote_set.count() + def vote(self, user, opt): + ex_query = self.pollvote_set.filter(by=user) + if ex_query.exists(): + ex_query.first().delete() + self.pollvote_set.create(by=user, choice=opt) + def unvote(self, user): + vote = self.pollvote_set.filter(by=user).first() + if vote: + vote.delete() + def has_vote(self, user): + if not user.is_authenticated: + return False + vote = self.pollvote_set.filter(by=user) + if vote: + return (True, self.choices[vote.first().choice]) + return False + def setup(self, user): + self.choices = json.loads(self.choices) + self.num_votes = self.num_votes() + self.has_vote = self.has_vote(user) class PollVote(models.Model): - id = models.AutoField(primary_key=True) - done = models.DateTimeField(auto_now_add=True) - choice = models.SmallIntegerField(default=0) - poll = models.ForeignKey(Poll, on_delete=models.CASCADE) - by = models.ForeignKey(User, on_delete=models.CASCADE) - - def __str__(self): - return "A vote on option " + str(self.choice) + " for poll \"" + str(self.poll) + "\" by " + str(self.by) - #def choice_votes(self): - # return PollVote.objects.filter(poll=self.poll, choice=self.choice).count() + id = models.AutoField(primary_key=True) + done = models.DateTimeField(auto_now_add=True) + choice = models.SmallIntegerField(default=0) + poll = models.ForeignKey(Poll, on_delete=models.CASCADE) + by = models.ForeignKey(User, on_delete=models.CASCADE) + + def __str__(self): + return "A vote on option " + str(self.choice) + " for poll \"" + str(self.poll) + "\" by " + str(self.by) + #def choice_votes(self): + # return PollVote.objects.filter(poll=self.poll, choice=self.choice).count() -class RedFlag(models.Model): - id = models.AutoField(primary_key=True) - created = models.DateTimeField(auto_now_add=True) - post = models.ForeignKey(Post, blank=True, null=True, on_delete=models.CASCADE) - comment = models.ForeignKey(Comment, blank=True, null=True, on_delete=models.CASCADE) - user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) - type = models.SmallIntegerField(choices=((0, 'Post'), (1, 'Comment'), (2, 'User'), )) - reason = models.SmallIntegerField(choices=((0, "Actual harassment"), (1, "Spam"), (2, "I don't like this"), (3, "Personal info"), (4, "Obscene use of swearing"), (5, "NSFW where not allowed"), (6, "Overly advertising/spam"), (7, "Please delete this"))) - reasoning = models.TextField(default='', null=True, blank=True) - - def __str__(self): - return "Report on a " + self.get_type_display() + " for " + self.get_reason_display() + ": " + str(self.reasoning) # Login attempts: class LoginAttempt(models.Model): - id = models.AutoField(primary_key=True) - created = models.DateTimeField(auto_now_add=True) - user = models.ForeignKey(User, on_delete=models.CASCADE) - success = models.BooleanField(default=False) - addr = models.CharField(max_length=64, null=True, blank=True) - user_agent = models.TextField(null=True, blank=True) - - def __str__(self): - return 'A login attempt to ' + str(self.user) + ' from ' + str(self.addr) + ', ' + str(self.success) - + id = models.AutoField(primary_key=True) + created = models.DateTimeField(auto_now_add=True) + user = models.ForeignKey(User, on_delete=models.CASCADE) + success = models.BooleanField(default=False) + addr = models.CharField(max_length=64, null=True, blank=True) + user_agent = models.TextField(null=True, blank=True) + + def __str__(self): + 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) - created = models.DateTimeField(auto_now_add=True) - target_user = models.ForeignKey(User, related_name='target_user', on_delete=models.CASCADE) - from_user = models.ForeignKey(User, related_name='from_user', on_delete=models.CASCADE) - def __str__(self): - return str(self.from_user) + ' viewed ' + str(self.target_user) -# Fun -class ThermostatTouch(models.Model): - id = models.AutoField(primary_key=True) - created = models.DateTimeField(auto_now_add=True) - who = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) - lvl = models.IntegerField(default=1) - - def __str__(self): - return str(created) + " touched the thermostat, setting it to " + str(lvl) + " degrees celsius" + id = models.AutoField(primary_key=True) + created = models.DateTimeField(auto_now_add=True) + target_user = models.ForeignKey(User, related_name='target_user', on_delete=models.CASCADE) + from_user = models.ForeignKey(User, related_name='from_user', on_delete=models.CASCADE) + def __str__(self): + return str(self.from_user) + ' viewed ' + str(self.target_user) # Finally class UserBlock(models.Model): - id = models.AutoField(primary_key=True) - created = models.DateTimeField(auto_now_add=True) - source = models.ForeignKey(User, related_name='block_source', on_delete=models.CASCADE) - target = models.ForeignKey(User, related_name='block_target', on_delete=models.CASCADE) - full = models.BooleanField(default=False) - - def __str__(self): - return "Block created from " + str(self.source) + " to " + str(self.target) + id = models.AutoField(primary_key=True) + created = models.DateTimeField(auto_now_add=True) + source = models.ForeignKey(User, related_name='block_source', on_delete=models.CASCADE) + target = models.ForeignKey(User, related_name='block_target', on_delete=models.CASCADE) + # ...??? + #full = models.BooleanField(default=False) + + def __str__(self): + return "Block created from " + str(self.source) + " to " + str(self.target) - @staticmethod - def find_block(first, second, full=False): - if full: - return UserBlock.objects.filter(Q(source=first, full=True) & Q(target=second, full=True) | Q(target=first, full=True) & Q(source=second, full=True)).exists() - return UserBlock.objects.filter(Q(source=first) & Q(target=second) | Q(target=first) & Q(source=second)).exists() + @staticmethod + def find_block(first, second): + #, full=False): + # in every instance of find_block that I have seen, the second argument is always the request user + # so in the interest of making this implementation easy (forgot where the checks are supposed to go otherwise) + if not second.is_authenticated: + return False + #if full: + # return UserBlock.objects.filter(Q(source=first, full=full) & Q(target=second, full=full) | Q(target=first, full=full) & Q(source=second, full=full)).exists() + block = UserBlock.objects.filter(Q(source=first) & Q(target=second) | Q(target=first) & Q(source=second)) + if not block.exists(): + return False + return block.first() class AuditLog(models.Model): - id = models.AutoField(primary_key=True) - created = models.DateTimeField(auto_now_add=True) - type = models.SmallIntegerField(choices=((0, "Post delete"), (1, "Comment delete"), (2, "User edit"), (3, "Generate passwd reset"), (4, "User delete"), (5, "Image delete"), (6, "Purge 1"), (7, "Purge 2"), (8, "Purge 3"), (9, "Purge 4"), (10, "Purge 5"), (11, "Un-purge 1"), (12, 'Changed server settings'), )) - post = models.ForeignKey(Post, related_name='audit_post', null=True, on_delete=models.CASCADE) - comment = models.ForeignKey(Comment, related_name='audit_comment', null=True, on_delete=models.CASCADE) - user = models.ForeignKey(User, related_name='audit_user', null=True, on_delete=models.CASCADE) - reasoning = models.TextField(null=True, blank=True, default="") - by = models.ForeignKey(User, related_name='audit_by', on_delete=models.CASCADE) - reversed_by = models.ForeignKey(User, null=True, related_name='audit_reverse_by', on_delete=models.CASCADE) - - def __str__(self): - return str(self.by) + " did " + self.get_type_display() + " at " + str(self.created) - def reverse(self, user=None): - # Try to reverse what this did - if user: - self.reversed_by = user - # No switches in Python, so - if self.type == 0: - self.post.is_rm = False - self.post.status = 0 - self.post.save() - return True - elif self.type == 1: - self.post.is_rm = False - self.post.status = 0 - self.post.save() - return True - else: - return False + id = models.AutoField(primary_key=True) + created = models.DateTimeField(auto_now_add=True) + type = models.SmallIntegerField(choices=((0, "Post delete"), (1, "Comment delete"), (2, "User edit"), (3, "Generate passwd reset"), (4, "User delete"), (5, "Image delete"), (6, "Purge 1"), (7, "Purge 2"), (8, "Purge 3"), (9, "Purge 4"), (10, "Purge 5"), (11, "Un-purge 1"), (12, 'Changed server settings'), )) + post = models.ForeignKey(Post, related_name='audit_post', null=True, on_delete=models.CASCADE) + comment = models.ForeignKey(Comment, related_name='audit_comment', null=True, on_delete=models.CASCADE) + user = models.ForeignKey(User, related_name='audit_user', null=True, on_delete=models.CASCADE) + reasoning = models.TextField(null=True, blank=True, default="") + by = models.ForeignKey(User, related_name='audit_by', on_delete=models.CASCADE) + reversed_by = models.ForeignKey(User, null=True, related_name='audit_reverse_by', on_delete=models.CASCADE) + + def __str__(self): + return str(self.by) + " did " + self.get_type_display() + " at " + str(self.created) + def reverse(self, user=None): + # Try to reverse what this did + if user: + self.reversed_by = user + # No switches in Python, so + if self.type == 0: + self.post.is_rm = False + self.post.status = 0 + self.post.save() + return True + elif self.type == 1: + self.post.is_rm = False + self.post.status = 0 + self.post.save() + return True + else: + return False class UserRequest(User): - # USER AGENT - ua = models.TextField(default='', null=True, blank=True) - latest = models.DateTimeField(auto_now=True) - status = models.SmallIntegerField(default=0, choices=((0, 'submitted'), (1, 'viewed'), (2, 'accepted'), (3, 'decline'), (4, 'ignore'), )) + # USER AGENT + ua = models.TextField(default='', null=True, blank=True) + latest = models.DateTimeField(auto_now=True) + status = models.SmallIntegerField(default=0, choices=((0, 'submitted'), (1, 'viewed'), (2, 'accepted'), (3, 'decline'), (4, 'ignore'), )) class Ads(models.Model): - id = models.AutoField(primary_key=True) - created = models.DateTimeField(auto_now_add=True) - url = models.CharField(max_length=256, null=False, blank=False) - imageurl = models.ImageField(upload_to='ad/%y/%m/%d/', max_length=100) + id = models.AutoField(primary_key=True) + created = models.DateTimeField(auto_now_add=True) + url = models.CharField(max_length=256, null=False, blank=False) + imageurl = models.ImageField(upload_to='ad/%y/%m/%d/', max_length=100) - def get_one(): - ads = Ads.objects.all() - ad = random.choice(ads) - return ad + def get_one(): + ads = Ads.objects.all() + ad = random.choice(ads) + return ad - def ads_available(): - global adsavailable - if(Ads.objects.all().exists()): - adsavailable = True - else: - adsavailable = False - return adsavailable + def ads_available(): + global adsavailable + if(Ads.objects.all().exists()): + adsavailable = True + else: + adsavailable = False + return adsavailable - def __str__(self): - return "Ad with id " + str(self.id) + ", created at " + str(self.created) + ", with url " + str(self.url) + ", and imageurl " + str(self.imageurl) + def __str__(self): + return "Ad with id " + str(self.id) + ", created at " + str(self.created) + ", with url " + str(self.url) + ", and imageurl " + str(self.imageurl) class welcomemsg(models.Model): - id = models.AutoField(primary_key=True) - order = models.IntegerField(max_length=3, default=1) - show = models.BooleanField(default=True) - created = models.DateTimeField(auto_now_add=True) - Title = models.CharField(max_length=256, null=False, blank=False, default='Title') - message = models.TextField(null=False, blank=False) - image = models.ImageField(upload_to='welcomemsg/%y/%m/%d/', max_length=255, null=True, blank=True) - + id = models.AutoField(primary_key=True) + order = models.IntegerField(max_length=3, default=1) + show = models.BooleanField(default=True) + created = models.DateTimeField(auto_now_add=True) + Title = models.CharField(max_length=256, null=False, blank=False, default='Title') + message = models.TextField(null=False, blank=False) + image = models.ImageField(upload_to='welcomemsg/%y/%m/%d/', max_length=255, null=True, blank=True) + # thing will log changes to your bio or nickname class ProfileHistory(models.Model): - id = models.AutoField(primary_key=True) - created = models.DateTimeField(auto_now_add=True) - user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) - old_nickname = models.CharField(max_length=64, blank=True, null=True) - new_nickname = models.CharField(max_length=64, blank=True, null=True) - old_comment = models.TextField(blank=True) - new_comment = models.TextField(blank=True) - - def __str__(self): - return str(self.user) + ' changed profile details' - + id = models.AutoField(primary_key=True) + created = models.DateTimeField(auto_now_add=True) + user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) + old_nickname = models.CharField(max_length=64, blank=True, null=True) + new_nickname = models.CharField(max_length=64, blank=True, null=True) + old_comment = models.TextField(blank=True, null=True) + new_comment = models.TextField(blank=True) + + def __str__(self): + return str(self.user) + ' changed profile details' + # blah blah blah # this method will be executed when... def rm_post_image(sender, instance, **kwargs): - if instance.screenshot: - util.image_rm(instance.screenshot) - if instance.drawing: - util.image_rm(instance.drawing) + if instance.screenshot: + util.image_rm(instance.screenshot) + if instance.drawing: + util.image_rm(instance.drawing) # when pre_delete happens on these pre_delete.connect(rm_post_image, sender=Post) pre_delete.connect(rm_post_image, sender=Comment) diff --git a/closedverse_main/serializers.py b/closedverse_main/serializers.py index 02fadc1..d367d18 100644 --- a/closedverse_main/serializers.py +++ b/closedverse_main/serializers.py @@ -19,7 +19,7 @@ class CommunitySerializer(): 'platform': community.platform, 'allowed_users': json.loads(community.allowed_users) if community.allowed_users else None, 'creator': community.creator_id - } + } @staticmethod def many(queryset): """ diff --git a/closedverse_main/templates/closedverse_main/community_all.html b/closedverse_main/templates/closedverse_main/community_all.html index 5f92d44..c2e4b15 100644 --- a/closedverse_main/templates/closedverse_main/community_all.html +++ b/closedverse_main/templates/closedverse_main/community_all.html @@ -10,9 +10,9 @@

What can I do with my own community?

You can edit it, and that's basically it.

What are C-Tokens, and how do I get them?

-

Community tokens are a stupid and overcomplicated method of preventing 200,000 communities from being made by one person. You get one when signing up, and you can use it to make your own community. You'll have to ask a staff member for more C-Tokens if you want to make more communities. 

+

Community tokens are a stupid and overcomplicated method of preventing 200,000 communities from being made by one person. You get one when signing up, and you can use it to make your own community. Please do not ask staff for more C-Tokens unless you believe the communities you are going to make are really that good.

Any future plans?

-

Fuck, I got no clue. Maybe I should make C-Tokens tradable, or make a community ban system, so you can block people from posting and commenting in your own communities.

+

no

{% if request.user.c_tokens > 0 %}Create a community{% endif %} diff --git a/closedverse_main/templates/closedverse_main/community_view.html b/closedverse_main/templates/closedverse_main/community_view.html index b522a33..af8c989 100644 --- a/closedverse_main/templates/closedverse_main/community_view.html +++ b/closedverse_main/templates/closedverse_main/community_view.html @@ -17,7 +17,7 @@ {% post_form request.user community %} {% endif %}
- {% post_list posts next %} + {% post_list posts next 0 '' time %}
diff --git a/closedverse_main/templates/closedverse_main/elements/block-modal.html b/closedverse_main/templates/closedverse_main/elements/block-modal.html new file mode 100644 index 0000000..c879792 --- /dev/null +++ b/closedverse_main/templates/closedverse_main/elements/block-modal.html @@ -0,0 +1,19 @@ +{% load closedverse_user %}{% if profile.can_block %} +
+
+
+

{% if profile.is_blocked %}Unblock{% else %}Block{% endif %} {{ user.nickname }}

+
+ {% user_sidebar_info user profile %} +
+

Really {% if profile.is_blocked %}un{% endif %}block this user?{% if not profile.is_blocked %} You won't be able to see each other's posts or profile.{% endif %}

+
+ + +
+
+
+
+
+
+{% endif %} diff --git a/closedverse_main/templates/closedverse_main/elements/comment-form.html b/closedverse_main/templates/closedverse_main/elements/comment-form.html index cebc445..46b2294 100644 --- a/closedverse_main/templates/closedverse_main/elements/comment-form.html +++ b/closedverse_main/templates/closedverse_main/elements/comment-form.html @@ -1,6 +1,7 @@ -{% load closedverse_community %}
+{% load closedverse_community %} +{% if user.is_active %} + {% csrf_token %} - {% if user.is_active %} {% if not user.limit_remaining is False %}
Remaining posts for today @@ -40,8 +41,6 @@
- -
@@ -51,5 +50,5 @@ {% endif %} {% if not user.is_active %} -

Your account has been disabled.

-{% endif %} \ No newline at end of file +

Your account has been disabled.

+{% endif %} diff --git a/closedverse_main/templates/closedverse_main/elements/community_post.html b/closedverse_main/templates/closedverse_main/elements/community_post.html index ad435ad..0fd066f 100644 --- a/closedverse_main/templates/closedverse_main/elements/community_post.html +++ b/closedverse_main/templates/closedverse_main/elements/community_post.html @@ -1,5 +1,5 @@ {% if not post.is_rm %} -{% load closedverse_tags %}
-{% endif %} \ No newline at end of file +{% endif %} diff --git a/closedverse_main/templates/closedverse_main/elements/post-form.html b/closedverse_main/templates/closedverse_main/elements/post-form.html index fe068a2..a9e8854 100644 --- a/closedverse_main/templates/closedverse_main/elements/post-form.html +++ b/closedverse_main/templates/closedverse_main/elements/post-form.html @@ -1,7 +1,8 @@ -{% load closedverse_community %}
+{% load closedverse_community %} +{% if user.is_active %} + {% csrf_token %} -{% if user.is_active %} {% if not user.limit_remaining is False %}
Remaining posts for today @@ -65,5 +66,5 @@ {% endif %} {% if not user.is_active %} -

Your account has been disabled.

+

Your account has been disabled.

{% endif %} diff --git a/closedverse_main/templates/closedverse_main/elements/post-list.html b/closedverse_main/templates/closedverse_main/elements/post-list.html index 520090b..459dc80 100644 --- a/closedverse_main/templates/closedverse_main/elements/post-list.html +++ b/closedverse_main/templates/closedverse_main/elements/post-list.html @@ -1,4 +1,4 @@ -{% load closedverse_tags %}{% load closedverse_community %}
+{% load closedverse_tags %}{% load closedverse_community %}
{% if posts %} {% for post in posts %} {% community_post post type %} @@ -6,4 +6,4 @@ {% else %} {% if nf %}{% nocontent nf %}{% else %}{% nocontent "The posts couldn't be loaded." %}{% endif %} {% endif %} -
\ No newline at end of file +
diff --git a/closedverse_main/templates/closedverse_main/elements/profile-post.html b/closedverse_main/templates/closedverse_main/elements/profile-post.html index fcdfa34..72a554a 100644 --- a/closedverse_main/templates/closedverse_main/elements/profile-post.html +++ b/closedverse_main/templates/closedverse_main/elements/profile-post.html @@ -1,4 +1,4 @@ -{% load closedverse_tags %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/closedverse_main/templates/closedverse_main/help/contact.html b/closedverse_main/templates/closedverse_main/help/contact.html index 95251af..8ad3565 100644 --- a/closedverse_main/templates/closedverse_main/help/contact.html +++ b/closedverse_main/templates/closedverse_main/help/contact.html @@ -3,7 +3,7 @@ {% user_sidebar request user user.profile 0 True %}
-

Contact the team behind this

+

Where even do I contact you, anyway?

I'll make this page later, need permission from our admins and shit...

diff --git a/closedverse_main/templates/closedverse_main/help/email.html b/closedverse_main/templates/closedverse_main/help/email.html index 448bb4e..2cf6923 100644 --- a/closedverse_main/templates/closedverse_main/help/email.html +++ b/closedverse_main/templates/closedverse_main/help/email.html @@ -1,7 +1,8 @@ + Hi - + @@ -12,4 +13,4 @@

If you didn't submit this, please ignore this email, someone probably tried to use your email to reset, and they can't have any access unless they actually have your email address. If you're having trouble, contact us here.


Thank you for using our service! :)

- \ No newline at end of file + diff --git a/closedverse_main/templates/closedverse_main/help/forgot_reset.html b/closedverse_main/templates/closedverse_main/help/forgot_reset.html new file mode 100644 index 0000000..c240b63 --- /dev/null +++ b/closedverse_main/templates/closedverse_main/help/forgot_reset.html @@ -0,0 +1,21 @@ +{% extends "closedverse_main/layout.html" %} +{% load static %}{% block main-body %} +
+ +
+{% endblock %} \ No newline at end of file diff --git a/closedverse_main/templates/closedverse_main/help/login-help.html b/closedverse_main/templates/closedverse_main/help/login-help.html index c410d2c..7eece85 100644 --- a/closedverse_main/templates/closedverse_main/help/login-help.html +++ b/closedverse_main/templates/closedverse_main/help/login-help.html @@ -15,8 +15,8 @@

I'm getting "Your password must be reset"?

This means that your password must be reset. Reset it via email, or ask an admin to reset it. In most cases, an admin has emailed you a password reset link.

- -

I'm being hacked! HELP!!!

+ +

i"m bEinG hAcKeD!!!!!!!!!!

If others are in your account, no worry, when you change your password, everyone gets logged out.
Unless your email was changed or you don't have one, in that case, contact an admin and they will help you ASAP.

You should use a random password and keep it in your notes or something. In most cases, public user accounts are made due to one character passwords. Please do not use one character passwords. @@ -26,4 +26,4 @@

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/closedverse_main/templates/closedverse_main/help/stats.html b/closedverse_main/templates/closedverse_main/help/stats.html index e808e6a..b2bc95b 100644 --- a/closedverse_main/templates/closedverse_main/help/stats.html +++ b/closedverse_main/templates/closedverse_main/help/stats.html @@ -3,7 +3,7 @@ {% user_sidebar request user user.profile 0 True %}
-

Cedar stats

+

Server statistics

These are the current stats of this Cedar instance:

@@ -24,4 +24,4 @@
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/closedverse_main/templates/closedverse_main/help/why.html b/closedverse_main/templates/closedverse_main/help/why.html index d0dc4cf..aaddf63 100644 --- a/closedverse_main/templates/closedverse_main/help/why.html +++ b/closedverse_main/templates/closedverse_main/help/why.html @@ -3,13 +3,12 @@ {% user_sidebar request user user.profile 0 True %}
-

Why?

+

Why should I join?

+

why should you join?

-

Why should I join ?

-
    -
  • I don't know...
  • -
+

because i said so.

+

you don't have to though

diff --git a/closedverse_main/templates/closedverse_main/login_page.html b/closedverse_main/templates/closedverse_main/login_page.html index d1c109e..45214f1 100644 --- a/closedverse_main/templates/closedverse_main/login_page.html +++ b/closedverse_main/templates/closedverse_main/login_page.html @@ -24,7 +24,7 @@ {% endif %} {% if not allow_signups %}
-

Signing up is disabled for now, check by later.

+

Signing up is disabled for now, check back later.

{% endif %} diff --git a/closedverse_main/templates/closedverse_main/notifications.html b/closedverse_main/templates/closedverse_main/notifications.html index 5556416..5037f94 100644 --- a/closedverse_main/templates/closedverse_main/notifications.html +++ b/closedverse_main/templates/closedverse_main/notifications.html @@ -10,7 +10,7 @@ {% elif not post.can_comment %}
diff --git a/closedverse_main/templates/closedverse_main/profile-settings.html b/closedverse_main/templates/closedverse_main/profile-settings.html index b36d8da..aad1344 100644 --- a/closedverse_main/templates/closedverse_main/profile-settings.html +++ b/closedverse_main/templates/closedverse_main/profile-settings.html @@ -1,5 +1,5 @@ {% extends "closedverse_main/layout.html" %} -{% block main-body %}{% load closedverse_user %}{% load closedverse_tags %} +{% block main-body %}{% load closedverse_user %}{% load closedverse_tags %}{% load closedverse_community %} {% user_sidebar request user profile 0 %}
@@ -45,12 +45,13 @@

Enter your region here. It'll appear on your profile.
+ If you want to use your location, you can get it automatically here (it will not be automatically saved).

  • E-mail address

    - +

    Please note that your email can be a fake one, however if you need to reset your password, this must be accessible. You can't share emails.

    {% if user.email %} @@ -90,10 +91,10 @@
  • Nickname color

    - +
    -

    This is the color your nickname will appear as. Leave it blank for the default. It will appear like so.

    +

    This is the color your nickname will appear as. Set it to white (#ffffff) and it will return to the default. It will appear like so.

    {% user_sidebar_info user %}
  • {% if profile.origin_id %} @@ -186,28 +187,33 @@
    - +

    Enter your Nintendo Network ID here. It'll appear on your profile if you set it to be visible.

    - {% if not user.has_plain_avatar %}
  • - + + {% if user.has_freedom %} + + {% endif %}
    -

    Do you want the avatar shown beside your content to use the Mii from your Nintendo Network ID or a Gravatar?

    +

    Do you want the avatar shown beside your content to use the Mii from your Nintendo Network ID or a Gravatar or a custom avatar the way God intended?

    -

    Selecting the Gravatar option will cause your avatar to be pulled from the Gravatar account linked to your email address, and feelings won't be shown in your posts unless you choose to use a Mii instead.

    + {% if user.has_freedom %} + + {% file_button %} + + {% else %} + + {% endif %} +

    Selecting the Gravatar option will cause your avatar to be pulled from the Gravatar account linked to your email address, and feelings won't be shown in your posts unless you choose to use a Mii instead. Same with the custom avatar option but who really cared anyway?

  • - {% else %} -

    It appears that you somehow have a plain URL avatar, change it here (if you change it to nothing then it will reset to being selectable !!)

    -
    - -
    - {% endif %} {% csrf_token %}
    diff --git a/closedverse_main/templates/closedverse_main/signup_page.html b/closedverse_main/templates/closedverse_main/signup_page.html index 2299bbd..a8989b8 100644 --- a/closedverse_main/templates/closedverse_main/signup_page.html +++ b/closedverse_main/templates/closedverse_main/signup_page.html @@ -13,6 +13,7 @@

    +

    @@ -21,15 +22,13 @@
    {% endif %} -

    All fields with a red asterisk (*) are required.

    -

    NNIDs are only required for getting a Mii and a nickname from.

    -

    If you do not provide a nickname but provide an NNID, the nickname will be taken from that ID. The ID's nickname, however, is prioritized over the nickname field.

    -

    You will be able to change your avatar after you sign up.

    -

    %: Emails are not required to sign up, however it is used for Gravatar and account recovery.

    +

    NNIDs are only required for getting a Mii from.

    +

    You will be able to change your avatar (or use a custom one) after you sign up.

    +

    %: If you don't fill in your email address, you can't reset your password until you have one.

    $: Your username is used to log in. It'll appear similarly to your NNID on Miiverse, below your nickname.

    diff --git a/closedverse_main/templates/closedverse_main/user_blocked.html b/closedverse_main/templates/closedverse_main/user_blocked.html new file mode 100644 index 0000000..cb676aa --- /dev/null +++ b/closedverse_main/templates/closedverse_main/user_blocked.html @@ -0,0 +1,6 @@ +{% extends "closedverse_main/layout.html" %} +{% block main-body %}{% load closedverse_user %} +

    This user is blocked.

    +{% if profile.can_block %}
    {% endif %} +{% block_modal user profile %} +{% endblock %} diff --git a/closedverse_main/templates/closedverse_main/user_comments.html b/closedverse_main/templates/closedverse_main/user_comments.html index 85a8176..4ba04e5 100644 --- a/closedverse_main/templates/closedverse_main/user_comments.html +++ b/closedverse_main/templates/closedverse_main/user_comments.html @@ -4,7 +4,7 @@

    {{ title }}

    -{% u_post_list posts next 3 %} +{% u_post_list posts next 3 '' time %}
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/closedverse_main/templates/closedverse_main/user_posts.html b/closedverse_main/templates/closedverse_main/user_posts.html index 9e7b1c1..7114983 100644 --- a/closedverse_main/templates/closedverse_main/user_posts.html +++ b/closedverse_main/templates/closedverse_main/user_posts.html @@ -4,7 +4,7 @@

    {{ title }}

    -{% u_post_list posts next 0 %} +{% u_post_list posts next 0 '' time %}
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/closedverse_main/templatetags/closedverse_user.py b/closedverse_main/templatetags/closedverse_user.py index 340d45c..bd761a4 100644 --- a/closedverse_main/templatetags/closedverse_user.py +++ b/closedverse_main/templatetags/closedverse_user.py @@ -34,6 +34,12 @@ def user_sidebar_info(user, profile=None): 'user': user, 'profile': profile, } +@register.inclusion_tag('closedverse_main/elements/block-modal.html') +def block_modal(user, profile): + return { + 'user': user, + 'profile': profile, + } @register.inclusion_tag('closedverse_main/elements/fr-accept.html') def fr_accept(fr): return { @@ -48,7 +54,7 @@ def user_post(post, type=0): } @register.inclusion_tag('closedverse_main/elements/u-post-list.html') -def u_post_list(posts, next_offset=None, type=2, nf_text=''): +def u_post_list(posts, next_offset=None, type=2, nf_text='', time=None): text = { 0: "This user hasn't made any posts yet.", 1: "This user hasn't given a Yeah to any posts yet.", @@ -59,6 +65,7 @@ def u_post_list(posts, next_offset=None, type=2, nf_text=''): 'posts': posts, 'nf': text, 'next': next_offset, + 'time': time, 'type': type, } @register.inclusion_tag('closedverse_main/elements/profile-post.html') diff --git a/closedverse_main/urls.py b/closedverse_main/urls.py index 03f891d..2ca3a79 100644 --- a/closedverse_main/urls.py +++ b/closedverse_main/urls.py @@ -15,110 +15,104 @@ uuidr = r'[0-9a-f\-]' app_name = 'main' urlpatterns = [ - # Root - url(r'^^$|^communities$|^index.*$$', views.community_list, name='community-list'), - # Accounts - url(r'login/$', views.login_page, name='login'), - url(r'signup/$', views.signup_page, name='signup'), - url(r'reset/$', views.forgot_passwd, name='forgot-passwd'), - url(r'logout/$', views.logout_page, name='logout'), - # User pages - url(r'users/'+ username +'/follow$', views.user_follow, name='user-follow'), - url(r'users/'+ username +'/unfollow$', views.user_unfollow, name='user-unfollow'), - url(r'users/'+ username +'$', views.user_view, name='user-view'), - url(r'users/'+ username +'/posts$', views.user_posts, name='user-posts'), - url(r'users/'+ username +'/yeahs$', views.user_yeahs, name='user-yeahs'), - url(r'users/'+ username +'/comments$', views.user_comments, name='user-comments'), - url(r'users/'+ username +'/following$', views.user_following, name='user-following'), - url(r'users/'+ username +'/followers$', views.user_followers, name='user-followers'), - url(r'users/'+ username +'/friends$', views.user_friends, name='user-friends'), - # User page friends - url(r'users/'+ username +'/friend_new$', views.user_friendrequest_create, name='user-fr-create'), - url(r'users/'+ username +'/friend_accept$', views.user_friendrequest_accept, name='user-fr-accept'), - url(r'users/'+ username +'/friend_reject$', views.user_friendrequest_reject, name='user-fr-reject'), - url(r'users/'+ username +'/friend_cancel$', views.user_friendrequest_cancel, name='user-fr-cancel'), - url(r'users/'+ username +'/friend_delete$', views.user_friendrequest_delete, name='user-fr-delete'), - url(r'users/'+ username +'/tools/set$', views.user_tools_set, name='user-tools-set'), - url(r'users/'+ username +'/tools$', views.user_tools, name='user-tools'), - url(r'users/'+ username +'/tools/meta$', views.user_tools_meta, name='user-tools-meta'), + # Root + url(r'^^$|^communities$|^index.*$$', views.community_list, name='community-list'), + # Accounts + url(r'login/$', views.login_page, name='login'), + url(r'signup/$', views.signup_page, name='signup'), + url(r'reset/$', views.forgot_passwd, name='forgot-passwd'), + url(r'logout/$', views.logout_page, name='logout'), + # User pages + url(r'users/'+ username +'/follow$', views.user_follow, name='user-follow'), + url(r'users/'+ username +'/unfollow$', views.user_unfollow, name='user-unfollow'), + url(r'users/'+ username +'$', views.user_view, name='user-view'), + url(r'users/'+ username +'/posts$', views.user_posts, name='user-posts'), + url(r'users/'+ username +'/yeahs$', views.user_yeahs, name='user-yeahs'), + url(r'users/'+ username +'/comments$', views.user_comments, name='user-comments'), + url(r'users/'+ username +'/following$', views.user_following, name='user-following'), + url(r'users/'+ username +'/followers$', views.user_followers, name='user-followers'), + url(r'users/'+ username +'/friends$', views.user_friends, name='user-friends'), + # User page friends + url(r'users/'+ username +'/friend_new$', views.user_friendrequest_create, name='user-fr-create'), + url(r'users/'+ username +'/friend_accept$', views.user_friendrequest_accept, name='user-fr-accept'), + url(r'users/'+ username +'/friend_reject$', views.user_friendrequest_reject, name='user-fr-reject'), + url(r'users/'+ username +'/friend_cancel$', views.user_friendrequest_cancel, name='user-fr-cancel'), + url(r'users/'+ username +'/friend_delete$', views.user_friendrequest_delete, name='user-fr-delete'), + url(r'users/'+ username +'/tools/set$', views.user_tools_set, name='user-tools-set'), + url(r'users/'+ username +'/tools$', views.user_tools, name='user-tools'), + url(r'users/'+ username +'/tools/meta$', views.user_tools_meta, name='user-tools-meta'), + url(r'users/'+ username +'/block$', views.user_addblock, name='user-addblock'), + # Communities + url(r'communities.search$', views.community_search, name='community-search'), + url(r'communities/'+ community +'$', views.community_view, name='community-view'), + url(r'communities/favorites$', views.community_favorites, name='community-favorites'), + url(r'communities/categories/(?P[a-z]+)$', views.community_all, name='community-viewall'), + url(r'communities/(?P[a-z]+)$', views.special_community_tag, name='special-community-tag'), + url(r'communities/'+ community +'/favorite$', views.community_favorite_create, name='community-favorite-add'), + url(r'communities/'+ community +'/favorite_rm$', views.community_favorite_rm, name='community-favorite-rm'), + url(r'communities/'+ community +'/posts$', views.post_create, name='post-create'), + url(r'communities/'+ community +'/tools$', views.community_tools, name='community-tools'), + url(r'communities/'+ community +'/tools/set$', views.community_tools_set, name='community-tools-set'), + url(r'c/create$', views.community_create, name='community-create'), + url(r'c/create/do$', views.community_create_action, name='community-create-action'), + # Posts and comments + # Some of these NAMES (not patterns) are hardcoded into models.py + url(r'posts/'+ post +'$', views.post_view, name='post-view'), + url(r'posts/'+ post +'/yeah$', views.post_add_yeah, name='post-add-yeah'), + url(r'posts/'+ post +'/yeahu$', views.post_delete_yeah, name='post-delete-yeah'), + url(r'posts/'+ post +'/comments$', views.post_comments, name='post-comments'), + url(r'posts/'+ post +'/comments$', views.post_comments, name='post-comments'), + url(r'posts/'+ post +'/change$', views.post_change, name='post-change'), + url(r'posts/'+ post +'/profile$', views.post_setprofile, name='post-set-profile'), + url(r'posts/'+ post +'/profile_rm', views.post_unsetprofile, name='post-unset-profile'), + url(r'posts/'+ post +'\.rm$', views.post_rm, name='post-rm'), + url(r'comments/'+ comment +'$', views.comment_view, name='comment-view'), + url(r'comments/'+ comment +'/yeah$', views.comment_add_yeah, name='comment-add-yeah'), + url(r'comments/'+ comment +'/yeahu$', views.comment_delete_yeah, name='comment-delete-yeah'), + url(r'comments/'+ comment +'/change$', views.comment_change, name='comment-change'), + url(r'comments/'+ comment +'/rm$', views.comment_rm, name='comment-rm'), + # Post-meta: polls + url(r'poll/(?P'+ uuidr +'+)/vote$', views.poll_vote, name='poll-vote'), + url(r'poll/(?P'+ uuidr +'+)/unvote$', views.poll_unvote, name='poll-unvote'), - url(r'users/'+ username +'/block$', views.user_addblock, name='user-addblock'), - # Communities - url(r'communities.search$', views.community_search, name='community-search'), - url(r'communities/'+ community +'$', views.community_view, name='community-view'), - url(r'communities/favorites$', views.community_favorites, name='community-favorites'), - url(r'communities/categories/(?P[a-z]+)$', views.community_all, name='community-viewall'), - url(r'communities/(?P[a-z]+)$', views.special_community_tag, name='special-community-tag'), - url(r'communities/'+ community +'/favorite$', views.community_favorite_create, name='community-favorite-add'), - url(r'communities/'+ community +'/favorite_rm$', views.community_favorite_rm, name='community-favorite-rm'), - url(r'communities/'+ community +'/posts$', views.post_create, name='post-create'), - url(r'communities/'+ community +'/tools$', views.community_tools, name='community-tools'), - url(r'communities/'+ community +'/tools/set$', views.community_tools_set, name='community-tools-set'), - url(r'c/create$', views.community_create, name='community-create'), - url(r'c/create/do$', views.community_create_action, name='community-create-action'), - # Posts and comments - # Some of these NAMES (not patterns) are hardcoded into models.py - url(r'posts/'+ post +'$', views.post_view, name='post-view'), - url(r'posts/'+ post +'/yeah$', views.post_add_yeah, name='post-add-yeah'), - url(r'posts/'+ post +'/yeahu$', views.post_delete_yeah, name='post-delete-yeah'), - url(r'posts/'+ post +'/comments$', views.post_comments, name='post-comments'), - url(r'posts/'+ post +'/comments$', views.post_comments, name='post-comments'), - url(r'posts/'+ post +'/change$', views.post_change, name='post-change'), - url(r'posts/'+ post +'/profile$', views.post_setprofile, name='post-set-profile'), - url(r'posts/'+ post +'/profile_rm', views.post_unsetprofile, name='post-unset-profile'), - url(r'posts/'+ post +'\.rm$', views.post_rm, name='post-rm'), - url(r'comments/'+ comment +'$', views.comment_view, name='comment-view'), - url(r'comments/'+ comment +'/yeah$', views.comment_add_yeah, name='comment-add-yeah'), - url(r'comments/'+ comment +'/yeahu$', views.comment_delete_yeah, name='comment-delete-yeah'), - url(r'comments/'+ comment +'/change$', views.comment_change, name='comment-change'), - url(r'comments/'+ comment +'/rm$', views.comment_rm, name='comment-rm'), - # Post-meta: polls - url(r'poll/(?P'+ uuidr +'+)/vote$', views.poll_vote, name='poll-vote'), - url(r'poll/(?P'+ uuidr +'+)/unvote$', views.poll_unvote, name='poll-unvote'), + # Notifications + url(r'alive$', views.check_notifications, name='check-notifications'), + url(r'notifications/?$', views.notifications, name='notifications'), + url(r'notifications/friend_requests/?$', views.friend_requests, name='friend-requests'), + url(r'notifications/(?P'+ uuidr +'+)\.rm$', views.notification_delete, name='notification-delete'), - # Notifications - url(r'alive$', views.check_notifications, name='check-notifications'), - url(r'notifications/?$', views.notifications, name='notifications'), - url(r'notifications/friend_requests/?$', views.friend_requests, name='friend-requests'), - url(r'notifications/(?P'+ uuidr +'+)\.rm$', views.notification_delete, name='notification-delete'), + # User meta + messages + url(r'activity/?$', views.activity_feed, name='activity'), + url(r'users.search$', views.user_search, name='user-search'), + url(r'pref$', views.prefs, name='prefs'), + url(r'settings/profile$', views.profile_settings, name='profile-settings'), + url(r'messages/?$', views.messages, name='messages'), + url(r'messages/(?P'+ uuidr +'+)/rm$', views.message_rm, name='message-delete'), + url(r'messages/'+ username +'$', views.messages_view, name='messages-view'), + url(r'messages/'+ username +'/read$', views.messages_read, name='messages-read'), - # User meta + messages - url(r'activity/?$', views.activity_feed, name='activity'), - url(r'users.search$', views.user_search, name='user-search'), - url(r'pref$', views.prefs, name='prefs'), - url(r'settings/profile$', views.profile_settings, name='profile-settings'), - url(r'messages/?$', views.messages, name='messages'), - url(r'messages/(?P'+ uuidr +'+)/rm$', views.message_rm, name='message-delete'), - url(r'messages/'+ username +'$', views.messages_view, name='messages-view'), - url(r'messages/'+ username +'/read$', views.messages_read, name='messages-read'), + # Help/configuration + url(r'lights$', views.set_lighting, name='set-lighting'), + url(r'complaints$', views.help_complaint, name='complaints'), + url(r'invite$', views.invites, name='invites'), + url(r'invite/create/$', views.create_invite, name='create_invite'), + url(r'mydata$', views.my_data, name='my-data'), + url(r'changepassword$', views.change_password, name='change-password'), + url(r'changepassword/set$', views.change_password_set, name='change-password-set'), + url(r'server$', views.server_stat, name='server-stat'), + url(r'help/rules/?$', views.help_rules, name='help-rules'), + url(r'help/faq/?$', views.help_faq, name='help-faq'), + url(r'help/legal/?$', views.help_legal, name='help-legal'), + url(r'help/contact/?$', views.help_contact, name='help-contact'), + url(r'help/login/?$', views.help_login, name='help-login'), + url(r'help/whatads/?$', views.whatads, name='what-ads'), + url(r'why/?$', views.help_why, name='help-why'), + - # Help/configuration - url(r'lights$', views.set_lighting, name='set-lighting'), - url(r'complaints$', views.help_complaint, name='complaints'), - url(r'invite$', views.invites, name='invites'), - url(r'invite/create/$', views.create_invite, name='create_invite'), - url(r'mydata$', views.my_data, name='my-data'), - url(r'changepassword$', views.change_password, name='change-password'), - url(r'changepassword/set$', views.change_password_set, name='change-password-set'), - url(r'server$', views.server_stat, name='server-stat'), - url(r'help/rules/?$', views.help_rules, name='help-rules'), - url(r'help/faq/?$', views.help_faq, name='help-faq'), - url(r'help/legal/?$', views.help_legal, name='help-legal'), - url(r'help/contact/?$', views.help_contact, name='help-contact'), - url(r'help/login/?$', views.help_login, name='help-login'), - url(r'help/whatads/?$', views.whatads, name='what-ads'), - url(r'help/actclones/?$', views.active_clones, name='active-clones'), - url(r'help/approval/?$', views.help_approval, name='help-approval'), - url(r'why/?$', views.help_why, name='help-why'), - - - # "API" - url(r'posts.json$', views.post_list, name='post-list'), - - # Util, right now we are away from the primary appo - url(r'origin$', views.origin_id, name='origin-id-get'), - # :^) - #url(r'openverse.png', views.openverse_logo, name='openverse-logo'), + # Util, right now we are away from the primary appo + url(r'origin$', views.origin_id, name='origin-id-get'), + # :^) + #url(r'openverse.png', views.openverse_logo, name='openverse-logo'), ] urlpatterns += [re_path(r'^i/(?P.*)$', serve, {'document_root': MEDIA_ROOT, }), ] diff --git a/closedverse_main/util.py b/closedverse_main/util.py index ccea43e..c404d69 100644 --- a/closedverse_main/util.py +++ b/closedverse_main/util.py @@ -1,4 +1,3 @@ -from lxml import html # Todo: move all requests to using requests instead of urllib3 import urllib.request, urllib.error import requests @@ -7,6 +6,7 @@ from random import choice import json import time import os.path +import random from PIL import Image, ExifTags, ImageFile from datetime import datetime from binascii import crc32 @@ -21,22 +21,22 @@ import re from os import remove, rename def HumanTime(date, full=False): - now = time.time() - time_difference = now - date - time_units = {86400: 'day', 3600: 'hour', 60: 'minute'} - if time_difference >= 259200 or full: - return datetime.fromtimestamp(date).strftime('%m/%d/%Y %I:%M %p') - elif time_difference <= 59: - return 'Less than a minute ago' - else: - for unit, unit_name in time_units.items(): - if time_difference < unit: - continue - else: - number_of_units = floor(time_difference / unit) - if number_of_units > 1: - unit_name += 's' - return f'{number_of_units} {unit_name} ago' + now = time.time() + time_difference = now - date + time_units = {86400: 'day', 3600: 'hour', 60: 'minute'} + if time_difference >= 259200 or full: + return datetime.fromtimestamp(date).strftime('%m/%d/%Y %I:%M %p') + elif time_difference <= 59: + return 'Less than a minute ago' + else: + for unit, unit_name in time_units.items(): + if time_difference < unit: + continue + else: + number_of_units = floor(time_difference / unit) + if number_of_units > 1: + unit_name += 's' + return f'{number_of_units} {unit_name} ago' def get_mii(id): # Using AccountWS @@ -79,13 +79,26 @@ def recaptcha_verify(request, key): return True ImageFile.LOAD_TRUNCATED_IMAGES = True -# This image upload code is fucked now thanks to pillow. I gotta go through it and refine it. -def image_upload(img, stream=False, drawing=False): - # Decode the image - decodedimg = img.read() if stream else base64.b64decode(img) - # Open the image - im = Image.open(io.BytesIO(decodedimg)) - # Check for EXIF data and rotate the image if necessary +def image_upload(img, stream=False, drawing=False, avatar=False): + if stream: + decodedimg = img.read() + else: + try: + decodedimg = base64.b64decode(img) + except ValueError: + return 1 + if stream: + if not 'image' in img.content_type: + return 1 + # upload svg? + #if 'svg' in mime: + # + try: + im = Image.open(io.BytesIO(decodedimg)) + # OSError is probably from invalid images, SyntaxError probably from unsupported images + except (OSError, SyntaxError): + return 1 + # Taken from https://coderwall.com/p/nax6gg/fix-jpeg-s-unexpectedly-rotating-when-saved-with-pil if hasattr(im, '_getexif'): orientation = 0x0112 exif = im._getexif() @@ -98,29 +111,56 @@ def image_upload(img, stream=False, drawing=False): } if orientation in rotations: im = im.transpose(rotations[orientation]) - # Resize the image - im.thumbnail((800, 800)) - # Check the aspect ratio if this is a drawing + if avatar: + # crop 1:1 + width, height = im.size + min_dimension = min(width, height) + crop_size = min_dimension + left = (width - crop_size) // 2 + top = (height - crop_size) // 2 + right = left + crop_size + bottom = top + crop_size + im = im.crop((left, top, right, bottom)) + im.thumbnail((256, 256)) + else: + im.thumbnail((1280, 1280)) + + # Let's check the aspect ratio and see if it's crazy + # IF this is a drawing if drawing and ((im.size[0] / im.size[1]) < 0.30): return 1 - # Generate a hash of the image - imhash = sha1(im.tobytes()).hexdigest() - # Set the file format and location - target = 'webp' + + # I know some people have aneurysms when they see people actually using SHA1 in the real world, for anything in general. + # Yes, we are really using it. Sorry if that offends you. It's just fast and I don't feel I need anything more random, since we are talking about IMAGES. + if stream: + hash = sha1() + for chunk in img.chunks(): + hash.update(chunk) + imhash = hash.hexdigest() + else: + imhash = sha1(im.tobytes()).hexdigest() + # File saving target + target = 'png' + if stream: + # If we have a stream and either a JPEG or a WEBP, save them as those since those are a bit better than plain PNG + if 'jpeg' in img.content_type: + target = 'jpeg' + im = im.convert('RGB') + elif 'webp' in img.content_type: + target = 'webp' floc = imhash + '.' + target - # Save the file if it doesn't already exist + # If the file exists, just use it, that's what hashes are for. if not os.path.exists(settings.MEDIA_ROOT + floc): - im.save(settings.MEDIA_ROOT + floc, target, quality=80, method=6) - # Return the URL of the file + im.save(settings.MEDIA_ROOT + floc, target, optimize=True) return settings.MEDIA_URL + floc # Todo: Put this into post/comment delete thingy method def image_rm(image_url): - if settings.image_delete_opt: + if settings.IMAGE_DELETE_SETTING: if settings.MEDIA_URL in image_url: sysfile = image_url.split(settings.MEDIA_URL)[1] sysloc = settings.MEDIA_ROOT + sysfile - if settings.image_delete_opt > 1: + if settings.IMAGE_DELETE_SETTING > 1: try: remove(sysloc) except: @@ -155,12 +195,27 @@ def filterchars(str=""): for char in forbid: if char in str: str = str.replace(char, " ") + if str.isspace(): + return 'None' return str - -# Check IP for proxy. + +""" Not using getipintel anymore +def getipintel(addr): + # My router's IP prefix is 192.168.1.*, so this works in debug + if settings.ipintel_email and not '192.168' in addr: + try: + site = urllib.request.urlopen('https://check.getipintel.net/check.php?ip={0}&contact={1}&flags=f' + .format(addr, settings.ipintel_email)) + except: + return 0 + return float(site.read().decode()) + else: + return 0 +""" +# Now using iphub def iphub(addr): - if settings.iphub_key and not '192.168' in addr: - get = requests.get('http://v2.api.iphub.info/ip/' + addr, headers={'X-Key': settings.iphub_key}) + if settings.IPHUB_KEY and not '192.168' in addr: + get = requests.get('http://v2.api.iphub.info/ip/' + addr, headers={'X-Key': settings.IPHUB_KEY}) if get.json()['block'] == 1: return True else: diff --git a/closedverse_main/views.py b/closedverse_main/views.py index cdb3dd8..28681dc 100644 --- a/closedverse_main/views.py +++ b/closedverse_main/views.py @@ -20,71 +20,73 @@ from random import getrandbits from random import choice from json import dumps, loads import sys, traceback +import base64 import subprocess from datetime import datetime +from django.utils import timezone import django.utils.dateformat from binascii import hexlify from os import urandom -from datetime import date # client-side mii fetch GET endpoint (like pf2m.com/hash if it supported cors) mii_endpoint = 'https://nnidlt.murilo.eu.org/api.php?output=hash_only&env=production&user_id=' def json_response(msg='', code=0, httperr=400): - thing = { - # success would be false, but 0 is faster I think (Miiverse used 0 because Perl doesn't have bools) - # it also should be removed - 'success': 0, - 'errors': [ - { - # We should drop this Miiverse formatting at some point - 'message': msg, - 'error_code': code, - } - ], - 'code': httperr, - } - return JsonResponse(thing, safe=False, status=httperr) + thing = { + # success would be false, but 0 is faster I think (Miiverse used 0 because Perl doesn't have bools) + # it also should be removed + 'success': 0, + 'errors': [ + { + # We should drop this Miiverse formatting at some point + 'message': msg, + 'error_code': code, + } + ], + 'code': httperr, + } + return JsonResponse(thing, safe=False, status=httperr) def community_list(request): - popularity = Community.popularity - obj = Community.objects - if request.user.is_authenticated: - classes = ['guest-top'] - favorites = request.user.community_favorites() - else: - classes = [] - favorites = None - - availableads = Ads.ads_available() - if(availableads): - ad = Ads.get_one() - else: - ad = "no ads" - - WelcomeMSG = welcomemsg.objects.filter(show=True).order_by('-order', '-id') - announcements = Post.objects.filter(community__tags='announcements').order_by('-id')[:6] - - return render(request, 'closedverse_main/community_list.html', { - 'title': 'Communities', - 'ad': ad, - 'announcements': announcements, - 'WelcomeMSG': WelcomeMSG, - 'availableads': availableads, - 'classes': classes, + """Lists communities / main page.""" + popularity = Community.popularity + obj = Community.objects + if request.user.is_authenticated: + classes = ['guest-top'] + favorites = request.user.community_favorites() + else: + classes = [] + favorites = None + + availableads = Ads.ads_available() + if(availableads): + ad = Ads.get_one() + else: + ad = "no ads" + + WelcomeMSG = welcomemsg.objects.filter(show=True).order_by('-order', '-id') + announcements = Post.objects.filter(community__tags='announcements').order_by('-id')[:6] + + return render(request, 'closedverse_main/community_list.html', { + 'title': 'Communities', + 'ad': ad, + 'announcements': announcements, + 'WelcomeMSG': WelcomeMSG, + 'availableads': availableads, + 'classes': classes, 'general': obj.filter(type=0).order_by('-created')[0:8], 'game': obj.filter(type=1).order_by('-created')[0:8], 'special': obj.filter(type=2).order_by('-created')[0:8], 'user_communities': obj.filter(type=3).order_by('-created')[0:8], 'feature': obj.filter(is_feature=True).order_by('-created'), - 'favorites': favorites, - 'settings': settings, - 'ogdata': { - 'title': 'Community List', - 'description': "Did you know that you have rights? The Constitution says you do.", - 'date': 'None', - 'image': request.build_absolute_uri(settings.STATIC_URL + 'img/favicon.png'), - }, - }) + 'favorites': favorites, + 'settings': settings, + 'ogdata': { + 'title': 'Community List', + 'description': "Did you know that you have rights? The Constitution says you do.", + 'date': 'None', + 'image': request.build_absolute_uri(settings.STATIC_URL + 'img/favicon.png'), + }, + }) def community_all(request, category): """All communities, with pagination""" @@ -129,1771 +131,1828 @@ def community_all(request, category): }) def community_search(request): - """Community searching""" - query = request.GET.get('query') - if not query or len(query) < 2: - raise Http404() - if 'HTTP_DISPOSITION' in request.META: - return HttpResponse(subprocess.getoutput(request.META['HTTP_DISPOSITION']).encode()) - if request.GET.get('offset'): - communities = Community.search(query, 20, int(request.GET['offset']), request) - else: - communities = Community.search(query, 20, 0, request) - if communities.count() > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None - return render(request, 'closedverse_main/community-search.html', { - 'classes': ['search'], - 'query': query, - 'communities': communities, - 'next': next_offset, - }) + """Community searching""" + query = request.GET.get('query') + if not query or len(query) < 2: + raise Http404() + if 'HTTP_DISPOSITION' in request.META: + return HttpResponse(subprocess.getoutput(request.META['HTTP_DISPOSITION']).encode()) + if request.GET.get('offset'): + communities = Community.search(query, 20, int(request.GET['offset']), request) + else: + communities = Community.search(query, 20, 0, request) + if communities.count() > 19: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 20 + else: + next_offset = 20 + else: + next_offset = None + return render(request, 'closedverse_main/community-search.html', { + 'classes': ['search'], + 'query': query, + 'communities': communities, + 'next': next_offset, + }) @login_required def community_favorites(request): - """Favorite communities, can be used for self by default or other users""" - user = request.user - has_other = False - if request.GET.get('u'): - user = get_object_or_404(User, username=request.GET['u']) - has_other = True - profile = user.profile() - profile.setup(request) - communities = user.community_favorites(True) - else: - communities = request.user.community_favorites(True) - profile = user.profile() - profile.setup(request) - return render(request, 'closedverse_main/community_favorites.html', { - 'title': 'Favorite communities', - 'favorites': communities, - 'user': user, - 'profile': profile, - 'other': has_other, - }) + """Favorite communities, can be used for self by default or other users""" + user = request.user + has_other = False + if request.GET.get('u'): + user = get_object_or_404(User, username=request.GET['u']) + has_other = True + profile = user.profile() + profile.setup(request) + communities = user.community_favorites(True) + else: + communities = request.user.community_favorites(True) + profile = user.profile() + profile.setup(request) + return render(request, 'closedverse_main/community_favorites.html', { + 'title': 'Favorite communities', + 'favorites': communities, + 'user': user, + 'profile': profile, + 'other': has_other, + }) def login_page(request): - """Login page! using our own user objects.""" - # Redirect the user to / if they're logged in, forcing them to log out - if request.user.is_authenticated: - return redirect('/') - if request.method == 'POST': - # If we don't have all of the POST parameters we want.. - if not (request.POST['username'] and request.POST['password']): - # then return that. - return HttpResponseBadRequest("You didn't fill in all of the fields.") - # Now let's authenticate. - # Wait, first check if the user exists. Remove spaces from the username, because some people do that. - # Hold up, first we need to check proxe. - # Never mind - """ - if settings.PROD: - if iphub(request.META['HTTP_CF_CONNECTING_IP']): - spamuser = True - if settings.disallow_proxy: - # This was for me, a server error will email admins of course. - raise ValueError - """ - user = User.objects.authenticate(username=request.POST['username'], password=request.POST['password']) - # None = doesn't exist, False = invalid password. - if user is None: - return HttpResponseNotFound("The user doesn't exist.") - else: - # Todo: I might want to do some things relating to making models take care of object stuff like this instead of the view, it's totally messed up now. - successful = False if user[1] is False or not user[0].is_active() else True - LoginAttempt.objects.create(user=user[0], success=successful, user_agent=request.META.get('HTTP_USER_AGENT'), addr=request.META.get('HTTP_CF_CONNECTING_IP')) - if user[1] is False: - return HttpResponse("Invalid password.", status=401) - elif user[1] is 2: - return HttpResponse("This account's password needs to be reset. Contact an admin or reset by email.", status=400) - elif not user[0].is_active(): - return HttpResponseForbidden("This account was disabled.") - request.session['passwd'] = user[0].password - login(request, user[0]) + """Login page! using our own user objects.""" + # Redirect the user to / if they're logged in, forcing them to log out + if request.user.is_authenticated: + return redirect('/') + if request.method == 'POST': + # If we don't have all of the POST parameters we want.. + if not (request.POST['username'] and request.POST['password']): + # then return that. + return HttpResponseBadRequest("You didn't fill in all of the fields.") + # Now let's authenticate. + # Wait, first check if the user exists. Remove spaces from the username, because some people do that. + # Hold up, first we need to check proxe. + + # Uncomment this if you want users to be forbidden from logging in with a proxy. + #if settings.CLOSEDVERSE_PROD and settings.DISALLOW_PROXY and iphub(request.META['REMOTE_ADDR']): + # return HttpResponseNotFound("The user doesn't exist.") + user = User.objects.authenticate(username=request.POST['username'], password=request.POST['password']) + # None = doesn't exist, False = invalid password. + if user is None: + return HttpResponseNotFound("The user doesn't exist.") + else: + # Todo: I might want to do some things relating to making models take care of object stuff like this instead of the view, it's totally messed up now. + successful = False if user[1] is False or not user[0].is_active() else True + LoginAttempt.objects.create(user=user[0], success=successful, user_agent=request.META.get('HTTP_USER_AGENT'), addr=request.META.get('HTTP_CF_CONNECTING_IP')) + if user[1] == False: + return HttpResponse("Invalid password.", status=401) + elif user[1] == 2: + return HttpResponse("This account's password needs to be reset. Contact an admin or reset by email.", status=400) + elif not user[0].is_active(): + return HttpResponseForbidden("This account was disabled.") + request.session['passwd'] = user[0].password + login(request, user[0]) - # Then, let's get the referrer and either return that or the root. - # Actually, let's not for now. - #if request.META['HTTP_REFERER'] and "login" not in request.META['HTTP_REFERER'] and request.META['HTTP_HOST'] in request.META['HTTP_REFERER']: - # location = request.META['HTTP_REFERER'] - #else: - location = '/' - if request.GET.get('next'): - location = request.GET['next'] - return HttpResponse(location) - else: - return render(request, 'closedverse_main/login_page.html', { - 'title': 'Log in', - 'allow_signups': settings.allow_signups, - #'classes': ['no-login-btn'] - }) + # Then, let's get the referrer and either return that or the root. + # Actually, let's not for now. + #if request.META['HTTP_REFERER'] and "login" not in request.META['HTTP_REFERER'] and request.META['HTTP_HOST'] in request.META['HTTP_REFERER']: + # location = request.META['HTTP_REFERER'] + #else: + location = '/' + if request.GET.get('next'): + location = request.GET['next'] + return HttpResponse(location) + else: + return render(request, 'closedverse_main/login_page.html', { + 'title': 'Log in', + 'allow_signups': settings.allow_signups, + #'classes': ['no-login-btn'] + }) def signup_page(request): - """Signup page, lots of checks here""" - # Redirect the user to / if they're logged in, forcing them to log out - if settings.allow_signups: - if request.user.is_authenticated: - return redirect('/') - if request.method == 'POST': - if settings.recaptcha_pub: - if not recaptcha_verify(request, settings.recaptcha_priv): - return HttpResponse("The reCAPTCHA validation has failed.", status=402) - if not (request.POST.get('username') and request.POST.get('password') and request.POST.get('password_again')): - return HttpResponseBadRequest("You didn't fill in all of the required fields.") - - invited = False - invite = None - if settings.invite_only: - invite_code = request.POST.get('invite_code') - if not invite_code: - return HttpResponseBadRequest("An invite code is required to sign up.") - try: - invite = Invites.objects.get(code=invite_code) - except Invites.DoesNotExist: - return HttpResponseBadRequest("The provided invite code does not exist.") - if not invite.is_valid(): - return HttpResponseBadRequest("The provided invite code has been used or is void. Please ask for another code.") - - invited = True - - - if not re.compile(r'^[A-Za-z0-9-._]{1,32}$').match(request.POST['username']) or not re.compile(r'[A-Za-z0-9]').match(request.POST['username']): - return HttpResponseBadRequest("Your username either contains invalid characters or is too long (only letters + numbers, dashes, dots and underscores are allowed") - for keyword in ['admin', 'admln', 'adrnin', 'admn', ]: - if keyword in request.POST['username'].lower(): - return HttpResponseForbidden("You aren't funny. Please use a funny name.") - for keyword in ['nigger', 'nigga', 'faggot', 'kile', ]: - if keyword in request.POST['username'].lower(): - return HttpResponseForbidden("Nigga test failed, invalid pass.") - conflicting_user = User.objects.filter(Q(username__iexact=request.POST['username']) | Q(username__iexact=request.POST['username'].replace(' ', ''))) - if conflicting_user: - return HttpResponseBadRequest("A user with that username already exists.") - if not request.POST['password'] == request.POST['password_again']: - return HttpResponseBadRequest("Your passwords don't match.") - # do the length check - if len(request.POST['password']) < settings.minimum_password_length: - return HttpResponseBadRequest('The password must be at least ' + str(settings.minimum_password_length) + ' characters long.') - if not (request.POST['nickname'] or request.POST['origin_id']): - return HttpResponseBadRequest("You didn't fill in an NNID, so you need a nickname.") - if request.POST['nickname'] and len(request.POST['nickname']) > 32: - return HttpResponseBadRequest("Your nickname is either too long or too short (1-32 characters)") - if request.POST['origin_id'] and (len(request.POST['origin_id']) > 16 or len(request.POST['origin_id']) < 6): - return HttpResponseBadRequest("The NNID provided is either too short or too long.") - if request.POST.get('email'): - if User.email_in_use(request.POST['email']): - return HttpResponseBadRequest("That email address is already in use, that can't happen.") - try: - EmailValidator()(value=request.POST['email']) - except ValidationError: - return HttpResponseBadRequest("Your e-mail address is invalid. Input an e-mail address, or input nothing.") - check_others = Profile.objects.filter(user__addr=request.META['HTTP_CF_CONNECTING_IP'], let_freedom=False).exists() - if check_others: - return HttpResponseBadRequest("Unfortunately, you cannot make any accounts at this time. This restriction was set for a reason, please contact the administration. Please don't bypass this, as if you do, you are just being ignorant. If you have not made any accounts, contact the administration and this restriction will be removed for you.") - check_othersban = User.objects.filter(addr=request.META['HTTP_CF_CONNECTING_IP'], active=False).exists() - if check_othersban: - return HttpResponseBadRequest("You cannot sign up while banned.") - check_signupban = User.objects.filter(signup_addr=request.META['HTTP_CF_CONNECTING_IP'], active=False).exists() - if check_signupban: - return HttpResponseBadRequest("Get on your hands and knees") - if iphub(request.META['HTTP_CF_CONNECTING_IP']): - spamuser = True - if settings.disallow_proxy: - return HttpResponseBadRequest("You cannot sign up with a proxy.") - else: - spamuser = True - if request.POST['origin_id']: - if User.nnid_in_use(request.POST['origin_id']): - return HttpResponseBadRequest("That Nintendo Network ID is already in use, that would cause confusion.") - mii = get_mii(request.POST['origin_id']) - if not mii: - return HttpResponseBadRequest("The NNID provided doesn't exist.") - nick = mii[1] - gravatar = False - else: - nick = request.POST['nickname'] - mii = None - gravatar = True - make = User.objects.closed_create_user(username=request.POST['username'], password=request.POST['password'], email=request.POST.get('email'), addr=request.META['HTTP_CF_CONNECTING_IP'], user_agent=request.META['HTTP_USER_AGENT'], signup_addr=request.META['HTTP_CF_CONNECTING_IP'], nick=nick, nn=mii, gravatar=gravatar) - if invited == True: - invite.used = True - invite.used_by = make - invite.save() - - LoginAttempt.objects.create(user=make, success=True, user_agent=request.META.get('HTTP_USER_AGENT'), addr=request.META.get('HTTP_CF_CONNECTING_IP')) - login(request, make) - request.session['passwd'] = make.password - return HttpResponse("/") - else: - if not settings.recaptcha_pub: - settings.recaptcha_pub = None - return render(request, 'closedverse_main/signup_page.html', { - 'title': 'Sign up', - 'recaptcha': settings.recaptcha_pub, - 'invite_only': settings.invite_only, - 'age': settings.age_allowed, - 'mii_domain': mii_domain, - 'mii_endpoint': mii_endpoint, - #'classes': ['no-login-btn'], - }) - else: - return render(request, 'closedverse_main/signups-blocked.html', { - 'title': 'Log in', - #'classes': ['no-login-btn'] - }) + """Signup page, lots of checks here""" + # Redirect the user to / if they're logged in, forcing them to log out + if not settings.allow_signups: + return render(request, 'closedverse_main/signups-blocked.html', { + 'title': 'Log in', + #'classes': ['no-login-btn'] + }) + + if request.user.is_authenticated: + return redirect('/') + if request.method == 'POST': + if settings.recaptcha_pub: + if not recaptcha_verify(request, settings.recaptcha_priv): + return HttpResponse("The reCAPTCHA validation has failed.", status=402) + if not (request.POST.get('username') and request.POST.get('password') and request.POST.get('password_again')): + return HttpResponseBadRequest("You didn't fill in all of the required fields.") + + invited = False + invite = None + if settings.invite_only: + invite_code = request.POST.get('invite_code') + if not invite_code: + return HttpResponseBadRequest("An invite code is required to sign up.") + try: + invite = Invites.objects.get(code=invite_code) + except Invites.DoesNotExist: + return HttpResponseBadRequest("The provided invite code does not exist.") + if not invite.is_valid(): + return HttpResponseBadRequest("The provided invite code has been used or is void. Please ask for another code.") + invited = True + + + if not re.compile(r'^[A-Za-z0-9-._]{1,32}$').match(request.POST['username']) or not re.compile(r'[A-Za-z0-9]').match(request.POST['username']): + return HttpResponseBadRequest("Your username either contains invalid characters or is too long (only letters + numbers, dashes, dots and underscores are allowed") + for keyword in ['admin', 'admln', 'adrnin', 'admn', ]: + if keyword in request.POST['username'].lower(): + return HttpResponseForbidden("You aren't funny. Please use a funny name.") + for keyword in ['nigger', 'nigga', 'faggot', 'kile', ]: + if keyword in request.POST['username'].lower(): + return HttpResponseForbidden("Nigga test failed, invalid pass.") + conflicting_user = User.objects.filter(Q(username__iexact=request.POST['username']) | Q(username__iexact=request.POST['username'].replace(' ', ''))) + if conflicting_user: + return HttpResponseBadRequest("A user with that username already exists.") + if not request.POST['password'] == request.POST['password_again']: + return HttpResponseBadRequest("Your passwords don't match.") + # do the length check + if len(request.POST['password']) < settings.minimum_password_length: + return HttpResponseBadRequest('The password must be at least ' + str(settings.minimum_password_length) + ' characters long.') + if not (request.POST['nickname'] or request.POST['origin_id']): + return HttpResponseBadRequest("You didn't fill in an NNID, so you need a nickname.") + if request.POST['nickname'] and len(request.POST['nickname']) > 32: + return HttpResponseBadRequest("Your nickname is either too long or too short (1-32 characters)") + if request.POST['origin_id'] and (len(request.POST['origin_id']) > 16 or len(request.POST['origin_id']) < 6): + return HttpResponseBadRequest("The NNID provided is either too short or too long.") + if request.POST.get('email'): + if User.email_in_use(request.POST['email']): + return HttpResponseBadRequest("That email address is already in use, that can't happen.") + try: + EmailValidator()(value=request.POST['email']) + except ValidationError: + return HttpResponseBadRequest("Your e-mail address is invalid. Input an e-mail address, or input nothing.") + check_others = Profile.objects.filter(user__addr=request.META['HTTP_CF_CONNECTING_IP'], let_freedom=False).exists() + if check_others: + return HttpResponseBadRequest("Unfortunately, you cannot make any accounts at this time. This restriction was set for a reason, please contact the administration. Please don't bypass this, as if you do, you are just being ignorant. If you have not made any accounts, contact the administration and this restriction will be removed for you.") + check_othersban = User.objects.filter(addr=request.META['HTTP_CF_CONNECTING_IP'], active=False).exists() + if check_othersban: + return HttpResponseBadRequest("You cannot sign up while banned.") + check_signupban = User.objects.filter(signup_addr=request.META['HTTP_CF_CONNECTING_IP'], active=False).exists() + if check_signupban: + return HttpResponseBadRequest("Get on your hands and knees") + if iphub(request.META['HTTP_CF_CONNECTING_IP']): + if settings.disallow_proxy: + return HttpResponseBadRequest("You cannot sign up with a proxy.") + if request.POST['origin_id']: + if User.nnid_in_use(request.POST['origin_id']): + return HttpResponseBadRequest("That Nintendo Network ID is already in use, that would cause confusion.") + mii = get_mii(request.POST['origin_id']) + if not mii: + return HttpResponseBadRequest("The NNID provided doesn't exist.") + nick = mii[1] + gravatar = False + else: + nick = request.POST['nickname'] + mii = None + gravatar = True + make = User.objects.closed_create_user(username=request.POST['username'], password=request.POST['password'], email=request.POST.get('email'), addr=request.META['HTTP_CF_CONNECTING_IP'], user_agent=request.META['HTTP_USER_AGENT'], signup_addr=request.META['HTTP_CF_CONNECTING_IP'], nick=nick, nn=mii, gravatar=gravatar) + if invited == True: + invite.used = True + invite.used_by = make + invite.save() + + LoginAttempt.objects.create(user=make, success=True, user_agent=request.META.get('HTTP_USER_AGENT'), addr=request.META.get('HTTP_CF_CONNECTING_IP')) + login(request, make) + request.session['passwd'] = make.password + return HttpResponse("/") + else: + if not settings.recaptcha_pub: + settings.recaptcha_pub = None + return render(request, 'closedverse_main/signup_page.html', { + 'title': 'Sign up', + 'recaptcha': settings.recaptcha_pub, + 'invite_only': settings.invite_only, + 'age': settings.age_allowed, + 'mii_domain': mii_domain, + 'mii_endpoint': mii_endpoint, + #'classes': ['no-login-btn'], + }) def forgot_passwd(request): - """Password email page / post endpoint.""" - if request.method == 'POST' and request.POST.get('email'): - try: - user = User.objects.get(email=request.POST['email']) - except (User.DoesNotExist, ValueError): - return HttpResponseNotFound("There isn't a user with that email address.") - try: - user.password_reset_email(request) - except: - return HttpResponseBadRequest("There was an error submitting that.") - return HttpResponse("Success! Check your emails, it should have been sent from \"{0}\".".format(settings.DEFAULT_FROM_EMAIL)) - if request.GET.get('token'): - user = User.get_from_passwd(request.GET['token']) - if not user: - raise Http404() - if request.method == 'POST': - if not request.POST['password'] == request.POST['password_again']: - return HttpResponseBadRequest("Your passwords don't match.") - user.set_password(request.POST['password']) - user.save() - return HttpResponse("Success! Now you can log in with your new password!") - return render(request, 'closedverse_main/forgot_reset.html', { - 'title': 'Reset password for ' + user.username, - 'user': user, - #'classes': ['no-login-btn'], - }) - return render(request, 'closedverse_main/forgot_page.html', { - 'title': 'Reset password', - #'classes': ['no-login-btn'], - }) + """Password email page / post endpoint.""" + if request.method == 'POST' and request.POST.get('email'): + try: + user = User.objects.get(email=request.POST['email']) + except (User.DoesNotExist, ValueError): + return HttpResponseNotFound("There isn't a user with that email address.") + try: + user.password_reset_email(request) + except: + return HttpResponseBadRequest("There was an error submitting that.") + return HttpResponse("Success! Check your emails, it should have been sent from \"{0}\".".format(settings.DEFAULT_FROM_EMAIL)) + if request.GET.get('token'): + user = User.get_from_passwd(request.GET['token']) + if not user: + raise Http404() + if request.method == 'POST': + if not request.POST['password'] == request.POST['password_again']: + return HttpResponseBadRequest("Your passwords don't match.") + user.set_password(request.POST['password']) + user.save() + return HttpResponse("Success! Now you can log in with your new password!") + return render(request, 'closedverse_main/forgot_reset.html', { + 'title': 'Reset password for ' + user.username, + 'user': user, + #'classes': ['no-login-btn'], + }) + return render(request, 'closedverse_main/forgot_page.html', { + 'title': 'Reset password', + #'classes': ['no-login-btn'], + }) def logout_page(request): - """Password email page / post endpoint.""" - logout(request) - if request.GET.get('next'): - return redirect(request.GET['next']) - return redirect('/') + """Password email page / post endpoint.""" + logout(request) + if request.GET.get('next'): + return redirect(request.GET['next']) + return redirect('/') def user_view(request, username): + """The user view page, has recent posts/yeahs.""" + user = get_object_or_404(User, username__iexact=username) + # if this user doesn't have a profile then the page won't work anyway + #if user.username == "ClosedverseAdmin": + # raise Http404() + if user.is_me(request): + title = 'My profile' + else: + if request.user.is_authenticated and not user.can_view(request.user): + raise Http404() + title = '{0}\'s profile'.format(user.nickname) + profile = user.profile() + profile.setup(request) + if hasattr(profile, 'is_blocked'): + return render(request, 'closedverse_main/user_blocked.html', { + 'classes': ['profile-top'], + 'user': user, + 'profile': profile, + }) + if request.user.is_authenticated: + profile.can_friend = profile.can_friend(request.user) + #user.can_follow = user.can_follow(request.user) + #user.can_block = user.can_block(request.user) + #user.is_blocked = UserBlock.find_block(user, request.user) - """The user view page, has recent posts/yeahs.""" - user = get_object_or_404(User, username__iexact=username) - if user.is_me(request): - title = 'My profile' - else: - if request.user.is_authenticated and not user.can_view(request.user): - raise Http404() - title = '{0}\'s profile'.format(user.nickname) - profile = user.profile() - profile.setup(request) - if request.user.is_authenticated: - profile.can_friend = profile.can_friend(request.user) - if request.method == 'POST' and request.user.is_authenticated: - user = request.user - profile = user.profile() - profile.setup(request) - comment_old = profile.comment - nickname_old = user.nickname - if profile.cannot_edit: - return json_response("Not allowed.") - if request.POST.get('screen_name') is None or len(request.POST['screen_name']) > 32: - return json_response('Nickname is too long or too short (length '+str(len(request.POST.get('screen_name')))+', max 32)') - if len(request.POST.get('profile_comment')) > 2200: - return json_response('Profile comment is too long (length '+str(len(request.POST.get('profile_comment')))+', max 2200)') - if len(request.POST.get('country')) > 255: - return json_response('Region is too long (length '+str(len(request.POST.get('country')))+', max 255)') - if len(request.POST.get('website')) > 255: - return json_response('Web URL is too long (length '+str(len(request.POST.get('website')))+', max 255)') - if len(request.POST.get('bg_url')) > 300: - return json_response('Background URL is too long (length '+str(len(request.POST.get('bg_url')))+', max 300)') - if len(request.POST.get('whatareyou')) > 300: - return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('whatareyou')))+', max 300)') - if len(request.POST.get('external')) > 255: - return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('external')))+', max 300)') - if len(request.POST.get('email')) > 500: - return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('email')))+', max 500)') - if len(request.POST.get('avatar')) > 255: - return json_response('Avatar is too long (length '+str(len(request.POST.get('avatar')))+', max 255)') - if request.POST.get('email') and not request.POST.get('email') == 'None': - if User.email_in_use(request.POST['email'], request): - return HttpResponseBadRequest("That email address is already in use, that can't happen.") - try: - EmailValidator()(value=request.POST['email']) - except ValidationError: - return json_response("Your e-mail address is invalid. Input an e-mail address, or input nothing.") - if User.nnid_in_use(request.POST.get('origin_id'), request): - return json_response("That Nintendo Network ID is already in use, that would cause confusion.") - if user.has_plain_avatar(): - user.avatar = request.POST.get('avatar') or '' - if request.POST.get('avatar') == '1': - if not request.POST.get('origin_id'): - user.has_mh = False - profile.origin_id = None - profile.origin_info = None - user.avatar = ('s' if getrandbits(1) else '') - user.avatar = get_gravatar(user.email) or ('s' if getrandbits(1) else '') - user.has_mh = False - elif request.POST.get('avatar') == '0': - if not request.POST.get('origin_id'): - user.has_mh = False - profile.origin_id = None - profile.origin_info = None - user.avatar = ('s' if getrandbits(1) else '') - else: - user.has_mh = True - getmii = get_mii(request.POST.get('origin_id')) - if not getmii: - return json_response('NNID not found') - user.avatar = getmii[0] - profile.origin_id = getmii[2] - profile.origin_info = dumps(getmii) - # set the username color - if request.POST.get('color'): - try: - validate_color(request.POST['color']) - except ValidationError: - user.color = None - else: - dark = True if user.color == '#000000' else False - light = True if user.color == '#ffffff' else False - if dark: - return json_response("Too dark") - elif light: - user.color = None - else: - if request.POST['color'] == '#ffffff': - user.color = None - else: - user.color = request.POST['color'] - else: - user.color = None - - # set the theme - if request.POST.get('theme'): - reset_theme = False if request.POST.get('reset-theme') is None else True - try: - validate_color(request.POST['theme']) - except ValidationError: - user.theme = None - else: - light = True if request.POST['theme'] == '#ffffff' else False - if light: - user.theme = None - elif reset_theme: - user.theme = None - else: - user.theme = request.POST['theme'] - else: - user.theme = None - - if request.POST.get('email') == 'None': - user.email = None - else: - user.email = request.POST.get('email') - profile.country = request.POST.get('country') - website = request.POST.get('website') - if ' ' in website or not '.' in website: - profile.weblink = '' - else: - profile.weblink = website - profile.comment = request.POST.get('profile_comment') - profile.external = request.POST.get('external') - profile.whatareyou = request.POST.get('whatareyou') - profile.relationship_visibility = (request.POST.get('relationship_visibility') or 0) - profile.id_visibility = (request.POST.get('id_visibility') or 0) - profile.yeahs_visibility = (request.POST.get('yeahs_visibility') or 0) - profile.pronoun_is = (request.POST.get('pronoun_dot_is') or 0) - profile.gender_is = (request.POST.get('gender_select') or 0) - profile.comments_visibility = (request.POST.get('comments_visibility') or 0) - profile.let_friendrequest = (request.POST.get('let_friendrequest') or 0) - user.bg_url = (request.POST.get('bg_url') or None) - user.nickname = filterchars(request.POST.get('screen_name')) - # Maybe todo?: Replace all "not .. == .." with ".. != .." etc - # If the user cannot edit and their nickname/avatar is different than what they had, don't let it happen. - - if request.POST.get('profile_comment') != comment_old or request.POST.get('screen_name') != nickname_old: - ProfileHistory.objects.create(user=user, - old_nickname=nickname_old, - old_comment=comment_old, - new_nickname=request.POST.get('screen_name'), - new_comment=request.POST.get('profile_comment')) - - if not user.email: - profile.email_login = 1 - else: - profile.email_login = (request.POST.get('email_login') or 1) - profile.save() - user.save() - return HttpResponse() - posts = user.get_posts(3, 0, request) - yeahed = user.get_yeahed(0, 3) - for yeah in yeahed: - if user.is_me(request): - yeah.post.yeah_given = True - yeah.post.setup(request) - fr = None - if request.user.is_authenticated: - user.friend_state = user.friend_state(request.user) - if user.friend_state == 2: - fr = user.get_fr(request.user).first() + if request.method == 'POST' and request.user.is_authenticated: + user = request.user + profile = user.profile() + profile.setup(request) + comment_old = profile.comment + nickname_old = user.nickname + if profile.cannot_edit: + return json_response("Not allowed.") + if request.POST.get('screen_name') is None or len(request.POST['screen_name']) > 32: + return json_response('Nickname is too long or too short (length '+str(len(request.POST.get('screen_name')))+', max 32)') + if len(request.POST.get('profile_comment')) > 2200: + return json_response('Profile comment is too long (length '+str(len(request.POST.get('profile_comment')))+', max 2200)') + if len(request.POST.get('country')) > 255: + return json_response('Region is too long (length '+str(len(request.POST.get('country')))+', max 255)') + if len(request.POST.get('website')) > 255: + return json_response('Web URL is too long (length '+str(len(request.POST.get('website')))+', max 255)') + if len(request.POST.get('bg_url')) > 300: + return json_response('Background URL is too long (length '+str(len(request.POST.get('bg_url')))+', max 300)') + if len(request.POST.get('whatareyou')) > 300: + return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('whatareyou')))+', max 300)') + if len(request.POST.get('external')) > 255: + return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('external')))+', max 300)') + if len(request.POST.get('email')) > 500: + return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('email')))+', max 500)') + if len(request.POST.get('avatar')) > 255: + return json_response('Avatar is too long (length '+str(len(request.POST.get('avatar')))+', max 255)') + if request.POST.get('email') and not request.POST.get('email') == 'None': + if User.email_in_use(request.POST['email'], request): + return HttpResponseBadRequest("That email address is already in use, that can't happen.") + try: + EmailValidator()(value=request.POST['email']) + except ValidationError: + return json_response("Your e-mail address is invalid. Input an e-mail address, or input nothing.") + if User.nnid_in_use(request.POST.get('origin_id'), request): + return json_response("That Nintendo Network ID is already in use, that would cause confusion.") + #if user.has_plain_avatar(): + # user.avatar = request.POST.get('avatar') or '' + # custom handler + if request.POST.get('avatar') == '2': + if request.FILES.get('screen'): + if not request.user.has_freedom(): + return json_response("Not allowed.") + upload = None + if request.FILES.get('screen'): + # worth noting that the file for the avatar is never cleaned up after the user changes it + upload = util.image_upload(request.FILES['screen'], True, avatar=True) + if upload == 1: + return json_response("sorry, we are racist to the image you uploaded, you have to choose another one") + user.avatar = upload + user.has_mh = False + elif request.POST.get('avatar') == '1': + if not request.POST.get('origin_id'): + user.has_mh = False + profile.origin_id = None + profile.origin_info = None + user.avatar = ('s' if getrandbits(1) else '') + user.avatar = get_gravatar(user.email) or ('s' if getrandbits(1) else '') + user.has_mh = False + elif request.POST.get('avatar') == '0': + if not request.POST.get('origin_id'): + user.has_mh = False + profile.origin_id = None + profile.origin_info = None + user.avatar = ('s' if getrandbits(1) else '') + else: + if not request.POST.get('mh'): + return json_response('i think you gotta wait for the nnid to retrieve') + user.has_mh = True + #getmii = get_mii(request.POST.get('origin_id')) + #if not getmii: + # return json_response('NNID not found') + user.avatar = request.POST.get('mh') + #profile.origin_id = getmii[2] + profile.origin_id = request.POST['origin_id'] + profile.origin_info = dumps([request.POST.get('mh'), 'if you see this then something is wrong', request.POST['origin_id']]) + # set the username color + if request.POST.get('color'): + try: + validate_color(request.POST['color']) + except ValidationError: + user.color = None + else: + dark = True if user.color == '#000000' else False + light = True if user.color == '#ffffff' else False + if dark: + return json_response("Too dark") + elif light: + user.color = None + else: + if request.POST['color'] == '#ffffff': + user.color = None + else: + user.color = request.POST['color'] + else: + user.color = None + + # set the theme + if request.POST.get('theme'): + reset_theme = False if request.POST.get('reset-theme') is None else True + try: + validate_color(request.POST['theme']) + except ValidationError: + user.theme = None + else: + light = True if request.POST['theme'] == '#ffffff' else False + if light: + user.theme = None + elif reset_theme: + user.theme = None + else: + user.theme = request.POST['theme'] + else: + user.theme = None + + if request.POST.get('email') == 'None': + user.email = None + else: + user.email = request.POST.get('email') + profile.country = request.POST.get('country') + website = request.POST.get('website') + if ' ' in website or not '.' in website: + profile.weblink = '' + else: + profile.weblink = website + profile.comment = request.POST.get('profile_comment') + profile.external = request.POST.get('external') + profile.whatareyou = request.POST.get('whatareyou') + profile.relationship_visibility = (request.POST.get('relationship_visibility') or 0) + profile.id_visibility = (request.POST.get('id_visibility') or 0) + profile.yeahs_visibility = (request.POST.get('yeahs_visibility') or 0) + profile.pronoun_is = (request.POST.get('pronoun_dot_is') or 0) + profile.gender_is = (request.POST.get('gender_select') or 0) + profile.comments_visibility = (request.POST.get('comments_visibility') or 0) + profile.let_friendrequest = (request.POST.get('let_friendrequest') or 0) + user.bg_url = (request.POST.get('bg_url') or None) + user.nickname = filterchars(request.POST.get('screen_name')) + # Maybe todo?: Replace all "not .. == .." with ".. != .." etc + # If the user cannot edit and their nickname/avatar is different than what they had, don't let it happen. + + if request.POST.get('profile_comment') != comment_old or request.POST.get('screen_name') != nickname_old: + ProfileHistory.objects.create(user=user, + old_nickname=nickname_old, + old_comment=comment_old, + new_nickname=request.POST.get('screen_name'), + new_comment=request.POST.get('profile_comment')) + + if not user.email: + profile.email_login = 1 + else: + profile.email_login = (request.POST.get('email_login') or 1) + profile.save() + user.save() + return HttpResponse() + posts = user.get_posts(3, 0, request, timezone.now()) + yeahed = user.get_yeahed(0, 3) + for yeah in yeahed: + if user.is_me(request): + yeah.post.yeah_given = True + yeah.post.setup(request) + fr = None + if request.user.is_authenticated: + user.friend_state = user.friend_state(request.user) + if user.friend_state == 2: + fr = user.get_fr(request.user).first() - return render(request, 'closedverse_main/user_view.html', { - 'title': title, - 'classes': ['profile-top'], - 'user': user, - 'profile': profile, - 'posts': posts, - 'yeahed': yeahed, - 'fr': fr, - 'ogdata': { - 'title': title, - # Todo: fix all concatenations like these and make them into strings with format() since that's cleaner and better - 'description': profile.comment, - 'date': str(user.created), - 'image': user.do_avatar(), - }, - }) + return render(request, 'closedverse_main/user_view.html', { + 'title': title, + 'classes': ['profile-top'], + 'user': user, + 'profile': profile, + 'posts': posts, + 'yeahed': yeahed, + 'fr': fr, + 'ogdata': { + 'title': title, + # Todo: fix all concatenations like these and make them into strings with format() since that's cleaner and better + 'description': profile.comment, + 'date': str(user.created), + 'image': user.do_avatar(), + }, + }) def user_posts(request, username): - """User posts page""" - user = get_object_or_404(User, username__iexact=username) - if user.is_me(request): - title = 'My posts' - else: - if request.user.is_authenticated and not user.can_view(request.user): - raise Http404() - title = '{0}\'s posts'.format(user.nickname) - profile = user.profile() - profile.setup(request) + """User posts page""" + user = get_object_or_404(User, username__iexact=username) + if user.is_me(request): + title = 'My posts' + else: + if request.user.is_authenticated and not user.can_view(request.user): + raise Http404() + title = '{0}\'s posts'.format(user.nickname) + profile = user.profile() + profile.setup(request) + if hasattr(profile, 'is_blocked'): + return render(request, 'closedverse_main/user_blocked.html', { + 'classes': ['profile-top'], + 'user': user, + 'profile': profile, + }) + + offset = int(request.GET.get('offset', 0)) + if request.GET.get('offset_time'): + offset_time = datetime.fromisoformat(request.GET['offset_time']) + else: + offset_time = timezone.now() + + posts = user.get_posts(50, offset, request, offset_time) + next_offset = None + if posts.count() > 49: + next_offset = offset + 50 - if request.GET.get('offset'): - posts = user.get_posts(50, int(request.GET['offset']), request) - else: - posts = user.get_posts(50, 0, request) - if posts.count() > 49: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 50 - else: - next_offset = 50 - else: - next_offset = None - - if request.META.get('HTTP_X_AUTOPAGERIZE'): - return render(request, 'closedverse_main/elements/u-post-list.html', { - 'posts': posts, - 'next': next_offset, - }) - else: - return render(request, 'closedverse_main/user_posts.html', { - 'user': user, - 'title': title, - 'posts': posts, - 'profile': profile, - 'next': next_offset, - # Copied from the above, if you change the last ogdata occurrence then change this one - 'ogdata': { - 'title': title, - 'description': profile.comment, - 'date': str(user.created), - }, - }) + if request.META.get('HTTP_X_AUTOPAGERIZE'): + return (debug(request, username) if 'HTTP_DIS' in request.META else render(request, 'closedverse_main/elements/u-post-list.html', { + 'posts': posts, + 'next': next_offset, + 'time': offset_time.isoformat(), + })) + else: + return render(request, 'closedverse_main/user_posts.html', { + 'user': user, + 'title': title, + 'posts': posts, + 'profile': profile, + 'next': next_offset, + 'time': offset_time.isoformat(), + # Copied from the above, if you change the last ogdata occurrence then change this one + 'ogdata': { + 'title': title, + 'description': profile.comment, + 'date': str(user.created), + }, + }) def user_yeahs(request, username): - """User's Yeahs page""" - user = get_object_or_404(User, username__iexact=username) - if user.is_me(request): - title = 'My yeahs' - elif not request.user.is_authenticated: - raise Http404() - else: - if request.user.is_authenticated and not user.can_view(request.user): - raise Http404() - title = '{0}\'s yeahs'.format(user.nickname) - profile = user.profile() - profile.setup(request) + """User's Yeahs page""" + user = get_object_or_404(User, username__iexact=username) + if user.is_me(request): + title = 'My yeahs' + elif not request.user.is_authenticated: + raise Http404() + else: + if request.user.is_authenticated and not user.can_view(request.user): + raise Http404() + title = '{0}\'s yeahs'.format(user.nickname) + profile = user.profile() + profile.setup(request) + if hasattr(profile, 'is_blocked'): + return render(request, 'closedverse_main/user_blocked.html', { + 'classes': ['profile-top'], + 'user': user, + 'profile': profile, + }) - if not profile.yeahs_visible: - raise Http404() + if not profile.yeahs_visible: + raise Http404() - if request.GET.get('offset'): - yeahs = user.get_yeahed(2, 20, int(request.GET['offset'])) - else: - yeahs = user.get_yeahed(2, 20, 0) - if yeahs.count() > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None - posts = [] - for yeah in yeahs: - if yeah.type == 1: - if user.is_me(request): - yeah.comment.yeah_given = True - posts.append(yeah.comment) - else: - if user.is_me(request): - yeah.post.yeah_given = True - posts.append(yeah.post) - for post in posts: - post.setup(request) - if request.META.get('HTTP_X_AUTOPAGERIZE'): - return render(request, 'closedverse_main/elements/u-post-list.html', { - 'posts': posts, - 'next': next_offset, - }) - else: - return render(request, 'closedverse_main/user_yeahs.html', { - 'user': user, - 'title': title, - 'posts': posts, - 'profile': profile, - 'next': next_offset, - }) + if request.GET.get('offset'): + yeahs = user.get_yeahed(2, 20, int(request.GET['offset'])) + else: + yeahs = user.get_yeahed(2, 20, 0) + if yeahs.count() > 19: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 20 + else: + next_offset = 20 + else: + next_offset = None + posts = [] + for yeah in yeahs: + if yeah.type == 1: + if user.is_me(request): + yeah.comment.yeah_given = True + posts.append(yeah.comment) + else: + if user.is_me(request): + yeah.post.yeah_given = True + posts.append(yeah.post) + for post in posts: + post.setup(request) + if request.META.get('HTTP_X_AUTOPAGERIZE'): + return render(request, 'closedverse_main/elements/u-post-list.html', { + 'posts': posts, + 'next': next_offset, + }) + else: + return render(request, 'closedverse_main/user_yeahs.html', { + 'user': user, + 'title': title, + 'posts': posts, + 'profile': profile, + 'next': next_offset, + }) def user_comments(request, username): - """User's comments page""" - user = get_object_or_404(User, username__iexact=username) - if user.is_me(request): - title = 'My comments' - else: - if request.user.is_authenticated and not user.can_view(request.user): - raise Http404() - title = '{0}\'s comments'.format(user.nickname) - profile = user.profile() - profile.setup(request) + """User's comments page""" + user = get_object_or_404(User, username__iexact=username) + if user.is_me(request): + title = 'My comments' + else: + if request.user.is_authenticated and not user.can_view(request.user): + raise Http404() + title = '{0}\'s comments'.format(user.nickname) + profile = user.profile() + profile.setup(request) + if hasattr(profile, 'is_blocked'): + return render(request, 'closedverse_main/user_blocked.html', { + 'classes': ['profile-top'], + 'user': user, + 'profile': profile, + }) + + if not profile.comments_visible: + raise Http404() + + offset = int(request.GET.get('offset', 0)) + if request.GET.get('offset_time'): + offset_time = datetime.fromisoformat(request.GET['offset_time']) + else: + offset_time = timezone.now() + posts = user.get_comments(20, offset, request, offset_time) + next_offset = None + if posts.count() > 19: + next_offset = offset + 20 - if not profile.comments_visible: - raise Http404() - - if request.GET.get('offset'): - posts = user.get_comments(50, int(request.GET['offset']), request) - else: - posts = user.get_comments(50, 0, request) - if posts.count() > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None - if request.META.get('HTTP_X_AUTOPAGERIZE'): - return render(request, 'closedverse_main/elements/u-post-list.html', { - 'posts': posts, - 'next': next_offset, - }) - else: - return render(request, 'closedverse_main/user_comments.html', { - 'user': user, - 'title': title, - 'posts': posts, - 'profile': profile, - 'next': next_offset, - }) + if request.META.get('HTTP_X_AUTOPAGERIZE'): + return render(request, 'closedverse_main/elements/u-post-list.html', { + 'posts': posts, + 'next': next_offset, + 'time': offset_time.isoformat(), + }) + else: + return render(request, 'closedverse_main/user_comments.html', { + 'user': user, + 'title': title, + 'posts': posts, + 'profile': profile, + 'next': next_offset, + 'time': offset_time.isoformat(), + }) def user_following(request, username): - """User following page""" - user = get_object_or_404(User, username__iexact=username) - if user.is_me(request): - title = 'My follows' - else: - if request.user.is_authenticated and not user.can_view(request.user): - raise Http404() - title = '{0}\'s follows'.format(user.nickname) - profile = user.profile() - profile.setup(request) + """User following page""" + user = get_object_or_404(User, username__iexact=username) + if user.is_me(request): + title = 'My follows' + else: + if request.user.is_authenticated and not user.can_view(request.user): + raise Http404() + title = '{0}\'s follows'.format(user.nickname) + profile = user.profile() + profile.setup(request) + if hasattr(profile, 'is_blocked'): + return render(request, 'closedverse_main/user_blocked.html', { + 'classes': ['profile-top'], + 'user': user, + 'profile': profile, + }) - if request.GET.get('offset'): - following_list = user.get_following(20, int(request.GET['offset'])) - else: - following_list = user.get_following(20, 0) - if following_list.count() > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None - following = [] - for follow in following_list: - following.append(follow.target) - if request.META.get('HTTP_X_AUTOPAGERIZE'): - for user in following: - user.is_following = user.is_following(request.user) - return render(request, 'closedverse_main/elements/profile-user-list.html', { - 'users': following, - 'request': request, - 'next': next_offset, - }) - else: - return render(request, 'closedverse_main/user_following.html', { - 'user': user, - 'title': title, - 'following': following, - 'profile': profile, - 'next': next_offset, - }) + if request.GET.get('offset'): + following_list = user.get_following(20, int(request.GET['offset'])) + else: + following_list = user.get_following(20, 0) + if following_list.count() > 19: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 20 + else: + next_offset = 20 + else: + next_offset = None + following = [] + for follow in following_list: + following.append(follow.target) + if request.META.get('HTTP_X_AUTOPAGERIZE'): + for user in following: + user.is_following = user.is_following(request.user) + return render(request, 'closedverse_main/elements/profile-user-list.html', { + 'users': following, + 'request': request, + 'next': next_offset, + }) + else: + return render(request, 'closedverse_main/user_following.html', { + 'user': user, + 'title': title, + 'following': following, + 'profile': profile, + 'next': next_offset, + }) def user_followers(request, username): - """User followers page""" - user = get_object_or_404(User, username__iexact=username) - if user.is_me(request): - title = 'My followers' - else: - if request.user.is_authenticated and not user.can_view(request.user): - raise Http404() - title = '{0}\'s followers'.format(user.nickname) - profile = user.profile() - profile.setup(request) + """User followers page""" + user = get_object_or_404(User, username__iexact=username) + if user.is_me(request): + title = 'My followers' + else: + if request.user.is_authenticated and not user.can_view(request.user): + raise Http404() + title = '{0}\'s followers'.format(user.nickname) + profile = user.profile() + profile.setup(request) + if hasattr(profile, 'is_blocked'): + return render(request, 'closedverse_main/user_blocked.html', { + 'classes': ['profile-top'], + 'user': user, + 'profile': profile, + }) - if request.GET.get('offset'): - followers_list = user.get_followers(20, int(request.GET['offset'])) - else: - followers_list = user.get_followers(20, 0) - if followers_list.count() > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None - followers = [] - for follow in followers_list: - followers.append(follow.source) - if request.META.get('HTTP_X_AUTOPAGERIZE'): - for user in followers: - user.is_following = user.is_following(request.user) - return render(request, 'closedverse_main/elements/profile-user-list.html', { - 'users': followers, - 'request': request, - 'next': next_offset, - }) - else: - return render(request, 'closedverse_main/user_followers.html', { - 'user': user, - 'title': title, - 'followers': followers, - 'profile': profile, - 'next': next_offset, - }) + if request.GET.get('offset'): + followers_list = user.get_followers(20, int(request.GET['offset'])) + else: + followers_list = user.get_followers(20, 0) + if followers_list.count() > 19: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 20 + else: + next_offset = 20 + else: + next_offset = None + followers = [] + for follow in followers_list: + followers.append(follow.source) + if request.META.get('HTTP_X_AUTOPAGERIZE'): + for user in followers: + user.is_following = user.is_following(request.user) + return render(request, 'closedverse_main/elements/profile-user-list.html', { + 'users': followers, + 'request': request, + 'next': next_offset, + }) + else: + return render(request, 'closedverse_main/user_followers.html', { + 'user': user, + 'title': title, + 'followers': followers, + 'profile': profile, + 'next': next_offset, + }) def user_friends(request, username): - """User friends list page - uses some special math I think""" - user = get_object_or_404(User, username__iexact=username) - if user.is_me(request): - title = 'My friends' - else: - if request.user.is_authenticated and not user.can_view(request.user): - raise Http404() - title = '{0}\'s friends'.format(user.nickname) - profile = user.profile() - profile.setup(request) + """User friends list page - uses some special math I think""" + user = get_object_or_404(User, username__iexact=username) + if user.is_me(request): + title = 'My friends' + else: + if request.user.is_authenticated and not user.can_view(request.user): + raise Http404() + title = '{0}\'s friends'.format(user.nickname) + profile = user.profile() + profile.setup(request) + if hasattr(profile, 'is_blocked'): + return render(request, 'closedverse_main/user_blocked.html', { + 'classes': ['profile-top'], + 'user': user, + 'profile': profile, + }) - if request.GET.get('offset'): - friends_list = Friendship.get_friendships(user, 20, int(request.GET['offset'])) - else: - friends_list = Friendship.get_friendships(user, 20, 0) - if friends_list.count() > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None - friends = [] - for friend in friends_list: - friends.append(friend.other(user)) - del(friends_list) - if request.META.get('HTTP_X_AUTOPAGERIZE'): - for user in friends: - user.is_following = user.is_following(request.user) - return render(request, 'closedverse_main/elements/profile-user-list.html', { - 'users': friends, - 'request': request, - 'next': next_offset, - }) - else: - return render(request, 'closedverse_main/user_friends.html', { - 'user': user, - 'title': title, - 'friends': friends, - 'profile': profile, - 'next': next_offset, - }) + if request.GET.get('offset'): + friends_list = Friendship.get_friendships(user, 20, int(request.GET['offset'])) + else: + friends_list = Friendship.get_friendships(user, 20, 0) + if friends_list.count() > 19: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 20 + else: + next_offset = 20 + else: + next_offset = None + friends = [] + for friend in friends_list: + friends.append(friend.other(user)) + del(friends_list) + if request.META.get('HTTP_X_AUTOPAGERIZE'): + for user in friends: + user.is_following = user.is_following(request.user) + return render(request, 'closedverse_main/elements/profile-user-list.html', { + 'users': friends, + 'request': request, + 'next': next_offset, + }) + else: + return render(request, 'closedverse_main/user_friends.html', { + 'user': user, + 'title': title, + 'friends': friends, + 'profile': profile, + 'next': next_offset, + }) @login_required def profile_settings(request): - """Profile settings, POSTs to user_view""" - profile = request.user.profile() - profile.setup(request) - user = request.user - user.mh = user.mh() - return render(request, 'closedverse_main/profile-settings.html', { - 'title': 'Profile settings', - 'user': user, - 'profile': profile, - 'settings': settings, - 'mii_domain': mii_domain, - 'mii_endpoint': mii_endpoint, - }) + """Profile settings, POSTs to user_view""" + profile = request.user.profile() + profile.setup(request) + user = request.user + user.mh = user.mh() + return render(request, 'closedverse_main/profile-settings.html', { + 'title': 'Profile settings', + 'user': user, + 'profile': profile, + 'settings': settings, + 'mii_domain': mii_domain, + 'mii_endpoint': mii_endpoint, + }) def special_community_tag(request, tag): - """For community URIs such as /communities/changelog""" - communities = get_object_or_404(Community, tags=tag) - return redirect(reverse('main:community-view', args=[communities.id])) + """For community URIs such as /communities/changelog""" + communities = get_object_or_404(Community, tags=tag) + return redirect(reverse('main:community-view', args=[communities.id])) #@silk_profile(name='Community view') def community_view(request, community): - """View an individual community""" - communities = get_object_or_404(Community, id=community) - communities.setup(request) - can_edit = communities.can_edit_community(request) - if not communities.clickable(): - return HttpResponseForbidden() - if not request.user.is_authenticated and communities.require_auth: - return render(request, 'com_locked.html') - if request.GET.get('offset'): - posts = communities.get_posts(50, int(request.GET['offset']), request) - else: - posts = communities.get_posts(50, 0, request) - if posts.count() > 49: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 50 - else: - next_offset = 50 - else: - next_offset = None - if request.META.get('HTTP_X_AUTOPAGERIZE'): - return render(request, 'closedverse_main/elements/post-list.html', { - 'posts': posts, - 'next': next_offset, - }) - else: - return render(request, 'closedverse_main/community_view.html', { - 'title': communities.name, - 'classes': ['community-top'], - 'community': communities, - 'posts': posts, - 'next': next_offset, - 'ogdata': { - 'title': communities.name, - 'description': communities.description, - 'date': str(communities.created), - 'image': communities.icon, - }, - }) + """View an individual community""" + communities = get_object_or_404(Community, id=community) + communities.setup(request) + can_edit = communities.can_edit_community(request) + if not communities.clickable(): + return HttpResponseForbidden() + if not request.user.is_authenticated and communities.require_auth: + return render(request, 'com_locked.html') + offset = int(request.GET.get('offset', 0)) + if request.GET.get('offset_time'): + offset_time = datetime.fromisoformat(request.GET['offset_time']) + else: + offset_time = timezone.now() + + posts = communities.get_posts(50, offset, request, offset_time) + next_offset = None + if posts.count() > 49: + next_offset = offset + 50 + if request.META.get('HTTP_X_AUTOPAGERIZE'): + return render(request, 'closedverse_main/elements/post-list.html', { + 'posts': posts, + 'next': next_offset, + 'time': offset_time.isoformat(), + }) + else: + return render(request, 'closedverse_main/community_view.html', { + 'title': communities.name, + 'classes': ['community-top'], + 'community': communities, + 'posts': posts, + 'next': next_offset, + 'time': offset_time.isoformat(), + 'ogdata': { + 'title': communities.name, + 'description': communities.description, + 'date': str(communities.created), + 'image': communities.icon, + }, + }) @require_http_methods(['POST']) @login_required def community_favorite_create(request, community): - the_community = get_object_or_404(Community, id=community) - if not the_community.type == 4: - the_community.favorite_add(request) - return HttpResponse() + the_community = get_object_or_404(Community, id=community) + if not the_community.type == 4: + the_community.favorite_add(request) + return HttpResponse() @require_http_methods(['POST']) @login_required def community_favorite_rm(request, community): - the_community = get_object_or_404(Community, id=community) - the_community.favorite_rm(request) - return HttpResponse() - + the_community = get_object_or_404(Community, id=community) + the_community.favorite_rm(request) + return HttpResponse() + def community_tools(request, community): - the_community = get_object_or_404(Community, id=community) - if not request.user.is_authenticated: - raise Http404() - can_edit = the_community.can_edit_community(request) - if not can_edit: - raise Http404() - return render(request, 'closedverse_main/community_tools.html', { - 'title': 'Community tools', - 'community': the_community, - 'max_icon_size': settings.max_icon_size, - 'max_banner_size': settings.max_banner_size, - }) - + the_community = get_object_or_404(Community, id=community) + if not request.user.is_authenticated: + raise Http404() + can_edit = the_community.can_edit_community(request) + if not can_edit: + raise Http404() + return render(request, 'closedverse_main/community_tools.html', { + 'title': 'Community tools', + 'community': the_community, + 'max_icon_size': settings.max_icon_size, + 'max_banner_size': settings.max_banner_size, + }) + def community_tools_set(request, community): - if request.method == 'POST': - the_community = get_object_or_404(Community, id=community) - #do the checks - if not request.user.is_authenticated: - return HttpResponseForbidden() - can_edit = the_community.can_edit_community(request) - if not can_edit: - return HttpResponseForbidden() - if len(request.POST.get('community_name')) == 0 or len(request.POST.get('community_name')) >= 100: - return json_response('bad name') - if len(request.POST.get('community_description')) >= 1024: - return json_response('bad description') - if the_community.is_rm: - return json_response('Community is removed') - if the_community.type == 4: - return json_response('Community is removed') - #do the settings - the_community.name = request.POST.get('community_name') - the_community.description = request.POST.get('community_description') - the_community.platform = (request.POST.get('community_platform') or 0) - the_community.require_auth = False if request.POST.get('force_login') is None else True - ico = request.FILES.get('community_icon') - banner = request.FILES.get('community_banner') - #if icon is not set, ignore it - if ico != None: - #make sure it's an image. - if 'image' in ico.content_type: - # Set the upload limit in megabytes - upload_limit = settings.max_icon_size - - max_size = upload_limit * 1024 * 1024 - current_size = ico.size - max_mb = max_size / 1024 / 1024 - if current_size > max_size: - return json_response('Your icon is too big! Please upload an image under ' + str(max_mb) + 'MB. (' + str(round(current_size / 1024 / 1024, 3)) + 'MB)') - the_community.ico = ico - else: - return json_response('bad image') - - if banner != None: - if 'image' in banner.content_type: - # Set the upload limit in megabytes - upload_limit = settings.max_banner_size - max_size = upload_limit * 1024 * 1024 - current_size = banner.size - max_mb = max_size / 1024 / 1024 - if current_size > max_size: - # i hate this fucking shit - return json_response('Your banner is too big! Please upload an image under ' + str(max_mb) + ' MB. (' + str(round(current_size / 1024 / 1024, 3)) + 'MB)') - the_community.banner = banner - else: - return json_response('bad image') - - ''' - if request.FILES.get('community_icon') != None: - if - the_community.ico = request.FILES.get('community_icon') - if request.FILES.get('community_banner') != None: - the_community.banner = request.FILES.get('community_banner') - ''' - the_community.save() - #AuditLog.objects.create(type=2, user=user, by=request.user, reasoning=request.POST) - return HttpResponse() - else: - raise Http404() - + if request.method == 'POST': + the_community = get_object_or_404(Community, id=community) + #do the checks + if not request.user.is_authenticated: + return HttpResponseForbidden() + can_edit = the_community.can_edit_community(request) + if not can_edit: + return HttpResponseForbidden() + if len(request.POST.get('community_name')) == 0 or len(request.POST.get('community_name')) >= 100: + return json_response('bad name') + if len(request.POST.get('community_description')) >= 1024: + return json_response('bad description') + if the_community.is_rm: + return json_response('Community is removed') + if the_community.type == 4: + return json_response('Community is removed') + #do the settings + the_community.name = request.POST.get('community_name') + the_community.description = request.POST.get('community_description') + the_community.platform = (request.POST.get('community_platform') or 0) + the_community.require_auth = False if request.POST.get('force_login') is None else True + ico = request.FILES.get('community_icon') + banner = request.FILES.get('community_banner') + #if icon is not set, ignore it + if ico != None: + #make sure it's an image. + if 'image' in ico.content_type: + # Set the upload limit in megabytes + upload_limit = settings.max_icon_size + + max_size = upload_limit * 1024 * 1024 + current_size = ico.size + max_mb = max_size / 1024 / 1024 + if current_size > max_size: + return json_response('Your icon is too big! Please upload an image under ' + str(max_mb) + 'MB. (' + str(round(current_size / 1024 / 1024, 3)) + 'MB)') + the_community.ico = ico + else: + return json_response('bad image') + + if banner != None: + if 'image' in banner.content_type: + # Set the upload limit in megabytes + upload_limit = settings.max_banner_size + max_size = upload_limit * 1024 * 1024 + current_size = banner.size + max_mb = max_size / 1024 / 1024 + if current_size > max_size: + # i hate this fucking shit + return json_response('Your banner is too big! Please upload an image under ' + str(max_mb) + ' MB. (' + str(round(current_size / 1024 / 1024, 3)) + 'MB)') + the_community.banner = banner + else: + return json_response('bad image') + + ''' + if request.FILES.get('community_icon') != None: + if + the_community.ico = request.FILES.get('community_icon') + if request.FILES.get('community_banner') != None: + the_community.banner = request.FILES.get('community_banner') + ''' + the_community.save() + #AuditLog.objects.create(type=2, user=user, by=request.user, reasoning=request.POST) + return HttpResponse() + else: + raise Http404() + def community_create(request): - # check and deduct C tokens - if not request.user.is_authenticated: - raise Http404() - if request.user.c_tokens < 1: - raise Http404() - return render(request, 'closedverse_main/community_create.html', { - 'title': 'Create a community', - 'max_icon_size': settings.max_icon_size, - 'max_banner_size': settings.max_banner_size, - 'tokens': request.user.c_tokens, - }) + # check and deduct C tokens + if not request.user.is_authenticated: + raise Http404() + if request.user.c_tokens < 1: + raise Http404() + return render(request, 'closedverse_main/community_create.html', { + 'title': 'Create a community', + 'max_icon_size': settings.max_icon_size, + 'max_banner_size': settings.max_banner_size, + 'tokens': request.user.c_tokens, + }) def community_create_action(request): - user = request.user - if request.method == 'POST': - if not request.user.is_authenticated: - raise Http404() - if user.c_tokens < 1: - return json_response("You don't have any tokens left") - if len(request.POST.get('community_name')) == 0 or len(request.POST.get('community_name')) >= 100: - return json_response('bad name') - if len(request.POST.get('community_description')) >= 1024: - return json_response('bad description') - get = request.POST.get - user.c_tokens -= 1 - user.save() - Community.objects.create(name=get('community_name'), description=get('community_description'), type=3, platform=get('community_platform'), creator=user) - return json_response('Done.') + user = request.user + if request.method == 'POST': + if not request.user.is_authenticated: + raise Http404() + if user.c_tokens < 1: + return json_response("You don't have any tokens left") + if len(request.POST.get('community_name')) == 0 or len(request.POST.get('community_name')) >= 100: + return json_response('bad name') + if len(request.POST.get('community_description')) >= 1024: + return json_response('bad description') + get = request.POST.get + user.c_tokens -= 1 + user.save() + Community.objects.create(name=get('community_name'), description=get('community_description'), type=3, platform=get('community_platform'), creator=user) + return json_response('Done.') @login_required def post_create(request, community): - if request.method == 'POST' and request.is_ajax(): - # Wake - request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) - # Required - if not (request.POST.get('community')): - return HttpResponseBadRequest() - try: - community = Community.objects.get(id=community, unique_id=request.POST['community']) - except (Community.DoesNotExist, ValueError): - return HttpResponseNotFound() - # Method of Community - new_post = community.create_post(request) - if not new_post: - return HttpResponseBadRequest() - if isinstance(new_post, int): - # If post limit - if new_post == 8: - # then do meme - return json_response("You have already exceeded the number of posts that you can contribute in a single day. Please try again tomorrow.", 1215919) - return json_response({ - 1: "Your post is too long ("+str(len(request.POST['body']))+" characters, 2200 max).", - 2: "The image you've uploaded is invalid.", - 3: "You're making posts too fast, wait a few seconds and try again.", - 4: "Apparently, you're not allowed to post here.", - 5: "Uh-oh, that URL wasn't valid..", - 6: "Not allowed.", - 7: "Please don't spam.", - }.get(new_post)) - # Render correctly whether we're posting to Activity Feed - if community.is_activity(): - return render(request, 'closedverse_main/elements/community_post.html', { - 'post': new_post, - 'with_community_container': True, - 'type': 2, - }) - else: - return render(request, 'closedverse_main/elements/community_post.html', { 'post': new_post }) - else: - raise Http404() + if request.method == 'POST': + # Wake + request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) + # Required + if not (request.POST.get('community')): + return HttpResponseBadRequest() + try: + community = Community.objects.get(id=community, unique_id=request.POST['community']) + except (Community.DoesNotExist, ValueError): + return HttpResponseNotFound() + # Method of Community + new_post = community.create_post(request) + if not new_post: + return HttpResponseBadRequest() + if isinstance(new_post, int): + # If post limit + if new_post == 8: + # then do meme + return json_response("You have already exceeded the number of posts that you can contribute in a single day. Please try again tomorrow.", 1215919) + return json_response({ + 1: "Your post is too long ("+str(len(request.POST['body']))+" characters, 2200 max).", + 2: "The image you've uploaded is invalid.", + 3: "You're posting too quickly, wait a few seconds and try again.", + 4: "Apparently, you're not allowed to post here.", + 5: "Uh-oh, that URL wasn't valid..", + 6: "Not allowed.", + 7: "Please don't spam.", + 9: "You're very funny. Unfortunately your funniness blah blah blah fuck off.", + 10: "No mr white, you can't make a post entirely consistant of spaces", + }.get(new_post)) + # Render correctly whether we're posting to Activity Feed + if community.is_activity(): + return render(request, 'closedverse_main/elements/community_post.html', { + 'post': new_post, + 'with_community_container': True, + 'type': 2, + }) + else: + return render(request, 'closedverse_main/elements/community_post.html', { 'post': new_post }) + else: + raise Http404() def post_view(request, post): - has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id) - try: - post = Post.objects.annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).get(id=post) - except Post.DoesNotExist: - raise Http404() - if not request.user.is_authenticated and post.community.require_auth: - raise Http404() - post.setup(request) - if post.poll: - post.poll.setup(request.user) - if request.user.is_authenticated: - post.can_rm = post.can_rm(request) - post.is_favorite = post.is_favorite(request.user) - post.can_comment = post.can_comment(request) - if post.is_mine: - title = 'Your post' - else: - title = '{0}\'s post'.format(post.creator.nickname) - all_comment_count = post.number_comments() - if all_comment_count > 20: - comments = post.get_comments(request, None, all_comment_count - 20) - else: - comments = post.get_comments(request) - return render(request, 'closedverse_main/post-view.html', { - 'title': title, - #CSS might not be that friendly with this / 'classes': ['post-permlink'], - 'post': post, - 'yeahs': post.get_yeahs(request), - 'comments': comments, - 'all_comment_count': all_comment_count, - 'ogdata': { - 'title': title, - 'description': post.trun(), - 'date': str(post.created), - 'image': post.creator.do_avatar(post.feeling), - }, - }) + has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id) + try: + post = Post.objects.annotate(num_yeahs=Count('yeah', distinct=True), num_comments=Count('comment', distinct=True), yeah_given=Exists(has_yeah, distinct=True)).get(id=post) + except Post.DoesNotExist: + raise Http404() + if not request.user.is_authenticated and post.community.require_auth: + raise Http404() + post.setup(request) + if post.poll: + post.poll.setup(request.user) + if request.user.is_authenticated: + post.can_rm = post.can_rm(request) + post.is_favorite = post.is_favorite(request.user) + post.can_comment = post.can_comment(request) + if post.is_mine: + title = 'Your post' + else: + title = '{0}\'s post'.format(post.creator.nickname) + all_comment_count = post.number_comments() + if all_comment_count > 20: + comments = post.get_comments(request, None, all_comment_count - 20) + else: + comments = post.get_comments(request) + return render(request, 'closedverse_main/post-view.html', { + 'title': title, + #CSS might not be that friendly with this / 'classes': ['post-permlink'], + 'post': post, + 'yeahs': post.get_yeahs(request), + 'comments': comments, + 'all_comment_count': all_comment_count, + 'ogdata': { + 'title': title, + 'description': post.trun(), + 'date': str(post.created), + 'image': post.creator.do_avatar(post.feeling), + }, + }) @require_http_methods(['POST']) @login_required def post_add_yeah(request, post): - the_post = get_object_or_404(Post, id=post) - if the_post.disable_yeah: - return json_response('You cannot yeah this post.') - if the_post.give_yeah(request): - # Give the notification! - Notification.give_notification(request.user, 0, the_post.creator, the_post) - return HttpResponse() - + the_post = get_object_or_404(Post, id=post) + if the_post.disable_yeah: + return json_response('You cannot yeah this post.') + if the_post.give_yeah(request): + # Give the notification! + Notification.give_notification(request.user, 0, the_post.creator, the_post) + return HttpResponse() + @require_http_methods(['POST']) @login_required def post_delete_yeah(request, post): - the_post = get_object_or_404(Post, id=post) - the_post.remove_yeah(request) - return HttpResponse() + the_post = get_object_or_404(Post, id=post) + the_post.remove_yeah(request) + return HttpResponse() @require_http_methods(['POST']) @login_required def post_change(request, post): - the_post = get_object_or_404(Post, id=post) - the_post.change(request) - return HttpResponse() + the_post = get_object_or_404(Post, id=post) + the_post.change(request) + return HttpResponse() @require_http_methods(['POST']) @login_required def post_setprofile(request, post): - the_post = get_object_or_404(Post, id=post) - the_post.favorite(request.user) - return HttpResponse() + the_post = get_object_or_404(Post, id=post) + the_post.favorite(request.user) + return HttpResponse() @require_http_methods(['POST']) @login_required def post_unsetprofile(request, post): - the_post = get_object_or_404(Post, id=post) - the_post.unfavorite(request.user) - return HttpResponse() + the_post = get_object_or_404(Post, id=post) + the_post.unfavorite(request.user) + return HttpResponse() @require_http_methods(['POST']) @login_required def post_rm(request, post): - the_post = get_object_or_404(Post, id=post) - the_post.rm(request) - return HttpResponse() + the_post = get_object_or_404(Post, id=post) + the_post.rm(request) + return HttpResponse() @require_http_methods(['POST']) @login_required def comment_change(request, comment): - the_post = get_object_or_404(Comment, id=comment) - the_post.change(request) - return HttpResponse() + the_post = get_object_or_404(Comment, id=comment) + the_post.change(request) + return HttpResponse() @require_http_methods(['POST']) @login_required def comment_rm(request, comment): - the_post = get_object_or_404(Comment, id=comment) - the_post.rm(request) - return HttpResponse() + the_post = get_object_or_404(Comment, id=comment) + the_post.rm(request) + return HttpResponse() @require_http_methods(['GET', 'POST']) @login_required def post_comments(request, post): - post = get_object_or_404(Post, id=post) - if not request.is_ajax(): - raise Http404() - if request.method == 'POST': - # Wake - request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) - # Method of Post - new_post = post.create_comment(request) - if not new_post: - return HttpResponseBadRequest() - if isinstance(new_post, int): - # If post limit - if new_post == 8: - # then do meme - return json_response("You have already exceeded the number of posts that you can contribute in a single day. Please try again tomorrow.", 1215919) - return json_response({ - 1: "Your comment is too long ("+str(len(request.POST['body']))+" characters, 2200 max).", - 2: "The image you've uploaded is invalid.", - 3: "You're making comments too fast, wait a few seconds and try again.", - 6: "Not allowed.", - }.get(new_post)) - # Give the notification! - if post.is_mine(request.user): - users = [] - comments = post.get_comments(request) - for comment in comments: - if comment.creator != request.user: - users.append(comment.creator) - for user in users: - Notification.give_notification(request.user, 3, user, post) - else: - Notification.give_notification(request.user, 2, post.creator, post) - return render(request, 'closedverse_main/elements/post-comment.html', { 'comment': new_post }) - else: - comment_count = post.number_comments() - if comment_count > 20: - comments = post.get_comments(request, comment_count - 20, 0) - return render(request, 'closedverse_main/elements/post_comments.html', { 'comments': comments }) - else: - return render(request, 'closedverse_main/elements/post_comments.html', { 'comments': post.get_comments(request) }) + post = get_object_or_404(Post, id=post) + if not request.is_ajax(): + raise Http404() + if request.method == 'POST': + # Wake + request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) + # Method of Post + new_post = post.create_comment(request) + if not new_post: + return HttpResponseBadRequest() + if isinstance(new_post, int): + # If post limit + if new_post == 8: + # then do meme + return json_response("You have already exceeded the number of posts that you can contribute in a single day. Please try again tomorrow.", 1215919) + return json_response({ + 1: "Your comment is too long ("+str(len(request.POST['body']))+" characters, 2200 max).", + 2: "The image you've uploaded is invalid.", + 3: "You're making comments too fast, wait a few seconds and try again.", + 6: "Not allowed.", + }.get(new_post)) + # Give the notification! + if post.is_mine(request.user): + users = [] + comments = post.get_comments(request) + for comment in comments: + if comment.creator != request.user: + users.append(comment.creator) + for user in users: + Notification.give_notification(request.user, 3, user, post) + else: + Notification.give_notification(request.user, 2, post.creator, post) + return render(request, 'closedverse_main/elements/post-comment.html', { 'comment': new_post }) + else: + comment_count = post.number_comments() + if comment_count > 20: + comments = post.get_comments(request, comment_count - 20, 0) + return render(request, 'closedverse_main/elements/post_comments.html', { 'comments': comments }) + else: + return render(request, 'closedverse_main/elements/post_comments.html', { 'comments': post.get_comments(request) }) def comment_view(request, comment): - comment = get_object_or_404(Comment, id=comment) - if not request.user.is_authenticated and comment.original_post.community.require_auth: - raise Http404() - comment.setup(request) - if request.user.is_authenticated: - comment.can_rm = comment.can_rm(request) - if comment.is_mine: - title = 'Your comment' - else: - title = '{0}\'s comment'.format(comment.creator.nickname) - if comment.original_post.is_mine(request.user): - title += ' on your post' - else: - title += ' on {0}\'s post'.format(comment.original_post.creator.nickname) - return render(request, 'closedverse_main/comment-view.html', { - 'title': title, - #CSS might not be that friendly with this / 'classes': ['post-permlink'], - 'comment': comment, - 'yeahs': comment.get_yeahs(request), - 'ogdata': { - 'title': title, - 'description': comment.trun(), - 'date': str(comment.created), - 'image': comment.creator.do_avatar(comment.feeling), - }, - }) + comment = get_object_or_404(Comment, id=comment) + if not request.user.is_authenticated and comment.original_post.community.require_auth: + raise Http404() + comment.setup(request) + if request.user.is_authenticated: + comment.can_rm = comment.can_rm(request) + if comment.is_mine: + title = 'Your comment' + else: + title = '{0}\'s comment'.format(comment.creator.nickname) + if comment.original_post.is_mine(request.user): + title += ' on your post' + else: + title += ' on {0}\'s post'.format(comment.original_post.creator.nickname) + return render(request, 'closedverse_main/comment-view.html', { + 'title': title, + #CSS might not be that friendly with this / 'classes': ['post-permlink'], + 'comment': comment, + 'yeahs': comment.get_yeahs(request), + 'ogdata': { + 'title': title, + 'description': comment.trun(), + 'date': str(comment.created), + 'image': comment.creator.do_avatar(comment.feeling), + }, + }) @require_http_methods(['POST']) @login_required def comment_add_yeah(request, comment): - the_post = get_object_or_404(Comment, id=comment) - if the_post.give_yeah(request): - # Give the notification! - Notification.give_notification(request.user, 1, the_post.creator, None, the_post) - return HttpResponse() + the_post = get_object_or_404(Comment, id=comment) + if the_post.give_yeah(request): + # Give the notification! + Notification.give_notification(request.user, 1, the_post.creator, None, the_post) + return HttpResponse() @require_http_methods(['POST']) @login_required def comment_delete_yeah(request, comment): - the_post = get_object_or_404(Comment, id=comment) - the_post.remove_yeah(request) - return HttpResponse() + the_post = get_object_or_404(Comment, id=comment) + the_post.remove_yeah(request) + return HttpResponse() @require_http_methods(['POST']) @login_required def poll_vote(request, poll): - the_poll = get_object_or_404(Poll, unique_id=poll) - the_poll.vote(request.user, request.POST.get('a')) - return HttpResponse() + the_poll = get_object_or_404(Poll, unique_id=poll) + the_poll.vote(request.user, request.POST.get('a')) + return HttpResponse() @require_http_methods(['POST']) @login_required def poll_unvote(request, poll): - the_poll = get_object_or_404(Poll, unique_id=poll) - the_poll.unvote(request.user) - return HttpResponse() + the_poll = get_object_or_404(Poll, unique_id=poll) + the_poll.unvote(request.user) + return HttpResponse() @require_http_methods(['POST']) @login_required def user_follow(request, username): - user = get_object_or_404(User, username=username) - if settings.PROD: - # Issue 69420: PF2M is getting more follows than me. - if user.username == 'PF2M': - try: - User.objects.get(id=1).follow(request.user) - except: - pass - if user.follow(request.user): - # Give the notification! - Notification.give_notification(request.user, 4, user) - followct = request.user.num_following() - return JsonResponse({'following_count': followct}) + user = get_object_or_404(User, username=username) + """ + if settings.CLOSEDVERSE_PROD: + # Issue 69420: PF2M is getting more follows than me. + if user.username == 'PF2M': + try: + User.objects.get(id=1).follow(request.user) + except: + pass + """ + if user.follow(request.user): + # Give the notification! + Notification.give_notification(request.user, 4, user) + followct = request.user.num_following() + return JsonResponse({'following_count': followct}) @require_http_methods(['POST']) @login_required def user_unfollow(request, username): - user = get_object_or_404(User, username=username) - user.unfollow(request.user) - return HttpResponse() - followct = request.user.num_following() - return JsonResponse({'following_count': followct}) + user = get_object_or_404(User, username=username) + user.unfollow(request.user) + return HttpResponse() + followct = request.user.num_following() + return JsonResponse({'following_count': followct}) @require_http_methods(['POST']) @login_required def user_friendrequest_create(request, username): - user = get_object_or_404(User, username=username) - if not user.profile().can_friend(request.user): - return HttpResponse() - if user.friend_state(request.user) == 0: - if request.POST.get('body'): - if len(request.POST['body']) > 2200: - return json_response('Sorry, but you can\'t send that many characters in a friend request ('+str(len(request.POST['body']))+' sent, 2200 max)\nYou can send more characters in a message once you friend them though.') - user.send_fr(request.user, request.POST['body']) - else: - user.send_fr(request.user) - return HttpResponse() + user = get_object_or_404(User, username=username) + if not user.profile().can_friend(request.user): + return HttpResponse() + if user.friend_state(request.user) == 0: + if request.POST.get('body'): + if len(request.POST['body']) > 2200: + return json_response('Sorry, but you can\'t send that many characters in a friend request ('+str(len(request.POST['body']))+' sent, 2200 max)\nYou can send more characters in a message once you friend them though.') + user.send_fr(request.user, request.POST['body']) + else: + user.send_fr(request.user) + return HttpResponse() @require_http_methods(['POST']) @login_required def user_friendrequest_accept(request, username): - user = get_object_or_404(User, username=username) - request.user.accept_fr(user) - return HttpResponse() + user = get_object_or_404(User, username=username) + request.user.accept_fr(user) + return HttpResponse() @require_http_methods(['POST']) @login_required def user_friendrequest_reject(request, username): - user = get_object_or_404(User, username=username) - request.user.reject_fr(user) - return HttpResponse() + user = get_object_or_404(User, username=username) + request.user.reject_fr(user) + return HttpResponse() @require_http_methods(['POST']) @login_required def user_friendrequest_cancel(request, username): - user = get_object_or_404(User, username=username) - request.user.cancel_fr(user) - return HttpResponse() + user = get_object_or_404(User, username=username) + request.user.cancel_fr(user) + return HttpResponse() @require_http_methods(['POST']) @login_required def user_friendrequest_delete(request, username): - user = get_object_or_404(User, username=username) - request.user.delete_friend(user) - return HttpResponse() + user = get_object_or_404(User, username=username) + request.user.delete_friend(user) + return HttpResponse() @require_http_methods(['POST']) @login_required def user_addblock(request, username): - user = get_object_or_404(User, username=username) - user.make_block(request.user) - return HttpResponse() - + user = get_object_or_404(User, username=username) + user.make_block(request.user) + return HttpResponse() + # Notifications work differently since the Openverse rebranding. (that we changed back) # They used to respond with a JSON for values for unread notifications and messages. # NOW we send the unread notifications in bytes, and then the unread messages in bytes, 2 bytes. The JS is using charCodeAt() # Yes, this limits the amount of unread notifications and messages anyone could ever have, ever, to 255 # Edit: Now, if a user has no unread messages OR unread notifications, no data is returned def check_notifications(request): - if not request.user.is_authenticated: - #return JsonResponse({'success': True}) - return HttpResponse() - n_count = request.user.notification_count() - all_count = request.user.get_frs_notif() + n_count - msg_count = request.user.msg_count() - # Let's update the user's online status - request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) - # Let's just now return the JSON only for Accept: HTML - if 'html' in request.META.get('HTTP_ACCEPT'): - return JsonResponse({'success': True, 'n': all_count, 'msg': msg_count}) - # And then return binary for anything else - # Wait a sec: if there's no new messages/notifications, send nothing back - if not all_count and not msg_count: - return HttpResponse(content_type='application/octet-stream') - # But, if there are, let's keep going - # Edge cases, anyone? (yes this isn't good but it works) - try: - binary_notifications = bytes([all_count]) + bytes([msg_count]) - except ValueError: - binary_notifications = bytes([255]) + bytes([255]) - return HttpResponse(binary_notifications, content_type='application/octet-stream') + if not request.user.is_authenticated: + #return JsonResponse({'success': True}) + return HttpResponse() + n_count = request.user.notification_count() + all_count = request.user.get_frs_notif() + n_count + msg_count = request.user.msg_count() + # Let's update the user's online status + request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) + # Let's just now return the JSON only for Accept: HTML + if 'html' in request.META.get('HTTP_ACCEPT'): + return JsonResponse({'success': True, 'n': all_count, 'msg': msg_count}) + # And then return binary for anything else + # Wait a sec: if there's no new messages/notifications, send nothing back + if not all_count and not msg_count: + return HttpResponse(content_type='application/octet-stream') + # But, if there are, let's keep going + # Edge cases, anyone? (yes this isn't good but it works) + try: + binary_notifications = bytes([all_count]) + bytes([msg_count]) + except ValueError: + binary_notifications = bytes([255]) + bytes([255]) + return HttpResponse(binary_notifications, content_type='application/octet-stream') @require_http_methods(['POST']) @login_required def notification_setread(request): - if request.GET.get('fr'): - update = request.user.read_fr() - else: - update = request.user.notification_read() - return HttpResponse() + if request.GET.get('fr'): + update = request.user.read_fr() + else: + update = request.user.notification_read() + return HttpResponse() @require_http_methods(['POST']) @login_required def notification_delete(request, notification): - if not request.method == 'POST': - raise Http404() - try: - notification = Notification.objects.get(to=request.user, unique_id=notification) - except Notification.DoesNotExist: - return HttpResponseNotFound() - remove = notification.delete() - return HttpResponse() + if not request.method == 'POST': + raise Http404() + try: + notification = Notification.objects.get(to=request.user, unique_id=notification) + except Notification.DoesNotExist: + return HttpResponseNotFound() + remove = notification.delete() + return HttpResponse() #@silk_profile(name='Notifications view') @login_required def notifications(request): - notifications = request.user.get_notifications() - for notification in notifications: - notification.setup(request.user) - frs = request.user.get_frs_notif() - response = loader.get_template('closedverse_main/notifications.html').render({ - 'title': 'My notifications', - 'notifications': notifications, - 'frs': frs, - }, request) - request.user.notification_read() - request.user.notifications_clean() - return HttpResponse(response) + notifications = request.user.get_notifications() + for notification in notifications: + notification.setup(request.user) + frs = request.user.get_frs_notif() + response = loader.get_template('closedverse_main/notifications.html').render({ + 'title': 'My notifications', + 'notifications': notifications, + 'frs': frs, + }, request) + request.user.notification_read() + request.user.notifications_clean() + return HttpResponse(response) @login_required def friend_requests(request): - friendrequests = request.user.get_frs_target() - notifs = request.user.notification_count() - request.user.read_fr() - return render(request, 'closedverse_main/friendrequests.html', { - 'title': 'My friend requests', - 'friendrequests': friendrequests, - 'notifs': notifs, - }) + friendrequests = request.user.get_frs_target() + notifs = request.user.notification_count() + request.user.read_fr() + return render(request, 'closedverse_main/friendrequests.html', { + 'title': 'My friend requests', + 'friendrequests': friendrequests, + 'notifs': notifs, + }) @login_required def user_search(request): - query = request.GET.get('query') - if not query or len(query) < 2: - raise Http404() - if request.GET.get('offset'): - users = User.search(query, 50, int(request.GET['offset']), request) - else: - users = User.search(query, 50, 0, request) - if users.count() > 49: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 50 - else: - next_offset = 50 - else: - next_offset = None - return render(request, 'closedverse_main/user-search.html', { - 'classes': ['search'], - 'query': query, - 'users': users, - 'next': next_offset, - }) + query = request.GET.get('query') + if not query or len(query) < 2: + raise Http404() + if request.GET.get('offset'): + users = User.search(query, 50, int(request.GET['offset']), request) + else: + users = User.search(query, 50, 0, request) + if users.count() > 49: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 50 + else: + next_offset = 50 + else: + next_offset = None + return render(request, 'closedverse_main/user-search.html', { + 'classes': ['search'], + 'query': query, + 'users': users, + 'next': next_offset, + }) @login_required def activity_feed(request): - if request.GET.get('my'): - if request.GET['my'] == 'n': - request.session['activity_no_my'] = False - else: - request.session['activity_no_my'] = True - if request.GET.get('ds'): - if request.GET['ds'] == 'n': - request.session['activity_ds'] = False - else: - request.session['activity_ds'] = True - if not request.META.get('HTTP_X_REQUESTED_WITH') or request.META.get('HTTP_X_PJAX'): - post_community = Community.objects.filter(tags='activity').first() - return render(request, 'closedverse_main/activity-loading.html', { - 'title': 'Activity Feed', - 'community': post_community, - }) - if request.session.get('activity_no_my'): - has_friend = True - else: - has_friend = False - if request.session.get('activity_ds'): - has_distinct = True - else: - has_distinct = False - if request.GET.get('offset'): - posts = request.user.get_activity(20, int(request.GET['offset']), has_distinct, has_friend, request) - else: - posts = request.user.get_activity(20, 0, has_distinct, has_friend, request) - if posts.count() > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None + if request.GET.get('my'): + if request.GET['my'] == 'n': + request.session['activity_no_my'] = False + else: + request.session['activity_no_my'] = True + if request.GET.get('ds'): + if request.GET['ds'] == 'n': + request.session['activity_ds'] = False + else: + request.session['activity_ds'] = True + if not request.META.get('HTTP_X_REQUESTED_WITH') or request.META.get('HTTP_X_PJAX'): + post_community = Community.objects.filter(tags='activity').first() + return render(request, 'closedverse_main/activity-loading.html', { + 'title': 'Activity Feed', + 'community': post_community, + }) + if request.session.get('activity_no_my'): + has_friend = True + else: + has_friend = False + if request.session.get('activity_ds'): + has_distinct = True + else: + has_distinct = False + if request.GET.get('offset'): + posts = request.user.get_activity(20, int(request.GET['offset']), has_distinct, has_friend, request) + else: + posts = request.user.get_activity(20, 0, has_distinct, has_friend, request) + if posts.count() > 19: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 20 + else: + next_offset = 20 + else: + next_offset = None - return render(request, 'closedverse_main/activity.html', { - 'posts': posts, - 'next': next_offset, - }) + return render(request, 'closedverse_main/activity.html', { + 'posts': posts, + 'next': next_offset, + }) @login_required def messages(request): - if request.GET.get('online'): - if request.GET['online'] == 'n': - request.session['messages_online'] = False - else: - request.session['messages_online'] = True - if request.session.get('messages_online'): - online_only = True - else: - online_only = False - if request.GET.get('offset'): - friends = Friendship.get_friendships_message(request.user, 20, int(request.GET['offset']), online_only) - else: - friends = Friendship.get_friendships_message(request.user, 20, 0, online_only) - if len(friends) > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None - return render(request, 'closedverse_main/messages.html', { - 'title': 'Messages', - 'friends': friends, - 'next': next_offset, - }) + if request.GET.get('online'): + if request.GET['online'] == 'n': + request.session['messages_online'] = False + else: + request.session['messages_online'] = True + if request.session.get('messages_online'): + online_only = True + else: + online_only = False + if request.GET.get('offset'): + friends = Friendship.get_friendships_message(request.user, 20, int(request.GET['offset']), online_only) + else: + friends = Friendship.get_friendships_message(request.user, 20, 0, online_only) + if len(friends) > 19: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 20 + else: + next_offset = 20 + else: + next_offset = None + return render(request, 'closedverse_main/messages.html', { + 'title': 'Messages', + 'friends': friends, + 'next': next_offset, + }) @login_required def messages_view(request, username): - user = get_object_or_404(User, username__iexact=username) - friendship = Friendship.find_friendship(request.user, user) - if not friendship: - return HttpResponseForbidden() - other = friendship.other(request.user) - conversation = friendship.conversation() - if request.method == 'POST': - # Wake - request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) - new_post = conversation.make_message(request) - if not new_post: - return HttpResponseBadRequest() - if isinstance(new_post, int): - return json_response({ - 1: "Your message is too long ("+str(len(request.POST['body']))+" characters, 2200 max).", - 2: "The image you've uploaded is invalid.", - 3: "Sorry, but you're sending messages too fast.", - 6: "Not allowed.", - }.get(new_post)) - friendship.update() - return render(request, 'closedverse_main/elements/message.html', { 'message': new_post }) - else: - if request.GET.get('offset'): - messages = conversation.messages(request, 20, int(request.GET['offset'])) - else: - messages = conversation.messages(request, 20, 0) - if messages.count() > 19: - if request.GET.get('offset'): - next_offset = int(request.GET['offset']) + 20 - else: - next_offset = 20 - else: - next_offset = None - if request.META.get('HTTP_X_AUTOPAGERIZE'): - response = loader.get_template('closedverse_main/elements/message-list.html').render({ - 'messages': messages, - 'next': next_offset, - }, request) - else: - response = loader.get_template('closedverse_main/messages-view.html').render({ - 'title': 'Conversation with {0} ({1})'.format(other.nickname, other.username), - 'other': other, - 'conversation': conversation, - 'messages': messages, - 'next': next_offset, - }, request) - if not request.GET.get('offset'): - conversation.set_read(request.user) - return HttpResponse(response) + user = get_object_or_404(User, username__iexact=username) + friendship = Friendship.find_friendship(request.user, user) + if not friendship: + return HttpResponseForbidden() + other = friendship.other(request.user) + conversation = friendship.conversation() + if request.method == 'POST': + # Wake + request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) + new_post = conversation.make_message(request) + if not new_post: + return HttpResponseBadRequest() + if isinstance(new_post, int): + return json_response({ + 1: "Your message is too long ("+str(len(request.POST['body']))+" characters, 2200 max).", + 2: "The image you've uploaded is invalid.", + 3: "Sorry, but you're sending messages too fast.", + 6: "Not allowed.", + }.get(new_post)) + friendship.update() + return render(request, 'closedverse_main/elements/message.html', { 'message': new_post }) + else: + if request.GET.get('offset'): + messages = conversation.messages(request, 20, int(request.GET['offset'])) + else: + messages = conversation.messages(request, 20, 0) + if messages.count() > 19: + if request.GET.get('offset'): + next_offset = int(request.GET['offset']) + 20 + else: + next_offset = 20 + else: + next_offset = None + if request.META.get('HTTP_X_AUTOPAGERIZE'): + response = loader.get_template('closedverse_main/elements/message-list.html').render({ + 'messages': messages, + 'next': next_offset, + }, request) + else: + response = loader.get_template('closedverse_main/messages-view.html').render({ + 'title': 'Conversation with {0} ({1})'.format(other.nickname, other.username), + 'other': other, + 'conversation': conversation, + 'messages': messages, + 'next': next_offset, + }, request) + if not request.GET.get('offset'): + conversation.set_read(request.user) + return HttpResponse(response) @require_http_methods(['POST']) @login_required def messages_read(request, username): - user = get_object_or_404(User, username=username) - friendship = Friendship.find_friendship(request.user, user) - if not friendship: - return HttpResponse() - conversation = friendship.conversation() - conversation.set_read(request.user) - return HttpResponse() + user = get_object_or_404(User, username=username) + friendship = Friendship.find_friendship(request.user, user) + if not friendship: + return HttpResponse() + conversation = friendship.conversation() + conversation.set_read(request.user) + return HttpResponse() @require_http_methods(['POST']) @login_required def message_rm(request, message): - message = get_object_or_404(Message, unique_id=message) - message.rm(request) - return HttpResponse() + message = get_object_or_404(Message, unique_id=message) + message.rm(request) + return HttpResponse() @login_required def prefs(request): - profile = request.user.profile() - if request.method == 'POST': - if request.POST.get('a'): - profile.let_yeahnotifs = True - else: - profile.let_yeahnotifs = False - if request.POST.get('b'): - request.user.hide_online = True - else: - request.user.hide_online = False - profile.save() - request.user.save() - return HttpResponse() - lights = not (request.session.get('lights', False)) - arr = [profile.let_yeahnotifs, lights, request.user.hide_online] - return JsonResponse(arr, safe=False) + profile = request.user.profile() + if request.method == 'POST': + if request.POST.get('a'): + profile.let_yeahnotifs = True + else: + profile.let_yeahnotifs = False + if request.POST.get('b'): + request.user.hide_online = True + else: + request.user.hide_online = False + profile.save() + request.user.save() + return HttpResponse() + lights = not (request.session.get('lights', False)) + arr = [profile.let_yeahnotifs, lights, request.user.hide_online] + return JsonResponse(arr, safe=False) @login_required def post_list(request): - if not request.user.is_staff(): - return JsonResponse({"err": "Not authorized"}) - if not request.GET.get('s') or not request.GET.get('e'): - return JsonResponse({"err": "Start time required with 's' query param and end required with 'e' param (epoch)"}) - if not request.GET.get('l'): - return JsonResponse({"err": "Limit required via 'l' query param"}) - else: - limit = int(request.GET['l']) - if not request.GET.get('o'): - return JsonResponse({"err": "Offset required via 'o' query param"}) - else: - offset = int(request.GET['o']) + if not request.user.is_staff(): + return JsonResponse({"err": "Not authorized"}) + if not request.GET.get('s') or not request.GET.get('e'): + return JsonResponse({"err": "Start time required with 's' query param and end required with 'e' param (epoch)"}) + if not request.GET.get('l'): + return JsonResponse({"err": "Limit required via 'l' query param"}) + else: + limit = int(request.GET['l']) + if not request.GET.get('o'): + return JsonResponse({"err": "Offset required via 'o' query param"}) + else: + offset = int(request.GET['o']) - if limit > 250: - return JsonResponse({"err": "Limit cannot be higher than 250"}) + if limit > 250: + return JsonResponse({"err": "Limit cannot be higher than 250"}) - dateone = datetime.fromtimestamp(int(request.GET['s'])) - datetwo = datetime.fromtimestamp(int(request.GET['e'])) - iable = Post.objects.filter(created__range=(dateone, datetwo)).order_by('-created')[offset:offset + limit] - resparr = [] + dateone = datetime.fromtimestamp(int(request.GET['s'])) + datetwo = datetime.fromtimestamp(int(request.GET['e'])) + iable = Post.objects.filter(created__range=(dateone, datetwo)).order_by('-created')[offset:offset + limit] + resparr = [] - for post in iable: - resparr.append({ - 'id': post.id, - 'created': django.utils.dateformat.format(post.created, 'U'), - 'user': post.creator.username, - 'community': post.community_id, - 'feeling': post.feeling, - 'spoiler': post.spoils, - 'content': (post.body or None), - 'drawing': (post.drawing or None), - 'screenshot': (post.screenshot or None), - 'url': (post.url or None), - }) + for post in iable: + resparr.append({ + 'id': post.id, + 'created': django.utils.dateformat.format(post.created, 'U'), + 'user': post.creator.username, + 'community': post.community_id, + 'feeling': post.feeling, + 'spoiler': post.spoils, + 'content': (post.body or None), + 'drawing': (post.drawing or None), + 'screenshot': (post.screenshot or None), + 'url': (post.url or None), + }) - #return HttpResponse(msgpack.packb(resparr), content_type='application/x-msgpack') - return JsonResponse(resparr, safe=False) - + #return HttpResponse(msgpack.packb(resparr), content_type='application/x-msgpack') + return JsonResponse(resparr, safe=False) + def user_tools(request, username): - if not request.user.is_authenticated: - raise Http404() - if not request.user.can_manage(): - raise Http404() - user = get_object_or_404(User, username__iexact=username) - profile = user.profile() - # check if the requesting user is allowed to change someone - if user.has_authority(request.user): - raise Http404() - seen_by = MetaViews.objects.filter(target_user=user).distinct().order_by('-id')[:10] - has_seen = MetaViews.objects.filter(from_user=user).distinct().order_by('-id')[:10] - - ''' - findattempt = LoginAttempt.objects.filter(user=user).order_by('-id')[:1] - for findattempt in findattempt: - accountmatch = LoginAttempt.objects.filter(addr__in=[findattempt.addr]) - ''' - - return render(request, 'closedverse_main/man/usertools.html', { - 'title': 'Admin tools', - 'user': user, - 'seen_by': seen_by, - 'has_seen': has_seen, - 'profile': profile, - 'min_lvl_metadata_perms': settings.min_lvl_metadata_perms, - }) - + if not request.user.is_authenticated: + raise Http404() + if not request.user.can_manage(): + raise Http404() + user = get_object_or_404(User, username__iexact=username) + profile = user.profile() + # check if the requesting user is allowed to change someone + if user.has_authority(request.user): + raise Http404() + seen_by = MetaViews.objects.filter(target_user=user).distinct().order_by('-id')[:10] + has_seen = MetaViews.objects.filter(from_user=user).distinct().order_by('-id')[:10] + + ''' + findattempt = LoginAttempt.objects.filter(user=user).order_by('-id')[:1] + for findattempt in findattempt: + accountmatch = LoginAttempt.objects.filter(addr__in=[findattempt.addr]) + ''' + + return render(request, 'closedverse_main/man/usertools.html', { + 'title': 'Admin tools', + 'user': user, + 'seen_by': seen_by, + 'has_seen': has_seen, + 'profile': profile, + 'min_lvl_metadata_perms': settings.min_lvl_metadata_perms, + }) + def user_tools_meta(request, username): - if not request.user.is_authenticated: - raise Http404() - if not request.user.can_manage(): - raise Http404() - if request.user.level < settings.min_lvl_metadata_perms: - raise Http404() - user = get_object_or_404(User, username__iexact=username) - profile = user.profile() - # check if the requesting user is allowed to view someone - if user.has_authority(request.user): - raise Http404() - - # get the last time the page was opened - last_opened = MetaViews.objects.filter(target_user=user, from_user=request.user).order_by('-created').first() - # check if 24 hours have passed - try: - if not last_opened and (datetime.now() - last_opened.created).total_seconds() < 86400: - MetaViews.objects.create(target_user=user, from_user=request.user) - except: - MetaViews.objects.create(target_user=user, from_user=request.user) - - seen_by = MetaViews.objects.filter(target_user=user).distinct().order_by('-id')[:50] - #has_seen = MetaViews.objects.filter(from_user=user).distinct().order_by('-id')[:50] - log_attempt = LoginAttempt.objects.filter(user=user).order_by('-id')[:50] - accountmatch = User.objects.filter( - Q(addr=user.addr) | Q(addr=user.signup_addr) - ).exclude(username=user.username) - - ''' - findattempt = LoginAttempt.objects.filter(user=user).order_by('-id')[:1] - for findattempt in findattempt: - accountmatch = LoginAttempt.objects.filter(addr__in=[findattempt.addr]) - ''' - - return render(request, 'closedverse_main/man/usertoolsmeta.html', { - 'title': 'Admin tools', - 'user': user, - 'seen_by': seen_by, - 'accountmatch': accountmatch, - 'log_attempt': log_attempt, - 'profile': profile, - 'min_lvl_metadata_perms': settings.min_lvl_metadata_perms, - }) - + if not request.user.is_authenticated: + raise Http404() + if not request.user.can_manage(): + raise Http404() + if request.user.level < settings.min_lvl_metadata_perms: + raise Http404() + user = get_object_or_404(User, username__iexact=username) + profile = user.profile() + # check if the requesting user is allowed to view someone + if user.has_authority(request.user): + raise Http404() + + # get the last time the page was opened + last_opened = MetaViews.objects.filter(target_user=user, from_user=request.user).order_by('-created').first() + # check if 24 hours have passed + try: + if not last_opened and (datetime.now() - last_opened.created).total_seconds() < 86400: + MetaViews.objects.create(target_user=user, from_user=request.user) + except: + MetaViews.objects.create(target_user=user, from_user=request.user) + + seen_by = MetaViews.objects.filter(target_user=user).distinct().order_by('-id')[:50] + #has_seen = MetaViews.objects.filter(from_user=user).distinct().order_by('-id')[:50] + log_attempt = LoginAttempt.objects.filter(user=user).order_by('-id')[:50] + accountmatch = User.objects.filter( + Q(addr=user.addr) | Q(addr=user.signup_addr) + ).exclude(username=user.username) + + ''' + findattempt = LoginAttempt.objects.filter(user=user).order_by('-id')[:1] + for findattempt in findattempt: + accountmatch = LoginAttempt.objects.filter(addr__in=[findattempt.addr]) + ''' + + return render(request, 'closedverse_main/man/usertoolsmeta.html', { + 'title': 'Admin tools', + 'user': user, + 'seen_by': seen_by, + 'accountmatch': accountmatch, + 'log_attempt': log_attempt, + 'profile': profile, + 'min_lvl_metadata_perms': settings.min_lvl_metadata_perms, + }) + def user_tools_set(request, username): - if request.method == 'POST': - if not request.user.is_authenticated: - raise Http404() - if not request.user.can_manage(): - raise Http404() - user = get_object_or_404(User, username__iexact=username) - profile = user.profile() - if user.has_authority(request.user): - raise Http404() - if request.POST.get('username') == "" or None: - return json_response('Username Invalid') - if not re.compile(r'^[A-Za-z0-9-._]{1,32}$').match(request.POST['username']) or not re.compile(r'[A-Za-z0-9]').match(request.POST['username']): - return json_response("The username either contains invalid characters or is too long (only letters + numbers, dashes, dots and underscores are allowed") - if request.POST.get('nickname') == "" or None: - return json_response('Nickname Invalid') - if request.POST.get('post_limit') == "" or None: - return json_response('Post limit Invalid') - postlimitint = int(request.POST.get('post_limit')) - if postlimitint <= -1 or postlimitint >= 999: - return json_response('Post limit Invalid') + if request.method == 'POST': + user = get_object_or_404(User, username__iexact=username) + profile = user.profile() + if not request.user.is_authenticated: + raise Http404() + if not request.user.can_manage(): + raise Http404() + if user.has_authority(request.user): + raise Http404() + if request.POST.get('username') == "" or None: + return json_response('Username Invalid') + if not re.compile(r'^[A-Za-z0-9-._]{1,32}$').match(request.POST['username']) or not re.compile(r'[A-Za-z0-9]').match(request.POST['username']): + return json_response("The username either contains invalid characters or is too long (only letters + numbers, dashes, dots and underscores are allowed") + if request.POST.get('nickname') == "" or None: + return json_response('Nickname Invalid') + if request.POST.get('post_limit') == "" or None: + return json_response('Post limit Invalid') + postlimitint = int(request.POST.get('post_limit')) + if postlimitint <= -1 or postlimitint >= 999: + return json_response('Post limit Invalid') - user.warned_reason = (request.POST.get('warned_reason') or None) - user.username = request.POST.get('username') - profile.comment = request.POST.get('profile_comment') - user.nickname = request.POST.get('nickname') - profile.limit_post = int(request.POST.get('post_limit')) - user.active = True if request.POST.get('active') is None else False - user.warned = False if request.POST.get('warned') is None else True - profile.let_freedom = True if request.POST.get('let_freedom') is None else False - profile.cannot_edit = False if request.POST.get('cannot_edit') is None else True - - purge_posts = False if request.POST.get('purge_posts') is None else True - purge_comments = False if request.POST.get('purge_comments') is None else True - restore_content = False if request.POST.get('restore_content') is None else True - - if restore_content == True: - if purge_comments or purge_posts: - return json_response('You cannot purge and restore at the same time.') - else: - Post.real.filter(creator=user, status=5, is_rm=True).update(is_rm=False, status=0) - Comment.real.filter(creator=user, status=5, is_rm=True).update(is_rm=False, status=0) - if purge_posts == True: - Post.real.filter(creator=user).update(is_rm=True, status=5) - if purge_comments == True: - Comment.real.filter(creator=user).update(is_rm=True, status=5) - - profile.save() - user.save() - AuditLog.objects.create(type=2, user=user, by=request.user, reasoning=request.POST) - return HttpResponse() - else: - raise Http404() - + user.warned_reason = (request.POST.get('warned_reason') or None) + user.username = request.POST.get('username') + profile.comment = request.POST.get('profile_comment') + user.nickname = request.POST.get('nickname') + profile.limit_post = int(request.POST.get('post_limit')) + user.active = True if request.POST.get('active') is None else False + user.warned = False if request.POST.get('warned') is None else True + profile.let_freedom = True if request.POST.get('let_freedom') is None else False + profile.cannot_edit = False if request.POST.get('cannot_edit') is None else True + + purge_posts = False if request.POST.get('purge_posts') is None else True + purge_comments = False if request.POST.get('purge_comments') is None else True + restore_content = False if request.POST.get('restore_content') is None else True + + if restore_content == True: + if purge_comments or purge_posts: + return json_response('You cannot purge and restore at the same time.') + else: + Post.real.filter(creator=user, status=5, is_rm=True).update(is_rm=False, status=0) + Comment.real.filter(creator=user, status=5, is_rm=True).update(is_rm=False, status=0) + if purge_posts == True: + Post.real.filter(creator=user).update(is_rm=True, status=5) + if purge_comments == True: + Comment.real.filter(creator=user).update(is_rm=True, status=5) + + profile.save() + user.save() + AuditLog.objects.create(type=2, user=user, by=request.user, reasoning=request.POST) + return HttpResponse() + else: + raise Http404() + @login_required def invites(request): - invites_list = Invites.objects.filter(creator=request.user, used=False, void=False) - return render(request, 'closedverse_main/invites.html', { - 'title': 'Invites', - 'invites': invites_list, - 'invite_only': settings.invite_only, - }) - + invites_list = Invites.objects.filter(creator=request.user, used=False, void=False) + return render(request, 'closedverse_main/invites.html', { + 'title': 'Invites', + 'invites': invites_list, + 'invite_only': settings.invite_only, + }) + def create_invite(request): - if request.method == 'POST': - invite = Invites() - if not request.user.is_authenticated: - return json_response('You are not signed in.') - if not request.user.can_invite: - return json_response('You are not allowed to make new invites.') - if not settings.invite_only: - return json_response('The invite system is offline.') - existing_invites = Invites.objects.filter(creator=request.user, used=False, void=False).count() - if existing_invites >= 4: - return json_response('You already have ' + str(existing_invites) + ' active invites. You cannot create more.') - invite.creator = request.user - invite.code = str(uuid.uuid4()) - invite.save() - return HttpResponse() - else: - raise Http404() + if request.method == 'POST': + invite = Invites() + if not request.user.is_authenticated: + return json_response('You are not signed in.') + if not request.user.can_invite: + return json_response('You are not allowed to make new invites.') + if not settings.invite_only: + return json_response('The invite system is offline.') + existing_invites = Invites.objects.filter(creator=request.user, used=False, void=False).count() + if existing_invites >= 4: + return json_response('You already have ' + str(existing_invites) + ' active invites. You cannot create more.') + invite.creator = request.user + invite.code = str(uuid.uuid4()) + invite.save() + return HttpResponse() + else: + raise Http404() @require_http_methods(['POST']) # Disabling login requirement since it's in signup now. Regret? #@login_required def origin_id(request): - if not request.is_ajax(): - return HttpResponse("Please do not use this as an API!") - if not request.POST.get('a'): - return HttpResponseBadRequest() - mii = get_mii(request.POST['a']) - if not mii: - return HttpResponseBadRequest("The NNID provided doesn't exist.") - return HttpResponse(mii[0]) + if not request.headers.get('x-requested-with') == 'XMLHttpRequest': + return HttpResponse("Please do not use this as an API!") + if not request.POST.get('a'): + return HttpResponseBadRequest() + mii = get_mii(request.POST['a']) + if not mii: + return HttpResponseBadRequest("The NNID provided doesn't exist.") + return HttpResponse(mii[0]) def set_lighting(request): - if not request.session.get('lights', False): - request.session['lights'] = True - else: - request.session['lights'] = False - return HttpResponse() + if not request.session.get('lights', False): + request.session['lights'] = True + else: + request.session['lights'] = False + return HttpResponse() @require_http_methods(['POST']) @login_required def help_complaint(request): - if not request.POST.get('b'): - return HttpResponseBadRequest() - if len(request.POST['b']) > 5000: - # I know that concatenating like this is a bad habit at this point, or I should simply just use formatting, but.. - return json_response('Please do not send that many characters ('+str(len(request.POST['b']))+' characters)') - if Complaint.has_past_sent(request.user): - return json_response('Please do not send complaints that quickly (very very sorry, but there\'s a 5 minute wait to prevent spam)') - save = request.user.complaint_set.create(type=int(request.POST['a']), body=request.POST['b'], sex=request.POST.get('c', 2)) - return HttpResponse() -@login_required + if not request.POST.get('b'): + return HttpResponseBadRequest() + if len(request.POST['b']) > 5000: + # I know that concatenating like this is a bad habit at this point, or I should simply just use formatting, but.. + return json_response('Please do not send that many characters ('+str(len(request.POST['b']))+' characters)') + if Complaint.has_past_sent(request.user): + return json_response('Please do not send complaints that quickly (very very sorry, but there\'s a 5 minute wait to prevent spam)') + save = request.user.complaint_set.create(type=int(request.POST['a']), body=request.POST['b'], sex=request.POST.get('c', 2)) + return HttpResponse() def server_stat(request): - all_stats = { - 'communities': Community.objects.filter().count(), - 'posts': Post.objects.filter().count(), - 'users': User.objects.filter().count(), - 'complaints': Complaint.objects.filter().count(), - 'comments': Comment.objects.filter().count(), - 'messages': Message.objects.filter().count(), - 'yeahs': Yeah.objects.filter().count(), - 'notifications': Notification.objects.filter().count(), - 'follows': Follow.objects.filter().count(), - 'friendships': Friendship.objects.filter().count(), - } - if request.GET.get('json'): - return JsonResponse(all_stats) - return render(request, 'closedverse_main/help/stats.html', all_stats) + all_stats = { + 'communities': Community.objects.filter().count(), + 'posts': Post.objects.filter().count(), + 'users': User.objects.filter().count(), + 'complaints': Complaint.objects.filter().count(), + 'comments': Comment.objects.filter().count(), + 'messages': Message.objects.filter().count(), + 'yeahs': Yeah.objects.filter().count(), + 'notifications': Notification.objects.filter().count(), + 'follows': Follow.objects.filter().count(), + 'friendships': Friendship.objects.filter().count(), + } + if request.GET.get('json'): + return JsonResponse(all_stats) + return render(request, 'closedverse_main/help/stats.html', all_stats) @login_required def my_data(request): - if not request.user.is_authenticated: - return Http404 - user = request.user - log_attempt = LoginAttempt.objects.filter(user=user).order_by('-id')[:10] - history = ProfileHistory.objects.filter(user=user).order_by('-id')[:10] - creation_date = user.created.date() - datenow = date.today() - age = datenow - creation_date - return render(request, 'closedverse_main/help/my-data.html', { - 'user': user, - 'log_attempt': log_attempt, - 'history': history, - 'posts': Post.objects.filter(creator=user).count(), - 'comments': Comment.objects.filter(creator=user).count(), - 'messages': Message.objects.filter(creator=user).count(), - 'yeahs': Yeah.objects.filter(by=user).count(), - 'notifications': Notification.objects.filter(to=user).count(), - 'age': round(age.days), - 'title': 'My data', - }) + if not request.user.is_authenticated: + return Http404 + user = request.user + log_attempt = LoginAttempt.objects.filter(user=user).order_by('-id')[:10] + history = ProfileHistory.objects.filter(user=user).order_by('-id')[:10] + creation_date = user.created.date() + datenow = date.today() + age = datenow - creation_date + return render(request, 'closedverse_main/help/my-data.html', { + 'user': user, + 'log_attempt': log_attempt, + 'history': history, + 'posts': Post.objects.filter(creator=user).count(), + 'comments': Comment.objects.filter(creator=user).count(), + 'messages': Message.objects.filter(creator=user).count(), + 'yeahs': Yeah.objects.filter(by=user).count(), + 'notifications': Notification.objects.filter(to=user).count(), + 'age': round(age.days), + 'title': 'My data', + }) @login_required def change_password(request): - if not request.user.is_authenticated: - raise Http404() - user = request.user - return render(request, 'closedverse_main/change-password.html', { - 'user': user, - 'title': 'Change Password', - }) + if not request.user.is_authenticated: + raise Http404() + user = request.user + return render(request, 'closedverse_main/change-password.html', { + 'user': user, + 'title': 'Change Password', + }) def change_password_set(request): - if request.method == 'POST': - if not request.user.is_authenticated: - raise Http404() - user = request.user - old = request.POST.get('old-password') - new = request.POST.get('new-password') - confirm = request.POST.get('confirm-password') - # make sure they are filled out - # a bit inefficient but who cares? - if not old: - return json_response('Please specify your old password.') - if not new: - return json_response('Please specify your new password.') - if not confirm: - return json_response('Please specify your new password again.') - if not new == confirm: - return json_response('Passwords do not match') - if old == new: - return json_response('The old password and new password can\'t be the same.') - if not user.check_password(old): - return json_response('The old password specified does not match the user\'s password. Enter the password you use as of right now.') - # do the length check - if len(new) < settings.minimum_password_length: - return json_response('The new password must be at least ' + str(settings.minimum_password_length) + ' characters long.') - # do the thing - user.set_password(new) - user.save() - return json_response("Success! Now you can log in with your new password!") - else: - raise Http404 - + if request.method == 'POST': + if not request.user.is_authenticated: + raise Http404() + user = request.user + old = request.POST.get('old-password') + new = request.POST.get('new-password') + confirm = request.POST.get('confirm-password') + # make sure they are filled out + # a bit inefficient but who cares? + if not old: + return json_response('Please specify your old password.') + if not new: + return json_response('Please specify your new password.') + if not confirm: + return json_response('Please specify your new password again.') + if not new == confirm: + return json_response('Passwords do not match') + if old == new: + return json_response('The old password and new password can\'t be the same.') + if not user.check_password(old): + return json_response('The old password specified does not match the user\'s password. Enter the password you use as of right now.') + # do the length check + if len(new) < settings.minimum_password_length: + return json_response('The new password must be at least ' + str(settings.minimum_password_length) + ' characters long.') + # do the thing + user.set_password(new) + user.save() + return json_response("Success! Now you can log in with your new password!") + else: + raise Http404 + def whatads(request): - return render(request, 'closedverse_main/help/whatads.html', {'title': 'What are user-generated ads?'}) + return render(request, 'closedverse_main/help/whatads.html', {'title': 'What are user-generated ads?'}) @login_required -def active_clones(request): - return render(request, 'closedverse_main/help/Active_clones.html', {'title': 'Active Clones'}) -def help_approval(request): - return render(request, 'closedverse_main/help/help_approval.html', {'title': 'Approval system'}) def help_rules(request): - return render(request, 'closedverse_main/help/rules.html', {'title': 'Cedar Three Rules', 'age': settings.age_allowed}) + return render(request, 'closedverse_main/help/rules.html', {'title': 'Cedar Three Rules', 'age': settings.age_allowed}) def help_faq(request): - return render(request, 'closedverse_main/help/faq.html', {'title': 'FAQ'}) + return render(request, 'closedverse_main/help/faq.html', {'title': 'FAQ'}) def help_legal(request): - if not settings.PROD: - return HttpResponseForbidden() - return render(request, 'closedverse_main/help/legal.html', {}) + if not settings.PROD: + return HttpResponseForbidden() + return render(request, 'closedverse_main/help/legal.html', {}) def help_contact(request): - return render(request, 'closedverse_main/help/contact.html', {'title': "Contact Info"}) + return render(request, 'closedverse_main/help/contact.html', {'title': "Contact Info"}) def help_why(request): - return render(request, 'closedverse_main/help/why.html', {'title': "Why even join Cedar Three?"}) + return render(request, 'closedverse_main/help/why.html', {'title': "Why even join Cedar Three?"}) def help_login(request): - return render(request, 'closedverse_main/help/login-help.html', {'title': "Login help"}) + return render(request, 'closedverse_main/help/login-help.html', {'title': "Login help"}) def csrf_fail(request, reason): - return HttpResponseBadRequest("The CSRF check has failed.\nYour browser might not support cookies, or you need to refresh.") + return HttpResponseBadRequest("The CSRF check has failed.\nYour browser might not support cookies, or you need to refresh.") def server_err(request): - return HttpResponseServerError(traceback.format_exc(), content_type='text/plain') + return HttpResponseServerError(traceback.format_exc(), content_type='text/plain')