diff --git a/docker-compose.yml b/docker-compose.yml index 7cab26997..691c16797 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,44 +6,10 @@ services: context: . volumes: - "./:/service" + env_file: env environment: - DATABASE_URL=postgresql://postgres@postgres:5432 - - MASTER_KEY=3435tdfsdudebussylmaoxxt43 - REDIS_URL=redis://redis - - DOMAIN=localhost - - SITE_NAME=Drama - - GIPHY_KEY=3435tdfsdudebussylmaoxxt43 - - DISCORD_SERVER_ID=3435tdfsdudebussylmaoxxt43 - - DISCORD_CLIENT_ID=3435tdfsdudebussylmaoxxt43 - - DISCORD_CLIENT_SECRET=3435tdfsdudebussylmaoxxt43 - - DISCORD_BOT_TOKEN=3435tdfsdudebussylmaoxxt43 - #- HCAPTCHA_SITEKEY=3435tdfsdudebussylmaoxxt43 - - HCAPTCHA_SECRET=3435tdfsdudebussylmaoxxt43 - - YOUTUBE_KEY=3435tdfsdudebussylmaoxxt43 - #- PUSHER_ID=3435tdfsdudebussylmaoxxt43 - - PUSHER_KEY=3435tdfsdudebussylmaoxxt43 - - IMGUR_KEY=3435tdfsdudebussylmaoxxt43 - - SPAM_SIMILARITY_THRESHOLD=0.5 - - SPAM_URL_SIMILARITY_THRESHOLD=0.1 - - SPAM_SIMILAR_COUNT_THRESHOLD=10 - - COMMENT_SPAM_SIMILAR_THRESHOLD=0.5 - - COMMENT_SPAM_COUNT_THRESHOLD=10 - - READ_ONLY=0 - - BOT_DISABLE=0 - - DEFAULT_TIME_FILTER=all - - DEFAULT_THEME=midnight - - DEFAULT_COLOR=ff66ac - - GUMROAD_TOKEN=3435tdfsdudebussylmaoxxt43 - - GUMROAD_LINK=https://marsey1.gumroad.com/l/tfcvri - - GUMROAD_ID=tfcvri - - CARD_VIEW=1 - - DISABLE_DOWNVOTES=0 - - DUES=0 - - MAIL_USERNAME=blahblahblah@gmail.com - - MAIL_PASSWORD=3435tdfsdudebussylmaoxxt43 - - DESCRIPTION=rdrama.net caters to drama in all forms such as Real life, videos, photos, gossip, rumors, news sites, Reddit, and Beyond™. There isn't drama we won't touch, and we want it all! - - CF_KEY=3435tdfsdudebussylmaoxxt43 - - CF_ZONE=3435tdfsdudebussylmaoxxt43 links: - "redis" - "postgres" diff --git a/env.sh b/env similarity index 93% rename from env.sh rename to env index 5f75c2e03..27da3b208 100644 --- a/env.sh +++ b/env @@ -1,4 +1,3 @@ -export DATABASE_URL="postgresql://postgres@localhost:5432" export MASTER_KEY="3435tdfsdudebussylmaoxxt43" export DOMAIN="localhost" export SITE_NAME="Drama" diff --git a/files/__main__.py b/files/__main__.py index c5c967b75..df1558a8b 100644 --- a/files/__main__.py +++ b/files/__main__.py @@ -30,7 +30,7 @@ faulthandler.enable() app.config["SITE_NAME"]=environ.get("SITE_NAME").strip() app.config["GUMROAD_LINK"]=environ.get("GUMROAD_LINK", "https://marsey1.gumroad.com/l/tfcvri").strip() app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False -app.config['DATABASE_URL'] = environ.get("DATABASE_URL") +app.config['DATABASE_URL'] = environ.get("DATABASE_URL", "postgresql://postgres@localhost:5432") app.config['SECRET_KEY'] = environ.get('MASTER_KEY') app.config["SERVER_NAME"] = environ.get("DOMAIN").strip() app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 2628000 diff --git a/files/classes/comment.py b/files/classes/comment.py index ac4dd90a4..64b2235b2 100644 --- a/files/classes/comment.py +++ b/files/classes/comment.py @@ -242,12 +242,7 @@ class Comment(Base): @property @lazy def permalink(self): - if self.post and self.post.club: - if self.post.sub: f"{SITE_FULL}/s/{self.post.sub}/comment/{self.id}?context=8#context" - else: f"{SITE_FULL}/comment/{self.id}?context=8#context" - - if self.post: return f"{self.post.permalink}/{self.id}?context=8#context" - else: return f"{SITE_FULL}/comment/{self.id}?context=8#context" + return f"{SITE_FULL}/comment/{self.id}?context=8#context" @property @lazy diff --git a/files/classes/mod.py b/files/classes/mod.py index 1d5aafcdd..3b1f2d7aa 100644 --- a/files/classes/mod.py +++ b/files/classes/mod.py @@ -1,12 +1,20 @@ from sqlalchemy import * from sqlalchemy.orm import relationship from files.__main__ import Base +from files.helpers.lazy import * +from time import strftime, gmtime class Mod(Base): __tablename__ = "mods" user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) sub = Column(String, ForeignKey("subs.name"), primary_key=True) + created_utc = Column(Integer) def __repr__(self): - return f"" \ No newline at end of file + return f"" + + @property + @lazy + def created_datetime(self): + return str(strftime("%d/%B/%Y %H:%M:%S UTC", gmtime(self.created_utc))) \ No newline at end of file diff --git a/files/classes/sub.py b/files/classes/sub.py index c7b9f92ce..852decaa3 100644 --- a/files/classes/sub.py +++ b/files/classes/sub.py @@ -2,9 +2,11 @@ from sqlalchemy import * from files.__main__ import Base from files.helpers.lazy import lazy from os import environ -from files.helpers.const import * SITE_NAME = environ.get("SITE_NAME", '').strip() +SITE = environ.get("DOMAIN", '').strip() +if SITE == "localhost": SITE_FULL = 'http://' + SITE +else: SITE_FULL = 'https://' + SITE class Sub(Base): @@ -14,6 +16,7 @@ class Sub(Base): sidebar_html = Column(String) sidebarurl = Column(String) bannerurl = Column(String) + css = Column(String) def __repr__(self): return f"" diff --git a/files/classes/user.py b/files/classes/user.py index 8acc2eda4..3c88a2557 100644 --- a/files/classes/user.py +++ b/files/classes/user.py @@ -153,7 +153,14 @@ class User(Base): @lazy def mods(self, sub): - return self.admin_level > 1 or g.db.query(Mod.user_id).filter_by(user_id=self.id, sub=sub).one_or_none() + return self.id == AEVANN_ID or g.db.query(Mod.user_id).filter_by(user_id=self.id, sub=sub).one_or_none() + + @lazy + def mod_date(self, sub): + if self.id == AEVANN_ID: return 1 + mod = g.db.query(Mod).filter_by(user_id=self.id, sub=sub).one_or_none() + if not mod: return None + return mod.created_utc @property @lazy diff --git a/files/helpers/const.py b/files/helpers/const.py index 580c5192b..fc9581d1e 100644 --- a/files/helpers/const.py +++ b/files/helpers/const.py @@ -362,6 +362,14 @@ AWARDS = { "color": "text-pink", "price": 300 }, + "scooter": { + "kind": "scooter", + "title": "Scooter", + "description": "Summons a scooter on the post.", + "icon": "fas fa-flag-usa", + "color": "text-muted", + "price": 300 + }, "wholesome": { "kind": "wholesome", "title": "Wholesome", @@ -369,6 +377,14 @@ AWARDS = { "icon": "fas fa-smile-beam", "color": "text-yellow", "price": 300 + }, + "tilt": { + "kind": "tilt", + "title": "Tilt", + "description": "Tilts the post by 1 degree (up to 4)", + "icon": "fas fa-car-tilt", + "color": "text-blue", + "price": 300 }, "ghosts": { "kind": "ghosts", diff --git a/files/helpers/sanitize.py b/files/helpers/sanitize.py index a91ab44f8..629dab803 100644 --- a/files/helpers/sanitize.py +++ b/files/helpers/sanitize.py @@ -7,7 +7,11 @@ from os import path, environ import re from mistletoe import markdown from json import loads, dump -from random import random +from random import random, choice + +db = db_session() +marseys = tuple(x[0] for x in db.query(Marsey.name).all()) +db.close() allowed_tags = tags = ['b', 'blockquote', @@ -203,7 +207,9 @@ def sanitize(sanitized, noimages=False, alert=False, comment=False, edit=False): classes = 'emoji-md' remoji = emoji - if not edit and random() < 0.005 and 'marsey' in emoji: classes += ' golden' + if not edit and random() < 0.005 and ('marsey' in emoji or emoji in marseys): classes += ' golden' + + if remoji == 'marseyrandom': remoji = choice(marseys) if path.isfile(f'files/assets/images/emojis/{remoji}.webp'): new = re.sub(f'(?', new, re.I) @@ -218,14 +224,20 @@ def sanitize(sanitized, noimages=False, alert=False, comment=False, edit=False): if emoji.startswith("!"): emoji = emoji[1:] classes = 'emoji mirrored' - if not edit and random() < 0.005 and 'marsey' in emoji: classes += ' golden' + if not edit and random() < 0.005 and ('marsey' in emoji or emoji in marseys): classes += ' golden' + + if emoji == 'marseyrandom': emoji = random.choice(marseys) + if path.isfile(f'files/assets/images/emojis/{emoji}.webp'): sanitized = re.sub(f'(?', sanitized, re.I) if comment: marseys_used.add(emoji) elif path.isfile(f'files/assets/images/emojis/{emoji}.webp'): classes = 'emoji' - if not edit and random() < 0.005 and 'marsey' in emoji: classes += ' golden' + if not edit and random() < 0.005 and ('marsey' in emoji or emoji in marseys): classes += ' golden' + + if emoji == 'marseyrandom': emoji = random.choice(marseys) + sanitized = re.sub(f'(?', sanitized, re.I) if comment: marseys_used.add(emoji) @@ -284,13 +296,19 @@ def filter_emojis_only(title, edit=False): if emoji.startswith("!"): emoji = emoji[1:] classes = 'emoji mirrored' - if not edit and random() < 0.005 and 'marsey' in emoji: classes += ' golden' + if not edit and random() < 0.005 and ('marsey' in emoji or emoji in marseys): classes += ' golden' + + if emoji == 'marseyrandom': emoji = random.choice(marseys) + if path.isfile(f'files/assets/images/emojis/{emoji}.webp'): title = re.sub(f'(?', title, re.I) elif path.isfile(f'files/assets/images/emojis/{emoji}.webp'): classes = 'emoji' - if not edit and random() < 0.005 and 'marsey' in emoji: classes += ' golden' + if not edit and random() < 0.005 and ('marsey' in emoji or emoji in marseys): classes += ' golden' + + if emoji == 'marseyrandom': emoji = random.choice(marseys) + title = re.sub(f'(?', title, re.I) if len(title) > 1500: abort(400) diff --git a/files/routes/awards.py b/files/routes/awards.py index 7464633f4..a0d9957a8 100644 --- a/files/routes/awards.py +++ b/files/routes/awards.py @@ -42,6 +42,14 @@ AWARDS3 = { "color": "text-pink", "price": 300 }, + "scooter": { + "kind": "scooter", + "title": "Scooter", + "description": "Summons a scooter on the post.", + "icon": "fas fa-flag-usa", + "color": "text-muted", + "price": 300 + }, "wholesome": { "kind": "wholesome", "title": "Wholesome", @@ -50,6 +58,14 @@ AWARDS3 = { "color": "text-yellow", "price": 300 }, + "tilt": { + "kind": "tilt", + "title": "Tilt", + "description": "Tilts the post by 1 degree (up to 4)", + "icon": "fas fa-car-tilt", + "color": "text-blue", + "price": 300 + }, } @app.get("/shop") diff --git a/files/routes/comments.py b/files/routes/comments.py index 8c9939e26..09bcce398 100644 --- a/files/routes/comments.py +++ b/files/routes/comments.py @@ -956,6 +956,49 @@ def unpin_comment(cid, v): g.db.commit() return {"message": "Comment unpinned!"} + +@app.post("/mod_pin/") +@auth_required +def mod_pin(cid, v): + + comment = get_comment(cid, v=v) + + if not comment: abort(404) + + if not (comment.post.sub and v.mods(comment.post.sub)): abort(403) + + comment.is_pinned = v.username + " (Mod)" + + g.db.add(comment) + + if v.id != comment.author_id: + message = f"@{v.username} (Mod) has pinned your [comment]({comment.permalink})!" + send_repeatable_notification(comment.author_id, message) + + g.db.commit() + return {"message": "Comment pinned!"} + + +@app.post("/mod_unpin/") +@auth_required +def mod_unpin(cid, v): + + comment = get_comment(cid, v=v) + + if not comment: abort(404) + + if not (comment.post.sub and v.mods(comment.post.sub)): abort(403) + + comment.is_pinned = None + g.db.add(comment) + + if v.id != comment.author_id: + message = f"@{v.username} (Mod) has unpinned your [comment]({comment.permalink})!" + send_repeatable_notification(comment.author_id, message) + g.db.commit() + return {"message": "Comment unpinned!"} + + @app.post("/save_comment/") @limiter.limit("1/second;30/minute;200/hour;1000/day") @auth_required diff --git a/files/routes/subs.py b/files/routes/subs.py index b198099b7..947e507c4 100644 --- a/files/routes/subs.py +++ b/files/routes/subs.py @@ -9,18 +9,18 @@ valid_sub_regex = re.compile("^[a-zA-Z0-9_\-]{3,25}$") @app.get("/s//mods") @is_not_permabanned def mods(v, sub): - sub = g.db.query(Sub).filter_by(name=sub.lower()).one_or_none() + sub = g.db.query(Sub).filter_by(name=sub.strip().lower()).one_or_none() if not sub: abort(404) - mods = [x[0] for x in g.db.query(Mod.user_id).filter_by(sub=sub.name).all()] - users = g.db.query(User).filter(User.id.in_(mods)).all() + users = g.db.query(User, Mod).join(Mod, Mod.user_id==User.id).filter_by(sub=sub.name).order_by(Mod.created_utc).all() + return render_template("sub/mods.html", v=v, sub=sub, users=users) @app.post("/s//add_mod") @is_not_permabanned def add_mod(v, sub): - sub = g.db.query(Sub).filter_by(name=sub.lower()).one_or_none() + sub = g.db.query(Sub).filter_by(name=sub.strip().lower()).one_or_none() if not sub: abort(404) sub = sub.name @@ -32,10 +32,41 @@ def add_mod(v, sub): user = get_user(user) - mod = Mod(user_id=user.id, sub=sub) - g.db.add(mod) + existing = g.db.query(Mod).filter_by(user_id=user.id, sub=sub).one_or_none() - send_repeatable_notification(user.id, f"You have been added as a mod to /s/{sub}") + if not existing: + mod = Mod(user_id=user.id, sub=sub, created_utc=int(time.time())) + g.db.add(mod) + + send_repeatable_notification(user.id, f"You have been added as a mod to /s/{sub}") + + g.db.commit() + + return redirect(f'/s/{sub}/mods') + + +@app.post("/s//remove_mod") +@is_not_permabanned +def remove_mod(v, sub): + sub = g.db.query(Sub).filter_by(name=sub.strip().lower()).one_or_none() + if not sub: abort(404) + sub = sub.name + + if not v.mods(sub): abort(403) + + uid = request.values.get('uid') + + if not uid: abort(400) + + try: uid = int(uid) + except: abort(400) + + mod = g.db.query(Mod).filter_by(user_id=uid, sub=sub).one_or_none() + if not mod: abort(400) + + g.db.delete(mod) + + send_repeatable_notification(uid, f"You have been removed as a mod from /s/{sub}") g.db.commit() @@ -70,7 +101,7 @@ def create_sub2(v): sub = Sub(name=name) g.db.add(sub) - mod = Mod(user_id=v.id, sub=sub.name) + mod = Mod(user_id=v.id, sub=sub.name, created_utc=int(time.time())) g.db.add(mod) g.db.commit() @@ -111,26 +142,47 @@ def sub_settings(v, sub): @limiter.limit("1/second;30/minute;200/hour;1000/day") @is_not_permabanned def post_sub_sidebar(v, sub): - sub = g.db.query(Sub).filter_by(name=sub.lower()).one_or_none() + sub = g.db.query(Sub).filter_by(name=sub.strip().lower()).one_or_none() if not sub: abort(404) if not v.mods(sub.name): abort(403) - sub.sidebar = request.values.get('sidebar', '').strip() + sub.sidebar = request.values.get('sidebar', '').strip()[:500] sub.sidebar_html = sanitize(sub.sidebar) - g.db.add(sub) + if len(sub.sidebar_html) > 1000: return "Sidebar is too big!" - ma = ModAction( - kind="change_sidebar", - user_id=v.id - ) - g.db.add(ma) + g.db.add(sub) g.db.commit() return redirect(f'/s/{sub.name}/settings') +@app.post('/s//css') +@limiter.limit("1/second;30/minute;200/hour;1000/day") +@is_not_permabanned +def post_sub_css(v, sub): + sub = g.db.query(Sub).filter_by(name=sub.strip().lower()).one_or_none() + if not sub: abort(404) + + if not v.mods(sub.name): abort(403) + + sub.css = request.values.get('css', '').strip() + g.db.add(sub) + + g.db.commit() + + return redirect(f'/s/{sub.name}/settings') + + +@app.get("/s//css") +def get_sub_css(sub): + sub = g.db.query(Sub).filter_by(name=sub.strip().lower()).one_or_none() + if not sub: abort(404) + resp=make_response(sub.css or "") + resp.headers.add("Content-Type", "text/css") + return resp + @app.post("/s//banner") @limiter.limit("1/second;30/minute;200/hour;1000/day") @is_not_permabanned diff --git a/files/routes/users.py b/files/routes/users.py index c60d1d0f9..1d8faf1ec 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -392,9 +392,7 @@ def leaderboard(v): @app.get("/@/css") def get_css(username): user = get_user(username) - if user.css: css = user.css - else: css = "" - resp=make_response(css) + resp=make_response(user.css or "") resp.headers.add("Content-Type", "text/css") return resp diff --git a/files/templates/admin/sidebar.html b/files/templates/admin/sidebar.html index a0f29c8a7..ab5d6e1c4 100644 --- a/files/templates/admin/sidebar.html +++ b/files/templates/admin/sidebar.html @@ -25,7 +25,7 @@
-
+ diff --git a/files/templates/authforms.html b/files/templates/authforms.html index 78b6e21c1..08326aff7 100644 --- a/files/templates/authforms.html +++ b/files/templates/authforms.html @@ -15,7 +15,7 @@ {% if v %} - + {% if v.agendaposter %} {% if v %} - + {% endif %} diff --git a/files/templates/default.html b/files/templates/default.html index 31d9002d1..8abd47785 100644 --- a/files/templates/default.html +++ b/files/templates/default.html @@ -7,7 +7,7 @@ {% if v %} - + {% if v.agendaposter %} - + {% endif %} + {% if sub and sub.css and not request.path.endswith('settings') %} + + {% endif %} + @@ -217,9 +221,7 @@ {% if v %} {% if sub %} - - /s/{[sub.name]} banner - + /s/{{sub.name}} banner {% elif SITE_NAME == 'Drama' %} {% set path = "assets/images/" + SITE_NAME + "/banners_bhm" %} {% set image = "/static/" + path + "/" + listdir('files/' + path)|random() + '?a=21' %} diff --git a/files/templates/emoji_modal.html b/files/templates/emoji_modal.html index 3635da6dd..dbea2f1a2 100644 --- a/files/templates/emoji_modal.html +++ b/files/templates/emoji_modal.html @@ -18,6 +18,9 @@ + @@ -69,6 +72,9 @@
+
+
+
@@ -100,7 +106,7 @@
- + - + {% if v.agendaposter %} - + {% endif %}
diff --git a/files/templates/login.html b/files/templates/login.html index 158f0bb23..1f54c9ee1 100644 --- a/files/templates/login.html +++ b/files/templates/login.html @@ -18,7 +18,7 @@ {% endblock %} - + diff --git a/files/templates/login_2fa.html b/files/templates/login_2fa.html index 99d8b2820..43933efb9 100644 --- a/files/templates/login_2fa.html +++ b/files/templates/login_2fa.html @@ -14,7 +14,7 @@ 2-Step Login - {{SITE_NAME}} - + diff --git a/files/templates/notifications.html b/files/templates/notifications.html index 3bfc65f7d..e86535253 100644 --- a/files/templates/notifications.html +++ b/files/templates/notifications.html @@ -30,7 +30,7 @@ Messages - {% if v.admin_level > 2 %} + {% if v.admin_level > 1 %}
+ + +

