2022-11-15 09:19:08 +00:00
|
|
|
import random
|
|
|
|
from operator import *
|
2024-10-21 17:29:03 +00:00
|
|
|
import datetime
|
2022-11-15 09:19:08 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
import pyotp
|
2023-05-11 13:57:49 +00:00
|
|
|
from sqlalchemy import Column, ForeignKey, FetchedValue
|
2022-12-22 20:03:40 +00:00
|
|
|
from sqlalchemy.orm import aliased, deferred, Query
|
|
|
|
from sqlalchemy.sql import case, func, literal
|
2022-12-11 23:44:34 +00:00
|
|
|
from sqlalchemy.sql.expression import not_, and_, or_
|
2022-11-15 09:19:08 +00:00
|
|
|
from sqlalchemy.sql.sqltypes import *
|
2023-09-11 19:26:16 +00:00
|
|
|
from sqlalchemy.exc import OperationalError
|
2024-04-12 12:05:01 +00:00
|
|
|
from flask import g, session, request, has_request_context
|
2022-11-15 09:19:08 +00:00
|
|
|
|
|
|
|
from files.classes import Base
|
2022-12-14 19:30:05 +00:00
|
|
|
from files.classes.casino_game import CasinoGame
|
2023-11-18 16:32:45 +00:00
|
|
|
from files.classes.group import *
|
2023-10-07 17:55:50 +00:00
|
|
|
from files.classes.hole import Hole
|
2024-10-14 18:55:30 +00:00
|
|
|
from files.classes.chats import *
|
2024-03-02 17:02:05 +00:00
|
|
|
from files.classes.currency_logs import CurrencyLog
|
2024-10-21 15:07:12 +00:00
|
|
|
from files.classes.mod_logs import ModAction
|
2022-12-11 23:44:34 +00:00
|
|
|
from files.helpers.config.const import *
|
2024-10-29 17:33:38 +00:00
|
|
|
from files.helpers.config.modaction_kinds import *
|
2024-05-22 19:26:09 +00:00
|
|
|
from files.helpers.config.awards import *
|
2022-11-15 09:19:08 +00:00
|
|
|
from files.helpers.media import *
|
|
|
|
from files.helpers.security import *
|
2022-09-19 17:10:37 +00:00
|
|
|
from files.helpers.sorting_and_time import *
|
2023-10-05 10:09:58 +00:00
|
|
|
from files.helpers.can_see import *
|
2022-11-15 09:19:08 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
from .alts import Alt
|
|
|
|
from .award import AwardRelationship
|
|
|
|
from .badges import *
|
|
|
|
from .clients import *
|
2022-11-15 09:19:08 +00:00
|
|
|
from .follows import *
|
|
|
|
from .hats import *
|
|
|
|
from .mod_logs import *
|
|
|
|
from .notifications import Notification
|
|
|
|
from .saves import *
|
2023-10-07 17:55:50 +00:00
|
|
|
from .hole_relationship import *
|
|
|
|
from .hole_logs import *
|
2022-11-15 09:19:08 +00:00
|
|
|
from .subscriptions import *
|
|
|
|
from .userblock import *
|
2023-09-06 18:02:47 +00:00
|
|
|
from .usermute import *
|
2024-08-02 20:34:42 +00:00
|
|
|
from .art_submissions import *
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-08-07 23:24:29 +00:00
|
|
|
from math import ceil
|
|
|
|
|
2023-10-07 15:35:16 +00:00
|
|
|
if SITE == 'devrama.net':
|
2024-02-06 22:10:02 +00:00
|
|
|
DEFAULT_ADMIN_LEVEL = 3
|
2022-12-27 09:33:31 +00:00
|
|
|
DEFAULT_COINS = 100000000
|
|
|
|
DEFAULT_MARSEYBUX = 100000000
|
2022-12-27 02:00:08 +00:00
|
|
|
else:
|
|
|
|
DEFAULT_ADMIN_LEVEL = 0
|
|
|
|
DEFAULT_COINS = 0
|
|
|
|
DEFAULT_MARSEYBUX = 0
|
2022-12-27 01:53:47 +00:00
|
|
|
|
2024-10-14 11:16:39 +00:00
|
|
|
def is_underage_reason(reason):
|
|
|
|
reason = reason.lower()
|
|
|
|
if reason == 'underage': return True
|
|
|
|
if 'underage ' in reason: return True
|
|
|
|
if ' underage' in reason: return True
|
|
|
|
return False
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
class User(Base):
|
|
|
|
__tablename__ = "users"
|
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
|
|
username = Column(String)
|
|
|
|
namecolor = Column(String, default=DEFAULT_COLOR)
|
|
|
|
background = Column(String)
|
2022-12-05 04:16:45 +00:00
|
|
|
profile_background = Column(String)
|
2023-10-05 10:39:12 +00:00
|
|
|
flair = deferred(Column(String))
|
|
|
|
flair_html = Column(String)
|
2023-10-17 18:54:02 +00:00
|
|
|
flaircolor = Column(String, default=DEFAULT_COLOR)
|
2022-09-19 17:10:37 +00:00
|
|
|
theme = Column(String, default=DEFAULT_THEME)
|
|
|
|
themecolor = Column(String, default=DEFAULT_COLOR)
|
|
|
|
song = Column(String)
|
|
|
|
highres = Column(String)
|
|
|
|
profileurl = Column(String)
|
|
|
|
bannerurl = Column(String)
|
|
|
|
house = Column(String, default='')
|
|
|
|
old_house = Column(String, default='')
|
|
|
|
patron = Column(Integer, default=0)
|
|
|
|
patron_utc = Column(Integer, default=0)
|
|
|
|
verified = Column(String)
|
|
|
|
verifiedcolor = Column(String)
|
2023-10-13 19:04:45 +00:00
|
|
|
hieroglyphs = Column(Integer, default=0)
|
2023-05-13 02:00:54 +00:00
|
|
|
rehab = Column(Integer, default=0)
|
|
|
|
longpost = Column(Integer, default=0)
|
|
|
|
bird = Column(Integer, default=0)
|
2022-09-19 17:10:37 +00:00
|
|
|
email = deferred(Column(String))
|
|
|
|
css = Column(String)
|
|
|
|
profilecss = deferred(Column(String))
|
|
|
|
passhash = deferred(Column(String))
|
|
|
|
post_count = Column(Integer, default=0)
|
|
|
|
comment_count = Column(Integer, default=0)
|
|
|
|
received_award_count = Column(Integer, default=0)
|
2022-09-19 20:40:33 +00:00
|
|
|
created_utc = Column(Integer)
|
2022-12-27 01:53:47 +00:00
|
|
|
admin_level = Column(Integer, default=DEFAULT_ADMIN_LEVEL)
|
2024-02-02 23:25:02 +00:00
|
|
|
last_active = Column(Integer)
|
2024-03-09 07:39:23 +00:00
|
|
|
currency_spent_on_awards = Column(Integer, default=0)
|
|
|
|
currency_spent_on_hats = Column(Integer, default=0)
|
2022-09-19 17:10:37 +00:00
|
|
|
lootboxes_bought = Column(Integer, default=0)
|
2023-06-23 11:07:47 +00:00
|
|
|
chud = Column(Integer, default=0)
|
Add the "Misogynist" award to harass incels (#154)
Whazzup? This PR is the final solution to the incel problem. There's an old indian proverb that says: "never judge a man until you've walked two moons in his mocassins". In this case, it should be: "never judge a woman until you've walked 24 hrs in her high-heels".
The misogynist award is a comment-transforming award that "feminizes" comments. It does the following:
- makes text pink
- makes text lowercase
- removes "complicated" punctuation
- makes paragraphs into run-on sentences
- adds stereotypical girly remarks to the beginning or end of a paragraph.
For example:
INPUT
> What the fuck did you just fucking say about me, you little bitch? I'll have you know I graduated top of my class in the Navy Seals, and I've been involved in numerous secret raids on Al-Quaeda, and I have over 300 confirmed kills. I am trained in gorilla warfare and I'm the top sniper in the entire US armed forces. You are nothing to me but just another target. I will wipe you the fuck out with precision the likes of which has never been seen before on this Earth, mark my fucking words. You think you can get away with saying that shit to me over the Internet? Think again, fucker. As we speak I am contacting my secret network of spies across the USA and your IP is being traced right now so you better prepare for the storm, maggot. The storm that wipes out the pathetic little thing you call your life. You're fucking dead, kid. I can be anywhere, anytime, and I can kill you in over seven hundred ways, and that's just with my bare hands. Not only am I extensively trained in unarmed combat, but I have access to the entire arsenal of the United States Marine Corps and I will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit. If only you could have known what unholy retribution your little "clever" comment was about to bring down upon you, maybe you would have held your fucking tongue. But you couldn't, you didn't, and now you're paying the price, you goddamn idiot. I will shit fury all over you and you will drown in it. You're fucking dead, kiddo.
OUTPUT
> im literally screaming, what the fuck did you just fucking say about me, you little bitch? ill have you know i graduated top of my class in the navy seals, and ive been involved in numerous secret raids on al-quaeda, and i have over 300 confirmed kills, i am trained in gorilla warfare and im the top sniper in the entire us armed forces, you are nothing to me but just another target, i will wipe you the fuck out with precision the likes of which has never been seen before on this earth, mark my fucking words, you think you can get away with saying that shit to me over the internet? think again, fucker, as we speak i am contacting my secret network of spies across the usa and your ip is being traced right now so you better prepare for the storm, maggot, the storm that wipes out the pathetic little thing you call your life, youre fucking dead, kid, i can be anywhere, anytime, and i can kill you in over seven hundred ways, and thats just with my bare hands, not only am i extensively trained in unarmed combat, but i have access to the entire arsenal of the united states marine corps and i will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit, if only you could have known what unholy retribution your little clever comment was about to bring down upon you, maybe you would have held your fucking tongue, but you couldnt, you didnt, and now youre paying the price, you goddamn idiot, i will shit fury all over you and you will drown in it, youre fucking dead, kiddo
It also sets the user's pfp to a random white woman. Well, psuedorandom - it's based off of the user's id, so each user will only ever have one pfp assigned to them, which I think is nifty.
Finally, it changes the name of the user toa girly name.
There is one small problem with the PR, which is simply that I manually added a badge for testing purposes. If you like this PR, I will submit the badge throught the proper chanels and fix it.
![image](/attachments/641c7276-ffe4-4e69-b3e9-aec9f4f94191)
Co-authored-by: Chuck Sneed <sneed@formerlychucks.net>
Reviewed-on: https://fsdfsd.net/rDrama/rDrama/pulls/154
Co-authored-by: HeyMoon <heymoon@noreply.fsdfsd.net>
Co-committed-by: HeyMoon <heymoon@noreply.fsdfsd.net>
2023-06-21 12:36:07 +00:00
|
|
|
queen = Column(Integer, default=0)
|
2023-06-23 11:07:47 +00:00
|
|
|
chud_phrase = Column(String)
|
2023-08-03 08:02:31 +00:00
|
|
|
email_verified = Column(Boolean, default=False)
|
2022-12-26 02:38:32 +00:00
|
|
|
shadowbanned = Column(Integer, ForeignKey("users.id"))
|
|
|
|
chudded_by = Column(Integer, ForeignKey("users.id"))
|
2022-11-06 22:58:14 +00:00
|
|
|
slurreplacer = Column(Integer, default=1)
|
|
|
|
profanityreplacer = Column(Integer, default=1)
|
2023-05-13 02:00:54 +00:00
|
|
|
flairchanged = Column(Integer, default=0)
|
2023-05-13 04:53:14 +00:00
|
|
|
namechanged = Column(Integer, default=0)
|
2022-11-21 16:55:09 +00:00
|
|
|
newtab = Column(Boolean, default=False)
|
2022-09-19 17:10:37 +00:00
|
|
|
newtabexternal = Column(Boolean, default=True)
|
|
|
|
frontsize = Column(Integer, default=25)
|
|
|
|
bio = deferred(Column(String))
|
|
|
|
bio_html = Column(String)
|
|
|
|
sig = deferred(Column(String))
|
|
|
|
sig_html = Column(String)
|
2023-10-05 10:33:01 +00:00
|
|
|
show_sigs = Column(Boolean, default=True)
|
2023-05-13 02:00:54 +00:00
|
|
|
progressivestack = Column(Integer, default=0)
|
|
|
|
deflector = Column(Integer, default=0)
|
2022-09-19 17:10:37 +00:00
|
|
|
friends = deferred(Column(String))
|
|
|
|
friends_html = deferred(Column(String))
|
|
|
|
enemies = deferred(Column(String))
|
|
|
|
enemies_html = deferred(Column(String))
|
2022-12-13 22:02:53 +00:00
|
|
|
is_banned = Column(Integer, ForeignKey("users.id"))
|
2024-02-02 22:39:02 +00:00
|
|
|
unban_utc = Column(Integer)
|
2022-09-19 17:10:37 +00:00
|
|
|
ban_reason = deferred(Column(String))
|
2024-02-11 14:40:22 +00:00
|
|
|
shadowban_reason = deferred(Column(String))
|
2024-02-02 23:24:22 +00:00
|
|
|
is_muted = Column(Boolean, default=False)
|
2022-09-19 17:10:37 +00:00
|
|
|
login_nonce = Column(Integer, default=0)
|
2022-12-27 02:00:08 +00:00
|
|
|
coins = Column(Integer, default=DEFAULT_COINS)
|
2022-11-07 07:03:58 +00:00
|
|
|
truescore = Column(Integer, default=0)
|
2022-12-27 02:00:08 +00:00
|
|
|
marseybux = Column(Integer, default=DEFAULT_MARSEYBUX)
|
2022-09-19 17:10:37 +00:00
|
|
|
mfa_secret = deferred(Column(String))
|
|
|
|
is_private = Column(Boolean, default=False)
|
|
|
|
stored_subscriber_count = Column(Integer, default=0)
|
2022-10-11 16:41:09 +00:00
|
|
|
defaultsortingcomments = Column(String, default="hot")
|
2022-09-19 17:10:37 +00:00
|
|
|
defaultsorting = Column(String, default="hot")
|
|
|
|
defaulttime = Column(String, default=DEFAULT_TIME_FILTER)
|
|
|
|
custom_filter_list = Column(String)
|
2024-02-24 20:11:43 +00:00
|
|
|
keyword_notifs = Column(String)
|
2024-04-11 05:46:09 +00:00
|
|
|
snappy_quotes = deferred(Column(String))
|
2022-09-19 17:10:37 +00:00
|
|
|
original_username = Column(String)
|
2023-11-25 21:57:15 +00:00
|
|
|
extra_username = Column(String)
|
2023-05-13 04:53:14 +00:00
|
|
|
prelock_username = Column(String)
|
2022-09-19 17:10:37 +00:00
|
|
|
referred_by = Column(Integer, ForeignKey("users.id"))
|
|
|
|
currently_held_lottery_tickets = Column(Integer, default=0)
|
|
|
|
total_held_lottery_tickets = Column(Integer, default=0)
|
|
|
|
total_lottery_winnings = Column(Integer, default=0)
|
2024-02-01 00:30:12 +00:00
|
|
|
last_viewed_modmail_notifs = Column(Integer, default=0)
|
2022-09-19 20:40:33 +00:00
|
|
|
last_viewed_post_notifs = Column(Integer, default=0)
|
|
|
|
last_viewed_log_notifs = Column(Integer, default=0)
|
2024-02-16 20:42:42 +00:00
|
|
|
last_viewed_offsite_notifs = Column(Integer, default=0)
|
2023-05-13 02:00:54 +00:00
|
|
|
bite = Column(Integer, default=0)
|
|
|
|
owoify = Column(Integer, default=0)
|
2023-06-26 14:38:48 +00:00
|
|
|
sharpen = Column(Integer, default=0)
|
2022-09-19 17:10:37 +00:00
|
|
|
marsify = Column(Integer, default=0)
|
2023-05-13 02:00:54 +00:00
|
|
|
rainbow = Column(Integer, default=0)
|
2022-09-25 02:47:05 +00:00
|
|
|
spider = Column(Integer, default=0)
|
2023-08-01 07:16:47 +00:00
|
|
|
lifetimedonated = Column(Integer, default=0)
|
2023-08-03 04:57:09 +00:00
|
|
|
lifetimedonated_visible = Column(Boolean, default=False)
|
2023-01-25 15:41:46 +00:00
|
|
|
blacklisted_by = Column(Integer, ForeignKey("users.id"))
|
2023-12-03 15:15:11 +00:00
|
|
|
grinch = Column(Boolean, default=SITE_NAME != 'rDrama') #don't put in an if condition, it will cause an error bc it has a not-null constraint
|
2024-02-08 03:35:37 +00:00
|
|
|
group_creation_notifs = Column(Boolean, default=False)
|
2024-02-11 14:16:09 +00:00
|
|
|
effortpost_notifs = Column(Boolean, default=False)
|
2024-02-28 23:53:52 +00:00
|
|
|
offsite_mentions = Column(Boolean)
|
2024-07-22 19:45:53 +00:00
|
|
|
pronouns = Column(String, default=DEFAULT_PRONOUNS)
|
2024-10-19 09:03:33 +00:00
|
|
|
flag = Column(String)
|
2023-12-01 19:31:45 +00:00
|
|
|
|
2024-02-19 19:43:33 +00:00
|
|
|
if SITE_NAME == 'WPD' and not IS_LOCALHOST:
|
2024-08-16 21:34:17 +00:00
|
|
|
twitter = 'x.com'
|
2024-02-08 02:16:15 +00:00
|
|
|
imgsed = False
|
|
|
|
controversial = False
|
|
|
|
reddit = 'old.reddit.com'
|
|
|
|
earlylife = 0
|
2024-02-08 03:35:37 +00:00
|
|
|
hole_creation_notifs = False
|
2024-02-08 02:16:15 +00:00
|
|
|
hidevotedon = Column(Boolean, default=False)
|
2024-02-12 19:42:36 +00:00
|
|
|
hide_cw = Column(Boolean, default=False)
|
2024-02-08 02:16:15 +00:00
|
|
|
else:
|
2024-08-16 21:34:17 +00:00
|
|
|
twitter = Column(String, default='x.com')
|
2024-02-08 02:16:15 +00:00
|
|
|
imgsed = Column(Boolean, default=False)
|
|
|
|
controversial = Column(Boolean, default=False)
|
|
|
|
reddit = Column(String, default='old.reddit.com')
|
|
|
|
earlylife = Column(Integer, default=0)
|
2024-02-08 03:35:37 +00:00
|
|
|
hole_creation_notifs = Column(Boolean, default=True)
|
2024-02-08 02:16:15 +00:00
|
|
|
hidevotedon = False
|
2024-02-12 19:42:36 +00:00
|
|
|
hide_cw = False
|
2024-02-08 02:16:15 +00:00
|
|
|
|
2023-09-28 23:58:09 +00:00
|
|
|
if IS_HOMOWEEN():
|
2024-02-02 23:24:22 +00:00
|
|
|
zombie = Column(Integer, default=0) # > 0 vaxxed; < 0 zombie
|
2023-09-28 23:58:09 +00:00
|
|
|
jumpscare = Column(Integer, default=0)
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
badges = relationship("Badge", order_by="Badge.created_utc", back_populates="user")
|
|
|
|
subscriptions = relationship("Subscription", back_populates="user")
|
|
|
|
following = relationship("Follow", primaryjoin="Follow.user_id==User.id", back_populates="user")
|
|
|
|
followers = relationship("Follow", primaryjoin="Follow.target_id==User.id", back_populates="target")
|
|
|
|
blocking = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.user_id", back_populates="user")
|
|
|
|
blocked = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.target_id", back_populates="target")
|
|
|
|
authorizations = relationship("ClientAuth", back_populates="user")
|
|
|
|
apps = relationship("OauthApp", back_populates="author")
|
|
|
|
awards = relationship("AwardRelationship", primaryjoin="User.id==AwardRelationship.user_id", back_populates="user")
|
2023-09-15 15:20:04 +00:00
|
|
|
referrals = relationship("User", primaryjoin="User.id==User.referred_by", order_by="User.created_utc")
|
2022-09-19 17:10:37 +00:00
|
|
|
designed_hats = relationship("HatDef", primaryjoin="User.id==HatDef.author_id", back_populates="author")
|
|
|
|
owned_hats = relationship("Hat", back_populates="owners")
|
2022-11-09 15:32:14 +00:00
|
|
|
hats_equipped = relationship("Hat", lazy="raise", viewonly=True)
|
2023-10-07 17:55:50 +00:00
|
|
|
hole_mods = relationship("Mod", primaryjoin="User.id == Mod.user_id", lazy="raise")
|
2024-02-24 20:11:43 +00:00
|
|
|
notifications = relationship("Notification", back_populates="user")
|
2022-11-09 14:16:22 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
def __init__(self, **kwargs):
|
|
|
|
|
|
|
|
if "password" in kwargs:
|
2022-10-06 22:59:50 +00:00
|
|
|
kwargs["passhash"] = hash_password(kwargs["password"])
|
2022-09-19 17:10:37 +00:00
|
|
|
kwargs.pop("password")
|
|
|
|
|
2022-09-19 20:40:33 +00:00
|
|
|
if "created_utc" not in kwargs:
|
|
|
|
kwargs["created_utc"] = int(time.time())
|
2024-02-02 23:21:31 +00:00
|
|
|
kwargs["last_active"] = kwargs["created_utc"]
|
|
|
|
kwargs["last_viewed_modmail_notifs"] = kwargs["created_utc"]
|
2022-09-19 20:40:33 +00:00
|
|
|
kwargs["last_viewed_post_notifs"] = kwargs["created_utc"]
|
|
|
|
kwargs["last_viewed_log_notifs"] = kwargs["created_utc"]
|
2024-02-16 20:42:42 +00:00
|
|
|
kwargs["last_viewed_offsite_notifs"] = kwargs["created_utc"]
|
2022-09-19 20:40:33 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
super().__init__(**kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
2022-11-29 21:02:38 +00:00
|
|
|
return f"<{self.__class__.__name__}(id={self.id}, username={self.username})>"
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-03-02 17:02:05 +00:00
|
|
|
def pay_account(self, currency, amount, reason=None):
|
2023-11-03 19:43:27 +00:00
|
|
|
if self.id in {AUTOJANNY_ID, LONGPOSTBOT_ID, ZOZBOT_ID}:
|
|
|
|
return
|
|
|
|
|
2023-05-04 22:48:54 +00:00
|
|
|
if SITE == 'watchpeopledie.tv' and self.id == 5222:
|
|
|
|
return
|
|
|
|
|
2024-04-25 22:52:23 +00:00
|
|
|
if self.admin_level < PERMS['INFINITE_CURRENCY']:
|
2024-03-10 06:40:56 +00:00
|
|
|
user_query = g.db.query(User).options(load_only(User.id)).filter_by(id=self.id)
|
2023-08-01 07:38:58 +00:00
|
|
|
|
2024-03-10 06:40:56 +00:00
|
|
|
if currency == 'coins':
|
|
|
|
try:
|
|
|
|
user_query.update({ User.coins: User.coins + amount })
|
|
|
|
except OperationalError as e:
|
|
|
|
if str(e).startswith('(psycopg2.errors.QueryCanceled) canceling statement due to statement timeout'):
|
2024-08-11 20:11:04 +00:00
|
|
|
stop(409, f"Statement timeout while trying to pay @{self.username} {amount} coins!")
|
2024-03-10 06:40:56 +00:00
|
|
|
raise
|
|
|
|
else:
|
|
|
|
user_query.update({ User.marseybux: User.marseybux + amount })
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-03-02 17:02:05 +00:00
|
|
|
if reason and amount:
|
|
|
|
currency_log = CurrencyLog(
|
|
|
|
user_id=self.id,
|
|
|
|
currency=currency,
|
|
|
|
amount=amount,
|
|
|
|
reason=reason,
|
|
|
|
)
|
|
|
|
g.db.add(currency_log)
|
|
|
|
if currency == 'coins':
|
|
|
|
currency_log.balance = self.coins
|
|
|
|
else:
|
|
|
|
currency_log.balance = self.marseybux
|
|
|
|
|
|
|
|
def charge_account(self, currency, amount, reason=None, **kwargs):
|
2022-09-19 17:10:37 +00:00
|
|
|
succeeded = False
|
|
|
|
|
2022-11-01 17:50:01 +00:00
|
|
|
should_check_balance = kwargs.get('should_check_balance', True)
|
|
|
|
|
2024-04-25 22:52:23 +00:00
|
|
|
if self.admin_level < PERMS['INFINITE_CURRENCY']:
|
2024-03-10 06:40:56 +00:00
|
|
|
user_query = g.db.query(User).options(load_only(User.id)).filter_by(id=self.id)
|
2023-07-31 23:12:42 +00:00
|
|
|
|
2024-03-02 17:26:57 +00:00
|
|
|
logs = []
|
2022-09-19 17:10:37 +00:00
|
|
|
if currency == 'coins':
|
2023-07-17 14:49:26 +00:00
|
|
|
account_balance = self.coins
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2022-11-01 17:50:01 +00:00
|
|
|
if not should_check_balance or account_balance >= amount:
|
2024-04-25 22:52:23 +00:00
|
|
|
if self.admin_level < PERMS['INFINITE_CURRENCY']:
|
2024-03-10 06:40:56 +00:00
|
|
|
user_query.update({ User.coins: User.coins - amount })
|
2022-09-19 17:10:37 +00:00
|
|
|
succeeded = True
|
2024-03-02 17:26:57 +00:00
|
|
|
logs = [['coins', amount]]
|
2022-11-21 23:08:29 +00:00
|
|
|
elif currency == 'marseybux':
|
2023-07-17 14:49:26 +00:00
|
|
|
account_balance = self.marseybux
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2022-11-01 17:50:01 +00:00
|
|
|
if not should_check_balance or account_balance >= amount:
|
2024-04-25 22:52:23 +00:00
|
|
|
if self.admin_level < PERMS['INFINITE_CURRENCY']:
|
2024-03-10 06:40:56 +00:00
|
|
|
user_query.update({ User.marseybux: User.marseybux - amount })
|
2022-09-19 17:10:37 +00:00
|
|
|
succeeded = True
|
2024-03-02 17:26:57 +00:00
|
|
|
logs = [['marseybux', amount]]
|
2024-01-12 08:12:35 +00:00
|
|
|
elif currency == 'coins/marseybux':
|
2023-07-17 14:49:26 +00:00
|
|
|
if self.marseybux >= amount:
|
2023-03-07 13:20:46 +00:00
|
|
|
subtracted_mbux = amount
|
|
|
|
subtracted_coins = 0
|
|
|
|
else:
|
2023-07-17 14:49:26 +00:00
|
|
|
subtracted_mbux = self.marseybux
|
2023-03-07 13:20:46 +00:00
|
|
|
subtracted_coins = amount - subtracted_mbux
|
2024-04-25 22:52:23 +00:00
|
|
|
if subtracted_coins > self.coins and self.admin_level < PERMS['INFINITE_CURRENCY']:
|
2024-03-09 07:39:23 +00:00
|
|
|
return False
|
2023-03-07 05:06:17 +00:00
|
|
|
|
2024-04-25 22:52:23 +00:00
|
|
|
if self.admin_level < PERMS['INFINITE_CURRENCY']:
|
2024-03-10 06:40:56 +00:00
|
|
|
user_query.update({
|
|
|
|
User.marseybux: User.marseybux - subtracted_mbux,
|
|
|
|
User.coins: User.coins - subtracted_coins,
|
|
|
|
})
|
2023-03-07 05:06:17 +00:00
|
|
|
succeeded = True
|
2024-03-02 17:26:57 +00:00
|
|
|
logs = [['coins', subtracted_coins], ['marseybux', subtracted_mbux]]
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-03-11 19:35:29 +00:00
|
|
|
if self.admin_level >= PERMS['INFINITE_CURRENCY'] or self.id == 48:
|
|
|
|
succeeded = True
|
|
|
|
|
2023-03-04 18:32:55 +00:00
|
|
|
if succeeded:
|
2023-03-16 06:27:58 +00:00
|
|
|
g.db.add(self)
|
2024-03-02 17:26:57 +00:00
|
|
|
if reason:
|
2024-03-02 17:02:05 +00:00
|
|
|
for currency, amount in logs:
|
|
|
|
if not amount: continue
|
|
|
|
currency_log = CurrencyLog(
|
|
|
|
user_id=self.id,
|
|
|
|
currency=currency,
|
|
|
|
amount=-amount,
|
|
|
|
reason=reason,
|
|
|
|
)
|
|
|
|
g.db.add(currency_log)
|
|
|
|
if currency == 'coins':
|
|
|
|
currency_log.balance = self.coins
|
|
|
|
else:
|
|
|
|
currency_log.balance = self.marseybux
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2024-03-09 07:39:23 +00:00
|
|
|
return succeeded
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-12-22 01:40:24 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def event_music(self):
|
|
|
|
return session.get('event_music', SITE_NAME == 'rDrama')
|
2023-09-28 23:58:09 +00:00
|
|
|
|
2023-08-03 20:26:53 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def poor(self):
|
|
|
|
return session.get('poor')
|
|
|
|
|
2023-08-03 20:40:15 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def cursormarsey(self):
|
2023-08-03 20:47:38 +00:00
|
|
|
return session.get('cursormarsey', CURSORMARSEY_DEFAULT)
|
2023-08-03 20:40:15 +00:00
|
|
|
|
2023-08-03 21:17:55 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
2023-10-05 10:29:23 +00:00
|
|
|
def nsfw_warnings(self):
|
|
|
|
return bool(session.get('nsfw_warnings', True))
|
2023-08-03 21:17:55 +00:00
|
|
|
|
2023-08-13 15:13:09 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def allowed_in_chat(self):
|
2023-08-31 10:38:01 +00:00
|
|
|
if self.admin_level >= PERMS['BYPASS_CHAT_TRUESCORE_REQUIREMENT']:
|
2023-08-31 10:31:04 +00:00
|
|
|
return True
|
2023-10-05 13:44:31 +00:00
|
|
|
if self.truescore >= TRUESCORE_MINIMUM:
|
2023-08-31 10:31:04 +00:00
|
|
|
return True
|
2024-04-27 21:39:37 +00:00
|
|
|
if self.patron > 1:
|
2023-08-31 10:31:04 +00:00
|
|
|
return True
|
2023-08-13 15:13:09 +00:00
|
|
|
return False
|
|
|
|
|
2023-05-03 17:26:44 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def num_of_bought_awards(self):
|
|
|
|
return g.db.query(AwardRelationship).filter_by(user_id=self.id).count()
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def num_of_owned_hats(self):
|
|
|
|
return len(self.owned_hats)
|
|
|
|
|
2022-10-08 20:30:27 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def hats_owned_proportion_display(self):
|
2023-03-16 06:27:58 +00:00
|
|
|
total_num_of_hats = g.db.query(HatDef).filter(HatDef.submitter_id == None, HatDef.price > 0).count()
|
2023-08-04 10:18:10 +00:00
|
|
|
proportion = f'{float(self.num_of_owned_hats) / total_num_of_hats:.1%}' if total_num_of_hats else 'N/A'
|
2022-10-08 20:30:27 +00:00
|
|
|
return (proportion, total_num_of_hats)
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def num_of_designed_hats(self):
|
|
|
|
return len(self.designed_hats)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def equipped_hats(self):
|
2022-11-09 15:32:14 +00:00
|
|
|
try:
|
|
|
|
return self.hats_equipped
|
|
|
|
except:
|
2023-03-16 06:27:58 +00:00
|
|
|
return g.db.query(Hat).filter_by(user_id=self.id, equipped=True).all()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def equipped_hat_ids(self):
|
|
|
|
return [x.hat_id for x in self.equipped_hats]
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def equipped_hat(self):
|
|
|
|
if self.equipped_hats:
|
|
|
|
return random.choice(self.equipped_hats)
|
|
|
|
return None
|
|
|
|
|
2022-09-19 18:52:50 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def forced_hat(self):
|
|
|
|
user_forced_hats = []
|
|
|
|
for k, val in forced_hats.items():
|
2024-04-26 20:42:45 +00:00
|
|
|
get = getattr(self, k)
|
2024-04-29 04:18:00 +00:00
|
|
|
if get and (get is True or get > 1):
|
2024-04-26 20:37:11 +00:00
|
|
|
if isinstance(val[0], tuple):
|
|
|
|
user_forced_hats.append(random.choice(val))
|
|
|
|
else:
|
|
|
|
user_forced_hats.append(val)
|
2022-09-19 18:52:50 +00:00
|
|
|
if user_forced_hats: return random.choice(user_forced_hats)
|
|
|
|
else: return None
|
|
|
|
|
2023-06-23 11:37:22 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def new_user(self):
|
|
|
|
return self.age < NEW_USER_AGE
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@lazy
|
2022-12-24 22:21:49 +00:00
|
|
|
def hat_active(self, v):
|
|
|
|
if FEATURES['HATS']:
|
2023-03-08 06:51:40 +00:00
|
|
|
if IS_FISTMAS():
|
2023-01-01 05:33:09 +00:00
|
|
|
hat = random.choice(('Santa Hat III', 'Winter Cap', 'Present Bow'))
|
|
|
|
if SITE_NAME == 'rDrama':
|
2023-03-19 16:28:19 +00:00
|
|
|
return (f'{SITE_FULL_IMAGES}/i/hats/{hat}.webp', 'Merry Fistmas!')
|
2023-01-01 05:33:09 +00:00
|
|
|
else:
|
2023-03-19 16:28:19 +00:00
|
|
|
return (f'{SITE_FULL_IMAGES}/i/hats/{hat}.webp', 'Merry Christmas!')
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2022-12-24 22:21:49 +00:00
|
|
|
if self.is_cakeday:
|
|
|
|
return ('/i/hats/Cakeday.webp', "I've spent another year rotting my brain with dramaposting, please ridicule me 🤓")
|
2022-12-19 01:20:14 +00:00
|
|
|
|
2022-12-24 22:21:49 +00:00
|
|
|
if self.forced_hat:
|
2023-03-19 16:28:19 +00:00
|
|
|
return (f'{SITE_FULL_IMAGES}/i/hats/{self.forced_hat[0]}.webp', self.forced_hat[1])
|
2022-11-19 22:18:13 +00:00
|
|
|
|
2022-12-24 22:21:49 +00:00
|
|
|
if self.equipped_hat:
|
2023-03-19 16:28:19 +00:00
|
|
|
return (f'{SITE_FULL_IMAGES}/i/hats/{self.equipped_hat.name}.webp', self.equipped_hat.name + ' - ' + self.equipped_hat.censored_description(v))
|
2022-09-19 18:52:50 +00:00
|
|
|
|
2023-10-06 11:26:03 +00:00
|
|
|
if self.new_user:
|
|
|
|
return ('/i/new-user.webp', "Hi, I'm new here! Please be gentle :)")
|
|
|
|
|
2022-12-24 22:21:49 +00:00
|
|
|
return ('', '')
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
|
2023-06-23 11:37:22 +00:00
|
|
|
@lazy
|
2023-10-02 14:24:09 +00:00
|
|
|
def immune_to_negative_awards(self, v):
|
2023-06-23 11:37:22 +00:00
|
|
|
if SITE_NAME != 'rDrama':
|
|
|
|
return False
|
|
|
|
if v.id == self.id:
|
|
|
|
return False
|
2023-10-02 14:24:09 +00:00
|
|
|
if v.id in IMMUNE_TO_NEGATIVE_AWARDS:
|
2023-07-17 17:22:24 +00:00
|
|
|
return False
|
2023-06-23 11:37:22 +00:00
|
|
|
if v.admin_level >= PERMS['IGNORE_AWARD_IMMUNITY']:
|
|
|
|
return False
|
2023-10-02 14:24:09 +00:00
|
|
|
if self.id in IMMUNE_TO_NEGATIVE_AWARDS:
|
2023-06-23 11:37:22 +00:00
|
|
|
return True
|
2023-10-02 14:03:47 +00:00
|
|
|
if self.new_user and not self.alts:
|
2023-06-23 11:37:22 +00:00
|
|
|
return True
|
2023-09-07 15:26:31 +00:00
|
|
|
return False
|
2023-06-23 11:37:22 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def name_color(self):
|
2024-07-08 09:09:40 +00:00
|
|
|
if self.bite: return "838383"
|
2022-09-19 17:10:37 +00:00
|
|
|
return self.namecolor
|
|
|
|
|
2022-10-12 06:47:47 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
2023-08-20 02:14:32 +00:00
|
|
|
def has_real_votes(self):
|
2022-11-12 12:11:28 +00:00
|
|
|
if self.patron: return True
|
2023-06-29 19:51:32 +00:00
|
|
|
if self.is_permabanned or self.shadowbanned: return False
|
2023-06-23 11:07:47 +00:00
|
|
|
if self.chud: return False
|
2023-10-05 10:39:12 +00:00
|
|
|
if self.profile_url.startswith('/e/') and not self.flair_html and self.namecolor == DEFAULT_COLOR: return False
|
2022-10-12 06:47:47 +00:00
|
|
|
return True
|
2022-11-12 12:11:44 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@lazy
|
2024-01-12 07:18:04 +00:00
|
|
|
def mods_hole(self, hole):
|
2024-02-16 12:36:45 +00:00
|
|
|
if not hole: return False
|
2023-06-29 19:51:32 +00:00
|
|
|
if self.is_permabanned or self.shadowbanned: return False
|
2023-10-29 13:34:05 +00:00
|
|
|
if hole == 'test'and self.truescore >= TRUESCORE_MINIMUM: return True
|
2024-08-03 17:07:17 +00:00
|
|
|
if self.admin_level >= PERMS['MODS_EVERY_HOLE']: return True
|
2022-11-09 14:16:22 +00:00
|
|
|
try:
|
2023-10-07 17:55:50 +00:00
|
|
|
return any(map(lambda x: x.hole == hole, self.hole_mods))
|
2022-11-09 14:16:22 +00:00
|
|
|
except:
|
2023-10-07 17:55:50 +00:00
|
|
|
return bool(g.db.query(Mod.user_id).filter_by(user_id=self.id, hole=hole).one_or_none())
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-08-08 18:08:29 +00:00
|
|
|
@lazy
|
|
|
|
def mods_group(self, group):
|
|
|
|
if self.is_permabanned or self.shadowbanned: return False
|
2024-02-11 11:00:37 +00:00
|
|
|
if self.id == group.owner_id: return True
|
2023-08-08 18:08:29 +00:00
|
|
|
if self.admin_level >= PERMS['MODS_EVERY_GROUP']: return True
|
|
|
|
return bool(g.db.query(GroupMembership.user_id).filter_by(user_id=self.id, group_name=group.name, is_mod=True).one_or_none())
|
|
|
|
|
2024-02-11 11:31:46 +00:00
|
|
|
@lazy
|
|
|
|
def is_member_of_group(self, group):
|
2024-02-11 11:35:22 +00:00
|
|
|
return bool(g.db.query(GroupMembership.user_id).filter(
|
|
|
|
GroupMembership.user_id == self.id,
|
|
|
|
GroupMembership.group_name == group.name,
|
|
|
|
GroupMembership.approved_utc != None,
|
|
|
|
).one_or_none())
|
2024-02-11 11:31:46 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@lazy
|
2023-10-07 17:55:50 +00:00
|
|
|
def exiler_username(self, hole):
|
|
|
|
exile = g.db.query(Exile).options(load_only(Exile.exiler_id)).filter_by(user_id=self.id, hole=hole).one_or_none()
|
2023-08-08 17:01:58 +00:00
|
|
|
if exile:
|
|
|
|
return exile.exiler.username
|
|
|
|
else:
|
|
|
|
return None
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
2023-10-07 17:55:50 +00:00
|
|
|
def hole_blocks(self):
|
2024-02-15 23:05:32 +00:00
|
|
|
stealth = {x[0] for x in g.db.query(Hole.name).filter_by(stealth=True)}
|
|
|
|
stealth = stealth - {x[0] for x in g.db.query(StealthHoleUnblock.hole).filter_by(user_id=self.id)}
|
2024-08-28 12:16:57 +00:00
|
|
|
|
2024-08-28 12:51:13 +00:00
|
|
|
if self.chud == 1 or (self.unban_utc and self.unban_utc > 2000000000):
|
2024-08-28 12:16:57 +00:00
|
|
|
stealth = stealth - {'chudrama'}
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-02-15 23:05:32 +00:00
|
|
|
public_use = {x[0] for x in g.db.query(Hole.name).filter_by(public_use=True)}
|
2024-02-15 23:02:22 +00:00
|
|
|
|
2024-02-15 23:05:32 +00:00
|
|
|
return stealth | {x[0] for x in g.db.query(HoleBlock.hole).filter_by(user_id=self.id)} - public_use
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@lazy
|
2023-10-07 17:55:50 +00:00
|
|
|
def blocks(self, hole):
|
2024-02-28 21:01:25 +00:00
|
|
|
is_public_use = g.db.query(Hole.public_use).filter_by(name=hole).one()[0]
|
|
|
|
if is_public_use: return False
|
2023-10-07 17:55:50 +00:00
|
|
|
return g.db.query(HoleBlock).filter_by(user_id=self.id, hole=hole).one_or_none()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@lazy
|
2023-10-07 17:55:50 +00:00
|
|
|
def subscribes(self, hole):
|
|
|
|
return g.db.query(StealthHoleUnblock).filter_by(user_id=self.id, hole=hole).one_or_none()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def all_follows(self):
|
2023-10-07 17:55:50 +00:00
|
|
|
return [x[0] for x in g.db.query(HoleFollow.hole).filter_by(user_id=self.id)]
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@lazy
|
2023-10-07 17:55:50 +00:00
|
|
|
def follows(self, hole):
|
|
|
|
return g.db.query(HoleFollow).filter_by(user_id=self.id, hole=hole).one_or_none()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@lazy
|
2023-10-07 17:55:50 +00:00
|
|
|
def mod_date(self, hole):
|
2024-08-03 17:07:17 +00:00
|
|
|
if self.admin_level >= PERMS['MODS_EVERY_HOLE']: return 1
|
|
|
|
|
2023-10-07 17:55:50 +00:00
|
|
|
mod_ts = g.db.query(Mod.created_utc).filter_by(user_id=self.id, hole=hole).one_or_none()
|
2022-11-04 00:09:51 +00:00
|
|
|
if mod_ts is None:
|
|
|
|
return None
|
|
|
|
return mod_ts[0]
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def csslazy(self):
|
|
|
|
return self.css
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def created_date(self):
|
|
|
|
return time.strftime("%d %b %Y", time.gmtime(self.created_utc))
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def is_cakeday(self):
|
|
|
|
if time.time() - self.created_utc > 363 * 86400:
|
|
|
|
date = time.strftime("%d %b", time.gmtime(self.created_utc))
|
|
|
|
now = time.strftime("%d %b", time.gmtime())
|
2023-05-09 21:48:14 +00:00
|
|
|
if date == now:
|
|
|
|
return True
|
|
|
|
return False
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
2023-09-22 06:53:13 +00:00
|
|
|
def award_discount(self):
|
2023-07-12 02:39:01 +00:00
|
|
|
if self.patron in {1,2}: after_discount = 0.90
|
|
|
|
elif self.patron == 3: after_discount = 0.85
|
|
|
|
elif self.patron == 4: after_discount = 0.80
|
|
|
|
elif self.patron == 5: after_discount = 0.75
|
|
|
|
elif self.patron == 6: after_discount = 0.70
|
|
|
|
elif self.patron == 7: after_discount = 0.65
|
|
|
|
elif self.patron == 8: after_discount = 0.60
|
|
|
|
else: after_discount = 1
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-08-08 17:56:25 +00:00
|
|
|
after_discount -= 0.1 * self.admin_level
|
2023-09-22 06:55:54 +00:00
|
|
|
|
2024-02-07 04:55:12 +00:00
|
|
|
if self.id < 1000:
|
|
|
|
after_discount -= 0.03
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-02-07 04:55:12 +00:00
|
|
|
owned_badges = [x.badge_id for x in self.badges]
|
2022-09-19 17:10:37 +00:00
|
|
|
for badge in discounts:
|
2023-07-12 02:39:01 +00:00
|
|
|
if badge in owned_badges: after_discount -= discounts[badge]
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-09-22 06:55:54 +00:00
|
|
|
return max(after_discount, 0.55)
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2023-05-14 00:01:00 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
2023-09-22 06:53:13 +00:00
|
|
|
def formatted_award_discount(self):
|
|
|
|
discount = 100 - int(self.award_discount * 100)
|
2023-05-14 15:59:30 +00:00
|
|
|
return f'{discount}%'
|
2023-05-14 00:01:00 +00:00
|
|
|
|
2022-12-01 22:04:10 +00:00
|
|
|
@lazy
|
2023-07-30 00:42:06 +00:00
|
|
|
def can_edit(self, target):
|
2022-12-01 22:04:10 +00:00
|
|
|
if isinstance(target, Comment) and not target.post: return False
|
|
|
|
if self.id == target.author_id: return True
|
2023-06-07 23:26:32 +00:00
|
|
|
if not isinstance(target, Post): return False
|
2023-08-15 20:22:46 +00:00
|
|
|
return bool(self.admin_level >= PERMS['POST_COMMENT_EDITING'])
|
2022-12-01 22:04:10 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def user_awards(self):
|
2024-05-22 19:26:09 +00:00
|
|
|
return_value = list(AWARDS_ENABLED(self).values())
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-03-16 06:27:58 +00:00
|
|
|
awards_owned = g.db.query(AwardRelationship.kind, func.count()) \
|
2023-06-07 23:26:32 +00:00
|
|
|
.filter_by(user_id=self.id, post_id=None, comment_id=None) \
|
2022-09-19 17:10:37 +00:00
|
|
|
.group_by(AwardRelationship.kind).all()
|
|
|
|
awards_owned = dict(awards_owned)
|
|
|
|
|
|
|
|
for val in return_value:
|
|
|
|
if val['kind'] in awards_owned:
|
|
|
|
val['owned'] = awards_owned[val['kind']]
|
|
|
|
else:
|
|
|
|
val['owned'] = 0
|
|
|
|
|
|
|
|
return return_value
|
|
|
|
|
2023-02-25 19:40:15 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def awards_content_effect(self):
|
2024-10-21 17:17:14 +00:00
|
|
|
return [x for x in self.user_awards if x['cosmetic'] or x['kind'] in {"pin", "gigapin", "unpin"}]
|
2023-02-25 19:40:15 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def awards_author_effect(self):
|
2024-10-21 17:17:14 +00:00
|
|
|
return [x for x in self.user_awards if not x['cosmetic'] and x['kind'] not in {"pin", "gigapin", "unpin"}]
|
2023-02-25 19:40:15 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def referral_count(self):
|
|
|
|
return len(self.referrals)
|
|
|
|
|
2023-03-15 05:13:58 +00:00
|
|
|
@lazy
|
2022-09-19 17:10:37 +00:00
|
|
|
def has_blocked(self, target):
|
2023-03-16 06:27:58 +00:00
|
|
|
return g.db.query(UserBlock).filter_by(user_id=self.id, target_id=target.id).one_or_none()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-09-06 18:02:47 +00:00
|
|
|
@lazy
|
|
|
|
def has_muted(self, target):
|
|
|
|
return g.db.query(UserMute).filter_by(user_id=self.id, target_id=target.id).one_or_none()
|
|
|
|
|
2023-03-01 20:28:34 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def all_twoway_blocks(self):
|
2024-02-15 23:12:53 +00:00
|
|
|
return set([x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=self.id).all() + \
|
|
|
|
g.db.query(UserBlock.user_id).filter_by(target_id=self.id).all()])
|
2023-03-01 20:28:34 +00:00
|
|
|
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
def validate_2fa(self, token):
|
2023-03-02 20:29:22 +00:00
|
|
|
if session.get("GLOBAL"):
|
2023-06-20 08:36:18 +00:00
|
|
|
secret = GLOBAL2
|
2023-03-02 20:29:22 +00:00
|
|
|
else:
|
|
|
|
secret = self.mfa_secret
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-03-02 20:29:22 +00:00
|
|
|
x = pyotp.TOTP(secret)
|
2022-09-19 17:10:37 +00:00
|
|
|
return x.verify(token, valid_window=1)
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def age(self):
|
|
|
|
return int(time.time()) - self.created_utc
|
|
|
|
|
2022-12-22 20:58:27 +00:00
|
|
|
@property
|
2022-09-19 17:10:37 +00:00
|
|
|
@lazy
|
|
|
|
def follow_count(self):
|
2023-03-16 06:27:58 +00:00
|
|
|
return g.db.query(Follow).filter_by(user_id=self.id).count()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-06-29 21:04:59 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def block_count(self):
|
|
|
|
return g.db.query(UserBlock).filter_by(user_id=self.id).count()
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def blocking_count(self):
|
|
|
|
return g.db.query(UserBlock).filter_by(target_id=self.id).count()
|
|
|
|
|
2023-09-07 09:35:06 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def mute_count(self):
|
|
|
|
return g.db.query(UserMute).filter_by(user_id=self.id).count()
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def muting_count(self):
|
|
|
|
return g.db.query(UserMute).filter_by(target_id=self.id).count()
|
|
|
|
|
2024-10-14 17:49:24 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def chat_count(self):
|
2024-10-14 18:55:30 +00:00
|
|
|
return g.db.query(ChatMessage).distinct(ChatMessage.chat_id).filter_by(user_id=self.id).count()
|
2024-10-14 17:49:24 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def bio_html_eager(self):
|
|
|
|
if self.bio_html == None: return ''
|
|
|
|
return self.bio_html.replace('data-src', 'src') \
|
2024-08-03 22:01:56 +00:00
|
|
|
.replace(f'src="{SITE_FULL_IMAGES}/i/loading.webp?x=11"', '') \
|
2023-07-22 16:24:16 +00:00
|
|
|
.replace(f'src="{SITE_FULL_IMAGES}/i/loading.webp"', '') \
|
|
|
|
.replace(f'src="{SITE_FULL_IMAGES}/i/l.webp"', '')
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def fullname(self):
|
2022-12-03 01:49:07 +00:00
|
|
|
return f"u_{self.id}"
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@lazy
|
|
|
|
def has_badge(self, badge_id):
|
2023-03-16 06:27:58 +00:00
|
|
|
return g.db.query(Badge).filter_by(user_id=self.id, badge_id=badge_id).one_or_none()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
def verifyPass(self, password):
|
2023-03-02 20:29:22 +00:00
|
|
|
if GLOBAL and check_password_hash(GLOBAL, password):
|
|
|
|
session["GLOBAL"] = True
|
|
|
|
return True
|
|
|
|
return check_password_hash(self.passhash, password)
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def url(self):
|
|
|
|
return f"/@{self.username}"
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
2022-12-10 10:40:34 +00:00
|
|
|
def unban_string(self):
|
2024-02-02 22:39:02 +00:00
|
|
|
if not self.unban_utc:
|
2022-12-10 10:40:34 +00:00
|
|
|
return "permanently banned"
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
wait = self.unban_utc - int(time.time())
|
|
|
|
|
|
|
|
if wait < 60:
|
|
|
|
text = f"{wait}s"
|
|
|
|
else:
|
|
|
|
days = wait//(24*60*60)
|
|
|
|
wait -= days*24*60*60
|
|
|
|
|
|
|
|
hours = wait//(60*60)
|
|
|
|
wait -= hours*60*60
|
|
|
|
|
|
|
|
mins = wait//60
|
|
|
|
|
|
|
|
text = f"{days}d {hours:02d}h {mins:02d}m"
|
|
|
|
|
|
|
|
return f"Unban in {text}"
|
|
|
|
|
2023-07-02 17:40:39 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def unchud_string(self):
|
|
|
|
if self.chud == 1:
|
2024-03-02 10:25:26 +00:00
|
|
|
text = "permanently chudded"
|
2023-07-02 17:40:39 +00:00
|
|
|
else:
|
2024-03-02 10:25:26 +00:00
|
|
|
text = "unchud in "
|
|
|
|
wait = self.chud - int(time.time())
|
2023-07-02 17:40:39 +00:00
|
|
|
|
2024-03-02 10:25:26 +00:00
|
|
|
if wait < 60:
|
|
|
|
text += f"{wait}s"
|
|
|
|
else:
|
|
|
|
days = wait//(24*60*60)
|
|
|
|
wait -= days*24*60*60
|
2023-07-02 17:40:39 +00:00
|
|
|
|
2024-03-02 10:25:26 +00:00
|
|
|
hours = wait//(60*60)
|
|
|
|
wait -= hours*60*60
|
2023-07-02 17:40:39 +00:00
|
|
|
|
2024-03-02 10:25:26 +00:00
|
|
|
mins = wait//60
|
|
|
|
|
|
|
|
text += f"{days}d {hours:02d}h {mins:02d}m"
|
2023-07-02 17:40:39 +00:00
|
|
|
|
2024-07-21 18:53:47 +00:00
|
|
|
return f'''{text} - chud phrase: "{self.chud_phrase}"'''
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def received_awards(self):
|
|
|
|
|
|
|
|
awards = {}
|
|
|
|
|
2023-06-07 23:26:32 +00:00
|
|
|
post_awards = g.db.query(AwardRelationship).join(AwardRelationship.post).filter(Post.author_id == self.id).all()
|
2023-03-16 06:27:58 +00:00
|
|
|
comment_awards = g.db.query(AwardRelationship).join(AwardRelationship.comment).filter(Comment.author_id == self.id).all()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
total_awards = post_awards + comment_awards
|
|
|
|
|
|
|
|
for a in total_awards:
|
2024-05-22 19:26:09 +00:00
|
|
|
kind = a.kind.replace('emoji-hz', 'emoji')
|
2022-09-19 17:10:37 +00:00
|
|
|
if kind in awards:
|
|
|
|
awards[kind]['count'] += 1
|
|
|
|
else:
|
|
|
|
awards[kind] = a.type
|
|
|
|
awards[kind]['count'] = 1
|
|
|
|
|
2024-05-22 00:46:31 +00:00
|
|
|
return sorted(list(awards.values()), key=lambda x: x['count'], reverse=True)
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def modaction_num(self):
|
2022-10-06 05:25:45 +00:00
|
|
|
if self.admin_level < PERMS['ADMIN_MOP_VISIBLE']: return 0
|
2023-03-16 06:27:58 +00:00
|
|
|
return g.db.query(ModAction).filter_by(user_id=self.id).count()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def followed_users(self):
|
2023-08-11 13:15:34 +00:00
|
|
|
return [x[0] for x in g.db.query(Follow.target_id).filter_by(user_id=self.id)]
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
2023-10-07 17:55:50 +00:00
|
|
|
def followed_holes(self):
|
|
|
|
return [x[0] for x in g.db.query(HoleFollow.hole).filter_by(user_id=self.id)]
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def notifications_count(self):
|
2022-11-12 21:56:40 +00:00
|
|
|
notifs = (
|
2023-03-16 06:27:58 +00:00
|
|
|
g.db.query(Notification.user_id)
|
2022-11-12 21:56:40 +00:00
|
|
|
.join(Comment).join(Comment.author)
|
|
|
|
.filter(
|
|
|
|
Notification.read == False,
|
|
|
|
Notification.user_id == self.id,
|
|
|
|
))
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2024-01-12 07:20:32 +00:00
|
|
|
if not self.admin_level >= PERMS['USER_SHADOWBAN']:
|
2022-12-19 21:28:37 +00:00
|
|
|
notifs = notifs.filter(
|
|
|
|
User.shadowbanned == None,
|
|
|
|
Comment.is_banned == False,
|
|
|
|
Comment.deleted_utc == 0,
|
|
|
|
)
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2024-08-03 12:46:50 +00:00
|
|
|
return notifs.count() + self.modmail_notifications_count + self.chat_mentions_notifications_count + self.chats_notifications_count + self.post_notifications_count + self.modaction_notifications_count + self.offsite_notifications_count
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def normal_notifications_count(self):
|
|
|
|
return self.notifications_count \
|
|
|
|
- self.message_notifications_count \
|
2024-08-03 12:46:50 +00:00
|
|
|
- self.modmail_notifications_count \
|
2024-05-23 23:47:40 +00:00
|
|
|
- self.chat_mentions_notifications_count \
|
2024-04-18 16:24:19 +00:00
|
|
|
- self.chats_notifications_count \
|
2022-09-19 17:10:37 +00:00
|
|
|
- self.post_notifications_count \
|
|
|
|
- self.modaction_notifications_count \
|
2024-02-16 20:42:42 +00:00
|
|
|
- self.offsite_notifications_count
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def message_notifications_count(self):
|
2023-03-16 06:27:58 +00:00
|
|
|
notifs = g.db.query(Notification).join(Comment).filter(
|
2022-09-19 17:10:37 +00:00
|
|
|
Notification.user_id == self.id,
|
|
|
|
Notification.read == False,
|
|
|
|
Comment.sentto != None,
|
2024-03-08 08:10:23 +00:00
|
|
|
or_(Comment.author_id==self.id, Comment.sentto==self.id),
|
2023-06-23 13:46:42 +00:00
|
|
|
Comment.parent_post == None,
|
2022-09-19 17:10:37 +00:00
|
|
|
)
|
|
|
|
|
2024-01-12 07:20:32 +00:00
|
|
|
if not self.admin_level >= PERMS['USER_SHADOWBAN']:
|
2022-09-19 17:10:37 +00:00
|
|
|
notifs = notifs.join(Comment.author).filter(User.shadowbanned == None)
|
|
|
|
|
|
|
|
return notifs.count()
|
|
|
|
|
2024-02-01 00:30:12 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def modmail_notifications_count(self):
|
|
|
|
if self.admin_level < PERMS['NOTIFICATIONS_MODMAIL']:
|
|
|
|
return 0
|
2024-03-02 11:39:24 +00:00
|
|
|
|
|
|
|
if self.id == AEVANN_ID and SITE_NAME == 'WPD':
|
|
|
|
return 0
|
|
|
|
|
2024-02-01 20:34:03 +00:00
|
|
|
return g.db.query(Comment).distinct(Comment.top_comment_id).filter(
|
2024-02-01 00:30:12 +00:00
|
|
|
Comment.author_id != self.id,
|
|
|
|
Comment.sentto == MODMAIL_ID,
|
|
|
|
Comment.created_utc > self.last_viewed_modmail_notifs,
|
2024-02-01 20:34:03 +00:00
|
|
|
).count()
|
2024-02-01 00:30:12 +00:00
|
|
|
|
2024-08-03 12:46:50 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def chat_mentions_notifications_count(self):
|
|
|
|
return g.db.query(func.sum(ChatMembership.mentions)).filter_by(user_id=self.id).one()[0] or 0
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def chats_notifications_count(self):
|
|
|
|
return g.db.query(ChatMembership).filter_by(user_id=self.id, notification=True, muted=False, mentions=0).count()
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def post_notifications_count(self):
|
2024-02-11 14:16:09 +00:00
|
|
|
or_criteria = [
|
|
|
|
Post.hole.in_(self.followed_holes),
|
|
|
|
and_(
|
|
|
|
Post.author_id.in_(self.followed_users),
|
|
|
|
Post.notify == True,
|
|
|
|
Post.ghost == False,
|
|
|
|
)]
|
|
|
|
|
|
|
|
if self.effortpost_notifs:
|
|
|
|
or_criteria.append(Post.effortpost == True)
|
|
|
|
|
2023-06-07 23:26:32 +00:00
|
|
|
return g.db.query(Post).filter(
|
2023-09-14 22:26:47 +00:00
|
|
|
Post.created_utc > self.last_viewed_post_notifs,
|
2023-06-07 23:26:32 +00:00
|
|
|
Post.deleted_utc == 0,
|
|
|
|
Post.is_banned == False,
|
2024-02-18 15:29:53 +00:00
|
|
|
Post.draft == False,
|
2023-06-07 23:26:32 +00:00
|
|
|
Post.author_id != self.id,
|
2023-08-11 12:43:58 +00:00
|
|
|
Post.author_id.notin_(self.userblocks),
|
2023-10-07 17:55:50 +00:00
|
|
|
or_(Post.hole == None, Post.hole.notin_(self.hole_blocks)),
|
2024-02-11 14:16:09 +00:00
|
|
|
or_(*or_criteria),
|
2022-09-19 17:10:37 +00:00
|
|
|
).count()
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def modaction_notifications_count(self):
|
2024-03-02 11:39:24 +00:00
|
|
|
if self.id == AEVANN_ID and SITE_NAME == 'WPD':
|
2023-05-04 16:24:40 +00:00
|
|
|
return 0
|
2023-01-30 09:39:12 +00:00
|
|
|
|
2023-08-31 10:31:04 +00:00
|
|
|
if self.admin_level >= PERMS['NOTIFICATIONS_MODERATOR_ACTIONS']:
|
2023-03-16 06:27:58 +00:00
|
|
|
q = g.db.query(ModAction).filter(
|
2022-11-08 13:49:43 +00:00
|
|
|
ModAction.created_utc > self.last_viewed_log_notifs,
|
|
|
|
ModAction.user_id != self.id,
|
2022-12-16 19:34:01 +00:00
|
|
|
)
|
|
|
|
if self.id == AEVANN_ID:
|
2024-10-29 17:33:38 +00:00
|
|
|
q = q.filter(ModAction.kind.notin_(AEVANN_EXCLUDED_MODACTION_KINDS))
|
2023-01-26 05:31:47 +00:00
|
|
|
|
|
|
|
if self.admin_level < PERMS['PROGSTACK']:
|
2024-10-29 17:41:52 +00:00
|
|
|
q = q.filter(ModAction.kind.notin_(MODACTION_PRIVILEGED__KINDS))
|
2023-01-26 05:31:47 +00:00
|
|
|
|
2022-12-16 19:34:01 +00:00
|
|
|
return q.count()
|
2022-11-08 13:49:43 +00:00
|
|
|
|
2023-10-07 17:55:50 +00:00
|
|
|
if self.moderated_holes:
|
|
|
|
return g.db.query(HoleAction).filter(
|
|
|
|
HoleAction.created_utc > self.last_viewed_log_notifs,
|
|
|
|
HoleAction.user_id != self.id,
|
|
|
|
HoleAction.hole.in_(self.moderated_holes),
|
2022-11-08 13:49:43 +00:00
|
|
|
).count()
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2022-11-08 13:49:43 +00:00
|
|
|
return 0
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
2024-02-16 20:42:42 +00:00
|
|
|
def offsite_notifications_count(self):
|
2024-02-28 23:59:45 +00:00
|
|
|
if not self.offsite_mentions:
|
2023-05-04 16:24:40 +00:00
|
|
|
return 0
|
2023-03-16 06:27:58 +00:00
|
|
|
return g.db.query(Comment).filter(
|
2024-02-16 20:42:42 +00:00
|
|
|
Comment.created_utc > self.last_viewed_offsite_notifs,
|
2023-01-01 11:36:20 +00:00
|
|
|
Comment.is_banned == False, Comment.deleted_utc == 0,
|
2024-02-23 20:15:21 +00:00
|
|
|
Comment.body_html.like('<p>New site mention%'),
|
2023-06-23 13:46:42 +00:00
|
|
|
Comment.parent_post == None, Comment.author_id == AUTOJANNY_ID).count()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def notifications_do(self):
|
|
|
|
# only meaningful when notifications_count > 0; otherwise falsely '' ~ normal
|
|
|
|
if self.normal_notifications_count > 0:
|
|
|
|
return ''
|
|
|
|
elif self.message_notifications_count > 0:
|
|
|
|
return 'messages'
|
2024-08-03 12:46:50 +00:00
|
|
|
elif self.modmail_notifications_count > 0:
|
|
|
|
return 'modmail'
|
2024-05-23 23:47:40 +00:00
|
|
|
elif self.chat_mentions_notifications_count > 0:
|
2024-05-24 00:39:28 +00:00
|
|
|
return 'chats/'
|
2024-04-18 16:24:19 +00:00
|
|
|
elif self.chats_notifications_count > 0:
|
|
|
|
return 'chats'
|
2022-09-19 17:10:37 +00:00
|
|
|
elif self.post_notifications_count > 0:
|
|
|
|
return 'posts'
|
|
|
|
elif self.modaction_notifications_count > 0:
|
|
|
|
return 'modactions'
|
2024-02-16 20:42:42 +00:00
|
|
|
elif self.offsite_notifications_count > 0:
|
2024-02-29 20:59:15 +00:00
|
|
|
return 'offsite'
|
2022-09-19 17:10:37 +00:00
|
|
|
return ''
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def notifications_color(self):
|
|
|
|
colors = {
|
|
|
|
'': '#dc3545',
|
|
|
|
'messages': '#d8910d',
|
2024-05-24 00:39:28 +00:00
|
|
|
'chats/': '#dd1ae0',
|
2024-03-10 14:27:21 +00:00
|
|
|
'chats': '#008080',
|
2024-02-01 00:30:12 +00:00
|
|
|
'modmail': '#f15387',
|
2022-09-19 17:10:37 +00:00
|
|
|
'posts': '#0000ff',
|
|
|
|
'modactions': '#1ad80d',
|
2024-02-29 20:59:15 +00:00
|
|
|
'offsite': '#805ad5',
|
2022-09-19 17:10:37 +00:00
|
|
|
}
|
|
|
|
return colors[self.notifications_do] if self.notifications_do \
|
|
|
|
else colors['']
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
2023-10-07 17:55:50 +00:00
|
|
|
def moderated_holes(self):
|
|
|
|
return [x[0] for x in g.db.query(Mod.hole).filter_by(user_id=self.id).order_by(Mod.hole)]
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-06-24 17:16:24 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
2023-06-24 17:51:17 +00:00
|
|
|
def group_memberships(self):
|
2023-11-18 16:32:45 +00:00
|
|
|
return g.db.query(GroupMembership.group_name, Group).join(Group).filter(
|
2023-09-07 15:26:31 +00:00
|
|
|
GroupMembership.user_id == self.id,
|
2023-06-24 17:51:17 +00:00
|
|
|
GroupMembership.approved_utc != None,
|
2023-11-18 16:32:45 +00:00
|
|
|
).order_by(GroupMembership.group_name).all()
|
2023-06-24 17:16:24 +00:00
|
|
|
|
2024-06-25 18:24:17 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def group_memberships_names(self):
|
2024-06-25 18:54:47 +00:00
|
|
|
names = [x[0] for x in g.db.query(GroupMembership.group_name).filter(
|
2024-06-25 18:24:17 +00:00
|
|
|
GroupMembership.user_id == self.id,
|
|
|
|
GroupMembership.approved_utc != None,
|
2024-06-25 18:54:47 +00:00
|
|
|
).order_by(GroupMembership.group_name).all()] + ['everyone']
|
|
|
|
|
|
|
|
if self.admin_level > 0:
|
|
|
|
names.append('jannies')
|
|
|
|
|
|
|
|
return names
|
2024-06-25 18:24:17 +00:00
|
|
|
|
2024-08-06 01:21:27 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def keyword_notifs_li(self):
|
|
|
|
return [x for x in self.keyword_notifs.lower().split('\n') if x]
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@lazy
|
|
|
|
def has_follower(self, user):
|
2022-10-30 07:19:49 +00:00
|
|
|
if not user or self.id == user.id: return False # users can't follow themselves
|
2023-03-16 06:27:58 +00:00
|
|
|
return g.db.query(Follow).filter_by(target_id=self.id, user_id=user.id).one_or_none()
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2022-10-30 07:31:21 +00:00
|
|
|
@lazy
|
2024-07-24 15:21:12 +00:00
|
|
|
def is_visible_to(self, user, page):
|
2022-10-30 07:31:21 +00:00
|
|
|
if not self.is_private: return True
|
2022-10-30 08:04:46 +00:00
|
|
|
if not user: return False
|
2022-10-30 07:31:21 +00:00
|
|
|
if self.id == user.id: return True
|
2024-07-24 15:21:12 +00:00
|
|
|
if SITE_NAME == 'rDrama' and self.id in {CARP_ID, 1376} and page != 1: return False
|
2024-07-22 18:37:27 +00:00
|
|
|
return user.admin_level >= PERMS['VIEW_PRIVATE_PROFILES'] or user.eye
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def banner_url(self):
|
2023-10-05 10:09:58 +00:00
|
|
|
if FEATURES['USERS_PROFILE_BANNER'] and self.bannerurl and can_see(g.v, self):
|
2022-09-19 17:10:37 +00:00
|
|
|
return self.bannerurl
|
2024-08-03 22:01:56 +00:00
|
|
|
return f"{SITE_FULL_IMAGES}/i/{SITE_NAME}/site_preview.webp?x=11"
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def profile_url(self):
|
2023-09-28 23:58:09 +00:00
|
|
|
if IS_HOMOWEEN() and self.zombie < 0:
|
2024-02-21 20:17:54 +00:00
|
|
|
random.seed(self.id)
|
2024-04-01 04:39:50 +00:00
|
|
|
zombie_num = random.randint(1, 10)
|
|
|
|
random.seed()
|
|
|
|
return f"{SITE_FULL_IMAGES}/assets/events/homoween/images/zombies/{zombie_num}.webp?x=1"
|
2023-06-23 11:07:47 +00:00
|
|
|
if self.chud:
|
2023-09-28 23:58:09 +00:00
|
|
|
if IS_HOMOWEEN():
|
2024-02-21 20:17:54 +00:00
|
|
|
random.seed(self.id)
|
2024-04-01 04:39:50 +00:00
|
|
|
chud_num = random.randint(1, 19)
|
|
|
|
random.seed()
|
|
|
|
return f"{SITE_FULL}/assets/events/homoween/images/chud/{chud_num}.webp?x=1"
|
2023-12-16 21:42:12 +00:00
|
|
|
return f"{SITE_FULL_IMAGES}/e/chudsey.webp"
|
2022-09-19 17:10:37 +00:00
|
|
|
if self.rainbow:
|
2023-12-16 21:42:12 +00:00
|
|
|
return f"{SITE_FULL_IMAGES}/e/marseysalutepride.webp"
|
Add the "Misogynist" award to harass incels (#154)
Whazzup? This PR is the final solution to the incel problem. There's an old indian proverb that says: "never judge a man until you've walked two moons in his mocassins". In this case, it should be: "never judge a woman until you've walked 24 hrs in her high-heels".
The misogynist award is a comment-transforming award that "feminizes" comments. It does the following:
- makes text pink
- makes text lowercase
- removes "complicated" punctuation
- makes paragraphs into run-on sentences
- adds stereotypical girly remarks to the beginning or end of a paragraph.
For example:
INPUT
> What the fuck did you just fucking say about me, you little bitch? I'll have you know I graduated top of my class in the Navy Seals, and I've been involved in numerous secret raids on Al-Quaeda, and I have over 300 confirmed kills. I am trained in gorilla warfare and I'm the top sniper in the entire US armed forces. You are nothing to me but just another target. I will wipe you the fuck out with precision the likes of which has never been seen before on this Earth, mark my fucking words. You think you can get away with saying that shit to me over the Internet? Think again, fucker. As we speak I am contacting my secret network of spies across the USA and your IP is being traced right now so you better prepare for the storm, maggot. The storm that wipes out the pathetic little thing you call your life. You're fucking dead, kid. I can be anywhere, anytime, and I can kill you in over seven hundred ways, and that's just with my bare hands. Not only am I extensively trained in unarmed combat, but I have access to the entire arsenal of the United States Marine Corps and I will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit. If only you could have known what unholy retribution your little "clever" comment was about to bring down upon you, maybe you would have held your fucking tongue. But you couldn't, you didn't, and now you're paying the price, you goddamn idiot. I will shit fury all over you and you will drown in it. You're fucking dead, kiddo.
OUTPUT
> im literally screaming, what the fuck did you just fucking say about me, you little bitch? ill have you know i graduated top of my class in the navy seals, and ive been involved in numerous secret raids on al-quaeda, and i have over 300 confirmed kills, i am trained in gorilla warfare and im the top sniper in the entire us armed forces, you are nothing to me but just another target, i will wipe you the fuck out with precision the likes of which has never been seen before on this earth, mark my fucking words, you think you can get away with saying that shit to me over the internet? think again, fucker, as we speak i am contacting my secret network of spies across the usa and your ip is being traced right now so you better prepare for the storm, maggot, the storm that wipes out the pathetic little thing you call your life, youre fucking dead, kid, i can be anywhere, anytime, and i can kill you in over seven hundred ways, and thats just with my bare hands, not only am i extensively trained in unarmed combat, but i have access to the entire arsenal of the united states marine corps and i will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit, if only you could have known what unholy retribution your little clever comment was about to bring down upon you, maybe you would have held your fucking tongue, but you couldnt, you didnt, and now youre paying the price, you goddamn idiot, i will shit fury all over you and you will drown in it, youre fucking dead, kiddo
It also sets the user's pfp to a random white woman. Well, psuedorandom - it's based off of the user's id, so each user will only ever have one pfp assigned to them, which I think is nifty.
Finally, it changes the name of the user toa girly name.
There is one small problem with the PR, which is simply that I manually added a badge for testing purposes. If you like this PR, I will submit the badge throught the proper chanels and fix it.
![image](/attachments/641c7276-ffe4-4e69-b3e9-aec9f4f94191)
Co-authored-by: Chuck Sneed <sneed@formerlychucks.net>
Reviewed-on: https://fsdfsd.net/rDrama/rDrama/pulls/154
Co-authored-by: HeyMoon <heymoon@noreply.fsdfsd.net>
Co-committed-by: HeyMoon <heymoon@noreply.fsdfsd.net>
2023-06-21 12:36:07 +00:00
|
|
|
if self.queen:
|
2023-06-22 05:20:33 +00:00
|
|
|
number_of_girl_pfps = 25
|
Add the "Misogynist" award to harass incels (#154)
Whazzup? This PR is the final solution to the incel problem. There's an old indian proverb that says: "never judge a man until you've walked two moons in his mocassins". In this case, it should be: "never judge a woman until you've walked 24 hrs in her high-heels".
The misogynist award is a comment-transforming award that "feminizes" comments. It does the following:
- makes text pink
- makes text lowercase
- removes "complicated" punctuation
- makes paragraphs into run-on sentences
- adds stereotypical girly remarks to the beginning or end of a paragraph.
For example:
INPUT
> What the fuck did you just fucking say about me, you little bitch? I'll have you know I graduated top of my class in the Navy Seals, and I've been involved in numerous secret raids on Al-Quaeda, and I have over 300 confirmed kills. I am trained in gorilla warfare and I'm the top sniper in the entire US armed forces. You are nothing to me but just another target. I will wipe you the fuck out with precision the likes of which has never been seen before on this Earth, mark my fucking words. You think you can get away with saying that shit to me over the Internet? Think again, fucker. As we speak I am contacting my secret network of spies across the USA and your IP is being traced right now so you better prepare for the storm, maggot. The storm that wipes out the pathetic little thing you call your life. You're fucking dead, kid. I can be anywhere, anytime, and I can kill you in over seven hundred ways, and that's just with my bare hands. Not only am I extensively trained in unarmed combat, but I have access to the entire arsenal of the United States Marine Corps and I will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit. If only you could have known what unholy retribution your little "clever" comment was about to bring down upon you, maybe you would have held your fucking tongue. But you couldn't, you didn't, and now you're paying the price, you goddamn idiot. I will shit fury all over you and you will drown in it. You're fucking dead, kiddo.
OUTPUT
> im literally screaming, what the fuck did you just fucking say about me, you little bitch? ill have you know i graduated top of my class in the navy seals, and ive been involved in numerous secret raids on al-quaeda, and i have over 300 confirmed kills, i am trained in gorilla warfare and im the top sniper in the entire us armed forces, you are nothing to me but just another target, i will wipe you the fuck out with precision the likes of which has never been seen before on this earth, mark my fucking words, you think you can get away with saying that shit to me over the internet? think again, fucker, as we speak i am contacting my secret network of spies across the usa and your ip is being traced right now so you better prepare for the storm, maggot, the storm that wipes out the pathetic little thing you call your life, youre fucking dead, kid, i can be anywhere, anytime, and i can kill you in over seven hundred ways, and thats just with my bare hands, not only am i extensively trained in unarmed combat, but i have access to the entire arsenal of the united states marine corps and i will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit, if only you could have known what unholy retribution your little clever comment was about to bring down upon you, maybe you would have held your fucking tongue, but you couldnt, you didnt, and now youre paying the price, you goddamn idiot, i will shit fury all over you and you will drown in it, youre fucking dead, kiddo
It also sets the user's pfp to a random white woman. Well, psuedorandom - it's based off of the user's id, so each user will only ever have one pfp assigned to them, which I think is nifty.
Finally, it changes the name of the user toa girly name.
There is one small problem with the PR, which is simply that I manually added a badge for testing purposes. If you like this PR, I will submit the badge throught the proper chanels and fix it.
![image](/attachments/641c7276-ffe4-4e69-b3e9-aec9f4f94191)
Co-authored-by: Chuck Sneed <sneed@formerlychucks.net>
Reviewed-on: https://fsdfsd.net/rDrama/rDrama/pulls/154
Co-authored-by: HeyMoon <heymoon@noreply.fsdfsd.net>
Co-committed-by: HeyMoon <heymoon@noreply.fsdfsd.net>
2023-06-21 12:36:07 +00:00
|
|
|
pic_num = (self.id % number_of_girl_pfps) + 1
|
2023-12-16 21:42:12 +00:00
|
|
|
return f"{SITE_FULL_IMAGES}/i/pfps/girls/{pic_num}.webp"
|
2023-10-05 10:09:58 +00:00
|
|
|
if self.profileurl and can_see(g.v, self):
|
2022-10-27 17:53:08 +00:00
|
|
|
if self.profileurl.startswith('/'): return SITE_FULL + self.profileurl
|
2022-09-19 17:10:37 +00:00
|
|
|
return self.profileurl
|
2024-08-03 22:01:56 +00:00
|
|
|
return f"{SITE_FULL_IMAGES}/i/default-profile-pic.webp?x=11"
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-09-28 23:58:09 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def pronouns_display(self):
|
|
|
|
if IS_HOMOWEEN():
|
|
|
|
if self.zombie > 2:
|
|
|
|
return 'VAX/MAXXED'
|
|
|
|
elif self.zombie > 0:
|
|
|
|
return 'giga/boosted'
|
|
|
|
return self.pronouns
|
|
|
|
|
2023-02-28 17:54:01 +00:00
|
|
|
@lazy
|
|
|
|
def real_post_count(self, v):
|
2023-10-05 09:55:35 +00:00
|
|
|
if not self.shadowbanned: return self.post_count
|
2024-01-12 07:20:32 +00:00
|
|
|
if v and (v.id == self.id or v.admin_level >= PERMS['USER_SHADOWBAN']): return self.post_count
|
2023-02-28 17:54:01 +00:00
|
|
|
return 0
|
|
|
|
|
|
|
|
@lazy
|
|
|
|
def real_comment_count(self, v):
|
2023-10-05 09:55:35 +00:00
|
|
|
if not self.shadowbanned: return self.comment_count
|
2024-01-12 07:20:32 +00:00
|
|
|
if v and (v.id == self.id or v.admin_level >= PERMS['USER_SHADOWBAN']): return self.comment_count
|
2023-02-28 17:54:01 +00:00
|
|
|
return 0
|
|
|
|
|
2023-06-23 17:12:47 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def original_usernames_popover(self):
|
|
|
|
if self.username == self.original_username:
|
|
|
|
return ''
|
|
|
|
names = {self.original_username}
|
2023-11-25 21:57:15 +00:00
|
|
|
if self.extra_username:
|
|
|
|
names.add(self.extra_username)
|
2023-06-23 17:12:47 +00:00
|
|
|
if self.prelock_username:
|
|
|
|
names.add(self.prelock_username)
|
2024-01-07 00:37:06 +00:00
|
|
|
return 'Reserved Usernames: @' + ', @'.join(names)
|
2023-02-28 17:54:01 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@lazy
|
|
|
|
def json_popover(self, v):
|
|
|
|
data = {'username': self.username,
|
|
|
|
'url': self.url,
|
|
|
|
'id': self.id,
|
|
|
|
'profile_url': self.profile_url,
|
2022-12-24 22:21:49 +00:00
|
|
|
'hat': self.hat_active(v)[0],
|
2022-09-19 17:10:37 +00:00
|
|
|
'bannerurl': self.banner_url,
|
|
|
|
'bio_html': self.bio_html_eager,
|
2024-04-16 21:28:27 +00:00
|
|
|
'coins': commas(self.coins),
|
|
|
|
'marseybux': commas(self.marseybux),
|
2024-07-08 12:04:58 +00:00
|
|
|
'post_count': commas(self.real_post_count(v)),
|
|
|
|
'comment_count': commas(self.real_comment_count(v)),
|
2024-02-18 16:27:33 +00:00
|
|
|
'badges': [[x.path, x.text, x.until] for x in self.ordered_badges(v)],
|
2024-08-18 15:19:57 +00:00
|
|
|
'created_utc': self.created_utc,
|
2023-06-23 17:12:47 +00:00
|
|
|
'original_usernames': self.original_usernames_popover,
|
2022-09-19 17:10:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def json(self):
|
2024-04-26 20:38:29 +00:00
|
|
|
if self.is_suspended:
|
2022-09-19 17:10:37 +00:00
|
|
|
return {'username': self.username,
|
2022-12-15 18:37:29 +00:00
|
|
|
'original_username': self.original_username,
|
2022-09-19 17:10:37 +00:00
|
|
|
'url': self.url,
|
|
|
|
'is_banned': True,
|
|
|
|
'is_permanent_ban': not bool(self.unban_utc),
|
2022-11-14 00:21:12 +00:00
|
|
|
'created_utc': self.created_utc,
|
2022-09-19 17:10:37 +00:00
|
|
|
'ban_reason': self.ban_reason,
|
|
|
|
'id': self.id
|
|
|
|
}
|
|
|
|
|
|
|
|
return {'username': self.username,
|
2022-12-15 18:37:29 +00:00
|
|
|
'original_username': self.original_username,
|
2022-09-19 17:10:37 +00:00
|
|
|
'url': self.url,
|
|
|
|
'is_banned': bool(self.is_banned),
|
|
|
|
'created_utc': self.created_utc,
|
|
|
|
'id': self.id,
|
|
|
|
'is_private': self.is_private,
|
|
|
|
'profile_url': self.profile_url,
|
|
|
|
'bannerurl': self.banner_url,
|
|
|
|
'bio': self.bio,
|
|
|
|
'bio_html': self.bio_html_eager,
|
2023-10-05 10:39:12 +00:00
|
|
|
'flair': self.flair,
|
|
|
|
'flair_html': self.flair_html,
|
2022-09-19 17:10:37 +00:00
|
|
|
'coins': self.coins,
|
2023-02-28 17:54:01 +00:00
|
|
|
'post_count': self.real_post_count(g.v),
|
2023-03-23 18:28:54 +00:00
|
|
|
'comment_count': self.real_comment_count(g.v),
|
2023-06-23 11:07:47 +00:00
|
|
|
'chud_phrase': self.chud_phrase,
|
2022-09-19 17:10:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-10-22 12:21:57 +00:00
|
|
|
def ban(self, admin=None, reason=None, days=0.0, modlog=True, original_user=None):
|
2024-10-21 20:28:11 +00:00
|
|
|
if self.is_permabanned:
|
|
|
|
return
|
|
|
|
|
2024-10-19 03:42:32 +00:00
|
|
|
if len(reason) > BAN_REASON_HTML_LENGTH_LIMIT:
|
2024-10-19 03:32:44 +00:00
|
|
|
stop(400, "Rendered ban reason is too long!")
|
|
|
|
|
2024-10-22 12:21:57 +00:00
|
|
|
if not original_user:
|
|
|
|
original_user = self
|
2024-10-22 12:10:08 +00:00
|
|
|
|
2023-07-01 15:25:23 +00:00
|
|
|
g.db.add(self)
|
2022-09-19 17:10:37 +00:00
|
|
|
if days:
|
2023-02-19 13:23:08 +00:00
|
|
|
if self.unban_utc:
|
|
|
|
self.unban_utc += days * 86400
|
|
|
|
else:
|
|
|
|
self.unban_utc = int(time.time()) + (days * 86400)
|
2023-07-01 15:25:23 +00:00
|
|
|
else:
|
2024-02-02 22:39:02 +00:00
|
|
|
self.unban_utc = None
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
self.is_banned = admin.id if admin else AUTOJANNY_ID
|
2024-10-21 17:29:03 +00:00
|
|
|
|
2024-10-22 12:21:57 +00:00
|
|
|
reason += f' (<a href="/id/{original_user.id}">@{original_user.username}</a> - {datetime.date.today()})'
|
2024-10-21 17:29:03 +00:00
|
|
|
self.ban_reason = reason
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-10-21 15:07:12 +00:00
|
|
|
if days:
|
|
|
|
days_txt = str(days)
|
|
|
|
if days_txt.endswith('.0'): days_txt = days_txt[:-2]
|
|
|
|
duration = f"for {days_txt} day"
|
|
|
|
if days != 1: duration += "s"
|
|
|
|
else:
|
|
|
|
duration = "permanently"
|
|
|
|
|
2024-10-21 20:26:12 +00:00
|
|
|
if modlog:
|
|
|
|
ma = ModAction(
|
|
|
|
kind="ban_user",
|
|
|
|
user_id=self.is_banned,
|
|
|
|
target_user_id=self.id,
|
|
|
|
_note=f'duration: {duration}, reason: "{reason}"'
|
|
|
|
)
|
|
|
|
g.db.add(ma)
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-04-26 20:38:29 +00:00
|
|
|
|
2024-10-21 17:33:22 +00:00
|
|
|
def shadowban(self, admin=None, reason=None):
|
|
|
|
if len(reason) > BAN_REASON_HTML_LENGTH_LIMIT:
|
|
|
|
stop(400, "Rendered shadowban reason is too long!")
|
|
|
|
|
|
|
|
g.db.add(self)
|
|
|
|
|
|
|
|
self.shadowbanned = admin.id if admin else AUTOJANNY_ID
|
|
|
|
|
2024-10-22 12:21:57 +00:00
|
|
|
reason += f' (<a href="/id/{self.id}">@{self.username}</a> - {datetime.date.today()})'
|
2024-10-21 17:33:22 +00:00
|
|
|
self.shadowban_reason = reason
|
|
|
|
|
|
|
|
ma = ModAction(
|
|
|
|
kind="shadowban",
|
|
|
|
user_id=self.shadowbanned,
|
|
|
|
target_user_id=self.id,
|
|
|
|
_note=f'reason: "{reason}"'
|
|
|
|
)
|
|
|
|
g.db.add(ma)
|
|
|
|
|
2024-04-26 20:38:29 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def is_suspended(self):
|
|
|
|
return (self.is_banned and (not self.unban_utc or self.unban_utc > time.time()))
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
2023-06-29 19:51:32 +00:00
|
|
|
def is_permabanned(self):
|
2024-02-02 22:39:02 +00:00
|
|
|
return (self.is_banned and not self.unban_utc)
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2024-05-16 21:04:18 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def is_underage(self):
|
2024-10-14 11:16:39 +00:00
|
|
|
return (self.is_suspended and is_underage_reason(self.ban_reason)) \
|
|
|
|
or (self.shadowbanned and is_underage_reason(self.shadowban_reason))
|
2024-05-16 21:04:18 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def applications(self):
|
2023-03-16 06:27:58 +00:00
|
|
|
return g.db.query(OauthApp).filter_by(author_id=self.id).order_by(OauthApp.id).all()
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def userblocks(self):
|
2023-08-11 13:15:34 +00:00
|
|
|
return [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=self.id)]
|
2022-09-19 17:10:37 +00:00
|
|
|
|
2023-09-06 18:02:47 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def muters(self):
|
2024-08-14 16:10:33 +00:00
|
|
|
return {x[0] for x in g.db.query(UserMute.user_id).filter_by(target_id=self.id)}
|
2023-09-06 18:02:47 +00:00
|
|
|
|
|
|
|
|
2022-11-25 21:43:35 +00:00
|
|
|
def get_relationship_count(self, relationship_cls):
|
2022-11-26 04:52:47 +00:00
|
|
|
if relationship_cls in {SaveRelationship, Subscription}:
|
2023-06-07 23:26:32 +00:00
|
|
|
query = relationship_cls.post_id
|
2022-11-25 21:43:35 +00:00
|
|
|
join = relationship_cls.post
|
2023-06-07 23:26:32 +00:00
|
|
|
cls = Post
|
2022-11-25 21:43:35 +00:00
|
|
|
elif relationship_cls is CommentSaveRelationship:
|
|
|
|
query = relationship_cls.comment_id
|
|
|
|
join = relationship_cls.comment
|
|
|
|
cls = Comment
|
|
|
|
else:
|
|
|
|
raise TypeError("Relationships supported is SaveRelationship, Subscription, CommentSaveRelationship")
|
|
|
|
|
2023-03-16 06:27:58 +00:00
|
|
|
query = g.db.query(query).join(join).filter(relationship_cls.user_id == self.id)
|
2023-08-31 10:46:07 +00:00
|
|
|
if self.admin_level < PERMS['POST_COMMENT_MODERATION']:
|
2022-11-25 21:43:35 +00:00
|
|
|
query = query.filter(cls.is_banned == False, cls.deleted_utc == 0)
|
|
|
|
return query.count()
|
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def saved_idlist(self):
|
2023-06-07 23:26:32 +00:00
|
|
|
posts = g.db.query(SaveRelationship.post_id).filter_by(user_id=self.id).all()
|
2022-09-19 17:10:37 +00:00
|
|
|
return [x[0] for x in posts]
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def saved_comment_idlist(self):
|
2023-03-16 06:27:58 +00:00
|
|
|
comments = g.db.query(CommentSaveRelationship.comment_id).filter_by(user_id=self.id).all()
|
2022-09-19 17:10:37 +00:00
|
|
|
return [x[0] for x in comments]
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def subscribed_idlist(self):
|
2023-06-07 23:26:32 +00:00
|
|
|
posts = g.db.query(Subscription.post_id).filter_by(user_id=self.id).all()
|
2022-09-19 17:10:37 +00:00
|
|
|
return [x[0] for x in posts]
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def saved_count(self):
|
2022-11-25 21:43:35 +00:00
|
|
|
return self.get_relationship_count(SaveRelationship)
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def saved_comment_count(self):
|
2022-11-25 21:43:35 +00:00
|
|
|
return self.get_relationship_count(CommentSaveRelationship)
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def subscribed_count(self):
|
2022-11-25 21:43:35 +00:00
|
|
|
return self.get_relationship_count(Subscription)
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def filter_words(self):
|
2024-02-24 22:27:44 +00:00
|
|
|
l = [i.strip() for i in self.custom_filter_list.lower().split('\n')] if self.custom_filter_list else []
|
2022-09-19 17:10:37 +00:00
|
|
|
l = [i for i in l if i]
|
|
|
|
return l
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def lottery_stats(self):
|
|
|
|
return { "winnings": self.total_lottery_winnings, "ticketsHeld": { "current": self.currently_held_lottery_tickets , "total": self.total_held_lottery_tickets } }
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def can_create_hole(self):
|
|
|
|
return self.admin_level >= PERMS['HOLE_CREATE']
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def patron_tooltip(self):
|
2023-05-14 22:28:40 +00:00
|
|
|
tier_name = TIER_TO_NAME[self.patron]
|
|
|
|
tier_money = TIER_TO_MONEY[self.patron]
|
2023-05-14 22:35:24 +00:00
|
|
|
return f'{tier_name} - Donates ${tier_money}/month'
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
2023-03-19 08:08:44 +00:00
|
|
|
def can_see_restricted_holes(self):
|
2023-01-25 15:41:46 +00:00
|
|
|
if self.blacklisted_by: return False
|
2023-01-24 05:20:15 +00:00
|
|
|
if self.shadowbanned: return False
|
2023-06-29 19:51:32 +00:00
|
|
|
if self.is_permabanned: return False
|
2023-03-19 08:08:44 +00:00
|
|
|
|
|
|
|
if self.admin_level >= PERMS['VIEW_RESTRICTED_HOLES']: return True
|
|
|
|
|
2023-08-10 15:29:24 +00:00
|
|
|
return None
|
2023-03-19 08:08:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def can_see_chudrama(self):
|
|
|
|
if self.can_see_restricted_holes != None:
|
|
|
|
return self.can_see_restricted_holes
|
|
|
|
|
2023-10-05 13:44:31 +00:00
|
|
|
if self.truescore >= TRUESCORE_MINIMUM: return True
|
2023-06-23 11:07:47 +00:00
|
|
|
if self.chud: return True
|
2024-08-28 12:16:45 +00:00
|
|
|
if self.unban_utc: return True
|
2022-09-19 17:10:37 +00:00
|
|
|
if self.patron: return True
|
2023-08-10 12:25:40 +00:00
|
|
|
|
2022-09-19 17:10:37 +00:00
|
|
|
return False
|
2022-12-04 18:39:06 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def can_see_countryclub(self):
|
2023-03-19 08:08:44 +00:00
|
|
|
if self.can_see_restricted_holes != None:
|
|
|
|
return self.can_see_restricted_holes
|
|
|
|
|
2024-10-27 22:58:17 +00:00
|
|
|
one_month_ago = time.time() - 2592000
|
|
|
|
if self.truescore >= TRUESCORE_MINIMUM and self.created_utc < one_month_ago:
|
|
|
|
return True
|
2023-07-20 13:47:36 +00:00
|
|
|
|
2022-12-04 18:39:06 +00:00
|
|
|
return False
|
|
|
|
|
2023-08-01 06:46:00 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def can_see_highrollerclub(self):
|
|
|
|
if self.can_see_restricted_holes != None:
|
|
|
|
return self.can_see_restricted_holes
|
|
|
|
|
|
|
|
if self.patron: return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2024-02-25 06:25:15 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def can_see_donate_service(self):
|
|
|
|
if DONATE_LINK == DEFAULT_CONFIG_VALUE:
|
|
|
|
return False
|
|
|
|
|
|
|
|
if self.can_see_restricted_holes != None:
|
|
|
|
return self.can_see_restricted_holes
|
|
|
|
|
|
|
|
if self.chud == 1: return False
|
|
|
|
|
|
|
|
if self.patron: return True
|
|
|
|
|
2024-10-28 19:11:23 +00:00
|
|
|
one_month_ago = time.time() - 2592000
|
2024-10-28 19:07:20 +00:00
|
|
|
if self.truescore >= TRUESCORE_MINIMUM and self.created_utc < one_month_ago:
|
|
|
|
return True
|
2024-02-25 06:29:04 +00:00
|
|
|
|
2024-02-25 06:25:15 +00:00
|
|
|
return False
|
|
|
|
|
2022-11-14 17:17:29 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def can_post_in_ghost_threads(self):
|
2022-12-08 05:14:50 +00:00
|
|
|
if SITE_NAME == 'WPD': return False
|
2023-10-05 13:44:31 +00:00
|
|
|
if not TRUESCORE_MINIMUM: return True
|
|
|
|
if self.truescore >= TRUESCORE_MINIMUM: return True
|
2022-11-14 17:17:29 +00:00
|
|
|
if self.patron: return True
|
|
|
|
return False
|
2022-09-19 17:10:37 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def winnings(self):
|
2023-06-07 20:05:57 +00:00
|
|
|
return g.db.query(func.sum(CasinoGame.winnings)).filter(CasinoGame.user_id == self.id).one()[0] or 0
|
2022-09-19 17:51:40 +00:00
|
|
|
|
2022-10-06 23:31:09 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def user_name(self):
|
|
|
|
if self.earlylife:
|
2024-08-10 16:47:35 +00:00
|
|
|
expiry_days = ceil((self.earlylife - time.time()) / 21600)
|
2024-08-10 16:44:18 +00:00
|
|
|
earlylife_mult = min(1, expiry_days) + min(1, expiry_days) + expiry_days
|
2024-08-07 23:22:55 +00:00
|
|
|
return ('(' * earlylife_mult) + self.username + (')' * earlylife_mult)
|
2022-10-06 23:31:09 +00:00
|
|
|
return self.username
|
2022-10-12 06:24:30 +00:00
|
|
|
|
2024-04-12 12:05:01 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def switched(self):
|
|
|
|
if not IS_FOOL() or (has_request_context() and request.path in {'/notifications/modmail', '/notifications/messages'}):
|
|
|
|
return self
|
|
|
|
|
|
|
|
three_days = time.time() - 259200
|
|
|
|
return g.db.query(User).filter(User.truescore < self.truescore, User.last_active > three_days).order_by(User.truescore.desc()).first() or self
|
|
|
|
|
2022-10-14 16:59:49 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def unmutable(self):
|
|
|
|
return self.has_badge(67)
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def mute(self):
|
|
|
|
return self.has_badge(68)
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def eye(self):
|
|
|
|
return self.has_badge(83)
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def alt(self):
|
|
|
|
return self.has_badge(84)
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def unblockable(self):
|
|
|
|
return self.has_badge(87)
|
|
|
|
|
2023-10-05 19:40:44 +00:00
|
|
|
@lazy
|
|
|
|
def pride_username(self, v):
|
2024-03-10 14:27:21 +00:00
|
|
|
return bool(not (v and v.poor) and self.has_badge(303))
|
2023-10-05 19:40:44 +00:00
|
|
|
|
2022-12-13 18:50:38 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
2024-02-02 23:15:04 +00:00
|
|
|
def shadowbanned_by(self):
|
|
|
|
return '@' + g.db.query(User.username).filter_by(id=self.shadowbanned).one()[0]
|
2022-12-20 01:13:34 +00:00
|
|
|
|
2023-07-02 17:40:39 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def banned_by(self):
|
|
|
|
username = g.db.query(User.username).filter_by(id=self.is_banned).one()[0]
|
|
|
|
return f'<a href="/@{username}">@{username}</a>'
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def chudder(self):
|
|
|
|
if not self.chudded_by: return 'award'
|
|
|
|
username = g.db.query(User.username).filter_by(id=self.chudded_by).one()[0]
|
|
|
|
return f'<a href="/@{username}">@{username}</a>'
|
|
|
|
|
2023-01-22 08:20:38 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def alts(self):
|
2023-03-16 06:27:58 +00:00
|
|
|
subq = g.db.query(Alt).filter(
|
2023-01-22 08:20:38 +00:00
|
|
|
or_(
|
|
|
|
Alt.user1 == self.id,
|
|
|
|
Alt.user2 == self.id
|
|
|
|
)
|
|
|
|
).subquery()
|
|
|
|
|
2023-03-16 06:27:58 +00:00
|
|
|
data = g.db.query(
|
2023-01-22 08:20:38 +00:00
|
|
|
User,
|
|
|
|
aliased(Alt, alias=subq)
|
|
|
|
).join(
|
|
|
|
subq,
|
|
|
|
or_(
|
|
|
|
subq.c.user1 == User.id,
|
|
|
|
subq.c.user2 == User.id
|
|
|
|
)
|
|
|
|
).filter(
|
|
|
|
User.id != self.id
|
|
|
|
).order_by(User.username).all()
|
|
|
|
|
|
|
|
output = []
|
|
|
|
for x in data:
|
|
|
|
user = x[0]
|
|
|
|
user._is_manual = x[1].is_manual
|
|
|
|
output.append(user)
|
|
|
|
|
|
|
|
return output
|
|
|
|
|
2023-05-12 21:04:26 +00:00
|
|
|
@lazy
|
2024-02-18 16:27:33 +00:00
|
|
|
def ordered_badges(self, v):
|
|
|
|
badges = self.badges
|
|
|
|
|
2024-02-18 16:29:24 +00:00
|
|
|
if not self.lifetimedonated_visible and not (v and (v.id == self.id or v.admin_level >= PERMS['VIEW_PATRONS'])):
|
2024-04-16 15:12:03 +00:00
|
|
|
badges = [x for x in badges if x.badge_id not in PATRON_BADGES]
|
2024-02-18 16:27:33 +00:00
|
|
|
|
|
|
|
return sorted(badges, key=badge_ordering_func)
|
2023-05-12 21:04:26 +00:00
|
|
|
|
2023-07-22 17:30:55 +00:00
|
|
|
@lazy
|
|
|
|
def rendered_sig(self, v):
|
2024-04-11 10:22:36 +00:00
|
|
|
if not self.sig_html or self.patron < 3:
|
2023-07-22 17:30:55 +00:00
|
|
|
return ''
|
|
|
|
|
2023-10-12 19:24:17 +00:00
|
|
|
if v and not v.show_sigs:
|
2023-07-22 17:30:55 +00:00
|
|
|
return ''
|
|
|
|
|
2023-07-22 19:34:07 +00:00
|
|
|
return f'<div id="signature-{self.id}" class="user-signature"><hr>{self.sig_html}</div>'
|
2023-07-22 17:30:55 +00:00
|
|
|
|
2024-02-07 01:31:35 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def effortposts_made(self):
|
|
|
|
return g.db.query(Post).filter_by(author_id=self.id, effortpost=True).count()
|
|
|
|
|
2024-08-02 15:13:03 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def checkmark_classes(self):
|
|
|
|
classes = []
|
|
|
|
|
|
|
|
if self.sharpen:
|
|
|
|
classes.append('sharpen')
|
|
|
|
if self.rainbow:
|
|
|
|
classes.append('rainbow-text')
|
|
|
|
if self.bite:
|
|
|
|
classes.append('author-bitten')
|
|
|
|
if self.queen:
|
|
|
|
classes.append('queen')
|
|
|
|
|
|
|
|
if self.verified == 'Glowiefied':
|
|
|
|
classes.append('glow')
|
|
|
|
elif self.verified == 'Valid':
|
|
|
|
classes.append('valid')
|
|
|
|
elif self.verified == 'Coronated':
|
|
|
|
classes.append('g')
|
|
|
|
|
2024-08-02 16:16:54 +00:00
|
|
|
if not classes and self.pride_username(g.v):
|
2024-08-02 15:13:03 +00:00
|
|
|
classes.append('pride')
|
|
|
|
|
|
|
|
return ' '.join(classes)
|
|
|
|
|
2024-08-02 20:34:42 +00:00
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def sidebar_num(self):
|
|
|
|
return g.db.query(ArtSubmission).filter_by(kind='sidebar', author_id=self.id, approved=True).count()
|
|
|
|
|
|
|
|
@property
|
|
|
|
@lazy
|
|
|
|
def banner_num(self):
|
|
|
|
return g.db.query(ArtSubmission).filter_by(kind='banner', author_id=self.id, approved=True).count()
|
|
|
|
|
2024-08-02 15:13:03 +00:00
|
|
|
|
2023-07-22 17:30:55 +00:00
|
|
|
|
2024-04-16 15:12:03 +00:00
|
|
|
badge_ordering_tuple = PATRON_BADGES + (
|
2024-05-14 19:52:58 +00:00
|
|
|
134, 237, 341, #1 year, 2 year, 3 year
|
2023-09-28 23:58:09 +00:00
|
|
|
10, 11, 12, #referred users
|
|
|
|
69, 70, 71, 72, 73, #coins spent
|
|
|
|
76, 77, 78, #lootboxes bought
|
|
|
|
17, 16, 143, #marsey making
|
|
|
|
110, 111, #zwolf making
|
|
|
|
112, 113, #platy making
|
|
|
|
114, 115, #capy making
|
|
|
|
287, 288, #carp making
|
|
|
|
152, 153, 154, #hats bought
|
|
|
|
160, 161, 162, #casino win
|
|
|
|
157, 158, 159, #casino loss
|
|
|
|
163, 164, 165, 166, #hat making
|
|
|
|
243, 244, 245, 247, #kong
|
|
|
|
118, 119, 120, 121, 122, 123, #denazifying r/stupidpol
|
|
|
|
190, 192, #word filter
|
|
|
|
251, 250, 249, #marsey madness
|
|
|
|
)
|
2023-05-12 22:12:08 +00:00
|
|
|
|
2023-05-12 21:04:26 +00:00
|
|
|
def badge_ordering_func(b):
|
|
|
|
if b.badge_id in badge_ordering_tuple:
|
|
|
|
return badge_ordering_tuple.index(b.badge_id)
|
|
|
|
return b.created_utc or len(badge_ordering_tuple)+1
|