Fix conflicts

master
Nekobit 2022-05-30 00:36:10 -04:00
commit 195c6936ee
26 changed files with 633 additions and 84 deletions

View File

@ -18,4 +18,5 @@ from .sub_block import *
from .saves import *
from .views import *
from .notifications import *
from .follows import *
from .follows import *
from .lottery import *

View File

@ -0,0 +1,32 @@
import time
from sqlalchemy import *
from files.__main__ import Base
from files.helpers.lazy import lazy
from files.helpers.const import *
class Lottery(Base):
__tablename__ = "lotteries"
id = Column(Integer, primary_key=True)
is_active = Column(Boolean, default=False)
ends_at = Column(Integer)
prize = Column(Integer, default=0)
tickets_sold = Column(Integer, default=0)
winner_id = Column(Integer, ForeignKey("users.id"))
@property
@lazy
def timeleft(self):
if not self.is_active:
return 0
epoch_time = int(time.time())
remaining_time = self.ends_at - epoch_time
return 0 if remaining_time < 0 else remaining_time
@property
@lazy
def stats(self):
return {"active": self.is_active, "timeLeft": self.timeleft, "prize": self.prize, "ticketsSoldThisSession": self.tickets_sold,}

View File

@ -127,6 +127,9 @@ class User(Base):
original_username = deferred(Column(String))
referred_by = Column(Integer, ForeignKey("users.id"))
subs_created = Column(Integer, default=0)
currently_held_lottery_tickets = Column(Integer, default=0)
total_held_lottery_tickets = Column(Integer, default=0)
total_lottery_winnings = Column(Integer, default=0)
badges = relationship("Badge", viewonly=True)
subscriptions = relationship("Subscription", viewonly=True)
@ -259,13 +262,6 @@ class User(Base):
def age(self):
return int(time.time()) - self.created_utc
@property
@lazy
def ban_reason_link(self):
if self.ban_reason:
if self.ban_reason.startswith("/post/"): return self.ban_reason.split(None, 1)[0]
if self.ban_reason.startswith("/comment/"): return self.ban_reason.split(None, 1)[0] + "?context=8#context"
@property
@lazy
def alts_unique(self):
@ -656,3 +652,8 @@ class User(Base):
l = [i.strip() for i in self.custom_filter_list.split('\n')] if self.custom_filter_list else []
l = [i for i in l if i]
return l
@property
@lazy
def lottery_stats(self):
return { "winnings": self.total_lottery_winnings, "ticketsHeld": { "current": self.currently_held_lottery_tickets , "total": self.total_held_lottery_tickets } }

View File

@ -173,6 +173,7 @@ if SITE in {'rdrama.net','devrama.xyz'}:
"6": "947236351445725204",
"7": "886781932430565418",
}
elif SITE == "pcmemes.net":
HOLE_COST = 10000
NOTIFICATIONS_ID = 1046
@ -1013,3 +1014,19 @@ procoins_li = (0,2500,5000,10000,25000,50000,125000,250000)
linefeeds_regex = re.compile("([^\n])\n([^\n])", flags=re.A)
def make_name(*args, **kwargs): return request.base_url
# Lottery
if SITE_NAME == 'rDrama':
LOTTERY_ENABLED = True
LOTTERY_TICKET_COST = 12
LOTTERY_SINK_RATE = 3
LOTTERY_ROYALTY_RATE = 1
LOTTERY_ROYALTY_ACCOUNT_ID = 8239 # (McCoxmaul)
LOTTERY_MANAGER_ACCOUNT_ID = 11651 # (Lottershe)
else:
LOTTERY_ENABLED = False
LOTTERY_TICKET_COST = 0
LOTTERY_SINK_RATE = 0
LOTTERY_ROYALTY_RATE = 0
LOTTERY_ROYALTY_ACCOUNT_ID = 0
LOTTERY_MANAGER_ACCOUNT_ID = 0

View File

@ -50,4 +50,9 @@ 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, "datetime":datetime, "time":time}
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, "time":time,
"LOTTERY_ENABLED": LOTTERY_ENABLED}

View File

