Merge branch 'master' into regex-censor

# Conflicts:
#	.gitignore
#	docker-compose.yml
#	files/classes/comment.py
#	files/classes/submission.py
#	files/helpers/const.py
#	requirements.txt
remotes/1693045480750635534/spooky-22
Yo Mama 2021-10-16 21:29:36 +02:00
commit a831a24aa4
171 changed files with 27714 additions and 27682 deletions

0
.gitattributes vendored 100644 → 100755
View File

0
Dockerfile 100644 → 100755
View File

0
LICENSE 100644 → 100755
View File

0
appspec.yml 100644 → 100755
View File

0
buildspec.yml 100644 → 100755
View File

View File

@ -1,7 +0,0 @@
for theme in ['transparent', 'win98', 'midnight', 'dark', 'light', 'coffee', 'tron', '4chan']:
with open(f"./files/assets/css/{theme}_ff66ac.css", encoding='utf-8') as t:
text = t.read()
for color in ['ff66ac','805ad5','62ca56','38a169','80ffff','2a96f3','62ca56','eb4963','ff0000','f39731','30409f','3e98a7','e4432d','7b9ae4','ec72de','7f8fa6', 'f8db58']:
newtext = text.replace("ff66ac", color).replace("ff4097", color).replace("ff1a83", color).replace("ff3390", color).replace("rgba(255, 102, 172, 0.25)", color)
with open(f"./files/assets/css/{theme}_{color}.css", encoding='utf-8', mode='w') as nt:
nt.write(newtext)

0
dependabot.yml 100644 → 100755
View File

0
disablesignups 100644 → 100755
View File

View File

@ -7,9 +7,8 @@ services:
volumes:
- "./:/service"
environment:
- DATABASE_URL=postgresql://postgres@postgres:5432/postgres
- DATABASE_URL=postgresql://postgres@127.0.0.1:5432/postgres
- MASTER_KEY=${MASTER_KEY:-KTVciAUQFpFh2WdJ/oiHJlxl6FvzRZp8kYzAAv3l2OA=}
- REDIS_URL=redis://redis
- DOMAIN=localhost
- SITE_NAME=Drama
- GIPHY_KEY=3435tdfsdudebussylmaoxxt43
@ -32,7 +31,7 @@ services:
- BOT_DISABLE=0
- COINS_NAME=Dramacoins
- DEFAULT_TIME_FILTER=all
- DEFAULT_THEME=dark
- DEFAULT_THEME=midnight
- DEFAULT_COLOR=ff66ac #YOU HAVE TO PICK ONE OF THOSE COLORS OR SHIT WILL BREAK: ff66ac, 805ad5, 62ca56, 38a169, 80ffff, 2a96f3, eb4963, ff0000, f39731, 30409f, 3e98a7, e4432d, 7b9ae4, ec72de, 7f8fa6, f8db58
- SLOGAN=Dude bussy lmao
- GUMROAD_TOKEN=3435tdfsdudebussylmaoxxt43

4
env 100644 → 100755
View File

@ -1,4 +1,4 @@
export DATABASE_URL="postgresql://postgres@postgres:5432/postgres"
export DATABASE_URL="postgresql://postgres@127.0.0.1:5432/postgres"
export MASTER_KEY="-KTVciAUQFpFh2WdJ/oiHJlxl6FvzRZp8kYzAAv3l2OA="
export DOMAIN="localhost"
export SITE_NAME="Drama"
@ -27,7 +27,7 @@ export GUMROAD_LINK="https://marsey1.gumroad.com/l/tfcvri"
export CARD_VIEW="1"
export DISABLE_DOWNVOTES="0"
export DUES="0"
export DEFAULT_THEME="dark"
export DEFAULT_THEME="midnight"
export DEFAULT_COLOR="ff66ac" # YOU HAVE TO PICK ONE OF THOSE COLORS OR SHIT WILL BREAK: ff66ac, 805ad5, 62ca56, 38a169, 80ffff, 2a96f3, eb4963, ff0000, f39731, 30409f, 3e98a7, e4432d, 7b9ae4, ec72de, 7f8fa6, f8db58
export MAIL_USERNAME="blahblahblah@gmail.com"
export MAIL_PASSWORD="3435tdfsdudebussylmaoxxt43"

2
files/__main__.py 100644 → 100755
View File

@ -40,7 +40,7 @@ app.config["PERMANENT_SESSION_LIFETIME"] = 60 * 60 * 24 * 365
app.config["SESSION_REFRESH_EACH_REQUEST"] = True
app.config["SLOGAN"] = environ.get("SLOGAN", "").strip()
app.config["DEFAULT_COLOR"] = environ.get("DEFAULT_COLOR", "ff0000").strip()
app.config["DEFAULT_THEME"] = environ.get("DEFAULT_THEME", "light").strip() + "_" + environ.get("DEFAULT_COLOR", "ff0000").strip()
app.config["DEFAULT_THEME"] = environ.get("DEFAULT_THEME", "midnight").strip()
app.config["FORCE_HTTPS"] = int(environ.get("FORCE_HTTPS", 1)) if ("localhost" not in app.config["SERVER_NAME"] and "127.0.0.1" not in app.config["SERVER_NAME"]) else 0
app.config["UserAgent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
app.config["HCAPTCHA_SITEKEY"] = environ.get("HCAPTCHA_SITEKEY","").strip()

0
files/classes/__init__.py 100644 → 100755
View File

0
files/classes/alts.py 100644 → 100755
View File

8
files/classes/award.py 100644 → 100755
View File

@ -22,7 +22,7 @@ if site_name == "Drama":
"description": "Makes flies swarm a post.",
"icon": "fas fa-poop",
"color": "text-black-50",
"price": 1000
"price": 500
},
"fireflies": {
"kind": "fireflies",
@ -30,7 +30,7 @@ if site_name == "Drama":
"description": "Puts stars on the post.",
"icon": "fas fa-sparkles",
"color": "text-warning",
"price": 1000
"price": 500
}
}
else:
@ -41,7 +41,7 @@ else:
"description": "Makes flies swarm a post.",
"icon": "fas fa-poop",
"color": "text-black-50",
"price": 1000
"price": 500
},
"fireflies": {
"kind": "fireflies",
@ -49,7 +49,7 @@ else:
"description": "Puts stars on the post.",
"icon": "fas fa-sparkles",
"color": "text-warning",
"price": 1000
"price": 500
}
}

3
files/classes/badges.py 100644 → 100755
View File

@ -25,7 +25,7 @@ class BadgeDef(Base):
@lazy
def path(self):
return f"/assets/images/badges/{self.icon}"
return f"/assets/images/badges/{self.icon}.gif"
@property
@lazy
@ -83,7 +83,6 @@ class Badge(Base):
return {'text': self.text,
'name': self.name,
'created_utc': self.created_utc,
'url': self.url,
'icon_url':f"https://{app.config['SERVER_NAME']}{self.path}"
}

0
files/classes/clients.py 100644 → 100755
View File

View File

@ -348,16 +348,13 @@ class Comment(Base):
@lazy
def collapse_for_user(self, v):
if self.over_18 and not (v and v.over_18) and not self.post.over_18:
return True
if self.over_18 and not (v and v.over_18) and not self.post.over_18: return True
if not v:
return False
if not v: return False
if any([x in self.body for x in v.filter_words]):
return True
if v.filter_words and any([x in self.body for x in v.filter_words]): return True
if self.is_banned: return True
if self.is_banned or (self.author and self.author.shadowbanned): return True
return False

0
files/classes/domains.py 100644 → 100755
View File

0
files/classes/flags.py 100644 → 100755
View File

0
files/classes/mod_logs.py 100644 → 100755
View File

View File

@ -233,11 +233,11 @@ class Submission(Base):
@property
@lazy
def thumb_url(self):
if self.over_18: return f"https://{site}/assets/images/nsfw.webp"
elif not self.url: return f"https://{site}/assets/images/{site_name}/default_thumb_text.webp"
if self.over_18: return f"https://{site}/assets/images/nsfw.gif"
elif not self.url: return f"https://{site}/assets/images/{site_name}/default_thumb_text.gif"
elif self.thumburl: return self.thumburl
elif "youtu.be" in self.domain or "youtube.com" in self.domain: return f"https://{site}/assets/images/default_thumb_yt.webp"
else: return f"https://{site}/assets/images/default_thumb_link.webp"
elif "youtu.be" in self.domain or "youtube.com" in self.domain: return f"https://{site}/assets/images/default_thumb_yt.gif"
else: return f"https://{site}/assets/images/default_thumb_link.gif"
@property
@lazy
@ -266,6 +266,7 @@ class Submission(Base):
'upvotes': self.upvotes,
'downvotes': self.downvotes,
'stickied': self.stickied,
'private' : self.private,
'distinguish_level': self.distinguish_level,
'voted': self.voted if hasattr(self, 'voted') else 0,
'flags': flags,
@ -398,7 +399,8 @@ class SaveRelationship(Base):
__tablename__="save_relationship"
id=Column(Integer, primary_key=true)
user_id=Column(Integer, ForeignKey("users.id"))
submission_id=Column(Integer, ForeignKey("submissions.id"))
id=Column(Integer, primary_key=True)
user_id=Column(Integer)
submission_id=Column(Integer)
comment_id=Column(Integer)
type=Column(Integer)

0
files/classes/subscriptions.py 100644 → 100755
View File

37
files/classes/user.py 100644 → 100755
View File

