Changeset 7c44c12 in Klonkt


Ignore:
Timestamp:
06/24/2026 01:45:21 PM (3 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
de3d24b
Parents:
a885afc
Message:

feat(account): editable username (does not affect the fediverse handle)

Username field in the profile form + validation (format, reserved, unique).
The AP handle is the site slug, so renaming the login name is purely cosmetic.

Co-Authored-By: Claude <noreply@…>

Location:
src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/routes/account.js

    ra885afc r7c44c12  
    124124
    125125// ==================== UPDATE BIO ====================
     126const RESERVED_USERNAMES = new Set(['admin', 'account', 'auth', 'login', 'register', 'logout', 'user', 'users', 'api', 'fediverse', 'posts', 'media', 'audio', 'assets', 'cirkel', 'authorize_interaction']);
     127
    126128router.post('/profile', requireAuth, (req, res) => {
    127129  const bio = (req.body.bio || '').toString().slice(0, 500).trim();
     130
     131  // Username (login + display name; does NOT affect the fediverse handle, which
     132  // is the site slug). Validate: format + reserved + unique (case-insensitive).
     133  const username = (req.body.username || '').toString().trim();
     134  if (username && username !== req.session.user.username) {
     135    if (!/^[A-Za-z0-9_-]{2,30}$/.test(username)) {
     136      return res.redirect('/account?error=' + encodeURIComponent('Gebruikersnaam: 2-30 tekens; letters, cijfers, _ en - .'));
     137    }
     138    if (RESERVED_USERNAMES.has(username.toLowerCase())) {
     139      return res.redirect('/account?error=' + encodeURIComponent('Die gebruikersnaam is gereserveerd.'));
     140    }
     141    const uTaken = db.prepare('SELECT 1 FROM users WHERE LOWER(username) = LOWER(?) AND id != ?').get(username, req.session.user.id);
     142    if (uTaken) {
     143      return res.redirect('/account?error=' + encodeURIComponent('Die gebruikersnaam is al in gebruik.'));
     144    }
     145    db.prepare('UPDATE users SET username = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(username, req.session.user.id);
     146    req.session.user.username = username;
     147  }
    128148
    129149  // Email (optionally also changed). Validation: valid format + not already in use
  • src/services/i18n.js

    ra885afc r7c44c12  
    799799    'acct.member_since': 'Lid sinds',
    800800    'acct.avatar_remove': 'Foto verwijderen',
     801    'acct.username': 'Gebruikersnaam',
    801802    'acct.email': 'E-mailadres',
    802803    'acct.email_ph': 'jij@email.nl',
     
    17921793    'acct.member_since': 'Member since',
    17931794    'acct.avatar_remove': 'Remove photo',
     1795    'acct.username': 'Username',
    17941796    'acct.email': 'Email address',
    17951797    'acct.email_ph': 'you@email.com',
     
    27852787    'acct.member_since': 'Mitglied seit',
    27862788    'acct.avatar_remove': 'Foto entfernen',
     2789    'acct.username': 'Benutzername',
    27872790    'acct.email': 'E-Mail-Adresse',
    27882791    'acct.email_ph': 'du@email.de',
  • src/views/pages/account.ejs

    ra885afc r7c44c12  
    7171      <form action="/account/profile" method="post" class="ax-form ax-form-bio">
    7272        <label class="ax-field">
     73          <span><%= t('acct.username') %></span>
     74          <input type="text" name="username" value="<%= account.username %>" minlength="2" maxlength="30" pattern="[A-Za-z0-9_\-]{2,30}" autocomplete="username">
     75        </label>
     76        <label class="ax-field">
    7377          <span><%= t('acct.email') %></span>
    7478          <input type="email" name="email" value="<%= account.email || '' %>" maxlength="254" autocomplete="email" placeholder="<%= t('acct.email_ph') %>">
Note: See TracChangeset for help on using the changeset viewer.