@ -0,0 +1,114 @@
import time
from random import choice
from sqlalchemy import *
from files.helpers.alerts import *
from files.helpers.wrappers import *
from flask import g
from .const import *
def get_active_lottery():
return g.db.query(Lottery).order_by(Lottery.id.desc()).filter(Lottery.is_active).one_or_none()
def get_users_participating_in_lottery():
return g.db.query(User).filter(User.currently_held_lottery_tickets > 0).all()
def get_active_lottery_stats():
active_lottery = get_active_lottery()
participating_users = get_users_participating_in_lottery()
return None if active_lottery is None else active_lottery.stats, len(participating_users)
def end_lottery_session():
active_lottery = get_active_lottery()
if (active_lottery is None):
return False, "There is no active lottery."
participating_users = get_users_participating_in_lottery()
raffle = []
for user in participating_users:
for _ in range(user.currently_held_lottery_tickets):
raffle.append(user.id)
winner = choice(raffle)
active_lottery.winner_id = winner
winning_user = next(filter(lambda x: x.id == winner, participating_users))
winning_user.coins += active_lottery.prize
winning_user.total_lottery_winnings += active_lottery.prize
for user in participating_users:
chance_to_win = user.currently_held_lottery_tickets / len(raffle) * 100
notification_text = f'You won {active_lottery.prize} dramacoins in the lottery! Congratulations!\nOdds of winning: {chance_to_win}%' if user.id == winner else "You did not win the lottery. Better luck next time!\nOdds of winning: {chance_to_win}%"
send_repeatable_notification(user.id, notification_text)
user.currently_held_lottery_tickets = 0
active_lottery.is_active = False
manager = g.db.query(User).get(LOTTERY_MANAGER_ACCOUNT_ID)
manager.coins -= active_lottery.prize
g.db.commit()
return True, f'{winning_user.username} won {active_lottery.prize} dramacoins!'
def start_new_lottery_session():
end_lottery_session()
lottery = Lottery()
epoch_time = int(time.time())
one_week_from_now = epoch_time + 60 * 60 * 24 * 7
lottery.ends_at = one_week_from_now
lottery.is_active = True
g.db.add(lottery)
g.db.commit()
def purchase_lottery_ticket(v):
if (v.coins < LOTTERY_TICKET_COST):
return False, f'Lottery tickets cost {LOTTERY_TICKET_COST} dramacoins each.'
most_recent_lottery = get_active_lottery()
if (most_recent_lottery is None):
return False, "There is no active lottery."
v.coins -= LOTTERY_TICKET_COST
v.currently_held_lottery_tickets += 1
v.total_held_lottery_tickets += 1
net_ticket_value = LOTTERY_TICKET_COST - LOTTERY_SINK_RATE - LOTTERY_ROYALTY_RATE
most_recent_lottery.prize += net_ticket_value
most_recent_lottery.tickets_sold += 1
grant_lottery_proceeds_to_manager(net_ticket_value)
beneficiary = g.db.query(User).get(LOTTERY_ROYALTY_ACCOUNT_ID)
beneficiary.coins += LOTTERY_ROYALTY_RATE
g.db.commit()
return True, 'Successfully purchased a lottery ticket!'
def grant_lottery_proceeds_to_manager(amount):
manager = g.db.query(User).get(LOTTERY_MANAGER_ACCOUNT_ID)
manager.coins += amount
def grant_lottery_tickets_to_user(v, amount):
active_lottery = get_active_lottery()
prize_value = amount * LOTTERY_TICKET_COST
if active_lottery:
v.currently_held_lottery_tickets += amount
v.total_held_lottery_tickets += amount
active_lottery.prize += prize_value
active_lottery.tickets_sold += amount
grant_lottery_proceeds_to_manager(amount)
g.db.commit()

View File

@ -247,7 +247,7 @@ def sanitize(sanitized, alert=False, comment=False, edit=False):
for rd in ["://reddit.com", "://new.reddit.com", "://www.reddit.com", "://redd.it", "://libredd.it", "://teddit.net"]:
sanitized = sanitized.replace(rd, "://old.reddit.com")
sanitized = normalize_url(sanitized)
sanitized = sanitize_url(sanitized)
sanitized = sanitized.replace('&amp;','&')
@ -377,7 +377,8 @@ def filter_emojis_only(title, edit=False, graceful=False):
if len(title) > 1500 and not graceful: abort(400)
else: return title
def normalize_url(url):
def sanitize_url(url):
# NB: Used in this file to sanitize all URLs in bulk text.
url = url.replace("nitter.net", "twitter.com") \
.replace("old.reddit.com/gallery", "reddit.com/gallery") \
.replace("https://youtu.be/", "https://youtube.com/watch?v=") \
@ -392,6 +393,11 @@ def normalize_url(url):
.replace("https://www.instagram", "https://instagram") \
.replace("https://www.tiktok", "https://tiktok")
return url
def normalize_url(url):
url = sanitize_url(url)
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:

View File

