forked from rDrama/rDrama
1
0
Fork 0

Compare commits

...

42 Commits

Author SHA1 Message Date
Aevann 1dfd4e1e06 Revert "shorter code"
This reverts commit e8374fb515.
2024-02-16 01:12:53 +02:00
Aevann e8374fb515 shorter code 2024-02-16 01:10:40 +02:00
Aevann eaa21370c9 fix 500 error 2024-02-16 01:05:32 +02:00
Aevann e213883f89 fix 500 error 2024-02-16 01:04:12 +02:00
Aevann 55daca6a20 make blocking not work for public_use holes 2024-02-16 01:02:22 +02:00
Aevann d97128fb07 log effortpost actions for me 2024-02-16 00:38:30 +02:00
Aevann 4b04e9bed6 retard-proof hole snappy quotes 2024-02-16 00:24:38 +02:00
Aevann 495400435f disallow mods from usurping groups, so they dont kick the latest month of memberships and usurp it 2024-02-16 00:17:04 +02:00
Aevann 7785dae3a8 remove now-unnecessary bool 2024-02-16 00:05:33 +02:00
Aevann a1fc1a9972 shorter var 2024-02-16 00:03:01 +02:00
Aevann ab91a9cbb6 fix 500 error 2024-02-16 00:02:49 +02:00
SneedBot 255e591ec9 sneed 2024-02-15 22:02:14 +00:00
Aevann 23d993496d remove print-debugging 2024-02-16 00:00:48 +02:00
Aevann 36abb0b397 confused as hell 2024-02-15 23:59:47 +02:00
Aevann 1e884878d8 print-debug 2024-02-15 23:58:03 +02:00
Aevann a8db5e8cbf update award description 2024-02-15 23:56:13 +02:00
Aevann 5785f7daaf print-debug 2024-02-15 23:54:56 +02:00
Aevann 36b1f5abd0 fix this https://rdrama.net/h/music/post/246274/mozart-leck-mich-im-arsch-canon/5950545#context 2024-02-15 23:47:05 +02:00
SneedBot 8e8d6fe48d sneed 2024-02-15 21:38:26 +00:00
Aevann 17375c753a make it so unblockable users cant block others 2024-02-15 23:38:00 +02:00
Aevann b5f046b1c9 fix sidebar image in localhost 2024-02-15 23:34:18 +02:00
Aevann 775169b2ab add public use mode 2024-02-15 23:34:09 +02:00
Aevann 946eb07949 better var name 2024-02-15 22:14:28 +02:00
Aevann 23ddbd047e add default for stealth column 2024-02-15 22:09:47 +02:00
SneedBot da1c744d15 sneed 2024-02-15 20:02:14 +00:00
SneedBot 1676482e9a sneed 2024-02-15 20:00:15 +00:00
SneedBot a33954558d sneed 2024-02-15 19:54:14 +00:00
Aevann 7009a6ffc6 fix this https://rdrama.net/post/18459/marseycapywalking-megathread-for-bugs-and-suggestions/5949837#context 2024-02-15 21:53:45 +02:00
SneedBot 46412f664c sneed 2024-02-15 19:40:43 +00:00
Aevann 4e449851e2 linkify reports, flairs, and group descriptions 2024-02-15 21:35:38 +02:00
Aevann 5b304cbbed remove unused import 2024-02-15 21:12:37 +02:00
Aevann 23d77a165a add tabs 2024-02-15 21:12:29 +02:00
Aevann 18fdd429bf add margin and emoji button 2024-02-15 21:01:52 +02:00
Aevann 9642aa64d9 increase description_html max length 2024-02-15 21:01:40 +02:00
Aevann b00aea67a4 fix group warning on mobile 2024-02-15 20:48:51 +02:00
Aevann 6c7eb8a3b2 do this https://watchpeopledie.tv/h/meta/post/61549/megathread-for-bugs-and-suggestions/2715484#context 2024-02-15 20:48:36 +02:00
Aevann fad0f736f3 fix error message 2024-02-15 20:36:01 +02:00
Aevann 73226a79a0 do this https://rdrama.net/post/245957/anyone-know-the-lore-on-this/5943668#context 2024-02-15 20:31:31 +02:00
Aevann 89713985ff Revert "move report box in post_listing.html"
This reverts commit 6c9069a196.
2024-02-15 20:28:26 +02:00
Aevann af4a6a5f92 fix emoji name 2024-02-15 20:25:03 +02:00
Aevann 631007a7f7 add lines 2024-02-15 19:25:57 +02:00
Aevann 5282126293 APPS_MODERATION should be JL4 2024-02-15 19:06:31 +02:00
37 changed files with 298 additions and 153 deletions

View File

