master
Aevann1 2021-11-21 19:40:47 +02:00
parent a66dd90553
commit 694ffb4e83
11 changed files with 234 additions and 208 deletions

View File

@ -3,42 +3,11 @@ from sqlalchemy.orm import relationship
from files.__main__ import Base, app from files.__main__ import Base, app
from os import environ from os import environ
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.const import BADGES
from datetime import datetime from datetime import datetime
site_name = environ.get("SITE_NAME").strip() site_name = environ.get("SITE_NAME").strip()
class BadgeDef(Base):
__tablename__ = "badge_defs"
id = Column(BigInteger, primary_key=True)
name = Column(String)
description = Column(String)
icon = Column(String)
kind = Column(Integer, default=1)
qualification_expr = Column(String)
def __repr__(self):
return f"<BadgeDef(badge_id={self.id})>"
@property
@lazy
def path(self):
return f"/assets/images/badges/{self.icon}.webp"
@property
@lazy
def json_core(self):
return {
"name": self.name,
"description": self.description,
"icon": self.icon
}
class Badge(Base): class Badge(Base):
__tablename__ = "badges" __tablename__ = "badges"
@ -46,41 +15,37 @@ class Badge(Base):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id')) user_id = Column(Integer, ForeignKey('users.id'))
badge_id = Column(Integer, ForeignKey("badge_defs.id")) badge_id = Column(Integer)
description = Column(String) description = Column(String)
url = Column(String) url = Column(String)
badge = relationship("BadgeDef", viewonly=True)
user = relationship("User", viewonly=True)
def __repr__(self): def __repr__(self):
return f"<Badge(user_id={self.user_id}, badge_id={self.badge_id})>" return f"<Badge(user_id={self.user_id}, badge_id={self.badge_id})>"
@property
@lazy
def badge(self):
return BADGES[self.badge_id]
@property @property
@lazy @lazy
def text(self): def text(self):
if self.name == "Agendaposter": if self.name == "Agendaposter":
ti = self.user.agendaposter_expires_utc ti = self.user.agendaposter_expires_utc
if ti: return self.badge.description + " until " + datetime.utcfromtimestamp(ti).strftime('%Y-%m-%d %H:%M:%S') if ti: return self.badge['description'] + " until " + datetime.utcfromtimestamp(ti).strftime('%Y-%m-%d %H:%M:%S')
else: return self.badge.description + " permanently" else: return self.badge['description'] + " permanently"
elif self.description: return self.description elif self.description: return self.description
else: return self.badge.description else: return self.badge['description']
@property
@lazy
def type(self):
return self.badge.id
@property @property
@lazy @lazy
def name(self): def name(self):
return self.badge.name return self.badge['name']
@property @property
@lazy @lazy
def path(self): def path(self):
return self.badge.path return f"/assets/images/badges/{self.name}.webp"
@property @property
@lazy @lazy

View File