@ -1,22 +1,26 @@
import random
from random import randint
from math import floor
from files.helpers.const import *
from files.helpers.lottery import *
special_min = 100
special_max = 200
standard_min = 10
standard_max = 100
lotterizer_rate = 33
def check_for_treasure(in_text, from_comment):
if '!slots' not in in_text and '!blackjack' not in in_text and '!wordle' not in in_text:
seed = random.randint(1, 1000)
seed = randint(1, 1000)
is_special = seed == 1000
is_standard = seed >= 990
amount = 0
if is_special:
amount = random.randint(special_min, special_max)
amount = randint(special_min, special_max)
elif is_standard:
amount = random.randint(standard_min, standard_max)
if random.randint(1, 100) > 90:
amount = randint(standard_min, standard_max)
if randint(1, 100) > 90:
user = from_comment.author
if amount > user.coins: amount = user.coins
amount = -amount
@ -24,6 +28,18 @@ def check_for_treasure(in_text, from_comment):
if amount != 0:
user = from_comment.author
user.coins += amount
if amount > 0:
active_lottery = get_active_lottery()
lottery_tickets_seed = randint(1, 100)
lottery_tickets_instead = lottery_tickets_seed <= lotterizer_rate
if active_lottery and lottery_tickets_instead:
ticket_count = floor(amount / LOTTERY_TICKET_COST)
grant_lottery_tickets_to_user(user, ticket_count)
from_comment.treasure_amount = f'l{ticket_count}'
return
user.coins += amount
from_comment.treasure_amount = str(amount)

View File

@ -137,4 +137,15 @@ def admin_level_required(x):
wrapper.__name__ = f.__name__
return wrapper
return wrapper_maker
return wrapper_maker
def lottery_required(f):
def wrapper(*args, **kwargs):
v = get_logged_in_user()
if not LOTTERY_ENABLED: abort(404)
return make_response(f(v=v))
wrapper.__name__ = f.__name__
return wrapper

View File

@ -15,4 +15,5 @@ from .votes import *
from .feeds import *
from .awards import *
from .giphy import *
from .subs import *
from .subs import *
from .lottery import *

View File

@ -932,18 +932,16 @@ def admin_removed_comments(v):
def agendaposter(user_id, v):
user = g.db.query(User).filter_by(id=user_id).one_or_none()
days = min(float(request.values.get("days", 30.0)), 30.0)
days = request.values.get("days")
if not days: days = 30.0
days = float(days)
days = min(days, 30.0)
expiry = int(time.time() + days*60*60*24)
user.agendaposter = expiry
g.db.add(user)
for alt in user.alts:
if alt.admin_level: return {"error": "User is an admin!"}
alt.agendaposter = expiry
g.db.add(alt)
note = f"for {days} days"
ma = ModAction(
@ -1123,16 +1121,19 @@ def ban_user(user_id, v):
days = float(request.values.get("days")) if request.values.get('days') else 0
reason = request.values.get("reason", "").strip()[:256]
passed_reason = filter_emojis_only(reason)
reason = filter_emojis_only(reason)
if len(passed_reason) > 256: passed_reason = reason
if reason.startswith("/") and '\\' not in reason:
reason = f'<a href="{reason.split()[0]}">{reason}</a>'
user.ban(admin=v, reason=passed_reason, days=days)
if len(reason) > 256: reason = reason
user.ban(admin=v, reason=reason, days=days)
if request.values.get("alts"):
for x in user.alts:
if x.admin_level: break
x.ban(admin=v, reason=passed_reason, days=days)
x.ban(admin=v, reason=reason, days=days)
if days:
if reason: text = f"@{v.username} has banned you for **{days}** days for the following reason:\n\n> {reason}"
@ -1268,6 +1269,10 @@ def ban_post(post_id, v):
v.coins += 1
g.db.add(v)
if SITE == 'rdrama.net' and v.id != AEVANN_ID:
message = f"@{v.username} has removed [{post.title}]({post.shortlink})"
send_repeatable_notification(AEVANN_ID, message)
requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, json={'files': [f"{SITE_FULL}/logged_out/"]}, timeout=5)
g.db.commit()
@ -1470,6 +1475,11 @@ def api_ban_comment(c_id, v):
target_comment_id=comment.id,
)
g.db.add(ma)
if SITE == 'rdrama.net' and v.id != AEVANN_ID:
message = f"@{v.username} has removed [comment]({comment.shortlink})"
send_repeatable_notification(AEVANN_ID, message)
g.db.commit()
return {"message": "Comment removed!"}

View File

