Guest User

models.py

a guest
May 16th, 2019
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 66.27 KB | None | 0 0
  1. from __future__ import unicode_literals
  2. from django.db import models
  3. from django.contrib.auth.models import BaseUserManager
  4. from django.db.models import Q, QuerySet, Max, F, Count, Case, When, Exists, OuterRef
  5. from django.utils import timezone
  6. from django.forms.models import model_to_dict
  7. from django.utils.dateformat import format
  8. from django.core.validators import RegexValidator, URLValidator
  9. from django.core.exceptions import ValidationError
  10. from datetime import timedelta, datetime, date, time
  11. from passlib.hash import bcrypt_sha256
  12. from closedverse import settings
  13. from . import util
  14. from random import getrandbits
  15. import uuid, json, base64
  16. from django.core.mail import send_mail
  17. from django.template.loader import render_to_string
  18. from django.urls import reverse
  19. from django.db.models.signals import pre_delete
  20. from django.dispatch import receiver
  21. import re
  22.  
  23. feelings = ((0, 'normal'), (1, 'happy'), (2, 'wink'), (3, 'surprised'), (4, 'frustrated'), (5, 'confused'), (38, 'japan'), (69, 'easter egg'), )
  24. post_status = ((0, 'ok'), (1, 'delete by user'), (2, 'delete by authority'), (3, 'delete by mod'), (4, 'delete by admin'), (5, 'account pruge'))
  25. visibility = ((0, 'show'), (1, 'friends only'), (2, 'hide'), )
  26.  
  27. # Like set() but orders
  28. def organ(seq):
  29. seen = set()
  30. seen_add = seen.add
  31. return [x for x in seq if not (x in seen or seen_add(x))]
  32.  
  33. class UserManager(BaseUserManager):
  34. # idk why this is even here
  35. def create_user(self, username, password):
  36. user = self.model(
  37. username=username,
  38. )
  39. user.set_password(password)
  40. user.save(using=self._db)
  41. return user
  42.  
  43. def closed_create_user(self, username, password, email, addr, nick, nn, gravatar):
  44. user = self.model(
  45. username = username,
  46. nickname = util.filterchars(nick),
  47. addr = addr,
  48. email = email,
  49. )
  50. if settings.PROD:
  51. if util.iphub(addr):
  52. spamuser = True
  53. if settings.disallow_proxy:
  54. # This was for me, a server error will email admins of course.
  55. raise ValueError
  56. else:
  57. spamuser = False
  58. else:
  59. spamuser = False
  60. profile = Profile.objects.model()
  61. if nn:
  62. user.avatar = nn[0]
  63. profile.origin_id = nn[2]
  64. profile.origin_info = json.dumps(nn)
  65. user.has_mh = True
  66. else:
  67. user.avatar = util.get_gravatar(email) or ('s' if getrandbits(1) else '')
  68.  
  69. user.has_mh = False
  70. user.set_password(password)
  71. user.save(using=self._db)
  72. if spamuser:
  73. profile.let_freedom = False
  74. else:
  75. profile.let_freedom = True
  76. profile.user = user
  77. profile.save()
  78. return user
  79. def create_superuser(self, username, password):
  80. user = self.model(
  81. username=username,
  82. )
  83. user.set_password(password)
  84. user.staff = True
  85. user.save()
  86. profile = Profile.objects.model()
  87. profile.user = user
  88. profile.save()
  89. return user
  90. def authenticate(self, username, password):
  91. if not username or username.isspace():
  92. return None
  93. user = self.filter(Q(username__iexact=username.replace(' ', '')) | Q(username__iexact=username) | Q(email=username))
  94. if not user.exists():
  95. return None
  96. user = user.first()
  97. # If the user is an admin, say that they don't exist
  98. # Or, if the user doesn't want username login, don't let them if they didn't enter their email
  99. if user.profile('email_login') == 2 and not user.email == username:
  100. return None
  101. elif user.profile('email_login') == 0 and user.email == username:
  102. return None
  103. try:
  104. passwd = user.check_password(password)
  105. # Check if the password is a valid bcrypt
  106. except ValueError:
  107. return (user, 2)
  108. else:
  109. if not passwd:
  110. if user.can_manage():
  111. return None
  112. return (user, False)
  113. return (user, True)
  114.  
  115. class PostManager(models.Manager):
  116. def get_queryset(self):
  117. return super(PostManager, self).get_queryset().filter(is_rm=False)
  118.  
  119. class CommunityFavoriteManager(models.Manager):
  120. def get_queryset(self):
  121. return super(CommunityFavoriteManager, self).get_queryset().filter(community__is_rm=False).exclude(community__type=3)
  122.  
  123. # Taken from https://github.com/jaredly/django-colorfield/blob/master/colorfield/fields.py
  124. color_re = re.compile('^#([A-Fa-f0-9]{6})$')
  125. validate_color = RegexValidator(color_re, "Enter a valid color", 'invalid')
  126. class ColorField(models.CharField):
  127. default_validators = [validate_color]
  128. def __init__(self, *args, **kwargs):
  129. kwargs['max_length'] = 18
  130. super(ColorField, self).__init__(*args, **kwargs)
  131.  
  132. class User(models.Model):
  133. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  134. id = models.AutoField(primary_key=True)
  135. username = models.CharField(max_length=32, unique=True)
  136. # Todo: Don't allow nickname to be null (once this is fixed, un-str-ify line 357 of views; the one with ogdata description)
  137. # Also don't let lots of other strings to be null
  138. nickname = models.CharField(max_length=64, null=True)
  139. password = models.CharField(max_length=128)
  140. email = models.EmailField(null=True, blank=True, default='')
  141. has_mh = models.BooleanField(default=False)
  142. avatar = models.CharField(max_length=1200, blank=True, default='')
  143. # LEVEL: 0-1 is default, everything else is just levels
  144. level = models.SmallIntegerField(default=0)
  145. # ROLE: This doesn't have anything
  146. role = models.SmallIntegerField(default=0, choices=((0, 'normal'), (1, 'bot'), (2, 'administrator'), (3, 'moderator'), (4, 'openverse'), (5, 'donator'), (6, 'tester'), (7, 'urapp'), (8, 'developer'), (9, 'pipinstalldjango') (10, 'staff') (11, 'Kanna' )( 12, 'realshit' ) (13, 'artcon') (14, 'contest') (15, 'gamecon') (16, 'mp') )
  147. addr = models.CharField(max_length=64, null=True, blank=True)
  148.  
  149. # Things that don't have to do with auth lol
  150. hide_online = models.BooleanField(default=False)
  151. color = ColorField(default='', null=True, blank=True)
  152.  
  153. staff = models.BooleanField(default=False)
  154. #active = models.SmallIntegerField(default=1, choices=((0, 'Disabled'), (1, 'Good'), (2, 'Redirect')))
  155. active = models.BooleanField(default=True)
  156.  
  157. is_anonymous = False
  158. is_authenticated = True
  159.  
  160. last_login = models.DateTimeField(auto_now=True)
  161. created = models.DateTimeField(auto_now_add=True)
  162. USERNAME_FIELD = 'username'
  163. EMAIL_FIELD = 'email'
  164. REQUIRED_FIELDS = []
  165.  
  166. objects = UserManager()
  167.  
  168. def __str__(self):
  169. return self.username
  170. def get_full_name(self):
  171. return self.username
  172. def get_short_name(self):
  173. return self.nickname
  174. def get_username(self):
  175. return self.username
  176. def has_module_perms(self, a):
  177. return True
  178. def has_perm(self, a):
  179. return self.staff
  180. def is_staff(self):
  181. return self.staff
  182. def is_active(self):
  183. return self.active
  184. def set_password(self, raw_password):
  185. self.password = bcrypt_sha256.using(rounds=13).hash(raw_password)
  186. def check_password(self, raw_password):
  187. return bcrypt_sha256.using(rounds=13).verify(raw_password, hash=self.password)
  188. def profile(self, thing=None):
  189. # If thing is specified, that field is retrieved
  190. if thing:
  191. return self.profile_set.all().values_list(thing, flat=True).first()
  192. # Otherwise just get full profile
  193. return self.profile_set.filter(user=self).first()
  194. def gravatar(self):
  195. g = util.get_gravatar(self.email)
  196. if not g:
  197. return settings.STATIC_URL + '/img/anonymous-mii.png'
  198. return g
  199. def mh(self):
  200. origin_info = self.profile('origin_info')
  201. if not origin_info:
  202. return None
  203. try:
  204. infodecode = json.loads(origin_info)
  205. except:
  206. return None
  207. return infodecode[0]
  208. def has_plain_avatar(self):
  209. if not self.has_mh and 'http' in self.avatar and not 'gravatar.com' in self.avatar:
  210. return True
  211. def has_avatar(self):
  212. if not self.avatar or len(self.avatar) == 1:
  213. return False
  214. return True
  215. def let_yeahnotifs(self):
  216. return self.profile('let_yeahnotifs')
  217. def limit_remaining(self):
  218. limit = self.profile('limit_post')
  219. # If False is returned, no post limit is assumed.
  220. if limit == 0:
  221. return False
  222. today_min = timezone.datetime.combine(timezone.datetime.today(), time.min)
  223. today_max = timezone.datetime.combine(timezone.datetime.today(), time.max)
  224. # recent_posts =
  225. # Posts made by the user today + posts made by the IP today +
  226. # same thing except with comments
  227. 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()
  228.  
  229. # Posts remaining
  230. return int(limit) - recent_posts
  231.  
  232. def get_class(self):
  233. first = {
  234. 1: 'tester',
  235. 2: 'administrator',
  236. 3: 'moderator',
  237. 4: 'openverse',
  238. 5: 'donator',
  239. 6: 'tester',
  240. 7: 'urapp',
  241. 8: 'developer',
  242. 9: 'pipinstalldjango'
  243. 10: 'staff'
  244. 11: 'Kanna'
  245. 12: 'Verified'
  246. 13: 'artcon'
  247. 14: 'contest'
  248. 15: 'gamecom'
  249. 16: 'mp'
  250. }.get(self.role, '')
  251. second = {
  252. 1: "Bot",
  253. 2: "Administrator",
  254. 3: "Moderator",
  255. 4: "O-PHP-enverse Man",
  256. 5: "Donator",
  257. 6: "Tester",
  258. 7: "cave story is okay",
  259. 8: "Friendship ended with PHP / Now PYTHON is my best friend",
  260. 9: "Pip install Django"
  261. 10: "Staff"
  262. 11: "Kanna Kamui from Miss Kobayashi's Dragon Maid aka Best Girl"
  263. 12: "Verified"
  264. 13: "Art Contest Winner"
  265. 14: "Contest Winner"
  266. 15: "Game Contest Winner"
  267. 16: "Mario's Princess"
  268.  
  269. }.get(self.role, '')
  270. if first:
  271. first = 'official ' + first
  272. return [first, second]
  273. def is_me(self, request):
  274. if request.user.is_authenticated:
  275. return (self == request.user)
  276. else:
  277. return False
  278. def has_freedom(self):
  279. return self.profile('let_freedom')
  280. # This is the coolest one
  281. def online_status(self, force=False):
  282. # Okay so this returns True if the user's offline, 2 if they're AFK, False if they're offline and None if they hide it
  283. if self.hide_online:
  284. return None
  285. if (timezone.now() - timedelta(seconds=50)) > self.last_login:
  286. return False
  287. elif (timezone.now() - timedelta(seconds=48)) > self.last_login:
  288. return 2
  289. else:
  290. return True
  291. def do_avatar(self, feeling=0):
  292. if self.has_mh and self.avatar:
  293. feeling = {
  294. 0: 'normal',
  295. 1: 'happy',
  296. 2: 'like',
  297. 3: 'surprised',
  298. 4: 'frustrated',
  299. 5: 'puzzled',
  300. }.get(feeling, "normal")
  301. url = 'https://mii-secure.cdn.nintendo.net/{0}_{1}_face.png'.format(self.avatar, feeling)
  302. return url
  303. elif not self.avatar:
  304. return settings.STATIC_URL + '/img/anonymous-mii.png'
  305. elif self.avatar == 's':
  306. return settings.STATIC_URL + '/img/anonymous-mii-sad.png'
  307. else:
  308. return self.avatar
  309.  
  310. def num_yeahs(self):
  311. return self.yeah_set.filter(by=self).count()
  312. def num_posts(self):
  313. return self.post_set.filter(creator=self).count()
  314. def num_comments(self):
  315. return self.comment_set.filter().count()
  316. def num_following(self):
  317. return self.follow_source.filter().count()
  318. def num_followers(self):
  319. return self.follow_target.filter().count()
  320. def num_friends(self):
  321. return self.friend_source.filter().count() + self.friend_target.filter().count()
  322. def can_follow(self, user):
  323. #if UserBlock.find_block(self, user):
  324. # return False
  325. return True
  326. def can_view(self, user):
  327. #if UserBlock.find_block(self, user, full=True):
  328. # return False
  329. return True
  330. def is_following(self, me):
  331. if not me.is_authenticated:
  332. return False
  333. if self == me:
  334. return True
  335. #if hasattr(self, 'has_follow'):
  336. # return self.has_follow
  337. return self.follow_target.filter(source=me).count() > 0
  338. def follow(self, source):
  339. if self.is_following(source) or source == self:
  340. return False
  341. if not self.can_follow(source):
  342. return False
  343. # Todo: put a follow limit here
  344. return self.follow_target.create(source=source, target=self)
  345. def unfollow(self, source):
  346. if not self.is_following(source) or source == self:
  347. return False
  348. return self.follow_target.filter(source=source, target=self).delete()
  349. def can_block(self, source):
  350. if self.can_manage():
  351. return False
  352. #if source.profile('moyenne'):
  353. # return False
  354. return True
  355. # BLOCK this user from SOURCE
  356. def make_block(self, source, full=False):
  357. if find_block(source, self):
  358. return False
  359. return UserBlock.objects.create(source=source, target=self, full=full)
  360. def get_posts(self, limit=50, offset=0, request=None):
  361. if request.user.is_authenticated:
  362. has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id)
  363. 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]
  364. else:
  365. 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')[offset:offset + limit]
  366. if request:
  367. for post in posts:
  368. post.setup(request)
  369. post.recent_comment = post.recent_comment()
  370. return posts
  371. def get_comments(self, limit=50, offset=0, request=None):
  372. if request.user.is_authenticated:
  373. has_yeah = Yeah.objects.filter(comment=OuterRef('id'), by=request.user.id)
  374. 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]
  375. else:
  376. 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')[offset:offset + limit]
  377. if request:
  378. for post in posts:
  379. post.setup(request)
  380. return posts
  381. def get_yeahed(self, type=0, limit=20, offset=0):
  382. # 0 - post, 1 - comment, 2 - any
  383. if type == 2:
  384. 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]
  385. else:
  386. 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]
  387. for thing in yeahs:
  388. if thing.post:
  389. thing.post.num_yeahs = thing.num_yeahs_post
  390. thing.post.num_comments = thing.num_comments
  391. elif thing.comment:
  392. thing.comment.num_yeahs = thing.num_yeahs_comment
  393. return yeahs
  394. def get_following(self, limit=50, offset=0, request=None):
  395. return self.follow_source.select_related('target').filter().order_by('-created')[offset:offset + limit]
  396. def get_followers(self, limit=50, offset=0, request=None):
  397. return self.follow_target.select_related('source').filter().order_by('-created')[offset:offset + limit]
  398. def notification_count(self):
  399. return self.notification_to.filter(read=False).count()
  400. def notification_read(self):
  401. return self.notification_to.filter(read=False).update(read=True)
  402. def get_notifications(self):
  403. return self.notification_to.select_related('context_post').select_related('context_comment').select_related('source').filter().order_by('-latest')[0:64]
  404. def notifications_clean(self):
  405. """ Broken - gives OperationError on MySQL
  406. notif_get = self.notification_to.all().values_list('id', flat=True)
  407. if notif_get.count() > 64:
  408. self.notification_to.filter().exclude(id__in=notif_get).delete()
  409. """
  410.  
  411. # Admin can-manage
  412. def can_manage(self):
  413. if (self.level >= 2) or self.is_staff():
  414. return True
  415. return False
  416. # Does user have authority over self?
  417. def has_authority(self, user):
  418. if self.is_staff():
  419. return False
  420. if (self.level < user.level):
  421. return True
  422. return False
  423. def friend_state(self, other):
  424. # Todo: return -1 for cannot, 0 for nothing, 1 for my friend pending, 2 for their friend pending, 3 for friends
  425. query1 = other.fr_source.filter(target=self, finished=False).exists()
  426. if query1:
  427. return 1
  428. query2 = self.fr_source.filter(target=other, finished=False).exists()
  429. if query2:
  430. return 2
  431. query3 = Friendship.find_friendship(self, other)
  432. if query3:
  433. return 3
  434. return 0
  435. def get_fr(self, other):
  436. return FriendRequest.objects.filter(Q(source=self) & Q(target=other) | Q(target=self) & Q(source=other)).exclude(finished=True)
  437. def get_frs_target(self):
  438. return FriendRequest.objects.filter(target=self, finished=False).order_by('-created')
  439. def get_frs_notif(self):
  440. return FriendRequest.objects.filter(target=self, finished=False, read=False).count()
  441. def reject_fr(self, target):
  442. fr = self.get_fr(target)
  443. if fr:
  444. try:
  445. fr.first().finish()
  446. except:
  447. pass
  448. def send_fr(self, source, body=None):
  449. if not self.get_fr(source):
  450. return FriendRequest.objects.create(source=source, target=self, body=body)
  451. def accept_fr(self, target):
  452. fr = self.get_fr(target)
  453. if fr:
  454. try:
  455. fr.first().finish()
  456. except:
  457. pass
  458. return Friendship.objects.create(source=self, target=target)
  459. def cancel_fr(self, target):
  460. fr = target.get_fr(self)
  461. if fr:
  462. try:
  463. fr.first().finish()
  464. except:
  465. pass
  466. def read_fr(self):
  467. return self.get_frs_target().update(read=True)
  468. def delete_friend(self, target):
  469. fr = Friendship.find_friendship(self, target)
  470. if fr:
  471. fr.conversation().all_read()
  472. fr.delete()
  473. def get_activity(self, limit=20, offset=0, distinct=False, friends_only=False, request=None):
  474. #Todo: make distinct work; combine friends and following, but then get posts from them
  475. friends = Friendship.get_friendships(self, 0)
  476. friend_ids = []
  477. for friend in friends:
  478. friend_ids.append(friend.other(self))
  479. follows = self.follow_source.filter().values_list('target', flat=True)
  480. if not friends_only:
  481. friend_ids.append(self.id)
  482. for thing in follows:
  483. friend_ids.append(thing)
  484. if request.user.is_authenticated:
  485. has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id)
  486. if distinct:
  487. 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]
  488. else:
  489. 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]
  490. if request:
  491. for post in posts:
  492. post.setup(request)
  493. post.recent_comment = post.recent_comment()
  494. return posts
  495. def community_favorites(self, all=False):
  496. if not all:
  497. favorites = self.communityfavorite_set.order_by('-created')[:8]
  498. else:
  499. favorites = self.communityfavorite_set.order_by('-created')
  500. communities = []
  501. for fav in favorites:
  502. communities.append(fav.community)
  503. del(favorites)
  504. return communities
  505. def wake(self, addr=None):
  506. if addr and not addr == self.addr:
  507. self.addr = addr
  508. return self.save(update_fields=['addr', 'last_login'])
  509. return self.save(update_fields=['last_login'])
  510.  
  511. def has_postspam(self, body, screenshot=None, drawing=None):
  512. latest_post = self.post_set.filter().order_by('-created')[:1]
  513. if not latest_post:
  514. return False
  515. latest_post = latest_post.first()
  516. if drawing and latest_post.drawing:
  517. if drawing == latest_post.drawing:
  518. return True
  519. elif latest_post.screenshot and screenshot and not drawing:
  520. if latest_post.screenshot == screenshot and latest_post.body == body:
  521. return True
  522. elif latest_post.body and body and not latest_post.screenshot and not latest_post.drawing:
  523. if latest_post.body == body:
  524. return True
  525. return False
  526.  
  527. def get_latest_msg(self, me):
  528. conversation = Conversation.objects.filter(Q(source=self) & Q(target=me) | Q(target=self) & Q(source=me)).order_by('-created')[:1].first()
  529. if not conversation:
  530. return False
  531. return conversation.latest_message(me)
  532. def conversations(self):
  533. return Conversation.objects.filter(Q(source=self) | Q(target=self)).order_by('-created')
  534. def msg_count(self):
  535. # Gets messages with conversations I am involved in, then looks for those unread and not by me, gets count and returns it
  536. messages = Message.objects.filter(Q(conversation__source=self.id) | Q(conversation__target=self.id)).filter(read=False).exclude(creator=self.id).count()
  537. return messages
  538. def password_reset_email(self, request):
  539. htmlmsg = render_to_string('closedverse_main/help/email.html', {
  540. 'menulogo': request.build_absolute_uri(settings.STATIC_URL + 'img/menu-logo.png'),
  541. 'contact': request.build_absolute_uri(reverse('main:help-contact')),
  542. 'link': request.build_absolute_uri(reverse('main:forgot-passwd')) + "?token=" + base64.urlsafe_b64encode(bytes(self.password, 'utf-8')).decode(),
  543. })
  544. subj = 'Closedverse password reset for "{0}"'.format(self.username)
  545. return send_mail(subject=subj, html_message=htmlmsg, from_email="Closedverse not Openverse <{0}>".format(settings.DEFAULT_FROM_EMAIL), recipient_list=[self.email], fail_silently=False)
  546. def find_related(self):
  547. 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)
  548. @staticmethod
  549. def search(query='', limit=50, offset=0, request=None):
  550. return User.objects.filter(Q(username__icontains=query) | Q(nickname__icontains=query)).order_by('-created')[offset:offset + limit]
  551. @staticmethod
  552. def email_in_use(addr, request=None):
  553. if not addr:
  554. return False
  555. if request:
  556. return User.objects.filter(email__iexact=addr).exclude(id=request.user.id).exists()
  557. else:
  558. return User.objects.filter(email__iexact=addr).exists()
  559. @staticmethod
  560. def nnid_in_use(id, request=None):
  561. if not id:
  562. return False
  563. if request:
  564. nnid_real = id.lower().replace('-', '').replace('.', '')
  565. return Profile.objects.filter(origin_id__iexact=nnid_real).exclude(user__id=request.user.id).exists()
  566. else:
  567. return Profile.objects.filter(origin_id=id).exists()
  568. @staticmethod
  569. def get_from_passwd(passwd):
  570. try:
  571. user = User.objects.get(password=base64.urlsafe_b64decode(passwd))
  572. # Too lazy to make except cases
  573. except:
  574. return False
  575. return user
  576.  
  577. class Community(models.Model):
  578. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  579. id = models.AutoField(primary_key=True)
  580. name = models.CharField(max_length=255)
  581. description = models.TextField(blank=True, default='')
  582. ico = models.CharField(max_length=255, blank=True)
  583. banner = models.CharField(max_length=255, blank=True)
  584. # Type: 0 - general, 1 - game, 2 - special
  585. type = models.SmallIntegerField(default=0, choices=((0, 'general'), (1, 'game'), (2, 'special'), (3, 'hide')))
  586. # Platform - 0/none, 1/3DS, 2/Wii U, 3/both
  587. platform = models.SmallIntegerField(default=0, choices=((0, 'none'), (1, '3ds'), (2, 'wii u'), (3, 'both')))
  588. tags = models.CharField(blank=True, null=True, max_length=255, choices=(('announcements', 'main announcement community'), ('changelog', 'main changelog'), ('activity', 'Activity Feed posting community')))
  589. created = models.DateTimeField(auto_now_add=True)
  590. updated = models.DateTimeField(auto_now=True)
  591. is_rm = models.BooleanField(default=False)
  592. is_feature = models.BooleanField(default=False)
  593. allowed_users = models.TextField(null=True, blank=True)
  594. creator = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
  595.  
  596. objects = PostManager()
  597. real = models.Manager()
  598.  
  599. def __str__(self):
  600. return self.name
  601. def icon(self):
  602. if not self.ico:
  603. return settings.STATIC_URL + "/img/title-icon-default.png"
  604. return self.ico
  605. def type_txt(self):
  606. if self.type == 1:
  607. return {
  608. 0: "",
  609. 1: "3DS Games",
  610. 2: "Wii U Games",
  611. 3: "Wii U Games\u30FB3DS Games",
  612. }.get(self.platform)
  613. else:
  614. return {
  615. 0: "General community",
  616. 1: "Game community",
  617. 2: "Special community",
  618. }.get(self.type)
  619. def type_platform(self):
  620. thing = {
  621. 0: "",
  622. 1: "3ds",
  623. 2: "wiiu",
  624. 3: "wiiu-3ds",
  625. }.get(self.platform)
  626. if thing == "":
  627. return None
  628. return "img/platform-tag-" + thing + ".png"
  629. def is_activity(self):
  630. return self.tags == 'activity'
  631. def clickable(self):
  632. return not self.is_activity() and not self.type == 3
  633. def get_posts(self, limit=50, offset=0, request=None, favorite=False):
  634. if request.user.is_authenticated:
  635. has_yeah = Yeah.objects.filter(post=OuterRef('id'), by=request.user.id)
  636. 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]
  637. else:
  638. 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')[offset:offset + limit]
  639. if request:
  640. for post in posts:
  641. post.setup(request)
  642. post.recent_comment = post.recent_comment()
  643. return posts
  644. def post_perm(self, request):
  645. if self.allowed_users:
  646. allows = self.allowed_users.split(',')
  647. if not request.user.is_authenticated or str(request.user.id) not in allows:
  648. return False
  649. return True
  650. else:
  651. return True
  652.  
  653. def has_favorite(self, request):
  654. if request.user.communityfavorite_set.filter(community=self).exists():
  655. return True
  656. return False
  657. def favorite_add(self, request):
  658. if not self.has_favorite(request):
  659. return request.user.communityfavorite_set.create(community=self)
  660. def favorite_rm(self, request):
  661. if self.has_favorite(request):
  662. return request.user.communityfavorite_set.filter(community=self).delete()
  663.  
  664.  
  665. def setup(self, request):
  666. if request.user.is_authenticated:
  667. self.post_perm = self.post_perm(request)
  668. self.has_favorite = self.has_favorite(request)
  669.  
  670. def create_post(self, request):
  671. if not self.post_perm(request):
  672. return 4
  673. limit = request.user.limit_remaining()
  674. if not limit is False and not limit > 0:
  675. return 8
  676. del(limit)
  677. if Post.real.filter(Q(creator=request.user) | Q(creator__addr=request.user.addr), created__gt=timezone.now() - timedelta(seconds=10)).exists():
  678. return 3
  679. if request.POST.get('url'):
  680. try:
  681. URLValidator()(value=request.POST['url'])
  682. except ValidationError:
  683. return 5
  684. if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')):
  685. return 6
  686. if len(request.POST['body']) > 2200 or (len(request.POST['body']) < 1 and not request.POST.get('_post_type') == 'painting'):
  687. return 1
  688. upload = None
  689. drawing = None
  690. if request.FILES.get('screen'):
  691. upload = util.image_upload(request.FILES['screen'], True)
  692. if upload == 1:
  693. return 2
  694. if request.POST.get('_post_type') == 'painting':
  695. if not request.POST.get('painting'):
  696. return 2
  697. drawing = util.image_upload(request.POST['painting'], False, True)
  698. if drawing == 1:
  699. return 2
  700. # Check for spam using our OWN ALGO!!!!!!!!!
  701. if request.user.has_postspam(request.POST.get('body'), upload, drawing):
  702. return 7
  703. 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'))
  704. new_post.is_mine = True
  705. return new_post
  706.  
  707. def search(query='', limit=50, offset=0, request=None):
  708. return Community.objects.filter(Q(name__icontains=query) | Q(description__contains=query)).exclude(type=3).order_by('-created')[offset:offset + limit]
  709.  
  710. def get_all(type=0, offset=0, limit=12):
  711. return Community.objects.filter(type=type).order_by('-created')[offset:offset + limit]
  712.  
  713. class Meta:
  714. verbose_name_plural = "communities"
  715.  
  716. # Links between communities for "related" communities
  717. class CommunityClink(models.Model):
  718. # root/also order doesn't matter, time does though
  719. root = models.ForeignKey(Community, related_name='one', on_delete=models.CASCADE)
  720. also = models.ForeignKey(Community, related_name='two', on_delete=models.CASCADE)
  721. created = models.DateTimeField(auto_now_add=True)
  722. # type: related (f) / sub (t)
  723. kind = models.BooleanField(default=False)
  724.  
  725. objects = CommunityFavoriteManager()
  726.  
  727. # Do this, or not
  728. class CommunityFavorite(models.Model):
  729. id = models.AutoField(primary_key=True)
  730. by = models.ForeignKey(User, on_delete=models.CASCADE)
  731. community = models.ForeignKey(Community, on_delete=models.CASCADE)
  732. created = models.DateTimeField(auto_now_add=True)
  733.  
  734. def __str__(self):
  735. return "Community favorite by " + str(self.by) + " for " + str(self.community)
  736.  
  737. class Post(models.Model):
  738. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  739. id = models.AutoField(primary_key=True)
  740. community = models.ForeignKey(Community, null=True, on_delete=models.CASCADE)
  741. feeling = models.SmallIntegerField(default=0, choices=feelings)
  742. body = models.TextField(null=True)
  743. drawing = models.CharField(max_length=200, null=True, blank=True)
  744. screenshot = models.CharField(max_length=1200, null=True, blank=True, default='')
  745. url = models.URLField(max_length=1200, null=True, blank=True, default='')
  746. spoils = models.BooleanField(default=False)
  747. created = models.DateTimeField(auto_now_add=True)
  748. edited = models.DateTimeField(auto_now=True)
  749. befores = models.TextField(null=True, blank=True)
  750. poll = models.ForeignKey('Poll', null=True, blank=True, on_delete=models.CASCADE)
  751. has_edit = models.BooleanField(default=False)
  752. is_rm = models.BooleanField(default=False)
  753. status = models.SmallIntegerField(default=0, choices=post_status)
  754. creator = models.ForeignKey(User, on_delete=models.CASCADE)
  755.  
  756. objects = PostManager()
  757. real = models.Manager()
  758.  
  759. def __str__(self):
  760. return self.body[:250]
  761. def is_reply(self):
  762. return False
  763. def trun(self):
  764. if self.is_rm:
  765. return 'deleted'
  766. if self.drawing:
  767. return 'drawing'
  768. else:
  769. return self.body
  770. def yt_vid(self):
  771. try:
  772. thing = re.search('(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})', self.url).group(6)
  773. except:
  774. return False
  775. return thing
  776. def has_line_trun(self):
  777. if self.body and len(self.body.splitlines()) > 10:
  778. return True
  779. return False
  780. def is_mine(self, user):
  781. if user.is_authenticated:
  782. return (self.creator == user)
  783. else:
  784. return False
  785. #def yeah_notification(self, request):
  786. # ???? What is this
  787. #Notification.give_notification
  788. def number_yeahs(self):
  789. if hasattr(self, 'num_yeahs'):
  790. return self.num_yeahs
  791. return self.yeah_set.filter(post=self).count()
  792. def has_yeah(self, request):
  793. if request.user.is_authenticated:
  794. if hasattr(self, 'yeah_given'):
  795. return self.yeah_given
  796. else:
  797. return self.yeah_set.filter(post=self, by=request.user).exists()
  798. else:
  799. return False
  800. def can_yeah(self, request):
  801. if request.user.is_authenticated:
  802. #if UserBlock.find_block(self.creator, request.user):
  803. # return False
  804. return not self.is_mine(request.user)
  805. else:
  806. return False
  807. def can_rm(self, request):
  808. if self.creator.has_authority(request.user):
  809. return True
  810. return False
  811. def give_yeah(self, request):
  812. if not request.user.has_freedom() and Yeah.objects.filter(by=request.user, created__gt=timezone.now() - timedelta(seconds=5)).exists():
  813. return False
  814. if self.has_yeah(request):
  815. return True
  816. if not self.can_yeah(request):
  817. return False
  818. return self.yeah_set.create(by=request.user, post=self)
  819. def remove_yeah(self, request):
  820. if not self.has_yeah(request):
  821. return True
  822. return self.yeah_set.filter(post=self, by=request.user).delete()
  823. def number_comments(self):
  824. # Number of comments cannot be accurate due to comment deleting
  825. #if hasattr(self, 'num_comments'):
  826. # return self.num_comments
  827. return self.comment_set.filter(original_post=self).count()
  828. def get_yeahs(self, request):
  829. return Yeah.objects.filter(type=0, post=self).order_by('-created')[0:30]
  830. def can_comment(self, request):
  831. # TODO: Make this so that if a post's comments exceeds 100, make the user able to close the comments section
  832. if self.number_comments() > 500:
  833. return False
  834. #if UserBlock.find_block(self.creator, request.user):
  835. # return False
  836. return True
  837. def get_comments(self, request=None, limit=0, offset=0):
  838. if request.user.is_authenticated:
  839. has_yeah = Yeah.objects.filter(comment=OuterRef('id'), by=request.user.id)
  840. if limit:
  841. 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]
  842. elif offset:
  843. 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:]
  844. else:
  845. comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah'), yeah_given=Exists(has_yeah)).filter(original_post=self).order_by('created')
  846. else:
  847. if limit:
  848. comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah')).filter(original_post=self).order_by('created')[offset:offset + limit]
  849. elif offset:
  850. comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah')).filter(original_post=self).order_by('created')[offset:]
  851. else:
  852. comments = self.comment_set.select_related('creator').annotate(num_yeahs=Count('yeah')).filter(original_post=self).order_by('created')
  853. if request:
  854. for post in comments:
  855. post.setup(request)
  856. return comments
  857. def create_comment(self, request):
  858. if not self.can_comment(request):
  859. return False
  860. limit = request.user.limit_remaining()
  861. if not limit is False and not limit > 0:
  862. return 8
  863. del(limit)
  864. if self.is_mine(request.user) and Comment.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=2)).exists():
  865. return 3
  866. elif not self.is_mine(request.user) and Comment.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=10)).exists():
  867. return 3
  868. if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')):
  869. return 6
  870. if len(request.POST['body']) > 2200 or (len(request.POST['body']) < 1 and not request.POST.get('_post_type') == 'painting'):
  871. return 1
  872. upload = None
  873. drawing = None
  874. if request.FILES.get('screen'):
  875. upload = util.image_upload(request.FILES['screen'], True)
  876. if upload == 1:
  877. return 2
  878. if request.POST.get('_post_type') == 'painting':
  879. if not request.POST.get('painting'):
  880. return 2
  881. drawing = util.image_upload(request.POST['painting'], False, True)
  882. if drawing == 1:
  883. return 2
  884. 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)
  885. new_post.is_mine = True
  886. return new_post
  887. def recent_comment(self):
  888. if self.number_comments() < 1:
  889. return False
  890. comments = self.comment_set.filter(spoils=False).exclude(creator=self.creator).order_by('-created')[:1]
  891. return comments.first()
  892. def change(self, request):
  893. if not self.is_mine(request.user) or self.has_edit:
  894. return 1
  895. if len(request.POST['body']) > 2200 or len(request.POST['body']) < 1:
  896. return 1
  897. if not self.befores:
  898. befores_json = []
  899. else:
  900. befores_json = json.loads(self.befores)
  901. befores_json.append(self.body)
  902. self.befores = json.dumps(befores_json)
  903. self.body = request.POST['body']
  904. self.spoils = request.POST.get('is_spoiler', False)
  905. self.feeling = request.POST.get('feeling_id', 0)
  906. if not timezone.now() < self.created + timezone.timedelta(minutes=2):
  907. self.has_edit = True
  908. return self.save()
  909. def is_favorite(self, user):
  910. profile = user.profile()
  911. if profile.favorite == self:
  912. return True
  913. else:
  914. return False
  915. def favorite(self, user):
  916. if not self.is_mine(user):
  917. return False
  918. profile = user.profile()
  919. if profile.favorite == self:
  920. return False
  921. profile.favorite = self
  922. return profile.save()
  923. def unfavorite(self, user):
  924. if not self.is_mine(user):
  925. return False
  926. profile = user.profile()
  927. if profile.favorite == self:
  928. profile.favorite = None
  929. return profile.save()
  930. def rm(self, request):
  931. if request and not self.is_mine(request.user) and not self.can_rm(request):
  932. return False
  933. if self.is_favorite(self.creator):
  934. self.unfavorite(self.creator)
  935. self.is_rm = True
  936. if self.is_mine(request.user):
  937. self.status = 1
  938. else:
  939. self.status = 2
  940. AuditLog.objects.create(type=0, post=self, user=self.creator, by=request.user)
  941. if self.screenshot:
  942. util.image_rm(self.screenshot)
  943. self.screenshot = None
  944. if self.drawing:
  945. util.image_rm(self.drawing)
  946. self.drawing = None
  947. self.save()
  948. def setup(self, request):
  949. self.has_yeah = self.has_yeah(request)
  950. self.can_yeah = self.can_yeah(request)
  951. self.is_mine = self.is_mine(request.user)
  952.  
  953.  
  954.  
  955. def max_yeahs():
  956. try:
  957. max_yeahs_post = Post.objects.annotate(num_yeahs=Count('yeah')).aggregate(max_yeahs=Max('num_yeahs'))['max_yeahs']
  958. except:
  959. return None
  960. the_post = Post.objects.annotate(num_yeahs=Count('yeah')).filter(num_yeahs=max_yeahs_post).order_by('-created')
  961. return the_post.first()
  962.  
  963. class Comment(models.Model):
  964. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  965. id = models.AutoField(primary_key=True)
  966. original_post = models.ForeignKey(Post, on_delete=models.CASCADE)
  967. community = models.ForeignKey(Community, on_delete=models.CASCADE)
  968. feeling = models.SmallIntegerField(default=0, choices=feelings)
  969. body = models.TextField(null=True)
  970. screenshot = models.CharField(max_length=1200, null=True, blank=True, default='')
  971. drawing = models.CharField(max_length=200, null=True, blank=True)
  972. spoils = models.BooleanField(default=False)
  973. created = models.DateTimeField(auto_now_add=True)
  974. edited = models.DateTimeField(auto_now=True)
  975. befores = models.TextField(null=True, blank=True)
  976. has_edit = models.BooleanField(default=False)
  977. is_rm = models.BooleanField(default=False)
  978. status = models.SmallIntegerField(default=0, choices=post_status)
  979. creator = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
  980.  
  981. objects = PostManager()
  982. real = models.Manager()
  983.  
  984. def __str__(self):
  985. return self.body[:250]
  986. def is_reply(self):
  987. return True
  988. def trun(self):
  989. if self.is_rm:
  990. return 'deleted'
  991. if self.drawing:
  992. return '(drawing)'
  993. else:
  994. return self.body
  995. def is_mine(self, user):
  996. if user.is_authenticated:
  997. return (self.creator == user)
  998. else:
  999. return False
  1000. def number_yeahs(self):
  1001. if hasattr(self, 'num_yeahs'):
  1002. return self.num_yeahs
  1003. return self.yeah_set.filter(comment=self, type=1).count()
  1004. def has_yeah(self, request):
  1005. if request.user.is_authenticated:
  1006. if hasattr(self, 'yeah_given'):
  1007. return self.yeah_given
  1008. else:
  1009. return self.yeah_set.filter(comment=self, type=1, by=request.user).exists()
  1010. else:
  1011. return False
  1012. def can_yeah(self, request):
  1013. if request.user.is_authenticated:
  1014. return not self.is_mine(request.user)
  1015. #if UserBlock.find_block(self.creator, request.user):
  1016. # return False
  1017. else:
  1018. return False
  1019. def can_rm(self, request):
  1020. if self.creator.has_authority(request.user):
  1021. return True
  1022. #if self.original_post.is_mine(request.user):
  1023. # return True
  1024. return False
  1025. def give_yeah(self, request):
  1026. if not request.user.has_freedom() and Yeah.objects.filter(by=request.user, created__gt=timezone.now() - timedelta(seconds=5)).exists():
  1027. return False
  1028. if self.has_yeah(request):
  1029. return True
  1030. if not self.can_yeah(request):
  1031. return False
  1032. return self.yeah_set.create(by=request.user, type=1, comment=self)
  1033. def remove_yeah(self, request):
  1034. if not self.has_yeah(request):
  1035. return True
  1036. return self.yeah_set.filter(comment=self, type=1, by=request.user).delete()
  1037. def get_yeahs(self, request):
  1038. return Yeah.objects.filter(type=1, comment=self).order_by('-created')[0:30]
  1039. def owner_post(self):
  1040. return (self.creator == self.original_post.creator)
  1041. def change(self, request):
  1042. if not self.is_mine(request.user) or self.has_edit:
  1043. return 1
  1044. if len(request.POST['body']) > 2200 or len(request.POST['body']) < 1:
  1045. return 1
  1046. if not self.befores:
  1047. befores_json = []
  1048. else:
  1049. befores_json = json.loads(self.befores)
  1050. befores_json.append(self.body)
  1051. self.befores = json.dumps(befores_json)
  1052. self.body = request.POST['body']
  1053. self.spoils = request.POST.get('is_spoiler', False)
  1054. self.feeling = request.POST.get('feeling_id', 0)
  1055. if not timezone.now() < self.created + timezone.timedelta(minutes=2):
  1056. self.has_edit = True
  1057. return self.save()
  1058. def rm(self, request):
  1059. if request and not self.is_mine(request.user) and not self.can_rm(request):
  1060. return False
  1061. self.is_rm = True
  1062. if self.is_mine(request.user):
  1063. self.status = 1
  1064. else:
  1065. self.status = 2
  1066. AuditLog.objects.create(type=1, comment=self, user=self.creator, by=request.user)
  1067. if self.screenshot:
  1068. util.image_rm(self.screenshot)
  1069. self.screenshot = None
  1070. if self.drawing:
  1071. util.image_rm(self.drawing)
  1072. self.drawing = None
  1073. self.save()
  1074. def setup(self, request):
  1075. self.has_yeah = self.has_yeah(request)
  1076. self.can_yeah = self.can_yeah(request)
  1077. self.is_mine = self.is_mine(request.user)
  1078.  
  1079. class Yeah(models.Model):
  1080. # Todo: make this a plain int at some point
  1081. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
  1082. by = models.ForeignKey(User, on_delete=models.CASCADE)
  1083. type = models.SmallIntegerField(default=0, choices=((0, 'post'), (1, 'comment'), ))
  1084. post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE)
  1085. # kldsjfldsfsdfd
  1086. #spam = models.BooleanField(default=False)
  1087. comment = models.ForeignKey(Comment, null=True, blank=True, on_delete=models.CASCADE)
  1088. created = models.DateTimeField(auto_now_add=True)
  1089.  
  1090. def __str__(self):
  1091. a = "from " + self.by.username + " to "
  1092. if self.post:
  1093. a += str(self.post.unique_id)
  1094. elif self.comment:
  1095. a += str(self.comment.unique_id)
  1096. return a
  1097.  
  1098. class Profile(models.Model):
  1099. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1100. id = models.AutoField(primary_key=True)
  1101. user = models.ForeignKey(User, on_delete=models.CASCADE)
  1102.  
  1103. origin_id = models.CharField(max_length=16, null=True, blank=True)
  1104. origin_info = models.CharField(max_length=255, null=True, blank=True)
  1105.  
  1106. comment = models.TextField(blank=True, default='')
  1107. country = models.CharField(max_length=120, blank=True, default='')
  1108. #birthday = models.DateField(null=True, blank=True)
  1109. id_visibility = models.SmallIntegerField(default=0, choices=visibility)
  1110. pronoun_is = models.IntegerField(default=0, choices=(
  1111. (0, "I don't know"), (1, "He/him"), (2, "She/her"), (3, "He/she"), (4, "It")
  1112. ))
  1113.  
  1114. let_friendrequest = models.SmallIntegerField(default=0, choices=visibility)
  1115.  
  1116. yeahs_visibility = models.SmallIntegerField(default=0, choices=visibility)
  1117. comments_visibility = models.SmallIntegerField(default=2, choices=visibility)
  1118. #relationship_visibility = models.SmallIntegerField(default=0, choices=visibility)
  1119. weblink = models.CharField(max_length=1200, blank=True, default='')
  1120. #gameskill = models.SmallIntegerField(default=0)
  1121. external = models.CharField(max_length=255, blank=True, default='')
  1122. favorite = models.ForeignKey(Post, blank=True, null=True, on_delete=models.CASCADE)
  1123.  
  1124. let_yeahnotifs = models.BooleanField(default=True)
  1125. let_freedom = models.BooleanField(default=True)
  1126. # 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
  1127. #let_avatar = models.BooleanField(default=False)
  1128. adopted = models.ForeignKey(User, null=True, blank=True, related_name='children', on_delete=models.CASCADE)
  1129. # Post limit, 0 for none
  1130. limit_post = models.SmallIntegerField(default=0)
  1131. # If this is true, the user can't change their avatar or nickname
  1132. cannot_edit = models.BooleanField(default=False)
  1133. email_login = models.SmallIntegerField(default=1, choices=((0, 'Do not allow'), (1, 'Okay'), (2, 'Only allow')))
  1134.  
  1135. def __str__(self):
  1136. return "profile " + str(self.unique_id) + " for " + self.user.username
  1137. def origin_id_public(self, user=None):
  1138. if user == self.user:
  1139. return self.origin_id
  1140. if self.id_visibility == 2:
  1141. return 1
  1142. elif self.id_visibility == 1:
  1143. if not user.is_authenticated or not Friendship.find_friendship(self.user, user):
  1144. return 1
  1145. return self.origin_id
  1146. elif not self.origin_id:
  1147. return None
  1148. return self.origin_id
  1149. def yeahs_visible(self, user=None):
  1150. if user == self.user:
  1151. return True
  1152. if self.yeahs_visibility == 2:
  1153. return False
  1154. elif self.yeahs_visibility == 1:
  1155. if not user.is_authenticated or not Friendship.find_friendship(self.user, user):
  1156. return False
  1157. return True
  1158. return True
  1159. def comments_visible(self, user=None):
  1160. if user == self.user:
  1161. return True
  1162. if self.comments_visibility == 2:
  1163. return False
  1164. elif self.comments_visibility == 1:
  1165. if not user.is_authenticated or not Friendship.find_friendship(self.user, user):
  1166. return False
  1167. return True
  1168. return True
  1169. def can_friend(self, user=None):
  1170. if self.let_friendrequest == 2:
  1171. return False
  1172. #if user.is_authenticated and UserBlock.find_block(self.user, user):
  1173. # return False
  1174. elif self.let_friendrequest == 1:
  1175. if not user.is_following(self.user):
  1176. return False
  1177. return True
  1178. return True
  1179. def got_fullurl(self):
  1180. if self.weblink:
  1181. try:
  1182. URLValidator()(value=self.weblink)
  1183. except ValidationError:
  1184. return False
  1185. return True
  1186. return False
  1187. def setup(self, request):
  1188. self.origin_id_public = self.origin_id_public(request.user)
  1189. self.yeahs_visible = self.yeahs_visible(request.user)
  1190. self.comments_visible = self.comments_visible(request.user)
  1191.  
  1192. class Follow(models.Model):
  1193. # Todo: remove this
  1194. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1195. id = models.AutoField(primary_key=True)
  1196. source = models.ForeignKey(User, related_name='follow_source', on_delete=models.CASCADE)
  1197. target = models.ForeignKey(User, related_name='follow_target', on_delete=models.CASCADE)
  1198. created = models.DateTimeField(auto_now_add=True)
  1199.  
  1200. def __str__(self):
  1201. return "follow: from " + self.source.username + " to " + self.target.username
  1202.  
  1203. class Notification(models.Model):
  1204. # Todo: make this a plain int at some point
  1205. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1206.  
  1207. to = models.ForeignKey(User, related_name='notification_to', on_delete=models.CASCADE)
  1208. source = models.ForeignKey(User, related_name='notification_sender', on_delete=models.CASCADE)
  1209. read = models.BooleanField(default=False)
  1210. type = models.SmallIntegerField(choices=(
  1211. (0, 'Yeah on post'),
  1212. (1, 'Yeah on comment'),
  1213. (2, 'Comment on my post'),
  1214. (3, 'Comment on others\' post'),
  1215. (4, 'Follow to me'),
  1216. ))
  1217. merges = models.TextField(blank=True, default='')
  1218. context_post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE)
  1219. context_comment = models.ForeignKey(Comment, null=True, blank=True, on_delete=models.CASCADE)
  1220.  
  1221. created = models.DateTimeField(auto_now_add=True)
  1222. latest = models.DateTimeField(auto_now=True)
  1223.  
  1224. def __str__(self):
  1225. return "Notification from " + str(self.source) + " to " + str(self.to) + " with type \"" + self.get_type_display() + "\""
  1226. def url(self):
  1227. what_type = {
  1228. 0: 'main:post-view',
  1229. 1: 'main:comment-view',
  1230. 2: 'main:post-view',
  1231. 3: 'main:post-view',
  1232. 4: 'main:user-followers',
  1233. }.get(self.type)
  1234. if self.type == 0 or self.type == 2 or self.type == 3:
  1235. what_id = self.context_post_id
  1236. elif self.type == 1:
  1237. what_id = self.context_comment_id
  1238. elif self.type == 4:
  1239. what_id = self.to.username
  1240. return reverse(what_type, args=[what_id])
  1241. def merge(self, user):
  1242. self.latest = timezone.now()
  1243. self.read = False
  1244. if not self.merges:
  1245. u = []
  1246. else:
  1247. u = json.loads(self.merges)
  1248. u.append(user.id)
  1249. self.merges = json.dumps(u)
  1250. self.save()
  1251. #return self.merged.create(source=user, to=self.to, type=self.type, context_post=self.context_post, context_comment=self.context_comment)
  1252. def set_unread(self):
  1253. self.read = False
  1254. self.latest = timezone.now()
  1255. return self.save()
  1256. def all_users(self):
  1257. if not self.merges:
  1258. u = []
  1259. else:
  1260. u = organ(json.loads(self.merges))
  1261. arr = []
  1262. arr.append(self.source)
  1263. for user in u:
  1264. # Todo: Clean this up and make this block better
  1265. if not u in arr:
  1266. try:
  1267. arr.append(User.objects.get(id=user))
  1268. except:
  1269. pass
  1270. del(u)
  1271. return arr
  1272. """
  1273. arr = []
  1274. arr.append(self.source)
  1275. merges = self.merged.filter().order_by('created')
  1276. for merge in merges:
  1277. arr.append(merge.source)
  1278. return arr
  1279. """
  1280. def setup(self, user):
  1281. # Only have is_following if the type is a follow; save SQL queries
  1282. if self.type == 4:
  1283. self.source.is_following = self.source.is_following(user)
  1284. else:
  1285. self.source.is_following = False
  1286. # In the future, please put giving notifications for classes into their respective classes (right now they're in views)
  1287. @staticmethod
  1288. def give_notification(user, type, to, post=None, comment=None):
  1289. # Just keeping this simple for now, might want to make it better later
  1290. # If the user sent a notification to this user at least 5 seconds ago, return False
  1291. # Or if user is to
  1292. # Or if yeah notifications are off and this is a yeah notification
  1293. user_is_self_unk = (not type == 3 and user == to)
  1294. is_notification_too_fast = (user.notification_sender.filter(created__gt=timezone.now() - timedelta(seconds=5), type=type).exclude(type=4) and not type == 3)
  1295. user_no_yeahnotif = (not to.let_yeahnotifs() and (type == 0 or type == 1))
  1296. if user_is_self_unk or is_notification_too_fast or user_no_yeahnotif:
  1297. return False
  1298. # Search for my own notifiaction. If it exists, set it as unread.
  1299. merge_own = user.notification_sender.filter(created__gt=timezone.now() - timedelta(hours=8), to=to, type=type, context_post=post, context_comment=comment)
  1300. if merge_own:
  1301. # If it's merged, don't unread that one, but unread what it's merging.
  1302. return merge_own.first().set_unread()
  1303. # Search for a notification already there so we can merge with it if it exists
  1304. merge_s = Notification.objects.filter(created__gt=timezone.now() - timedelta(hours=8), to=to, type=type, context_post=post, context_comment=comment)
  1305. # If it exists, merge with it. Else, create a new notification.
  1306. if merge_s:
  1307. return merge_s.first().merge(user)
  1308. else:
  1309. return user.notification_sender.create(source=user, type=type, to=to, context_post=post, context_comment=comment)
  1310.  
  1311. class Complaint(models.Model):
  1312. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1313. id = models.AutoField(primary_key=True)
  1314. creator = models.ForeignKey(User, on_delete=models.CASCADE)
  1315. type = models.SmallIntegerField(choices=(
  1316. (0, 'Bug report'),
  1317. (1, 'Suggestion'),
  1318. (2, 'Want'),
  1319. ))
  1320. body = models.TextField(blank=True, default='')
  1321. sex = models.SmallIntegerField(null=True, choices=((0, 'girl'), (1, 'privileged one'), (2, '(none)'),
  1322. ))
  1323. created = models.DateTimeField(auto_now_add=True)
  1324.  
  1325. def __str__(self):
  1326. return "\"" + str(self.body) + "\" from " + str(self.creator) + " as a " + str(self.get_sex_display())
  1327. def has_past_sent(user):
  1328. return user.complaint_set.filter(created__gt=timezone.now() - timedelta(minutes=5)).exists()
  1329.  
  1330. class FriendRequest(models.Model):
  1331. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1332. id = models.AutoField(primary_key=True)
  1333. source = models.ForeignKey(User, related_name='fr_source', on_delete=models.CASCADE)
  1334. target = models.ForeignKey(User, related_name='fr_target', on_delete=models.CASCADE)
  1335. body = models.TextField(blank=True, null=True, default='')
  1336. read = models.BooleanField(default=False)
  1337. finished = models.BooleanField(default=False)
  1338. created = models.DateTimeField(auto_now_add=True)
  1339.  
  1340. def __str__(self):
  1341. return "friend request ("+str(self.finished)+"): from " + str(self.source) + " to " + str(self.target)
  1342. def finish(self):
  1343. self.finished = True
  1344. self.save()
  1345.  
  1346. class Friendship(models.Model):
  1347. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1348. id = models.AutoField(primary_key=True)
  1349. source = models.ForeignKey(User, related_name='friend_source', on_delete=models.CASCADE)
  1350. target = models.ForeignKey(User, related_name='friend_target', on_delete=models.CASCADE)
  1351. created = models.DateTimeField(auto_now_add=True)
  1352. latest = models.DateTimeField(auto_now=True)
  1353.  
  1354. def __str__(self):
  1355. return "friendship with " + str(self.source) + " and " + str(self.target)
  1356. def update(self):
  1357. return self.save(update_fields=['latest'])
  1358. def other(self, user):
  1359. if self.source == user:
  1360. return self.target
  1361. return self.source
  1362. def conversation(self):
  1363. conv = Conversation.objects.filter(Q(source=self.source) & Q(target=self.target) | Q(target=self.source) & Q(source=self.target)).order_by('-created')
  1364. if not conv:
  1365. return Conversation.objects.create(source=self.source, target=self.target)
  1366. return conv.first()
  1367. @staticmethod
  1368. def get_friendships(user, limit=50, offset=0, latest=False, online_only=False):
  1369. if not limit:
  1370. return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-created')
  1371. if latest:
  1372. if online_only:
  1373. delta = timezone.now() - timedelta(seconds=48)
  1374. awman = []
  1375. for friend in Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-latest')[offset:offset + limit]:
  1376. if friend.other(user).last_login > delta:
  1377. awman.append(friend)
  1378. return awman
  1379. # Fix all of this at some point
  1380. # return Friendship.objects.filter(
  1381. #source=When(source__ne=user, source__last_login__gt=delta),
  1382. #target=When(target__ne=user, target__last_login__gt=delta)
  1383. #).order_by('-latest')[offset:offset + limit]
  1384. else:
  1385. return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-latest')[offset:offset + limit]
  1386. else:
  1387. return Friendship.objects.filter(Q(source=user) | Q(target=user)).order_by('-created')[offset:offset + limit]
  1388. @staticmethod
  1389. def find_friendship(first, second):
  1390. return Friendship.objects.filter(Q(source=first) & Q(target=second) | Q(target=first) & Q(source=second)).order_by('-created').first()
  1391. @staticmethod
  1392. def get_friendships_message(user, limit=20, offset=0, online_only=False):
  1393. friends_list = Friendship.get_friendships(user, limit, offset, True, online_only)
  1394. friends = []
  1395. for friend in friends_list:
  1396. friends.append(friend.other(user))
  1397. del(friends_list)
  1398. for friend in friends:
  1399. friend.get_latest_msg = friend.get_latest_msg(user)
  1400. return friends
  1401.  
  1402. class Conversation(models.Model):
  1403. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1404. id = models.AutoField(primary_key=True)
  1405. source = models.ForeignKey(User, related_name='conv_source', on_delete=models.CASCADE)
  1406. target = models.ForeignKey(User, related_name='conv_target', on_delete=models.CASCADE)
  1407. created = models.DateTimeField(auto_now_add=True)
  1408.  
  1409. def __str__(self):
  1410. return "conversation with " + str(self.source) + " and " + str(self.target)
  1411. def latest_message(self, user):
  1412. msgs = Message.objects.filter(conversation=self).order_by('-created')[:5]
  1413. if not msgs:
  1414. return False
  1415. message = msgs.first()
  1416. message.mine = message.mine(user)
  1417. return message
  1418. def unread(self, user):
  1419. return self.message_set.filter(read=False).exclude(creator=user).order_by('-created')
  1420. def set_read(self, user):
  1421. return self.unread(user).update(read=True)
  1422. def all_read(self):
  1423. return self.message_set.filter().update(read=True)
  1424. def messages(self, request, limit=50, offset=0):
  1425. msgs = self.message_set.filter().order_by('-created')[offset:offset + limit]
  1426. for msg in msgs:
  1427. msg.mine = msg.mine(request.user)
  1428. return msgs
  1429. def make_message(self, request):
  1430. if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')):
  1431. return 6
  1432. if Message.real.filter(creator=request.user, created__gt=timezone.now() - timedelta(seconds=2)).exists():
  1433. return 3
  1434. if len(request.POST['body']) > 50000 or (len(request.POST['body']) < 1 and not request.POST.get('_post_type') == 'painting'):
  1435. return 1
  1436. upload = None
  1437. drawing = None
  1438. if request.FILES.get('screen'):
  1439. upload = util.image_upload(request.FILES['screen'], True)
  1440. if upload == 1:
  1441. return 2
  1442. if request.POST.get('_post_type') == 'painting':
  1443. if not request.POST.get('painting'):
  1444. return 2
  1445. drawing = util.image_upload(request.POST['painting'], False, True)
  1446. if drawing == 1:
  1447. return 2
  1448. 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)
  1449. new_post.mine = True
  1450. return new_post
  1451. class Message(models.Model):
  1452. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1453. id = models.AutoField(primary_key=True)
  1454. conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE)
  1455. feeling = models.SmallIntegerField(default=0, choices=feelings)
  1456. body = models.TextField(null=True)
  1457. drawing = models.CharField(max_length=200, null=True, blank=True)
  1458. screenshot = models.CharField(max_length=1200, null=True, blank=True, default='')
  1459. url = models.URLField(max_length=1200, null=True, blank=True, default='')
  1460. created = models.DateTimeField(auto_now_add=True)
  1461. read = models.BooleanField(default=False)
  1462. is_rm = models.BooleanField(default=False)
  1463. creator = models.ForeignKey(User, on_delete=models.CASCADE)
  1464.  
  1465. objects = PostManager()
  1466. real = models.Manager()
  1467.  
  1468. def __str__(self):
  1469. return self.body[:250]
  1470. def trun(self):
  1471. if self.is_rm:
  1472. return 'deleted'
  1473. if self.drawing:
  1474. return '(drawing)'
  1475. else:
  1476. return self.body
  1477. def mine(self, user):
  1478. if self.creator == user:
  1479. return True
  1480. return False
  1481. def rm(self, request):
  1482. if self.conversation.source == request.user or self.conversation.target == request.user:
  1483. self.is_rm = True
  1484. if self.screenshot:
  1485. util.image_rm(self.screenshot)
  1486. self.screenshot = None
  1487. if self.drawing:
  1488. util.image_rm(self.drawing)
  1489. self.drawing = None
  1490. self.save()
  1491.  
  1492. def makeopt(ls):
  1493. if len(ls) < 1:
  1494. raise ValueError
  1495. return json.dumps(ls)
  1496.  
  1497. class ConversationInvite(models.Model):
  1498. id = models.AutoField(primary_key=True)
  1499. conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE)
  1500. source = models.ForeignKey(User, related_name='convinvite_source', on_delete=models.CASCADE)
  1501. target = models.ForeignKey(User, related_name='convinvite_target', on_delete=models.CASCADE)
  1502. body = models.TextField(blank=True, null=True, default='')
  1503. read = models.BooleanField(default=False)
  1504. finished = models.BooleanField(default=False)
  1505. created = models.DateTimeField(auto_now_add=True)
  1506.  
  1507. def __str__(self):
  1508. return "Invite to conversation " + str(self.conversation) + " from " + str(self.source) + " to " + str(self.target)
  1509.  
  1510. class Poll(models.Model):
  1511. # Todo: make this a plain int at some point
  1512. unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
  1513. id = models.AutoField(primary_key=True)
  1514. able_vote = models.BooleanField(default=True)
  1515. choices = models.TextField(default="[]")
  1516. created = models.DateTimeField(auto_now_add=True)
  1517.  
  1518. def __str__(self):
  1519. return "A poll created at " + str(self.created)
  1520. def num_votes(self):
  1521. return self.pollvote_set.count()
  1522. def vote(self, user, opt):
  1523. ex_query = self.pollvote_set.filter(by=user)
  1524. if ex_query.exists():
  1525. ex_query.first().delete()
  1526. self.pollvote_set.create(by=user, choice=opt)
  1527. def unvote(self, user):
  1528. vote = self.pollvote_set.filter(by=user).first()
  1529. if vote:
  1530. vote.delete()
  1531. def has_vote(self, user):
  1532. if not user.is_authenticated:
  1533. return False
  1534. vote = self.pollvote_set.filter(by=user)
  1535. if vote:
  1536. return (True, self.choices[vote.first().choice])
  1537. return False
  1538. def setup(self, user):
  1539. self.choices = json.loads(self.choices)
  1540. self.num_votes = self.num_votes()
  1541. self.has_vote = self.has_vote(user)
  1542. class PollVote(models.Model):
  1543. id = models.AutoField(primary_key=True)
  1544. done = models.DateTimeField(auto_now_add=True)
  1545. choice = models.SmallIntegerField(default=0)
  1546. poll = models.ForeignKey(Poll, on_delete=models.CASCADE)
  1547. by = models.ForeignKey(User, on_delete=models.CASCADE)
  1548.  
  1549. def __str__(self):
  1550. return "A vote on option " + str(self.choice) + " for poll \"" + str(self.poll) + "\" by " + str(self.by)
  1551. #def choice_votes(self):
  1552. # return PollVote.objects.filter(poll=self.poll, choice=self.choice).count()
  1553.  
  1554. class RedFlag(models.Model):
  1555. id = models.AutoField(primary_key=True)
  1556. created = models.DateTimeField(auto_now_add=True)
  1557. post = models.ForeignKey(Post, blank=True, null=True, on_delete=models.CASCADE)
  1558. comment = models.ForeignKey(Comment, blank=True, null=True, on_delete=models.CASCADE)
  1559. user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
  1560. type = models.SmallIntegerField(choices=((0, 'Post'), (1, 'Comment'), (2, 'User'), ))
  1561. 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")))
  1562. reasoning = models.TextField(default='', null=True, blank=True)
  1563.  
  1564. def __str__(self):
  1565. return "Report on a " + self.get_type_display() + " for " + self.get_reason_display() + ": " + str(self.reasoning)
  1566.  
  1567. # Login attempts: for incorrect passwords
  1568. class LoginAttempt(models.Model):
  1569. id = models.AutoField(primary_key=True)
  1570. created = models.DateTimeField(auto_now_add=True)
  1571. user = models.ForeignKey(User, on_delete=models.CASCADE)
  1572. success = models.BooleanField(default=False)
  1573. addr = models.CharField(max_length=64, null=True, blank=True)
  1574.  
  1575. def __str__(self):
  1576. return 'A login attempt to ' + str(self.user) + ' from ' + self.addr + ', ' + str(self.success)
  1577.  
  1578. # Fun
  1579. class ThermostatTouch(models.Model):
  1580. id = models.AutoField(primary_key=True)
  1581. created = models.DateTimeField(auto_now_add=True)
  1582. who = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
  1583. lvl = models.IntegerField(default=1)
  1584.  
  1585. def __str__(self):
  1586. return str(created) + " touched the thermostat, setting it to " + str(lvl) + " degrees celsius"
  1587.  
  1588. # Finally
  1589. class UserBlock(models.Model):
  1590. id = models.AutoField(primary_key=True)
  1591. created = models.DateTimeField(auto_now_add=True)
  1592. source = models.ForeignKey(User, related_name='block_source', on_delete=models.CASCADE)
  1593. target = models.ForeignKey(User, related_name='block_target', on_delete=models.CASCADE)
  1594. full = models.BooleanField(default=False)
  1595.  
  1596. def __str__(self):
  1597. return "Block created from " + str(self.source) + " to " + str(self.target)
  1598.  
  1599. @staticmethod
  1600. def find_block(first, second, full=False):
  1601. if full:
  1602. 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()
  1603. return UserBlock.objects.filter(Q(source=first) & Q(target=second) | Q(target=first) & Q(source=second)).exists()
  1604.  
  1605. class AuditLog(models.Model):
  1606. id = models.AutoField(primary_key=True)
  1607. created = models.DateTimeField(auto_now_add=True)
  1608. 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"), ))
  1609. post = models.ForeignKey(Post, related_name='audit_post', null=True, on_delete=models.CASCADE)
  1610. comment = models.ForeignKey(Comment, related_name='audit_comment', null=True, on_delete=models.CASCADE)
  1611. user = models.ForeignKey(User, related_name='audit_user', null=True, on_delete=models.CASCADE)
  1612. reasoning = models.TextField(null=True, blank=True, default="")
  1613. by = models.ForeignKey(User, related_name='audit_by', on_delete=models.CASCADE)
  1614. reversed_by = models.ForeignKey(User, null=True, related_name='audit_reverse_by', on_delete=models.CASCADE)
  1615.  
  1616. def __str__(self):
  1617. return str(self.by) + " did " + self.get_type_display() + " at " + str(self.created)
  1618. def reverse(self, user=None):
  1619. # Try to reverse what this did
  1620. if user:
  1621. self.reversed_by = user
  1622. # No switches in Python, so
  1623. if self.type == 0:
  1624. self.post.is_rm = False
  1625. self.post.status = 0
  1626. self.post.save()
  1627. return True
  1628. elif self.type == 1:
  1629. self.post.is_rm = False
  1630. self.post.status = 0
  1631. self.post.save()
  1632. return True
  1633. else:
  1634. return False
  1635.  
  1636. # TODO: MAKE THIS ACTUALLY WORK
  1637. class Restriction(models.Model):
  1638. id = models.AutoField(primary_key=True)
  1639. created = models.DateTimeField(auto_now_add=True)
  1640. type = models.SmallIntegerField(choices=((0, "Prevent yeah"), (1, "Prevent follow"), (2, "Prevent comment"), ))
  1641. post = models.ForeignKey(Post, related_name='restriction_post', null=True, on_delete=models.CASCADE)
  1642. comment = models.ForeignKey(Comment, related_name='restriction_comment', null=True, on_delete=models.CASCADE)
  1643. user = models.ForeignKey(User, related_name='restriction_user', null=True, on_delete=models.CASCADE)
  1644. by = models.ForeignKey(User, related_name='restriction_by', on_delete=models.CASCADE)
  1645.  
  1646. def __str__(self):
  1647. return "Restrict " + str(self.user) + " on " + self.get_type_display() + " at " + str(self.created)
  1648.  
  1649. class UserRequest(User):
  1650. # USER AGENT
  1651. ua = models.TextField(default='', null=True, blank=True)
  1652. latest = models.DateTimeField(auto_now=True)
  1653. status = models.SmallIntegerField(default=0, choices=((0, 'submitted'), (1, 'viewed'), (2, 'accepted'), (3, 'decline'), (4, 'ignore'), ))
  1654.  
  1655.  
  1656. # blah blah blah
  1657. # this method will be executed when...
  1658. def rm_post_image(sender, instance, **kwargs):
  1659. if instance.screenshot:
  1660. util.image_rm(instance.screenshot)
  1661. if instance.drawing:
  1662. util.image_rm(instance.drawing)
  1663. # when pre_delete happens on these
  1664. pre_delete.connect(rm_post_image, sender=Post)
  1665. pre_delete.connect(rm_post_image, sender=Comment)
  1666. pre_delete.connect(rm_post_image, sender=Message)
Add Comment
Please, Sign In to add comment