@ -220,7 +220,7 @@
.queen:not(a) img, .queen:not(.ectoplasm), h1.queen.post-title a {
color: hotpink !important;
font-weight: 700 !important;
text-transform: lowercase !important;
text-transform: lowercase;
}
.sharpen:not(a):not(.blood), h1.sharpen.post-title a {

View File

@ -7719,3 +7719,9 @@ thead {
left: calc(50% - 122px);
}
}
@media (min-width: 768px) {
#group-warning {
max-width: 50%
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -16,6 +16,7 @@ class Group(Base):
created_utc = Column(Integer)
owner_id = Column(Integer, ForeignKey("users.id"))
description = Column(String)
description_html = Column(String)
memberships = relationship("GroupMembership", primaryjoin="GroupMembership.group_name==Group.name", order_by="GroupMembership.approved_utc")
owner = relationship("User", primaryjoin="Group.owner_id==User.id")

View File

@ -22,7 +22,8 @@ class Hole(Base):
bannerurls = Column(MutableList.as_mutable(ARRAY(VARCHAR(HOLE_BANNER_URL_COLUMN_LENGTH))), default=MutableList([]))
marseyurl = Column(VARCHAR(HOLE_MARSEY_URL_LENGTH))
css = deferred(Column(VARCHAR(CSS_LENGTH_LIMIT)))
stealth = Column(Boolean)
stealth = Column(Boolean, default=False)
public_use = Column(Boolean, default=False)
created_utc = Column(Integer)
if SITE_NAME == 'WPD':
snappy_quotes = None
@ -31,7 +32,7 @@ class Hole(Base):
blocks = relationship("HoleBlock", primaryjoin="HoleBlock.hole==Hole.name")
followers = relationship("HoleFollow", primaryjoin="HoleFollow.hole==Hole.name")
joins = relationship("StealthHoleUnblock", lazy="dynamic", primaryjoin="StealthHoleUnblock.hole==Hole.name")
stealth_hole_unblocks = relationship("StealthHoleUnblock", lazy="dynamic", primaryjoin="StealthHoleUnblock.hole==Hole.name")
def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -60,8 +61,8 @@ class Hole(Base):
@property
@lazy
def join_num(self):
return self.joins.count()
def stealth_hole_unblock_num(self):
return self.stealth_hole_unblocks.count()
@property
@lazy

View File

@ -465,11 +465,13 @@ class User(Base):
@property
@lazy
def hole_blocks(self):
stealth = set(x[0] for x in g.db.query(Hole.name).filter_by(stealth=True))
stealth = stealth - set(x[0] for x in g.db.query(StealthHoleUnblock.hole).filter_by(user_id=self.id))
stealth = {x[0] for x in g.db.query(Hole.name).filter_by(stealth=True)}
stealth = stealth - {x[0] for x in g.db.query(StealthHoleUnblock.hole).filter_by(user_id=self.id)}
if self.chud == 1: stealth = stealth - {'chudrama'}
return list(stealth) + [x[0] for x in g.db.query(HoleBlock.hole).filter_by(user_id=self.id)]
public_use = {x[0] for x in g.db.query(Hole.name).filter_by(public_use=True)}
return stealth | {x[0] for x in g.db.query(HoleBlock.hole).filter_by(user_id=self.id)} - public_use
@lazy
def blocks(self, hole):

View File

@ -85,8 +85,14 @@ def bleach_body_html(body_html, runtime=False):
attributes=allowed_attributes,
protocols=['http', 'https'],
css_sanitizer=css_sanitizer,
filters=[partial(LinkifyFilter, skip_tags=["pre"],
parse_email=False, url_re=sanitize_url_regex)]
filters=[
partial(
LinkifyFilter,
skip_tags=["pre"],
parse_email=False,
url_re=sanitize_url_regex
)
]
).clean(body_html)
return body_html

View File