@ -413,7 +413,8 @@ def api_comment(v):
level=level+1,
body_html=filter_emojis_only(option),
upvotes=0,
is_bot=True
is_bot=True,
ghost=c.ghost
)
g.db.add(c_option)
@ -425,7 +426,8 @@ def api_comment(v):
level=level+1,
body_html=filter_emojis_only(choice),
upvotes=0,
is_bot=True
is_bot=True,
ghost=c.ghost
)
g.db.add(c_choice)
@ -454,7 +456,7 @@ def api_comment(v):
is_bot=True,
body_html=body_based_html,
top_comment_id=c.top_comment_id,
ghost=parent_post.ghost
ghost=c.ghost
)
g.db.add(c_based)
@ -486,7 +488,7 @@ def api_comment(v):
is_bot=True,
body_html=body_jannied_html,
top_comment_id=c.top_comment_id,
ghost=parent_post.ghost
ghost=c.ghost
)
g.db.add(c_jannied)
@ -522,7 +524,7 @@ def api_comment(v):
is_bot=True,
body_html=body_html2,
top_comment_id=c.top_comment_id,
ghost=parent_post.ghost
ghost=c.ghost
)
g.db.add(c2)
@ -553,7 +555,7 @@ def api_comment(v):
is_bot=True,
body_html=body_html2,
top_comment_id=c.top_comment_id,
ghost=parent_post.ghost,
ghost=c.ghost,
distinguish_level=6
)
@ -578,7 +580,7 @@ def api_comment(v):
is_bot=True,
body_html=body_html2,
top_comment_id=c.top_comment_id,
ghost=parent_post.ghost,
ghost=c.ghost,
distinguish_level=6
)
@ -596,7 +598,7 @@ def api_comment(v):
is_bot=True,
body_html=body_html2,
top_comment_id=c.top_comment_id,
ghost=parent_post.ghost,
ghost=c.ghost,
distinguish_level=6
)
@ -708,7 +710,8 @@ def edit_comment(cid, v):
level=c.level+1,
body_html=filter_emojis_only(i.group(1)),
upvotes=0,
is_bot=True
is_bot=True,
ghost=c.ghost
)
g.db.add(c_option)
@ -720,7 +723,8 @@ def edit_comment(cid, v):
level=c.level+1,
body_html=filter_emojis_only(i.group(1)),
upvotes=0,
is_bot=True
is_bot=True,
ghost=c.ghost
)
g.db.add(c_choice)

View File

@ -0,0 +1,47 @@
from files.__main__ import app, limiter
from files.helpers.wrappers import *
from files.helpers.alerts import *
from files.helpers.get import *
from files.helpers.const import *
from files.helpers.wrappers import *
from files.helpers.lottery import *
@app.post("/lottery/end")
@admin_level_required(3)
@lottery_required
def lottery_end(v):
success, message = end_lottery_session()
return {"message": message} if success else {"error": message}
@app.post("/lottery/start")
@admin_level_required(3)
@lottery_required
def lottery_start(v):
start_new_lottery_session()
return {"message": "Lottery started."}
@app.post("/lottery/buy")
@limiter.limit("3/second;100/minute;500/hour;1000/day")
@auth_required
@lottery_required
def lottery_buy(v):
success, message = purchase_lottery_ticket(v)
lottery, participants = get_active_lottery_stats()
if success:
return {"message": message, "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}}
else:
return {"error": message, "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}}
@app.get("/lottery/active")
@limiter.limit("3/second;100/minute;500/hour;1000/day")
@auth_required
@lottery_required
def lottery_active(v):
lottery, participants = get_active_lottery_stats()
return {"message": "", "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}}

View File

@ -483,7 +483,8 @@ def edit_post(pid, v):
level=1,
body_html=filter_emojis_only(i.group(1)),
upvotes=0,
is_bot=True
is_bot=True,
ghost=p.ghost
)
g.db.add(c)
@ -494,7 +495,8 @@ def edit_post(pid, v):
level=1,
body_html=filter_emojis_only(i.group(1)),
upvotes=0,
is_bot=True
is_bot=True,
ghost=p.ghost
)
g.db.add(c)
@ -1138,7 +1140,8 @@ def submit_post(v, sub=None):
level=1,
body_html=filter_emojis_only(option),
upvotes=0,
is_bot=True
is_bot=True,
ghost=post.ghost
)
g.db.add(c)
@ -1148,7 +1151,8 @@ def submit_post(v, sub=None):
level=1,
body_html=filter_emojis_only(choice),
upvotes=0,
is_bot=True
is_bot=True,
ghost=post.ghost
)
g.db.add(c)
@ -1227,6 +1231,7 @@ def submit_post(v, sub=None):
stickied='AutoJanny',
distinguish_level=6,
body_html=body_jannied_html,
ghost=post.ghost
)
g.db.add(c_jannied)
@ -1329,7 +1334,8 @@ def submit_post(v, sub=None):
over_18=False,
is_bot=True,
app_id=None,
body_html=body_html
body_html=body_html,
ghost=post.ghost
)
g.db.add(c)

View File