@ -272,8 +272,8 @@ class User(Base):
if not self.is_suspended: return None if not self.is_suspended: return None
return g.db.query(User).filter_by(id=self.is_banned).first() return g.db.query(User).filter_by(id=self.is_banned).first()
def has_badge(self, badgedef_id): def has_badge(self, badge_id):
return g.db.query(Badge).filter_by(user_id=self.id, badge_id=badgedef_id).first() return g.db.query(Badge).filter_by(user_id=self.id, badge_id=badge_id).first()
def hash_password(self, password): def hash_password(self, password):
return generate_password_hash( return generate_password_hash(

View File

@ -163,6 +163,197 @@ def censor_slurs(body: str, logged_user) -> str:
if not logged_user or logged_user.slurreplacer: body = SLUR_REGEX.sub(sub_matcher, body) if not logged_user or logged_user.slurreplacer: body = SLUR_REGEX.sub(sub_matcher, body)
return body return body
BADGES = {
1: {
'name': 'Alpha User',
'description': 'Joined during open alpha'
},
2: {
'name': 'Verified Email',
'description': 'Verified Email'
},
3: {
'name': 'Code Contributor',
'description': 'Contributed to Drama source code'
},
4: {
'name': 'White Hat',
'description': 'Responsibly reported a security issue'
},
6: {
'name': 'Beta User',
'description': 'Joined during open beta'
},
7: {
'name': 'Bug Finder',
'description': 'Found a bug'
},
10: {
'name': 'Bronze Recruiter',
'description': 'Recruited 1 friend to join Drama'
},
11: {
'name': 'Silver Recruiter',
'description': 'Recruited 10 friends to join Drama'
},
12: {
'name': 'Gold Recruiter',
'description': 'Recruited 100 friends to join Drama'
},
15: {
'name': 'Idea Maker',
'description': 'Had a good idea for Drama which was implemented by the developers'
},
16: {
'name': 'Marsey Master',
'description': 'Contributed 10 (or more!!!!) Marsey emojis ✨'
},
17: {
'name': 'Marsey Artisan',
'description': 'Contributed a Marsey emoji ✨'
},
18: {
'name': 'Artisan',
'description': 'Contributed to Drama artwork'
},
21: {
'name': 'Paypig',
'description': 'Contributed at least $5/month'
},
22: {
'name': 'Renthog',
'description': 'Contributed at least $10/month'
},
23: {
'name': 'Landchad',
'description': 'Contributed at least $20/month'
},
24: {
'name': 'Terminally online turboautist',
'description': 'Contributed at least $50/month'
},
25: {
'name': 'Footpig',
'description': 'Contributed at least $100/month'
},
26: {
'name': 'Agendaposter',
'description': 'Forced to use the agendaposter theme'
},
27: {
'name': 'Lolcow',
'description': 'Beautiful and valid milk provider'
},
28: {
'name': 'Rich Bich',
'description': 'Contributed $500'
},
58: {
'name': 'Diamond Recruiter',
'description': 'Recruited 1000 friends to join Drama'
},
60: {
'name': 'Unironically Retarded',
'description': 'Demonstrated a wholesale inability to read the room'
},
61: {
'name': 'Lab Rat',
'description': 'Helped test features in development'
},
62: {
'name': 'Master Baiter',
'description': 'For outstanding achievement in the field of catching fish'
},
63: {
'name': 'Balls',
'description': 'I wrote carp on my balls as a sign of submission'
},
64: {
'name': 'The Other Kind Of Good Journalist',
'description': 'Contributed positive media attention to rDrama'
},
65: {
'name': '2021 Spooooooky Marsey Artist',
'description': 'Contributed a VERY SCARY Marsey for Halloween 2021!'
},
66: {
'name': 'Sk8r Boi',
'description': 'Certifies that this user is NOT a poser'
},
67: {
'name': 'Unpausable',
'description': 'Spent 40,000 dramacoins on an unpausable profile anthem'
},
68: {
'name': 'Pause Button',
'description': 'Spent 20,000 dramacoins on a profile anthem pause button'
},
69: {
'name': 'Little Big Spender',
'description': 'Dropped 10,000 dramacoins at the shop'
},
70: {
'name': 'Big Spender',
'description': 'Dropped 100,000 dramacoins at the shop'
},
71: {
'name': 'Big Big Spender',
'description': 'Dropped 250,000 dramacoins at the shop'
},
72: {
'name': 'Big Big Big Spender',
'description': 'Dropped 500,000 dramacoins at the shop'
},
73: {
'name': 'Le Rich Gentlesir',
'description': 'Spent a fucking million dramacoins at the shop'
},
74: {
'name': 'Grass Toucher',
'description': 'Awarded for molesting plant life'
},
75: {
'name': 'Halloween 21',
'description': 'Awarded for surviving Homoween 2021'
},
76: {
'name': 'Low Roller',
'description': 'Bought 10 lootboxes'
},
77: {
'name': 'Middle Roller',
'description': 'Bought 50 lootboxes'
},
78: {
'name': 'High Roller',
'description': 'Bought 150 lootboxes'
},
79: {
'name': 'Merchant',
'description': "Contributed a new line of product to Marsey's Coin Emporium"
},
80: {
'name': 'Artist Laureate',
'description': ''
},
81: {
'name': 'Patron of the Arts',
'description': 'Sponsored the creation of an approved Marsey'
},
82: {
'name': 'Background',
'description': 'Bought a profile background from the shop'
},
83: {
'name': 'All-Seeing Eye',
'description': 'Can view private profiles'
},
84: {
'name': 'Alt-Seeing Eye',
'description': 'Can see alts'
}
}
AWARDS = { AWARDS = {
"shit": { "shit": {
"kind": "shit", "kind": "shit",

View File

@ -351,15 +351,13 @@ def disablesignups(v):
@admin_level_required(2) @admin_level_required(2)
def badge_grant_get(v): def badge_grant_get(v):
badge_types = g.db.query(BadgeDef).all()
errors = {"already_owned": "That user already has that badge.", errors = {"already_owned": "That user already has that badge.",
"no_user": "That user doesn't exist." "no_user": "That user doesn't exist."
} }
return render_template("admin/badge_grant.html", return render_template("admin/badge_grant.html",
v=v, v=v,
badge_types=badge_types, badge_types=BADGES,
error=errors.get( error=errors.get(
request.values.get("error"), request.values.get("error"),
None) if request.values.get('error') else None, None) if request.values.get('error') else None,

View File

@ -301,21 +301,21 @@ def sign_up_post(v):
ref_id = int(request.values.get("referred_by", 0)) ref_id = int(request.values.get("referred_by", 0))
if ref_id: # if ref_id:
ref_user = g.db.query(User).filter_by(id=ref_id).first() # ref_user = g.db.query(User).filter_by(id=ref_id).first()
if ref_user: # if ref_user:
badge_types = g.db.query(BadgeDef).filter(BadgeDef.qualification_expr.isnot(None)).all() # badge_types = g.db.query(BadgeDef).filter(BadgeDef.qualification_expr.isnot(None)).all()
for badge in badge_types: # for badge in badge_types:
if eval(badge.qualification_expr, {}, {'v': ref_user}): # if eval(badge.qualification_expr, {}, {'v': ref_user}):
if not ref_user.has_badge(badge.id): # if not ref_user.has_badge(badge.id):
new_badge = Badge(user_id=ref_user.id, badge_id=badge.id) # new_badge = Badge(user_id=ref_user.id, badge_id=badge.id)
g.db.add(new_badge) # g.db.add(new_badge)
else: # else:
bad_badge = ref_user.has_badge(badge.id) # bad_badge = ref_user.has_badge(badge.id)
if bad_badge: g.db.delete(bad_badge) # if bad_badge: g.db.delete(bad_badge)
g.db.add(ref_user) # g.db.add(ref_user)
id_1 = g.db.query(User.id).filter_by(id=7).count() id_1 = g.db.query(User.id).filter_by(id=7).count()
users_count = g.db.query(User.id).count() users_count = g.db.query(User.id).count()

View File

@ -93,7 +93,7 @@ def searchposts(v):
) )
if not (v and v.admin_level > 1): if not (v and v.admin_level > 1):
posts.filter(Submission.deleted_utc == 0, Submission.is_banned == False) posts = posts.filter(Submission.deleted_utc == 0, Submission.is_banned == False)
if not (v and v.eye): posts = posts.join(User, User.id==Submission.author_id).filter(User.is_private == False) if not (v and v.eye): posts = posts.join(User, User.id==Submission.author_id).filter(User.is_private == False)
if v and v.admin_level > 1: pass if v and v.admin_level > 1: pass

View File

@ -1,6 +1,7 @@
from files.mail import * from files.mail import *
from files.__main__ import app, limiter, mail from files.__main__ import app, limiter, mail
from files.helpers.alerts import * from files.helpers.alerts import *
from files.helpers.const import BADGES
from files.classes.award import AWARDS from files.classes.award import AWARDS
from sqlalchemy import func from sqlalchemy import func
from os import path from os import path
@ -294,10 +295,7 @@ def settings_profile(v):
@app.get("/badges") @app.get("/badges")
@auth_desired @auth_desired
def badges(v): def badges(v):
return render_template("badges.html", v=v, badges=BADGES)
badges = g.db.query(BadgeDef).all()
return render_template("badges.html", v=v, badges=badges)
@app.get("/blocks") @app.get("/blocks")
@auth_desired @auth_desired

View File

@ -52,12 +52,12 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for badge in badge_types %} {% for k, v in badge_types.items() %}
<tr> <tr>
<td><input type="radio" id="badge-{{badge.id}}" name="badge_id" value="{{badge.id}}"></td> <td><input type="radio" id="badge-{{k}}" name="badge_id" value="{{k}}"></td>
<td><label for="badge-{{badge.id}}"><img loading="lazy" src="{{badge.path}}" width="70px" height="70px"></label></td> <td><label for="badge-{{k}}"><img loading="lazy" src="/assets/images/badges/{{v['name']}}.webp" width="70px" height="70px"></label></td>
<td>{{badge.name}}</td> <td>{{v['name']}}</td>
<td>{{badge.description}}</td> <td>{{v['description']}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

View File

@ -6,11 +6,10 @@
</pre> </pre>
<h1>User Badges</h1> <h1>User Badges</h1>
<div>This page describes the requirements for obtaining all profile badges.</div> <div>This page describes the requirements for obtaining all profile badges.</div>
<div>Badges are sorted into bronze, silver, gold, and diamond tiers, based on the relative difficulty of obtaining them.</div> <pre>
<h2 class="mt-3">Unlockable Badges</h2>
<div>These badges are automatically granted through different kinds of activity on {{'SITE_NAME' | app_config}}.</div> </pre>
<pre></pre>
<table class="table table-striped mb-5"> <table class="table table-striped mb-5">
<thead class="bg-primary text-white"> <thead class="bg-primary text-white">
<tr> <tr>
@ -19,52 +18,11 @@
<th>Description</th> <th>Description</th>
</tr> </tr>
</thead> </thead>
{% for badge in badges if badge.kind==1 %} {% for k,v in badges.items() %}
<tr> <tr>
<td>{{badge.name}}</td> <td>{{v['name']}}</td>
<td><img loading="lazy" src="{{badge.path}}" width=50 height=50> <td><img loading="lazy" src="/assets/images/badges/{{v['name']}}.webp" width=50 height=50>
<td>{{badge.description}}</td> <td>{{v['description']}}</td>
</tr>
{% endfor %}
</table>
<h2 class="mt-3">Granted Badges</h2>
<div>These badges can be granted by admins.</div>
<pre></pre>
<table class="table table-striped mb-5">
<thead class="bg-primary text-white">
<tr>
<th>Name</th>
<th>Image</th>
<th>Description</th>
</tr>
</thead>
{% for badge in badges if badge.kind==3 %}
<tr>
<td>{{badge.name}}</td>
<td><img loading="lazy" src="{{badge.path}}" width=50 height=50>
<td>{{badge.description}}</td>
</tr>
{% endfor %}
</table>
<h2 class="mt-3">Unobtainable Badges</h2>
<div>There is no way to acquire these badges if you don't already have them.</div>
<pre></pre>
<table class="table table-striped mb-5">
<thead class="bg-primary text-white">
<tr>
<th>Name</th>
<th>Image</th>
<th>Description</th>
</tr>
</thead>
{% for badge in badges if badge.kind==4 %}
<tr>
<td>{{badge.name}}</td>
<td><img loading="lazy" src="{{badge.path}}" width=50 height=50>
<td>{{badge.description}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

View File

@ -127,20 +127,6 @@ CREATE SEQUENCE public.award_relationships_id_seq
ALTER SEQUENCE public.award_relationships_id_seq OWNED BY public.award_relationships.id; ALTER SEQUENCE public.award_relationships_id_seq OWNED BY public.award_relationships.id;
--
-- Name: badge_defs; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.badge_defs (
id integer NOT NULL,
name character varying(64),
description character varying(256),
icon character varying(64),
kind integer,
qualification_expr character varying(128)
);
-- --
-- Name: badge_list_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- Name: badge_list_id_seq; Type: SEQUENCE; Schema: public; Owner: -
-- --
@ -154,13 +140,6 @@ CREATE SEQUENCE public.badge_list_id_seq
CACHE 1; CACHE 1;
--
-- Name: badge_list_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.badge_list_id_seq OWNED BY public.badge_defs.id;
-- --
-- Name: badges; Type: TABLE; Schema: public; Owner: - -- Name: badges; Type: TABLE; Schema: public; Owner: -
-- --
@ -899,12 +878,6 @@ ALTER TABLE ONLY public.alts ALTER COLUMN id SET DEFAULT nextval('public.alts_id
ALTER TABLE ONLY public.award_relationships ALTER COLUMN id SET DEFAULT nextval('public.award_relationships_id_seq'::regclass); ALTER TABLE ONLY public.award_relationships ALTER COLUMN id SET DEFAULT nextval('public.award_relationships_id_seq'::regclass);
--
-- Name: badge_defs id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.badge_defs ALTER COLUMN id SET DEFAULT nextval('public.badge_list_id_seq'::regclass);
-- --
-- Name: badges id; Type: DEFAULT; Schema: public; Owner: - -- Name: badges id; Type: DEFAULT; Schema: public; Owner: -
@ -1056,22 +1029,6 @@ ALTER TABLE ONLY public.award_relationships
ADD CONSTRAINT award_relationships_pkey PRIMARY KEY (id); ADD CONSTRAINT award_relationships_pkey PRIMARY KEY (id);
--
-- Name: badge_defs badge_defs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.badge_defs
ADD CONSTRAINT badge_defs_pkey PRIMARY KEY (id);
--
-- Name: badge_defs badge_list_icon_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.badge_defs
ADD CONSTRAINT badge_list_icon_key UNIQUE (icon);
-- --
-- Name: badges badges_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- Name: badges badges_pkey; Type: CONSTRAINT; Schema: public; Owner: -
-- --
@ -1363,13 +1320,6 @@ CREATE INDEX award_post_idx ON public.award_relationships USING btree (submissio
CREATE INDEX award_user_idx ON public.award_relationships USING btree (user_id); CREATE INDEX award_user_idx ON public.award_relationships USING btree (user_id);
--
-- Name: badgedef_qual_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX badgedef_qual_idx ON public.badge_defs USING btree (qualification_expr);
-- --
-- Name: badges_badge_id_idx; Type: INDEX; Schema: public; Owner: - -- Name: badges_badge_id_idx; Type: INDEX; Schema: public; Owner: -
-- --
@ -1755,14 +1705,6 @@ CREATE INDEX votes_submission_id_index ON public.votes USING btree (submission_i
CREATE INDEX votes_type_index ON public.votes USING btree (vote_type); CREATE INDEX votes_type_index ON public.votes USING btree (vote_type);
--
-- Name: badges badges_badge_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.badges
ADD CONSTRAINT badges_badge_id_fkey FOREIGN KEY (badge_id) REFERENCES public.badge_defs(id);
-- --
-- Name: commentflags commentflags_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- Name: commentflags commentflags_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
-- --

View File

@ -1,29 +1,3 @@
INSERT INTO public.badge_defs VALUES (12, 'Gold Recruiter', 'Recruited 100 friends to join Drama', 'recruit-100', 'v.referral_count>=100 and v.referral_count <=999');
INSERT INTO public.badge_defs VALUES (11, 'Silver Recruiter', 'Recruited 10 friends to join Drama', 'recruit-10', 'v.referral_count>=10 and v.referral_count <= 99');
INSERT INTO public.badge_defs VALUES (10, 'Bronze Recruiter', 'Recruited 1 friend to join Drama', 'recruit-1', 'v.referral_count>=1 and v.referral_count<9');
INSERT INTO public.badge_defs VALUES (58, 'Diamond Recruiter', 'Recruited 1000 friends to join Drama', 'recruit-1000', 'v.referral_count >= 1000');
INSERT INTO public.badge_defs VALUES (25, 'Footpig', 'Contributed at least $100/month', 'patron-5', 3, NULL);
INSERT INTO public.badge_defs VALUES (61, 'Lab Rat', 'Helped test features in development', 'labrat', 3, NULL);
INSERT INTO public.badge_defs VALUES (63, 'Balls', 'I wrote carp on my balls as a sign of submission', 'carpballs', 3, NULL);
INSERT INTO public.badge_defs VALUES (4, 'White Hat', 'Responsibly reported a security issue', 'whitehat', 3, NULL);
INSERT INTO public.badge_defs VALUES (2, 'Verified Email', 'Verified Email', 'mail', NULL);
INSERT INTO public.badge_defs VALUES (6, 'Beta User', 'Joined during open beta', 'beta', 4, NULL);
INSERT INTO public.badge_defs VALUES (15, 'Idea Maker', 'Had a good idea for Drama which was implemented by the developers', 'idea', 3, NULL);
INSERT INTO public.badge_defs VALUES (3, 'Code Contributor', 'Contributed to Drama source code', 'git', 3, NULL);
INSERT INTO public.badge_defs VALUES (1, 'Alpha User', 'Joined during open alpha', 'alpha', 4, NULL);
INSERT INTO public.badge_defs VALUES (18, 'Artisan', 'Contributed to Drama artwork', 'art', 3, NULL);
INSERT INTO public.badge_defs VALUES (27, 'Lolcow', 'Beautiful and valid milk provider', 'lolcow', 3, NULL);
INSERT INTO public.badge_defs VALUES (21, 'Paypig', 'Contributed at least $5/month', 'patron-1', 3, NULL);
INSERT INTO public.badge_defs VALUES (22, 'Renthog', 'Contributed at least $10/month', 'patron-2', 3, NULL);
INSERT INTO public.badge_defs VALUES (23, 'Landchad', 'Contributed at least $20/month', 'patron-3', 3, NULL);
INSERT INTO public.badge_defs VALUES (24, 'Terminally online turboautist', 'Contributed at least $50/month', 'patron-4', 3, NULL);
INSERT INTO public.badge_defs VALUES (28, 'Rich Bich', 'Contributed $500', 'patron-8', 3, NULL);
INSERT INTO public.badge_defs VALUES (7, 'Bug Finder', 'Found a bug', 'sitebreaker', 3, NULL);
INSERT INTO public.badge_defs VALUES (60, 'Unironically Retarded', 'Demonstrated a wholesale inability to read the room', 'retarded', 3, NULL);
INSERT INTO public.badge_defs VALUES (26, 'Agendaposter', 'Forced to use the agendaposter theme', 'agendaposter', NULL);
INSERT INTO public.badge_defs VALUES (17, 'Marsey Artisan', 'Contributed a Marsey emoji ✨', 'marseybadge-1', 3, NULL);
INSERT INTO public.badge_defs VALUES (16, 'Marsey Master', 'Contributed 10 (or more!!!!) Marsey emojis ✨', 'marseybadge-2', 3, NULL);
insert into public.award_relationships(id,user_id,kind) values(1,1,'shit'); insert into public.award_relationships(id,user_id,kind) values(1,1,'shit');
INSERT INTO public.users ( INSERT INTO public.users (