password change feature
All checks were successful
Build Images and Deploy / Update-PROD-Stack (push) Successful in 29s
All checks were successful
Build Images and Deploy / Update-PROD-Stack (push) Successful in 29s
This commit is contained in:
10
public/favicon.svg
Normal file
10
public/favicon.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<circle cx="32" cy="32" r="30" fill="#6c5ce7"/>
|
||||
<circle cx="32" cy="32" r="20" fill="none" stroke="#fdcb6e" stroke-width="3"/>
|
||||
<circle cx="32" cy="32" r="10" fill="none" stroke="#fdcb6e" stroke-width="3"/>
|
||||
<circle cx="32" cy="32" r="3" fill="#fdcb6e"/>
|
||||
<line x1="32" y1="2" x2="32" y2="16" stroke="#fdcb6e" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="32" y1="48" x2="32" y2="62" stroke="#fdcb6e" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="2" y1="32" x2="16" y2="32" stroke="#fdcb6e" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="48" y1="32" x2="62" y2="32" stroke="#fdcb6e" stroke-width="3" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 723 B |
@@ -1,5 +1,6 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { requireAuth } = require('../middleware/auth');
|
||||
const { Hunts, Packages, Scans, Users } = require('../models');
|
||||
|
||||
// ─── Hunt profile ─────────────────────────────────────────
|
||||
@@ -95,6 +96,36 @@ router.get('/player/:username', (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Change password (own profile) ────────────────────────
|
||||
router.post('/player/:username/password', requireAuth, (req, res) => {
|
||||
const user = Users.findByUsername(req.params.username);
|
||||
if (!user || user.id !== req.session.userId) {
|
||||
return res.status(403).render('error', { title: 'Forbidden', message: 'You can only change your own password.' });
|
||||
}
|
||||
|
||||
const { current_password, new_password, new_password_confirm } = req.body;
|
||||
|
||||
const fullUser = Users.findByUsername(user.username);
|
||||
if (!Users.verifyPassword(fullUser, current_password)) {
|
||||
req.session.flash = { type: 'danger', message: 'Current password is incorrect.' };
|
||||
return res.redirect(`/player/${user.username}`);
|
||||
}
|
||||
|
||||
if (!new_password || new_password.length < 6) {
|
||||
req.session.flash = { type: 'danger', message: 'New password must be at least 6 characters.' };
|
||||
return res.redirect(`/player/${user.username}`);
|
||||
}
|
||||
|
||||
if (new_password !== new_password_confirm) {
|
||||
req.session.flash = { type: 'danger', message: 'New passwords do not match.' };
|
||||
return res.redirect(`/player/${user.username}`);
|
||||
}
|
||||
|
||||
Users.setPassword(user.id, new_password);
|
||||
req.session.flash = { type: 'success', message: 'Password changed successfully.' };
|
||||
res.redirect(`/player/${user.username}`);
|
||||
});
|
||||
|
||||
// ─── Browse all hunts ─────────────────────────────────────
|
||||
router.get('/hunts', (req, res) => {
|
||||
const hunts = Hunts.getAll();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><%= typeof title !== 'undefined' ? title + ' | Loot Hunt' : 'Loot Hunt' %></title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<script>
|
||||
// Apply theme before render to prevent flash
|
||||
|
||||
@@ -86,6 +86,28 @@
|
||||
<div style="text-align: center; margin-top: 1rem;">
|
||||
<a href="/leaderboard" class="btn btn-outline">Global Leaderboard</a>
|
||||
</div>
|
||||
|
||||
<% if (typeof isOwnProfile !== 'undefined' && isOwnProfile) { %>
|
||||
<div class="card" style="margin-top: 1.5rem;">
|
||||
<div class="card-header">🔒 Change Password</div>
|
||||
<form method="POST" action="/player/<%= profile.username %>/password">
|
||||
<div class="form-group">
|
||||
<label for="current_password">Current Password</label>
|
||||
<input type="password" id="current_password" name="current_password" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password">New Password</label>
|
||||
<input type="password" id="new_password" name="new_password" class="form-control" required minlength="6">
|
||||
<div class="form-hint">At least 6 characters.</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password_confirm">Confirm New Password</label>
|
||||
<input type="password" id="new_password_confirm" name="new_password_confirm" class="form-control" required minlength="6">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Change Password</button>
|
||||
</form>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<%- include('../partials/footer') %>
|
||||
|
||||
Reference in New Issue
Block a user