@ -140,9 +140,9 @@ def stats(site=None):
stats.update(stats2)
bots = g.db.query(User).filter(User.id.in_(bots))
accs = g.db.query(User).filter(User.id.in_(bots))
for u in bots:
for u in accs:
g.db.add(u)
if u.patron_utc and u.patron_utc < time.time():
@ -232,8 +232,16 @@ 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(55)][1:]
else: day_cutoffs = [today_cutoff - 86400 * 7 * i for i in range(55)][1:]
if SITE == 'rdrama.net':
time_diff = time.time() - 1619827200
num_of_weeks = int(time_diff / 604800)
chart_width = int(num_of_weeks/1.4)
else:
num_of_weeks = 30
chart_width = 30
if kind == "daily": day_cutoffs = [today_cutoff - 86400 * i for i in range(num_of_weeks)][1:]
else: day_cutoffs = [today_cutoff - 86400 * 7 * i for i in range(num_of_weeks)][1:]
day_cutoffs.insert(0, calendar.timegm(now))
@ -245,11 +253,11 @@ def cached_chart(kind, site):
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)
plt.rcParams["figure.figsize"] = (chart_width, 20)
signup_chart = plt.subplot2grid((30, 20), (0, 0), rowspan=6, colspan=30)
posts_chart = plt.subplot2grid((30, 20), (10, 0), rowspan=6, colspan=30)
comments_chart = plt.subplot2grid((30, 20), (20, 0), rowspan=6, colspan=30)
signup_chart = plt.subplot2grid((chart_width, 20), (0, 0), rowspan=6, colspan=chart_width)
posts_chart = plt.subplot2grid((chart_width, 20), (10, 0), rowspan=6, colspan=chart_width)
comments_chart = plt.subplot2grid((chart_width, 20), (20, 0), rowspan=6, colspan=chart_width)
signup_chart.grid(), posts_chart.grid(), comments_chart.grid()

View File

@ -1,7 +1,7 @@
{% extends "admin/removed_posts.html" %}
{% block title %}
<title>Comments</title>
<title>Removed Comments</title>
{% endblock %}
{% block listing %}

View File

@ -1,7 +1,7 @@
{% extends "admin/reported_posts.html" %}
{% block title %}
<title>Removed Comments</title>
<title>Reported Comments</title>
{% endblock %}
{% block listing %}

View File

@ -7,6 +7,7 @@
{% if v %}
{% include "award_modal.html" %}
{% include "lottery_modal.html" %}
{% endif %}
<div style="display:none" id="popover">
@ -224,14 +225,18 @@
{% endif %}
{% if c.treasure_amount and c.treasure_amount != '0' %}
<img class="treasure" alt="treasure" src="/assets/images/chest.webp" width="20" />
{% if '-' in c.treasure_amount %}
<em>A Mimic Ate {{c.treasure_amount.replace('-', '')}} Coins!</em>
{% else %}
<em>Found {{c.treasure_amount}} Coins!</em>
{% endif %}
{% if c.treasure_amount.startswith('l') %}
<img class="treasure" alt="treasure" src="/assets/images/treasure_tickets.webp" width="20" />
<em>Found {{c.treasure_amount.replace('l', '')}} Lottershe Tickets!</em>
{% elif '-' in c.treasure_amount %}
<img class="treasure" alt="treasure" src="/assets/images/treasure_mimic.webp" width="20" />
<em>A Mimic Ate {{c.treasure_amount.replace('-', '')}} Coins!</em>
{% else %}
<img class="treasure" alt="treasure" src="/assets/images/treasure_coins.webp" width="20" />
<em>Found {{c.treasure_amount}} Coins!</em>
{% endif %}
{% endif %}
{% if c.slots_result %}
<em style="position: relative; top: 2px; margin-left: 0.5rem">{{c.slots_result}}</em>
{% endif %}
@ -463,9 +468,10 @@
{% if v %}
<button style="margin-top:0.2rem" class="btn caction py-0 nobackground px-1 text-muted" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></button>
<ul class="dropdown-menu">
{% if v.admin_level and v.id==c.author_id %}
<button id="undistinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.distinguish_level %}d-md-block{% endif %} text-info" onclick="post_toast3(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}','no')"><i class="fas fa-id-badge text-info fa-fw"></i>Undistinguish</button>
<button id="distinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.distinguish_level %}d-md-block{% endif %} text-info" onclick="post_toast3(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}','yes')"><i class="fas fa-id-badge text-info fa-fw"></i>Distinguish</button>
<button id="undistinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.distinguish_level %}d-md-block{% endif %} text-info" onclick="post_toast3(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}')"><i class="fas fa-id-badge text-info fa-fw"></i>Undistinguish</button>
<button id="distinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.distinguish_level %}d-md-block{% endif %} text-info" onclick="post_toast3(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}')"><i class="fas fa-id-badge text-info fa-fw"></i>Distinguish</button>
{% endif %}
{% if v.id != c.author_id and not c.ghost %}
@ -649,11 +655,6 @@
{% if c.author_id == v.id %}
<a role="button" data-bs-dismiss="modal" onclick="toggleEdit('{{c.id}}')" class="list-group-item"><i class="fas fa-edit mr-2"></i>Edit</a>
{% if v.admin_level == 1 %}
<a id="distinguish2-{{c.id}}" class="list-group-item {% if c.distinguish_level %}d-none{% endif %} text-info" role="button" onclick="post_toast2(this,'/distinguish_comment/{{c.id}}','distinguish2-{{c.id}}','undistinguish2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-id-badge text-info mr-2"></i>Distinguish</a>
<a id="undistinguish2-{{c.id}}" class="list-group-item {% if not c.distinguish_level %}d-none{% endif %} text-info" role="button" onclick="post_toast2(this,'/distinguish_comment/{{c.id}}','distinguish2-{{c.id}}','undistinguish2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-id-badge text-info mr-2"></i>Undistinguish</a>
{% endif %}
<a id="undelete2-{{c.id}}" class="{% if not c.deleted_utc %}d-none{% endif %} list-group-item text-success" role="button" onclick="post_toast2(this,'/undelete/comment/{{c.id}}', 'delete2-{{c.id}}', 'undelete2-{{c.id}}');document.getElementById('comment-{{c.id}}').classList.remove('deleted')" data-bs-dismiss="modal"><i class="far fa-trash-alt text-success mr-2"></i>Undelete</a>
@ -846,7 +847,7 @@
{% if v %}
<script src="/assets/js/marked.js?v=256"></script>
<script src="/assets/js/comments_v.js?v=271"></script>
<script src="/assets/js/comments_v.js?v=272"></script>
{% endif %}
<script src="/assets/js/clipboard.js?v=250"></script>