@ -832,7 +832,7 @@ AWARDS = {
"unblockable": {
"kind": "unblockable",
"title": "Unblockable",
"description": "Makes the recipient unblockable and removes all blocks on them.",
"description": "Makes the recipient unblockable and removes all blocks on them at the cost of being unable to block others.",
"icon": "fas fa-laugh-squint",
"color": "text-lightgreen",
"price": 20000,

View File

@ -196,7 +196,6 @@ PERMS = { # Minimum admin_level to perform action.
'SITE_SETTINGS': 3,
'SITE_CACHE_PURGE_CDN': 3,
'NOTIFICATIONS_FROM_SHADOWBANNED_USERS': 3,
'APPS_MODERATION': 3,
'USE_ADMIGGER_THREADS': 3,
'MODERATE_PENDING_SUBMITTED_ASSETS': 3,
'UPDATE_ASSETS': 3,
@ -220,6 +219,7 @@ PERMS = { # Minimum admin_level to perform action.
'CLAIM_REWARDS_ALL_USERS': 4,
'IGNORE_AWARD_IMMUNITY': 4,
'INSERT_TRANSACTION': 4,
'APPS_MODERATION': 4,
'MODS_EVERY_HOLE': 5,
'MODS_EVERY_GROUP': 5,

View File

@ -94,6 +94,16 @@ HOLEACTION_TYPES = {
"icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-muted'
},
'enable_public_use': {
"str": 'enabled public use mode',
"icon": 'fa-users',
"color": 'bg-primary'
},
'disable_public_use': {
"str": 'disabled public use mode',
"icon": 'fa-users',
"color": 'bg-muted'
},
'enable_stealth': {
"str": 'enabled stealth mode',
"icon": 'fa-user-ninja',

View File

@ -458,6 +458,7 @@ MODACTION_PRIVILEGED_TYPES = {
'schedule_orgy', 'remove_orgy',
'insert_transaction',
'change_under_siege',
'mark_effortpost', 'unmark_effortpost',
}
MODACTION_PRIVILEGED__TYPES = {'progstack_post', 'progstack_comment',
'unprogstack_post', 'unprogstack_comment'}

View File

@ -238,7 +238,7 @@ sanitize_url_regex = re.compile(
###REDDIT
#sanitizing
reddit_mention_regex = re.compile('(^|\s)\/?((r|u)\/[\w-]{2,25})' + NOT_IN_CODE_OR_LINKS, flags=re.I|re.A)
reddit_mention_regex = re.compile('([>\s])\/?((r|u)\/[\w-]{2,25})' + NOT_IN_CODE_OR_LINKS, flags=re.I|re.A)
reddit_domain_regex = re.compile("(^|\s|\()https?:\/\/(redd.it\/|((www\.|new\.)?reddit\.com|teddit\.net|libreddit\.hu|redd\.it)\/(u\/|user\/|(r\/\w{2,25}\/)?comments\/|r\/\w{2,25}\/?$))", flags=re.A)
reddit_comment_link_regex = re.compile("https:\/\/old.reddit.com\/r\/\w{2,25}\/comments(\/\w+){3}\/?.*", flags=re.A)

View File

@ -10,7 +10,6 @@ import requests
from sqlalchemy.sql import func
import bleach
from bleach.css_sanitizer import CSSSanitizer
from bleach.linkifier import LinkifyFilter
from bs4 import BeautifulSoup
from mistletoe import markdown
@ -136,7 +135,7 @@ def find_all_emoji_endings(emoji):
emoji = emoji[:-8]
continue
if emoji.endswith('love') and emoji not in {'marseycornlove', 'marseycapylove'}:
if emoji.endswith('love') and emoji not in {'marseycornlove', 'capylove'}:
if 'love' in endings:
is_non_ending_found = True
continue
@ -620,7 +619,7 @@ def allowed_attributes_emojis(tag, name, value):
@with_sigalrm_timeout(2)
def filter_emojis_only(title, golden=True, count_emojis=False, obj=None, author=None):
def filter_emojis_only(title, golden=True, count_emojis=False, obj=None, author=None, link=False):
title = title.replace("\n", "").replace("\r", "").replace("\t", "").replace('<','&lt;').replace('>','&gt;')
@ -652,7 +651,29 @@ def filter_emojis_only(title, golden=True, count_emojis=False, obj=None, author=
title = strikethrough_regex.sub(r'\1<del>\2</del>', title)
title = bleach.clean(title, tags=['img','del','span'], attributes=allowed_attributes_emojis, protocols=['http','https']).replace('\n','')
if link:
title = bleach.Cleaner(
tags=['img','del','span'],
attributes=allowed_attributes_emojis,
protocols=['http','https'],
filters=[
partial(
LinkifyFilter,
skip_tags=["pre"],
parse_email=False,
url_re=sanitize_url_regex
)
]
).clean(title)
else:
title = bleach.clean(
title,
tags=['img','del','span'],
attributes=allowed_attributes_emojis,
protocols=['http','https']
)
title = title.replace('\n','')
if len(title) > POST_TITLE_HTML_LENGTH_LIMIT:
abort(400, "Rendered title is too long!")

View File

@ -882,7 +882,7 @@ def shadowban(user_id, v):
reason = filter_emojis_only(reason)
if len(reason) > 256:
abort(400, "Ban reason is too long (max 256 characters)")
abort(400, "Rendered shadowban reason is too long!")
user.shadowban_reason = reason
g.db.add(user)
@ -945,7 +945,7 @@ def admin_change_flair(user_id, v):
abort(400, "New flair is too long (max 256 characters)")
user.flair = new_flair
new_flair = filter_emojis_only(new_flair)
new_flair = filter_emojis_only(new_flair, link=True)
new_flair = censor_slurs_profanities(new_flair, None)
user = get_account(user.id)
@ -1417,7 +1417,7 @@ def remove_post(post_id, v):
def approve_post(post_id, v):
post = get_post(post_id)
if post.chudded and post.ban_reason == 'AutoJanny':
if post.chudded and post.author.chud and post.ban_reason == 'AutoJanny':
abort(400, "You can't bypass the chud award!")
if post.is_banned:
@ -1653,7 +1653,7 @@ def remove_comment(c_id, v):
def approve_comment(c_id, v):
comment = get_comment(c_id)
if comment.chudded and comment.ban_reason == 'AutoJanny':
if comment.chudded and comment.author.chud and comment.ban_reason == 'AutoJanny':
abort(400, "You can't bypass the chud award!")
if comment.is_banned:

View File

@ -412,7 +412,7 @@ def award_thing(v, thing_type, id):
author.flairchanged += 86400
else:
author.flair = new_flair
new_flair = filter_emojis_only(new_flair)
new_flair = filter_emojis_only(new_flair, link=True)
new_flair = censor_slurs_profanities(new_flair, None)
if len(new_flair) > 1000: abort(403)
author.flair_html = new_flair
@ -470,7 +470,14 @@ def award_thing(v, thing_type, id):
badge_grant(badge_id=84, user=author)
elif kind == "unblockable":
badge_grant(badge_id=87, user=author)
for block in g.db.query(UserBlock).filter_by(target_id=author.id): g.db.delete(block)
blocks = g.db.query(UserBlock).filter(
or_(
UserBlock.user_id == author.id,
UserBlock.target_id == author.id,
)
)
for block in blocks:
g.db.delete(block)
elif kind == "progressivestack":
if not FEATURES['PINS']:
abort(403)

View File

@ -308,6 +308,9 @@ def group_usurp(v, group_name):
group = g.db.get(Group, group_name)
if not group: abort(404)
if v.mods_group(group):
abort(403, f"You're a mod of /h/{group.name} can't usurp it!")
if not v.is_member_of_group(group):
abort(403, "Only members of groups can usurp them!")
@ -353,10 +356,18 @@ def group_change_description(v, group_name):
if description:
description = description.strip()
if len(description) > 100:
abort(400, "New description is too long (max 100 characters)")
description_html = filter_emojis_only(description, link=True)
if len(description_html) > 1000:
abort(400, "Rendered description is too long!")
else:
description = None
description_html = None
group.description = description
group.description_html = description_html
g.db.add(group)
return {"message": 'Description changed successfully!'}

View File

@ -16,13 +16,15 @@ from files.__main__ import app, cache, limiter
@auth_required
def exile_post(v, pid):
p = get_post(pid)
hole = p.hole
hole = p.hole_obj
if not hole: abort(400)
if not v.mods_hole(hole): abort(403)
if hole.public_use:
abort(403, "You can't exile users while Public Use mode is enabled!")
if hole in {'atheism', 'dioceseofrdrama', 'truth'}:
abort(403, f"/h/{hole} has the exiling feature disabled due to being unblockable.")
hole = hole.name
if not v.mods_hole(hole): abort(403)
u = p.author
@ -53,13 +55,15 @@ def exile_post(v, pid):
@auth_required
def exile_comment(v, cid):
c = get_comment(cid)
hole = c.post.hole
hole = c.post.hole_obj
if not hole: abort(400)
if not v.mods_hole(hole): abort(403)
if hole.public_use:
abort(403, "You can't exile users while Public Use mode is enabled!")
if hole in {'atheism', 'dioceseofrdrama', 'truth'}:
abort(403, f"/h/{hole} has the exiling feature disabled due to being unblockable.")
hole = hole.name
if not v.mods_hole(hole): abort(403)
u = c.author
@ -116,10 +120,13 @@ def unexile(v, hole, uid):
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def block_sub(v, hole):
if hole in {'atheism', 'dioceseofrdrama', 'truth'}:
abort(403, f"/h/{hole} is unblockable!")
hole = get_hole(hole)
if hole.public_use:
abort(403, f"/h/{hole} has Public Use mode enabled and is unblockable!")
hole = hole.name
hole = get_hole(hole).name
existing = g.db.query(HoleBlock).filter_by(user_id=v.id, hole=hole).one_or_none()
if not existing:
block = HoleBlock(user_id=v.id, hole=hole)
@ -846,6 +853,41 @@ def hole_stealth(v, hole):
g.db.add(ma)
return {"message": f"Stealth mode has been disabled for /h/{hole} successfully!"}
@app.post('/h/<hole>/public_use')
@limiter.limit('1/second', scope=rpath)
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def hole_public_use(v, hole):
hole = get_hole(hole)
if not v.mods_hole(hole.name): abort(403)
hole.public_use = not hole.public_use
g.db.add(hole)
exiles = g.db.query(Exile).filter_by(hole=hole.name)
for exile in exiles:
send_repeatable_notification(exile.user_id, f"Your exile from /h/{exile.hole} has been revoked due to its jannies enabling Public Use mode!")
g.db.delete(exile)
if hole.public_use:
ma = HoleAction(
hole=hole.name,
kind='enable_public_use',
user_id=v.id
)
g.db.add(ma)
return {"message": f"Public Use mode has been enabled for /h/{hole} successfully!"}
else:
ma = HoleAction(
hole=hole.name,
kind='disable_public_use',
user_id=v.id
)
g.db.add(ma)
return {"message": f"Public Use mode has been disabled for /h/{hole} successfully!"}
@app.post("/pin_comment_mod/<int:cid>")
@feature_required('PINS')
@ -991,6 +1033,9 @@ def post_hole_snappy_quotes(v, hole):
if not v.mods_hole(hole.name): abort(403)
if v.shadowbanned: abort(400)
if snappy_quotes.endswith('[para]'):
snappy_quotes = snappy_quotes[:-6].strip()
if len(snappy_quotes) > HOLE_SNAPPY_QUOTES_LENGTH:
abort(400, f"Quotes are too long (max {HOLE_SNAPPY_QUOTES_LENGTH} characters)")

View File

@ -53,9 +53,11 @@ def _add_post_view(pid):
@is_not_banned
def publish(pid, v):
p = get_post(pid)
if not p.private: return {"message": "Post published!"}
if p.author_id != v.id: abort(403)
p.private = False
p.created_utc = int(time.time())
g.db.add(p)

View File

@ -27,7 +27,7 @@ def report_post(pid, v):
abort(400, "Report reason is too long (max 100 characters)")
og_flair = reason[1:]
reason_html = filter_emojis_only(reason)
reason_html = filter_emojis_only(reason, link=True)
if len(reason_html) > 350:
abort(400, "Rendered report reason is too long!")
@ -95,7 +95,7 @@ def report_comment(cid, v):
if len(reason) > 100:
abort(400, "Report reason is too long (max 100 characters)")
reason_html = filter_emojis_only(reason)
reason_html = filter_emojis_only(reason, link=True)
if len(reason_html) > 350:
abort(400, "Rendered report reason is too long!")

View File

@ -715,6 +715,9 @@ def settings_blocks(v):
@limiter.limit("20/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def settings_block_user(v):
if v.unblockable:
abort(403, "You're unblockable so you can't block others!")
user = get_user(request.values.get("username"))
if user.unblockable:
@ -957,7 +960,7 @@ def settings_change_flair(v):
flair = process_settings_plaintext("flair", v.flair, 100, None)
if flair:
flair_html = filter_emojis_only(flair)
flair_html = filter_emojis_only(flair, link=True)
flair_html = censor_slurs_profanities(flair_html, None)
if len(flair_html) > 1000:

View File

@ -1,125 +1,130 @@
{% extends "default.html" %}
{%- import 'util/macros.html' as macros with context -%}
{% block pagetitle %}!{{group}}{% endblock %}
{% block content %}
{% if v.id != group.owner_id %}
<button id="leave-{{group}}" type="button" class="mt-4 btn btn-danger btn-block {% if v.id not in group.membership_user_ids %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group}}/leave','leave-{{group}}','apply-{{group}}','d-none')">
{%- if v.id in group.member_ids or group.name == 'verifiedrich' -%}
Leave
{%- else -%}
Cancel Application
{%- endif -%}
</button>
<div class="mx-2">
{% if v.id != group.owner_id %}
<button id="leave-{{group}}" type="button" class="mt-4 btn btn-danger btn-block {% if v.id not in group.membership_user_ids %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group}}/leave','leave-{{group}}','apply-{{group}}','d-none')">
{%- if v.id in group.member_ids or group.name == 'verifiedrich' -%}
Leave
{%- else -%}
Cancel Application
{%- endif -%}
</button>
<button id="apply-{{group}}" type="button" class="mt-4 {% if v.id in group.membership_user_ids %}d-none{% endif %} btn btn-success btn-block" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group}}/apply','leave-{{group}}','apply-{{group}}','d-none')">{% if group.name != 'verifiedrich' %}Apply to {% endif %}Join</button>
{% endif %}
<button id="apply-{{group}}" type="button" class="mt-4 {% if v.id in group.membership_user_ids %}d-none{% endif %} btn btn-success btn-block" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group}}/apply','leave-{{group}}','apply-{{group}}','d-none')">{% if group.name != 'verifiedrich' %}Apply to {% endif %}Join</button>
{% endif %}
{% if v.id == group.owner_id %}
<h5 class="mt-5">!{{group}} Description</h3>
<form class="mt-3" action="/!{{group.name}}/description" method="post" data-nonce="{{g.nonce}}" data-onsubmit="sendFormXHR(this)">
<div class="container pb-0" style="background-color: transparent !important">
<div class="row">
<div class="col col-md-6 px-0 py-3 py-md-0">
<div class="body">
<input hidden name="formkey" value="{{v|formkey}}">
<input maxlength="100" class="form-control" type="text" name="description" {% if group.description %}value="{{group.description}}"{% endif %}>
<small>Limit of 100 characters</small>
<div class="footer">
<div class="d-flex">
<button type="submit" class="btn btn-primary ml-auto">Submit</button>
{% if v.id == group.owner_id %}
{% include "modals/emoji.html" %}
<h5 class="mt-5">!{{group}} Description</h3>
<form class="mt-3" action="/!{{group.name}}/description" method="post" data-nonce="{{g.nonce}}" data-onsubmit="sendFormXHR(this)">
<div class="container pb-0" style="background-color: transparent !important">
<div class="row">
<div class="col col-md-6 px-0 py-3 py-md-0">
<div class="body">
<input hidden name="formkey" value="{{v|formkey}}">
<input id="edit-group-description" maxlength="100" class="form-control allow-emojis" type="text" name="description" {% if group.description %}value="{{group.description}}"{% endif %}>
{{macros.emoji_btn('edit-group-description')}}
<div class="footer">
<div class="d-flex">
<small class="mt-2">Limit of 100 characters</small>
<button type="submit" class="btn btn-primary ml-auto">Submit</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
{% elif group.description %}
<h5 class="mt-5">!{{group}} Description</h3>
<p class="mb-2">{{group.description}}</p>
{% endif %}
</form>
{% elif group.description_html %}
<h5 class="mt-5">!{{group}} Description</h3>
<p class="mb-2">{{group.description_html | safe}}</p>
{% endif %}
<br>
{% macro process_memberships(memberships, name) %}
<h5 class="my-3">!{{group}} {{name}}</h5>
<br>
{% macro process_memberships(memberships, name) %}
<h5 class="my-3">!{{group}} {{name}}</h5>
<div class="overflow-x-auto mt-1">
<table class="ping-groups">
<thead>
<tr>
<th>#</th>
<th>Name</th>
{% if name == 'members' %}
<th>Approved on</th>
{% else %}
<th>Applied on</th>
{% endif %}
{% if v.is_member_of_group(group) or v.mods_group(group) %}
<th class="disable-sort-click"></th>
{% endif %}
</tr>
</thead>
<tbody id="{{name}}_tbody">
{% for membership in memberships %}
<tr id="{{membership.user_id}}">
<td id="counter-{{membership.user_id}}">{{loop.index}}</td>
{% set is_owner = membership.user_id == group.owner_id %}
<td {% if is_owner %}class="unbreakable"{% endif %}>
{% with user=membership.user %}
{% include "user_in_table.html" %}
{% endwith %}
{% if is_owner %}
<img class="mx-2 group-owner" data-bs-toggle="tooltip" alt="Owner" title="Owner" src="{{SITE_FULL_IMAGES}}/e/marseykingretard.webp">
{% elif membership.is_mod %}
<img class="mx-2 group-mod" data-bs-toggle="tooltip" alt="Mod" title="Mod" src="{{SITE_FULL_IMAGES}}/e/marseyjanny.webp">
{% endif %}
</td>
<div class="overflow-x-auto mt-1">
<table class="ping-groups">
<thead>
<tr>
<th>#</th>
<th>Name</th>
{% if name == 'members' %}
<td id="time-{{membership.user_id}}" data-time="{{membership.approved_utc}}"></td>
<th>Approved on</th>
{% else %}
<td id="time-{{membership.user_id}}" data-time="{{membership.created_utc}}"></td>
<th>Applied on</th>
{% endif %}
<td>
{% if v.mods_group(group) %}
{% if v.id == group.owner_id and v.id != membership.user_id %}
<div id="mod-{{membership.user_id}}" class="mb-2 {% if name == 'applications' %}d-none{% endif %}">
<button id="add-mod-{{membership.user_id}}" type="button" class="btn btn-success btn-block {% if membership.is_mod %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group.name}}/{{membership.user_id}}/add_mod','add-mod-{{membership.user_id}}','remove-mod-{{membership.user_id}}','d-none')">Add as Mod</button>
<button id="remove-mod-{{membership.user_id}}" type="button" class="btn btn-danger btn-block {% if not membership.is_mod %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group.name}}/{{membership.user_id}}/remove_mod','add-mod-{{membership.user_id}}','remove-mod-{{membership.user_id}}','d-none')">Remove as Mod</button>
</div>
{% endif %}
{% if v.id == membership.user_id or v.id == group.owner_id or not membership.user.mods_group(group) %}
<div id="kick-{{membership.user_id}}" {% if name == 'applications' %}class="d-none"{% endif %}>
<button type="button" class="btn btn-danger btn-block" data-nonce="{{g.nonce}}" data-onclick="reject_membership(this,'{{group}}','{{membership.user_id}}')">{% if v.id == membership.user_id %}Leave{% else %}Kick{% endif %}</button>
</div>
{% endif %}
<div {% if name == 'members' %}class="d-none"{% endif %}>
<button type="button" class="btn btn-success btn-block" data-nonce="{{g.nonce}}" data-onclick="approve_membership(this,'{{group}}','{{membership.user_id}}')">Approve</button>
<button type="button" class="btn btn-danger btn-block" data-nonce="{{g.nonce}}" data-onclick="reject_membership(this,'{{group}}','{{membership.user_id}}')">Reject</button>
</div>
{% endif %}
{% if v.is_member_of_group(group) and is_owner and v.id != group.owner_id %}
<button type="button" class="btn btn-danger btn-block" data-nonce="{{g.nonce}}" data-onclick="areyousure(this)" data-areyousure="postToastReload(this,'/!{{group}}/usurp')">Usurp</button>
{% endif %}
</td>
{% if v.is_member_of_group(group) or v.mods_group(group) %}
<th class="disable-sort-click"></th>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endmacro %}
</thead>
<tbody id="{{name}}_tbody">
{% for membership in memberships %}
<tr id="{{membership.user_id}}">
<td id="counter-{{membership.user_id}}">{{loop.index}}</td>
{% set is_owner = membership.user_id == group.owner_id %}
<td {% if is_owner %}class="unbreakable"{% endif %}>
{% with user=membership.user %}
{% include "user_in_table.html" %}
{% endwith %}
{% if is_owner %}
<img class="mx-2 group-owner" data-bs-toggle="tooltip" alt="Owner" title="Owner" src="{{SITE_FULL_IMAGES}}/e/marseykingretard.webp">
{% elif membership.is_mod %}
<img class="mx-2 group-mod" data-bs-toggle="tooltip" alt="Mod" title="Mod" src="{{SITE_FULL_IMAGES}}/e/marseyjanny.webp">
{% endif %}
</td>
{% if v.mods_group(group) %}
{{process_memberships(applications, 'applications')}}
{{process_memberships(members, 'members')}}
<script defer src="{{'js/group_members_owner.js' | asset}}"></script>
{% else %}
{{process_memberships(members, 'members')}}
{{process_memberships(applications, 'applications')}}
{% endif %}
{% if name == 'members' %}
<td id="time-{{membership.user_id}}" data-time="{{membership.approved_utc}}"></td>
{% else %}
<td id="time-{{membership.user_id}}" data-time="{{membership.created_utc}}"></td>
{% endif %}
<td>
{% if v.mods_group(group) %}
{% if v.id == group.owner_id and v.id != membership.user_id %}
<div id="mod-{{membership.user_id}}" class="mb-2 {% if name == 'applications' %}d-none{% endif %}">
<button id="add-mod-{{membership.user_id}}" type="button" class="btn btn-success btn-block {% if membership.is_mod %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group.name}}/{{membership.user_id}}/add_mod','add-mod-{{membership.user_id}}','remove-mod-{{membership.user_id}}','d-none')">Add as Mod</button>
<button id="remove-mod-{{membership.user_id}}" type="button" class="btn btn-danger btn-block {% if not membership.is_mod %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group.name}}/{{membership.user_id}}/remove_mod','add-mod-{{membership.user_id}}','remove-mod-{{membership.user_id}}','d-none')">Remove as Mod</button>
</div>
{% endif %}
{% if v.id == membership.user_id or v.id == group.owner_id or not membership.user.mods_group(group) %}
<div id="kick-{{membership.user_id}}" {% if name == 'applications' %}class="d-none"{% endif %}>
<button type="button" class="btn btn-danger btn-block" data-nonce="{{g.nonce}}" data-onclick="reject_membership(this,'{{group}}','{{membership.user_id}}')">{% if v.id == membership.user_id %}Leave{% else %}Kick{% endif %}</button>
</div>
{% endif %}
<div {% if name == 'members' %}class="d-none"{% endif %}>
<button type="button" class="btn btn-success btn-block" data-nonce="{{g.nonce}}" data-onclick="approve_membership(this,'{{group}}','{{membership.user_id}}')">Approve</button>
<button type="button" class="btn btn-danger btn-block" data-nonce="{{g.nonce}}" data-onclick="reject_membership(this,'{{group}}','{{membership.user_id}}')">Reject</button>
</div>
{% endif %}
{% if v.is_member_of_group(group) and is_owner and v.id != group.owner_id %}
<button type="button" class="btn btn-danger btn-block" data-nonce="{{g.nonce}}" data-onclick="areyousure(this)" data-areyousure="postToastReload(this,'/!{{group}}/usurp')">Usurp</button>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endmacro %}
{% if v.mods_group(group) %}
{{process_memberships(applications, 'applications')}}
{{process_memberships(members, 'members')}}
<script defer src="{{'js/group_members_owner.js' | asset}}"></script>
{% else %}
{{process_memberships(members, 'members')}}
{{process_memberships(applications, 'applications')}}
{% endif %}
</div>
{% endblock %}

View File

@ -6,7 +6,7 @@
<form class="mt-3" action="/create_group" method="post" data-nonce="{{g.nonce}}" data-onsubmit="sendFormXHRReload(this)">
<div class="container pb-0" style="background-color: transparent !important">
<div class="row">
<div class="col col-md-6 px-0 py-3 py-md-0">
<div class="col col-md-6 px-0 pt-3 py-md-0">
<div class="body">
<input hidden name="formkey" value="{{v|formkey}}">
<label for="title">Group Name</label>
@ -25,7 +25,7 @@
</div>
</form>
<p class="text-danger" style="max-width: 50%">
<p id="group-warning" class="text-danger">
Warning: ping groups can get usurped from their owners if they spend more than a month not reviewing membership applications.
</p>
@ -62,8 +62,8 @@
{% endif %}
</td>
<td>
{% if group.description %}
{{group.description}}
{% if group.description_html %}
{{group.description_html | safe}}
{% endif %}
</td>
<td data-time="{{group.created_utc}}"></td>

View File

@ -22,7 +22,7 @@
<td><a href="/h/{{hole}}">{{count}}</a></td>
<td><a href="/h/{{hole}}/followers">{{hole.follow_num}}</a></td>
{% if hole.stealth %}
<td>{{total_users - hole.join_num}}</td>
<td>{{total_users - hole.stealth_hole_unblock_num}}</td>
{% else %}
<td><a href="/h/{{hole}}/blockers">{{hole.block_num}}</a></td>
{% endif %}

View File

@ -15,6 +15,19 @@
</span>
</div>
<div class="title mt-5">
<label class="text-lg" for="public_use">Public Use Mode</label>
</div>
<div class="d-inline-block w-lg-100 pt-1 pt-lg-3">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="public_use" name="public_use" {% if hole.public_use %}checked{% endif %} data-nonce="{{g.nonce}}" data-onchange="postToastSwitch(this,'/h/{{hole}}/public_use')">
<label class="custom-control-label" for="public_use"></label>
</div>
<span class="text-small text-muted">
Make this hole unblockable and can't be exiled from.
</span>
</div>
<h5 class="mt-5 pt-5">Marsey</h5>
<div class="settings-section rounded">
<img loading="lazy" alt="sub marsey picture" src="{{hole.marsey_url}}" style="max-width:100px">

View File

@ -32,6 +32,8 @@
{% set v_forbid_deleted = (p.deleted_utc != 0 or p.is_banned) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == p.author_id) %}
{{macros.reports(p, 'post')}}
<div id="post-{{p.id}}" class="actual-post card {% if u and p.is_pinned %}pinned-to-profile{% endif %} {% if p.ghost %}ghost-post{% endif %} {% if p.unread %}unread{% endif %} {% if p.is_banned %} banned{% endif %}{% if p.deleted_utc %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted == 1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.nsfw %} nsfw{% endif %}">
<div class="d-flex flex-row-reverse flex-md-row flex-nowrap" style="align-items:flex-start">
<div class="voting my-2 d-none d-md-flex pr-2">
@ -88,9 +90,6 @@
<div class="post-meta text-left x-scroll hide-scrollbar mb-md-2">
{{macros.post_meta(p)}}
</div>
{{macros.reports(p, 'post')}}
<h5 class="card-title post-title text-left w-lg-95 pb-0 pb-md-1">
{% if p.cw %}
<span class="post-flair bg-danger font-weight-bolder mr-1">CHILD WARNING</span>

View File

@ -16,7 +16,7 @@
</a>
{% if not v %}
{% set image = "https://i.watchpeopledie.tv/assets/images/WPD/sidebar/1.webp?x=7" %}
{% set image = SITE_FULL_IMAGES + "/assets/images/WPD/sidebar/1.webp?x=7" %}
{% elif IS_FISTMAS() %}
{% set image = macros.random_image("assets/events/" ~ IS_EVENT() ~ "/images/sidebar/" ~ SITE_NAME ) %}
{% elif IS_EVENT() %}

View File

@ -16,7 +16,7 @@
</a>
{% if not v %}
{% set image = "https://i.rdrama.net/assets/images/rDrama/sidebar/63.webp?x=7" %}
{% set image = SITE_FULL_IMAGES + "/assets/images/rDrama/sidebar/63.webp?x=7" %}
{% elif hole and hole.sidebarurls %}
{% set image = hole.random_sidebar %}
{% elif IS_FISTMAS() %}

View File

@ -0,0 +1,2 @@
alter table groups add column description_html varchar(1000);
update groups set description_html=description;

View File

@ -0,0 +1,2 @@
alter table holes add column public_use bool default false not null;
alter table holes alter column public_use drop default;

View File

@ -557,7 +557,8 @@ CREATE TABLE public.groups (
name character varying(25) NOT NULL,
created_utc integer NOT NULL,
owner_id integer,
description character varying(100)
description character varying(100),
description_html character varying(1000)
);

View File

@ -83,6 +83,7 @@ INSERT INTO public.emojis (name, kind, author_id, tags, nsfw, created_utc) VALUE
('genderspecial', 'Classic', 2, 'hermaphrodite trans sex symbol', false, 1707442950),
('gisellegewelle', 'Misc', 2, 'bleach hat', false, 1699505752),
('glaceonspin', 'Misc', 2, 'spinning eevee', false, 1702261200),
('gooseknife', 'Misc', 2, 'honk murder', false, 1707884626),
('heartglitter', 'Misc', 2, 'valentines love sparkle cute', false, 1707443520),
('jamesgoy', 'Misc', 2, 'snow snowshovel shovel kill shot dead dispute gun shouldhavekeptyourfuckingmouthshut', false, 1701629768),
('lisagoy', 'Misc', 2, 'snow snowshovel shovel kill shot dead dispute gun shouldhavekeptyourfuckingmouthshut', false, 1701630128),
@ -259,6 +260,7 @@ INSERT INTO public.emojis (name, kind, author_id, tags, nsfw, created_utc) VALUE
('marseyhokiesmascot', 'Marsey', 2, 'university ncaa sports', false, 1701222977),
('marseyholdingdildo', 'Marsey', 2, 'sextoy', false, 1700445232),
('marseyhoosiersmascot', 'Marsey', 2, 'university ncaa sports', false, 1701016930),
('marseyhooves', 'Marsey', 2, 'pony mlp little wings', false, 1707949830),
('marseyhornedfrogsmascot', 'Marsey', 2, 'university ncaa sports', false, 1701123758),
('marseyhurricanesmascot', 'Marsey', 2, 'university ncaa sports', false, 1701219570),
('marseyhuskieswashingtonmascot', 'Marsey', 2, 'university ncaa sports', false, 1701095122),
@ -273,6 +275,7 @@ INSERT INTO public.emojis (name, kind, author_id, tags, nsfw, created_utc) VALUE
('marseykenjaku', 'Marsey', 2, 'jjk jujutsu kaisen anime', false, 1706040899),
('marseykissit', 'Marsey', 2, 'ass', false, 1706606220),
('marseyknightsmascot', 'Marsey', 2, 'university ncaa sports', false, 1701119592),
('marseylaugh2', 'Marsey', 2, 'laughing crack', false, 1708020167),
('marseylickitung', 'Marsey', 2, 'pokemon 108', false, 1698868591),
('marseylifeloser', 'Marsey', 2, 'sad pepe fat obese frog', false, 1706461397),
('marseylightsparkle', 'Marsey', 2, 'little pony twilightsparkle', false, 1707775829),
@ -301,6 +304,7 @@ INSERT INTO public.emojis (name, kind, author_id, tags, nsfw, created_utc) VALUE
('marseymimikyu2', 'Marsey', 2, 'pkmn pokemon 778', false, 1699096302),
('marseymimikyu3', 'Marsey', 2, 'pokemon pkmn 778', false, 1700407513),
('marseymola', 'Marsey', 2, 'sunfish molamola fish', false, 1706975944),
('marseymonika', 'Misc', 2, 'ddlc doki schoolgirl', false, 1707964086),
('marseymoonman', 'Marsey', 2, 'racist', false, 1706667718),
('marseymountaineersmascot', 'Marsey', 2, 'university ncaa sports', false, 1701126947),
('marseymug', 'Marsey', 2, 'unamused mondaymorning tired coffee sleepy', false, 1700761066),
@ -463,6 +467,8 @@ INSERT INTO public.emojis (name, kind, author_id, tags, nsfw, created_utc) VALUE
('pepeiloveyou', 'Misc', 2, 'heart lovely', false, 1707497948),
('pepejesus', 'Misc', 2, 'god cross christ', false, 1707468640),
('pepemath', 'Misc', 2, 'think calculating', false, 1707468735),
('pepemexican', 'Misc', 2, 'sad mexico latino', false, 1707680546),
('pepesuit', 'Misc', 2, 'cigarette classy', false, 1707417675),
('pinkiepietroublemaker', 'Misc', 2, 'hardbody horse mylittlepony mlp', false, 1705517339),
('platyannoyedreal', 'Platy', 2, 'anger angry mad', false, 1699679070),
('platybear', 'Platy', 2, 'costume', false, 1700216904),
@ -514,6 +520,7 @@ INSERT INTO public.emojis (name, kind, author_id, tags, nsfw, created_utc) VALUE
('wolfisisfemboy', 'Wolf', 2, 'daesh terrorist islam muslim', false, 1707120944),
('wolfmarseyfacepeel', 'Wolf', 2, 'gore blood scalp skin watchpeopledie', false, 1706906754),
('wolfreal', 'Wolf', 2, 'zombie undead realistic howl moon canine hulk', false, 1699410946),
('wolfsmiley', 'Wolf', 2, 'manhunt smileys mask blood', false, 1707853001),
('wolfthumbsuppenisshadow', 'Wolf', 2, 'cock', false, 1699809842),
('wpdbillboard', 'Misc', 2, 'welcome hello watchpeopledie', false, 1707015071),
('wpdreadtherules', 'Misc', 2, 'broken cookie watchpeopledie', false, 1707015362)