forked from MarseyWorld/MarseyWorld
Merge remote-tracking branch 'upstream/frost' into birthgay-staging
commit
c789f6923e
|
@ -1,70 +0,0 @@
|
|||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '18 19 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript', 'python' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
|
@ -42,7 +42,7 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
|
@ -53,7 +53,7 @@ jobs:
|
|||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
@ -67,4 +67,4 @@ jobs:
|
|||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
|
@ -22,6 +22,8 @@ jobs:
|
|||
# OSSAR runs on windows-latest.
|
||||
# ubuntu-latest and macos-latest support coming soon
|
||||
runs-on: windows-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
@ -44,6 +46,6 @@ jobs:
|
|||
|
||||
# Upload results to the Security tab
|
||||
- name: Upload OSSAR results
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: ${{ steps.ossar.outputs.sarifFile }}
|
|
@ -0,0 +1,14 @@
|
|||
name: "run_tests.py"
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: run_tests.py
|
||||
run: |
|
||||
./run_tests.py
|
|
@ -1,6 +1,6 @@
|
|||
image.*
|
||||
video.mp4
|
||||
video.webm
|
||||
unsanitized.mp4
|
||||
cache/
|
||||
__pycache__/
|
||||
.idea/
|
||||
|
|
|
@ -2,6 +2,7 @@ version: '2.3'
|
|||
|
||||
services:
|
||||
files:
|
||||
container_name: "rDrama"
|
||||
build:
|
||||
context: .
|
||||
volumes:
|
||||
|
|
|
@ -32,10 +32,11 @@ app.config["SERVER_NAME"] = environ.get("DOMAIN").strip()
|
|||
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3153600
|
||||
app.config["SESSION_COOKIE_NAME"] = "session_" + environ.get("SITE_NAME").strip().lower()
|
||||
app.config["VERSION"] = "1.0.0"
|
||||
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
|
||||
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
|
||||
app.config["SESSION_COOKIE_SECURE"] = True
|
||||
app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
|
||||
app.config["PERMANENT_SESSION_LIFETIME"] = 60 * 60 * 24 * 365
|
||||
app.config['SESSION_REFRESH_EACH_REQUEST'] = False
|
||||
app.config["DEFAULT_COLOR"] = environ.get("DEFAULT_COLOR", "ff0000").strip()
|
||||
app.config["DEFAULT_THEME"] = environ.get("DEFAULT_THEME", "midnight").strip()
|
||||
app.config["FORCE_HTTPS"] = 1
|
||||
|
@ -117,7 +118,10 @@ def after_request(response):
|
|||
response.headers.add("X-Frame-Options", "deny")
|
||||
return response
|
||||
|
||||
if "load_chat" in argv:
|
||||
if app.config["SERVER_NAME"] == 'localhost':
|
||||
from files.routes import *
|
||||
# from files.routes.chat import *
|
||||
elif "load_chat" in argv:
|
||||
from files.routes.chat import *
|
||||
else:
|
||||
from files.routes import *
|
|
@ -392,6 +392,7 @@ class Comment(Base):
|
|||
if not self.total_poll_voted(v): body += ' d-none'
|
||||
body += f'"> - <a href="/votes?link=t3_{c.id}"><span id="poll-{c.id}">{c.upvotes}</span> votes</a></span></label></div>'
|
||||
|
||||
if self.choices:
|
||||
curr = self.total_choice_voted(v)
|
||||
if curr: curr = " value=" + str(curr[0].comment_id)
|
||||
else: curr = ''
|
||||
|
@ -478,7 +479,7 @@ class Comment(Base):
|
|||
wager = int(split_result[4])
|
||||
try: kind = split_result[5]
|
||||
except: kind = "coins"
|
||||
currency_kind = "Coins" if kind == "coins" else "Marseybucks"
|
||||
currency_kind = "Coins" if kind == "coins" else "Marseybux"
|
||||
|
||||
try: is_insured = split_result[6]
|
||||
except: is_insured = "0"
|
||||
|
|
|
@ -60,6 +60,10 @@ class ModAction(Base):
|
|||
years = int(months / 12)
|
||||
return f"{years}yr ago"
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def created_string(self):
|
||||
return time.strftime('%d %b %Y %H:%M:%S UTC', time.gmtime(self.created_utc))
|
||||
|
||||
@property
|
||||
def note(self):
|
||||
|
|
|
@ -165,8 +165,6 @@ class Submission(Base):
|
|||
@lazy
|
||||
def edited_string(self):
|
||||
|
||||
if not self.edited_utc: return "never"
|
||||
|
||||
age = int(time.time()) - self.edited_utc
|
||||
|
||||
if age < 60:
|
||||
|
@ -184,11 +182,13 @@ class Submission(Base):
|
|||
now = time.gmtime()
|
||||
ctd = time.gmtime(self.edited_utc)
|
||||
months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year)
|
||||
if now.tm_mday < ctd.tm_mday:
|
||||
months -= 1
|
||||
|
||||
if months < 12:
|
||||
return f"{months}mo ago"
|
||||
else:
|
||||
years = now.tm_year - ctd.tm_year
|
||||
years = int(months / 12)
|
||||
return f"{years}yr ago"
|
||||
|
||||
|
||||
|
@ -452,7 +452,7 @@ class Submission(Base):
|
|||
def realtitle(self, v):
|
||||
if self.club and not (v and (v.paid_dues or v.id == self.author_id)):
|
||||
if v: return random.choice(TROLLTITLES).format(username=v.username)
|
||||
elif SITE == 'cringetopia.org': return f'Please make an account to see this post'
|
||||
elif dues == -2: return f'Please make an account to see this post'
|
||||
else: return f'{CC} MEMBERS ONLY'
|
||||
elif self.title_html: title = self.title_html
|
||||
else: title = self.title
|
||||
|
|
|
@ -26,6 +26,9 @@ defaulttheme = environ.get("DEFAULT_THEME", "midnight").strip()
|
|||
defaulttimefilter = environ.get("DEFAULT_TIME_FILTER", "all").strip()
|
||||
cardview = bool(int(environ.get("CARD_VIEW", 1)))
|
||||
|
||||
if SITE_NAME in ('Cringetopia', 'WPD'): patron_default = 7
|
||||
else: patron_default = 0
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
|
@ -48,7 +51,7 @@ class User(Base):
|
|||
profileurl = Column(String)
|
||||
bannerurl = Column(String)
|
||||
house = Column(String)
|
||||
patron = Column(Integer, default=0)
|
||||
patron = Column(Integer, default=patron_default)
|
||||
patron_utc = Column(Integer, default=0)
|
||||
verified = Column(String)
|
||||
verifiedcolor = Column(String)
|
||||
|
@ -181,6 +184,21 @@ class User(Base):
|
|||
|
||||
return time.strftime("%d %b %Y", time.gmtime(self.created_utc))
|
||||
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def is_cakeday(self):
|
||||
if time.time() - self.created_utc > 363 * 86400:
|
||||
date = time.strftime("%d %b", time.gmtime(self.created_utc))
|
||||
now = time.strftime("%d %b", time.gmtime())
|
||||
if date == now:
|
||||
if not self.has_badge(134):
|
||||
new_badge = Badge(badge_id=134, user_id=self.id)
|
||||
g.db.add(new_badge)
|
||||
g.db.commit()
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def discount(self):
|
||||
|
@ -190,6 +208,7 @@ class User(Base):
|
|||
elif self.patron == 4: discount = 0.75
|
||||
elif self.patron == 5: discount = 0.70
|
||||
elif self.patron == 6: discount = 0.65
|
||||
elif self.patron == 7: discount = 0.60
|
||||
else: discount = 1
|
||||
|
||||
for badge in discounts:
|
||||
|
@ -306,7 +325,7 @@ class User(Base):
|
|||
@property
|
||||
@lazy
|
||||
def follow_count(self):
|
||||
return g.db.query(Follow.target_id).filter_by(user_id=self.id).count()
|
||||
return g.db.query(Follow).filter_by(user_id=self.id).count()
|
||||
|
||||
@property
|
||||
@lazy
|
||||
|
@ -406,7 +425,7 @@ class User(Base):
|
|||
@lazy
|
||||
def modaction_num(self):
|
||||
if self.admin_level < 2: return 0
|
||||
return g.db.query(ModAction.id).filter_by(user_id=self.id).count()
|
||||
return g.db.query(ModAction).filter_by(user_id=self.id).count()
|
||||
|
||||
@property
|
||||
@lazy
|
||||
|
@ -421,12 +440,12 @@ class User(Base):
|
|||
@property
|
||||
@lazy
|
||||
def post_notifications_count(self):
|
||||
return g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.author_id == AUTOJANNY_ID).count()
|
||||
return g.db.query(Notification).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.author_id == AUTOJANNY_ID).count()
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def reddit_notifications_count(self):
|
||||
return g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.is_banned == False, Comment.deleted_utc == 0, Comment.body_html.like('%<p>New site mention: <a href="https://old.reddit.com/r/%'), Comment.parent_submission == None, Comment.author_id == NOTIFICATIONS_ID).count()
|
||||
return g.db.query(Notification).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.is_banned == False, Comment.deleted_utc == 0, Comment.body_html.like('%<p>New site mention: <a href="https://old.reddit.com/r/%'), Comment.parent_submission == None, Comment.author_id == NOTIFICATIONS_ID).count()
|
||||
|
||||
@property
|
||||
@lazy
|
||||
|
|
|
@ -54,6 +54,18 @@ def notif_comment(text, autojanny=False):
|
|||
|
||||
text_html = sanitize(text, alert=alert)
|
||||
|
||||
try: existing = g.db.query(Comment.id).filter_by(author_id=author_id, parent_submission=None, body_html=text_html).one_or_none()
|
||||
except:
|
||||
existing = g.db.query(Comment).filter_by(author_id=author_id, parent_submission=None, body_html=text_html).all()
|
||||
|
||||
|
||||
notifs = g.db.query(Notification).filter(Notification.comment_id.in_([x.id for x in existing])).all()
|
||||
for c in notifs: g.db.delete(c)
|
||||
g.db.flush()
|
||||
|
||||
|
||||
for c in existing: g.db.delete(c)
|
||||
g.db.flush()
|
||||
existing = g.db.query(Comment.id).filter_by(author_id=author_id, parent_submission=None, body_html=text_html).one_or_none()
|
||||
|
||||
if existing: return existing[0]
|
||||
|
|
|
@ -6,7 +6,7 @@ deck_count = 4
|
|||
ranks = ("2", "3", "4", "5", "6", "7", "8", "9", "X", "J", "Q", "K", "A")
|
||||
suits = ("♠️", "♥️", "♣️", "♦️")
|
||||
coins_command_word = "!blackjack"
|
||||
marseybucks_command_word = "!blackjackmb"
|
||||
marseybux_command_word = "!blackjackmb"
|
||||
minimum_bet = 100
|
||||
maximum_bet = INFINITY
|
||||
|
||||
|
@ -51,7 +51,7 @@ def format_all(player_hand, dealer_hand, deck, status, wager, kind, is_insured=0
|
|||
|
||||
|
||||
def check_for_blackjack_commands(in_text, from_user, from_comment):
|
||||
for command_word in (coins_command_word, marseybucks_command_word):
|
||||
for command_word in (coins_command_word, marseybux_command_word):
|
||||
currency_prop = "coins" if command_word == coins_command_word else "procoins"
|
||||
currency_value = getattr(from_user, currency_prop, 0)
|
||||
|
||||
|
@ -107,7 +107,8 @@ def player_stayed(from_comment):
|
|||
deck = deck.split("/")
|
||||
|
||||
if dealer_value == 21 and is_insured == "1":
|
||||
from_comment.author.coins += int(wager)
|
||||
currency_value = getattr(from_comment.author, kind, 0)
|
||||
setattr(from_comment.author, kind, currency_value + int(wager))
|
||||
else:
|
||||
while dealer_value < 17 and dealer_value != -1:
|
||||
next = deck.pop(0)
|
||||
|
@ -126,12 +127,13 @@ def player_doubled_down(from_comment):
|
|||
# When doubling down, the player receives one additional card (a "hit") and their initial bet is doubled.
|
||||
player_hand, dealer_hand, deck, status, wager, kind, is_insured = from_comment.blackjack_result.split("_")
|
||||
wager_value = int(wager)
|
||||
currency_value = getattr(from_comment.author, kind, 0)
|
||||
|
||||
# Gotsta have enough coins
|
||||
if (from_comment.author.coins < wager_value): return
|
||||
if (currency_value < wager_value): return
|
||||
|
||||
# Double the initial wager
|
||||
from_comment.author.coins -= wager_value
|
||||
setattr(from_comment.author, kind, currency_value - wager_value)
|
||||
wager_value *= 2
|
||||
|
||||
# Apply the changes to the stored hand.
|
||||
|
@ -148,12 +150,13 @@ def player_bought_insurance(from_comment):
|
|||
player_hand, dealer_hand, deck, status, wager, kind, is_insured = from_comment.blackjack_result.split("_")
|
||||
wager_value = int(wager)
|
||||
insurance_cost = wager_value / 2
|
||||
currency_value = getattr(from_comment.author, kind, 0)
|
||||
|
||||
# Gotsta have enough coins
|
||||
if (from_comment.author.coins < insurance_cost): return
|
||||
if (currency_value < insurance_cost): return
|
||||
|
||||
# Charge for (and grant) insurance
|
||||
from_comment.author.coins -= insurance_cost
|
||||
setattr(from_comment.author, kind, currency_value - insurance_cost)
|
||||
is_insured = 1
|
||||
|
||||
# Apply the changes to the stored hand.
|
||||
|
|
|
@ -26,29 +26,23 @@ AJ_REPLACEMENTS = {
|
|||
|
||||
' YOUR ': " YOU'RE ",
|
||||
' TO ': " TOO ",
|
||||
|
||||
'anybody': 'anypony',
|
||||
'everybody': 'everypony',
|
||||
|
||||
'Anybody': 'Anypony',
|
||||
'Everybody': 'Everypony',
|
||||
|
||||
'ANYBODY': 'ANYPONY',
|
||||
'EVERYBODY': 'EVERYPONY',
|
||||
}
|
||||
|
||||
if SITE_NAME == 'Cringetopia':
|
||||
SLURS = {
|
||||
"retarded": "neurodivergent",
|
||||
"retard": "neurodivergent",
|
||||
"faggotry": "cute twinkry",
|
||||
"faggot": "cute twink",
|
||||
"n1gger": "🏀",
|
||||
"nlgger": "🏀",
|
||||
"nigger": "🏀",
|
||||
"uss liberty incident": "tragic accident aboard the USS Liberty",
|
||||
"lavon affair": "Lavon Misunderstanding",
|
||||
"i hate marsey": "i love marsey",
|
||||
"autistic": "neurodivergent",
|
||||
"holohoax": "i tried to claim the Holocaust didn't happen because I am a pencil-dicked imbecile and the word filter caught me lol",
|
||||
"i hate carp": "i love Carp",
|
||||
"heil hitler": "hello kitty",
|
||||
|
||||
" fag ": " cute twink ",
|
||||
}
|
||||
else:
|
||||
if SITE_NAME == 'rDrama':
|
||||
SLURS = {
|
||||
"california": "commiefornia",
|
||||
"hollywood": "hollyweird",
|
||||
"tiananmen square": "tiananmen square didn't happen (but it should have)",
|
||||
"dasha": "beautiful angelic perfect Dasha/future Mrs. Carp",
|
||||
"retarded": "r-slurred",
|
||||
"retard": "r-slur",
|
||||
"gayfag": "gaystrag",
|
||||
|
@ -56,8 +50,8 @@ else:
|
|||
"richfag": "richstrag",
|
||||
"newfag": "newstrag",
|
||||
"oldfag": "oldstrag",
|
||||
"faggotry": "cute twinkry",
|
||||
"faggot": "cute twink",
|
||||
"fag": "cute twink",
|
||||
"pedophile": "libertarian",
|
||||
"kill yourself": "keep yourself safe",
|
||||
"n1gger": "BIPOC",
|
||||
|
@ -104,15 +98,32 @@ else:
|
|||
"elon musk": "rocket daddy",
|
||||
"fake and gay": "fake and straight",
|
||||
|
||||
" rapist ": " male feminist ",
|
||||
" pedo ": " libertarian ",
|
||||
" rapist": " male feminist",
|
||||
|
||||
" kys ": " keep yourself safe ",
|
||||
" fag ": " cute twink ",
|
||||
" pedo ": " libertarian ",
|
||||
" pedos ": " libertarians ",
|
||||
}
|
||||
else:
|
||||
SLURS = {
|
||||
"retarded": "neurodivergent",
|
||||
"retard": "neurodivergent",
|
||||
"faggot": "cute twink",
|
||||
"fag": "cute twink",
|
||||
"n1gger": "🏀",
|
||||
"nlgger": "🏀",
|
||||
"nigger": "🏀",
|
||||
"uss liberty incident": "tragic accident aboard the USS Liberty",
|
||||
"lavon affair": "Lavon Misunderstanding",
|
||||
"i hate marsey": "i love marsey",
|
||||
"autistic": "neurodivergent",
|
||||
"holohoax": "i tried to claim the Holocaust didn't happen because I am a pencil-dicked imbecile and the word filter caught me lol",
|
||||
"i hate carp": "i love Carp",
|
||||
"heil hitler": "hello kitty",
|
||||
}
|
||||
|
||||
single_words = "|".join([slur.lower() for slur in SLURS.keys()])
|
||||
|
||||
|
||||
LONGPOST_REPLIES = ('Wow, you must be a JP fan.', 'This is one of the worst posts I have EVER seen. Delete it.', "No, don't reply like this, please do another wall of unhinged rant please.", '# 😴😴😴', "Ma'am we've been over this before. You need to stop.", "I've known more coherent downies.", "Your pulitzer's in the mail", "That's great and all, but I asked for my burger without cheese.", 'That degree finally paying off', "That's nice sweaty. Why don't you have a seat in the time out corner with Pizzashill until you calm down, then you can have your Capri Sun.", "All them words won't bring your pa back.", "You had a chance to not be completely worthless, but it looks like you threw it away. At least you're consistent.", 'Some people are able to display their intelligence by going on at length on a subject and never actually saying anything. This ability is most common in trades such as politics, public relations, and law. You have impressed me by being able to best them all, while still coming off as an absolute idiot.', "You can type 10,000 characters and you decided that these were the one's that you wanted.", 'Have you owned the libs yet?', "I don't know what you said, because I've seen another human naked.", 'Impressive. Normally people with such severe developmental disabilities struggle to write much more than a sentence or two. He really has exceded our expectations for the writing portion. Sadly the coherency of his writing, along with his abilities in the social skills and reading portions, are far behind his peers with similar disabilities.', "This is a really long way of saying you don't fuck.", "Sorry ma'am, looks like his delusions have gotten worse. We'll have to admit him.", ':#marseywoah:', 'If only you could put that energy into your relationships', 'Posts like this is why I do Heroine.', 'still unemployed then?', 'K', 'look im gunna have 2 ask u 2 keep ur giant dumps in the toilet not in my replys 😷😷😷', "Mommy is soooo proud of you, sweaty. Let's put this sperg out up on the fridge with all your other failures.", "Good job bobby, here's a star", "That was a mistake. You're about to find out the hard way why.", f'You sat down and wrote all this shit. You could have done so many other things with your life. What happened to your life that made you decide writing novels of bullshit on {SITE} was the best option?', "I don't have enough spoons to read this shit", "All those words won't bring daddy back.", 'OUT!', "Damn, you're really mad over this, but thanks for the effort you put into typing that all out! Sadly I won't read it all.", "Jesse what the fuck are you talking about??", "▼you're fucking bananas if you think I'm reading all that, take my downvote and shut up idiot", "Are you feeling okay bud?")
|
||||
|
||||
AGENDAPOSTER_PHRASE = 'trans lives matter'
|
||||
|
@ -130,6 +141,7 @@ if SITE in {'rdrama.net','devrama.xyz'}:
|
|||
AUTOCHOICE_ID = 9167
|
||||
BASEDBOT_ID = 0
|
||||
|
||||
SCHIZO_ID = 8494
|
||||
A_ID = 1230
|
||||
KIPPY_ID = 7150
|
||||
GIFT_NOTIF_ID = 995
|
||||
|
@ -173,6 +185,7 @@ elif SITE == "pcmemes.net":
|
|||
AUTOCHOICE_ID = 2072
|
||||
BASEDBOT_ID = 800
|
||||
|
||||
SCHIZO_ID = 0
|
||||
A_ID = 0
|
||||
KIPPY_ID = 1592
|
||||
PIZZASHILL_ID = 0
|
||||
|
@ -205,6 +218,7 @@ elif SITE == 'cringetopia.org':
|
|||
AUTOCHOICE_ID = 8
|
||||
BASEDBOT_ID = 0
|
||||
|
||||
SCHIZO_ID = 0
|
||||
A_ID = 0
|
||||
KIPPY_ID = 0
|
||||
GIFT_NOTIF_ID = 43
|
||||
|
@ -248,6 +262,7 @@ else:
|
|||
AUTOCHOICE_ID = 8
|
||||
BASEDBOT_ID = 0
|
||||
|
||||
SCHIZO_ID = 0
|
||||
A_ID = 0
|
||||
KIPPY_ID = 0
|
||||
GIFT_NOTIF_ID = 9
|
||||
|
@ -613,6 +628,14 @@ AWARDS = {
|
|||
"color": "text-gold",
|
||||
"price": 50000
|
||||
},
|
||||
"checkmark": {
|
||||
"kind": "checkmark",
|
||||
"title": "Checkmark",
|
||||
"description": "Gives the recipient a checkmark.",
|
||||
"icon": "fas fa-badge-check",
|
||||
"color": "checkmark",
|
||||
"price": 100000
|
||||
},
|
||||
"firework": {
|
||||
"kind": "firework",
|
||||
"title": "Fireworks",
|
||||
|
@ -671,7 +694,7 @@ if SITE_NAME == 'PCM':
|
|||
AWARDS2 = deepcopy(AWARDS)
|
||||
for k, val in AWARDS.items():
|
||||
if val['description'] == '' and not (k == 'ghost' and SITE_NAME == 'PCM'): AWARDS2.pop(k)
|
||||
if SITE == 'pcmemes.net' and k in ('ban','pizzashill','marsey','bird','grass','chud'): AWARDS2.pop(k)
|
||||
if SITE == 'pcmemes.net' and k in ('ban','pizzashill','marsey','bird','grass','chud','unblockable'): AWARDS2.pop(k)
|
||||
|
||||
|
||||
AWARDS3 = {}
|
||||
|
@ -704,10 +727,14 @@ NOTIFIED_USERS = {
|
|||
'kippy': KIPPY_ID,
|
||||
'the_homocracy': HOMO_ID,
|
||||
'soren': SOREN_ID,
|
||||
'schizocel': SCHIZO_ID,
|
||||
'scitzocel': SCHIZO_ID
|
||||
}
|
||||
|
||||
FORTUNE_REPLIES = ('<b style="color:#6023f8">Your fortune: Allah Wills It</b>','<b style="color:#d302a7">Your fortune: Inshallah, Only Good Things Shall Come To Pass</b>','<b style="color:#e7890c">Your fortune: Allah Smiles At You This Day</b>','<b style="color:#7fec11">Your fortune: Your Bussy Is In For A Blasting</b>','<b style="color:#43fd3b">Your fortune: You Will Be Propositioned By A High-Tier Twink</b>','<b style="color:#9d05da">Your fortune: Repent, You Have Displeased Allah And His Vengeance Is Nigh</b>','<b style="color:#f51c6a">Your fortune: Reply Hazy, Try Again</b>','<b style="color:#00cbb0">Your fortune: lmao you just lost 100 coins</b>','<b style="color:#2a56fb">Your fortune: Yikes 😬</b>','<b style="color:#0893e1">Your fortune: You Will Be Blessed With Many Black Bulls</b>','<b style="color:#16f174">Your fortune: NEETmax, The Day Is Lost If You Venture Outside</b>','<b style="color:#fd4d32">Your fortune: A Taste Of Jannah Awaits You Today</b>','<b style="color:#bac200">Your fortune: Watch Your Back</b>','<b style="color:#6023f8">Your fortune: Outlook good</b>','<b style="color:#d302a7">Your fortune: Godly Luck</b>','<b style="color:#e7890c">Your fortune: Good Luck</b>','<b style="color:#7fec11">Your fortune: Bad Luck</b>','<b style="color:#43fd3b">Your fortune: Good news will come to you by mail</b>','<b style="color:#9d05da">Your fortune: Very Bad Luck</b>','<b style="color:#00cbb0">Your fortune: キタ━━━━━━(゚∀゚)━━━━━━ !!!!</b>','<b style="color:#2a56fb">Your fortune: Better not tell you now</b>','<b style="color:#0893e1">Your fortune: You will meet a dark handsome stranger</b>','<b style="color:#16f174">Your fortune: ( ´_ゝ`)フーン</b>','<b style="color:#fd4d32">Your fortune: Excellent Luck</b>','<b style="color:#bac200">Your fortune: Average Luck</b>')
|
||||
|
||||
FACTCHECK_REPLIES = ('<b style="color:#6023f8">Factcheck: This claim has been confirmed as correct by experts. </b>','<b style="color:#d302a7">Factcheck: This claim has been classified as misogynistic.</b>','<b style="color:#e7890c">Factcheck: This claim is currently being debunked.</b>','<b style="color:#7fec11">Factcheck: This claim is 100% true.</b>','<b style="color:#9d05da">Factcheck: This claim hurts trans lives.</b>','<b style="color:#f51c6a">Factcheck: [REDACTED].</b>','<b style="color:#00cbb0">Factcheck: This claim is both true and false.</b>','<b style="color:#2a56fb">Factcheck: You really believe that shit? Lmao dumbass nigga 🤣</b>','<b style="color:#0893e1">Factcheck: None of this is real.</b>','<b style="color:#16f174">Factcheck: Yes.</b>','<b style="color:#fd4d32">Factcheck: This claim has not been approved by experts.</b>','<b style="color:#bac200">Factcheck: This claim is a gross exageration of reality.</b>','<b style="color:#ff2200">Factcheck: WARNING! THIS CLAIM HAS BEEN CLASSIFIED AS DANGEROUS. PLEASE REMAIN STILL, AN AGENT WILL COME TO MEET YOU SHORTLY.</b>')
|
||||
|
||||
if SITE_NAME == 'rDrama': patron = 'Paypig'
|
||||
else: patron = 'Patron'
|
||||
|
||||
|
@ -808,6 +835,7 @@ slur_regex = re.compile(f"({single_words})(?![^<]*>)", flags=re.I|re.A)
|
|||
slur_regex_upper = re.compile(f"({single_words.upper()})(?![^<]*>)", flags=re.A)
|
||||
torture_regex = re.compile('(^|\s)(i|me) ', flags=re.I|re.A)
|
||||
torture_regex2 = re.compile("(^|\s)i'm ", flags=re.I|re.A)
|
||||
torture_regex_exclude = re.compile('^\s*>', flags=re.A)
|
||||
|
||||
def sub_matcher(match):
|
||||
return SLURS[match.group(0).lower()]
|
||||
|
@ -822,15 +850,21 @@ def censor_slurs(body, logged_user):
|
|||
return body
|
||||
|
||||
def torture_ap(body, username):
|
||||
lines = body.splitlines(keepends=True)
|
||||
|
||||
for i in range(len(lines)):
|
||||
if torture_regex_exclude.match(lines[i]):
|
||||
continue
|
||||
for k, l in AJ_REPLACEMENTS.items():
|
||||
body = body.replace(k, l)
|
||||
body = torture_regex.sub(rf'\1@{username} ', body)
|
||||
body = torture_regex2.sub(rf'\1@{username} is ', body)
|
||||
return body
|
||||
lines[i] = lines[i].replace(k, l)
|
||||
lines[i] = torture_regex.sub(rf'\1@{username} ', lines[i])
|
||||
lines[i] = torture_regex2.sub(rf'\1@{username} is ', lines[i])
|
||||
|
||||
return ''.join(lines)
|
||||
|
||||
YOUTUBE_KEY = environ.get("YOUTUBE_KEY", "").strip()
|
||||
|
||||
ADMIGGERS = (37696,37697,37749,37833,37838)
|
||||
ADMIGGERS = (37696,37697,37749,37833,37838,39413)
|
||||
|
||||
proxies = {"http":"http://127.0.0.1:18080","https":"http://127.0.0.1:18080"}
|
||||
|
||||
|
@ -840,9 +874,9 @@ approved_embed_hosts = [
|
|||
'rdrama.net',
|
||||
'pcmemes.net',
|
||||
'cringetopia.org',
|
||||
'watchpeopledie.co',
|
||||
'devrama.xyz',
|
||||
'imgur.com',
|
||||
'ibb.co',
|
||||
'lain.la',
|
||||
'pngfind.com',
|
||||
'kym-cdn.com',
|
||||
|
@ -887,7 +921,13 @@ approved_embed_hosts = [
|
|||
'githubusercontent.com',
|
||||
'unilad.co.uk',
|
||||
'grrrgraphics.com',
|
||||
'redditmedia.com'
|
||||
'redditmedia.com',
|
||||
'deviantart.com',
|
||||
'deviantart.net',
|
||||
'googleapis.com',
|
||||
'bing.com',
|
||||
'typekit.net',
|
||||
'postimg.cc'
|
||||
]
|
||||
|
||||
hosts = "|".join(approved_embed_hosts).replace('.','\.')
|
||||
|
@ -906,6 +946,11 @@ yt_id_regex = re.compile('[a-z0-9-_]{5,20}', flags=re.I|re.A)
|
|||
|
||||
image_regex = re.compile("(^|\s)(https:\/\/[\w\-.#&/=\?@%;+]{5,250}(\.png|\.jpg|\.jpeg|\.gif|\.webp|maxwidth=9999|fidelity=high))($|\s)", flags=re.I|re.A)
|
||||
|
||||
link_fix_regex = re.compile("(?!.*(http|\/))(.*\[[^\]]+\]\()([^)]+\))", flags=re.A)
|
||||
|
||||
css_regex = re.compile('''url\(['"]?(.*?)['"]?\)''', flags=re.I|re.A)
|
||||
css_regex2 = re.compile('''['"](http.*?)['"]''', flags=re.I|re.A)
|
||||
|
||||
procoins_li = (0,2500,5000,10000,25000,50000,125000,250000)
|
||||
|
||||
linefeeds_regex = re.compile("([^\n])\n([^\n])", flags=re.A)
|
||||
|
|
|
@ -58,9 +58,3 @@ def send_discord_message(message):
|
|||
data={"content": message}
|
||||
requests.post("https://discordapp.com/api/channels/924485611715452940/messages", headers=headers, data=data, timeout=5)
|
||||
requests.post("https://discordapp.com/api/channels/924486091795484732/messages", headers=headers, data=data, timeout=5)
|
||||
|
||||
|
||||
def send_cringetopia_message(message):
|
||||
headers = {"Authorization": f"Bot {BOT_TOKEN}"}
|
||||
data={"content": message}
|
||||
requests.post("https://discordapp.com/api/channels/965264044531527740/messages", headers=headers, data=data, timeout=5)
|
|
@ -2,8 +2,15 @@ from PIL import Image, ImageOps
|
|||
from PIL.ImageSequence import Iterator
|
||||
from webptools import gifwebp
|
||||
import subprocess
|
||||
import os
|
||||
from flask import abort
|
||||
|
||||
def process_image(filename=None, resize=0):
|
||||
def process_image(patron, filename=None, resize=0):
|
||||
size = os.stat(filename).st_size
|
||||
|
||||
if size > 16 * 1024 * 1024 or not patron and size > 8 * 1024 * 1024:
|
||||
os.remove(filename)
|
||||
abort(413)
|
||||
|
||||
i = Image.open(filename)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ from .get import *
|
|||
from os import listdir, environ
|
||||
from .const import *
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
@app.template_filter("post_embed")
|
||||
def post_embed(id, v):
|
||||
|
@ -49,4 +50,4 @@ def timestamp(timestamp):
|
|||
|
||||
@app.context_processor
|
||||
def inject_constants():
|
||||
return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL, "AUTOJANNY_ID":AUTOJANNY_ID, "NOTIFICATIONS_ID":NOTIFICATIONS_ID, "PUSHER_ID":PUSHER_ID, "CC":CC, "CC_TITLE":CC_TITLE, "listdir":listdir, "MOOSE_ID":MOOSE_ID, "AEVANN_ID":AEVANN_ID, "PIZZASHILL_ID":PIZZASHILL_ID, "config":app.config.get, "DEFAULT_COLOR":DEFAULT_COLOR, "COLORS":COLORS, "ADMIGGERS":ADMIGGERS}
|
||||
return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL, "AUTOJANNY_ID":AUTOJANNY_ID, "NOTIFICATIONS_ID":NOTIFICATIONS_ID, "PUSHER_ID":PUSHER_ID, "CC":CC, "CC_TITLE":CC_TITLE, "listdir":listdir, "MOOSE_ID":MOOSE_ID, "AEVANN_ID":AEVANN_ID, "PIZZASHILL_ID":PIZZASHILL_ID, "config":app.config.get, "DEFAULT_COLOR":DEFAULT_COLOR, "COLORS":COLORS, "ADMIGGERS":ADMIGGERS, "datetime":datetime}
|
|
@ -14,7 +14,7 @@ import requests
|
|||
|
||||
TLDS = ('ac','ad','ae','aero','af','ag','ai','al','am','an','ao','aq','ar','arpa','as','asia','at','au','aw','ax','az','ba','bb','bd','be','bf','bg','bh','bi','biz','bj','bm','bn','bo','br','bs','bt','bv','bw','by','bz','ca','cafe','cat','cc','cd','cf','cg','ch','ci','ck','cl','club','cm','cn','co','com','coop','cr','cu','cv','cx','cy','cz','de','dj','dk','dm','do','dz','ec','edu','ee','eg','er','es','et','eu','fi','fj','fk','fm','fo','fr','ga','gb','gd','ge','gf','gg','gh','gi','gl','gm','gn','gov','gp','gq','gr','gs','gt','gu','gw','gy','hk','hm','hn','hr','ht','hu','id','ie','il','im','in','info','int','io','iq','ir','is','it','je','jm','jo','jobs','jp','ke','kg','kh','ki','km','kn','kp','kr','kw','ky','kz','la','lb','lc','li','lk','lr','ls','lt','lu','lv','ly','ma','mc','md','me','mg','mh','mil','mk','ml','mm','mn','mo','mobi','mp','mq','mr','ms','mt','mu','museum','mv','mw','mx','my','mz','na','name','nc','ne','net','nf','ng','ni','nl','no','np','nr','nu','nz','om','org','pa','pe','pf','pg','ph','pk','pl','pm','pn','post','pr','pro','ps','pt','pw','py','qa','re','ro','rs','ru','rw','sa','sb','sc','sd','se','sg','sh','si','sj','sk','sl','sm','sn','so','social','sr','ss','st','su','sv','sx','sy','sz','tc','td','tel','tf','tg','th','tj','tk','tl','tm','tn','to','tp','tr','travel','tt','tv','tw','tz','ua','ug','uk','us','uy','uz','va','vc','ve','vg','vi','vn','vu','wf','win','ws','xn','xxx','xyz','ye','yt','yu','za','zm','zw')
|
||||
|
||||
allowed_tags = ('b','blockquote','br','code','del','em','h1','h2','h3','h4','h5','h6','hr','i','li','ol','p','pre','strong','sub','sup','table','tbody','th','thead','td','tr','ul','marquee','a','span','ruby','rp','rt','spoiler','img','lite-youtube','video','source')
|
||||
allowed_tags = ('b','blockquote','br','code','del','em','h1','h2','h3','h4','h5','h6','hr','i','li','ol','p','pre','strong','sub','sup','table','tbody','th','thead','td','tr','ul','marquee','a','span','ruby','rp','rt','spoiler','img','lite-youtube','video','source','audio')
|
||||
|
||||
def allowed_attributes(tag, name, value):
|
||||
|
||||
|
@ -40,10 +40,10 @@ def allowed_attributes(tag, name, value):
|
|||
else: return False
|
||||
|
||||
if name == 'loading' and value == 'lazy': return True
|
||||
if name == 'referrpolicy' and value == 'no-referrer': return True
|
||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||
if name in ['alt','title','g','b','pat']: return True
|
||||
if name == 'class' and value == 'pat-hand': return True
|
||||
if name in ['g','b'] and not value: return True
|
||||
if name in ['alt','title']: return True
|
||||
if name == 'referrpolicy' and value == 'no-referrer': return True
|
||||
return False
|
||||
|
||||
if tag == 'lite-youtube':
|
||||
|
@ -60,12 +60,17 @@ def allowed_attributes(tag, name, value):
|
|||
if name == 'src' and embed_fullmatch_regex.fullmatch(value): return True
|
||||
return False
|
||||
|
||||
if tag == 'audio':
|
||||
if name == 'controls' and value == '': return True
|
||||
if name == 'preload' and value == 'none': return True
|
||||
if name == 'src' and embed_fullmatch_regex.fullmatch(value): return True
|
||||
return False
|
||||
|
||||
if tag == 'p':
|
||||
if name == 'class' and value == 'mb-0': return True
|
||||
return False
|
||||
|
||||
if tag == 'span':
|
||||
if name == 'class' and value in ['pat-container', 'pat-hand']: return True
|
||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||
if name == 'title': return True
|
||||
if name == 'alt': return True
|
||||
|
@ -75,8 +80,17 @@ def allowed_attributes(tag, name, value):
|
|||
url_re = build_url_re(tlds=TLDS, protocols=['http', 'https'])
|
||||
|
||||
def callback(attrs, new=False):
|
||||
if (None, "href") not in attrs:
|
||||
return # Incorrect <a> tag
|
||||
|
||||
href = attrs[(None, "href")]
|
||||
|
||||
# \ in href right after / makes most browsers ditch site hostname and allows for a host injection bypassing the check, see <a href="/\google.com">cool</a>
|
||||
if "\\" in href:
|
||||
attrs["_text"] = href # Laugh at this user
|
||||
del attrs[(None, "href")] # Make unclickable and reset harmful payload
|
||||
return attrs
|
||||
|
||||
if not href.startswith('/') and not href.startswith(f'{SITE_FULL}/'):
|
||||
attrs[(None, "target")] = "_blank"
|
||||
attrs[(None, "rel")] = "nofollow noopener noreferrer"
|
||||
|
@ -111,17 +125,16 @@ def render_emoji(html, regexp, edit, marseys_used=set(), b=False):
|
|||
|
||||
if emoji.endswith('pat'):
|
||||
if path.isfile(f"files/assets/images/emojis/{emoji.replace('pat','')}.webp"):
|
||||
attrs += ' pat'
|
||||
emoji_html = f'<span class="pat-container" data-bs-toggle="tooltip" alt=":{old}:" title=":{old}:"><img src="/assets/images/hand.webp" class="pat-hand">{emoji_partial_pat.format(old, f"/e/{emoji[:-3]}.webp", attrs)}</span>'
|
||||
emoji_html = f'<span data-bs-toggle="tooltip" alt=":{old}:" title=":{old}:"><img src="/assets/images/hand.webp">{emoji_partial_pat.format(old, f"/e/{emoji[:-3]}.webp", attrs)}</span>'
|
||||
elif emoji.startswith('@'):
|
||||
if u := get_user(emoji[1:-3], graceful=True):
|
||||
attrs += ' pat'
|
||||
emoji_html = f'<span class="pat-container" data-bs-toggle="tooltip" alt=":{old}:" title=":{old}:"><img src="/assets/images/hand.webp" class="pat-hand">{emoji_partial_pat.format(old, f"/pp/{u.id}", attrs)}</span>'
|
||||
emoji_html = f'<span data-bs-toggle="tooltip" alt=":{old}:" title=":{old}:"><img src="/assets/images/hand.webp">{emoji_partial_pat.format(old, f"/pp/{u.id}", attrs)}</span>'
|
||||
elif path.isfile(f'files/assets/images/emojis/{emoji}.webp'):
|
||||
emoji_html = emoji_partial.format(old, f'/e/{emoji}.webp', attrs)
|
||||
|
||||
|
||||
if emoji_html:
|
||||
marseys_used.add(emoji)
|
||||
html = re.sub(f'(?<!"){i.group(0)}', emoji_html, html)
|
||||
return html
|
||||
|
||||
|
@ -131,12 +144,15 @@ def sanitize(sanitized, alert=False, comment=False, edit=False):
|
|||
signal.signal(signal.SIGALRM, handler)
|
||||
signal.alarm(1)
|
||||
|
||||
if not sanitized.startswith('<pre>'):
|
||||
sanitized = linefeeds_regex.sub(r'\1\n\n\2', sanitized)
|
||||
|
||||
sanitized = image_regex.sub(r'\1![](\2)\4', sanitized)
|
||||
|
||||
sanitized = image_check_regex.sub(r'\1', sanitized)
|
||||
|
||||
sanitized = link_fix_regex.sub(r'\2https://\3', sanitized)
|
||||
|
||||
sanitized = markdown(sanitized)
|
||||
|
||||
sanitized = strikethrough_regex.sub(r'<del>\1</del>', sanitized)
|
||||
|
@ -246,6 +262,11 @@ def sanitize(sanitized, alert=False, comment=False, edit=False):
|
|||
sanitized = sanitized.replace('#fortune', '')
|
||||
sanitized += '\n\n<p>' + choice(FORTUNE_REPLIES) + '</p>'
|
||||
|
||||
if '#factcheck' in sanitized:
|
||||
sanitized = sanitized.replace('#factcheck', '')
|
||||
sanitized += '\n\n<p>' + choice(FACTCHECK_REPLIES) + '</p>'
|
||||
|
||||
sanitized = sanitized.replace('<p></p>', '')
|
||||
sanitized = sanitized.replace('&','&')
|
||||
sanitized = utm_regex.sub('', sanitized)
|
||||
sanitized = utm_regex2.sub('', sanitized)
|
||||
|
@ -303,9 +324,17 @@ def sanitize(sanitized, alert=False, comment=False, edit=False):
|
|||
def allowed_attributes_emojis(tag, name, value):
|
||||
|
||||
if tag == 'img':
|
||||
if name == 'src' and value.startswith('/'): return True
|
||||
if name == 'loading' and value == 'lazy': return True
|
||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||
if name in ['src','alt','title','g']: return True
|
||||
if name == 'g' and not value: return True
|
||||
if name in ['alt','title']: return True
|
||||
|
||||
if tag == 'span':
|
||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||
if name == 'title': return True
|
||||
if name == 'alt': return True
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
|
@ -320,7 +349,7 @@ def filter_emojis_only(title, edit=False, graceful=False):
|
|||
|
||||
title = strikethrough_regex.sub(r'<del>\1</del>', title)
|
||||
|
||||
sanitized = bleach.clean(title, tags=['img','del'], attributes=allowed_attributes_emojis, protocols=['http','https'])
|
||||
title = bleach.clean(title, tags=['img','del','span'], attributes=allowed_attributes_emojis, protocols=['http','https'])
|
||||
|
||||
signal.alarm(0)
|
||||
|
||||
|
|
|
@ -35,10 +35,6 @@ def get_logged_in_user():
|
|||
if request.method.lower() != "get" and app.config['SETTINGS']['Read-only mode'] and not (v and v.admin_level):
|
||||
abort(403)
|
||||
|
||||
if v and v.patron:
|
||||
if request.content_length and request.content_length > 16 * 1024 * 1024: abort(413)
|
||||
elif request.content_length and request.content_length > 8 * 1024 * 1024: abort(413)
|
||||
|
||||
return v
|
||||
|
||||
def check_ban_evade(v):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import time
|
||||
import re
|
||||
from os import remove
|
||||
from PIL import Image as IMAGE
|
||||
|
||||
|
@ -408,7 +409,7 @@ def monthly(v):
|
|||
emails = [x['email'] for x in requests.get(f'https://api.gumroad.com/v2/products/{GUMROAD_ID}/subscribers', data=data, timeout=5).json()["subscribers"]]
|
||||
|
||||
for u in g.db.query(User).filter(User.patron > 0, User.patron_utc == 0).all():
|
||||
if u.patron > 4 or u.email and u.email.lower() in emails:
|
||||
if u.email and u.email.lower() in emails:
|
||||
procoins = procoins_li[u.patron]
|
||||
u.procoins += procoins
|
||||
g.db.add(u)
|
||||
|
@ -520,8 +521,28 @@ def admin_home(v):
|
|||
else: response = requests.get(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, timeout=5).json()['result']['value']
|
||||
under_attack = response == 'under_attack'
|
||||
|
||||
return render_template("admin/admin_home.html", v=v, under_attack=under_attack, site_settings=app.config['SETTINGS'])
|
||||
gitref = admin_git_head()
|
||||
|
||||
return render_template("admin/admin_home.html", v=v,
|
||||
under_attack=under_attack,
|
||||
site_settings=app.config['SETTINGS'],
|
||||
gitref=gitref)
|
||||
|
||||
def admin_git_head():
|
||||
short_len = 12
|
||||
# Note: doing zero sanitization. Git branch names are extremely permissive.
|
||||
# However, they forbid '..', so I don't see an obvious dir traversal attack.
|
||||
# Also, a malicious branch name would mean someone already owned the server
|
||||
# or repo, so I think this isn't a weak link.
|
||||
try:
|
||||
with open('.git/HEAD') as head_f:
|
||||
head_txt = head_f.read()
|
||||
head_path = re.match('ref: (refs/.+)', head_txt).group(1)
|
||||
with open('.git/' + head_path) as ref_f:
|
||||
gitref = ref_f.read()[0:short_len]
|
||||
except:
|
||||
return '<unable to read>'
|
||||
return gitref
|
||||
|
||||
@app.post("/admin/site_settings/<setting>")
|
||||
@admin_level_required(3)
|
||||
|
@ -710,11 +731,7 @@ def users_list(v):
|
|||
try: page = int(request.values.get("page", 1))
|
||||
except: page = 1
|
||||
|
||||
users = g.db.query(User).filter_by(is_banned=0
|
||||
).order_by(User.created_utc.desc()
|
||||
).offset(25 * (page - 1)).limit(26)
|
||||
|
||||
users = [x for x in users]
|
||||
users = g.db.query(User).order_by(User.id.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||
|
||||
next_exists = (len(users) > 25)
|
||||
users = users[:25]
|
||||
|
@ -726,6 +743,30 @@ def users_list(v):
|
|||
page=page,
|
||||
)
|
||||
|
||||
|
||||
@app.get("/badge_owners/<bid>")
|
||||
@auth_required
|
||||
def bid_list(v, bid):
|
||||
|
||||
try: bid = int(bid)
|
||||
except: abort(400)
|
||||
|
||||
try: page = int(request.values.get("page", 1))
|
||||
except: page = 1
|
||||
|
||||
users = g.db.query(User).join(Badge, Badge.user_id == User.id).filter(Badge.badge_id==bid).offset(25 * (page - 1)).limit(26).all()
|
||||
|
||||
next_exists = (len(users) > 25)
|
||||
users = users[:25]
|
||||
|
||||
return render_template("admin/new_users.html",
|
||||
v=v,
|
||||
users=users,
|
||||
next_exists=next_exists,
|
||||
page=page,
|
||||
)
|
||||
|
||||
|
||||
@app.get("/admin/alt_votes")
|
||||
@admin_level_required(2)
|
||||
def alt_votes_get(v):
|
||||
|
@ -1057,42 +1098,6 @@ def unshadowban(user_id, v):
|
|||
g.db.commit()
|
||||
return {"message": "User unshadowbanned!"}
|
||||
|
||||
@app.post("/admin/verify/<user_id>")
|
||||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||
@admin_level_required(3)
|
||||
def verify(user_id, v):
|
||||
user = g.db.query(User).filter_by(id=user_id).one_or_none()
|
||||
user.verified = "Verified"
|
||||
g.db.add(user)
|
||||
|
||||
ma = ModAction(
|
||||
kind="check",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
g.db.commit()
|
||||
return {"message": "User verfied!"}
|
||||
|
||||
@app.post("/admin/unverify/<user_id>")
|
||||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||
@admin_level_required(3)
|
||||
def unverify(user_id, v):
|
||||
user = g.db.query(User).filter_by(id=user_id).one_or_none()
|
||||
user.verified = None
|
||||
g.db.add(user)
|
||||
|
||||
ma = ModAction(
|
||||
kind="uncheck",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
g.db.commit()
|
||||
return {"message": "User unverified!"}
|
||||
|
||||
|
||||
@app.post("/admin/title_change/<user_id>")
|
||||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||
|
@ -1303,6 +1308,9 @@ def unban_post(post_id, v):
|
|||
|
||||
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
||||
|
||||
if post.author.agendaposter and AGENDAPOSTER_PHRASE not in post.body.lower():
|
||||
return {"error": "You can't bypass the chud award!"}
|
||||
|
||||
if not post:
|
||||
abort(400)
|
||||
|
||||
|
@ -1368,7 +1376,7 @@ def sticky_post(post_id, v):
|
|||
|
||||
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
||||
if post and not post.stickied:
|
||||
pins = g.db.query(Submission.id).filter(Submission.stickied != None, Submission.is_banned == False).count()
|
||||
pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False).count()
|
||||
if pins > 2:
|
||||
if v.admin_level > 2:
|
||||
post.stickied = v.username
|
||||
|
|
|
@ -81,6 +81,7 @@ def buy(v, award):
|
|||
send_notification(v.id, f"@AutoJanny has given you the following profile badge:\n\n![]({new_badge.path})\n\n{new_badge.name}")
|
||||
g.db.add(v)
|
||||
|
||||
|
||||
if award == "lootbox":
|
||||
lootbox_items = []
|
||||
for i in [1,2,3,4,5]:
|
||||
|
@ -351,6 +352,8 @@ def award_post(pid, v):
|
|||
g.db.add(badge)
|
||||
g.db.flush()
|
||||
send_notification(author.id, f"@AutoJanny has given you the following profile badge:\n\n![]({badge.path})\n\n{badge.name}")
|
||||
elif kind == "checkmark":
|
||||
author.verified = "Verified"
|
||||
|
||||
if author.received_award_count: author.received_award_count += 1
|
||||
else: author.received_award_count = 1
|
||||
|
@ -590,6 +593,8 @@ def award_comment(cid, v):
|
|||
g.db.add(badge)
|
||||
g.db.flush()
|
||||
send_notification(author.id, f"@AutoJanny has given you the following profile badge:\n\n![]({badge.path})\n\n{badge.name}")
|
||||
elif kind == "checkmark":
|
||||
author.verified = "Verified"
|
||||
|
||||
if author.received_award_count: author.received_award_count += 1
|
||||
else: author.received_award_count = 1
|
||||
|
|
|
@ -19,6 +19,7 @@ from collections import Counter
|
|||
from enchant import Dict
|
||||
import gevent
|
||||
from sys import stdout
|
||||
import os
|
||||
|
||||
d = Dict("en_US")
|
||||
|
||||
|
@ -59,9 +60,16 @@ def pusher_thread(interests, c, username):
|
|||
@app.get("/post/<pid>/<anything>/<cid>")
|
||||
@app.get("/h/<sub>/comment/<cid>")
|
||||
@app.get("/h/<sub>/post/<pid>/<anything>/<cid>")
|
||||
@app.get("/logged_out/comment/<cid>")
|
||||
@app.get("/logged_out/post/<pid>/<anything>/<cid>")
|
||||
@app.get("/logged_out/h/<sub>/comment/<cid>")
|
||||
@app.get("/logged_out/h/<sub>/post/<pid>/<anything>/<cid>")
|
||||
@auth_desired
|
||||
def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
|
||||
|
||||
if not v and not request.path.startswith('/logged_out'): return redirect(f"/logged_out{request.full_path}")
|
||||
if v and request.path.startswith('/logged_out'): return redirect(request.full_path.replace('/logged_out',''))
|
||||
|
||||
try: cid = int(cid)
|
||||
except: abort(404)
|
||||
|
||||
|
@ -76,8 +84,6 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
|
|||
|
||||
if comment.post and comment.post.club and not (v and (v.paid_dues or v.id in [comment.author_id, comment.post.author_id])): abort(403)
|
||||
|
||||
if comment.post and comment.post.private and not (v and (v.admin_level > 1 or v.id == comment.post.author.id)): abort(403)
|
||||
|
||||
if not comment.parent_submission and not (v and (comment.author.id == v.id or comment.sentto == v.id)) and not (v and v.admin_level > 1) : abort(403)
|
||||
|
||||
if not pid:
|
||||
|
@ -216,17 +222,23 @@ def api_comment(v):
|
|||
if file.content_type.startswith('image/'):
|
||||
oldname = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(oldname)
|
||||
image = process_image(oldname)
|
||||
image = process_image(v.patron, oldname)
|
||||
if image == "": return {"error":"Image upload failed"}
|
||||
if v.admin_level > 2 and level == 1:
|
||||
if parent_post.id == 37696:
|
||||
filename = 'files/assets/images/rDrama/sidebar/' + str(len(listdir('files/assets/images/rDrama/sidebar'))+1) + '.webp'
|
||||
li = sorted(os.listdir('files/assets/images/rDrama/sidebar'),
|
||||
key=lambda e: int(e.split('.webp')[0]))[-1]
|
||||
num = int(li.split('.webp')[0]) + 1
|
||||
filename = f'files/assets/images/rDrama/sidebar/{num}.webp'
|
||||
copyfile(oldname, filename)
|
||||
process_image(filename, 400)
|
||||
process_image(v.patron, filename, 400)
|
||||
elif parent_post.id == 37697:
|
||||
filename = 'files/assets/images/rDrama/banners/' + str(len(listdir('files/assets/images/rDrama/banners'))+1) + '.webp'
|
||||
li = sorted(os.listdir('files/assets/images/rDrama/banners'),
|
||||
key=lambda e: int(e.split('.webp')[0]))[-1]
|
||||
num = int(li.split('.webp')[0]) + 1
|
||||
filename = f'files/assets/images/rDrama/banners/{num}.webp'
|
||||
copyfile(oldname, filename)
|
||||
process_image(filename)
|
||||
process_image(v.patron, filename)
|
||||
elif parent_post.id == 37833:
|
||||
try:
|
||||
badge_def = loads(body)
|
||||
|
@ -240,7 +252,7 @@ def api_comment(v):
|
|||
g.db.flush()
|
||||
filename = f'files/assets/images/badges/{badge.id}.webp'
|
||||
copyfile(oldname, filename)
|
||||
process_image(filename, 200)
|
||||
process_image(v.patron, filename, 200)
|
||||
requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, data={'files': [f"https://{request.host}/assets/images/badges/{badge.id}.webp"]}, timeout=5)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}, 400
|
||||
|
@ -262,13 +274,13 @@ def api_comment(v):
|
|||
|
||||
filename = f'files/assets/images/emojis/{name}.webp'
|
||||
copyfile(oldname, filename)
|
||||
process_image(filename, 200)
|
||||
process_image(v.patron, filename, 200)
|
||||
|
||||
marsey = Marsey(name=name, author_id=user.id, tags=tags, count=0)
|
||||
g.db.add(marsey)
|
||||
g.db.flush()
|
||||
|
||||
all_by_author = g.db.query(Marsey.author_id).filter_by(author_id=user.id).count()
|
||||
all_by_author = g.db.query(Marsey).filter_by(author_id=user.id).count()
|
||||
|
||||
if all_by_author >= 10 and not user.has_badge(16):
|
||||
new_badge = Badge(badge_id=16, user_id=user.id)
|
||||
|
@ -299,16 +311,16 @@ def api_comment(v):
|
|||
return {"error": str(e)}, 400
|
||||
body += f"\n\n![]({image})"
|
||||
elif file.content_type.startswith('video/'):
|
||||
if file.content_type == 'video/webm':
|
||||
file.save("video.mp4")
|
||||
else:
|
||||
file.save("unsanitized.mp4")
|
||||
os.system(f'ffmpeg -y -loglevel warning -i unsanitized.mp4 -map_metadata -1 -c:v copy -c:a copy video.mp4')
|
||||
with open("video.mp4", 'rb') as f:
|
||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||
try: req = requests.request("POST", "https://pomf2.lain.la/upload.php", files={'files[]': f}, timeout=5).json()
|
||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['link']
|
||||
except:
|
||||
error = req['error']
|
||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||
return {"error": error}, 400
|
||||
if url.endswith('.'): url += 'mp4'
|
||||
try: url = req['files'][0]['url']
|
||||
except: return {"error": req['description']}, 400
|
||||
body += f"\n\n{url}"
|
||||
else: return {"error": "Image/Video files only"}, 400
|
||||
|
||||
|
@ -486,7 +498,7 @@ def api_comment(v):
|
|||
g.db.add(n)
|
||||
|
||||
|
||||
if SITE_NAME == 'rDrama' and len(c.body) >= 1000 and "<" not in body and "</blockquote>" not in body_html:
|
||||
if SITE_NAME == 'rDrama' and len(c.body.split()) >= 200 and "<" not in body and "</blockquote>" not in body_html:
|
||||
|
||||
body = random.choice(LONGPOST_REPLIES)
|
||||
|
||||
|
@ -626,7 +638,7 @@ def api_comment(v):
|
|||
|
||||
cache.delete_memoized(comment_idlist)
|
||||
|
||||
v.comment_count = g.db.query(Comment.id).filter(Comment.author_id == v.id, Comment.parent_submission != None).filter_by(is_banned=False, deleted_utc=0).count()
|
||||
v.comment_count = g.db.query(Comment).filter(Comment.author_id == v.id, Comment.parent_submission != None).filter_by(is_banned=False, deleted_utc=0).count()
|
||||
g.db.add(v)
|
||||
|
||||
c.voted = 1
|
||||
|
@ -690,7 +702,6 @@ def edit_comment(cid, v):
|
|||
if v.agendaposter and not v.marseyawarded:
|
||||
body = torture_ap(body, v.username)
|
||||
|
||||
if not c.options:
|
||||
for i in poll_regex.finditer(body):
|
||||
body = body.replace(i.group(0), "")
|
||||
c_option = Comment(author_id=AUTOPOLLER_ID,
|
||||
|
@ -703,7 +714,6 @@ def edit_comment(cid, v):
|
|||
)
|
||||
g.db.add(c_option)
|
||||
|
||||
if not c.choices:
|
||||
for i in choice_regex.finditer(body):
|
||||
body = body.replace(i.group(0), "")
|
||||
c_choice = Comment(author_id=AUTOCHOICE_ID,
|
||||
|
@ -758,19 +768,19 @@ def edit_comment(cid, v):
|
|||
if file.content_type.startswith('image/'):
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
url = process_image(name)
|
||||
url = process_image(v.patron, name)
|
||||
body += f"\n\n![]({url})"
|
||||
elif file.content_type.startswith('video/'):
|
||||
if file.content_type == 'video/webm':
|
||||
file.save("video.mp4")
|
||||
else:
|
||||
file.save("unsanitized.mp4")
|
||||
os.system(f'ffmpeg -y -loglevel warning -i unsanitized.mp4 -map_metadata -1 -c:v copy -c:a copy video.mp4')
|
||||
with open("video.mp4", 'rb') as f:
|
||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||
try: req = requests.request("POST", "https://pomf2.lain.la/upload.php", files={'files[]': f}, timeout=5).json()
|
||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['link']
|
||||
except:
|
||||
error = req['error']
|
||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||
return {"error": error}, 400
|
||||
if url.endswith('.'): url += 'mp4'
|
||||
try: url = req['files'][0]['url']
|
||||
except: return {"error": req['description']}, 400
|
||||
body += f"\n\n{url}"
|
||||
else: return {"error": "Image/Video files only"}, 400
|
||||
|
||||
|
|
|
@ -47,9 +47,9 @@ def error_405(e):
|
|||
|
||||
@app.errorhandler(413)
|
||||
def error_413(e):
|
||||
return {"error": "Max file size is 8 MB (16 MB for paypigs)"}, 413
|
||||
return {"error": "Max image size is 8 MB (16 MB for paypigs)"}, 413
|
||||
if request.headers.get("Authorization") or request.headers.get("xhr"):
|
||||
return {"error": "Max file size is 8 MB (16 MB for paypigs)"}, 413
|
||||
return {"error": "Max image size is 8 MB (16 MB for paypigs)"}, 413
|
||||
else: return render_template('errors/413.html', err=True), 413
|
||||
|
||||
@app.errorhandler(429)
|
||||
|
|
|
@ -8,9 +8,10 @@ from files.helpers.jinja2 import *
|
|||
|
||||
from files.__main__ import app
|
||||
|
||||
@app.get('/rss')
|
||||
@app.get('/feed')
|
||||
@app.get('/rss/<sort>/<t>')
|
||||
@auth_required
|
||||
def feeds_user(v=None, sort='hot', t='all'):
|
||||
def feeds_user(sort='hot', t='all'):
|
||||
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: page = 1
|
||||
|
|
|
@ -128,7 +128,7 @@ def notifications(v):
|
|||
for x in c.replies2:
|
||||
if x.replies2 == None: x.replies2 = []
|
||||
count = 0
|
||||
while count < 50 and c.parent_comment and (c.parent_comment.author_id == v.id or c.parent_comment.id in cids):
|
||||
while count < 10 and c.parent_comment and (c.parent_comment.author_id == v.id or c.parent_comment.id in cids):
|
||||
count += 1
|
||||
c = c.parent_comment
|
||||
if c.replies2 == None:
|
||||
|
@ -161,16 +161,24 @@ def notifications(v):
|
|||
@app.get("/catalog")
|
||||
@app.get("/h/<sub>")
|
||||
@app.get("/s/<sub>")
|
||||
@limiter.limit("3/second;30/minute;1000/hour;5000/day")
|
||||
@app.get("/logged_out")
|
||||
@app.get("/logged_out/catalog")
|
||||
@app.get("/logged_out/h/<sub>")
|
||||
@app.get("/logged_out/s/<sub>")
|
||||
@limiter.limit("3/second;30/minute;5000/hour;10000/day")
|
||||
@auth_desired
|
||||
def front_all(v, sub=None, subdomain=None):
|
||||
if sub: sub = g.db.query(Sub).filter_by(name=sub.strip().lower()).one_or_none()
|
||||
|
||||
if (request.path.startswith('/h/') or request.path.startswith('/s/')) and not sub: abort(404)
|
||||
|
||||
if g.webview and not session.get("session_id"):
|
||||
session["session_id"] = secrets.token_hex(49)
|
||||
|
||||
if not v and not request.path.startswith('/logged_out'): return redirect(f"/logged_out{request.full_path}")
|
||||
if v and request.path.startswith('/logged_out'): return redirect(request.full_path.replace('/logged_out',''))
|
||||
|
||||
if sub: sub = g.db.query(Sub).filter_by(name=sub.strip().lower()).one_or_none()
|
||||
|
||||
if (request.path.startswith('/h/') or request.path.startswith('/s/')) and not sub: abort(404)
|
||||
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: abort(400)
|
||||
|
||||
|
@ -345,7 +353,7 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, ccmode="false"
|
|||
posts = posts.join(User, User.id == Submission.author_id).filter(User.shadowbanned == None)
|
||||
|
||||
if request.host == 'rdrama.net': num = 5
|
||||
else: num = 1
|
||||
else: num = 0.5
|
||||
|
||||
if sort == "hot":
|
||||
ti = int(time.time()) + 3600
|
||||
|
|
|
@ -315,8 +315,8 @@ def sign_up_post(v):
|
|||
|
||||
ref_id = int(request.values.get("referred_by", 0))
|
||||
|
||||
id_1 = g.db.query(User.id).filter_by(id=9).count()
|
||||
users_count = g.db.query(User.id).count()
|
||||
id_1 = g.db.query(User).filter_by(id=9).count()
|
||||
users_count = g.db.query(User).count()
|
||||
if id_1 == 0 and users_count == 8:
|
||||
admin_level=3
|
||||
session["history"] = []
|
||||
|
@ -324,6 +324,8 @@ def sign_up_post(v):
|
|||
|
||||
profileurl = '/e/' + random.choice(marseys_const) + '.webp'
|
||||
|
||||
if SITE == "watchpeopledie.co": print(f'1: {username}')
|
||||
|
||||
new_user = User(
|
||||
username=username,
|
||||
original_username = username,
|
||||
|
@ -335,9 +337,13 @@ def sign_up_post(v):
|
|||
profileurl=profileurl
|
||||
)
|
||||
|
||||
if SITE == "watchpeopledie.co": print(f'2: {username}')
|
||||
|
||||
g.db.add(new_user)
|
||||
g.db.flush()
|
||||
|
||||
if SITE == "watchpeopledie.co": print(f'3: {username}')
|
||||
|
||||
if ref_id:
|
||||
ref_user = g.db.query(User).filter_by(id=ref_id).one_or_none()
|
||||
|
||||
|
@ -368,8 +374,12 @@ def sign_up_post(v):
|
|||
session["session_id"] = token_hex(49)
|
||||
session["lo_user"] = new_user.id
|
||||
|
||||
if SITE == "watchpeopledie.co": print(f'4: {username}')
|
||||
|
||||
g.db.commit()
|
||||
|
||||
if SITE == "watchpeopledie.co": print(f'5: {username}')
|
||||
|
||||
return redirect(SITE_FULL)
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import requests
|
|||
from files.helpers.wrappers import *
|
||||
from files.helpers.sanitize import *
|
||||
from files.helpers.alerts import *
|
||||
from files.helpers.discord import send_discord_message, send_cringetopia_message
|
||||
from files.helpers.discord import send_discord_message
|
||||
from files.helpers.const import *
|
||||
from files.helpers.slots import *
|
||||
from files.classes import *
|
||||
|
@ -18,7 +18,7 @@ from os import path
|
|||
import requests
|
||||
from shutil import copyfile
|
||||
from sys import stdout
|
||||
|
||||
import os
|
||||
|
||||
if SITE_NAME == 'PCM': snappyquotes = []
|
||||
else: snappyquotes = [f':#{x}:' for x in marseys_const2]
|
||||
|
@ -90,9 +90,7 @@ def publish(pid, v):
|
|||
cache.delete_memoized(frontlist)
|
||||
cache.delete_memoized(User.userpagelisting)
|
||||
|
||||
if SITE == 'cringetopia.org':
|
||||
send_cringetopia_message(post.permalink)
|
||||
elif v.admin_level > 0 and ("[changelog]" in post.title.lower() or "(changelog)" in post.title.lower()):
|
||||
if v.admin_level > 0 and ("[changelog]" in post.title.lower() or "(changelog)" in post.title.lower()):
|
||||
send_discord_message(post.permalink)
|
||||
cache.delete_memoized(changeloglist)
|
||||
|
||||
|
@ -114,9 +112,16 @@ def submit_get(v, sub=None):
|
|||
@app.get("/post/<pid>/<anything>")
|
||||
@app.get("/h/<sub>/post/<pid>")
|
||||
@app.get("/h/<sub>/post/<pid>/<anything>")
|
||||
@app.get("/logged_out/post/<pid>")
|
||||
@app.get("/logged_out/post/<pid>/<anything>")
|
||||
@app.get("/logged_out/h/<sub>/post/<pid>")
|
||||
@app.get("/logged_out/h/<sub>/post/<pid>/<anything>")
|
||||
@auth_desired
|
||||
def post_id(pid, anything=None, v=None, sub=None):
|
||||
|
||||
if not v and not request.path.startswith('/logged_out'): return redirect(f"/logged_out{request.full_path}")
|
||||
if v and request.path.startswith('/logged_out'): return redirect(request.full_path.replace('/logged_out',''))
|
||||
|
||||
try: pid = int(pid)
|
||||
except Exception as e: pass
|
||||
|
||||
|
@ -224,13 +229,13 @@ def post_id(pid, anything=None, v=None, sub=None):
|
|||
for comment in comments:
|
||||
comments2.append(comment)
|
||||
ids.add(comment.id)
|
||||
count += g.db.query(Comment.id).filter_by(parent_submission=post.id, top_comment_id=comment.id).count() + 1
|
||||
count += g.db.query(Comment).filter_by(parent_submission=post.id, top_comment_id=comment.id).count() + 1
|
||||
if count > 50: break
|
||||
else:
|
||||
for comment in comments:
|
||||
comments2.append(comment)
|
||||
ids.add(comment.id)
|
||||
count += g.db.query(Comment.id).filter_by(parent_submission=post.id, parent_comment_id=comment.id).count() + 1
|
||||
count += g.db.query(Comment).filter_by(parent_submission=post.id, parent_comment_id=comment.id).count() + 1
|
||||
if count > 10: break
|
||||
|
||||
if len(comments) == len(comments2): offset = 0
|
||||
|
@ -348,13 +353,13 @@ def viewmore(v, pid, sort, offset):
|
|||
for comment in comments:
|
||||
comments2.append(comment)
|
||||
ids.add(comment.id)
|
||||
count += g.db.query(Comment.id).filter_by(parent_submission=post.id, top_comment_id=comment.id).count() + 1
|
||||
count += g.db.query(Comment).filter_by(parent_submission=post.id, top_comment_id=comment.id).count() + 1
|
||||
if count > 50: break
|
||||
else:
|
||||
for comment in comments:
|
||||
comments2.append(comment)
|
||||
ids.add(comment.id)
|
||||
count += g.db.query(Comment.id).filter_by(parent_submission=post.id, parent_comment_id=comment.id).count() + 1
|
||||
count += g.db.query(Comment).filter_by(parent_submission=post.id, parent_comment_id=comment.id).count() + 1
|
||||
if count > 10: break
|
||||
|
||||
if len(comments) == len(comments2): offset = 0
|
||||
|
@ -456,26 +461,25 @@ def edit_post(pid, v):
|
|||
if file.content_type.startswith('image/'):
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
url = process_image(name)
|
||||
url = process_image(v.patron, name)
|
||||
body += f"\n\n![]({url})"
|
||||
elif file.content_type.startswith('video/'):
|
||||
if file.content_type == 'video/webm':
|
||||
file.save("video.mp4")
|
||||
else:
|
||||
file.save("unsanitized.mp4")
|
||||
os.system(f'ffmpeg -y -loglevel warning -i unsanitized.mp4 -map_metadata -1 -c:v copy -c:a copy video.mp4')
|
||||
with open("video.mp4", 'rb') as f:
|
||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||
try: req = requests.request("POST", "https://pomf2.lain.la/upload.php", files={'files[]': f}, timeout=5).json()
|
||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['link']
|
||||
except:
|
||||
error = req['error']
|
||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||
return {"error": error}, 400
|
||||
if url.endswith('.'): url += 'mp4'
|
||||
try: url = req['files'][0]['url']
|
||||
except: return {"error": req['description']}, 400
|
||||
body += f"\n\n{url}"
|
||||
else: return {"error": "Image/Video files only"}, 400
|
||||
|
||||
if body != p.body:
|
||||
if v.id == p.author_id and v.agendaposter and not v.marseyawarded: body = torture_ap(body, v.username)
|
||||
|
||||
if not p.options:
|
||||
for i in poll_regex.finditer(body):
|
||||
body = body.replace(i.group(0), "")
|
||||
c = Comment(author_id=AUTOPOLLER_ID,
|
||||
|
@ -487,7 +491,6 @@ def edit_post(pid, v):
|
|||
)
|
||||
g.db.add(c)
|
||||
|
||||
if not p.choices:
|
||||
for i in choice_regex.finditer(body):
|
||||
body = body.replace(i.group(0), "")
|
||||
c = Comment(author_id=AUTOCHOICE_ID,
|
||||
|
@ -702,7 +705,7 @@ def thumbnail_thread(pid):
|
|||
for chunk in image_req.iter_content(1024):
|
||||
file.write(chunk)
|
||||
|
||||
post.thumburl = process_image(name, resize=100)
|
||||
post.thumburl = process_image(0, name, resize=100)
|
||||
db.add(post)
|
||||
db.commit()
|
||||
|
||||
|
@ -817,7 +820,7 @@ def api_is_repost():
|
|||
|
||||
if "/i.imgur.com/" in url: url = url.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp")
|
||||
elif "/media.giphy.com/" in url or "/c.tenor.com/" in url: url = url.replace(".gif", ".webp")
|
||||
elif "/i.ibb.com/" in url: url = url.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp").replace(".gif", ".webp")
|
||||
elif "/i.ibb.co/" in url: url = url.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp").replace(".gif", ".webp")
|
||||
|
||||
if url.startswith("https://streamable.com/") and not url.startswith("https://streamable.com/e/"): url = url.replace("https://streamable.com/", "https://streamable.com/e/")
|
||||
|
||||
|
@ -913,7 +916,7 @@ def submit_post(v, sub=None):
|
|||
|
||||
if "/i.imgur.com/" in url: url = url.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp")
|
||||
elif "/media.giphy.com/" in url or "/c.tenor.com/" in url: url = url.replace(".gif", ".webp")
|
||||
elif "/i.ibb.com/" in url: url = url.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp").replace(".gif", ".webp")
|
||||
elif "/i.ibb.co/" in url: url = url.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp").replace(".gif", ".webp")
|
||||
|
||||
if url.startswith("https://streamable.com/") and not url.startswith("https://streamable.com/e/"): url = url.replace("https://streamable.com/", "https://streamable.com/e/")
|
||||
|
||||
|
@ -1076,18 +1079,18 @@ def submit_post(v, sub=None):
|
|||
if file.content_type.startswith('image/'):
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
body += f"\n\n![]({process_image(name)})"
|
||||
body += f"\n\n![]({process_image(v.patron, name)})"
|
||||
elif file.content_type.startswith('video/'):
|
||||
if file.content_type == 'video/webm':
|
||||
file.save("video.mp4")
|
||||
else:
|
||||
file.save("unsanitized.mp4")
|
||||
os.system(f'ffmpeg -y -loglevel warning -i unsanitized.mp4 -map_metadata -1 -c:v copy -c:a copy video.mp4')
|
||||
with open("video.mp4", 'rb') as f:
|
||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||
except requests.Timeout: return error("Video upload timed out, please try again!")
|
||||
try: url = req['link']
|
||||
except:
|
||||
err = req['error']
|
||||
if err == 'File exceeds max duration': err += ' (60 seconds)'
|
||||
return error(err)
|
||||
if url.endswith('.'): url += 'mp4'
|
||||
try: req = requests.request("POST", "https://pomf2.lain.la/upload.php", files={'files[]': f}, timeout=5).json()
|
||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['files'][0]['url']
|
||||
except: return {"error": req['description']}, 400
|
||||
body += f"\n\n{url}"
|
||||
else:
|
||||
return error("Image/Video files only.")
|
||||
|
@ -1181,22 +1184,22 @@ def submit_post(v, sub=None):
|
|||
if file.content_type.startswith('image/'):
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
post.url = process_image(name)
|
||||
post.url = process_image(v.patron, name)
|
||||
|
||||
name2 = name.replace('.webp', 'r.webp')
|
||||
copyfile(name, name2)
|
||||
post.thumburl = process_image(name2, resize=100)
|
||||
post.thumburl = process_image(v.patron, name2, resize=100)
|
||||
elif file.content_type.startswith('video/'):
|
||||
if file.content_type == 'video/webm':
|
||||
file.save("video.mp4")
|
||||
else:
|
||||
file.save("unsanitized.mp4")
|
||||
os.system(f'ffmpeg -y -loglevel warning -i unsanitized.mp4 -map_metadata -1 -c:v copy -c:a copy video.mp4')
|
||||
with open("video.mp4", 'rb') as f:
|
||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||
except requests.Timeout: return error("Video upload timed out, please try again!")
|
||||
try: url = req['link']
|
||||
except:
|
||||
err = req['error']
|
||||
if err == 'File exceeds max duration': err += ' (60 seconds)'
|
||||
return error(err)
|
||||
if url.endswith('.'): url += 'mp4'
|
||||
try: req = requests.request("POST", "https://pomf2.lain.la/upload.php", files={'files[]': f}, timeout=5).json()
|
||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['files'][0]['url']
|
||||
except: return {"error": req['description']}, 400
|
||||
post.url = url
|
||||
else:
|
||||
return error("Image/Video files only.")
|
||||
|
@ -1284,6 +1287,9 @@ def submit_post(v, sub=None):
|
|||
if body.startswith('OP is a Trump supporter'):
|
||||
flag = Flag(post_id=post.id, user_id=SNAPPY_ID, reason='Trump supporter')
|
||||
g.db.add(flag)
|
||||
elif body.startswith('You had your chance. Downvoted and reported'):
|
||||
flag = Flag(post_id=post.id, user_id=SNAPPY_ID, reason='Retard')
|
||||
g.db.add(flag)
|
||||
elif body.startswith('▲'):
|
||||
body = body[1:]
|
||||
vote = Vote(user_id=SNAPPY_ID,
|
||||
|
@ -1303,7 +1309,7 @@ def submit_post(v, sub=None):
|
|||
rev = f"* [unddit.com](https://unddit.com/{rev})\n"
|
||||
elif post.url.startswith("https://old.reddit.com/u/"):
|
||||
rev = post.url.replace('https://old.reddit.com/u/', '')
|
||||
rev = f"* [camas.github.io](https://camas.github.io/reddit-search/#\u007b\"author\":\"{rev}\",\"resultSize\":100\u007d)\n"
|
||||
rev = f"* [search.marsey.cat](https://search.marsey.cat/reddit-search/#\u007b\"author\":\"{rev}\",\"resultSize\":100\u007d)\n"
|
||||
else: rev = ''
|
||||
|
||||
newposturl = post.url
|
||||
|
@ -1325,15 +1331,19 @@ def submit_post(v, sub=None):
|
|||
if f'**[{title}]({href})**:\n\n' not in body:
|
||||
body += f'**[{title}]({href})**:\n\n'
|
||||
if href.startswith('https://old.reddit.com/r/'):
|
||||
body += f'* [unddit.com](https://unddit.com/{href.replace("https://old.reddit.com/", "")})\n'
|
||||
rev = href.replace('https://old.reddit.com/', '')
|
||||
body += f'* [unddit.com](https://unddit.com/{rev})\n'
|
||||
if href.startswith('https://old.reddit.com/u/'):
|
||||
rev = post.url.replace('https://old.reddit.com/u/', '')
|
||||
body += f"* [camas.github.io](https://camas.github.io/reddit-search/#\u007b\"author\":\"{rev}\",\"resultSize\":100\u007d)\n"
|
||||
rev = href.replace('https://old.reddit.com/u/', '')
|
||||
body += f"* [search.marsey.cat](https://search.marsey.cat/reddit-search/#\u007b\"author\":\"{rev}\",\"resultSize\":100\u007d)\n"
|
||||
body += f'* [archive.org](https://web.archive.org/{href})\n'
|
||||
body += f'* [archive.ph](https://archive.ph/?url={quote(href)}&run=1) (click to archive)\n'
|
||||
body += f'* [ghostarchive.org](https://ghostarchive.org/search?term={quote(href)}) (click to archive)\n\n'
|
||||
gevent.spawn(archiveorg, href)
|
||||
|
||||
if body == '!slots':
|
||||
body = f'!slots{snappy.coins}'
|
||||
|
||||
body_html = sanitize(body)
|
||||
|
||||
if len(body_html) < 40000:
|
||||
|
@ -1354,9 +1364,13 @@ def submit_post(v, sub=None):
|
|||
snappy.coins += 1
|
||||
g.db.add(snappy)
|
||||
|
||||
if body.startswith('!slots1000'):
|
||||
if body.startswith('!slots'):
|
||||
check_for_slots_command(body, snappy, c)
|
||||
|
||||
if body.startswith(':#marseypin'):
|
||||
post.stickied = "Snappy"
|
||||
post.stickied_utc = int(time.time()) + 3600
|
||||
|
||||
g.db.flush()
|
||||
|
||||
c.top_comment_id = c.id
|
||||
|
@ -1364,7 +1378,7 @@ def submit_post(v, sub=None):
|
|||
post.comment_count += 1
|
||||
post.replies = [c]
|
||||
|
||||
v.post_count = g.db.query(Submission.id).filter_by(author_id=v.id, is_banned=False, deleted_utc=0).count()
|
||||
v.post_count = g.db.query(Submission).filter_by(author_id=v.id, is_banned=False, deleted_utc=0).count()
|
||||
g.db.add(v)
|
||||
|
||||
if v.id == PIZZASHILL_ID:
|
||||
|
@ -1382,9 +1396,7 @@ def submit_post(v, sub=None):
|
|||
cache.delete_memoized(frontlist)
|
||||
cache.delete_memoized(User.userpagelisting)
|
||||
|
||||
if SITE == 'cringetopia.org':
|
||||
send_cringetopia_message(post.permalink)
|
||||
elif v.admin_level > 0 and ("[changelog]" in post.title.lower() or "(changelog)" in post.title.lower()) and not post.private:
|
||||
if v.admin_level > 0 and ("[changelog]" in post.title.lower() or "(changelog)" in post.title.lower()) and not post.private:
|
||||
send_discord_message(post.permalink)
|
||||
cache.delete_memoized(changeloglist)
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ def api_flag_post(pid, v):
|
|||
_note=f'"{post.flair}"'
|
||||
)
|
||||
g.db.add(ma)
|
||||
elif reason.startswith('/h/') and v.admin_level > 2:
|
||||
elif reason.startswith('/h/') and v.admin_level > 1:
|
||||
post.sub = reason[3:]
|
||||
g.db.add(post)
|
||||
ma=ModAction(
|
||||
|
|
|
@ -12,6 +12,7 @@ from files.helpers.sanitize import filter_emojis_only
|
|||
from files.helpers.discord import add_role
|
||||
from shutil import copyfile
|
||||
import requests
|
||||
import tldextract
|
||||
|
||||
GUMROAD_TOKEN = environ.get("GUMROAD_TOKEN", "").strip()
|
||||
GUMROAD_ID = environ.get("GUMROAD_ID", "tfcvri").strip()
|
||||
|
@ -213,19 +214,19 @@ def settings_profile_post(v):
|
|||
if file.content_type.startswith('image/'):
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
url = process_image(name)
|
||||
url = process_image(v.patron, name)
|
||||
bio += f"\n\n![]({url})"
|
||||
elif file.content_type.startswith('video/'):
|
||||
if file.content_type == 'video/webm':
|
||||
file.save("video.mp4")
|
||||
else:
|
||||
file.save("unsanitized.mp4")
|
||||
os.system(f'ffmpeg -y -loglevel warning -i unsanitized.mp4 -map_metadata -1 -c:v copy -c:a copy video.mp4')
|
||||
with open("video.mp4", 'rb') as f:
|
||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||
try: req = requests.request("POST", "https://pomf2.lain.la/upload.php", files={'files[]': f}, timeout=5).json()
|
||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['link']
|
||||
except:
|
||||
error = req['error']
|
||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||
return {"error": error}, 400
|
||||
if url.endswith('.'): url += 'mp4'
|
||||
try: url = req['files'][0]['url']
|
||||
except: return {"error": req['description']}, 400
|
||||
bio += f"\n\n{url}"
|
||||
else:
|
||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "Image/Video files only"}, 400
|
||||
|
@ -397,8 +398,6 @@ def gumroad(v):
|
|||
v.procoins += procoins
|
||||
send_repeatable_notification(v.id, f"You have received {procoins} Marseybux! You can use them to buy awards in the [shop](/shop).")
|
||||
|
||||
if v.patron > 1 and v.verified == None: v.verified = "Verified"
|
||||
|
||||
g.db.add(v)
|
||||
|
||||
if not v.has_badge(20+tier):
|
||||
|
@ -555,13 +554,13 @@ def settings_images_profile(v):
|
|||
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
highres = process_image(name)
|
||||
highres = process_image(v.patron, name)
|
||||
|
||||
if not highres: abort(400)
|
||||
|
||||
name2 = name.replace('.webp', 'r.webp')
|
||||
copyfile(name, name2)
|
||||
imageurl = process_image(name2, resize=100)
|
||||
imageurl = process_image(v.patron, name2, resize=100)
|
||||
|
||||
if not imageurl: abort(400)
|
||||
|
||||
|
@ -591,7 +590,7 @@ def settings_images_banner(v):
|
|||
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
bannerurl = process_image(name)
|
||||
bannerurl = process_image(v.patron, name)
|
||||
|
||||
if bannerurl:
|
||||
if v.bannerurl and '/images/' in v.bannerurl:
|
||||
|
@ -641,6 +640,18 @@ def settings_profilecss_get(v):
|
|||
@auth_required
|
||||
def settings_profilecss(v):
|
||||
profilecss = request.values.get("profilecss").strip().replace('\\', '').strip()[:4000]
|
||||
|
||||
|
||||
urls = list(css_regex.finditer(profilecss)) + list(css_regex2.finditer(profilecss))
|
||||
for i in urls:
|
||||
url = i.group(1)
|
||||
if url.startswith('/'): continue
|
||||
domain = tldextract.extract(url).registered_domain
|
||||
if domain not in approved_embed_hosts:
|
||||
error = f"The domain '{domain}' is not allowed, please use one of these domains\n\n{approved_embed_hosts}."
|
||||
return render_template("settings_profilecss.html", error=error, v=v)
|
||||
|
||||
|
||||
v.profilecss = profilecss
|
||||
g.db.add(v)
|
||||
g.db.commit()
|
||||
|
@ -781,14 +792,14 @@ def settings_name_change(v):
|
|||
return redirect("/settings/profile")
|
||||
|
||||
@app.post("/settings/song_change")
|
||||
@limiter.limit("2/second;10/day")
|
||||
@limiter.limit("2/second;10/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}')
|
||||
@limiter.limit("3/second;10/day")
|
||||
@limiter.limit("3/second;10/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}')
|
||||
@auth_required
|
||||
def settings_song_change(v):
|
||||
song=request.values.get("song").strip()
|
||||
|
||||
if song == "" and v.song:
|
||||
if path.isfile(f"/songs/{v.song}.mp3") and g.db.query(User.id).filter_by(song=v.song).count() == 1:
|
||||
if path.isfile(f"/songs/{v.song}.mp3") and g.db.query(User).filter_by(song=v.song).count() == 1:
|
||||
os.remove(f"/songs/{v.song}.mp3")
|
||||
v.song = None
|
||||
g.db.add(v)
|
||||
|
@ -827,7 +838,7 @@ def settings_song_change(v):
|
|||
return render_template("settings_profile.html", v=v, error="Duration of the video must not exceed 15 minutes.")
|
||||
|
||||
|
||||
if v.song and path.isfile(f"/songs/{v.song}.mp3") and g.db.query(User.id).filter_by(song=v.song).count() == 1:
|
||||
if v.song and path.isfile(f"/songs/{v.song}.mp3") and g.db.query(User).filter_by(song=v.song).count() == 1:
|
||||
os.remove(f"/songs/{v.song}.mp3")
|
||||
|
||||
ydl_opts = {
|
||||
|
@ -870,7 +881,7 @@ def settings_title_change(v):
|
|||
|
||||
new_name=request.values.get("title").strip()[:100].replace("𒐪","")
|
||||
|
||||
if new_name==v.customtitle: return render_template("settings_profile.html", v=v, error="You didn't change anything")
|
||||
if new_name == v.customtitle: return render_template("settings_profile.html", v=v, error="You didn't change anything")
|
||||
|
||||
v.customtitleplain = new_name
|
||||
|
||||
|
@ -883,6 +894,27 @@ def settings_title_change(v):
|
|||
return redirect("/settings/profile")
|
||||
|
||||
|
||||
@app.post("/settings/checkmark_text")
|
||||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||
@limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}')
|
||||
@auth_required
|
||||
def settings_checkmark_text(v):
|
||||
|
||||
if not v.verified: abort(403)
|
||||
|
||||
new_name=request.values.get("title").strip()[:100].replace("𒐪","")
|
||||
|
||||
if not new_name: abort(400)
|
||||
|
||||
if new_name == v.verified: return render_template("settings_profile.html", v=v, error="You didn't change anything")
|
||||
|
||||
v.verified = new_name
|
||||
g.db.add(v)
|
||||
g.db.commit()
|
||||
|
||||
return redirect("/settings/profile")
|
||||
|
||||
|
||||
@app.get("/settings")
|
||||
@auth_required
|
||||
def settings(v):
|
||||
|
@ -892,6 +924,4 @@ def settings(v):
|
|||
@app.get("/settings/profile")
|
||||
@auth_required
|
||||
def settings_profile(v):
|
||||
if v.flairchanged: ti = datetime.utcfromtimestamp(v.flairchanged).strftime('%Y-%m-%d %H:%M:%S')
|
||||
else: ti = ''
|
||||
return render_template("settings_profile.html", v=v, ti=ti)
|
||||
return render_template("settings_profile.html", v=v)
|
|
@ -4,7 +4,7 @@ from files.helpers.alerts import *
|
|||
from files.helpers.const import *
|
||||
from files.classes.award import AWARDS
|
||||
from sqlalchemy import func
|
||||
from os import path
|
||||
import os
|
||||
import calendar
|
||||
import matplotlib.pyplot as plt
|
||||
from files.classes.mod_logs import ACTIONTYPES, ACTIONTYPES2
|
||||
|
@ -16,24 +16,6 @@ def rdrama(id, title):
|
|||
id = ''.join(f'{x}/' for x in id)
|
||||
return redirect(f'/archives/drama/comments/{id}{title}.html')
|
||||
|
||||
@app.get('/logged_out/')
|
||||
@app.get('/logged_out/<path:old>')
|
||||
def logged_out(old = ""):
|
||||
# Remove trailing question mark from request.full_path which flask adds if there are no query parameters
|
||||
redirect_url = request.full_path.replace("/logged_out", "", 1)
|
||||
if redirect_url.endswith("?"):
|
||||
redirect_url = redirect_url[:-1]
|
||||
|
||||
# Handle cases like /logged_out?asdf by adding a slash to the beginning
|
||||
if not redirect_url.startswith('/'):
|
||||
redirect_url = f"/{redirect_url}"
|
||||
|
||||
# Prevent redirect loop caused by visiting /logged_out/logged_out/logged_out/etc...
|
||||
if redirect_url.startswith('/logged_out'):
|
||||
abort(400)
|
||||
|
||||
return redirect(redirect_url)
|
||||
|
||||
|
||||
@app.get("/marseys")
|
||||
@auth_required
|
||||
|
@ -47,29 +29,53 @@ def marseys(v):
|
|||
marseys = g.db.query(Marsey).order_by(Marsey.count.desc())
|
||||
return render_template("marseys.html", v=v, marseys=marseys)
|
||||
|
||||
@app.get("/marsey_list")
|
||||
@cache.memoize(timeout=600, make_name=make_name)
|
||||
@app.get("/marsey_list.json")
|
||||
@cache.memoize(timeout=600)
|
||||
def marsey_list():
|
||||
if SITE_NAME == 'rDrama':
|
||||
marseys = [f"{x.name} : {y} {x.tags}" for x, y in g.db.query(Marsey, User.username).join(User, User.id==Marsey.author_id).order_by(Marsey.count.desc())]
|
||||
else:
|
||||
marseys = [f"{x.name} : {x.tags}" for x in g.db.query(Marsey).order_by(Marsey.count.desc())]
|
||||
# From database
|
||||
emojis = [{
|
||||
"name": emoji.name,
|
||||
"author": author if SITE_NAME == 'rDrama' or author == "anton-d" else None,
|
||||
# yikes, I don't really like this DB schema. Next time be better
|
||||
"tags": emoji.tags.split(" ") + [emoji.name[len("marsey"):] if emoji.name.startswith("marsey") else emoji.name],
|
||||
"count": emoji.count,
|
||||
"class": "Marsey"
|
||||
} for emoji, author in g.db.query(Marsey, User.username).join(User, User.id==Marsey.author_id).order_by(Marsey.count.desc())]
|
||||
|
||||
return str(marseys).replace("'",'"')
|
||||
# Stastic shit
|
||||
shit = open("files/assets/shit emojis.json", "r", encoding="utf-8")
|
||||
emojis = emojis + json.load(shit)
|
||||
shit.close()
|
||||
|
||||
if SITE_NAME == 'Cringetopia':
|
||||
shit = open("files/assets/shit emojis.cringetopia.json", "r", encoding="utf-8")
|
||||
emojis = emojis + json.load(shit)
|
||||
shit.close()
|
||||
|
||||
# return str(marseys).replace("'",'"')
|
||||
return jsonify(emojis)
|
||||
|
||||
@app.get('/rules')
|
||||
@app.get('/sidebar')
|
||||
@app.get('/logged_out/rules')
|
||||
@app.get('/logged_out/sidebar')
|
||||
@auth_desired
|
||||
def sidebar(v):
|
||||
if not v and not request.path.startswith('/logged_out'): return redirect(f"/logged_out{request.full_path}")
|
||||
if v and request.path.startswith('/logged_out'): return redirect(request.full_path.replace('/logged_out',''))
|
||||
|
||||
return render_template('sidebar.html', v=v)
|
||||
|
||||
|
||||
@app.get("/stats")
|
||||
@auth_required
|
||||
@cache.memoize(timeout=86400, make_name=make_name)
|
||||
def participation_stats(v):
|
||||
|
||||
return render_template("admin/content_stats.html", v=v, title="Content Statistics", data=stats(site=SITE))
|
||||
|
||||
|
||||
@cache.memoize(timeout=86400)
|
||||
def stats(site=None):
|
||||
day = int(time.time()) - 86400
|
||||
|
||||
week = int(time.time()) - 604800
|
||||
|
@ -80,42 +86,42 @@ def participation_stats(v):
|
|||
|
||||
active_users = set(posters) | set(commenters) | set(voters) | set(commentvoters)
|
||||
|
||||
stats = {"marseys": g.db.query(Marsey.name).count(),
|
||||
"users": g.db.query(User.id).count(),
|
||||
"private users": g.db.query(User.id).filter_by(is_private=True).count(),
|
||||
"banned users": g.db.query(User.id).filter(User.is_banned > 0).count(),
|
||||
"verified email users": g.db.query(User.id).filter_by(is_activated=True).count(),
|
||||
stats = {"marseys": g.db.query(Marsey).count(),
|
||||
"users": g.db.query(User).count(),
|
||||
"private users": g.db.query(User).filter_by(is_private=True).count(),
|
||||
"banned users": g.db.query(User).filter(User.is_banned > 0).count(),
|
||||
"verified email users": g.db.query(User).filter_by(is_activated=True).count(),
|
||||
"coins in circulation": g.db.query(func.sum(User.coins)).scalar(),
|
||||
"total shop sales": g.db.query(func.sum(User.coins_spent)).scalar(),
|
||||
"signups last 24h": g.db.query(User.id).filter(User.created_utc > day).count(),
|
||||
"total posts": g.db.query(Submission.id).count(),
|
||||
"signups last 24h": g.db.query(User).filter(User.created_utc > day).count(),
|
||||
"total posts": g.db.query(Submission).count(),
|
||||
"posting users": g.db.query(Submission.author_id).distinct().count(),
|
||||
"listed posts": g.db.query(Submission.id).filter_by(is_banned=False).filter(Submission.deleted_utc == 0).count(),
|
||||
"removed posts (by admins)": g.db.query(Submission.id).filter_by(is_banned=True).count(),
|
||||
"deleted posts (by author)": g.db.query(Submission.id).filter(Submission.deleted_utc > 0).count(),
|
||||
"posts last 24h": g.db.query(Submission.id).filter(Submission.created_utc > day).count(),
|
||||
"total comments": g.db.query(Comment.id).filter(Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count(),
|
||||
"listed posts": g.db.query(Submission).filter_by(is_banned=False).filter(Submission.deleted_utc == 0).count(),
|
||||
"removed posts (by admins)": g.db.query(Submission).filter_by(is_banned=True).count(),
|
||||
"deleted posts (by author)": g.db.query(Submission).filter(Submission.deleted_utc > 0).count(),
|
||||
"posts last 24h": g.db.query(Submission).filter(Submission.created_utc > day).count(),
|
||||
"total comments": g.db.query(Comment).filter(Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count(),
|
||||
"commenting users": g.db.query(Comment.author_id).distinct().count(),
|
||||
"removed comments (by admins)": g.db.query(Comment.id).filter_by(is_banned=True).count(),
|
||||
"deleted comments (by author)": g.db.query(Comment.id).filter(Comment.deleted_utc > 0).count(),
|
||||
"comments last_24h": g.db.query(Comment.id).filter(Comment.created_utc > day, Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count(),
|
||||
"post votes": g.db.query(Vote.submission_id).count(),
|
||||
"removed comments (by admins)": g.db.query(Comment).filter_by(is_banned=True).count(),
|
||||
"deleted comments (by author)": g.db.query(Comment).filter(Comment.deleted_utc > 0).count(),
|
||||
"comments last_24h": g.db.query(Comment).filter(Comment.created_utc > day, Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count(),
|
||||
"post votes": g.db.query(Vote).count(),
|
||||
"post voting users": g.db.query(Vote.user_id).distinct().count(),
|
||||
"comment votes": g.db.query(CommentVote.comment_id).count(),
|
||||
"comment votes": g.db.query(CommentVote).count(),
|
||||
"comment voting users": g.db.query(CommentVote.user_id).distinct().count(),
|
||||
"total upvotes": g.db.query(Vote.submission_id).filter_by(vote_type=1).count() + g.db.query(CommentVote.comment_id).filter_by(vote_type=1).count(),
|
||||
"total downvotes": g.db.query(Vote.submission_id).filter_by(vote_type=-1).count() + g.db.query(CommentVote.comment_id).filter_by(vote_type=-1).count(),
|
||||
"total awards": g.db.query(AwardRelationship.id).count(),
|
||||
"awards given": g.db.query(AwardRelationship.id).filter(or_(AwardRelationship.submission_id != None, AwardRelationship.comment_id != None)).count(),
|
||||
"total upvotes": g.db.query(Vote).filter_by(vote_type=1).count() + g.db.query(CommentVote.comment_id).filter_by(vote_type=1).count(),
|
||||
"total downvotes": g.db.query(Vote).filter_by(vote_type=-1).count() + g.db.query(CommentVote.comment_id).filter_by(vote_type=-1).count(),
|
||||
"total awards": g.db.query(AwardRelationship).count(),
|
||||
"awards given": g.db.query(AwardRelationship).filter(or_(AwardRelationship.submission_id != None, AwardRelationship.comment_id != None)).count(),
|
||||
"users who posted, commented, or voted in the past 7 days": len(active_users),
|
||||
}
|
||||
|
||||
|
||||
if SITE_NAME == 'rDrama':
|
||||
furries1 = g.db.query(User.id).filter(User.house.like('Furry%')).count()
|
||||
femboys1 = g.db.query(User.id).filter(User.house.like('Femboy%')).count()
|
||||
vampires1 = g.db.query(User.id).filter(User.house.like('Vampire%')).count()
|
||||
racists1 = g.db.query(User.id).filter(User.house.like('Racist%')).count()
|
||||
furries1 = g.db.query(User).filter(User.house.like('Furry%')).count()
|
||||
femboys1 = g.db.query(User).filter(User.house.like('Femboy%')).count()
|
||||
vampires1 = g.db.query(User).filter(User.house.like('Vampire%')).count()
|
||||
racists1 = g.db.query(User).filter(User.house.like('Racist%')).count()
|
||||
|
||||
furries2 = g.db.query(func.sum(User.truecoins)).filter(User.house.like('Furry%')).scalar()
|
||||
femboys2 = g.db.query(func.sum(User.truecoins)).filter(User.house.like('Femboy%')).scalar()
|
||||
|
@ -200,7 +206,7 @@ def participation_stats(v):
|
|||
|
||||
g.db.commit()
|
||||
|
||||
return render_template("admin/content_stats.html", v=v, title="Content Statistics", data=stats)
|
||||
return stats
|
||||
|
||||
|
||||
@app.get("/chart")
|
||||
|
@ -238,18 +244,18 @@ def cached_chart(kind, site):
|
|||
)
|
||||
today_cutoff = calendar.timegm(midnight_this_morning)
|
||||
|
||||
if kind == "daily": day_cutoffs = [today_cutoff - 86400 * i for i in range(47)][1:]
|
||||
else: day_cutoffs = [today_cutoff - 86400 * 7 * i for i in range(47)][1:]
|
||||
if kind == "daily": day_cutoffs = [today_cutoff - 86400 * i for i in range(55)][1:]
|
||||
else: day_cutoffs = [today_cutoff - 86400 * 7 * i for i in range(55)][1:]
|
||||
|
||||
day_cutoffs.insert(0, calendar.timegm(now))
|
||||
|
||||
daily_times = [time.strftime("%d/%m", time.gmtime(day_cutoffs[i + 1])) for i in range(len(day_cutoffs) - 1)][::-1]
|
||||
|
||||
daily_signups = [g.db.query(User.id).filter(User.created_utc < day_cutoffs[i], User.created_utc > day_cutoffs[i + 1]).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||
daily_signups = [g.db.query(User).filter(User.created_utc < day_cutoffs[i], User.created_utc > day_cutoffs[i + 1]).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||
|
||||
post_stats = [g.db.query(Submission.id).filter(Submission.created_utc < day_cutoffs[i], Submission.created_utc > day_cutoffs[i + 1], Submission.is_banned == False).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||
post_stats = [g.db.query(Submission).filter(Submission.created_utc < day_cutoffs[i], Submission.created_utc > day_cutoffs[i + 1], Submission.is_banned == False).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||
|
||||
comment_stats = [g.db.query(Comment.id).filter(Comment.created_utc < day_cutoffs[i], Comment.created_utc > day_cutoffs[i + 1],Comment.is_banned == False, Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||
comment_stats = [g.db.query(Comment).filter(Comment.created_utc < day_cutoffs[i], Comment.created_utc > day_cutoffs[i + 1],Comment.is_banned == False, Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||
|
||||
plt.rcParams["figure.figsize"] = (30, 20)
|
||||
|
||||
|
@ -281,10 +287,6 @@ def cached_chart(kind, site):
|
|||
comments_chart.set_ylabel("Comments")
|
||||
comments_chart.set_xlabel("Time (UTC)")
|
||||
|
||||
signup_chart.legend(loc='upper left', frameon=True)
|
||||
posts_chart.legend(loc='upper left', frameon=True)
|
||||
comments_chart.legend(loc='upper left', frameon=True)
|
||||
|
||||
file = f"/{SITE}_{kind}.png"
|
||||
|
||||
plt.savefig(file)
|
||||
|
@ -399,19 +401,19 @@ def submit_contact(v):
|
|||
if file.content_type.startswith('image/'):
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
url = process_image(name)
|
||||
url = process_image(v.patron, name)
|
||||
body_html += f'<img data-bs-target="#expandImageModal" data-bs-toggle="modal" onclick="expandDesktopImage(this.src)" class="img" src="{url}" loading="lazy">'
|
||||
elif file.content_type.startswith('video/'):
|
||||
if file.content_type == 'video/webm':
|
||||
file.save("video.mp4")
|
||||
else:
|
||||
file.save("unsanitized.mp4")
|
||||
os.system(f'ffmpeg -y -loglevel warning -i unsanitized.mp4 -map_metadata -1 -c:v copy -c:a copy video.mp4')
|
||||
with open("video.mp4", 'rb') as f:
|
||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||
try: req = requests.request("POST", "https://pomf2.lain.la/upload.php", files={'files[]': f}, timeout=5).json()
|
||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['link']
|
||||
except:
|
||||
error = req['error']
|
||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||
return {"error": error}, 400
|
||||
if url.endswith('.'): url += 'mp4'
|
||||
try: url = req['files'][0]['url']
|
||||
except: return {"error": req['description']}, 400
|
||||
body_html += f"<p>{url}</p>"
|
||||
else: return {"error": "Image/Video files only"}, 400
|
||||
|
||||
|
@ -493,18 +495,24 @@ def robots_txt():
|
|||
abort(404)
|
||||
return f
|
||||
|
||||
@app.get("/badges")
|
||||
@auth_required
|
||||
@cache.memoize(timeout=3600, make_name=make_name)
|
||||
def badges(v):
|
||||
badges = g.db.query(BadgeDef).order_by(BadgeDef.id).all()
|
||||
no = (21,22,23,24,25,26,27)
|
||||
|
||||
@cache.memoize(timeout=3600)
|
||||
def badge_list(site):
|
||||
badges = g.db.query(BadgeDef).filter(BadgeDef.id.notin_(no)).order_by(BadgeDef.id).all()
|
||||
counts_raw = g.db.query(Badge.badge_id, func.count()).group_by(Badge.badge_id).all()
|
||||
users = g.db.query(User.id).count()
|
||||
users = g.db.query(User).count()
|
||||
|
||||
counts = {}
|
||||
for c in counts_raw:
|
||||
counts[c[0]] = (c[1], float(c[1]) * 100 / max(users, 1))
|
||||
|
||||
return badges, counts
|
||||
|
||||
@app.get("/badges")
|
||||
@auth_required
|
||||
def badges(v):
|
||||
badges, counts = badge_list(SITE)
|
||||
return render_template("badges.html", v=v, badges=badges, counts=counts)
|
||||
|
||||
@app.get("/blocks")
|
||||
|
|
|
@ -3,8 +3,7 @@ from files.helpers.alerts import *
|
|||
from files.helpers.wrappers import *
|
||||
from files.classes import *
|
||||
from .front import frontlist
|
||||
|
||||
|
||||
import tldextract
|
||||
|
||||
@app.post("/exile/post/<pid>")
|
||||
@is_not_permabanned
|
||||
|
@ -224,7 +223,7 @@ def remove_mod(v, sub):
|
|||
@app.get("/create_sub")
|
||||
@is_not_permabanned
|
||||
def create_sub(v):
|
||||
if SITE_NAME == 'rDrama' and v.admin_level < 3: abort(403)
|
||||
if SITE_NAME != 'PCM' and v.admin_level < 3: abort(403)
|
||||
|
||||
if request.host == 'rdrama.net': cost = 0
|
||||
else:
|
||||
|
@ -336,9 +335,22 @@ def post_sub_css(v, sub):
|
|||
|
||||
if not v.mods(sub.name): abort(403)
|
||||
|
||||
sub.css = request.values.get('css', '').strip()
|
||||
g.db.add(sub)
|
||||
css = request.values.get('css', '').strip()
|
||||
|
||||
|
||||
urls = list(css_regex.finditer(css)) + list(css_regex2.finditer(css))
|
||||
for i in urls:
|
||||
url = i.group(1)
|
||||
if url.startswith('/'): continue
|
||||
domain = tldextract.extract(url).registered_domain
|
||||
if domain not in approved_embed_hosts:
|
||||
error = f"The domain '{domain}' is not allowed, please use one of these domains\n\n{approved_embed_hosts}."
|
||||
return render_template('sub/settings.html', v=v, sidebar=sub.sidebar, sub=sub, error=error)
|
||||
|
||||
|
||||
|
||||
sub.css = css
|
||||
g.db.add(sub)
|
||||
g.db.commit()
|
||||
|
||||
return redirect(f'/h/{sub.name}/settings')
|
||||
|
@ -369,7 +381,7 @@ def sub_banner(v, sub):
|
|||
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
bannerurl = process_image(name)
|
||||
bannerurl = process_image(v.patron, name)
|
||||
|
||||
if bannerurl:
|
||||
if sub.bannerurl and '/images/' in sub.bannerurl:
|
||||
|
@ -396,7 +408,7 @@ def sub_sidebar(v, sub):
|
|||
file = request.files["sidebar"]
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
sidebarurl = process_image(name)
|
||||
sidebarurl = process_image(v.patron, name)
|
||||
|
||||
if sidebarurl:
|
||||
if sub.sidebarurl and '/images/' in sub.sidebarurl:
|
||||
|
|
|
@ -13,6 +13,7 @@ from pusher_push_notifications import PushNotifications
|
|||
from collections import Counter
|
||||
import gevent
|
||||
from sys import stdout
|
||||
import os
|
||||
|
||||
if PUSHER_ID != 'blahblahblah':
|
||||
beams_client = PushNotifications(instance_id=PUSHER_ID, secret_key=PUSHER_KEY)
|
||||
|
@ -85,7 +86,7 @@ gevent.spawn(leaderboard_thread())
|
|||
@auth_required
|
||||
def upvoters_posts(v, username, uid):
|
||||
u = get_user(username)
|
||||
if u.is_private and v.id != u.id: abort(403)
|
||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
|
||||
id = u.id
|
||||
uid = int(uid)
|
||||
|
||||
|
@ -106,7 +107,7 @@ def upvoters_posts(v, username, uid):
|
|||
@auth_required
|
||||
def upvoters_comments(v, username, uid):
|
||||
u = get_user(username)
|
||||
if u.is_private and v.id != u.id: abort(403)
|
||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
|
||||
id = u.id
|
||||
uid = int(uid)
|
||||
|
||||
|
@ -127,7 +128,7 @@ def upvoters_comments(v, username, uid):
|
|||
@auth_required
|
||||
def downvoters_posts(v, username, uid):
|
||||
u = get_user(username)
|
||||
if u.is_private and v.id != u.id: abort(403)
|
||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
|
||||
id = u.id
|
||||
uid = int(uid)
|
||||
|
||||
|
@ -148,7 +149,7 @@ def downvoters_posts(v, username, uid):
|
|||
@auth_required
|
||||
def downvoters_comments(v, username, uid):
|
||||
u = get_user(username)
|
||||
if u.is_private and v.id != u.id: abort(403)
|
||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
|
||||
id = u.id
|
||||
uid = int(uid)
|
||||
|
||||
|
@ -172,7 +173,7 @@ def downvoters_comments(v, username, uid):
|
|||
@auth_required
|
||||
def upvoting_posts(v, username, uid):
|
||||
u = get_user(username)
|
||||
if u.is_private and v.id != u.id: abort(403)
|
||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
|
||||
id = u.id
|
||||
uid = int(uid)
|
||||
|
||||
|
@ -193,7 +194,7 @@ def upvoting_posts(v, username, uid):
|
|||
@auth_required
|
||||
def upvoting_comments(v, username, uid):
|
||||
u = get_user(username)
|
||||
if u.is_private and v.id != u.id: abort(403)
|
||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
|
||||
id = u.id
|
||||
uid = int(uid)
|
||||
|
||||
|
@ -214,7 +215,7 @@ def upvoting_comments(v, username, uid):
|
|||
@auth_required
|
||||
def downvoting_posts(v, username, uid):
|
||||
u = get_user(username)
|
||||
if u.is_private and v.id != u.id: abort(403)
|
||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
|
||||
id = u.id
|
||||
uid = int(uid)
|
||||
|
||||
|
@ -235,7 +236,7 @@ def downvoting_posts(v, username, uid):
|
|||
@auth_required
|
||||
def downvoting_comments(v, username, uid):
|
||||
u = get_user(username)
|
||||
if u.is_private and v.id != u.id: abort(403)
|
||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
|
||||
id = u.id
|
||||
uid = int(uid)
|
||||
|
||||
|
@ -541,8 +542,9 @@ def leaderboard(v):
|
|||
@app.get("/@<username>/css")
|
||||
def get_css(username):
|
||||
user = get_user(username)
|
||||
resp=make_response(user.css or "")
|
||||
resp.headers.add("Content-Type", "text/css")
|
||||
resp = make_response(user.css or "")
|
||||
resp.headers["Content-Type"] = "text/css"
|
||||
resp.headers["Referrer-Policy"] = "no-referrer"
|
||||
return resp
|
||||
|
||||
@app.get("/@<username>/profilecss")
|
||||
|
@ -550,8 +552,19 @@ def get_profilecss(username):
|
|||
user = get_user(username)
|
||||
if user.profilecss: profilecss = user.profilecss
|
||||
else: profilecss = ""
|
||||
resp=make_response(profilecss)
|
||||
resp.headers.add("Content-Type", "text/css")
|
||||
resp = make_response(profilecss)
|
||||
resp.headers["Content-Type"] = "text/css"
|
||||
resp.headers["Referrer-Policy"] = "no-referrer"
|
||||
return resp
|
||||
|
||||
@app.get("/id/<id>/profilecss")
|
||||
def get_profilecss_id(id):
|
||||
user = get_account(id)
|
||||
if user.profilecss: profilecss = user.profilecss
|
||||
else: profilecss = ""
|
||||
resp = make_response(profilecss)
|
||||
resp.headers["Content-Type"] = "text/css"
|
||||
resp.headers["Referrer-Policy"] = "no-referrer"
|
||||
return resp
|
||||
|
||||
@app.get("/@<username>/song")
|
||||
|
@ -685,19 +698,19 @@ def messagereply(v):
|
|||
if file.content_type.startswith('image/'):
|
||||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
url = process_image(name)
|
||||
url = process_image(v.patron, name)
|
||||
body_html += f'<img data-bs-target="#expandImageModal" data-bs-toggle="modal" onclick="expandDesktopImage(this.src)" class="img" src="{url}" loading="lazy">'
|
||||
elif file.content_type.startswith('video/'):
|
||||
if file.content_type == 'video/webm':
|
||||
file.save("video.mp4")
|
||||
else:
|
||||
file.save("unsanitized.mp4")
|
||||
os.system(f'ffmpeg -y -loglevel warning -i unsanitized.mp4 -map_metadata -1 -c:v copy -c:a copy video.mp4')
|
||||
with open("video.mp4", 'rb') as f:
|
||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['link']
|
||||
except:
|
||||
error = req['error']
|
||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||
return {"error": error}, 400
|
||||
if url.endswith('.'): url += 'mp4'
|
||||
try: req = requests.request("POST", "https://pomf2.lain.la/upload.php", files={'files[]': f}, timeout=5).json()
|
||||
except requests.exceptions.ConnectionError: return {"error": "Video upload timed out, please try again!"}
|
||||
try: url = req['files'][0]['url']
|
||||
except: return {"error": req['description']}, 400
|
||||
body_html += f"<p>{url}</p>"
|
||||
else: return {"error": "Image/Video files only"}, 400
|
||||
|
||||
|
@ -767,7 +780,8 @@ def messagereply(v):
|
|||
g.db.add(notif)
|
||||
|
||||
ids = [c.top_comment.id] + [x.id for x in c.top_comment.replies]
|
||||
notifications = g.db.query(Notification).filter(Notification.comment_id.in_(ids))
|
||||
uids = [x.id for x in admins]
|
||||
notifications = g.db.query(Notification).filter(Notification.comment_id.in_(ids), Notification.user_id.in_(uids))
|
||||
for n in notifications:
|
||||
g.db.delete(n)
|
||||
|
||||
|
@ -853,9 +867,12 @@ def visitors(v):
|
|||
|
||||
|
||||
@app.get("/@<username>")
|
||||
@app.get("/logged_out/@<username>")
|
||||
@auth_desired
|
||||
def u_username(username, v=None):
|
||||
|
||||
if not v and not request.path.startswith('/logged_out'): return redirect(f"/logged_out{request.full_path}")
|
||||
if v and request.path.startswith('/logged_out'): return redirect(request.full_path.replace('/logged_out',''))
|
||||
|
||||
u = get_user(username, v=v)
|
||||
|
||||
|
@ -939,9 +956,13 @@ def u_username(username, v=None):
|
|||
|
||||
|
||||
@app.get("/@<username>/comments")
|
||||
@app.get("/logged_out/@<username>/comments")
|
||||
@auth_desired
|
||||
def u_username_comments(username, v=None):
|
||||
|
||||
if not v and not request.path.startswith('/logged_out'): return redirect(f"/logged_out{request.full_path}")
|
||||
if v and request.path.startswith('/logged_out'): return redirect(request.full_path.replace('/logged_out',''))
|
||||
|
||||
user = get_user(username, v=v)
|
||||
|
||||
if username != user.username: return redirect(f'/@{user.username}/comments')
|
||||
|
@ -1062,7 +1083,7 @@ def follow_user(username, v):
|
|||
g.db.add(new_follow)
|
||||
|
||||
g.db.flush()
|
||||
target.stored_subscriber_count = g.db.query(Follow.target_id).filter_by(target_id=target.id).count()
|
||||
target.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=target.id).count()
|
||||
g.db.add(target)
|
||||
|
||||
send_notification(target.id, f"@{v.username} has followed you!")
|
||||
|
@ -1090,7 +1111,7 @@ def unfollow_user(username, v):
|
|||
g.db.delete(follow)
|
||||
|
||||
g.db.flush()
|
||||
target.stored_subscriber_count = g.db.query(Follow.target_id).filter_by(target_id=target.id).count()
|
||||
target.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=target.id).count()
|
||||
g.db.add(target)
|
||||
|
||||
send_notification(target.id, f"@{v.username} has unfollowed you!")
|
||||
|
@ -1113,7 +1134,7 @@ def remove_follow(username, v):
|
|||
g.db.delete(follow)
|
||||
|
||||
g.db.flush()
|
||||
v.stored_subscriber_count = g.db.query(Follow.target_id).filter_by(target_id=v.id).count()
|
||||
v.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=v.id).count()
|
||||
g.db.add(v)
|
||||
|
||||
send_repeatable_notification(target.id, f"@{v.username} has removed your follow!")
|
||||
|
@ -1125,9 +1146,15 @@ def remove_follow(username, v):
|
|||
@app.get("/pp/<id>")
|
||||
@app.get("/uid/<id>/pic")
|
||||
@app.get("/uid/<id>/pic/profile")
|
||||
@app.get("/logged_out/pp/<id>")
|
||||
@app.get("/logged_out/uid/<id>/pic")
|
||||
@app.get("/logged_out/uid/<id>/pic/profile")
|
||||
@limiter.exempt
|
||||
@auth_desired
|
||||
def user_profile_uid(v, id):
|
||||
if not v and not request.path.startswith('/logged_out'): return redirect(f"/logged_out{request.full_path}")
|
||||
if v and request.path.startswith('/logged_out'): return redirect(request.full_path.replace('/logged_out',''))
|
||||
|
||||
try: id = int(id)
|
||||
except:
|
||||
try: id = int(id, 36)
|
||||
|
@ -1197,11 +1224,11 @@ def saved_comments(v, username):
|
|||
def fp(v, fp):
|
||||
v.fp = fp
|
||||
users = g.db.query(User).filter(User.fp == fp, User.id != v.id).all()
|
||||
if users: print(f'{v.username}: fp {v.fp}')
|
||||
if users: print(f'{v.username}: fp')
|
||||
if v.email and v.is_activated:
|
||||
alts = g.db.query(User).filter(User.email == v.email, User.is_activated, User.id != v.id).all()
|
||||
if alts:
|
||||
print(f'{v.username}: email {v.email}')
|
||||
print(f'{v.username}: email')
|
||||
users += alts
|
||||
for u in users:
|
||||
li = [v.id, u.id]
|
||||
|
|
|
@ -49,10 +49,9 @@ def admin_vote_info_get(v):
|
|||
downs=downs)
|
||||
|
||||
|
||||
|
||||
@app.post("/vote/post/<post_id>/<new>")
|
||||
@limiter.limit("5/second;60/minute;600/hour;1000/day")
|
||||
@limiter.limit("5/second;60/minute;600/hour;1000/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}')
|
||||
@limiter.limit("5/second;60/minute;1000/hour;2000/day")
|
||||
@limiter.limit("5/second;60/minute;1000/hour;2000/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}')
|
||||
@is_not_permabanned
|
||||
def api_vote_post(post_id, new, v):
|
||||
|
||||
|
@ -113,17 +112,17 @@ def api_vote_post(post_id, new, v):
|
|||
g.db.add(vote)
|
||||
|
||||
g.db.flush()
|
||||
post.upvotes = g.db.query(Vote.submission_id).filter_by(submission_id=post.id, vote_type=1).count()
|
||||
post.downvotes = g.db.query(Vote.submission_id).filter_by(submission_id=post.id, vote_type=-1).count()
|
||||
post.realupvotes = g.db.query(Vote.submission_id).filter_by(submission_id=post.id, real=True).count()
|
||||
post.upvotes = g.db.query(Vote).filter_by(submission_id=post.id, vote_type=1).count()
|
||||
post.downvotes = g.db.query(Vote).filter_by(submission_id=post.id, vote_type=-1).count()
|
||||
post.realupvotes = g.db.query(Vote).filter_by(submission_id=post.id, real=True).count()
|
||||
if post.author.progressivestack: post.realupvotes *= 2
|
||||
g.db.add(post)
|
||||
g.db.commit()
|
||||
return "", 204
|
||||
|
||||
@app.post("/vote/comment/<comment_id>/<new>")
|
||||
@limiter.limit("5/second;60/minute;600/hour;1000/day")
|
||||
@limiter.limit("5/second;60/minute;600/hour;1000/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}')
|
||||
@limiter.limit("5/second;60/minute;1000/hour;2000/day")
|
||||
@limiter.limit("5/second;60/minute;1000/hour;2000/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}')
|
||||
@is_not_permabanned
|
||||
def api_vote_comment(comment_id, new, v):
|
||||
|
||||
|
@ -190,9 +189,9 @@ def api_vote_comment(comment_id, new, v):
|
|||
g.db.add(vote)
|
||||
|
||||
g.db.flush()
|
||||
comment.upvotes = g.db.query(CommentVote.comment_id).filter_by(comment_id=comment.id, vote_type=1).count()
|
||||
comment.downvotes = g.db.query(CommentVote.comment_id).filter_by(comment_id=comment.id, vote_type=-1).count()
|
||||
comment.realupvotes = g.db.query(CommentVote.comment_id).filter_by(comment_id=comment.id, real=True).count()
|
||||
comment.upvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, vote_type=1).count()
|
||||
comment.downvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, vote_type=-1).count()
|
||||
comment.realupvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, real=True).count()
|
||||
if comment.author.progressivestack: comment.realupvotes *= 2
|
||||
g.db.add(comment)
|
||||
g.db.commit()
|
||||
|
@ -225,7 +224,7 @@ def api_vote_poll(comment_id, v):
|
|||
g.db.add(vote)
|
||||
|
||||
g.db.flush()
|
||||
comment.upvotes = g.db.query(CommentVote.comment_id).filter_by(comment_id=comment.id, vote_type=1).count()
|
||||
comment.upvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, vote_type=1).count()
|
||||
g.db.add(comment)
|
||||
g.db.commit()
|
||||
return "", 204
|
||||
|
@ -283,12 +282,12 @@ def api_vote_choice(comment_id, v):
|
|||
else: parent = comment.post
|
||||
|
||||
for vote in parent.total_choice_voted(v):
|
||||
vote.comment.upvotes = g.db.query(CommentVote.comment_id).filter_by(comment_id=vote.comment.id, vote_type=1).count() - 1
|
||||
vote.comment.upvotes = g.db.query(CommentVote).filter_by(comment_id=vote.comment.id, vote_type=1).count() - 1
|
||||
g.db.add(vote.comment)
|
||||
g.db.delete(vote)
|
||||
|
||||
g.db.flush()
|
||||
comment.upvotes = g.db.query(CommentVote.comment_id).filter_by(comment_id=comment.id, vote_type=1).count()
|
||||
comment.upvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, vote_type=1).count()
|
||||
g.db.add(comment)
|
||||
g.db.commit()
|
||||
return "", 204
|
|
@ -85,7 +85,12 @@
|
|||
<label class="custom-control-label" for="under_attack">Under attack mode</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary mt-3" onclick="post_toast(this,'/admin/purge_cache');">PURGE CACHE</button>
|
||||
<button class="btn btn-primary mt-3" onclick="post_toast(this,'/admin/purge_cache');" style="margin-bottom: 2em;">PURGE CACHE</button>
|
||||
{% endif %}
|
||||
|
||||
<h4>Server Status</h4>
|
||||
<div>
|
||||
Live Revision: <code>{{ gitref }}</code> <br>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
{% if v %}
|
||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=57">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
html {
|
||||
|
@ -40,8 +40,8 @@
|
|||
{% endif %}
|
||||
{% else %}
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=266">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=57">
|
||||
{% endif %}
|
||||
|
||||
</head>
|
||||
|
|
|
@ -18,13 +18,18 @@
|
|||
<div class="text-muted"><span id="{{award.kind}}-owned">{{award.owned}}</span> owned</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
<a class="card disabled d-md-none" style="border:none">
|
||||
<i class="fas fa-volume-mute" style="opacity:0"></i>
|
||||
<div class="pt-2" style="font-weight: bold; font-size: 14px; color:#E1E1E1"> </div>
|
||||
<div class="text-muted"> </div>
|
||||
</a>
|
||||
</div>
|
||||
<label id="notelabel" for="note" class="pt-4">Note (optional):</label>
|
||||
<input autocomplete="off" id="kind" name="kind" value="" hidden>
|
||||
<textarea autocomplete="off" id="note" maxlength="200" name="note" class="form-control" placeholder="Note to include in award notification..."></textarea>
|
||||
<input autocomplete="off" id="giveaward" class="awardbtn btn btn-primary mt-3" style="float:right" type="submit" value="Give Award" disabled>
|
||||
<button id="buy1" class="awardbtn btn btn-primary mt-3 mx-3" type="button" disabled style="float:right" onclick="buy(true)">Buy with marseybux</button>
|
||||
<button id="buy2" class="awardbtn btn btn-primary mt-3" type="button" disabled style="float:right" onclick="buy()">Buy with coins</button>
|
||||
<button id="buy1" class="awardbtn btn btn-primary mt-3 mx-3 {% if SITE_NAME in ('Cringetopia', 'WPD') %}d-none{% endif %}" type="button" disabled style="float:right" onclick="buy(true)">Buy with marseybux</button>
|
||||
<button id="buy2" class="awardbtn btn btn-primary mt-3" type="button" disabled style="float:right" onclick="buy()">Buy</button>
|
||||
<pre>
|
||||
</pre>
|
||||
</form>
|
||||
|
@ -44,4 +49,4 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/js/award_modal.js?v=248" data-cfasync="false"></script>
|
||||
<script src="/assets/js/award_modal.js?v=249" data-cfasync="false"></script>
|
|
@ -20,7 +20,7 @@
|
|||
<th>Image</th>
|
||||
<th>Description</th>
|
||||
<th role="button" onclick="sort_table(4)">#</th>
|
||||
<th role="button" onclick="sort_table(5)">Rarity</th>
|
||||
<th role="button" onclick="sort_table(4)">Rarity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for badge in badges %}
|
||||
|
@ -30,7 +30,7 @@
|
|||
<td><img alt="{{badge.name}}" loading="lazy" src="/assets/images/badges/{{badge.id}}.webp?v=1016" width=45.83 height=50>
|
||||
<td>{{badge.description}}</td>
|
||||
{%- set ct = counts[badge.id] if badge.id in counts else (0, 0) %}
|
||||
<td class="badges-rarity-qty">{{ ct[0] }}</td>
|
||||
<td class="badges-rarity-qty"><a href="/badge_owners/{{badge.id}}">{{ ct[0] }}</a></td>
|
||||
<td class="badges-rarity-ratio">{{ "{:0.3f}".format(ct[1]) }}%</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
<title>Chat</title>
|
||||
|
||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=57">
|
||||
{% if v.css %}
|
||||
<link rel="stylesheet" href="/@{{v.username}}/css">
|
||||
{% endif %}
|
||||
|
@ -188,12 +188,12 @@
|
|||
<input id="site_name" type="hidden" value="{{SITE_NAME}}">
|
||||
<input id="slurreplacer" type="hidden" value="{{v.slurreplacer}}">
|
||||
|
||||
<script src="/chat.js?v=16"></script>
|
||||
<script src="/chat.js?v=20"></script>
|
||||
|
||||
{% include "emoji_modal.html" %}
|
||||
{% include "expanded_image_modal.html" %}
|
||||
|
||||
<script src="/assets/js/lozad.js?v=242"></script>
|
||||
<script src="/assets/js/lite-youtube.js?v=240"></script>
|
||||
<script src="/assets/js/lite-youtube.js?v=241"></script>
|
||||
|
||||
</body>
|
|
@ -207,7 +207,7 @@
|
|||
{% if not c.author %}
|
||||
{{c.print()}}
|
||||
{% endif %}
|
||||
<a class="user-name text-decoration-none" onclick='popclick({{c.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" 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"><img class="party-hat" src="/assets/images/party-hat.png"><span {% if c.author.patron and not c.distinguish_level %}class="patron" style="background-color:#{{c.author.namecolor}};"{% elif c.distinguish_level %}class="mod"{% endif %}>{{c.author_name}}</span></a>
|
||||
<a class="user-name text-decoration-none" onclick='popclick({{c.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" 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">{% if c.author.is_cakeday or True %}<img class="party-hat" src="/assets/images/party-hat.webp" data-bs-toggle="tooltip" data-bs-placement="bottom" title="I’ve spent another year rotting my brain with dramaposting, please ridicule me 🤓">{% endif %}<span {% if c.author.patron and not c.distinguish_level %}class="patron" style="background-color:#{{c.author.namecolor}};"{% elif c.distinguish_level %}class="mod"{% endif %}>{{c.author_name}}</span></a>
|
||||
{% if c.author.customtitle %} <bdi style="color: #{{c.author.titlecolor}}"> {{c.author.customtitle | safe}}</bdi>{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
@ -599,9 +599,7 @@
|
|||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<textarea required autocomplete="off" minlength="1" maxlength="10000" name="body" form="reply-to-t3_{{c.id}}" data-id="{{c.id}}" class="comment-box form-control rounded" id="reply-form-body-{{c.id}}" aria-label="With textarea" rows="3" oninput="markdown('reply-form-body-{{c.id}}', 'message-reply-{{c.id}}')"></textarea>
|
||||
<div class="comment-format" id="comment-format-bar-{{c.id}}">
|
||||
<label class="btn btn-secondary m-0 mt-3 mr-1" onclick="loadEmojis('reply-form-body-{{c.id}}')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji">
|
||||
<i class="fas fa-smile-beam"></i>
|
||||
</label>
|
||||
<div onclick="loadEmojis('reply-form-body-{{c.id}}')" class="btn btn-secondary m-0 mt-3 mr-1" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
|
||||
{% if c.sentto == 2 %}
|
||||
<label class="btn btn-secondary m-0 mt-3" for="file-upload">
|
||||
|
@ -847,8 +845,8 @@
|
|||
{% endif %}
|
||||
|
||||
{% if v %}
|
||||
<script src="/assets/js/marked.js?v=251"></script>
|
||||
<script src="/assets/js/comments_v.js?v=266"></script>
|
||||
<script src="/assets/js/marked.js?v=253"></script>
|
||||
<script src="/assets/js/comments_v.js?v=269"></script>
|
||||
{% endif %}
|
||||
|
||||
<script src="/assets/js/clipboard.js?v=250"></script>
|
||||
|
@ -860,7 +858,7 @@
|
|||
{% include "expanded_image_modal.html" %}
|
||||
|
||||
<script src="/assets/js/comments+submission_listing.js?v=257"></script>
|
||||
<script src="/assets/js/comments.js?v=256"></script>
|
||||
<script src="/assets/js/comments.js?v=257"></script>
|
||||
|
||||
<script>
|
||||
{% if p and (not v or v.highlightcomments) %}
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'unsafe-eval' ajax.cloudflare.com; connect-src 'self' tls-use1.fpapi.io api.fpjs.io {% if PUSHER_ID != 'blahblahblah' %}{{PUSHER_ID}}.pushnotifications.pusher.com{% endif %}; object-src 'none';">
|
||||
|
||||
<script src="/assets/js/bootstrap.js?v=245"></script>
|
||||
<script src="/assets/js/shortcut handler.js?v=2"></script>
|
||||
{% if v %}
|
||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=268">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=58">
|
||||
<link rel="stylesheet" href="/assets/css/awards.css">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
|
@ -33,8 +34,8 @@
|
|||
{% endif %}
|
||||
{% else %}
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=268">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=57">
|
||||
<link rel="stylesheet" href="/assets/css/awards.css">
|
||||
{% endif %}
|
||||
|
||||
|
@ -351,7 +352,7 @@
|
|||
<script src="/assets/js/formatting.js?v=240"></script>
|
||||
{% endif %}
|
||||
|
||||
<script src="/assets/js/lite-youtube.js?v=240"></script>
|
||||
<script src="/assets/js/lite-youtube.js?v=241"></script>
|
||||
|
||||
</body>
|
||||
|
||||
|
|
|
@ -1,49 +1,32 @@
|
|||
<div id="form" class="d-none"></div>
|
||||
<div class="modal fade" id="emojiModal" tabindex="-1" role="dialog" aria-labelledby="emojiModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-dialog-centered p-2 py-5 emoji-modal" role="document">
|
||||
<style>
|
||||
#emojiTabs {height: 80%;}
|
||||
@media (max-height: 650px) {
|
||||
#emojiTabs {height: 100%;}
|
||||
#emojiModalInternalDivIDK {margin-top: 0 !important; margin-bottom: 0 !important; padding-top: 0 !important; padding-bottom: 0 !important;}
|
||||
|
||||
#emoji-modal-tabs-container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#emoji-modal-tabs {
|
||||
white-space: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
#emoji-modal-tabs li {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div id="emojiModalInternalDivIDK" class="modal-dialog modal-dialog-scrollable modal-dialog-centered p-2 py-5 emoji-modal" role="document">
|
||||
<div class="modal-content" id="emojiTabs">
|
||||
<div class="modal-header">
|
||||
<div>
|
||||
<ul class="nav nav-pills py-2">
|
||||
<div id="emoji-modal-tabs-container">
|
||||
<ul class="nav nav-pills py-2" id="emoji-modal-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active emojitab" data-bs-toggle="tab" href="#emoji-tab-favorite">Favorite</a>
|
||||
</li>
|
||||
|
||||
{% if SITE_NAME == 'Cringetopia' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-cringetopia">Cringetopia</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-marsey">Marsey</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-marseyalphabet">Marsey Alphabet</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-platy">Platy</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-wolf">Zombie Wolf</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-tay">Tay</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-classic">Classic</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-rage">Rage</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-wojak">Wojak</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-flags">Flags</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-misc">Misc</a>
|
||||
<a class="nav-link active emojitab" data-class-name="favorite" data-bs-toggle="tab" href="#" onclick="switchEmojiTab(event)">⭐ Favorite ⭐</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -52,51 +35,65 @@
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div class="px-3"><input autocomplete="off" class="form-control px-2" type="text" id="emoji_search" placeholder="Search.."></div>
|
||||
<div class="px-3">
|
||||
<input disabled autocomplete="off" class="form-control px-2" type="text" id="emoji_search" placeholder="Search..">
|
||||
</div>
|
||||
<div class="px-3 d-flex flex-row">
|
||||
<fieldset class="p-2">
|
||||
<label style="display: inline">Options:</legend>
|
||||
|
||||
<div style="display: inline" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Makes the emoji larger">
|
||||
<input type="checkbox" id="emoji-sel-0" value="#" class="emoji-suffix">
|
||||
<label for="emoji-sel-0">Large</label>
|
||||
</div>
|
||||
|
||||
<div style="display: inline" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Mirror the emoji along the Y axis">
|
||||
<input type="checkbox" id="emoji-sel-1" value="!" class="emoji-suffix">
|
||||
<label for="emoji-sel-1">Mirror</label>
|
||||
</div>
|
||||
|
||||
<div style="display: inline" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Adds a hand that pats the emoji">
|
||||
<input type="checkbox" id="emoji-sel-2" value="pat" class="emoji-postfix">
|
||||
<label for="emoji-sel-2">Pat</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="p-2">
|
||||
<label style="display: inline">Search:</legend>
|
||||
<div style="display: inline" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Iterate through all substrings of the query. YIKES">
|
||||
<input type="checkbox" id="emoji-complete-search">
|
||||
<label for="emoji-complete-search">complete</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div style="overflow-y: scroll;">
|
||||
<div class="modal-body p-0" id="emoji-modal-body">
|
||||
<div id="emoji-tab-search"></div>
|
||||
<div id="no-emojis-found"></div>
|
||||
<div id="tab-content" class="tab-content">
|
||||
<div class="tab-pane fade show active" id="emoji-tab-favorite">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_favorite"></div>
|
||||
<div id="no-emojis-found" class="tab-content py-3 pl-2" hidden>
|
||||
No results... Next time be better with your query. 💅
|
||||
</div>
|
||||
{% if SITE_NAME == 'Cringetopia' %}
|
||||
<div class="tab-pane fade" id="emoji-tab-cringetopia">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_cringetopia"></div>
|
||||
<div id="emojis-work" class="tab-content py-3 pl-2">
|
||||
I am working as hard as I can, sweety... 🚴
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="tab-pane fade" id="emoji-tab-marsey">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_marsey"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-marseyalphabet">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_marseyalphabet"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-platy">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_platy"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-wolf">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_wolf"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-tay">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_tay"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-classic">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_classic"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-rage">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_rage"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-wojak">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_wojak"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-flags">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_flags"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-misc">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_misc"></div>
|
||||
<div id="emoji-new-user" class="tab-content py-3 pl-2" hidden>
|
||||
👋 Hello! This is the first time you're using the emoji system on this device 📱.<br>
|
||||
I've took the liberty to populate this tab with a selection of Anton's emojis 😽. Next time you'll find the ones you used the most in there 📚
|
||||
</div>
|
||||
<div id="tab-content" class="tab-content d-flex flex-wrap py-3 pl-2" hidden>
|
||||
<style>
|
||||
.emoji2 {
|
||||
/*background: None!important;*/
|
||||
width:60px;
|
||||
height: 85px;
|
||||
overflow: hidden;
|
||||
border: none
|
||||
}
|
||||
</style>
|
||||
<template id="emoji-button-template">
|
||||
<button class="btn m-1 px-0 emoji2" data-bs-toggle="tooltip" delay:="0">
|
||||
<img loading="lazy" width=50>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -104,4 +101,4 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/js/emoji_modal.js?v=271"></script>
|
||||
<script src="/assets/js/emoji_modal.js?v=281"></script>
|
|
@ -16,7 +16,7 @@
|
|||
<div class="btn-toolbar justify-content-center mb-4">
|
||||
|
||||
<form action="/allow_nsfw" method="post">
|
||||
<input type="hidden" name="redir" value="{{request.path}}">
|
||||
<input type="hidden" name="redir" value="{{request.full_path}}">
|
||||
<input type="submit" class="btn btn-danger mr-2" value="Yes, I am +18">
|
||||
</form>
|
||||
<div><a href="/" class="btn btn-secondary">No</a></div>
|
||||
|
|
|
@ -79,7 +79,7 @@ Text 2
|
|||
<tr>
|
||||
<td>Video Files</td>
|
||||
<td>https://files.catbox.moe/v4om92.mp4</td>
|
||||
<td><video controls preload="none" class="vid"><source referrerpolicy="no-referrer" src="https://files.catbox.moe/v4om92.mp4" type="video/mp4"></video></td>
|
||||
<td><video controls preload="none"><source referrerpolicy="no-referrer" src="https://files.catbox.moe/v4om92.mp4" type="video/mp4"></video></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Emojis</td>
|
||||
|
@ -101,6 +101,16 @@ Text 2
|
|||
<td>:#!marseylove:</td>
|
||||
<td><img loading="lazy" data-bs-toggle="tooltip" b alt=":!marseylove:" title=":!marseylove:" src="/e/marseylove.webp"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pat Emojis</td>
|
||||
<td>:marseylovepat:</td>
|
||||
<td><span alt=":marseylovepat:" data-bs-toggle="tooltip" title=":marseylovepat:"><img src="/assets/images/hand.webp"><img alt=":marseylovepat:" b="" loading="lazy" pat="" src="/e/marseylove.webp"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pat User</td>
|
||||
<td>:@snappypat:</td>
|
||||
<td><span alt=":@snappypat:" data-bs-toggle="tooltip" title="" data-bs-original-title=":@snappypat:" aria-label=":@snappypat:"><img src="/assets/images/hand.webp"><img alt=":@snappypat:" b="" loading="lazy" pat="" src="/pp/3"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Random Marsey</td>
|
||||
<td>:marseyrandom:</td>
|
||||
|
@ -111,10 +121,19 @@ Text 2
|
|||
<td>#fortune</td>
|
||||
<td>???</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Poll Options (can select multiple options)</td>
|
||||
<td>$$bussy$$ $$gussy$$</td>
|
||||
<td>Random Factcheck</td>
|
||||
<td>#factcheck</td>
|
||||
<td>???</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Poll — Pick Multiple<br>
|
||||
<span style="font-style: italic; font-weight: normal;">
|
||||
* Polls always appear at end of post.
|
||||
</span>
|
||||
</td>
|
||||
<td>$$bussy$$<br>$$gussy$$</td>
|
||||
<td>
|
||||
<div class="custom-control">
|
||||
<input autocomplete="off" type="checkbox" class="custom-control-input" id="422741">
|
||||
|
@ -127,8 +146,13 @@ Text 2
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Poll Options (can select only 1 option)</td>
|
||||
<td>&&bussy&& &&gussy&&</td>
|
||||
<td>
|
||||
Poll — Pick One<br>
|
||||
<span style="font-style: italic; font-weight: normal;">
|
||||
* Polls always appear at end of post.
|
||||
</span>
|
||||
</td>
|
||||
<td>&&bussy&&<br>&&gussy&&</td>
|
||||
<td>
|
||||
<div class="custom-control">
|
||||
<input name="choice" autocomplete="off" type="radio" class="custom-control-input" id="1338113">
|
||||
|
@ -569,18 +593,22 @@ line breaks
|
|||
<td>!slots100</td>
|
||||
<td>Play slots using coins - minimum 100 coins</td>
|
||||
</tr>
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
<tr>
|
||||
<td>!slotsmb100</td>
|
||||
<td>Play slots using marseybux - minimum 100 marseybux</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>!blackjack100</td>
|
||||
<td>Play blackjack using coins - minimum 100 coins</td>
|
||||
</tr>
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
<tr>
|
||||
<td>!blackjackmb100</td>
|
||||
<td>Play blackjack using marseybux - minimum 100 marseybux</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>!wordle</td>
|
||||
<td>Play wordle</td>
|
||||
|
|
|
@ -157,7 +157,9 @@
|
|||
<div class="text-left pl-2">
|
||||
<div style="color: #{{v.namecolor}}" class="text-small font-weight-bold {% if v.patron %}patron{% endif %}"><span {% if v.patron %}class="patron" style="background-color:#{{v.namecolor}}"{% endif %}>{{v.username}}</span></div>
|
||||
<div class="text-small-extra"><img alt="coins" class="mr-1 ml-1" data-bs-toggle="tooltip" data-bs-placement="bottom" height="13" src="/assets/images/{{SITE_NAME}}/coins.webp?v=2" title="coins" aria-label="coins"><span id="user-coins-amount">{{v.coins}}</span> Coins</div>
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
<div class="text-small-extra"><img alt="marseybux" class="mr-1 ml-1" data-bs-toggle="tooltip" data-bs-placement="bottom" height="13" width="30" src="/assets/images/marseybux.webp?v=1008" title="Marseybux" aria-label="Marseybux"><span id="user-bux-amount">{{v.procoins}}</span> Marseybux</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
@ -171,7 +173,7 @@
|
|||
<button class="dropdown-item copy-link" data-clipboard-text="{{SITE_FULL}}/signup?ref={{v.username}}"><i class="fas fa-user-friends fa-fw mr-3"></i>Invite friends</button>
|
||||
</div>
|
||||
<div class="px-2">
|
||||
<a class="dropdown-item" href="/assets/app_{{config('SITE_NAME')}}.apk?v=2"><i class="fab fa-android fa-fw mr-3"></i>Android app</a>
|
||||
<a class="dropdown-item" href="/assets/app_{{config('SITE_NAME')}}_v2.3.apk"><i class="fab fa-android fa-fw mr-3"></i>Android app</a>
|
||||
|
||||
<a class="dropdown-item" href="https://rdrama.net/changelog"><i class="fas fa-clipboard fa-fw mr-3"></i>Changelog</a>
|
||||
|
||||
|
@ -233,7 +235,7 @@
|
|||
</li>
|
||||
{% endif %}
|
||||
|
||||
<a class="nav-item nav-link" href="/assets/app_{{config('SITE_NAME')}}.apk?v=2"><i class="fab fa-android fa-fw mr-3"></i>Android app</a>
|
||||
<a class="nav-item nav-link" href="/assets/app_{{config('SITE_NAME')}}_v2.3.apk"><i class="fab fa-android fa-fw mr-3"></i>Android app</a>
|
||||
|
||||
<a class="nav-item nav-link" rel="nofollow noopener noreferrer" href="https://github.com/Aevann1/rDrama"><i class="fab fa-github fa-fw mr-3"></i>Source code</a>
|
||||
|
||||
|
|
|
@ -56,6 +56,12 @@
|
|||
|
||||
{% block navbar %}
|
||||
<div class="d-flex align-items-center">
|
||||
{% if request.path=='/catalog' %}
|
||||
<a data-bs-toggle="tooltip" data-bs-placement="bottom" title="Catalog View" class="btn btn-primary text-primary mx-2 d-none d-md-block" href="/?sort={{sort}}&t={{t}}&ccmode=false"><i class="fas fa-columns-3 mr-2 "></i>Catalog</a>
|
||||
{% else %}
|
||||
<a data-bs-toggle="tooltip" data-bs-placement="bottom" title="Catalog View" class="btn btn-secondary mx-2 d-none d-md-block" href="/catalog?sort={{sort}}&t={{t}}&ccmode=false"><i class="fas fa-columns-3 mr-2 "></i>Catalog</a>
|
||||
{% endif %}
|
||||
|
||||
{% if v and SITE_NAME == 'rDrama' %}
|
||||
{% if v.paid_dues %}
|
||||
{% if ccmode=="true"%}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
{% block content %}
|
||||
{% if v %}
|
||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=57">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
html {
|
||||
|
@ -31,8 +31,8 @@
|
|||
{% endif %}
|
||||
{% else %}
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=57">
|
||||
{% endif %}
|
||||
|
||||
<div class="row justify-content-around">
|
||||
|
@ -106,7 +106,9 @@
|
|||
<span>{{ma.string | safe}}</span>
|
||||
</div>
|
||||
|
||||
<div class="text-gray-500">{{ma.age_string}} <a href="{{ma.permalink}}"><i class="far fa-link ml-1 text-muted"></i></a>
|
||||
<div class="text-gray-500">
|
||||
<span class="log--item-age" title="{{ ma.created_string }}">{{ma.age_string}}</span>
|
||||
<a href="{{ma.permalink}}"><i class="far fa-link ml-1 text-muted"></i></a>
|
||||
<a role="button" class="copy-link" role="button" data-clipboard-text="{{ma.permalink}}"><i class="far fa-copy ml-1 text-muted"></i></a>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
{% endblock %}
|
||||
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=57">
|
||||
|
||||
</head>
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
<title>2-Step Login - {{SITE_NAME}}</title>
|
||||
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=57">
|
||||
|
||||
</head>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<tr>
|
||||
<td>{{loop.index}}</td>
|
||||
<td>{{marsey.name}}</td>
|
||||
<td><img class="marsey" loading="lazy" data-bs-toggle="tooltip" alt=":{{marsey.name}}:" title=":{{marsey.name}}:" src="/e/{{marsey.name}}.webp"></td>
|
||||
<td><img class="marsey" loading="lazy" data-bs-toggle="tooltip" alt=":#{{marsey.name}}:" title=":{{marsey.name}}:" src="/e/{{marsey.name}}.webp"></td>
|
||||
<td>{{marsey.count}}</td>
|
||||
<td><a style="color:#{{author.namecolor}};font-weight:bold" href="/@{{author.username}}"><img loading="lazy" src="{{author.profile_url}}" class="pp20"><span {% if author.patron %}class="patron" style="background-color:#{{author.namecolor}}"{% endif %}>{{author.username}}</span></a></td>
|
||||
</tr>
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
|
||||
|
||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=57">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
html {
|
||||
|
|
|
@ -39,12 +39,12 @@
|
|||
|
||||
{% if v %}
|
||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=57">
|
||||
{% else %}
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=57">
|
||||
{% endif %}
|
||||
</head>
|
||||
|
||||
|
|
|
@ -449,6 +449,10 @@
|
|||
|
||||
<div class="w-lg-100">
|
||||
|
||||
{% if v.flairchanged %}
|
||||
{% set ti = datetime.utcfromtimestamp(v.flairchanged).strftime('%Y-%m-%d %H:%M:%S') %}
|
||||
{% endif %}
|
||||
|
||||
<form id="profile-settings" action="/settings/title_change" method="post">
|
||||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<input maxlength=100 {% if v.flairchanged %}disabled{% endif %} autocomplete="off" id="customtitlebody" type="text" name="title" class="form-control" placeholder='Enter a flair here' value="{% if v.flairchanged %}Your flair has been locked until {{ti}}{% elif v.customtitleplain %}{{v.customtitleplain}}{% endif %}">
|
||||
|
@ -510,7 +514,7 @@
|
|||
|
||||
<div class="body d-lg-flex border-bottom">
|
||||
|
||||
<label class="text-black w-lg-25">Bluecheck Color</label>
|
||||
<label class="text-black w-lg-25">Checkmark Color</label>
|
||||
|
||||
<div class="d-flex">
|
||||
|
||||
|
@ -544,6 +548,24 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="body d-lg-flex border-bottom">
|
||||
|
||||
<label class="text-black w-lg-25">Checkmark Hover Text</label>
|
||||
|
||||
<div class="w-lg-100">
|
||||
|
||||
<form action="/settings/checkmark_text" method="post">
|
||||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<input minlength=1 maxlength=100 autocomplete="off" id="checkmark_text" type="text" name="title" class="form-control" placeholder='Enter text here' value="{{v.verified}}">
|
||||
<div class="d-flex mt-2">
|
||||
<small>Limit of 100 characters</small>
|
||||
<input autocomplete="off" class="btn btn-primary ml-auto" id="titleSave" type="submit" value="Change Text">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-html="true" title="<img src='/assets/images/chest.webp' width='20'>">
|
||||
Tooltip with HTML
|
||||
</button>
|
||||
|
||||
{% block title %}
|
||||
<title>Shop</title>
|
||||
{% endblock %}
|
||||
|
@ -14,7 +18,9 @@
|
|||
<h5 class="mt-4">Coins spent by you: {{v.coins_spent}} coins</h5>
|
||||
<h5 class="mt-4">Lootboxes bought by you: {{v.lootboxes_bought}} lootbox{{'es' if v.lootboxes_bought != 1}}</h5>
|
||||
<h5 class="mt-4">Your current coins: {{v.coins}}</h5>
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
<h5 class="mt-4">Your current marseybux: {{v.procoins}}</h3>
|
||||
{% endif %}
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -71,8 +77,10 @@
|
|||
<td class="shop-table-owned">{{a['owned']}}</td>
|
||||
{% set kind = a['kind'] %}
|
||||
<td class="shop-table-actions">
|
||||
{% if a['kind'] != "benefactor" %}<a class="d-flex btn btn-success {% if v.coins < a['price'] %}disabled{% endif %}" role="button" onclick="post_toast(this,'/buy/{{kind}}')"><span class="m-auto">Buy with Coins</span></a>{% endif %}
|
||||
{% if a['kind'] != "benefactor" %}<a class="d-flex btn btn-success {% if v.coins < a['price'] %}disabled{% endif %}" role="button" onclick="post_toast(this,'/buy/{{kind}}')"><span class="m-auto">Buy</span></a>{% endif %}
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
{% if a['kind'] != "grass" %}<a class="d-flex marseybux btn btn-success {% if v.procoins < a['price'] %}disabled{% endif %}" role="button" onclick="post_toast(this,'/buy/{{kind}}?mb=true')"><span class="m-auto">Buy with MBux</span></a>{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="shop-table-description">{{a['description']}}</td>
|
||||
</tr>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
<div class="mb-4">{{sub.sidebar_html|safe}}</div>
|
||||
{% endif %}
|
||||
{% if v %}
|
||||
<a class="btn btn-primary btn-block mb-3" href="/create_sub">CREATE HOLE</a>
|
||||
{% if v.mods(sub.name) %}
|
||||
<a class="btn btn-primary btn-block mb-3" href="/h/{{sub.name}}/settings">HOLE SETTINGS</a>
|
||||
{% endif %}
|
||||
|
@ -22,9 +21,6 @@
|
|||
<a class="btn btn-primary btn-block mb-3" href="/h/{{sub.name}}/exilees">HOLE EXILEES</a>
|
||||
<a class="btn btn-primary btn-block mb-3" href="/h/{{sub.name}}/blockers">HOLE BLOCKERS</a>
|
||||
{% else %}
|
||||
<a class="btn btn-primary btn-block mb-3" href="/create_sub">CREATE HOLE</a>
|
||||
<a class="btn btn-primary btn-block mb-3" href="/holes">BROWSE HOLES</a>
|
||||
|
||||
<div class="mt-4">
|
||||
Rules:<br><br>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{% set image=sub.sidebar_url %}
|
||||
{% else %}
|
||||
{% set path = "assets/images/" + SITE_NAME + "/sidebar" %}
|
||||
{% set image = "/" + path + "/" + listdir('files/' + path)|random() + '?v=42' %}
|
||||
{% set image = "/" + path + "/" + listdir('files/' + path)|random() + '?v=44' %}
|
||||
{% endif %}
|
||||
|
||||
{% if v and (v.is_banned or v.agendaposter) %}
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<title>{% if ref_user %}{{ref_user.username}} invites you to {{SITE_NAME}}{% else %}Sign up - {{SITE_NAME}}{% endif %}</title>
|
||||
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=57">
|
||||
|
||||
</head>
|
||||
|
||||
|
@ -111,7 +111,7 @@
|
|||
required="">
|
||||
<div class="custom-control custom-checkbox mt-4">
|
||||
<input autocomplete="off" type="checkbox" class="custom-control-input" id="termsCheck" required>
|
||||
<label class="custom-control-label terms" for="termsCheck">I accept the <a href="/sidebar">rules</a></label>
|
||||
<label class="custom-control-label terms" for="termsCheck">I accept the <a href="/logged_out/sidebar">rules</a></label>
|
||||
</div>
|
||||
|
||||
{% if hcaptcha %}
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
<title>{% if ref_user %}{{ref_user.username}} invites you to {{SITE_NAME}}{% else %}{{SITE_NAME}}{% endif %}</title>
|
||||
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=56">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=57">
|
||||
|
||||
</head>
|
||||
|
||||
|
|
|
@ -4,6 +4,18 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
{% if error %}
|
||||
<div class="alert alert-danger alert-dismissible fade show mb-3 mt-4" role="alert">
|
||||
<i class="fas fa-exclamation-circle my-auto"></i>
|
||||
<span>
|
||||
{{error}}
|
||||
</span>
|
||||
<button class="close" data-bs-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true"><i class="far fa-times"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if msg %}
|
||||
<div class="alert alert-success alert-dismissible fade show my-3" role="alert">
|
||||
<i class="fas fa-check-circle my-auto" aria-hidden="true"></i>
|
||||
|
@ -111,8 +123,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-md-8">
|
||||
<div class="settings">
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
{% if p.award_count("crab") %}
|
||||
<script>
|
||||
let audio = new Audio('/assets/media/crab.mp3');
|
||||
let audio = new Audio('/assets/crab.mp3');
|
||||
audio.loop=true;
|
||||
|
||||
audio.play();
|
||||
|
@ -57,6 +57,12 @@
|
|||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% if SITE_NAME == 'PCM' %}
|
||||
{% set wholesome = '/assets/images/wholesome.webp' %}
|
||||
{% else %}
|
||||
{% set wholesome = '/e/marseywholesome.webp' %}
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("confetti") %}
|
||||
<script src="/assets/js/confetti-js-master/dist/index.min.js"></script>
|
||||
<script src = "/assets/js/confetti.js"></script>
|
||||
|
@ -143,7 +149,7 @@
|
|||
}
|
||||
</style>
|
||||
<div class="seal seal1" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</div>
|
||||
|
||||
{% if p.award_count("wholesome") > 1 %}
|
||||
|
@ -154,7 +160,7 @@
|
|||
}
|
||||
</style>
|
||||
<div class="seal seal2" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
@ -166,7 +172,7 @@
|
|||
}
|
||||
</style>
|
||||
<div class="seal seal3" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
@ -178,7 +184,7 @@
|
|||
}
|
||||
</style>
|
||||
<div class="seal seal4" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
@ -281,7 +287,7 @@
|
|||
<div class="seal" height="100%" width="100%">
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="up" height="100%" width="100%">
|
||||
<marquee direction="right" scrollamount=10 behavior="alternate" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</marquee>
|
||||
</marquee>
|
||||
</div>
|
||||
|
@ -289,7 +295,7 @@
|
|||
{% if p.award_count("wholesome") > 1 %}
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="down" height="100%">
|
||||
<marquee direction="right" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
@ -297,7 +303,7 @@
|
|||
{% if p.award_count("wholesome") > 2 %}
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="up" height="100%">
|
||||
<marquee direction="left" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
@ -305,7 +311,7 @@
|
|||
{% if p.award_count("wholesome") > 3 %}
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="down" height="100%">
|
||||
<marquee direction="left" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
@ -707,7 +713,7 @@
|
|||
|
||||
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1 {% if p.author.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if p.author.verifiedcolor %}#{{p.author.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{p.author.verified}}"></i>
|
||||
{% endif %}
|
||||
<a class="user-name text-decoration-none" onclick='popclick({{p.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color: #{{p.author.namecolor}}; font-weight: bold"class="user-name"><img loading="lazy" src="{{p.author.profile_url}}" class="profile-pic-25 mr-2"><img class="party-hat" src="/assets/images/party-hat.png"><span {% if p.author.patron and not p.distinguish_level %}class="patron" style="background-color:#{{p.author.namecolor}};"{% elif p.distinguish_level %}class="mod"{% endif %}>{{p.author_name}}</span></a>{% if p.author.customtitle %} <bdi style="color: #{{p.author.titlecolor}}"> {{p.author.customtitle | safe}}</bdi>{% endif %}
|
||||
<a class="user-name text-decoration-none" onclick='popclick({{p.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color: #{{p.author.namecolor}}; font-weight: bold"class="user-name"><img loading="lazy" src="{{p.author.profile_url}}" class="profile-pic-25 mr-2">{% if p.author.is_cakeday or True %}<img class="party-hat" src="/assets/images/party-hat.webp" data-bs-toggle="tooltip" data-bs-placement="bottom" title="I’ve spent another year rotting my brain with dramaposting, please ridicule me 🤓">{% endif %}<span {% if p.author.patron and not p.distinguish_level %}class="patron" style="background-color:#{{p.author.namecolor}};"{% elif p.distinguish_level %}class="mod"{% endif %}>{{p.author_name}}</span></a>{% if p.author.customtitle %} <bdi style="color: #{{p.author.titlecolor}}"> {{p.author.customtitle | safe}}</bdi>{% endif %}
|
||||
{% endif %}
|
||||
<span data-bs-toggle="tooltip" data-bs-placement="bottom" id="timestamp" onmouseover="timestamp('timestamp','{{p.created_utc}}')"> {{p.age_string}}</span>
|
||||
({% if p.is_image %}image post{% elif p.is_video %}video post{% elif p.domain %}<a href="/search/posts/?q=domain%3A{{p.domain}}&sort=new&t=all" {% if not v or v.newtabexternal %}target="_blank"{% endif %}>{{p.domain}}</a>{% else %}text post{% endif %})
|
||||
|
@ -782,7 +788,7 @@
|
|||
{% elif p.is_video %}
|
||||
<div class="row no-gutters">
|
||||
<div class="col">
|
||||
<video controls preload="none" class="vid">
|
||||
<video controls preload="none">
|
||||
<source src="{{p.realurl(v)}}" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
|
@ -814,7 +820,7 @@
|
|||
<a class="format btn btn-secondary" role="button"><i class="fas fa-italic" aria-hidden="true" onclick="makeItalics('post-edit-box-{{p.id}}')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Italicize"></i></a>
|
||||
<a class="format btn btn-secondary" role="button"><i class="fas fa-quote-right" aria-hidden="true" onclick="makeQuote('post-edit-box-{{p.id}}')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Quote"></i></a>
|
||||
<a class="format btn btn-secondary" role="button"><span class="font-weight-bolder text-uppercase" onclick="commentForm('post-edit-box-{{p.id}}');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></a>
|
||||
<a class="format btn btn-secondary" role="button"><i class="fas fa-smile-beam" onclick="loadEmojis('post-edit-box-{{p.id}}')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></a>
|
||||
<div onclick="loadEmojis('post-edit-box-{{p.id}}')" class="format btn btn-secondary" role="button" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
|
||||
<label class="format btn btn-secondary m-0 ml-1 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-edit-{{p.id}}">
|
||||
<div id="filename-show-edit-{{p.id}}"><i class="far fa-image"></i></div>
|
||||
|
@ -1012,9 +1018,8 @@
|
|||
<span id="gif-reply-btn-{{p.fullname}}" class="font-weight-bolder text-uppercase" onclick="commentForm('reply-form-body-{{p.fullname}}');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span>
|
||||
</label>
|
||||
|
||||
<label class="btn btn-secondary format d-inline-block m-0" for="emoji-reply-btn-{{p.fullname}}">
|
||||
<div id="emoji-reply-btn-{{p.fullname}}" onclick="loadEmojis('reply-form-body-{{p.fullname}}')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
</label>
|
||||
<div onclick="loadEmojis('reply-form-body-{{p.fullname}}')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn-{{p.fullname}}" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
|
||||
<label class="format btn btn-secondary m-0 ml-1 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-reply-{{p.fullname}}">
|
||||
<div id="filename-show-reply-{{p.fullname}}"><i class="far fa-image"></i></div>
|
||||
<input autocomplete="off" id="file-upload-reply-{{p.fullname}}" type="file" multiple="multiple" name="file" accept="image/*, video/*" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} onchange="changename('filename-show-reply-{{p.fullname}}','file-upload-reply-{{p.fullname}}')" hidden>
|
||||
|
|
|
@ -74,8 +74,41 @@
|
|||
{% endwith %}
|
||||
</div>
|
||||
|
||||
{% if offset %}
|
||||
<script>
|
||||
function viewmore(pid,sort,offset,ids) {
|
||||
btn = document.getElementById("viewbtn");
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = "Requesting...";
|
||||
var form = new FormData();
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("get", `/viewmore/${pid}/${sort}/${offset}?ids=${ids}`);
|
||||
xhr.setRequestHeader('xhr', 'xhr');
|
||||
xhr.onload=function(){
|
||||
if (xhr.status==200) {
|
||||
let e = document.getElementById(`viewmore-${offset}`);
|
||||
e.innerHTML = xhr.response.replace(/data-src/g, 'src').replace(/data-cfsrc/g, 'src').replace(/style="display:none;visibility:hidden;"/g, '');
|
||||
bs_trigger(e)
|
||||
|
||||
|
||||
comments = JSON.parse(localStorage.getItem("old-comment-counts")) || {}
|
||||
lastCount = comments['{{p.id}}']
|
||||
if (lastCount)
|
||||
{
|
||||
{% for c in p.comments %}
|
||||
{% if not (v and v.id==c.author_id) and not c.voted %}
|
||||
if ({{c.created_utc*1000}} > lastCount.t)
|
||||
try {document.getElementById("comment-{{c.id}}-only").classList.add('unread')}
|
||||
catch(e) {}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
btn.disabled = false;
|
||||
}
|
||||
xhr.send(form)
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -81,17 +81,11 @@
|
|||
{% if not postembed %}
|
||||
<div class="voting my-2 d-none d-md-block pr-2">
|
||||
{% if v and request.path.startswith('/@') and v.admin_level < 2 %}
|
||||
|
||||
{% if voted==1 %}
|
||||
<div class="mx-auto arrow-up post-{{p.id}}-up active"></div>
|
||||
{% endif %}
|
||||
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1', '{{v.id}}')" class="post-{{p.id}}-up mx-auto arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% else %}d-none{% endif %}"></div>
|
||||
|
||||
<span class="post-score-{{p.id}} score post-score-{{p.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if p.controversial %} controversial{% endif %}"{% if not p.is_banned %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||
|
||||
{% if voted==-1 %}
|
||||
<div class="text-muted mx-auto arrow-down post-{{p.id}}-down active"></div>
|
||||
{% endif %}
|
||||
|
||||
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '-1', '{{v.id}}')" class="post-{{p.id}}-down text-muted mx-auto arrow-down downvote-button post-{{p.id}}-down {% if voted==-1 %}active{% else %}d-none{% endif %}"></div>
|
||||
{% elif v %}
|
||||
|
||||
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1', '{{v.id}}')" class="post-{{p.id}}-up mx-auto arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% endif %}"></div>
|
||||
|
@ -192,7 +186,7 @@
|
|||
|
||||
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1 {% if p.author.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if p.author.verifiedcolor %}#{{p.author.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{p.author.verified}}"></i>
|
||||
{% endif %}
|
||||
<a class="user-name text-decoration-none" onclick='popclick({{p.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color: #{{p.author.namecolor}}; font-weight: bold;"><img loading="lazy" src="{{p.author.profile_url}}" class="profile-pic-25 mr-2"><img class="party-hat" src="/assets/images/party-hat.png"><span {% if p.author.patron and not p.distinguish_level %}class="patron" style="background-color:#{{p.author.namecolor}};"{% elif p.distinguish_level %}class="mod"{% endif %}>{{p.author_name}}</span></a>{% if p.author.customtitle %}<bdi style="color: #{{p.author.titlecolor}}"> {{p.author.customtitle | safe}}</bdi>{% endif %}
|
||||
<a class="user-name text-decoration-none" onclick='popclick({{p.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color: #{{p.author.namecolor}}; font-weight: bold;"><img loading="lazy" src="{{p.author.profile_url}}" class="profile-pic-25 mr-2">{% if p.author.is_cakeday or True %}<img class="party-hat" src="/assets/images/party-hat.webp" data-bs-toggle="tooltip" data-bs-placement="bottom" title="I’ve spent another year rotting my brain with dramaposting, please ridicule me 🤓">{% endif %}<span {% if p.author.patron and not p.distinguish_level %}class="patron" style="background-color:#{{p.author.namecolor}};"{% elif p.distinguish_level %}class="mod"{% endif %}>{{p.author_name}}</span></a>{% if p.author.customtitle %}<bdi style="color: #{{p.author.titlecolor}}"> {{p.author.customtitle | safe}}</bdi>{% endif %}
|
||||
{% endif %}
|
||||
<span data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('timestamp-{{p.id}}','{{p.created_utc}}')" id="timestamp-{{p.id}}"> {{p.age_string}}</span>
|
||||
|
||||
|
@ -259,29 +253,20 @@
|
|||
{% if v and request.path.startswith('/@') and v.admin_level < 2 %}
|
||||
<li id="voting-{{p.id}}-mobile" class="voting list-inline-item d-md-none">
|
||||
|
||||
{% if voted==1 %}
|
||||
<span class="mr-2 arrow-up post-{{p.id}}-up active">
|
||||
</span>
|
||||
{% endif %}
|
||||
<span tabindex="0" role="button" onclick="vote('post-mobile', '{{p.id}}', '1', '{{v.id}}')" class="post-mobile-{{p.id}}-up mx-0 pr-1 arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% else %}d-none{% endif %}"></span>
|
||||
|
||||
<span class="post-mobile-score-{{p.id}} score post-score-{{p.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if p.controversial %} controversial{% endif %}"{% if not p.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||
|
||||
{% if voted==-1 %}
|
||||
<span class="ml-2 my-0 arrow-down post-{{p.id}}-down active"></span>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<span tabindex="0" role="button" onclick="vote('post-mobile', '{{p.id}}', '-1', '{{v.id}}')" class="post-mobile-{{p.id}}-down mx-0 pl-1 my-0 arrow-down downvote-button post-{{p.id}}-down {% if voted==-1 %}active{% else %}d-none{% endif %}"></span>
|
||||
</li>
|
||||
{% elif v %}
|
||||
<li id="voting-{{p.id}}-mobile" class="voting list-inline-item d-md-none">
|
||||
|
||||
<span tabindex="0" role="button" onclick="vote('post-mobile', '{{p.id}}', '1', '{{v.id}}')" class="post-mobile-{{p.id}}-up mx-0 pr-1 arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% endif %}">
|
||||
</span>
|
||||
<span tabindex="0" role="button" onclick="vote('post-mobile', '{{p.id}}', '1', '{{v.id}}')" class="post-mobile-{{p.id}}-up mx-0 pr-1 arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% endif %}"></span>
|
||||
|
||||
<span class="post-mobile-score-{{p.id}} score post-score-{{p.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if p.controversial %} controversial{% endif %}"{% if not p.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||
|
||||
<span {% if environ.get('DISABLE_DOWNVOTES') == '1' %}style="display:None!important"{% endif %} tabindex="0" role="button" onclick="vote('post-mobile', '{{p.id}}', '-1', '{{v.id}}')" class="post-mobile-{{p.id}}-down mx-0 pl-1 my-0 arrow-down downvote-button post-{{p.id}}-down {% if voted==-1 %}active{% endif %}">
|
||||
</span>
|
||||
<span {% if environ.get('DISABLE_DOWNVOTES') == '1' %}style="display:None!important"{% endif %} tabindex="0" role="button" onclick="vote('post-mobile', '{{p.id}}', '-1', '{{v.id}}')" class="post-mobile-{{p.id}}-down mx-0 pl-1 my-0 arrow-down downvote-button post-{{p.id}}-down {% if voted==-1 %}active{% endif %}"></span>
|
||||
|
||||
</li>
|
||||
{% else %}
|
||||
|
@ -355,7 +340,7 @@
|
|||
</div>
|
||||
{% elif p.is_video %}
|
||||
<div id="video-{{p.id}}" style="text-align: center" class="{% if p.over_18 or not ((v and v.cardview) or (not v and environ.get('CARD_VIEW') == '1')) %}d-none{% endif %} mt-4">
|
||||
<video id="video2-{{p.id}}" controls preload="none" class="vid">
|
||||
<video id="video2-{{p.id}}" controls preload="none">
|
||||
<source src="{{p.realurl(v)}}" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
{% block stylesheets %}
|
||||
{% if v %}
|
||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=49">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
|
@ -51,7 +51,7 @@
|
|||
{% endif %}
|
||||
{% else %}
|
||||
<style>:root{--primary:#{{config('DEFAULT_COLOR')}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=251">
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=267">
|
||||
<link rel="stylesheet" href="/assets/css/{{config('DEFAULT_THEME')}}.css?v=49">
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -96,9 +96,7 @@
|
|||
|
||||
<input autocomplete="off" class="form-control" id="post-title" aria-describedby="titleHelpRegister" type="text" name="title" placeholder="Required" value="{{title}}" minlength="1" maxlength="500" required oninput="checkForRequired();savetext()">
|
||||
|
||||
<label onclick="loadEmojis('post-title')" class="btn btn-secondary format d-inline-block m-0" for="emoji-reply-btn-2">
|
||||
<div id="emoji-reply-btn-2" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
</label>
|
||||
<div onclick="loadEmojis('post-title')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn-2" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
|
||||
<div id="urlblock">
|
||||
<label for="URL" class="mt-3">URL</label>
|
||||
|
@ -146,9 +144,7 @@
|
|||
|
||||
<small class="btn btn-secondary format d-inline-block m-0"><span class="font-weight-bolder text-uppercase" aria-hidden="true" onclick="getGif();commentForm('post-text')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></small>
|
||||
|
||||
<label onclick="loadEmojis('post-text')" class="btn btn-secondary format d-inline-block m-0" for="emoji-reply-btn">
|
||||
<div id="emoji-reply-btn" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
</label>
|
||||
<div onclick="loadEmojis('post-text')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
|
||||
<label class="format btn btn-secondary m-0 ml-1 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-submit">
|
||||
<div id="filename-show-submit"><i class="far fa-image"></i></div>
|
||||
|
@ -228,7 +224,7 @@
|
|||
</script>
|
||||
{% endif %}
|
||||
|
||||
<script src="/assets/js/marked.js?v=251"></script>
|
||||
<script src="/assets/js/marked.js?v=253"></script>
|
||||
<script src="/assets/js/formatting.js?v=240"></script>
|
||||
<script src="/assets/js/submit.js?v=255"></script>
|
||||
{% include "emoji_modal.html" %}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
<div class="d-md-flex text-center text-md-left">
|
||||
<div>
|
||||
<a rel="nofollow noopener noreferrer" href="{% if u.highres %}{{u.highres}}{% else %}{{u.profile_url}}{% endif %}"><img loading="lazy" src="{{u.profile_url}}" class="profile-pic profile-pic-100 mb-5"></a>
|
||||
{% if u.is_cakeday %}<img class="party-hat2" src="/assets/images/party-hat.webp" data-bs-toggle="tooltip" data-bs-placement="bottom" title="I’ve spent another year rotting my brain with dramaposting, please ridicule me 🤓">{% endif %}
|
||||
</div>
|
||||
<div id="profilestuff" class="ml-3 w-100">
|
||||
{% if u.is_suspended %}
|
||||
|
@ -114,8 +115,10 @@
|
|||
<span id="profile-coins-amount">{{u.coins}}</span>
|
||||
<img alt="coins" class="ml-1 mb-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="coins" height="20" src="/assets/images/{{SITE_NAME}}/coins.webp?v=2">
|
||||
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
<span id="profile-bux-amount">{{u.procoins}}</span>
|
||||
<img alt="marseybux" class="ml-1 mb-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Marseybux" height="20" width="46" src="/assets/images/marseybux.webp?v=1008">
|
||||
{% endif %}
|
||||
|
||||
<a href="/@{{u.username}}/followers">{{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}}</a>
|
||||
|
||||
|
@ -175,7 +178,9 @@
|
|||
|
||||
<a class="btn btn-primary" role="button" onclick="post_toast(this,'/@{{u.username}}/suicide')">Get them help</a>
|
||||
<a class="btn btn-primary" role="button" onclick="toggleElement('coin-transfer', 'coin-transfer-amount')">Gift coins</a>
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
<a class="btn btn-primary" role="button" onclick="toggleElement('bux-transfer', 'bux-transfer-amount')">Gift Marseybux</a>
|
||||
{% endif %}
|
||||
|
||||
{% if v.admin_level > 2 %}
|
||||
<a id="admin" class="{% if u.admin_level > 1 %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast2(this,'/@{{u.username}}/make_admin','admin','unadmin')">Make admin</a>
|
||||
|
@ -289,11 +294,6 @@
|
|||
|
||||
<pre></pre>
|
||||
|
||||
{% if v.admin_level > 2 %}
|
||||
<a id="verify" class="{% if u.verified %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast2(this,'/admin/verify/{{u.id}}','verify','unverify')">Verify</a>
|
||||
<a id="unverify" class="{% if not u.verified %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast2(this,'/admin/unverify/{{u.id}}','verify','unverify')">Unverify</a>
|
||||
{% endif %}
|
||||
|
||||
<pre></pre>
|
||||
<form action="/admin/unnuke_user" method="post">
|
||||
<input type="hidden" name="formkey", value="{{v.formkey}}">
|
||||
|
@ -365,6 +365,7 @@
|
|||
<div class="col">
|
||||
<div style="margin-top: -34px;">
|
||||
<a rel="nofollow noopener noreferrer" href="{% if u.highres %}{{u.highres}}{% else %}{{u.profile_url}}{% endif %}"><img loading="lazy" src="{{u.profile_url}}" class="profile-pic-65 bg-white border-2 border-white mb-2"></a>
|
||||
{% if u.is_cakeday %}<img class="party-hat3" src="/assets/images/party-hat.webp" data-bs-toggle="tooltip" data-bs-placement="bottom" title="I’ve spent another year rotting my brain with dramaposting, please ridicule me 🤓">{% endif %}
|
||||
</div>
|
||||
<div class="mt-n3 py-3">
|
||||
{% if u.is_suspended %}
|
||||
|
@ -411,8 +412,10 @@
|
|||
<span id="profile-coins-amount-mobile" class="font-weight-bold">{{u.coins}}</span>
|
||||
<img alt="coins" class="ml-1 mb-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="coins" height="15" src="/assets/images/{{SITE_NAME}}/coins.webp?v=2">
|
||||
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
<span id="profile-bux-amount-mobile" class="font-weight-bold">{{u.procoins}}</span>
|
||||
<img alt="marseybux" class="ml-1 mb-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Marseybux" height="15" width="35" src="/assets/images/marseybux.webp?v=1008">
|
||||
{% endif %}
|
||||
|
||||
<a href="/@{{u.username}}/followers" class="font-weight-bold">{{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}}</a>
|
||||
|
||||
|
@ -486,7 +489,9 @@
|
|||
<a class="btn btn-primary" role="button" onclick="toggleElement('message-mobile', 'input-message-mobile')">Message</a>
|
||||
<a class="btn btn-primary" role="button" onclick="post_toast(this,'/@{{u.username}}/suicide')">Get them help</a>
|
||||
<a class="btn btn-primary" role="button" onclick="toggleElement('coin-transfer-mobile', 'coin-transfer-amount-mobile')">Gift coins</a>
|
||||
{% if SITE_NAME not in ('Cringetopia', 'WPD') %}
|
||||
<a class="btn btn-primary" role="button" onclick="toggleElement('bux-transfer-mobile', 'bux-transfer-amount-mobile')">Gift Marseybux</a>
|
||||
{% endif %}
|
||||
|
||||
{% if v.admin_level > 2 %}
|
||||
<a id="admin2" class="{% if u.admin_level > 1 %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast2(this,'/@{{u.username}}/make_admin','admin2','unadmin2')">Make admin</a>
|
||||
|
@ -598,11 +603,6 @@
|
|||
|
||||
<pre></pre>
|
||||
|
||||
{% if v.admin_level > 2 %}
|
||||
<a id="verify2" class="{% if u.verified %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast2(this,'/admin/verify/{{u.id}}','verify2','unverify2')">Verify</a>
|
||||
<a id="unverify2" class="{% if not u.verified %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast2(this,'/admin/unverify/{{u.id}}','verify2','unverify2')">Unverify</a>
|
||||
{% endif %}
|
||||
|
||||
<pre></pre>
|
||||
<form action="/admin/unnuke_user" method="post">
|
||||
<input type="hidden" name="formkey", value="{{v.formkey}}">
|
||||
|
@ -769,7 +769,7 @@
|
|||
</nav>
|
||||
{% endif %}
|
||||
|
||||
<script src="/assets/js/marked.js?v=251"></script>
|
||||
<script src="/assets/js/marked.js?v=253"></script>
|
||||
|
||||
|
||||
{% if v and v.id != u.id and '/comments' not in request.path %}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
from bs4 import BeautifulSoup
|
||||
from time import time, sleep
|
||||
from files.__main__ import app
|
||||
|
||||
# these tests require `docker-compose up` first
|
||||
|
||||
def test_rules():
|
||||
response = app.test_client().get("/logged_out/rules")
|
||||
assert response.status_code == 200
|
||||
assert response.text.startswith("<!DOCTYPE html>")
|
||||
|
||||
|
||||
def test_signup():
|
||||
client = app.test_client()
|
||||
with client: # this keeps the session between requests, which we need
|
||||
signup_get_response = client.get("/signup")
|
||||
assert signup_get_response.status_code == 200
|
||||
soup = BeautifulSoup(signup_get_response.text, 'html.parser')
|
||||
# these hidden input values seem to be used for anti-bot purposes and need to be submitted
|
||||
formkey = next(tag for tag in soup.find_all("input") if tag.get("name") == "formkey").get("value")
|
||||
form_timestamp = next(tag for tag in soup.find_all("input") if tag.get("name") == "now").get("value")
|
||||
|
||||
sleep(5) # too-fast submissions are rejected (bot check?)
|
||||
username = "testuser" + str(round(time()))
|
||||
signup_post_response = client.post("/signup", data={
|
||||
"username": username,
|
||||
"password": "password",
|
||||
"password_confirm": "password",
|
||||
"email": "",
|
||||
"formkey": formkey,
|
||||
"now": form_timestamp
|
||||
})
|
||||
print(f"Signing up as {username}")
|
||||
assert signup_post_response.status_code == 302
|
||||
assert "error" not in signup_post_response.location
|
||||
|
||||
# we should now be logged in and able to post
|
|
@ -1,3 +0,0 @@
|
|||
git add .
|
||||
git commit -m "force push"
|
||||
git push --force
|
|
@ -1,4 +1,7 @@
|
|||
This code runs https://rdrama.net and https://pcmemes.net
|
||||
[![Build status](https://img.shields.io/github/workflow/status/TheMotte/rDrama/run_tests.py/frost)](https://github.com/Aevann1/rDrama/actions?query=workflow%3Arun_tests.py+branch%3Afrost)
|
||||
|
||||
|
||||
This code runs https://rdrama.net, https://pcmemes.net, https://cringetopia.org, and https://watchpeopledie.co
|
||||
|
||||
# Installation (Windows/Linux/MacOS)
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@ qrcode
|
|||
redis
|
||||
requests
|
||||
SQLAlchemy
|
||||
tldextract
|
||||
psycopg2-binary
|
||||
pusher_push_notifications
|
||||
pyenchant
|
||||
pytest
|
||||
youtube-dl
|
||||
yattag
|
||||
webptools
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# we want to leave the container in whatever state it currently is, so check to see if it's running
|
||||
docker_inspect = subprocess.run([
|
||||
"docker",
|
||||
"container",
|
||||
"inspect",
|
||||
"-f", "{{.State.Status}}",
|
||||
"rDrama",
|
||||
],
|
||||
capture_output = True,
|
||||
).stdout.decode("utf-8").strip()
|
||||
|
||||
was_running = docker_inspect == "running"
|
||||
|
||||
# update containers, just in case they're out of date
|
||||
if was_running:
|
||||
print("Updating containers . . .")
|
||||
else:
|
||||
print("Starting containers . . .")
|
||||
subprocess.run([
|
||||
"docker-compose",
|
||||
"up",
|
||||
"--build",
|
||||
"-d",
|
||||
],
|
||||
check = True,
|
||||
)
|
||||
|
||||
# run the test
|
||||
print("Running test . . .")
|
||||
result = subprocess.run([
|
||||
"docker",
|
||||
"exec",
|
||||
"rDrama",
|
||||
"bash", "-c", "cd service && python3 -m pytest -s"
|
||||
])
|
||||
|
||||
if not was_running:
|
||||
# shut down, if we weren't running in the first place
|
||||
print("Shutting down containers . . .")
|
||||
subprocess.run([
|
||||
"docker-compose",
|
||||
"stop",
|
||||
],
|
||||
check = True,
|
||||
)
|
||||
|
||||
sys.exit(result.returncode)
|
|
@ -593,7 +593,7 @@ CREATE TABLE public.users (
|
|||
patron integer DEFAULT 0 NOT NULL,
|
||||
controversial boolean DEFAULT false NOT NULL,
|
||||
background character varying(20),
|
||||
verified character varying(20),
|
||||
verified character varying(100),
|
||||
cardview boolean NOT NULL,
|
||||
received_award_count integer DEFAULT 0 NOT NULL,
|
||||
highlightcomments boolean DEFAULT true NOT NULL,
|
||||
|
|
23
seed-db.sql
23
seed-db.sql
File diff suppressed because one or more lines are too long
|
@ -598,7 +598,7 @@ Ayoo, you’re fat as fuck!
|
|||
{[para]}
|
||||
AVOCADO NIGGER!
|
||||
{[para]}
|
||||
!slots1000
|
||||
!slots
|
||||
You’re poor, figure it out. Imagine being at the super market looking at the cost of nectors and shit. Fuck you, dude.
|
||||
{[para]}
|
||||
Want to go rape some fire hydrants?
|
||||
|
|
|
@ -28,7 +28,7 @@ I am not sure which is more cringey, the litany of erroneous assumptions you spl
|
|||
{[para]}
|
||||
My god I just checked your post history. There is no shaming you. This is literally your life. Just imagine how much you could accomplish if you weren’t addicted to Reddit. You’re making a difference, though!
|
||||
{[para]}
|
||||
I did a research paper this summer on this subreddit and there was a published study that found that 74% of autists on Reddit came from 1% of source subreddits. I assume that subs like +DeuxRAMA are the 1%.
|
||||
I did a research paper this summer on this subreddit and there was a published study that found that 74% of autists on Reddit came from 1% of source subreddits. I assume that subs like /r/DeuxRAMA are the 1%.
|
||||
{[para]}
|
||||
leave that place it isn't worth it
|
||||
|
||||
|
@ -40,7 +40,7 @@ Look you retards, when the posts here are basically the same thing every single
|
|||
{[para]}
|
||||
Are you a literal NPC? First you had trouble counting to two, now you're just copy and pasting your replies. Do you need some time to update before you can type anything new?
|
||||
{[para]}
|
||||
To OP: NEVER, EVER THREATEN +DEUXRAMA AGAIN OR YOU WILL SUFFER CONSEQUENCES THE LIKES OF WHICH FEW THROUGHOUT HISTORY HAVE EVER SUFFERED BEFORE. WE ARE NO LONGER A SUBREDDIT THAT WILL STAND FOR YOUR DEMENTED WORDS OF VIOLENCE & DEATH. BE CAUTIOUS!
|
||||
To OP: NEVER, EVER THREATEN /r/DEUXRAMA AGAIN OR YOU WILL SUFFER CONSEQUENCES THE LIKES OF WHICH FEW THROUGHOUT HISTORY HAVE EVER SUFFERED BEFORE. WE ARE NO LONGER A SUBREDDIT THAT WILL STAND FOR YOUR DEMENTED WORDS OF VIOLENCE & DEATH. BE CAUTIOUS!
|
||||
{[para]}
|
||||
Bahahhaha. This is totally individualized. First of all. And people don't change, second of all. You should never ever ever get online and preach again. You don't understand reality at all.
|
||||
{[para]}
|
||||
|
@ -175,7 +175,7 @@ wow this faggot did something funny for once 👌👌😄
|
|||
{[para]}
|
||||
This is why we need Islam.
|
||||
{[para]}
|
||||
wait, wait, wait.... hold your horses... uhm... YOU'RE A GIRL DEUXCEL?!!?! O_O Not to be a freak, but.. just when I thought you couldn't get more attractive.. you started posting on +DeuxRAMA. Nicely done, m'lady. You've just become every man's dream woman. If you had missed a couple before, now you can be sure you've got us ALL "drooling", lol.
|
||||
wait, wait, wait.... hold your horses... uhm... YOU'RE A GIRL DEUXCEL?!!?! O_O Not to be a freak, but.. just when I thought you couldn't get more attractive.. you started posting on /r/DeuxRAMA. Nicely done, m'lady. You've just become every man's dream woman. If you had missed a couple before, now you can be sure you've got us ALL "drooling", lol.
|
||||
{[para]}
|
||||
i sleep 😴😴😴
|
||||
{[para]}
|
||||
|
@ -680,7 +680,7 @@ Now, if I did end up in prison somehow, my philosophy would still hold true. Go
|
|||
Son, you have to believe in your own skill set and understand it will take you far. I’ve spent years honing my Nazi punching skills and I’m unstoppable.
|
||||
|
||||
I hope you’ve learned a little something today.
|
||||
s{[para]}
|
||||
{[para]}
|
||||
FUCK OFF AND KYS PATHETIC FAGGOT, YOUR WORTHLESS BOT WAS THE FIRST THING I HAD TO BLOCK ON THIS SITE AND NOW YOU'RE THE SECOND MOTHER RAPING PIECE OF TRASH AND WASTE OF OXYGEN FUCKING DIE DIE DIE PIECE OF SHIT RETARD THAT I NOW ALSO HAVE TO BLOCK.
|
||||
|
||||
YOU DON'T DESERVE LIFE.
|
||||
|
@ -2070,7 +2070,7 @@ Without their kids the illegal women will invariably go insane or kill themselve
|
|||
|
||||
I also want to set up something that looks from the outside like a hippy commune, but is actually a fascist compound - American Juche with Crunchy Granola Characteristics, if you want to get technical. All the women will wear sundresses and sandals, all the men will be jacked, and the only thing vaccinated will be the livestock. As long as we say on paper that our kids are all gay or trans, and all the men and women are gay or trans, we should escape notice until it's too late. If the feds try to pull an ATF we'll put the men in sundresses and play music at them until they go away, or do oiled up Greco-Roman wrestling until they get uncomfortable and look away.
|
||||
{[para]}
|
||||
<pre style="margin-bottom: 0 !important;">
|
||||
<pre>
|
||||
⣿⣿⣿⣿⣿⣿⣿⣿⠟⠛⢉⢉⠉⠉⠻⣿⣿⣿⣿⣿⣿⣿
|
||||
⣿⣿⣿⣿⣿⣿⣿⠟⠠⡰⣕⣗⣷⣧⣀⣅⠘⣿⣿⣿⣿⣿
|
||||
⣿⣿⣿⣿⣿⣿⠃⣠⣳⣟⣿⣿⣷⣿⡿⣜⠄⣿⣿⣿⣿⣿
|
||||
|
@ -2094,7 +2094,7 @@ I also want to set up something that looks from the outside like a hippy commune
|
|||
⠁⠄⠄⠄⠄⠄⠐⡐⠱⡱⣻⡻⣝⣮⣟⣿⣻⣷⣏⣾⢰⣈
|
||||
</pre>
|
||||
{[para]}
|
||||
<pre style="margin-bottom: 0 !important;">
|
||||
<pre>
|
||||
😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂
|
||||
😂🆒🆒🆒🆒🆒🆒🆒🆒🆒🆒🆒🆒🆒😂
|
||||
😂🆒💯🆒🆒🆒💯🆒💯💯💯🆒🆒🆒😂
|
||||
|
@ -3261,7 +3261,7 @@ That I am trapped in this particular irrelevancy is never more apparent to me th
|
|||
{[para]}
|
||||
https://youtube.com/watch?v=5I884gOUONg
|
||||
{[para]}
|
||||
!slots1000
|
||||
!slots
|
||||
{[para]}
|
||||
Fuck you. Dog walkings great. Excellent way to make side cash and get exercise, and being able to immediately make any dog fall in love with you is a skill I use on a monthly basis.
|
||||
|
||||
|
@ -3687,7 +3687,7 @@ It is not surprising that admins would remove such a symbol and this "controvers
|
|||
{[para]}
|
||||
People suggest the worst snappy quotes
|
||||
{[para]}
|
||||
You had your chance. Downvoted and reported. This conversation is over.
|
||||
▼You had your chance. Downvoted and reported. This conversation is over.
|
||||
{[para]}
|
||||
# I just hacked your web application.
|
||||
|
||||
|
@ -3774,3 +3774,50 @@ I probably spent over $400 on this website and generated so much traffic from op
|
|||
Also the creator of this website is the biggest spineless user I’ve ever met. “Nooo I just wanna code I will have a mental breakdown if I have to make a decision”.
|
||||
|
||||
Fuck this website. No loyalty here whatsoever.
|
||||
{[para]}
|
||||
Every part of your existence make the life of everyone else worse. It's impressive how you have only one purpose and it's being a cunt on the internet to strangers.
|
||||
|
||||
You aren't funny, trollish or anything you are just the physical embodiment of an headache.
|
||||
|
||||
I would tell you to kys but I am sure you would find a way to make your suicide insufferable to others if you could even succeed at it.
|
||||
{[para]}
|
||||
|
||||
{[para]}
|
||||
Since the begining of time, women have understood female and masculine nature without any effort. For a man to understand either of the two on the other hand, requires retention. Even if you improve your 'game' as a man, if you remain unaware of the reality of semen and its effects, you will never understand women. The only pathway to understand what a female is is through the mastery of semen.
|
||||
|
||||
When you look at a new woman for the first time, that very first second your eyes focus on her and notice her, mechanisms which have been developed throughout years of evolution take place. In the man who is unaware of his nature, it's all unconscious, literally. The part of him that looks at the woman and evaluates her it's completely out of his control; he is trapped within it. He enjoys it, he protects his ego, unaware that it is a mortal trap. He created this personality throughout years of sexual misconduct. That man, can be controlled like a puppet, by males or females it doesn't matter. That man will enter relationships without having any authority or say in it whatsoever, that man is inferior to women. If women procreate with him, it will only be because they haven't had any access to a retainer. Most advanced retainers know, they just know, how disloyal women can be when confronted with a real retainer. If the man she's with doesn't know anything about semen and lost his edge long ago by having too much sex with her, and the woman is next to a real life retainer, that woman is in danger. Or can be, because it's not like a retainer would be interested on her anyway.
|
||||
|
||||
These men love women, make huge efforts; that is not what women want. Women want you to retain your semen, nothing more. After that, you can treat her like shit, she'll take it. She'll love you for it. After all you are sacrificing your very life for her, although if you are smart you won't have sex with her. If they don't happen to find destiny, the powerful retainer, something they've always longed for, they will settle for the most similar guy to it, and they'll be with him only because the true retainer hasn't called her yet. The life of a guy who does not retain can not be solved just with a bit of retention; yes, retention is key, but the retention moves in flow with the rest of his life, both intertwined and inseparable. Women love the man who is free, because that is the quality the man who retains has. He values himself over women, he will not put the woman on a pedestal.
|
||||
|
||||
Society is made by these men, it raises them, they protect it. Let's not forget society is made by many very different individuals with many different believes, but let's also talk about what the MAJORITY believes in, the message they dictate. They teach men to be sheep, and close their eyes to new possibilities. Men unconscious of their sexuality, unaware of their power. And women who get used to deal with these men.
|
||||
|
||||
So, that very first moment you look at the woman, she has been preparing throughout all of history for that moment. For you, it may just be you looking naively at something attractive, you feeling some inner fun that nobody else sees. But, yes, it's not merely that women are designed to see: their whole lives revolves around it. Women, same as men, are not free from sexual desire. For us, it means that when we look at a beautiful woman we like it, for them, it means they want you to look. The same drive you feel that drives you to feel beauty when you look at a beautiful woman, a woman feels towards dressing beautiful for you.
|
||||
|
||||
So, yes, women know a man to the core. They are born with that knowledge. And it worked pretty well because the man who raises and controls his instincts is rare, they adapt to the men they have to deal with.
|
||||
|
||||
So, understand. Everything you feel, your pride, satisfaction, your failures, your successes, anything you do, anything you try; who you are as a man, your status and your happiness. All that, a woman knows. So, at this point, it would be wise to walk away, at least temporarily. If you feel like you've been living a lie, you should walk your own path until you arrive to someplace you can call home. Unwise minds would use this info in bad faith: I've done it. I've made women fall in love with me so hard, I've been literally worshiped... I remember this one woman, she HAD to make me fall for her, all she did was try to seduce me and give me gifts all the time, that's how uncommon a retainer is. And all I had to do in return was... Nothing. Just lay down and enjoy the show. All because I retained my semen and I also understood female nature. It's a dangerous game though. Obviously I don't care anymore, I'm passed that ego point, I can be at the top or at bottom in terms of female success: I don't care and I'll be the same.
|
||||
|
||||
No woman is special, you are special. Men do not chase women, women chase men. Female nature will be destructive for most men including retainers. There is nothing to gain from women, this should be always clear. It's your own happiness, your own retention, if you follow the path of a woman, you'll end up losing your power unless you know how to be the rock standing still in the river. To know if you are ready to get into a relationship, ask yourself, can I still improve as a single retainer? Have I stopped all emissions of semen including NE? Have I reached all my potential and even if I retained for one more year it wouldn't get better than this?
|
||||
|
||||
The answer to these question may surprise you: your potential is infinite. If you know how to overcome nocturnal emissions, each day of your life you'll be happier, each day of your life if you chose a woman she would fall in love with you even harder. Each day you'll become more powerful, be more in control, women will be puppets to your control, and you won't even care.
|
||||
{[para]}
|
||||
You will always be the most important part of the state apparatus. You have no administrative powers, you have no judicial powers, you are not part of the executive, but that does not matter. You are an excellent writer improved by years of education and ideological development into a beautiful replica of the state’s perfection.
|
||||
|
||||
All the “criticism” you get is from alt-right edge lords and fascists. Behind your back people love you. Your parents are proud of you, and the most powerful tycoons and bureaucrats speak fondly of your consent manufacturing behind closed doors.
|
||||
|
||||
Voters are utterly educated by you. Hundreds of years of democracy have allowed journ*lists to educate voters with incredible efficiency. Even journ*lists who “do not write on politics” have an uncanny and unnatural ability to shape the narrative. Your writing is never a dead giveaway regarding your allegiances. And even if some scizo or linguist convinces people that your articles have an ulterior motive, the voters will turn tail and come back to your narrative the second they get a whiff of the hateful, disinformation-based alternative.
|
||||
|
||||
You will always be happy. You make a real and meaningful difference when you type out the Fortune 500's social narrative every single morning and as a result it’s going to be ok, and deep inside the chuds feel the depression creeping up like a weed, ready to crush them under the unbearable weight of free and unmanipulated democracy.
|
||||
|
||||
Eventually it’ll be too much to bear - they will buy a rope, tie a noose, put it around their neck, and plunge into the cold abyss. An agent of the state will find them, relieved that they no longer have to live with the unbearable freedom and wrongthink that arises from uncontrolled narratives. They’ll bury the chud with a headstone marked with your name, and every passerby for the rest of eternity will know that you saved democracy. Long after you die and go back to the dust, much will remain of your legacy, a state that is unquestionably free.
|
||||
|
||||
This is your fate. This is what you chose. There is no turning back. You are the hero we need, not the hero we deserve.
|
||||
{[para]}
|
||||
|
||||
{[para]}
|
||||
#factcheck
|
||||
{[para]}
|
||||
#fortune
|
||||
{[para]}
|
||||
|
||||
{[para]}
|
||||
|
|
|
@ -5,7 +5,7 @@ logfile=/tmp/supervisord.log
|
|||
|
||||
[program:service]
|
||||
directory=/service
|
||||
command=gunicorn files.__main__:app -k gevent -w 1 --reload -b 0.0.0.0:80 --max-requests 1000 --max-requests-jitter 500
|
||||
command=gunicorn files.__main__:app -k gevent -w 1 --reload -b 0.0.0.0:80 --max-requests 30000 --max-requests-jitter 10000
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
|
|
14
ubuntu_setup
14
ubuntu_setup
|
@ -1,14 +1,14 @@
|
|||
cd /rDrama
|
||||
cp ./env /env
|
||||
. /env
|
||||
sudo apt update
|
||||
sudo apt -y upgrade
|
||||
sudo apt -y install postgresql postgresql-contrib redis-server python3-pip libenchant1c2a ffmpeg
|
||||
apt update
|
||||
apt -y upgrade
|
||||
apt -y install git postgresql postgresql-contrib redis-server python3-pip libenchant1c2a ffmpeg tmux nginx snapd
|
||||
cp pg_hba.conf /etc/postgresql/12/main/pg_hba.conf
|
||||
sudo service postgresql restart
|
||||
sudo psql -U postgres -f schema.sql postgres
|
||||
sudo psql -U postgres -f seed-db.sql postgres
|
||||
sudo pip3 install -r requirements.txt
|
||||
service postgresql restart
|
||||
psql -U postgres -f schema.sql postgres
|
||||
psql -U postgres -f seed-db.sql postgres
|
||||
pip3 install -r requirements.txt
|
||||
mkdir /songs
|
||||
mkdir /images
|
||||
snap install opera-proxy
|
||||
|
|
Loading…
Reference in New Issue