View File

@ -261,7 +261,7 @@
{% if v and (v.is_banned or v.agendaposter) %}
<img alt="site banner" src="/assets/images/rDrama/banner2.webp?v=1" width="100%">
{% else %}
<img alt="site banner" src="{{image}}" width="100%">
<img alt="site banner" src="{% if v %}{{image}}{% else %}/assets/images/rDrama/cached.webp?v=100{% endif %}" width="100%">
{% endif %}
</a>
{% else %}

View File

@ -77,6 +77,17 @@
{% if not err %}
<a class="mobile-nav-icon d-md-none" href="/random_user"><i class="fas fa-music align-middle text-gray-500 black"></i></a>
<a class="mobile-nav-icon d-md-none" href="/random_post"><i class="fas fa-random align-middle text-gray-500 black"></i></a>
{% if v and LOTTERY_ENABLED %}
<a
href="#"
class="mobile-nav-icon d-md-none"
title="Lottershe"
data-bs-toggle="modal"
data-bs-dismiss="modal"
data-bs-target="#lotteryModal">
<i class="fas fa-ticket align-middle text-gray-500"></i>
</a>
{% endif %}
{% if v and v.admin_level > 1 %}
<a class="mobile-nav-icon d-md-none" href="/admin"><i class="fas fa-crown align-middle text-gray-500 black"></i></a>
{% endif %}
@ -103,6 +114,20 @@
<a class="nav-link" href="/random_post/" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Random post"><i class="fas fa-random"></i></a>
</li>
{% if v and LOTTERY_ENABLED %}
<li class="nav-item d-flex align-items-center justify-content-center text-center mx-1">
<a
href="#"
class="nav-link"
title="Lottershe"
data-bs-toggle="modal"
data-bs-dismiss="modal"
data-bs-target="#lotteryModal">
<i class="fas fa-ticket"></i>
</a>
</li>
{% endif %}
<li class="nav-item d-flex align-items-center justify-content-center text-center mx-1">
<a class="nav-link" href="/chat/" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Chat"><i class="fas fa-messages"></i></a>
</li>

View File

