From 864f7707620031342fd3a05d5f4e7463b1fcce99 Mon Sep 17 00:00:00 2001 From: Aevann Date: Sat, 13 May 2023 07:53:14 +0300 Subject: [PATCH] add namelock award --- files/assets/css/dark.css | 4 ++++ files/assets/css/main.css | 1 + files/assets/css/midnight.css | 4 ++++ files/assets/js/award_modal.js | 5 +++++ files/assets/js/namechanged.js | 4 ++++ files/classes/user.py | 2 ++ files/helpers/config/awards.py | 14 +++++++++++++- files/helpers/cron.py | 4 ++++ files/helpers/get.py | 9 ++++++--- files/helpers/sanitize.py | 2 ++ files/routes/admin.py | 3 ++- files/routes/awards.py | 11 +++++++++++ files/routes/search.py | 3 ++- files/routes/settings.py | 6 +++++- files/routes/users.py | 3 ++- files/templates/settings/personal.html | 10 ++++++++-- migrations/20230513-add-namelock-award.sql | 7 +++++++ 17 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 files/assets/js/namechanged.js create mode 100644 migrations/20230513-add-namelock-award.sql diff --git a/files/assets/css/dark.css b/files/assets/css/dark.css index 0c4cb7873..7de079168 100644 --- a/files/assets/css/dark.css +++ b/files/assets/css/dark.css @@ -95,3 +95,7 @@ pre { h5.post-title a:visited { color: #7a7a7a !important; } + +[disabled], .disabled, button[disabled], .btn[disabled], button.disabled, .btn.disabled { + color: #bbb !important; +} diff --git a/files/assets/css/main.css b/files/assets/css/main.css index 762b71897..a5f1e9ad4 100644 --- a/files/assets/css/main.css +++ b/files/assets/css/main.css @@ -205,6 +205,7 @@ .fa-lock-open:before{content:"\f3c1"} .fa-down:before{content:"\f354"} .fa-shield-virus:before{content:"\e06c"} +.fa-at:before{content:"\40"} button { background: none; diff --git a/files/assets/css/midnight.css b/files/assets/css/midnight.css index 13f83eddb..18ac8d475 100644 --- a/files/assets/css/midnight.css +++ b/files/assets/css/midnight.css @@ -64,3 +64,7 @@ h5.post-title a:visited { .modal-content { border: 1px var(--gray-500) solid; } + +[disabled], .disabled, button[disabled], .btn[disabled], button.disabled, .btn.disabled { + color: #bbb !important; +} diff --git a/files/assets/js/award_modal.js b/files/assets/js/award_modal.js index 3ab3dbb0a..e84cd0cfd 100644 --- a/files/assets/js/award_modal.js +++ b/files/assets/js/award_modal.js @@ -133,6 +133,11 @@ function pick(kind, price, coins, marseybux) { document.getElementById('note').placeholder = "Insert new flair here, or leave empty to add 1 day to the duration of the current flair. 100 characters max."; document.getElementById('note').maxLength = 100; } + else if (kind == "namelock") { + document.getElementById('notelabel').innerHTML = "New username:"; + document.getElementById('note').placeholder = "Insert new username here, or leave empty to add 1 day to the duration of the current username. 25 characters max."; + document.getElementById('note').maxLength = 25; + } else { document.getElementById('notelabel').innerHTML = "Note (optional):"; document.getElementById('note').placeholder = "Note to include in award notification"; diff --git a/files/assets/js/namechanged.js b/files/assets/js/namechanged.js new file mode 100644 index 000000000..80d44573e --- /dev/null +++ b/files/assets/js/namechanged.js @@ -0,0 +1,4 @@ +const namechanged = document.getElementById('namechanged').value +const namedate = formatDate(new Date(namechanged*1000)); +const nametext = ` - Your username has been locked until ${namedate}`; +document.getElementById('name-body').value += nametext; diff --git a/files/classes/user.py b/files/classes/user.py index ec4ec48bd..cbe6e916f 100644 --- a/files/classes/user.py +++ b/files/classes/user.py @@ -105,6 +105,7 @@ class User(Base): slurreplacer = Column(Integer, default=1) profanityreplacer = Column(Integer, default=1) flairchanged = Column(Integer, default=0) + namechanged = Column(Integer, default=0) newtab = Column(Boolean, default=False) newtabexternal = Column(Boolean, default=True) reddit = Column(String, default='old.reddit.com') @@ -140,6 +141,7 @@ class User(Base): defaulttime = Column(String, default=DEFAULT_TIME_FILTER) custom_filter_list = Column(String) original_username = Column(String) + prelock_username = Column(String) referred_by = Column(Integer, ForeignKey("users.id")) currently_held_lottery_tickets = Column(Integer, default=0) total_held_lottery_tickets = Column(Integer, default=0) diff --git a/files/helpers/config/awards.py b/files/helpers/config/awards.py index d023b7a1f..2796ed30d 100644 --- a/files/helpers/config/awards.py +++ b/files/helpers/config/awards.py @@ -507,6 +507,18 @@ AWARDS = { "ghost": False, "enabled": True, }, + "namelock": { + "kind": "namelock", + "title": "1-Day Namelock", + "description": "Changes the user's username to something of your choosing for 24 hours.", + "icon": "fas fa-at", + "color": "text-pink", + "price": 1000, + "deflectable": True, + "cosmetic": False, + "ghost": False, + "enabled": True, + }, "agendaposter": { "kind": "agendaposter", "title": "Chud", @@ -704,7 +716,7 @@ AWARDS = { "title": "Fish", "description": "This user cannot be unfollowed", "icon": "fas fa-fish", - "color": "text-lightblue", + "color": "text-gold", "price": 20000, "deflectable": True, "cosmetic": False, diff --git a/files/helpers/cron.py b/files/helpers/cron.py index 85d004ea5..554009fe5 100644 --- a/files/helpers/cron.py +++ b/files/helpers/cron.py @@ -242,3 +242,7 @@ def _award_timers_task(): User.chudded_by: None, }) _process_timer(User.flairchanged, [96], "Your temporary flair-lock has expired. You can now change your flair!") + _process_timer(User.namechanged, [], "Your temporary name-lock has expired. You're now back to your old username!", { + User.username: User.prelock_username, + User.prelock_username: None, + }) diff --git a/files/helpers/get.py b/files/helpers/get.py index 3e20257f7..e9314a57f 100644 --- a/files/helpers/get.py +++ b/files/helpers/get.py @@ -22,7 +22,8 @@ def get_id(username:str, graceful=False) -> Optional[int]: ).filter( or_( User.username.ilike(username), - User.original_username.ilike(username) + User.original_username.ilike(username), + User.prelock_username.ilike(username), ) ).one_or_none() @@ -46,7 +47,8 @@ def get_user(username:Optional[str], v:Optional[User]=None, graceful=False, incl ).filter( or_( User.username.ilike(username), - User.original_username.ilike(username) + User.original_username.ilike(username), + User.prelock_username.ilike(username), ) ) @@ -75,7 +77,8 @@ def get_users(usernames:Iterable[str], ids_only=False, graceful=False) -> List[U users = users.filter( or_( User.username.ilike(any_(usernames)), - User.original_username.ilike(any_(usernames)) + User.original_username.ilike(any_(usernames)), + User.prelock_username.ilike(any_(usernames)), ) ).all() diff --git a/files/helpers/sanitize.py b/files/helpers/sanitize.py index c8a058443..5c30cbcc2 100644 --- a/files/helpers/sanitize.py +++ b/files/helpers/sanitize.py @@ -381,6 +381,8 @@ def sanitize(sanitized, golden=True, limit_pings=0, showmore=True, count_emojis= users_dict[u.username.lower()] = u if u.original_username: users_dict[u.original_username.lower()] = u + if u.prelock_username: + users_dict[u.prelock_username.lower()] = u def replacer(m): u = users_dict.get(m.group(1).lower()) diff --git a/files/routes/admin.py b/files/routes/admin.py index 4fb167e75..a27a765e7 100644 --- a/files/routes/admin.py +++ b/files/routes/admin.py @@ -903,7 +903,8 @@ def admin_title_change(user_id, v): user=get_account(user.id) user.customtitle=new_name - if request.values.get("locked"): user.flairchanged = int(time.time()) + 2629746 + if request.values.get("locked"): + user.flairchanged = int(time.time()) + 2629746 else: user.flairchanged = 0 badge = user.has_badge(96) diff --git a/files/routes/awards.py b/files/routes/awards.py index d2ff0e59e..6b18f2741 100644 --- a/files/routes/awards.py +++ b/files/routes/awards.py @@ -348,6 +348,17 @@ def award_thing(v, thing_type, id): author.customtitle = new_name author.flairchanged = int(time.time()) + 86400 badge_grant(user=author, badge_id=96) + elif kind == "namelock": + new_name = note.strip() + if not valid_username_regex.fullmatch(new_name): + abort(400, "Invalid username") + + if not new_name and author.prelock_username: + author.namechanged += 86400 + else: + author.prelock_username = author.username + author.username = new_name + author.namechanged = int(time.time()) + 86400 elif kind == "pause": badge_grant(badge_id=68, user=author) elif kind == "unpausable": diff --git a/files/routes/search.py b/files/routes/search.py index 0952c7a46..ae857af9a 100644 --- a/files/routes/search.py +++ b/files/routes/search.py @@ -397,7 +397,8 @@ def searchusers(v:User): users = users.filter( or_( User.username.ilike(f'%{term}%'), - User.original_username.ilike(f'%{term}%') + User.original_username.ilike(f'%{term}%'), + User.prelock_username.ilike(f'%{term}%'), ) ).order_by(User.username.ilike(term).desc(), User.stored_subscriber_count.desc()) diff --git a/files/routes/settings.py b/files/routes/settings.py index f78fc960e..4b8662eef 100644 --- a/files/routes/settings.py +++ b/files/routes/settings.py @@ -572,6 +572,7 @@ def settings_images_profile(v): cache.delete_memoized(get_profile_picture, v.id) cache.delete_memoized(get_profile_picture, v.username) cache.delete_memoized(get_profile_picture, v.original_username) + cache.delete_memoized(get_profile_picture, v.prelock_username) return redirect("/settings/personal?msg=Profile picture successfully updated!") @@ -720,6 +721,8 @@ def settings_advanced_get(v:User): @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def settings_name_change(v): + if v.namechanged: abort(403) + new_name=request.values.get("name").strip() if new_name==v.username: @@ -737,7 +740,8 @@ def settings_name_change(v): x = g.db.query(User).filter( or_( User.username.ilike(search_name), - User.original_username.ilike(search_name) + User.original_username.ilike(search_name), + User.prelock_username.ilike(search_name), ) ).one_or_none() diff --git a/files/routes/users.py b/files/routes/users.py index 764ba2ebe..4aaa44e07 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -715,7 +715,8 @@ def is_available(name:str): x = g.db.query(User).filter( or_( User.username.ilike(name2), - User.original_username.ilike(name2) + User.original_username.ilike(name2), + User.prelock_username.ilike(name2), ) ).one_or_none() diff --git a/files/templates/settings/personal.html b/files/templates/settings/personal.html index 395cd75ea..3287e0025 100644 --- a/files/templates/settings/personal.html +++ b/files/templates/settings/personal.html @@ -163,10 +163,10 @@

Your original username will always stay reserved for you: {{v.original_username}}

- + 3-25 characters, including letters, numbers, _ , and -
- +
@@ -268,6 +268,12 @@ {% if v.flairchanged %} + +{% endif %} + +{% if v.namechanged %} + + {% endif %} diff --git a/migrations/20230513-add-namelock-award.sql b/migrations/20230513-add-namelock-award.sql new file mode 100644 index 000000000..11a2a9664 --- /dev/null +++ b/migrations/20230513-add-namelock-award.sql @@ -0,0 +1,7 @@ +alter table users add column prelock_username varchar(30) unique; + +alter table users add column namechanged integer; + +create unique index lowercase_prelock_username on users using btree (lower((prelock_username)::text)); + +create index users_prelock_username_trgm_idx on users using gin (prelock_username gin_trgm_ops);