feat(admin): SmartAdmin template redesign + security hardening
- Migrated all admin views from inline JS string templates to EJS - Integrated SmartAdmin template with dark sidebar, fixed header, CSS grid - Added express-ejs-layouts for master layout wrapper - Security: - CSRF protection (double-submit cookie) - Rate limiting on /login (5/15min) - Token revocation via jti + globalLogoutTimestamp - Re-auth (reauth_token) for destructive endpoints - Settings whitelist (ALLOWED_KEYS) + removed process.exit - Seed phrases no longer rendered in HTML (CSV export only) - Multer fileFilter for image uploads + safe filename generation - SQL injection fix (currency column allowlist) - Global error handler + asyncHandler wrapper - New files: csrf.js, errorHandler.js, error.ejs, all EJS templates - SmartAdmin assets: CSS, icons, webfonts, plugins, scripts
This commit is contained in:
57
src/admin/views/locations.ejs
Normal file
57
src/admin/views/locations.ejs
Normal file
@@ -0,0 +1,57 @@
|
||||
<div class="panel panel-icon mb-3">
|
||||
<div class="panel-hdr">
|
||||
<h2 class="d-flex align-items-center gap-2">
|
||||
<button class="btn btn-link p-0 text-decoration-none" type="button" data-bs-toggle="collapse" data-bs-target="#addLocationCollapse" aria-expanded="false" aria-controls="addLocationCollapse">Add Location</button>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="collapse" id="addLocationCollapse">
|
||||
<div class="panel-content">
|
||||
<form method="POST" action="/locations" class="d-flex flex-wrap gap-2 align-items-end">
|
||||
<div>
|
||||
<label class="form-label">Country</label>
|
||||
<input name="country" class="form-control form-control-sm" placeholder="Country" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">City</label>
|
||||
<input name="city" class="form-control form-control-sm" placeholder="City" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">District</label>
|
||||
<input name="district" class="form-control form-control-sm" placeholder="District">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-icon">
|
||||
<div class="panel-container show">
|
||||
<div class="panel-content">
|
||||
<table class="table table-striped table-bordered table-hover mb-0">
|
||||
<thead><tr><th>ID</th><th>Country</th><th>City</th><th>District</th><th>Categories</th><th>Products</th><th>Actions</th></tr></thead>
|
||||
<tbody>
|
||||
<% if (locations.length === 0) { %>
|
||||
<tr><td colspan="7" class="text-muted">No locations</td></tr>
|
||||
<% } else { %>
|
||||
<% locations.forEach(function(l) { %>
|
||||
<tr>
|
||||
<td><%= l.id %></td>
|
||||
<td><%= l.country %></td>
|
||||
<td><%= l.city %></td>
|
||||
<td><%= l.district || '' %></td>
|
||||
<td><%= l.category_count || 0 %></td>
|
||||
<td><%= l.product_count || 0 %></td>
|
||||
<td>
|
||||
<form method="POST" action="/locations/<%= l.id %>/delete" class="d-inline" onsubmit="return confirm('Delete location?')">
|
||||
<button class="btn btn-sm btn-danger">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<% }); %>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user