@ -0,0 +1,186 @@
{% if LOTTERY_ENABLED %}
<div
class="modal fade"
id="lotteryModal"
tabindex="-1"
role="dialog"
aria-labelledby="lotteryModalTitle"
aria-hidden="true"
>
<div class="modal-dialog lottery-modal--dialog" role="document">
<div class="modal-content lottery-modal--content">
<button
class="close lottery-modal--close"
data-bs-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true"><i class="far fa-times"></i></span>
</button>
<div class="lottery-modal--wrapper">
<div class="lottery-modal--image">
<img src="/assets/images/rDrama/lottery_modal.webp?v=2" />
<img
id="lotteryTicketPulled"
src="/assets/images/rDrama/lottery_modal_active.webp?v=2"
style="display: none"
/>
</div>
<div class="lottery-modal--stats">
{% if v.admin_level > 2 %}
<div
class="lottery-modal--stat"
style="position: relative; padding-top: 1rem"
>
<i
class="fas fa-broom"
style="
position: absolute;
top: -8px;
right: -8px;
font-size: 20px;
"
>
</i>
<button
type="button"
class="btn btn-danger"
id="endLotterySession"
style="display: none"
onclick="endLotterySession()"
>
End Current Session
</button>
<button
type="button"
class="btn btn-success"
id="startLotterySession"
style="display: none"
onclick="startLotterySession()"
>
Start New Session
</button>
</div>
{% endif %}
<div class="lottery-modal--stat">
<div class="lottery-modal--stat-keys">
<div>Prize</div>
<div>Time Remaining</div>
<div>Tickets Sold This Session</div>
<div>Participants This Session</div>
</div>
<div class="lottery-modal--stat-values">
<div>
<img
id="prize-image"
alt="coins"
class="mr-1 ml-1"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
height="13"
src="/assets/images/rDrama/coins.webp?v=2"
title=""
aria-label="coins"
data-bs-original-title="coins"
style="display: none; position: relative; top: -2px"
/>
<span id="prize">-</span>
</div>
<div id="timeLeft">-</div>
<div id="ticketsSoldThisSession">-</div>
<div id="participantsThisSession">-</div>
</div>
</div>
<div class="lottery-modal--stat">
<div class="lottery-modal--stat-keys">
<div>Tickets Owned This Session</div>
<div>Total Tickets Owned</div>
<div>Total Winnings</div>
</div>
<div class="lottery-modal--stat-values">
<div id="ticketsHeldCurrent">-</div>
<div id="ticketsHeldTotal">-</div>
<div id="winnings">-</div>
</div>
</div>
<button
type="button"
class="btn btn-success lottery-modal--action"
id="purchaseTicket"
onclick="purchaseLotteryTicket()"
disabled="true"
>
Purchase 1 for
<img
alt="coins"
class="mr-1 ml-1"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
height="13"
src="/assets/images/rDrama/coins.webp?v=2"
title=""
aria-label="coins"
data-bs-original-title="coins"
/>
12
</button>
</div>
</div>
</div>
</div>
<!-- Success -->
<div
class="toast"
id="lottery-post-success"
style="
position: fixed;
bottom: 1.5rem;
margin: 0 auto;
left: 0;
right: 0;
width: 275px;
z-index: 1000;
"
role="alert"
aria-live="assertive"
aria-atomic="true"
data-bs-animation="true"
data-bs-autohide="true"
data-bs-delay="5000"
>
<div class="toast-body bg-success text-center text-white">
<i class="fas fa-comment-alt-smile mr-2"></i
><span id="lottery-post-success-text"></span>
</div>
</div>
<!-- Error -->
<div
class="toast"
id="lottery-post-error"
style="
position: fixed;
bottom: 1.5rem;
margin: 0 auto;
left: 0;
right: 0;
width: 275px;
z-index: 1000;
"
role="alert"
aria-live="assertive"
aria-atomic="true"
data-bs-animation="true"
data-bs-autohide="true"
data-bs-delay="5000"
>
<div class="toast-body bg-danger text-center text-white">
<i class="fas fa-exclamation-circle mr-2"></i
><span id="lottery-post-error-text"></span>
</div>
</div>
</div>
<script src="/assets/js/lottery_modal.js?v=249" data-cfasync="false"></script>
{% endif %}

View File

@ -22,11 +22,6 @@
{% if v.id==p.author_id %}
{% if v.admin_level == 1 %}
<button id="distinguish2-{{p.id}}" class="{% if p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center mr-3"></i>Distinguish</button>
<button id="undistinguish2-{{p.id}}" class="{% if not p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center mr-3"></i>Undistinguish</button>
{% endif %}
{% if request.path.startswith('/@') %}
<button id="pin-profile2-{{p.id}}" class="{% if p.is_pinned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-muted text-left"role="button" onclick="post_toast2(this,'/pin/{{p.id}}','pin-profile2-{{p.id}}','unpin-profile2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center mr-3"></i>Pin to profile</button>
<button id="unpin-profile2-{{p.id}}" class="{% if not p.is_pinned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-muted text-left" role="button" onclick="post_toast2(this,'/pin/{{p.id}}','pin-profile2-{{p.id}}','unpin-profile2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center mr-3"></i>Unpin from profile</button>

View File

@ -2,6 +2,7 @@
{% if v %}
{% include "award_modal.html" %}
{% include "lottery_modal.html" %}
{% endif %}
{% if request.host == 'pcmemes.net' %}

View File