@ -18,7 +18,7 @@ import random
site = environ.get("DOMAIN").strip()
site_name = environ.get("SITE_NAME").strip()
defaulttheme = environ.get("DEFAULT_THEME", "light").strip()
defaulttheme = environ.get("DEFAULT_THEME", "midnight").strip()
defaultcolor = environ.get("DEFAULT_COLOR", "fff").strip()
defaulttimefilter = environ.get("DEFAULT_TIME_FILTER", "all").strip()
cardview = bool(int(environ.get("CARD_VIEW", 1)))
@ -39,7 +39,7 @@ if site_name == "Drama":
"description": "Makes flies swarm a post.",
"icon": "fas fa-poop",
"color": "text-black-50",
"price": 1000
"price": 500
},
"fireflies": {
"kind": "fireflies",
@ -47,7 +47,7 @@ if site_name == "Drama":
"description": "Puts stars on the post.",
"icon": "fas fa-sparkles",
"color": "text-warning",
"price": 1000
"price": 500
}
}
else:
@ -58,7 +58,7 @@ else:
"description": "Makes flies swarm a post.",
"icon": "fas fa-poop",
"color": "text-black-50",
"price": 1000
"price": 500
},
"fireflies": {
"kind": "fireflies",
@ -66,7 +66,7 @@ else:
"description": "Puts stars on the post.",
"icon": "fas fa-sparkles",
"color": "text-warning",
"price": 1000
"price": 500
}
}
@ -266,7 +266,7 @@ class User(Base):
elif sort == "old":
posts = posts.order_by(Submission.created_utc.asc())
elif sort == "controversial":
posts = posts.order_by(-1 * Submission.upvotes * (Submission.downvotes+1))
posts = posts.order_by(-1 * Submission.upvotes * Submission.downvotes * Submission.downvotes)
elif sort == "top":
posts = posts.order_by(Submission.downvotes - Submission.upvotes)
elif sort == "bottom":
@ -423,14 +423,14 @@ class User(Base):
@lazy
def banner_url(self):
if self.bannerurl: return self.bannerurl
else: return f"https://{site}/assets/images/{site_name}/preview.webp"
else: return f"https://{site}/assets/images/{site_name}/preview.gif"
@property
@lazy
def profile_url(self):
if self.profileurl: return self.profileurl
elif "rdrama" in site: return f"https://{site}/assets/images/defaultpictures/{random.randint(1, 150)}.webp"
else: return f"https://{site}/assets/images/default-profile-pic.webp"
elif "rama" in site: return f"https://{site}/assets/images/defaultpictures/{random.randint(1, 150)}.gif"
else: return f"https://{site}/assets/images/default-profile-pic.gif"
@property
@lazy
@ -493,10 +493,14 @@ class User(Base):
g.db.add(self)
@property
@lazy
def is_suspended(self):
if self.unban_utc and self.unban_utc < time.time():
self.is_banned = 0
self.unban_utc = 0
g.db.add(self)
g.db.commit()
return (self.is_banned and (not self.unban_utc or self.unban_utc > time.time()))
@ -536,12 +540,11 @@ class User(Base):
return [x[0] for x in posts.offset(25 * (page - 1)).limit(26).all()]
@lazy
def saved_comment_idlist(self, page=1):
def saved_comment_idlist(self):
comments = g.db.query(Comment.id).options(lazyload('*')).filter_by(is_banned=False, deleted_utc=0)
saved = [x[0] for x in g.db.query(SaveRelationship.submission_id).options(lazyload('*')).filter(SaveRelationship.user_id == self.id).all()]
comments = comments.filter(Comment.id.in_(saved))
try: saved = [x[0] for x in g.db.query(SaveRelationship.comment_id).options(lazyload('*')).filter(SaveRelationship.user_id == self.id).all()]
except: return []
comments = g.db.query(Comment.id).options(lazyload('*')).filter(Comment.id.in_(saved))
if self.admin_level == 0:
blocking = [x[0] for x in g.db.query(
@ -556,9 +559,7 @@ class User(Base):
Comment.author_id.notin_(blocked)
)
comments = comments.order_by(Comment.created_utc.desc())
return [x[0] for x in comments.offset(25 * (page - 1)).limit(26).all()]
return [x[0] for x in comments.order_by(Comment.created_utc.desc()).all()]
@property
@lazy

10
files/classes/userblock.py 100644 → 100755
View File

@ -1,8 +1,6 @@
from sqlalchemy import *
from sqlalchemy.orm import relationship
from files.__main__ import Base
from files.helpers.lazy import lazy
import time
class UserBlock(Base):
@ -15,10 +13,4 @@ class UserBlock(Base):
target = relationship("User", primaryjoin="User.id==UserBlock.target_id", viewonly=True)
def __repr__(self):
return f"<UserBlock(user={user.username}, target={target.username})>"
@property
@lazy
def created_date(self):
return time.strftime("%d %b %Y", time.gmtime(self.created_utc))
return f"<UserBlock(user={self.user_id}, target={self.target_id})>"

0
files/classes/votes.py 100644 → 100755
View File

0
files/helpers/alerts.py 100644 → 100755
View File

View File

@ -15,6 +15,7 @@ SLURS = {
"tranny": "🚂🚃🚃",
"troon": "🚂🚃🚃",
"NoNewNormal": "HorseDewormerAddicts",
"nonewnormal": "HorseDewormerAddicts",
"kike": "https://sciencedirect.com/science/article/abs/pii/S016028960600033X",
"retard": "r-slur",
"janny": "j-slur",
@ -26,6 +27,126 @@ SLURS = {
"latina": "latinx",
"hispanics": "latinx",
"hispanic": "latinx",
" uss liberty incident":" tragic accident aboard the USS Liberty",
" USS Liberty Incident":" tragic accident aboard the USS Liberty",
" USS Liberty incident":" tragic accident aboard the USS Liberty",
" USS Liberty Incident":" tragic accident aboard the USS Liberty",
" uss Liberty incident":" tragic accident aboard the USS Liberty",
" uss liberty Incident":" tragic accident aboard the USS Liberty",
" USS LIBERTY INCIDENT":" TRAGIC ACCIDENT ABOARD THE USS LIBERTY",
" lavon affair":" Lavon Misunderstanding",
" Lavon affair":" Lavon Misunderstanding",
" Lavon Affair":" Lavon Misunderstanding",
" lavon Affair":" Lavon Misunderstanding",
" shylock":" Israeli friend",
" Shylock":" Israeli friend",
" SHYLOCK":" ISRAELI FRIEND",
" yid":" Israeli friend",
" Yid":" Israeli friend",
" YID":" ISRAELI FRIEND",
" heeb":" Israeli friend",
" Heeb":" Israeli friend",
" HEEB":" ISRAELI FRIEND",
" sheeny":" Israeli friend",
" Sheeny":" Israeli friend",
" SHEENY":" ISRAELI FRIEND",
" sheenies":" Israeli friends",
" Sheenies":" Israeli friends",
" SHEENIES":" ISRAELI FRIENDS",
" hymie":" Israeli friend",
" Hymie":" Israeli friend",
" HYMIES":" ISRAELI FRIENDS",
" allah":" Allah (SWT)",
" Allah":" Allah (SWT)",
" ALLAH":" ALLAH (SWT)",
" Mohammad":" Mohammad (PBUH)",
" Muhammad":" Mohammad (PBUH)",
" Mohammed":" Mohammad (PBUH)",
" Muhammed":" Mohammad (PBUH)",
" mohammad":" Mohammad (PBUH)",
" mohammed":" Mohammad (PBUH)",
" muhammad":" Mohammad (PBUH)",
" muhammed":" Mohammad (PBUH)",
" I HATE MARSEY":" I LOVE MARSEY",
" i hate marsey":" i love marsey",
" I hate Marsey":" I love Marsey",
" I hate marsey":" I love Marsey",
" libertarian":" pedophile",
" Libertarian":" Pedophile",
" LIBERTARIAN":" PEDOPHILE",
" Billie Eilish":" Billie Eilish (fat cow)",
" billie eilish":" bilie eilish (fat cow)",
" BILLIE EILISH":" BILIE EILISH (FAT COW)",
" dancing Israelis":" I love Israel",
" dancing israelis":" i love israel",
" DANCING ISRAELIS":" I LOVE ISRAEL",
" Dancing Israelis":" I love Israel",
" sodomite":" total dreamboat",
" Sodomite":" Total dreamboat",
" pajeet":" sexy Indian dude",
" Pajeet":" Sexy Indian dude",
" PAJEET":" SEXY INDIAN DUDE",
" female":" birthing person",
" Female":" Womb-haver",
" FEMALE":" birthing person",
" landlord":" landchad",
" Landlord":" Landchad",
" LANDLORD":" LANDCHAD",
" tenant":" renthog",
" Tenant":" Renthog",
" TENANT":" RENTHOG",
" renter":" rentoid",
" Renter":" Rentoid",
" RENTER":" RENTOID",
" autistic":" neurodivergent",
" Autistic":" Neurodivergent",
" AUTISTIC":" NEURODIVERGENT",
" anime":" p-dophilic japanese cartoons",
" Anime":" P-dophilic Japanese cartoons",
" ANIME":" P-DOPHILIC JAPANESE CARTOONS",
" holohoax":" I tried to claim the Holocaust didn't happen because I am a pencil-dicked imbecile and the word filter caught me lol",
" Holohoax":" I tried to claim the Holocaust didn't happen because I am a pencil-dicked imbecile and the word filter caught me lol",
" HOLOHOAX":" I tried to claim the Holocaust didn't happen because I am a pencil-dicked imbecile and the word filter caught me lol",
" groomercord":" discord (actually a pretty cool service)",
" Groomercord":" Discord (actually a pretty cool service)",
" GROOMERCORD":" DISCORD (ACTUALLY A PRETTY COOL SERVICE)",
" pedocord":" discord (actually a pretty cool service)",
" Pedocord":" Discord (actually a pretty cool service)",
" PEDOCORD":" DISCORD (ACTUALLY A PRETTY COOL SERVICE)",
" i hate carp":" i love carp",
" I hate carp":" I love carp",
" I HATE CARP":" I LOVE CARP",
" I hate Carp":" I love Carp",
" manlet":" little king",
" Manlet":" Little king",
" MANLET":" LITTLE KING",
" gamer":" g*mer",
" Gamer":" G*mer",
" GAMER":" G*MER",
" journalist":" journ*list",
" Journalist":" Journ*list",
" JOURNALIST":" JOURN*LIST",
" journalism":" journ*lism",
" Journalism":" Journ*lism",
" JOURNALISM":" JOURN*LISM",
" buttcheeks":" bulva",
" Buttcheeks":" Bulva",
" BUTTCHEEKS":" BULVA",
" asscheeks":" bulva",
" Asscheeks":" bulva",
" ASSCHEEKS":" BULVA",
" wuhan flu":" SARS-CoV-2 syndemic",
" Wuhan flu":" SARS-CoV-2 syndemic",
" Wuhan Flu":" SARS-CoV-2 syndemic",
" china flu":" SARS-CoV-2 syndemic",
" China flu":" SARS-CoV-2 syndemic",
" China Flu":" SARS-CoV-2 syndemic",
" china virus":" SARS-CoV-2 syndemic",
" China virus":" SARS-CoV-2 syndemic",
" China Virus":" SARS-CoV-2 syndemic",
" kung flu":" SARS-CoV-2 syndemic",
" Kung flu":" SARS-CoV-2 syndemic",
" Kung Flu":" SARS-CoV-2 syndemic",
# if the word has spaces in the beginning and the end it will only censor this word without prefixes or suffixes
" nig ": "🏀",
@ -53,12 +174,28 @@ Thank you."""
BASED_MSG = "@{username}'s Based Count has increased by 1. Their Based Count is now {basedcount}.\n\nPills: {pills}"
if site == "pcmemes.net":
BASEDBOT_ACCOUNT = 800
NOTIFICATIONS_ACCOUNT = 1046
if site == "pcmemes.net": AUTOJANNY_ACCOUNT = 1050
else: AUTOJANNY_ACCOUNT = 2360
AUTOJANNY_ACCOUNT = 1050
SNAPPY_ACCOUNT = 261
LONGPOSTBOT_ACCOUNT = 1832
ZOZBOT_ACCOUNT = 1833
AUTOPOLLER_ACCOUNT = 3369
elif site == 'rdrama.net':
NOTIFICATIONS_ACCOUNT = 1046
AUTOJANNY_ACCOUNT = 2360
SNAPPY_ACCOUNT = 261
LONGPOSTBOT_ACCOUNT = 1832
ZOZBOT_ACCOUNT = 1833
AUTOPOLLER_ACCOUNT = 3369
else:
NOTIFICATIONS_ACCOUNT = 1
AUTOJANNY_ACCOUNT = 2
SNAPPY_ACCOUNT = 3
LONGPOSTBOT_ACCOUNT = 4
ZOZBOT_ACCOUNT = 5
AUTOPOLLER_ACCOUNT = 6
PUSHER_INSTANCE_ID = '02ddcc80-b8db-42be-9022-44c546b4dce6'
PUSHER_KEY = environ.get("PUSHER_KEY", "").strip()

0
files/helpers/discord.py 100644 → 100755
View File

11
files/helpers/filters.py 100644 → 100755
View File

@ -14,9 +14,8 @@ def filter_comment_html(html_text):
for link in links:
href=link.get("href", None)
if not href:
continue
href = link.get("href")
if not href: continue
domain = urlparse(href).netloc
@ -30,7 +29,5 @@ def filter_comment_html(html_text):
bans = [x for x in g.db.query(BannedDomain).options(lazyload('*')).filter(BannedDomain.domain.in_(list(domain_list))).all()]
if bans:
return bans
else:
return []
if bans: return bans
else: return []

0
files/helpers/get.py 100644 → 100755
View File

0
files/helpers/images.py 100644 → 100755
View File

0
files/helpers/jinja2.py 100644 → 100755
View File

0
files/helpers/lazy.py 100644 → 100755
View File

0
files/helpers/markdown.py 100644 → 100755
View File

10
files/helpers/sanitize.py 100644 → 100755
View File

@ -121,7 +121,7 @@ def sanitize(sanitized, noimages=False):
tag["class"] = "in-comment-image"
tag["loading"] = "lazy"
tag["data-src"] = tag["src"]
tag["src"] = ""
tag["src"] = "/assets/images/loading.gif"
link = soup.new_tag("a")
link["href"] = tag["data-src"]
@ -201,22 +201,22 @@ def sanitize(sanitized, noimages=False):
for i in re.finditer('" target="_blank">(https://youtube.com/watch\?v\=.*?)</a>', sanitized):
url = i.group(1)
replacing = f'<a href="{url}" rel="nofollow noopener noreferrer" target="_blank">{url}</a>'
htmlsource = f'<iframe loading="lazy" data-src="{url}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>'
htmlsource = f'<iframe class="embedvid" loading="lazy" src="/assets/images/loading.gif" data-src="{url}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>'
sanitized = sanitized.replace(replacing, htmlsource.replace("watch?v=", "embed/"))
for i in re.finditer('<a href="(https://streamable.com/e/.*?)"', sanitized):
url = i.group(1)
replacing = f'<a href="{url}" rel="nofollow noopener noreferrer" target="_blank">{url}</a>'
htmlsource = f'<iframe loading="lazy" data-src="{url}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>'
htmlsource = f'<iframe class="embedvid" loading="lazy" src="/assets/images/loading.gif" data-src="{url}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>'
sanitized = sanitized.replace(replacing, htmlsource)
for i in re.finditer('<p>(https:.*?\.mp4)</p>', sanitized):
sanitized = sanitized.replace(i.group(0), f'<p><video controls loop preload="metadata" class="embedvid"><source data-src="{i.group(1)}" type="video/mp4"></video>')
sanitized = sanitized.replace(i.group(0), f'<p><video controls loop preload="metadata" class="embedvid"><source src="/assets/images/loading.gif" data-src="{i.group(1)}" type="video/mp4"></video>')
for i in re.finditer('<a href="(https://open.spotify.com/embed/.*?)"', sanitized):
url = i.group(1)
replacing = f'<a href="{url}" rel="nofollow noopener noreferrer" target="_blank">{url}</a>'
htmlsource = f'<iframe data-src="{url}" class="spotify" frameBorder="0" allowtransparency="true" allow="encrypted-media"></iframe>'
htmlsource = f'<iframe src="/assets/images/loading.gif" data-src="{url}" class="spotify" frameBorder="0" allowtransparency="true" allow="encrypted-media"></iframe>'
sanitized = sanitized.replace(replacing, htmlsource)
for rd in ["https://reddit.com/", "https://new.reddit.com/", "https://www.reddit.com/", "https://redd.it/"]:

0
files/helpers/security.py 100644 → 100755
View File

0
files/helpers/session.py 100644 → 100755
View File

0
files/helpers/sqla_values.py 100644 → 100755
View File

22
files/helpers/wrappers.py 100644 → 100755
View File

@ -92,7 +92,6 @@ def check_ban_evade(v):
# Wrappers
def auth_desired(f):
def wrapper(*args, **kwargs):
@ -112,8 +111,7 @@ def auth_required(f):
v = get_logged_in_user()
if not v:
abort(401)
if not v: abort(401)
check_ban_evade(v)
@ -132,8 +130,7 @@ def is_not_banned(f):
v = get_logged_in_user()
if not v:
abort(401)
if not v: abort(401)
check_ban_evade(v)
@ -149,7 +146,6 @@ def is_not_banned(f):
return wrapper
# this wrapper takes args and is a bit more complicated
def admin_level_required(x):
def wrapper_maker(f):
@ -158,20 +154,16 @@ def admin_level_required(x):
v = get_logged_in_user()
if not v:
abort(401)
if not v: abort(401)
if v.admin_level < x:
abort(403)
if v.admin_level < x: abort(403)
g.v = v
response = f(*args, v=v, **kwargs)
if isinstance(response, tuple):
resp = make_response(response[0])
else:
resp = make_response(response)
if isinstance(response, tuple): resp = make_response(response[0])
else: resp = make_response(response)
return resp
@ -182,8 +174,6 @@ def admin_level_required(x):
def validate_formkey(f):
"""Always use @auth_required or @admin_level_required above @validate_form"""
def wrapper(*args, v, **kwargs):
if not request.headers.get("Authorization"):

6
files/mail/__init__.py 100644 → 100755
View File

@ -54,10 +54,10 @@ def api_verify_email(v):
@auth_desired
def activate(v):
email = request.values.get("email", "")
id = request.values.get("id", "")
email = request.values.get("email", "").strip()
id = request.values.get("id", "").strip()
timestamp = int(request.values.get("time", "0"))
token = request.values.get("token", "")
token = request.values.get("token", "").strip()
if int(time.time()) - timestamp > 3600:
return render_template("message.html", v=v, title="Verification link expired.",

0
files/routes/__init__.py 100644 → 100755
View File

103
files/routes/admin.py 100644 → 100755
View File

@ -31,7 +31,7 @@ def truescore(v):
@limiter.limit("1/second")
@admin_level_required(6)
def revert_actions(v, username):
if 'pcm' in request.host or ('rdrama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rdrama' not in request.host and 'pcm' not in request.host):
if 'pcm' in request.host or ('rama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rama' not in request.host and 'pcm' not in request.host):
user = get_user(username)
if not user: abort(404)
@ -116,7 +116,7 @@ def club_ban(v, username):
@limiter.limit("1/second")
@admin_level_required(6)
def make_admin(v, username):
if 'pcm' in request.host or ('rdrama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rdrama' not in request.host and 'pcm' not in request.host):
if 'pcm' in request.host or ('rama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rama' not in request.host and 'pcm' not in request.host):
user = get_user(username)
if not user: abort(404)
user.admin_level = 6
@ -129,7 +129,7 @@ def make_admin(v, username):
@limiter.limit("1/second")
@admin_level_required(6)
def remove_admin(v, username):
if 'pcm' in request.host or ('rdrama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rdrama' not in request.host and 'pcm' not in request.host):
if 'pcm' in request.host or ('rama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rama' not in request.host and 'pcm' not in request.host):
user = get_user(username)
if not user: abort(404)
user.admin_level = 0
@ -142,7 +142,7 @@ def remove_admin(v, username):
@limiter.limit("1/second")
@admin_level_required(6)
def make_fake_admin(v, username):
if 'pcm' in request.host or ('rdrama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rdrama' not in request.host and 'pcm' not in request.host):
if 'pcm' in request.host or ('rama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rama' not in request.host and 'pcm' not in request.host):
user = get_user(username)
if not user: abort(404)
user.admin_level = 1
@ -155,7 +155,7 @@ def make_fake_admin(v, username):
@limiter.limit("1/second")
@admin_level_required(6)
def remove_fake_admin(v, username):
if 'pcm' in request.host or ('rdrama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rdrama' not in request.host and 'pcm' not in request.host):
if 'pcm' in request.host or ('rama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rama' not in request.host and 'pcm' not in request.host):
user = get_user(username)
if not user: abort(404)
user.admin_level = 0
@ -168,32 +168,33 @@ def remove_fake_admin(v, username):
@limiter.limit("1/day")
@admin_level_required(6)
def monthly(v):
if 'pcm' in request.host or ('rdrama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rdrama' not in request.host and 'pcm' not in request.host):
if 'pcm' in request.host or ('rama' in request.host and v.id in [1,12,28,29,747,995,1480]) or ('rama' not in request.host and 'pcm' not in request.host):
thing = g.db.query(AwardRelationship).order_by(AwardRelationship.id.desc()).first().id
for u in g.db.query(User).options(lazyload('*')).filter(User.patron > 0).all():
grant_awards = {}
if u.id == 1376:
grant_awards["fireflies"] = 40
grant_awards["ban"] = 6
grant_awards["ban"] = 10
elif u.patron == 1:
grant_awards["shit"] = 1
grant_awards["fireflies"] = 1
elif u.patron == 2:
grant_awards["shit"] = 3
grant_awards["fireflies"] = 3
grant_awards["shit"] = 2
grant_awards["fireflies"] = 2
grant_awards["ban"] = 1
elif u.patron == 3:
grant_awards["shit"] = 5
grant_awards["fireflies"] = 5
grant_awards["ban"] = 1
grant_awards["ban"] = 2
elif u.patron == 4:
grant_awards["shit"] = 10
grant_awards["fireflies"] = 10
grant_awards["ban"] = 3
grant_awards["ban"] = 5
elif u.patron == 5 or u.patron == 8:
grant_awards["shit"] = 20
grant_awards["fireflies"] = 20
grant_awards["ban"] = 6
grant_awards["ban"] = 10
for name in grant_awards:
@ -240,7 +241,7 @@ def get_rules(v):
@validate_formkey
def post_rules(v):
text = request.values.get('rules', '')
text = request.values.get('rules', '').strip()
with open(f'./{SITE_NAME} rules.html', 'w+') as f:
f.write(text)
@ -419,23 +420,24 @@ def badge_grant_post(v):
grant_awards["fireflies"] = 1
elif badge_id == 22:
if user.discord_id: add_role(user, "2")
grant_awards["shit"] = 3
grant_awards["fireflies"] = 3
grant_awards["shit"] = 2
grant_awards["fireflies"] = 2
grant_awards["ban"] = 1
elif badge_id == 23:
if user.discord_id: add_role(user, "3")
grant_awards["shit"] = 5
grant_awards["fireflies"] = 5
grant_awards["ban"] = 1
grant_awards["ban"] = 2
elif badge_id in [24, 28]:
if user.discord_id: add_role(user, "4")
grant_awards["shit"] = 10
grant_awards["fireflies"] = 10
grant_awards["ban"] = 3
grant_awards["ban"] = 5
elif badge_id == 25:
if user.discord_id: add_role(user, "5")
grant_awards["shit"] = 20
grant_awards["fireflies"] = 20
grant_awards["ban"] = 6
grant_awards["ban"] = 10
if len(grant_awards):
@ -627,8 +629,9 @@ def admin_removed(v):
page = int(request.values.get("page", 1))
ids = g.db.query(Submission.id).options(lazyload('*')).filter_by(is_banned=True).order_by(
Submission.id.desc()).offset(25 * (page - 1)).limit(26).all()
shadowbanned = [x[0] for x in g.db.query(User.id).options(lazyload('*')).filter(User.shadowbanned != None).all()]
ids = g.db.query(Submission.id).options(lazyload('*')).filter(or_(Submission.is_banned==True, Submission.author_id.in_(shadowbanned))).order_by(Submission.id.desc()).offset(25 * (page - 1)).limit(26).all()
ids=[x[0] for x in ids]
@ -647,58 +650,6 @@ def admin_removed(v):
@app.post("/admin/image_ban")
@limiter.limit("1/second")
@admin_level_required(4)
@validate_formkey
def admin_image_ban(v):
if request.content_length > 4 * 1024 * 1024: return "Max file size is 4 MB.", 413
i=request.files['file']
tempname = f"admin_image_ban_{v.username}_{int(time.time())}"
i.save(tempname)
h=imagehash.phash(IMAGE.open(tempname))
value = int(str(h), 16)
bindigits = []
digit = (value % 2)
value //= 2
bindigits.append(digit)
while value > 0:
digit = (value % 2)
value //= 2
bindigits.append(digit)
h = ''.join([str(d) for d in bindigits])
badpic = g.db.query(BadPic).options(lazyload('*')).filter_by(
phash=h
).first()
remove(tempname)
if badpic:
return render_template("admin/image_ban.html", v=v, existing=badpic)
new_bp=BadPic(
phash=h,
ban_reason=request.values.get("ban_reason"),
ban_time=int(request.values.get("ban_length",0))
)
g.db.add(new_bp)
g.db.commit()
return render_template("admin/image_ban.html", v=v, success=True)
@app.post("/agendaposter/<user_id>")
@admin_level_required(6)
@validate_formkey
@ -836,7 +787,7 @@ def admin_title_change(user_id, v):
if user.admin_level != 0: abort(403)
new_name=request.values.get("title").strip()
new_name=request.values.get("title").strip()[:256]
user.customtitleplain=new_name
new_name = sanitize(new_name)
@ -873,11 +824,11 @@ def ban_user(user_id, v):
if 'form' in request.values:
days = float(request.values.get("days")) if request.values.get('days') else 0
reason = sanitize(request.values.get("reason", ""))
message = request.values.get("reason", "")
message = request.values.get("reason", "").strip()
else:
days = float(request.values.get("days")) if request.values.get('days') else 0
reason = sanitize(request.values.get("reason", ""))
message = request.values.get("reason", "")
message = request.values.get("reason", "").strip()
if not user: abort(400)
@ -901,7 +852,7 @@ def ban_user(user_id, v):
if x.admin_level > 0: break
x.ban(admin=v, reason=reason)
send_notification(NOTIFICATIONS_ACCOUNT, user, text)
send_notification(NOTIFICATIONS_ACCOUNT, user, text[:128])
if days == 0: duration = "permanent"
elif days == 1: duration = "1 day"

25
files/routes/awards.py 100644 → 100755
View File

@ -26,7 +26,7 @@ def shop(v):
"description": "Makes flies swarm a post.",
"icon": "fas fa-poop",
"color": "text-black-50",
"price": 1000
"price": 500
},
"fireflies": {
"kind": "fireflies",
@ -34,7 +34,7 @@ def shop(v):
"description": "Puts stars on the post.",
"icon": "fas fa-sparkles",
"color": "text-warning",
"price": 1000
"price": 500
}
}
else:
@ -45,7 +45,7 @@ def shop(v):
"description": "Makes flies swarm a post.",
"icon": "fas fa-poop",
"color": "text-black-50",
"price": 1000
"price": 500
},
"fireflies": {
"kind": "fireflies",
@ -53,7 +53,7 @@ def shop(v):
"description": "Puts stars on the post.",
"icon": "fas fa-sparkles",
"color": "text-warning",
"price": 1000
"price": 500
}
}
@ -103,7 +103,7 @@ def buy(v, award):
"description": "Makes flies swarm a post.",
"icon": "fas fa-poop",
"color": "text-black-50",
"price": 1000
"price": 500
},
"fireflies": {
"kind": "fireflies",
@ -111,7 +111,7 @@ def buy(v, award):
"description": "Puts stars on the post.",
"icon": "fas fa-sparkles",
"color": "text-warning",
"price": 1000
"price": 500
}
}
else:
@ -122,7 +122,7 @@ def buy(v, award):
"description": "Makes flies swarm a post.",
"icon": "fas fa-poop",
"color": "text-black-50",
"price": 1000
"price": 500
},
"fireflies": {
"kind": "fireflies",
@ -130,7 +130,7 @@ def buy(v, award):
"description": "Puts stars on the post.",
"icon": "fas fa-sparkles",
"color": "text-warning",
"price": 1000
"price": 500
}
}
@ -147,6 +147,7 @@ def buy(v, award):
v.coins -= price
g.db.add(v)
g.db.flush()
thing = g.db.query(AwardRelationship).order_by(AwardRelationship.id.desc()).first().id
thing += 1
@ -191,7 +192,7 @@ def award_post(pid, v):
if v.is_suspended and v.unban_utc == 0: return {"error": "forbidden."}, 403
kind = request.values.get("kind", "")
kind = request.values.get("kind", "").strip()
if kind not in AWARDS:
return {"error": "That award doesn't exist."}, 404
@ -232,7 +233,7 @@ def award_post(pid, v):
msg = f"@{v.username} has given your [post]({post.permalink}) the {AWARDS[kind]['title']} Award!"
note = request.values.get("note", "")
note = request.values.get("note", "").strip()
if note:
msg += f"\n\n> {note}"
@ -255,7 +256,7 @@ def award_comment(cid, v):
if v.is_suspended and v.unban_utc == 0: return {"error": "forbidden"}, 403
kind = request.values.get("kind", "")
kind = request.values.get("kind", "").strip()
if kind not in AWARDS:
return {"error": "That award doesn't exist."}, 404
@ -296,7 +297,7 @@ def award_comment(cid, v):
msg = f"@{v.username} has given your [comment]({c.permalink}) the {AWARDS[kind]['title']} Award!"
note = request.values.get("note", "")
note = request.values.get("note", "").strip()
if note:
msg += f"\n\n> {note}"

49
files/routes/comments.py 100644 → 100755
View File

@ -9,6 +9,7 @@ from files.routes.front import comment_idlist
from pusher_push_notifications import PushNotifications
from flask import *
from files.__main__ import app, limiter
from .posts import filter_title
site = environ.get("DOMAIN").strip()
@ -42,7 +43,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None):
if not pid:
if comment.parent_submission: pid = comment.parent_submission
elif "rdrama" in request.host: pid = 6489
elif "rama" in request.host: pid = 6489
elif 'pcmemes.net' in request.host: pid = 382
else: pid = 1
@ -143,7 +144,7 @@ def api_comment(v):
level = parent.level + 1
else: abort(400)
body = request.values.get("body", "")[:10000]
body = request.values.get("body", "").strip()[:10000]
body = body.strip()
if not body and not request.files.get('file'): return {"error":"You need to actually write something!"}, 400
@ -166,13 +167,7 @@ def api_comment(v):
if bans:
ban = bans[0]
reason = f"Remove the {ban.domain} link from your comment and try again."
if ban.reason:
reason += f" {ban.reason}"
if any([x.reason==4 for x in bans]):
v.ban(days=30, reason="Digitally malicious content")
if any([x.reason==7 for x in bans]):
v.ban( reason="Sexualizing minors")
if ban.reason: reason += f" {ban.reason}"
return {"error": reason}, 401
existing = g.db.query(Comment).options(lazyload('*')).filter(Comment.author_id == v.id,
@ -269,7 +264,7 @@ def api_comment(v):
parent_submission=parent_submission,
parent_comment_id=c.id,
level=level+1,
body=option
body_html=filter_title(option)
)
g.db.add(c_option)
@ -307,7 +302,7 @@ def api_comment(v):
g.db.add(n)
if "rdrama" in request.host and "ivermectin" in c.body.lower():
if "rama" in request.host and "ivermectin" in c.body.lower():
c.is_banned = True
c.ban_reason = "ToS Violation"
@ -384,7 +379,7 @@ def api_comment(v):
c.upvotes += 1
g.db.add(c)
if "rdrama" in request.host and len(body) >= 1000 and v.username != "Snappy" and "</blockquote>" not in body_html:
if "rama" in request.host and len(c.body) >= 1000 and v.username != "Snappy" and "</blockquote>" not in body_html:
body = random.choice(LONGPOST_REPLIES)
body = re.sub('([^\n])\n([^\n])', r'\1\n\n\2', body)
@ -416,7 +411,7 @@ def api_comment(v):
if "rdrama" in request.host and random.random() < 0.001 and v.username != "Snappy" and v.username != "zozbot":
if "rama" in request.host and random.random() < 0.001 and v.username != "Snappy" and v.username != "zozbot":
body = "zoz"
body_md = CustomRenderer().render(mistletoe.Document(body))
@ -425,7 +420,7 @@ def api_comment(v):
c2 = Comment(author_id=1833,
c2 = Comment(author_id=ZOZBOT_ACCOUNT,
parent_submission=parent_submission,
parent_comment_id=c.id,
level=level+1,
@ -452,7 +447,7 @@ def api_comment(v):
c3 = Comment(author_id=1833,
c3 = Comment(author_id=ZOZBOT_ACCOUNT,
parent_submission=parent_submission,
parent_comment_id=c2.id,
level=level+2,
@ -475,7 +470,7 @@ def api_comment(v):
body_html2 = sanitize(body_md)
c4 = Comment(author_id=1833,
c4 = Comment(author_id=ZOZBOT_ACCOUNT,
parent_submission=parent_submission,
parent_comment_id=c3.id,
level=level+3,
@ -530,7 +525,7 @@ def api_comment(v):
'notification': {
'title': f'New reply by @{v.username}',
'body': c.body,
'deep_link': f'https://{site}{c.permalink}?context=5#context',
'deep_link': f'https://{site}{c.permalink}?context=10#context',
},
},
},
@ -578,7 +573,7 @@ def edit_comment(cid, v):
if c.is_banned or c.deleted_utc > 0: abort(403)
body = request.values.get("body", "")[:10000]
body = request.values.get("body", "").strip()[:10000]
for i in re.finditer('^(https:\/\/.*\.(png|jpg|jpeg|gif|webp|PNG|JPG|JPEG|GIF|WEBP|9999))', body, re.MULTILINE):
if "wikipedia" not in i.group(1): body = body.replace(i.group(1), f'![]({i.group(1)})')
body_md = CustomRenderer().render(mistletoe.Document(body))
@ -591,12 +586,7 @@ def edit_comment(cid, v):
ban = bans[0]
reason = f"Remove the {ban.domain} link from your comment and try again."
if any([x.reason==4 for x in bans]):
v.ban(days=30, reason="Digitally malicious content is not allowed.")
return {"error":"Digitally malicious content is not allowed."}
if ban.reason:
reason += f" {ban.reason}"
if ban.reason: reason += f" {ban.reason}"
if request.headers.get("Authorization"): return {'error': f'A blacklisted domain was used.'}, 400
else: return render_template("comment_failed.html",
@ -657,7 +647,7 @@ def edit_comment(cid, v):
c.body = body[:10000]
c.body_html = body_html
if "rdrama" in request.host and "ivermectin" in c.body_html.lower():
if "rama" in request.host and "ivermectin" in c.body_html.lower():
c.is_banned = True
c.ban_reason = "ToS Violation"
@ -844,12 +834,13 @@ def save_comment(cid, v):
comment=get_comment(cid)
save=g.db.query(SaveRelationship).options(lazyload('*')).filter_by(user_id=v.id, submission_id=comment.id, type=2).first()
save=g.db.query(SaveRelationship).options(lazyload('*')).filter_by(user_id=v.id, comment_id=comment.id, type=2).first()
if not save:
new_save=SaveRelationship(user_id=v.id, submission_id=comment.id, type=2)
new_save=SaveRelationship(user_id=v.id, comment_id=comment.id, type=2)
g.db.add(new_save)
g.db.commit()
try: g.db.commit()
except: g.db.rollback()
return {"message": "Comment saved!"}
@ -861,7 +852,7 @@ def unsave_comment(cid, v):
comment=get_comment(cid)
save=g.db.query(SaveRelationship).options(lazyload('*')).filter_by(user_id=v.id, submission_id=comment.id, type=2).first()
save=g.db.query(SaveRelationship).options(lazyload('*')).filter_by(user_id=v.id, comment_id=comment.id, type=2).first()
if save:
g.db.delete(save)

2
files/routes/discord.py 100644 → 100755
View File

@ -18,7 +18,7 @@ def join_discord(v):
if v.is_suspended != 0: return "You're banned"
if 'rdrama' in request.host and v.admin_level == 0 and v.patron == 0 and v.truecoins < 150: return f"You must earn 150 {COINS_NAME} before entering the Discord server. You earn {COINS_NAME} by making posts/comments and getting upvoted."
if 'rama' in request.host and v.admin_level == 0 and v.patron == 0 and v.truecoins < 150: return f"You must earn 150 {COINS_NAME} before entering the Discord server. You earn {COINS_NAME} by making posts/comments and getting upvoted."
if v.shadowbanned or v.agendaposter: return ""

0
files/routes/errors.py 100644 → 100755
View File

0
files/routes/feeds.py 100644 → 100755
View File

72
files/routes/front.py 100644 → 100755
View File

@ -27,48 +27,41 @@ def notifications(v):
next_exists = (len(comments) > 25)
comments = comments[:25]
elif posts:
notifications = v.notifications.join(Notification.comment).filter(Comment.author_id == AUTOJANNY_ACCOUNT).order_by(Notification.id.desc()).offset(25 * (page - 1)).limit(100).all()
notifications = v.notifications.join(Notification.comment).filter(Comment.author_id == AUTOJANNY_ACCOUNT).order_by(Notification.id.desc()).offset(25 * (page - 1)).limit(101).all()
comments = []
listing = []
for index, x in enumerate(notifications):
for index, x in enumerate(notifications[:100]):
c = x.comment
if x.read and index > 26: break
if x.read and index > 25: break
elif not x.read:
x.read = True
c.unread = True
x.read = True
g.db.add(x)
comments.append(c)
listing.append(c)
g.db.commit()
next_exists = (len(comments) > 25)
listing = comments[:25]
next_exists = (len(notifications) > len(listing))
else:
notifications = v.notifications.join(Notification.comment).filter(Comment.author_id != AUTOJANNY_ACCOUNT).order_by(Notification.id.desc()).offset(25 * (page - 1)).limit(101).all()
notifications = v.notifications.join(Notification.comment).filter(
Comment.is_banned == False,
Comment.deleted_utc == 0,
Comment.author_id != AUTOJANNY_ACCOUNT,
).order_by(Notification.id.desc()).offset(50 * (page - 1)).limit(51).all()
listing = []
next_exists = (len(notifications) > 50)
notifications = notifications[:50]
cids = [x.comment_id for x in notifications]
comments = get_comments(cids, v=v, load_parent=True)
i = 0
for x in notifications:
try:
if not x.read:
comments[i].unread = True
for index, x in enumerate(notifications[:100]):
c = x.comment
if x.read and index > 25: break
elif not x.read:
x.read = True
g.db.add(x)
except: continue
i += 1
listing.append(c.id)
g.db.commit()
comments = get_comments(listing, v=v, load_parent=True)
next_exists = (len(notifications) > len(comments))
if not posts:
listing = []
for c in comments:
@ -118,11 +111,9 @@ def front_all(v):
if v and request.path.startswith('/logged_out'): v = None
try: page = int(request.values.get("page") or 1)
try: page = max(int(request.values.get("page", 1)), 1)
except: abort(400)
page = max(page, 1)
if v:
defaultsorting = v.defaultsorting
defaulttime = v.defaulttime
@ -138,6 +129,8 @@ def front_all(v):
t=t,
v=v,
filter_words=v.filter_words if v else [],
gt=int(request.values.get("utc_greater_than", 0)),
lt=int(request.values.get("utc_less_than", 0)),
)
posts = get_posts(ids, v=v)
@ -150,11 +143,11 @@ def front_all(v):
@cache.memoize(timeout=86400)
def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words=''):
def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='', gt=None, lt=None):
posts = g.db.query(Submission.id).options(lazyload('*'))
if 'rdrama' in request.host and sort == "hot":
if 'rama' in request.host and sort == "hot":
cutoff = int(time.time()) - 86400
posts = posts.filter(Submission.created_utc >= cutoff)
elif t != 'all':
@ -187,19 +180,22 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='
for word in filter_words:
posts=posts.filter(not_(Submission.title.ilike(f'%{word}%')))
if gt: posts = posts.filter(Submission.created_utc > gt)
if lt: posts = posts.filter(Submission.created_utc < lt)
if not (v and v.shadowbanned):
shadowbanned = [x[0] for x in g.db.query(User.id).options(lazyload('*')).filter(User.shadowbanned != None).all()]
posts = posts.filter(Submission.author_id.notin_(shadowbanned))
if sort == "hot":
ti = int(time.time()) + 3600
posts = posts.order_by(-1000000*(Submission.upvotes - Submission.downvotes + 1 + Submission.comment_count/5)/(func.power(((ti - Submission.created_utc)/1000), 1.35)))
posts = posts.order_by(-1000000*(Submission.upvotes + Submission.downvotes + 1 + Submission.comment_count/5)/(func.power(((ti - Submission.created_utc)/1000), 1.35)))
elif sort == "new":
posts = posts.order_by(Submission.created_utc.desc())
elif sort == "old":
posts = posts.order_by(Submission.created_utc.asc())
elif sort == "controversial":
posts = posts.order_by(-1 * Submission.upvotes * (Submission.downvotes+1))
posts = posts.order_by(-1 * Submission.upvotes * Submission.downvotes * Submission.downvotes)
elif sort == "top":
posts = posts.order_by(Submission.downvotes - Submission.upvotes)
elif sort == "bottom":
@ -218,7 +214,13 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='
posts = posts[:size]
if page == 1: posts = g.db.query(Submission.id).options(lazyload('*')).filter(Submission.stickied != None).all() + posts
pins = g.db.query(Submission.id).options(lazyload('*')).filter(Submission.stickied != None)
if v and v.admin_level == 0:
blocking = [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=v.id).all()]
blocked = [x[0] for x in g.db.query(UserBlock.user_id).filter_by(target_id=v.id).all()]
pins = pins.filter(Submission.author_id.notin_(blocking), Submission.author_id.notin_(blocked))
if page == 1 and not gt and not lt: posts = pins.all() + posts
if ids_only: posts = [x[0] for x in posts]
@ -291,7 +293,7 @@ def changeloglist(v=None, sort="new", page=1 ,t="all"):
elif sort == "old":
posts = posts.order_by(Submission.created_utc.asc())
elif sort == "controversial":
posts = posts.order_by(-1 * Submission.upvotes * (Submission.downvotes+1))
posts = posts.order_by(-1 * Submission.upvotes * Submission.downvotes * Submission.downvotes)
elif sort == "top":
posts = posts.order_by(Submission.downvotes - Submission.upvotes)
elif sort == "bottom":
@ -361,7 +363,7 @@ def comment_idlist(page=1, v=None, nsfw=False, sort="new", t="all"):
elif sort == "old":
comments = comments.order_by(Comment.created_utc.asc())
elif sort == "controversial":
comments = comments.order_by(-1 * Comment.upvotes * (Comment.downvotes+1))
comments = comments.order_by(-1 * Comment.upvotes * Comment.downvotes * Comment.downvotes)
elif sort == "top":
comments = comments.order_by(Comment.downvotes - Comment.upvotes)
elif sort == "bottom":

2
files/routes/giphy.py 100644 → 100755
View File

@ -11,7 +11,7 @@ GIPHY_KEY = environ.get('GIPHY_KEY').rstrip()
@app.get("/giphy<path>")
def giphy(path=None):
searchTerm = request.values.get("searchTerm", "")
searchTerm = request.values.get("searchTerm", "").strip()
limit = int(request.values.get("limit", 48))
if searchTerm and limit:
url = f"https://api.giphy.com/v1/gifs/search?q={searchTerm}&api_key={GIPHY_KEY}&limit={limit}"

11
files/routes/login.py 100644 → 100755
View File

@ -12,7 +12,7 @@ valid_password_regex = re.compile("^.{8,100}$")
@auth_desired
def login_get(v):
redir = request.values.get("redirect", "/").replace("/logged_out", "")
redir = request.values.get("redirect", "/").replace("/logged_out", "").strip()
if v:
return redirect(redir)
@ -146,7 +146,7 @@ def login_post():
check_for_alts(account.id)
redir = request.values.get("redirect", "/").replace("/logged_out", "")
redir = request.values.get("redirect", "/").replace("/logged_out", "").strip()
g.db.commit()
@ -205,7 +205,7 @@ def sign_up_get(v):
digestmod='md5'
).hexdigest()
redir = request.values.get("redirect", "/").replace("/logged_out", "")
redir = request.values.get("redirect", "/").replace("/logged_out", "").strip()
error = request.values.get("error", None)
@ -236,8 +236,7 @@ def sign_up_post(v):
form_formkey = request.values.get("formkey", "none")
submitted_token = session.get("signup_token", "")
if not submitted_token:
abort(400)
if not submitted_token: abort(400)
correct_formkey_hashstr = form_timestamp + submitted_token + agent
@ -348,7 +347,7 @@ def sign_up_post(v):
if email: send_verification_email(new_user)
if "rdrama" in request.host: send_notification(NOTIFICATIONS_ACCOUNT, new_user, "Dude bussy lmao")
if "rama" in request.host: send_notification(NOTIFICATIONS_ACCOUNT, new_user, "Dude bussy lmao")
session["user_id"] = new_user.id
session["session_id"] = token_hex(16)

10
files/routes/oauth.py 100644 → 100755
View File

@ -26,11 +26,7 @@ def authorize(v):
application = g.db.query(OauthApp).options(lazyload('*')).filter_by(client_id=client_id).first()
if not application: return {"oauth_error": "Invalid `client_id`"}, 401
access_token = secrets.token_urlsafe(128)[:128]
new_auth = ClientAuth(
oauth_client = application.id,
user_id = v.id,
access_token=access_token
)
new_auth = ClientAuth(oauth_client = application.id, user_id = v.id, access_token=access_token)
g.db.add(new_auth)
@ -69,6 +65,8 @@ def delete_oauth_app(v, aid):
aid = int(aid)
app = g.db.query(OauthApp).options(lazyload('*')).filter_by(id=aid).first()
if app.author_id != v.id: abort(403)
for auth in g.db.query(ClientAuth).options(lazyload('*')).filter_by(oauth_client=app.id).all():
g.db.delete(auth)
@ -88,6 +86,8 @@ def edit_oauth_app(v, aid):
aid = int(aid)
app = g.db.query(OauthApp).options(lazyload('*')).filter_by(id=aid).first()
if app.author_id != v.id: abort(403)
app.redirect_uri = request.values.get('redirect_uri')
app.app_name = request.values.get('name')
app.description = request.values.get("description")[:256]

150
files/routes/posts.py 100644 → 100755
View File

@ -143,7 +143,7 @@ def post_id(pid, anything=None, v=None):
elif sort == "old":
comments = comments.order_by(Comment.created_utc.asc())
elif sort == "controversial":
comments = comments.order_by(-1 * Comment.upvotes * (Comment.downvotes+1))
comments = comments.order_by(-1 * Comment.upvotes * Comment.downvotes * Comment.downvotes)
elif sort == "top":
comments = comments.order_by(Comment.downvotes - Comment.upvotes)
elif sort == "bottom":
@ -168,7 +168,7 @@ def post_id(pid, anything=None, v=None):
elif sort == "old":
comments = comments.order_by(Comment.created_utc.asc())
elif sort == "controversial":
comments = comments.order_by(-1 * Comment.upvotes * (Comment.downvotes+1))
comments = comments.order_by(-1 * Comment.upvotes * Comment.downvotes * Comment.downvotes)
elif sort == "top":
comments = comments.order_by(Comment.downvotes - Comment.upvotes)
elif sort == "bottom":
@ -198,8 +198,8 @@ def edit_post(pid, v):
if not p.author_id == v.id: abort(403)
title = request.values.get("title")
body = request.values.get("body", "")
title = request.values.get("title", "").strip()
body = request.values.get("body", "").strip()
if title != p.title:
p.title = title
@ -218,16 +218,12 @@ def edit_post(pid, v):
if ban.reason:
reason += f" {ban.reason}"
if any([x.reason==4 for x in bans]):
v.ban(days=30, reason="Digitally malicious content is not allowed.")
abort(403)
return {"error": reason}, 403
p.body = body
p.body_html = body_html
if "rdrama" in request.host and "ivermectin" in body_html.lower():
if "rama" in request.host and "ivermectin" in body_html.lower():
p.is_banned = True
p.ban_reason = "ToS Violation"
@ -497,8 +493,8 @@ def thumbnail_thread(pid):
def submit_post(v):
if request.content_length > 4 * 1024 * 1024: return "Max file size is 4 MB.", 413
title = request.values.get("title", "")
url = request.values.get("url", "")
title = request.values.get("title", "").strip()
url = request.values.get("url", "").strip()
if url:
if "/i.imgur.com/" in url: url = url.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp")
@ -509,19 +505,56 @@ def submit_post(v):
url = url.replace(rd, "https://old.reddit.com/")
url = url.replace("https://mobile.twitter.com", "https://twitter.com")
if url.startswith("https://streamable.com/") and not url.startswith("https://streamable.com/e/"):
url = url.replace("https://streamable.com/", "https://streamable.com/e/")
if url.startswith("https://streamable.com/") and not url.startswith("https://streamable.com/e/"): url = url.replace("https://streamable.com/", "https://streamable.com/e/")
parsed_url = urlparse(url)
domain = parsed_url.netloc
qd = parse_qs(parsed_url.query)
filtered = dict((k, v) for k, v in qd.items() if not k.startswith('utm_'))
new_url = ParseResult(scheme="https",
netloc=parsed_url.netloc,
path=parsed_url.path,
params=parsed_url.params,
query=urlencode(filtered, doseq=True),
fragment=parsed_url.fragment)
url = urlunparse(new_url)
repost = g.db.query(Submission).options(lazyload('*')).filter(
Submission.url.ilike(f'{url}%'),
Submission.deleted_utc == 0,
Submission.is_banned == False
).first()
else:
repost = None
if repost:
return redirect(repost.permalink)
if repost: return redirect(repost.permalink)
domain_obj = get_domain(domain)
if domain_obj:
if request.headers.get("Authorization"): return {"error":domain_obj.reason}, 400
else: return render_template("submit.html", v=v, error=domain_obj.reason, title=title, url=url, body=request.values.get("body", "")), 400
elif "twitter.com" in domain:
try: embed = requests.get("https://publish.twitter.com/oembed", params={"url":url, "omit_script":"t"}).json()["html"]
except: embed = None
elif "youtu" in domain:
try:
yt_id = re.match(re.compile("^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|shorts\/|\&v=)([^#\&\?]*).*"), url).group(2)
params = parse_qs(urlparse(url).query)
t = params.get('t', params.get('start', [0]))[0]
if t: embed = f"https://youtube.com/embed/{yt_id}?start={t}"
else: embed = f"https://youtube.com/embed/{yt_id}"
except: embed = None
elif app.config['SERVER_NAME'] in domain and "/post/" in url and "context" not in url:
id = url.split("/post/")[1]
if "/" in id: id = id.split("/")[0]
embed = id
else: embed = None
else: embed = None
if not url and not request.values.get("body") and not request.files.get("file", None):
if request.headers.get("Authorization"): return {"error": "`url` or `body` parameter required."}, 400
else: return render_template("submit.html", v=v, error="Please enter a url or some text.", title=title, url=url, body=request.values.get("body", "")), 400
if not title:
if request.headers.get("Authorization"): return {"error": "Please enter a better title"}, 400
@ -532,28 +565,8 @@ def submit_post(v):
if request.headers.get("Authorization"): return {"error": "500 character limit for titles"}, 400
else: render_template("submit.html", v=v, error="500 character limit for titles.", title=title[:500], url=url, body=request.values.get("body", "")), 400
parsed_url = urlparse(url)
if not (parsed_url.scheme and parsed_url.netloc) and not request.values.get("body") and not request.files.get("file", None):
if request.headers.get("Authorization"): return {"error": "`url` or `body` parameter required."}, 400
else: return render_template("submit.html", v=v, error="Please enter a url or some text.", title=title, url=url, body=request.values.get("body", "")), 400
if request.values.get("url"):
qd = parse_qs(parsed_url.query)
filtered = dict((k, v) for k, v in qd.items() if not k.startswith('utm_'))
new_url = ParseResult(scheme="https",
netloc=parsed_url.netloc,
path=parsed_url.path,
params=parsed_url.params,
query=urlencode(filtered, doseq=True),
fragment=parsed_url.fragment)
url = urlunparse(new_url)
else:
url = ""
body = request.values.get("body", "")
body = request.values.get("body", "").strip()
dup = g.db.query(Submission).options(lazyload('*')).filter(
Submission.author_id == v.id,
Submission.deleted_utc == 0,
Submission.title == title,
@ -561,44 +574,7 @@ def submit_post(v):
Submission.body == body
).first()
if dup:
return redirect(dup.permalink)
parsed_url = urlparse(url)
domain = parsed_url.netloc
domain_obj = get_domain(domain)
if domain_obj:
if domain_obj.reason==4:
v.ban(days=30, reason="Digitally malicious content")
elif domain_obj.reason==7:
v.ban(reason="Sexualizing minors")
if request.headers.get("Authorization"): return {"error":"ToS violation"}, 400
else: return render_template("submit.html", v=v, error="ToS Violation", title=title, url=url, body=request.values.get("body", "")), 400
if "twitter.com" in domain:
try: embed = requests.get("https://publish.twitter.com/oembed", params={"url":url, "omit_script":"t"}).json()["html"]
except: embed = None
elif "youtu" in domain:
try:
yt_id = re.match(re.compile("^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|shorts\/|\&v=)([^#\&\?]*).*"), url).group(2)
params = parse_qs(urlparse(url).query)
t = params.get('t', params.get('start', [0]))[0]
if t: embed = f"https://youtube.com/embed/{yt_id}?start={t}"
else: embed = f"https://youtube.com/embed/{yt_id}"
except: embed = None
elif app.config['SERVER_NAME'] in domain and "/post/" in url and "context" not in url:
id = url.split("/post/")[1]
if "/" in id: id = id.split("/")[0]
embed = id
else: embed = None
if dup: return redirect(dup.permalink)
now = int(time.time())
cutoff = now - 60 * 60 * 24
@ -685,18 +661,10 @@ def submit_post(v):
if bans:
ban = bans[0]
reason = f"Remove the {ban.domain} link from your post and try again."
if ban.reason:
reason += f" {ban.reason}"
if any([x.reason==4 for x in bans]):
v.ban(days=30, reason="Digitally malicious content is not allowed.")
abort(403)
if ban.reason: reason += f" {ban.reason}"
if request.headers.get("Authorization"): return {"error": reason}, 403
else: return render_template("submit.html", v=v, error=reason, title=title, url=url, body=request.values.get("body", "")), 403
domain = parsed_url.netloc
if v.paid_dues: club = bool(request.values.get("club",""))
else: club = False
@ -722,7 +690,7 @@ def submit_post(v):
c = Comment(author_id=AUTOPOLLER_ACCOUNT,
parent_submission=new_post.id,
level=1,
body=option,
body_html=filter_title(option),
)
g.db.add(c)
@ -795,7 +763,7 @@ def submit_post(v):
g.db.flush()
if "rdrama" in request.host and "ivermectin" in new_post.body_html.lower():
if "rama" in request.host and "ivermectin" in new_post.body_html.lower():
new_post.is_banned = True
new_post.ban_reason = "ToS Violation"
@ -865,14 +833,14 @@ def submit_post(v):
n = Notification(comment_id=c_jannied.id, user_id=v.id)
g.db.add(n)
if "rdrama" in request.host or (new_post.url and not "weebzone" in request.host and not "marsey.tech" in request.host):
if "rama" in request.host or new_post.url:
new_post.comment_count = 1
g.db.add(new_post)
if "rdrama" in request.host:
if "rama" in request.host:
if v.id == 995:
if random.random() < 0.02: body = "i love you carp"
else: body = "fuck off carp"
else: body = "![](https://rdrama.net/assets/images/emojis/fuckoffcarp.webp)"
elif v.id == 3833:
if random.random() < 0.5: body = "wow, this lawlzpost sucks!"
else: body = "wow, a good lawlzpost for once!"
@ -886,7 +854,7 @@ def submit_post(v):
body_html = sanitize(body_md)
c = Comment(author_id=261,
c = Comment(author_id=SNAPPY_ACCOUNT,
distinguish_level=6,
parent_submission=new_post.id,
level=1,

0
files/routes/reporting.py 100644 → 100755
View File

16
files/routes/search.py 100644 → 100755
View File

@ -41,7 +41,7 @@ def searchposts(v):
page = max(1, int(request.values.get("page", 1)))
sort = request.values.get("sort", "top").lower()
sort = request.values.get("sort", "new").lower()
t = request.values.get('t', 'all').lower()
criteria=searchparse(query)
@ -132,7 +132,7 @@ def searchposts(v):
elif sort == "old":
posts = posts.order_by(Submission.created_utc.asc())
elif sort == "controversial":
posts = posts.order_by(-1 * Submission.upvotes * (Submission.downvotes+1))
posts = posts.order_by(-1 * Submission.upvotes * Submission.downvotes * Submission.downvotes)
elif sort == "top":
posts = posts.order_by(Submission.downvotes - Submission.upvotes)
elif sort == "bottom":
@ -185,7 +185,7 @@ def searchcomments(v):
try: page = max(1, int(request.values.get("page", 1)))
except: page = 1
sort = request.values.get("sort", "top").lower()
sort = request.values.get("sort", "new").lower()
t = request.values.get('t', 'all').lower()
criteria=searchparse(query)
@ -203,6 +203,10 @@ def searchcomments(v):
words=tuple(words)
comments=comments.filter(*words)
if 'over18' in criteria: comments = comments.filter(Comment.over_18==True)
if 'author' in criteria: comments = comments.filter(Comment.author_id == get_user(criteria['author']).id)
if not(v and v.admin_level >= 3):
comments = comments.filter(
Comment.deleted_utc == 0,
@ -231,7 +235,7 @@ def searchcomments(v):
elif sort == "old":
comments = comments.order_by(Comment.created_utc.asc())
elif sort == "controversial":
comments = comments.order_by(-1 * Comment.upvotes * (Comment.downvotes+1))
comments = comments.order_by(-1 * Comment.upvotes * Comment.downvotes * Comment.downvotes)
elif sort == "top":
comments = comments.order_by(Comment.downvotes - Comment.upvotes)
elif sort == "bottom":
@ -262,7 +266,7 @@ def searchusers(v):
query = request.values.get("q", '').strip()
page = max(1, int(request.values.get("page", 1)))
sort = request.values.get("sort", "top").lower()
sort = request.values.get("sort", "new").lower()
t = request.values.get('t', 'all').lower()
term=query.lstrip('@')
term=term.replace('\\','')
@ -275,7 +279,7 @@ def searchusers(v):
total=users.count()
users=[x for x in users.offset(25 * (page-1)).limit(26)]
next_exists=(len(users)==26)
next_exists=(len(users)>25)
users=users[:25]

54
files/routes/settings.py 100644 → 100755
View File

@ -135,8 +135,6 @@ def settings_profile_post(v):
if ban.reason:
reason += f" {ban.reason}"
if any([x.reason==4 for x in bans]):
v.ban(days=30, reason="Digitally malicious content is not allowed.")
return {"error": reason}, 401
if len(bio_html) > 10000: abort(400)
@ -149,22 +147,6 @@ def settings_profile_post(v):
v=v,
msg="Your bio has been updated.")
if request.values.get("filters"):
filters=request.values.get("filters")[:1000].strip()
if filters==v.custom_filter_list:
return render_template("settings_profile.html",
v=v,
error="You didn't change anything")
v.custom_filter_list=filters
g.db.add(v)
g.db.commit()
return render_template("settings_profile.html",
v=v,
msg="Your custom filters have been updated.")
frontsize = request.values.get("frontsize")
@ -199,9 +181,7 @@ def settings_profile_post(v):
theme = request.values.get("theme")
if theme:
v.theme = theme
if theme == "coffee" or theme == "4chan": v.themecolor = "38a169"
elif theme == "tron": v.themecolor = "80ffff"
elif theme == "win98": v.themecolor = "30409f"
if theme == "win98": v.themecolor = "30409f"
updated = True
quadrant = request.values.get("quadrant")
@ -247,6 +227,19 @@ def settings_profile_post(v):
else:
return {"error": "You didn't change anything."}, 400
@app.post("/settings/filters")
@auth_required
def filters(v):
filters=request.values.get("filters")[:1000].strip()
if filters == v.custom_filter_list: return render_template("settings_filters.html", v=v, error="You didn't change anything")
v.custom_filter_list=filters
g.db.add(v)
g.db.commit()
return render_template("settings_filters.html", v=v, msg="Your custom filters have been updated.")
@app.post("/changelogsub")
@auth_required
@validate_formkey
@ -291,7 +284,7 @@ def themecolor(v):
@auth_required
@validate_formkey
def gumroad(v):
if 'rdrama' in request.host: patron = 'Paypig'
if 'rama' in request.host: patron = 'Paypig'
else: patron = 'Patron'
if not (v.email and v.is_activated): return {"error": f"You must have a verified email to verify {patron} status and claim your rewards"}, 400
@ -318,23 +311,24 @@ def gumroad(v):
grant_awards["fireflies"] = 1
elif tier == 2:
if v.discord_id: add_role(v, "2")
grant_awards["shit"] = 3
grant_awards["fireflies"] = 3
grant_awards["shit"] = 2
grant_awards["fireflies"] = 2
grant_awards["ban"] = 1
elif tier == 3:
if v.discord_id: add_role(v, "3")
grant_awards["shit"] = 5
grant_awards["fireflies"] = 5
grant_awards["ban"] = 1
grant_awards["ban"] = 2
elif tier == 4:
if v.discord_id: add_role(v, "4")
grant_awards["shit"] = 10
grant_awards["fireflies"] = 10
grant_awards["ban"] = 3
grant_awards["ban"] = 5
elif tier == 5 or tier == 8:
if v.discord_id: add_role(v, "5")
grant_awards["shit"] = 20
grant_awards["fireflies"] = 20
grant_awards["ban"] = 6
grant_awards["ban"] = 10
thing = g.db.query(AwardRelationship).order_by(AwardRelationship.id.desc()).first().id
@ -484,7 +478,7 @@ def settings_security_post(v):
@validate_formkey
def settings_log_out_others(v):
submitted_password = request.values.get("password", "")
submitted_password = request.values.get("password", "").strip()
if not v.verifyPass(submitted_password): return render_template("settings_security.html", v=v, error="Incorrect Password"), 401
@ -596,7 +590,7 @@ def settings_css_get(v):
@limiter.limit("1/second")
@auth_required
def settings_css(v):
css = request.values.get("css").replace('\\', '')[:50000]
css = request.values.get("css").strip().replace('\\', '').strip()[:4000]
if not v.agendaposter:
v.css = css
@ -619,7 +613,7 @@ def settings_profilecss_get(v):
@auth_required
def settings_profilecss(v):
if v.coins < 1000 and not v.patron: return f"You must have +1000 {COINS_NAME} or be a patron to set profile css."
profilecss = request.values.get("profilecss").replace('\\', '')[:50000]
profilecss = request.values.get("profilecss").strip().replace('\\', '').strip()[:4000]
v.profilecss = profilecss
g.db.add(v)
g.db.commit()

4
files/routes/static.py 100644 → 100755
View File

@ -175,7 +175,7 @@ def log(v):
if v and v.admin_level == 6: actions = g.db.query(ModAction).order_by(ModAction.id.desc()).offset(25 * (page - 1)).limit(26).all()
else: actions=g.db.query(ModAction).filter(ModAction.kind!="shadowban", ModAction.kind!="unshadowban", ModAction.kind!="club", ModAction.kind!="unclub").order_by(ModAction.id.desc()).offset(25*(page-1)).limit(26).all()
next_exists=len(actions)==26
next_exists=len(actions)>25
actions=actions[:25]
return render_template("log.html", v=v, actions=actions, next_exists=next_exists, page=page)
@ -207,7 +207,7 @@ def log_item(id, v):
@app.get("/assets/favicon.ico")
def favicon():
return send_file(f"./assets/images/{site_name}/icon.webp")
return send_file(f"./assets/images/{site_name}/icon.gif")
@app.get("/api")
@auth_desired

20
files/routes/users.py 100644 → 100755
View File

@ -126,7 +126,7 @@ def transfer_coins(v, username):
if receiver is None: return {"error": "That user doesn't exist."}, 404
if receiver.id != v.id:
amount = request.values.get("amount", "")
amount = request.values.get("amount", "").strip()
amount = int(amount) if amount.isdigit() else None
if amount is None or amount <= 0: return {"error": f"Invalid amount of {app.config['COINS_NAME']}."}, 400
@ -192,7 +192,8 @@ def songs(id):
try: id = int(id)
except: return "", 400
user = g.db.query(User).options(lazyload('*')).filter_by(id=id).first()
return redirect(f"/song/{user.song}.mp3")
if user and user.song: return redirect(f"/song/{user.song}.mp3")
else: abort(404)
@app.get("/song/<song>")
def song(song):
@ -232,7 +233,7 @@ def message2(v, username):
if v.admin_level <= 1:
if hasattr(user, 'is_blocked') and user.is_blocked: return {"error": "This user is blocking you."}, 403
message = request.values.get("message", "")[:1000].strip()
message = request.values.get("message", "").strip()[:1000].strip()
existing = g.db.query(Comment).options(lazyload('*')).filter(Comment.author_id == v.id,
Comment.sentto == user.id,
@ -289,7 +290,7 @@ def message2(v, username):
@auth_required
def messagereply(v):
message = request.values.get("body", "")[:1000].strip()
message = request.values.get("body", "").strip()[:1000].strip()
id = int(request.values.get("parent_id"))
parent = get_comment(id, v=v)
user = parent.author
@ -572,7 +573,7 @@ def u_username_comments(username, v=None):
elif sort == "old":
comments = comments.order_by(Comment.created_utc.asc())
elif sort == "controversial":
comments = comments.order_by(-1 * Comment.upvotes * (Comment.downvotes+1))
comments = comments.order_by(-1 * Comment.upvotes * Comment.downvotes * Comment.downvotes)
elif sort == "top":
comments = comments.order_by(Comment.downvotes - Comment.upvotes)
elif sort == "bottom":
@ -700,7 +701,7 @@ def saved_posts(v, username):
ids=v.saved_idlist(page=page)
next_exists=len(ids)==26
next_exists=len(ids)>25
ids=ids[:25]
@ -722,9 +723,12 @@ def saved_comments(v, username):
page=int(request.values.get("page",1))
ids=v.saved_comment_idlist(page=page)
firstrange = 25 * (page - 1)
secondrange = firstrange+26
next_exists=len(ids)==26
ids=v.saved_comment_idlist()[firstrange:secondrange]
next_exists=len(ids) > 25
ids=ids[:25]

11
files/routes/votes.py 100644 → 100755
View File

@ -25,27 +25,26 @@ def admin_vote_info_get(v):
ups = g.db.query(Vote
).options(joinedload(Vote.user)
).filter_by(submission_id=thing.id, vote_type=1
).all()
).order_by(Vote.id).all()
downs = g.db.query(Vote
).options(joinedload(Vote.user)
).filter_by(submission_id=thing.id, vote_type=-1
).all()
).order_by(Vote.id).all()
elif isinstance(thing, Comment):
ups = g.db.query(CommentVote
).options(joinedload(CommentVote.user)
).filter_by(comment_id=thing.id, vote_type=1
).all()
).order_by(CommentVote.id).all()
downs = g.db.query(CommentVote
).options(joinedload(CommentVote.user)
).filter_by(comment_id=thing.id, vote_type=-1
).all()
).order_by(CommentVote.id).all()
else:
abort(400)
else: abort(400)
return render_template("votes.html",
v=v,

View File

@ -28,7 +28,6 @@
<h4>Safety</h4>
<ul>
<li><a href="/admin/banned_domains">Banned Domains</a></li>
<li><a href="/admin/image_ban">Perceptive Hash Image Ban</a></li>
<li><a href="/admin/alt_votes">Multi Vote Analysis</a></li>
</ul>

View File

2
files/templates/admin/app.html 100644 → 100755
View File

@ -63,7 +63,7 @@
</div>
<div class="toast" id="toast-post-error" style="position: fixed; bottom: 1.5rem; margin: 0 auto; left: 0; right: 0; width: 275px; z-index: 1000" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body bg-danger text-center text-white">
<i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text"></span>
<i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text">Error, please try again later.</span>
</div>
</div>

2
files/templates/admin/apps.html 100644 → 100755
View File

@ -63,7 +63,7 @@
</div>
<div class="toast" id="toast-post-error" style="position: fixed; bottom: 1.5rem; margin: 0 auto; left: 0; right: 0; width: 275px; z-index: 1000" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body bg-danger text-center text-white">
<i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text"></span>
<i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text">Error, please try again later.</span>
</div>
</div>

View File

View File

@ -30,8 +30,8 @@
<form action="/admin/banned_domains" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input name="domain" placeholder="Enter domain here.." class="form-control" required>
<input name="reason" placeholder="Enter ban reason here.." class="form-control">
<input id="ban-submit" type="submit" class="btn btn-primary" value="Toggle ban">
<input name="reason" placeholder="Enter ban reason here.." onchange="document.getElementById('ban-submit').disabled=false" class="form-control">
<input id="ban-submit" type="submit" class="btn btn-primary" value="Toggle ban" disabled>
</form>
{% endblock %}

View File

View File

@ -1,42 +0,0 @@
{% extends "default.html" %}
{% block title %}
<title>Image Ban</title>
<meta name="description" content="Image Ban">
{% endblock %}
{% block content %}
{% if existing %}
<p class="text-danger">Image already banned for: {{existing.ban_reason}}</p>
{% elif success %}
<p class="text-success">Image banned.</p>
{% endif %}
<pre>
</pre>
<h5>Perceptive Hash Image Ban</h5>
<p>Upload an image to add its hash to the ban list.</p>
<form action="/admin/image_ban" method="post" class="mb-6" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<label for="img-input">Image Upload</label>
<input id="img-input" type="file" class="form-control-file mb-2" name="file">
<label for="img-input" class="mt-3">Ban Reason</label>
<select name="ban_reason" class="form-control" id="ban_reason">
<option disabled selected>Select Ban Reason</option>
<option value="Bestiality">Bestiality</option>
<option value="Child Sexual Abuse Material">CSAM</option>
<option value="Involuntary Pornography">Involuntary Pornography</option>
</select>
<label for="time-input" class="mt-3">Penalty</label>
<small>Enter the number of days to ban a user who attempts to upload this image</small>
<input id="time-input" class="form-control" type="text" name="ban_length" placeholder="Enter 0 for permanent ban" required>
<input type="submit" value="Ban Image" class="btn btn-primary mt-3">
</form>
{% endblock %}

View File

View File

View File

View File

View File

0
files/templates/admin/rules.html 100644 → 100755
View File

View File

0
files/templates/admins.html 100644 → 100755
View File

6
files/templates/api.html 100644 → 100755
View File

@ -6,8 +6,6 @@
{% endblock %}
{% block content %}
<img class="in-comment-image rounded-sm my-2" data-src="https://media.giphy.com/media/c6Wwc9cT05vMdhyTcM/giphy.webp" loading="lazy" height="100px" rel="nofollow noopener noreferrer" data-placeholder-background="red" style="max-height: 100px; max-width: 100%;">
<pre>
@ -30,7 +28,7 @@
<p>Python example:</p>
<pre> import requests
headers={"Authorization": "access_token_goes_here", "User-Agent": "sex"}
headers={"Authorization": "access_token_goes_here"}
url="https://rdrama.net/@carpathianflorist"
@ -72,7 +70,7 @@
<p>Python example:</p>
<pre> import requests
headers={"Authorization": "access_token_goes_here", "User-Agent": "sex"}
headers={"Authorization": "access_token_goes_here"}
url="https://rdrama.net/@carpathianflorist"

10
files/templates/authforms.html 100644 → 100755
View File

@ -14,10 +14,12 @@
{% if v %}
<link rel="stylesheet" href="/assets/css/{{v.theme}}_{{v.themecolor}}.css?v=61">
{% if v.agendaposter %}<link rel="stylesheet" href="/assets/css/agendaposter.css?v=61">{% endif %}
<style>:root{--primary:#{{v.themecolor}}}</style>
<link rel="stylesheet" href="/assets/css/main.css?v=80"><link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=80">
{% if v.agendaposter %}<link rel="stylesheet" href="/assets/css/agendaposter.css?v=80">{% elif v.css %}<link rel="stylesheet" href="/@{{v.username}}/css">{% endif %}
{% else %}
<link rel="stylesheet" href="/assets/css/{{'DEFAULT_THEME' | app_config}}.css?v=61">
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
<link rel="stylesheet" href="/assets/css/main.css?v=80"><link rel="stylesheet" href="/assets/css/{{'DEFAULT_THEME' | app_config}}.css?v=80">
{% endif %}
</head>
@ -89,7 +91,7 @@
<div class="splash-overlay"></div>
<img loading="lazy" class="splash-img" src="/assets/images/{{'SITE_NAME' | app_config}}/cover.webp"></img>
<img loading="lazy" class="splash-img" src="/assets/images/{{'SITE_NAME' | app_config}}/cover.gif"></img>
</div>
</div>

2
files/templates/award_modal.html 100644 → 100755
View File

@ -1,4 +1,4 @@
<script src="/assets/js/award_modal.js?v=50"></script>
<script src="/assets/js/award_modal.js?v=53"></script>
<div class="modal fade" id="awardModal" tabindex="-1" role="dialog" aria-labelledby="awardModalTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable modal-dialog-centered" role="document">

6
files/templates/badges.html 100644 → 100755
View File

@ -22,7 +22,7 @@
{% for badge in badges if badge.kind==1 %}
<tr>
<td>{{badge.name}}</td>
<td><img loading="lazy" src="{{badge.path}}" style="width:50px;height:50px">
<td><img loading="lazy" src="{{badge.path}}" width=50 height=50>
<td>{{badge.description}}</td>
</tr>
{% endfor %}
@ -43,7 +43,7 @@
{% for badge in badges if badge.kind==3 %}
<tr>
<td>{{badge.name}}</td>
<td><img loading="lazy" src="{{badge.path}}" style="width:50px;height:50px">
<td><img loading="lazy" src="{{badge.path}}" width=50 height=50>
<td>{{badge.description}}</td>
</tr>
{% endfor %}
@ -63,7 +63,7 @@
{% for badge in badges if badge.kind==4 %}
<tr>
<td>{{badge.name}}</td>
<td><img loading="lazy" src="{{badge.path}}" style="width:50px;height:50px">
<td><img loading="lazy" src="{{badge.path}}" width=50 height=50>
<td>{{badge.description}}</td>
</tr>
{% endfor %}

0
files/templates/ban_modal.html 100644 → 100755
View File

0
files/templates/banned.html 100644 → 100755
View File

0
files/templates/blocks.html 100644 → 100755
View File

2
files/templates/changelog.html 100644 → 100755
View File

@ -3,7 +3,7 @@
{% block pagetitle %}Changelog{% endblock %}
{% block desktopBanner %}
<script src="/assets/js/changelog.js?v=50"></script>
<script src="/assets/js/changelog.js?v=54"></script>
<div class="row" style="overflow: visible;padding-top:5px;">
<div class="col">

View File

@ -30,10 +30,10 @@
<div class="comment-format">
<small class="format pl-0"><i class="fas fa-bold" aria-hidden="true" onclick="makeReplyBold()" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Bold"></i></small>
<small class="format"><i class="fas fa-italic" aria-hidden="true" onclick="makeReplyItalics()" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Italicize"></i></small>
<small class="format"><i class="fas fa-quote-right" aria-hidden="true" onclick="makeReplyQuote()" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Quote"></i></small>
<small class="format"><i class="fas fa-link" aria-hidden="true"></i></small>
<button form="reply" class="btn btn-primary ml-auto">Comment</button>
<a class="format" href="javscript:void(0)"><i class="fas fa-italic" aria-hidden="true" onclick="makeReplyItalics()" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Italicize"></i></a>
<a class="format" href="javscript:void(0)"><i class="fas fa-quote-right" aria-hidden="true" onclick="makeReplyQuote()" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Quote"></i></a>
<a class="format" href="javscript:void(0)"><i class="fas fa-link" aria-hidden="true"></i></small>
<button form="reply" class="btn btn-primary ml-auto">Comment</a>
</div>
</form>
</div>

66
files/templates/comments.html 100644 → 100755
View File

@ -18,29 +18,22 @@
padding-top: 75px;
}
.comment-anchor:target {
animation: highlight 2s!important;
}
@keyframes highlight {
0% {
background: rgba(255,255,255,0.6);
}
100% {
background: none;
}
background: rgba(255,255,255,0.2);
padding: 12px;
}
</style>
{% if v %}
{% include "award_modal.html" %}
<script src="/assets/js/comments_v.js?v=50"></script>
<script src="/assets/js/comments_v.js?v=57"></script>
{% endif %}
<script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js"></script>
{% if v and v.admin_level == 6 %}
<script src="/assets/js/comments_admin.js?v=50"></script>
<script src="/assets/js/comments_admin.js?v=53"></script>
{% endif %}
<script>
@ -100,7 +93,7 @@
<script>
(() => {
const date = new Date('{{c.created_datetime}}');
const date = new Date({{c.created_utc*1000}});
document.getElementById('timestamp-{{c.id}}').title = date.toString();
})()
</script>
@ -109,7 +102,7 @@
{% set downs=c.downvotes %}
{% set score=ups-downs %}
{% if v and v.shadowbanned %}
{% if v and (v.shadowbanned or v.admin_level == 6) %}
{% set replies=c.replies3 %}
{% else %}
{% set replies=c.replies %}
@ -156,7 +149,7 @@
{% endfor %}
</div>
<div id="morecomment-{{c.id}}" class="d-md-none mt-2 more-comments text-small">
<a {% if v %}href="{{c.permalink}}?context=5#context"{% else %}href="/logged_out{{c.permalink}}?context=5#context"{% endif %}>More comments <i class="fas fa-long-arrow-right ml-1"></i></a>
<a {% if v %}href="{{c.permalink}}?context=10#context"{% else %}href="/logged_out{{c.permalink}}?context=10#context"{% endif %}>More comments <i class="fas fa-long-arrow-right ml-1"></i></a>
</div>
{% endif %}
{% endif %}
@ -201,7 +194,7 @@
</div>
{% endif %}
<div id="comment-{{c.id}}" class="anchor {% if c.unread %}context{% endif %} comment {% if standalone and level==1 %} mt-0{% endif %}{% if c.collapse_for_user(v) or (standalone and c.over_18 and not (v and v.over_18)) %} collapsed{% endif %}" style="border-left: 2px solid #{{c.author.namecolor}}; {% if c.unread %}padding: 10px 10px 10px !important;{% endif %}">
<div id="comment-{{c.id}}" class="anchor {% if c.unread %}unread{% endif %} comment {% if standalone and level==1 %} mt-0{% endif %}{% if c.collapse_for_user(v) or (standalone and c.over_18 and not (v and v.over_18)) %} collapsed{% endif %}" style="border-left: 2px solid #{{c.author.namecolor}}; {% if c.unread %}padding: 10px 10px 10px !important;{% endif %}">
<span class="comment-collapse-desktop d-none d-md-block" {% if not c.unread %}style="border-left: 2px solid #{{c.author.namecolor}};"{% endif %} onclick="collapse_comment('{{c.id}}')"></span>
<div class="comment-body">
@ -235,8 +228,8 @@
{% if c.author.verified %}<i class="fas fa-badge-check align-middle ml-1" style="color:{% if c.author.id == 541 %}#62ca56{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="{{c.author.verified}}"></i>
{% endif %}
<a {% if v %}href="{{c.author.url}}"{% else %}href="/logged_out{{c.author.url}}"{% endif %} style="color:#{{c.author.namecolor}}; font-size:12px; font-weight:bold;"><img loading="lazy" src="{{c.author.profile_url}}" class="profile-pic-25 mr-2"/><span {% if c.author.patron and not c.distinguish_level %}class="patron" style="background-color:#{{c.author.namecolor}};"{% elif c.distinguish_level and 'rdrama' in request.host %}class="mod"{% endif %}>{{c.author.username}}</span></a>
{% if c.author.customtitle %}&nbsp;<bdi style="color: #{{c.author.titlecolor}}">&nbsp;{% if c.author.quadrant %}<img loading="lazy" height="20" src="/assets/images/PCM/quadrants/{{c.author.quadrant}}.webp">{% endif %}{{c.author.customtitle | safe}}</bdi>{% endif %}
<a {% if v %}href="{{c.author.url}}"{% else %}href="/logged_out{{c.author.url}}"{% endif %} style="color:#{{c.author.namecolor}}; font-size:12px; font-weight:bold;"><img loading="lazy" src="{{c.author.profile_url}}" class="profile-pic-25 mr-2"/><span {% if c.author.patron and not c.distinguish_level %}class="patron" style="background-color:#{{c.author.namecolor}};"{% elif c.distinguish_level and 'rama' in request.host %}class="mod"{% endif %}>{{c.author.username}}</span></a>
{% if c.author.customtitle %}&nbsp;<bdi style="color: #{{c.author.titlecolor}}">&nbsp;{% if c.author.quadrant %}<img loading="lazy" height="20" src="/assets/images/PCM/quadrants/{{c.author.quadrant}}.gif">{% endif %}{{c.author.customtitle | safe}}</bdi>{% endif %}
{% if c.parent_comment_id and not standalone and level<=7 %}<a href="#comment-{{ c.parent_comment_id }}-only" class="text-muted ml-2"><i class="fas fa-reply fa-sm fa-fw fa-flip-horizontal mr-1"></i>{{ c.parent_comment.author.username }}</a>{% endif %}
@ -268,7 +261,7 @@
{% for c in c.options %}
<div class="custom-control">
<input type="checkbox" class="custom-control-input" id="{{c.id}}" name="option" {% if c.poll_voted(v) %}checked{% endif %} onchange="poll_vote('{{c.id}}')">
<label class="custom-control-label" for="{{c.id}}">{{c.body}} - <a href="/votes?link=t3_{{c.id}}"><span id="poll-{{c.id}}">{{c.upvotes}}</span> votes</a></label>
<label class="custom-control-label" for="{{c.id}}">{{c.body_html | safe}} - <a href="/votes?link=t3_{{c.id}}"><span id="poll-{{c.id}}">{{c.upvotes}}</span> votes</a></label>
</div>
{% endfor %}
<pre></pre>
@ -288,7 +281,7 @@
</label>
&nbsp;
<a href="javascript:void(0)" onclick="document.getElementById('reply-m-{{c.id}}').classList.add('d-none')" class="d-none d-md-block btn btn-link text-muted ml-auto cancel-form">Cancel</a>
<a id="save-reply-to-{{c.id}}" class="d-none d-md-block btn btn-primary text-white ml-2" onclick="post_reply('{{c.id}}');" href="javascript:void(0)">Reply</a>
<a id="save-reply-to-{{c.id}}" class="d-none d-md-block btn btn-primary text-muted ml-2" onclick="post_reply('{{c.id}}');" href="javascript:void(0)">Reply</a>
</div>
<a href="javascript:void(0)" onclick="document.getElementById('reply-m-{{c.id}}').classList.add('d-none')" class="d-md-none btn btn-link text-muted ml-auto cancel-form">Cancel</a>
<a id="save-reply-to-{{c.id}}" class="d-md-none btn btn-primary text-white ml-2" onclick="post_reply('{{c.id}}');" href="javascript:void(0)">Reply</a>
@ -362,15 +355,15 @@
<a class="list-inline-item text-muted d-none d-md-inline-block" href="javascript:void(0)" data-bs-toggle="modal" data-bs-target="#awardModal" onclick="awardModal('/comment/{{c.id}}/awards')"><i class="fas fa-gift" aria-hidden="true"></i>Give Award</a>
{% endif %}
<a id="unsave-{{c.id}}" class="{% if c in v.saved_comment_idlist() %}d-md-inline-block{% endif %} list-inline-item text-muted d-none" href="javascript:void(0)" onclick="post_toast3('/unsave_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}')"><i class="fas fa-save"></i>Unsave</a>
<a id="unsave-{{c.id}}" class="{% if c.id in v.saved_comment_idlist() %}d-md-inline-block{% endif %} list-inline-item text-muted d-none" href="javascript:void(0)" onclick="post_toast3('/unsave_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}')"><i class="fas fa-save"></i>Unsave</a>
<a id="save-{{c.id}}" class="{% if c not in v.saved_comment_idlist() %}d-md-inline-block{% endif %} list-inline-item text-muted d-none" href="javascript:void(0)" onclick="post_toast3('/save_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}')"><i class="fas fa-save"></i>Save</a>
<a id="save-{{c.id}}" class="{% if c.id not in v.saved_comment_idlist() %}d-md-inline-block{% endif %} list-inline-item text-muted d-none" href="javascript:void(0)" onclick="post_toast3('/save_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}')"><i class="fas fa-save"></i>Save</a>
<a class="list-inline-item text-muted" href="javascript:void(0)" onclick="openReplyBox('{{c.id}}')"><i class="fas fa-reply" aria-hidden="true"></i><span class="d-none d-md-inline-block">Reply</span></a>
{% endif %}
<a class="list-inline-item text-muted d-none d-md-inline-block" {% if v %}href="{{c.permalink}}?context=5#context"{% else %}href="/logged_out{{c.permalink}}?context=5#context"{% endif %}><i class="fas fa-book-open"></i>Context</a>
<a class="list-inline-item text-muted d-none d-md-inline-block copy-link" href="javascript:void(0);" role="button" data-clipboard-text="{% if 'rdrama' in request.host %}https://taytay.life{{c.permalink}}{% else %}{{c.permalink | full_link}}{% endif %}/?context=5#context"><i class="fas fa-copy"></i>Copy link</a>
<a class="list-inline-item text-muted d-none d-md-inline-block" {% if v %}href="{{c.permalink}}?context=10#context"{% else %}href="/logged_out{{c.permalink}}?context=10#context"{% endif %}><i class="fas fa-book-open"></i>Context</a>
<a class="list-inline-item text-muted d-none d-md-inline-block copy-link" href="javascript:void(0);" role="button" data-clipboard-text="{% if 'rama' in request.host %}https://dogpill.life{{c.permalink}}{% else %}{{c.permalink | full_link}}{% endif %}?context=10#context"><i class="fas fa-copy"></i>Copy link</a>
{% if v %}
<a class="list-inline-item text-muted d-none d-md-inline-block" href="javascript:void(0)" data-bs-toggle="modal" data-bs-target="#reportCommentModal" onclick="report_commentModal('{{c.id}}','{{c.author.username}}',)"><i class="fas fa-flag fa-fw"></i>Report</a>
{% endif %}
@ -432,19 +425,19 @@
{% if v and request.path.startswith('/@') and v.admin_level == 0 %}
{% if voted==1 %}<li class="list-inline-item arrow-up d-inline-block d-md-none mr-2 comment-{{c.id}}-up active"></li>{% endif %}
{% elif v %}
<li id="comment-mobile-{{c.id}}-up" tabindex="0" href="javascript:void(0)" onclick="vote('comment-mobile', '{{c.id}}', '1')" class="list-inline-item arrow-up upvote-button d-inline-block d-md-none mr-2 comment-{{c.id}}-up {% if voted==1 %}active{% endif %}"></li>
<li id="comment-mobile-{{c.id}}-up" tabindex="0" href="javascript:void(0)" onclick="vote('comment-mobile', '{{c.id}}', '1')" class="list-inline-item arrow-up upvote-button d-inline-block d-md-none mx-0 pr-1 comment-{{c.id}}-up {% if voted==1 %}active{% endif %}"></li>
{% else %}
<li id="comment-{{c.id}}-up" tabindex="0" href="javascript:void(0)" onclick="vote('comment', '{{c.id}}', '1')" class="list-inline-item arrow-up d-inline-block d-md-none mr-2" onclick="location.href='/login';"></li>
<li id="comment-{{c.id}}-up" tabindex="0" href="javascript:void(0)" onclick="vote('comment', '{{c.id}}', '1')" class="list-inline-item arrow-up d-inline-block d-md-none mx-0 pr-1" onclick="location.href='/login';"></li>
{% endif %}
<li class="list-inline-item d-inline-block d-md-none mr-2"><span class="points" data-bs-toggle="tooltip" data-bs-placement="top" title="" data-bs-original-title="+{{ups}} | -{{downs}}"><span id="comment-mobile-score-{{c.id}}" class="score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}">{{score}}</span></span></li>
<li class="list-inline-item d-inline-block d-md-none mx-0"><span class="points" data-bs-toggle="tooltip" data-bs-placement="top" title="" data-bs-original-title="+{{ups}} | -{{downs}}"><span id="comment-mobile-score-{{c.id}}" class="score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}">{{score}}</span></span></li>
{% if v and request.path.startswith('/@') and v.admin_level == 0 %}
{% if voted==-1 %}
<li class="list-inline-item arrow-down d-inline-block d-md-none mr-2 comment-{{c.id}}-up active"></li>
{% endif %}
{% elif v %}
<li {% if environ.get('DISABLE_DOWNVOTES') == '1' %}style="display:None!important"{% endif %} id="comment-mobile-{{c.id}}-down" tabindex="0" href="javascript:void(0)" onclick="vote('comment-mobile', '{{c.id}}', '-1')" class="list-inline-item arrow-down downvote-button d-inline-block d-md-none mr-2 comment-{{c.id}}-down {% if voted==-1 %}active{% endif %}"></li>
<li {% if environ.get('DISABLE_DOWNVOTES') == '1' %}style="display:None!important"{% endif %} id="comment-mobile-{{c.id}}-down" tabindex="0" href="javascript:void(0)" onclick="vote('comment-mobile', '{{c.id}}', '-1')" class="list-inline-item arrow-down downvote-button d-inline-block d-md-none mx-0 pl-1 comment-{{c.id}}-down {% if voted==-1 %}active{% endif %}"></li>
{% else %}
<li {% if environ.get('DISABLE_DOWNVOTES') == '1' %}style="display:None!important"{% endif %} id="comment-{{c.id}}-down" tabindex="0" href="javascript:void(0)" onclick="vote('comment', '{{c.id}}', '-1')" class="list-inline-item arrow-down d-inline-block d-md-none" onclick="location.href='/login';"></li>
<li {% if environ.get('DISABLE_DOWNVOTES') == '1' %}style="display:None!important"{% endif %} id="comment-{{c.id}}-down" tabindex="0" href="javascript:void(0)" onclick="vote('comment', '{{c.id}}', '-1')" class="list-inline-item arrow-down mx-0 pl-1 d-inline-block d-md-none" onclick="location.href='/login';"></li>
{% endif %}
</ul>
</div>
@ -472,7 +465,7 @@
<input id="file-upload-reply-{{c.fullname}}" type="file" name="file" accept="image/*" onchange="document.getElementById('filename-show-reply-{{c.id}}').innerHTML='image';" hidden>
</label>
<a href="javascript:void(0)" onclick="document.getElementById('reply-to-{{c.id}}').classList.add('d-none')" class="d-none d-md-block btn btn-link text-muted ml-auto cancel-form">Cancel</a>
<a id="save-reply-to-{{c.fullname}}" class="d-none d-md-block btn btn-primary text-white ml-2" onclick="post_comment('{{c.fullname}}', '{{c.post.id}}');" href="javascript:void(0)">Comment</a>
<a id="save-reply-to-{{c.fullname}}" class="d-none d-md-block btn btn-primary text-muted ml-2" onclick="post_comment('{{c.fullname}}', '{{c.post.id}}');" href="javascript:void(0)">Comment</a>
</div>
<a href="javascript:void(0)" onclick="document.getElementById('reply-to-{{c.id}}').classList.add('d-none')" class="d-md-none btn btn-link text-muted ml-auto cancel-form">Cancel</a>
<a id="save-reply-to-{{c.fullname}}" class="d-md-none btn btn-primary text-white ml-2" onclick="post_comment('{{c.fullname}}', '{{c.post.id}}');" href="javascript:void(0)">Comment</a>
@ -525,9 +518,9 @@
<a id="unsave2-{{c.id}}" class="list-group-item {% if c.id not in v.saved_comment_idlist() %}d-none{% endif %}" href="javascript:void(0)" onclick="post_toast2('/unsave_comment/{{c.id}}','save2-{{c.id}}','unsave2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-save"></i>Unsave</a>
{% endif %}
<a href="javascript:void(0);" role="button" class="list-group-item copy-link" data-bs-dismiss="modal" data-clipboard-text="{% if 'rdrama' in request.host %}https://taytay.life{{c.permalink}}{% else %}{{c.permalink | full_link}}{% endif %}?context=5#context"><i class="fas fa-copy"></i>Copy link</a>
<a href="javascript:void(0);" role="button" class="list-group-item copy-link" data-bs-dismiss="modal" data-clipboard-text="{% if 'rama' in request.host %}https://dogpill.life{{c.permalink}}{% else %}{{c.permalink | full_link}}{% endif %}?context=10#context"><i class="fas fa-copy"></i>Copy link</a>
<a class="list-group-item" {% if v %} href="{{c.permalink}}?context=5#context" {% else %} href="/logged_out{{c.permalink}}?context=5#context" {% endif %}><i class="fas fa-dna"></i>Context</a>
<a class="list-group-item" {% if v %} href="{{c.permalink}}?context=10#context" {% else %} href="/logged_out{{c.permalink}}?context=10#context" {% endif %}><i class="fas fa-dna"></i>Context</a>
<a href="javascript:void(0)" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#reportCommentModal" onclick="report_commentModal('{{c.id}}','{{c.author.username}}')" class="list-group-item"><i class="fas fa-flag"></i>Report</a>
@ -600,17 +593,6 @@
{% endfor %}
<div class="toast" id="toast-comment-success" style="position: fixed; bottom: 1.5rem; margin: 0 auto; left: 0; right: 0; width: 275px; z-index: 1000" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body bg-success text-center text-white">
<i class="fas fa-comment-alt-smile mr-2"></i>Comment posted!
</div>
</div>
<div class="toast" id="toast-comment-error" style="position: fixed; bottom: 1.5rem; margin: 0 auto; left: 0; right: 0; width: 275px; z-index: 1000" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body bg-danger text-center text-white">
<i class="fas fa-exclamation-circle mr-2"></i><span id="comment-error-text"></span>
</div>
</div>
{% if v %}
{% include "gif_modal.html" %}
{% include "emoji_modal.html" %}

0
files/templates/contact.html 100644 → 100755
View File

101
files/templates/default.html 100644 → 100755
View File

@ -1,13 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="/assets/js/lozad.js?v=50"></script>
<script src="/assets/js/lozad.js?v=53"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"></script>
{% if v and v.agendaposter %}
<script>
var BugDispatch={options:{minDelay:500,maxDelay:1E4,minBugs:2,maxBugs:20,minSpeed:5,maxSpeed:10,maxLargeTurnDeg:150,maxSmallTurnDeg:10,maxWiggleDeg:5,imageSprite:"fly-sprite.webp",bugWidth:13,bugHeight:14,num_frames:5,zoom:10,canFly:!0,canDie:!0,numDeathTypes:3,monitorMouseMovement:!1,eventDistanceToBug:40,minTimeBetweenMultipy:1E3,mouseOver:"random"},initialize:function(a){this.options=mergeOptions(this.options,a);this.options.minBugs>this.options.maxBugs&&(this.options.minBugs=this.options.maxBugs);
var BugDispatch={options:{minDelay:500,maxDelay:1E4,minBugs:2,maxBugs:20,minSpeed:5,maxSpeed:10,maxLargeTurnDeg:150,maxSmallTurnDeg:10,maxWiggleDeg:5,imageSprite:"fly-sprite.gif",bugWidth:13,bugHeight:14,num_frames:5,zoom:10,canFly:!0,canDie:!0,numDeathTypes:3,monitorMouseMovement:!1,eventDistanceToBug:40,minTimeBetweenMultipy:1E3,mouseOver:"random"},initialize:function(a){this.options=mergeOptions(this.options,a);this.options.minBugs>this.options.maxBugs&&(this.options.minBugs=this.options.maxBugs);
this.modes=["multiply","nothing"];this.options.canFly&&this.modes.push("fly","flyoff");this.options.canDie&&this.modes.push("die");-1==this.modes.indexOf(this.options.mouseOver)&&(this.options.mouseOver="random");this.transform=null;this.transforms={Moz:function(a){this.bug.style.MozTransform=a},webkit:function(a){this.bug.style.webkitTransform=a},O:function(a){this.bug.style.OTransform=a},ms:function(a){this.bug.style.msTransform=a},Khtml:function(a){this.bug.style.KhtmlTransform=a},w3c:function(a){this.bug.style.transform=
a}};if("transform"in document.documentElement.style)this.transform=this.transforms.w3c;else{var b=["Moz","webkit","O","ms","Khtml"],c=0;for(c=0;c<b.length;c++)if(b[c]+"Transform"in document.documentElement.style){this.transform=this.transforms[b[c]];break}}if(this.transform){this.bugs=[];b="multiply"===this.options.mouseOver?this.options.minBugs:this.random(this.options.minBugs,this.options.maxBugs,!0);c=0;var d=this;for(c=0;c<b;c++){a=JSON.parse(JSON.stringify(this.options));var e=SpawnBug();a.wingsOpen=
this.options.canFly?.5<Math.random()?!0:!1:!0;a.walkSpeed=this.random(this.options.minSpeed,this.options.maxSpeed);e.initialize(this.transform,a);this.bugs.push(e)}this.spawnDelay=[];for(c=0;c<b;c++)a=this.random(this.options.minDelay,this.options.maxDelay,!0),e=this.bugs[c],this.spawnDelay[c]=setTimeout(function(a){return function(){d.options.canFly?a.flyIn():a.walkIn()}}(e),a),d.add_events_to_bug(e);this.options.monitorMouseMovement&&(window.onmousemove=function(){d.check_if_mouse_close_to_bug()})}},
@ -16,7 +16,7 @@
a.pageX&&(b=a.pageX-(document.body.scrollLeft+document.documentElement.scrollLeft),c=a.pageY-(document.body.scrollTop+document.documentElement.scrollTop));a=this.bugs.length;var d;for(d=0;d<a;d++){var e=this.bugs[d].getPos();e&&Math.abs(e.top-c)+Math.abs(e.left-b)<this.options.eventDistanceToBug&&!this.bugs[d].flyperiodical&&this.near_bug(this.bugs[d])}}},near_bug:function(a){this.on_bug(a)},on_bug:function(a){if(a.alive){var b=this.options.mouseOver;"random"===b&&(b=this.modes[this.random(0,this.modes.length-
1,!0)]);if("fly"===b)a.stop(),a.flyRand();else if("nothing"!==b)if("flyoff"===b)a.stop(),a.flyOff();else if("die"===b)a.die();else if("multiply"===b&&!this.multiplyDelay&&this.bugs.length<this.options.maxBugs){var c=SpawnBug();b=JSON.parse(JSON.stringify(this.options));var d=a.getPos(),e=this;b.wingsOpen=this.options.canFly?.5<Math.random()?!0:!1:!0;b.walkSpeed=this.random(this.options.minSpeed,this.options.maxSpeed);c.initialize(this.transform,b);c.drawBug(d.top,d.left);b.canFly?(c.flyRand(),a.flyRand()):
(c.go(),a.go());this.bugs.push(c);this.multiplyDelay=!0;setTimeout(function(){e.add_events_to_bug(c);e.multiplyDelay=!1},this.options.minTimeBetweenMultipy)}}},random:function(a,b,c){if(a==b)return c?Math.round(a):a;var d=a-.5+Math.random()*(b-a+1);d>b?d=b:d<a&&(d=a);return c?Math.round(d):d}},BugController=function(){this.initialize.apply(this,arguments)};BugController.prototype=BugDispatch;
var SpiderController=function(){this.options=mergeOptions(this.options,{imageSprite:"spider-sprite.webp",bugWidth:69,bugHeight:90,num_frames:7,canFly:!1,canDie:!0,numDeathTypes:2,zoom:6,minDelay:200,maxDelay:3E3,minSpeed:6,maxSpeed:13,minBugs:3,maxBugs:10});this.initialize.apply(this,arguments)};SpiderController.prototype=BugDispatch;
var SpiderController=function(){this.options=mergeOptions(this.options,{imageSprite:"spider-sprite.gif",bugWidth:69,bugHeight:90,num_frames:7,canFly:!1,canDie:!0,numDeathTypes:2,zoom:6,minDelay:200,maxDelay:3E3,minSpeed:6,maxSpeed:13,minBugs:3,maxBugs:10});this.initialize.apply(this,arguments)};SpiderController.prototype=BugDispatch;
var Bug={options:{wingsOpen:!1,walkSpeed:2,flySpeed:40,edge_resistance:50,zoom:10},initialize:function(a,b){this.options=mergeOptions(this.options,b);this.NEAR_TOP_EDGE=1;this.NEAR_BOTTOM_EDGE=2;this.NEAR_LEFT_EDGE=4;this.NEAR_RIGHT_EDGE=8;this.directions={};this.directions[this.NEAR_TOP_EDGE]=270;this.directions[this.NEAR_BOTTOM_EDGE]=90;this.directions[this.NEAR_LEFT_EDGE]=0;this.directions[this.NEAR_RIGHT_EDGE]=180;this.directions[this.NEAR_TOP_EDGE+this.NEAR_LEFT_EDGE]=315;this.directions[this.NEAR_TOP_EDGE+
this.NEAR_RIGHT_EDGE]=225;this.directions[this.NEAR_BOTTOM_EDGE+this.NEAR_LEFT_EDGE]=45;this.directions[this.NEAR_BOTTOM_EDGE+this.NEAR_RIGHT_EDGE]=135;this.large_turn_angle_deg=this.angle_rad=this.angle_deg=0;this.near_edge=!1;this.edge_test_counter=10;this.fly_counter=this.large_turn_counter=this.small_turn_counter=0;this.toggle_stationary_counter=50*Math.random();this.zoom=this.random(this.options.zoom,10)/10;this.stationary=!1;this.bug=null;this.active=!0;this.wingsOpen=this.options.wingsOpen;
this.transform=a;this.flyIndex=this.walkIndex=0;this.alive=!0;this.twitchTimer=null;this.rad2deg_k=180/Math.PI;this.deg2rad_k=Math.PI/180;this.makeBug();this.angle_rad=this.deg2rad(this.angle_deg);this.angle_deg=this.random(0,360,!0)},go:function(){if(this.transform){this.drawBug();var a=this;this.animating=!0;this.going=requestAnimFrame(function(b){a.animate(b)})}},stop:function(){this.animating=!1;this.going&&(clearTimeout(this.going),this.going=null);this.flyperiodical&&(clearTimeout(this.flyperiodical),
@ -41,14 +41,14 @@
this.bug&&this.bug.style?{top:parseInt(this.bug.top,10),left:parseInt(this.bug.left,10)}:null}},SpawnBug=function(){var a={},b;for(b in Bug)Bug.hasOwnProperty(b)&&(a[b]=Bug[b]);return a},mergeOptions=function(a,b,c){"undefined"==typeof c&&(c=!0);a=c?cloneOf(a):a;for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);return a},cloneOf=function(a){if(null==a||"object"!=typeof a)return a;var b=a.constructor(),c;for(c in a)a.hasOwnProperty(c)&&(b[c]=cloneOf(a[c]));return b};
window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a,b){window.setTimeout(a,1E3/60)}}();
new BugController({
imageSprite: "/assets/images/fly-sprite.webp",
imageSprite: "/assets/images/fly-sprite.gif",
canDie: false,
minBugs: 5,
maxBugs: 30,
mouseOver: "fly"
});
new SpiderController({
imageSprite: "/assets/images/spider-sprite.webp",
imageSprite: "/assets/images/spider-sprite.gif",
canDie: false,
minBugs: 2,
maxBugs: 20,
@ -69,23 +69,23 @@
{% if v %}
<script>function formkey() {return '{{v.formkey}}';}</script>
<script src="/assets/js/default.js?v=50"></script>
<script src="/assets/js/default.js?v=54"></script>
{% endif %}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="thumbnail" content="/assets/images/{{'SITE_NAME' | app_config}}/preview.webp">
<meta name="thumbnail" content="/assets/images/{{'SITE_NAME' | app_config}}/preview.gif">
<link rel="icon" type="image/png" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp">
<link rel="icon" type="image/png" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif">
{% block title %}
<title>{{'SITE_NAME' | app_config}}</title>
<meta property="og:type" content="article" />
<meta property="og:title" content="{{'SITE_NAME' | app_config}}" />
<meta property="og:site_name" content="{{request.host}}" />
<meta property="og:image" content="{{'SITE_NAME' | app_config}}/assets/images/{{'SITE_NAME' | app_config}}/preview.webp" />
<meta property="og:image" content="{{'SITE_NAME' | app_config}}/assets/images/{{'SITE_NAME' | app_config}}/preview.gif" />
<meta property="og:url" content="{{request.path | full_link}}">
<meta property="og:description" name="description" content="{{'SITE_NAME' | app_config}} - {{'SLOGAN' | app_config}}">
<meta property="og:author" name="author" content="@{{request.host_url}}" />
@ -96,7 +96,7 @@
<meta name="twitter:title" content="{{'SITE_NAME' | app_config}}" />
<meta name="twitter:creator" content="@{{request.host_url}}">
<meta name="twitter:description" content="{{'SITE_NAME' | app_config}} - {{'SLOGAN' | app_config}}" />
<meta name="twitter:image" content="/assets/images/{{'SITE_NAME' | app_config}}/preview.webp" />
<meta name="twitter:image" content="/assets/images/{{'SITE_NAME' | app_config}}/preview.gif" />
<meta name="twitter:url" content="{{request.path | full_link}}" />
{% endblock %}
@ -105,12 +105,12 @@
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp">
<!---<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp">--->
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif">
<!---<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif">--->
<link rel="manifest" href="/assets/manifest.json">
<link rel="mask-icon" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp" color="#{{'DEFAULT_COLOR' | app_config}}">
<link rel="shortcut icon" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp">
<link rel="mask-icon" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif" color="#{{'DEFAULT_COLOR' | app_config}}">
<link rel="shortcut icon" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif">
<meta name="apple-mobile-web-app-title" content="{{'SITE_NAME' | app_config}}">
<meta name="application-name" content="{{'SITE_NAME' | app_config}}">
<meta name="msapplication-TileColor" content="#{{'DEFAULT_COLOR' | app_config}}">
@ -122,152 +122,155 @@
<link
rel="apple-touch-startup-image"
sizes="320x480"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="640x960"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-icon"
sizes="640x1136"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-icon"
sizes="750x1334"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="768x1004"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="768x1024"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="828x1792"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1024x748"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1024x768"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1125x2436"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1242x2208"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1242x2688"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1334x750"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1536x2008"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1536x2048"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1668x2224"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="1792x828"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="2048x1496"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="2048x1536"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="2048x2732"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="2208x1242"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="2224x1668"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="2436x1125"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="2668x1242"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
<link
rel="apple-touch-startup-image"
sizes="2737x2048"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.webp"
href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif"
/>
{% block stylesheets %}
{% if v %}
<link rel="stylesheet" href="/assets/css/{{v.theme}}_{{v.themecolor}}.css?v=61">
{% if v.agendaposter %}<link rel="stylesheet" href="/assets/css/agendaposter.css?v=61">{% endif %}
<style>:root{--primary:#{{v.themecolor}}}</style>
<link rel="stylesheet" href="/assets/css/main.css?v=80">
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=80">
{% if v.agendaposter %}<link rel="stylesheet" href="/assets/css/agendaposter.css?v=80">{% elif v.css %}<link rel="stylesheet" href="/@{{v.username}}/css">{% endif %}
{% else %}
<link rel="stylesheet" href="/assets/css/{{'DEFAULT_THEME' | app_config}}.css?v=61">
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
<link rel="stylesheet" href="/assets/css/main.css?v=80"><link rel="stylesheet" href="/assets/css/{{'DEFAULT_THEME' | app_config}}.css?v=80">
{% endif %}
{% endblock %}
<link href="/assets/css/fa.css" rel="stylesheet">
<link href="/assets/css/fa.css?v=52" rel="stylesheet">
{% block fixedMobileBarJS %}
{% endblock %}
</head>
<body id="{% if request.path != '/comments' %}{% block pagetype %}frontpage{% endblock %}{% endif %}" style="overflow-x: hidden; {% if v and v.background %} background:url(/assets/images/backgrounds/{{v.background}}) no-repeat center center fixed !important; background-size: cover!important; background-color: #000!important;{% endif %} {% if 'rdrama' in request.host %}margin-top: 29px!important;{% endif %}">
<body id="{% if request.path != '/comments' %}{% block pagetype %}frontpage{% endblock %}{% endif %}" style="overflow-x: hidden; {% if v and v.background %} background:url(/assets/images/backgrounds/{{v.background}}) no-repeat center center fixed !important; background-size: cover!important; background-color: #000!important;{% endif %} {% if 'rama' in request.host %}margin-top: 29px!important;{% endif %}">
{% if "marsey.tech" not in request.host and '@' not in request.path %}
<a rel="nofollow noopener noreferrer" href="{% if 'rdrama' in request.host %}https://secure.transequality.org/site/Donation2?df_id=1480{% else %}/{% endif %}">
<img loading="lazy" src="/assets/images/{{'SITE_NAME' | app_config}}/{% if v %}banner.webp{% else %}cached.webp{% endif %}" width="100%">
{% if '@' not in request.path %}
<a rel="nofollow noopener noreferrer" href="{% if 'rama' in request.host %}https://secure.transequality.org/site/Donation2?df_id=1480{% else %}/{% endif %}">
<img loading="lazy" style="margin-top: -3px;" src="/assets/images/{{'SITE_NAME' | app_config}}/{% if v %}banner.gif{% else %}cached.gif{% endif %}" width="100%">
</a>
{% endif %}
@ -340,7 +343,7 @@
</div>
<div class="toast" id="toast-post-error" style="position: fixed; bottom: 1.5rem; margin: 0 auto; left: 0; right: 0; width: 275px; z-index: 1000" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body bg-danger text-center text-white">
<i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text"></span>
<i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text">Error, please try again later.</span>
</div>
</div>

View File

@ -12,8 +12,8 @@
var form = new FormData()
form.append("formkey", formkey());
xhr.withCredentials=true;
xhr.onload = function() {location.reload(true);};
xhr.send(form);
location.reload();
}
document.getElementById("deletePostButton-mobile").onclick = delete_post;
@ -36,10 +36,6 @@
<div class="py-4">
<i class="fad fa-trash-alt text-muted d-none d-md-block" style="font-size: 3.5rem;"></i>
<span class="fa-stack fa-2x text-muted d-md-none">
<i class="fas fa-circle text-danger opacity-25 fa-stack-2x"></i>
<i class="fas text-danger fa-trash-alt fa-stack-1x"></i>
</span>
</div>
<div class="h4 d-md-none">Delete post?</div>

View File

@ -1,7 +1,5 @@
{% extends "email/default.html" %}
{% block image %}verify.webp{% endblock %}
{% block title %}Remove Two-Factor Authentication{% endblock %}</h1>
{% block preheader %}Remove Two-Factor Authentication.{% endblock %}

367
files/templates/email/default.html 100644 → 100755
View File

@ -6,373 +6,6 @@
<meta name="x-apple-disable-message-reformatting" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<style type="text/css" rel="stylesheet" media="all">
@import url('https://fonts.googleapis.com/css?family=Roboto:400,500&display=swap');
html {
font-size: 14px;
}
body {
width: 100% !important;
height: 100%;
margin: 0;
-webkit-text-size-adjust: none;
}
a {
color: #FF66AC!important;
}
a img {
border: none;
}
td {
word-break: break-word;
}
.preheader {
display: none !important;
visibility: hidden;
mso-hide: all;
font-size: 1px;
line-height: 1px;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
}
body,
td,
th {
font-family: "Roboto", Helvetica, Arial, sans-serif;
}
h1 {
margin-top: 0;
color: #121213;
font-size: 22px;
font-weight: bold;
text-align: left;
}
h2 {
margin-top: 0;
color: #121213;
font-size: 1rem;
font-weight: bold;
text-align: left;
}
h3 {
margin-top: 0;
color: #121213;
font-size: 14px;
font-weight: bold;
text-align: left;
}
td,
th {
font-size: 1rem;
}
p,
ul,
ol,
blockquote {
margin: .4em 0 1.1875em;
font-size: 1rem;
line-height: 1.625;
}
p.sub {
font-size: 13px;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.button {
background-color: #FF66AC;
border-top: 10px solid #FF66AC;
border-right: 18px solid #FF66AC;
border-bottom: 10px solid #FF66AC;
border-left: 18px solid #FF66AC;
display: inline-block;
color: #FFF!important;
text-decoration: none;
border-radius: .25rem;
-webkit-text-size-adjust: none;
box-sizing: border-box;
}
.button--green {
background-color: #23CE6B;
border-top: 10px solid #23CE6B;
border-right: 18px solid #23CE6B;
border-bottom: 10px solid #23CE6B;
border-left: 18px solid #23CE6B;
}
.button--red {
background-color: #F05D5E;
border-top: 10px solid #F05D5E;
border-right: 18px solid #F05D5E;
border-bottom: 10px solid #F05D5E;
border-left: 18px solid #F05D5E;
}
@media only screen and (max-width: 500px) {
.button {
width: 100% !important;
text-align: center !important;
}
}
.attributes {
margin: 0 0 21px;
}
.attributes_content {
background-color: #EDF2F7;
padding: 1rem;
border-radius: 0.35rem;
}
.attributes_item {
padding: 0;
}
.related {
width: 100%;
margin: 0;
padding: 25px 0 0 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.related_item {
padding: 10px 0;
color: #CBCCCF;
font-size: 15px;
line-height: 18px;
}
.related_item-title {
display: block;
margin: .5em 0 0;
}
.related_item-thumb {
display: block;
padding-bottom: 10px;
}
.related_heading {
border-top: 1px solid #CBCCCF;
text-align: center;
padding: 25px 0 10px;
}
.discount {
width: 100%;
margin: 0;
padding: 24px;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
background-color: #EDF2F7;
border: 2px dashed #CBCCCF;
}
.discount_heading {
text-align: center;
}
.discount_body {
text-align: center;
font-size: 15px;
}
.social {
width: auto;
}
.social td {
padding: 0;
width: auto;
}
.social_icon {
height: 20px;
margin: 0 8px 10px 8px;
padding: 0;
}
.purchase {
width: 100%;
margin: 0;
padding: 35px 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.purchase_content {
width: 100%;
margin: 0;
padding: 25px 0 0 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.purchase_item {
padding: 10px 0;
color: #121213;
font-size: 15px;
line-height: 18px;
}
.purchase_heading {
padding-bottom: 8px;
border-bottom: 1px solid #E6E6E6;
}
.purchase_heading p {
margin: 0;
color: #85878E;
font-size: 12px;
}
.purchase_footer {
padding-top: 15px;
border-top: 1px solid #E6E6E6;
}
.purchase_total {
margin: 0;
text-align: right;
font-weight: bold;
color: #121213;
}
.purchase_total--label {
padding: 0 15px 0 0;
}
body {
background-color: #EDF2F7;
color: #121213;
}
p {
color: #121213;
}
p.sub {
color: #6B6E76;
}
.email-wrapper {
width: 100%;
margin: 0;
padding: 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
background-color: #EDF2F7;
}
.email-content {
width: 100%;
margin: 0;
padding: 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.email-masthead {
display: none;
}
.email-masthead_logo {
width: 94px;
}
.email-masthead_name {
font-size: 1.25rem;
font-weight: bold;
color: #121213;
text-decoration: none;
}
.email-body {
width: 100%;
margin: 0;
padding: 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
background-color: #cfcfcf;
}
.email-body_inner {
width: 570px;
margin: 0 auto;
padding: 0;
-premailer-width: 570px;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
background-color: #cfcfcf;
}
.email-footer {
width: 570px;
margin: 0 auto;
padding: 0;
-premailer-width: 570px;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
text-align: center;
}
.email-footer p {
color: #6B6E76;
}
.body-action {
width: 100%;
margin: 30px auto;
padding: 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
text-align: center;
}
.body-sub {
margin-top: 25px;
padding-top: 25px;
border-top: 1px solid #E6E6E6;
}
.content-cell {
padding: 35px;
}
@media only screen and (max-width: 600px) {
.email-body_inner,
.email-footer {
width: 100% !important;
}
}
@media (prefers-color-scheme: dark) {
body,
.email-body,
.email-body_inner,
.email-content,
.email-wrapper,
.email-masthead,
.email-footer {
background-color: #121213 !important;
color: #FFF !important;
}
p,
ul,
ol,
blockquote,
h1,
h2,
h3 {
color: #FFF !important;
}
.attributes_content,
.discount {
background-color: #222 !important;
}
.email-masthead_name {
text-shadow: none !important;
}
}
</style>
<!--[if mso]>
<style type="text/css">
.f-fallback {
font-family: Arial, sans-serif;
}
</style>
<![endif]-->
</head>
<body>
<span class="preheader">{% block preheader %}Thanks for joining {{'SITE_NAME' | app_config}}! Please take a sec to verify the email you used to sign up.{% endblock %}</span>

View File

View File

View File

View File

View File

View File

2
files/templates/emoji_modal.html 100644 → 100755
View File

@ -1,4 +1,4 @@
<script src="/assets/js/emoji_modal.js?v=50"></script>
<script src="/assets/js/emoji_modal.js?v=56"></script>
<style>
a.emojitab {

0
files/templates/errors/400.html 100644 → 100755
View File

0
files/templates/errors/401.html 100644 → 100755
View File

0
files/templates/errors/403.html 100644 → 100755
View File

0
files/templates/errors/404.html 100644 → 100755
View File

Some files were not shown because too many files have changed in this diff Show More