Banner

@@ -84,6 +86,8 @@
+ +
@@ -93,9 +97,34 @@
-
+ - + + +
+ +
+
+
+
+
+
+ + + + +
+
+
+
+

Edit CSS

+
+
+
+
+
+ +
diff --git a/files/templates/submission.html b/files/templates/submission.html index 84c8666b5..064cc4972 100644 --- a/files/templates/submission.html +++ b/files/templates/submission.html @@ -153,23 +153,13 @@ {% endif %} {% endif %} -{% if p.award_count("train") %} +{% if p.award_count("train") or p.award_count("scooter") %} +{% endif %} + +{% if p.award_count("train") %} + :#marseytrain: @@ -208,6 +213,54 @@ {% endif %} + +{% if p.award_count("scooter") %} + + + :#marseyscooter: + +{% endif %} + +{% if p.award_count("scooter") > 1 %} + + :#marseyscooter: + +{% endif %} + +{% if p.award_count("scooter") > 2 %} + + :#marseyscooter: + +{% endif %} + +{% if p.award_count("scooter") > 3 %} + + :#marseyscooter: + +{% endif %} + + + +{% if p.award_count("tilt") %} + +{% endif %} + + diff --git a/files/templates/submission_listing.html b/files/templates/submission_listing.html index 541848e90..5959db266 100644 --- a/files/templates/submission_listing.html +++ b/files/templates/submission_listing.html @@ -129,7 +129,7 @@ post thumnail {% elif p.is_image %} - post thumnail + sidebar image {% elif p.is_video %} post thumnail diff --git a/files/templates/submit.html b/files/templates/submit.html index be3e22a20..63c7f225f 100644 --- a/files/templates/submit.html +++ b/files/templates/submit.html @@ -26,7 +26,7 @@ {% block stylesheets %} {% if v %} - + {% if v.agendaposter %} - + {% endif %} {% endblock %} @@ -257,7 +257,7 @@ checkForRequired() - + {% include "emoji_modal.html" %} diff --git a/files/templates/userpage.html b/files/templates/userpage.html index d45d16d63..0147f2cd4 100644 --- a/files/templates/userpage.html +++ b/files/templates/userpage.html @@ -704,7 +704,7 @@ {% if v %}
{% if v.patron or u.patron or v.alts_patron or u.alts_patron %}0{% else %}0.03{% endif %}
- +
{{u.username}}
{% endif %} @@ -734,7 +734,7 @@ {% endif %} - +