@ -44,12 +44,14 @@
</div>
<div id="profilestuff" class="ml-3 w-100">
{% if u.is_suspended %}
<h5 class="text-primary" id="profile--banned">BANNED USER{% if u.ban_reason %}:
{% if u.ban_reason_link %}<a href="{{u.ban_reason_link}}"><i class="fas fa-link"></i>{% endif %}
<h5 class="text-primary" id="profile--banned">BANNED USER
{% if u.ban_reason %}:
{{u.ban_reason | safe}}
{% if u.ban_reason_link %}</a>{% endif %}
{% endif %}</h5>
{% if u.unban_utc %}<h5 class="text-primary" id="profile--unban">{{u.unban_string}}</h5>{% endif %}
{% endif %}
</h5>
{% if u.unban_utc %}
<h5 class="text-primary" id="profile--unban">{{u.unban_string}}</h5>
{% endif %}
{% endif %}
<div class="d-flex align-items-center mt-1 mb-2">
<h1 class="font-weight-bolder h3 mb-0" id="profile--name" style="color: #{{u.namecolor}}"><span {% if u.patron %}class="patron" style="background-color:#{{u.namecolor}}"{% endif %}>{{u.username}}</span></h1>
@ -68,7 +70,7 @@
<span id="profile--verified"><i class="fas fa-badge-check align-middle ml-2 {% if u.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if u.verifiedcolor %}#{{u.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{u.verified}}"></i></span>
{% endif %}
{% if u.admin_level > 1 or (u.admin_level == 1 and not(v and v.admin_level > 1)) %}
{% if u.admin_level > 1 %}
<span id="profile--mop">
<i class="fas fa-broom text-admin align-middle ml-2" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Admin"></i>
</span>
@ -388,7 +390,7 @@
<span id="profile--verified"><i class="fas fa-badge-check align-middle ml-2 {% if u.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if u.verifiedcolor %}#{{u.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{u.verified}}"></i></span>&nbsp;
{% endif %}
{% if u.admin_level > 1 or (u.admin_level == 1 and not(v and v.admin_level > 1)) %}
{% if u.admin_level > 1 %}
<span id="profile--mop">
<i class="fas fa-broom text-admin align-middle ml-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Admin"></i>
</span>

View File

@ -1,6 +1,6 @@
{%-
set CACHE_VER = {
'css/main.css': 281,
'css/main.css': 283,
'js/award_modal.js': 251,
'js/bootstrap.js': 257,
'js/header.js': 268,

View File

@ -356,6 +356,40 @@ CREATE TABLE public.follows (
);
--
-- Name: lotteries; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.lotteries (
id integer NOT NULL,
is_active boolean DEFAULT false NOT NULL,
ends_at integer DEFAULT 0 NOT NULL,
prize integer DEFAULT 0 NOT NULL,
tickets_sold integer DEFAULT 0 NOT NULL,
winner_id integer
);
--
-- Name: lotteries_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.lotteries_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: lotteries_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.lotteries_id_seq OWNED BY public.lotteries.id;
--
-- Name: marseys; Type: TABLE; Schema: public; Owner: -
--
@ -630,7 +664,10 @@ CREATE TABLE public.users (
subs_created integer DEFAULT 0 NOT NULL,
deflector integer,
reddit character varying(15) NOT NULL,
animations boolean DEFAULT true NOT NULL
animations boolean DEFAULT true NOT NULL,
currently_held_lottery_tickets integer DEFAULT 0 NOT NULL,
total_held_lottery_tickets integer DEFAULT 0 NOT NULL,
total_lottery_winnings integer DEFAULT 0 NOT NULL
);
@ -700,6 +737,13 @@ ALTER TABLE ONLY public.badge_defs ALTER COLUMN id SET DEFAULT nextval('public.b
ALTER TABLE ONLY public.comments ALTER COLUMN id SET DEFAULT nextval('public.comments_id_seq'::regclass);
--
-- Name: lotteries id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.lotteries ALTER COLUMN id SET DEFAULT nextval('public.lotteries_id_seq'::regclass);
--
-- Name: modactions id; Type: DEFAULT; Schema: public; Owner: -
--
@ -848,6 +892,14 @@ ALTER TABLE ONLY public.follows
ADD CONSTRAINT follows_pkey PRIMARY KEY (target_id, user_id);
--
-- Name: lotteries lotteries_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.lotteries
ADD CONSTRAINT lotteries_pkey PRIMARY KEY (id);
--
-- Name: marseys marseys_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -1636,6 +1688,14 @@ ALTER TABLE ONLY public.exiles
ADD CONSTRAINT exile_user_fkey FOREIGN KEY (user_id) REFERENCES public.users(id);
--
-- Name: lotteries fk_winner; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.lotteries
ADD CONSTRAINT fk_winner FOREIGN KEY (winner_id) REFERENCES public.users(id);
--
-- Name: flags flags_post_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--