Sep 11 - Reupload the code
This commit is contained in:
@@ -0,0 +1,671 @@
|
||||
{% extends "base_authenticated.html" %} {% block title %}Create New User - QR
|
||||
Code Management{% endblock %} {% block content %}
|
||||
<div class="create-user-page">
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>
|
||||
<i class="fas fa-user-plus"></i>
|
||||
Create New User
|
||||
</h1>
|
||||
<p>Add a new user to the system with appropriate role permissions</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="create-user-container">
|
||||
<form
|
||||
id="createUserForm"
|
||||
method="POST"
|
||||
action="{{ url_for('users.create_user') }}"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="form-section">
|
||||
<h3>
|
||||
<i class="fas fa-user"></i>
|
||||
User Information
|
||||
</h3>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="full_name">
|
||||
<i class="fas fa-id-card"></i>
|
||||
Full Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="full_name"
|
||||
name="full_name"
|
||||
required
|
||||
placeholder="Enter full name"
|
||||
/>
|
||||
<small class="form-help">First and last name</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">
|
||||
<i class="fas fa-envelope"></i>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
placeholder="user@example.com"
|
||||
/>
|
||||
<small class="form-help">Must be unique in the system</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username">
|
||||
<i class="fas fa-user"></i>
|
||||
Username
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
name="username"
|
||||
required
|
||||
pattern="[a-zA-Z0-9_]+"
|
||||
placeholder="Enter username"
|
||||
/>
|
||||
<small class="form-help"
|
||||
>Letters, numbers, and underscores only</small
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="role">
|
||||
<i class="fas fa-user-shield"></i>
|
||||
User Role
|
||||
</label>
|
||||
<select id="role" name="role" required>
|
||||
<option value="">Select Role</option>
|
||||
<option value="staff">Staff User</option>
|
||||
<option value="payroll">Payroll Specialist</option>
|
||||
<option value="accounting">Accounting Specialist</option>
|
||||
<option value="project_manager">Project Manager</option>
|
||||
<option value="admin">Administrator</option>
|
||||
</select>
|
||||
<small class="form-help"
|
||||
>Determines user permissions and system access level</small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">
|
||||
<i class="fas fa-lock"></i>
|
||||
Initial Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
required
|
||||
minlength="6"
|
||||
placeholder="Enter initial password"
|
||||
/>
|
||||
<div class="password-strength" id="passwordStrength"></div>
|
||||
<small class="form-help"
|
||||
>Minimum 6 characters. User should change on first login</small
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- Project Manager Permissions Section -->
|
||||
<div class="permissions-section" id="pmPermissionsSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
<h3>
|
||||
<i class="fas fa-shield-alt"></i>
|
||||
Project Manager Permissions
|
||||
</h3>
|
||||
<p class="section-description">
|
||||
Follow the steps below to configure access permissions for this Project Manager.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Step 1: Select Projects -->
|
||||
<div class="permission-step" id="projectStep">
|
||||
<div class="step-header">
|
||||
<span class="step-number">1</span>
|
||||
<div class="step-info">
|
||||
<h4>Select Projects</h4>
|
||||
<p>Choose which projects this Project Manager can access</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox-group" id="projectCheckboxGroup">
|
||||
{% if projects %}
|
||||
{% for project in projects %}
|
||||
<label class="checkbox-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="assigned_projects"
|
||||
value="{{ project.id }}"
|
||||
class="checkbox-input project-checkbox"
|
||||
data-project-name="{{ project.name }}"
|
||||
>
|
||||
<span class="checkbox-text">{{ project.name }}</span>
|
||||
<span class="project-qr-count" title="QR codes in this project">
|
||||
<i class="fas fa-qrcode"></i> {{ project.qr_count or 0 }}
|
||||
</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="text-muted">No active projects available</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-footer">
|
||||
<div class="selection-summary" id="projectSummary">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>No projects selected</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Select Locations -->
|
||||
<div class="permission-step" id="locationStep" style="display: none;">
|
||||
<div class="step-header">
|
||||
<span class="step-number">2</span>
|
||||
<div class="step-info">
|
||||
<h4>Select Locations</h4>
|
||||
<p>Choose specific locations within the selected projects</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="location-loading" id="locationLoading" style="display: none;">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
<span>Loading locations...</span>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-group" id="locationCheckboxGroup">
|
||||
<!-- Locations will be populated dynamically -->
|
||||
</div>
|
||||
|
||||
<div class="location-empty" id="locationEmpty" style="display: none;">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<p>No locations found for the selected projects.</p>
|
||||
<small>QR codes in these projects may not have location data.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-footer">
|
||||
<div class="selection-summary" id="locationSummary">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>No locations selected</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selection Overview -->
|
||||
<div class="permissions-overview" id="permissionsOverview" style="display: none;">
|
||||
<div class="overview-header">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<h4>Permission Summary</h4>
|
||||
</div>
|
||||
<div class="overview-content">
|
||||
<div class="overview-item">
|
||||
<strong>Projects:</strong>
|
||||
<span id="overviewProjects">-</span>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
<strong>Locations:</strong>
|
||||
<span id="overviewLocations">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Role Information Panel -->
|
||||
<div class="info-panel" id="roleInfo" style="display: none">
|
||||
<div class="info-header">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>Role Permissions</span>
|
||||
</div>
|
||||
<div class="info-content" id="roleContent">
|
||||
<!-- Dynamic content based on selected role -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User Creation Summary -->
|
||||
<div class="creation-summary" id="creationSummary" style="display: none">
|
||||
<h3>
|
||||
<i class="fas fa-check-circle"></i>
|
||||
User Creation Summary
|
||||
</h3>
|
||||
<div class="summary-grid">
|
||||
<div class="summary-item">
|
||||
<strong>Name:</strong> <span id="summaryName">-</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<strong>Email:</strong> <span id="summaryEmail">-</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<strong>Username:</strong> <span id="summaryUsername">-</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<strong>Role:</strong> <span id="summaryRole">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<a href="{{ url_for('users.users') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
Back to Users
|
||||
</a>
|
||||
<button type="button" class="btn btn-info" id="previewUser">
|
||||
<i class="fas fa-eye"></i>
|
||||
Preview User
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-user-plus"></i>
|
||||
Create User
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %} {% block extra_scripts %}
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const form = document.getElementById("createUserForm");
|
||||
const roleSelect = document.getElementById("role");
|
||||
const roleInfo = document.getElementById("roleInfo");
|
||||
const roleContent = document.getElementById("roleContent");
|
||||
const previewBtn = document.getElementById("previewUser");
|
||||
const creationSummary = document.getElementById("creationSummary");
|
||||
|
||||
// Permission section elements
|
||||
const pmSection = document.getElementById('pmPermissionsSection');
|
||||
const projectStep = document.getElementById('projectStep');
|
||||
const locationStep = document.getElementById('locationStep');
|
||||
const permissionsOverview = document.getElementById('permissionsOverview');
|
||||
const projectCheckboxes = document.querySelectorAll('.project-checkbox');
|
||||
const projectSummary = document.getElementById('projectSummary');
|
||||
const locationSummary = document.getElementById('locationSummary');
|
||||
const locationCheckboxGroup = document.getElementById('locationCheckboxGroup');
|
||||
const locationLoading = document.getElementById('locationLoading');
|
||||
const locationEmpty = document.getElementById('locationEmpty');
|
||||
|
||||
// Form inputs
|
||||
const fullNameInput = document.getElementById("full_name");
|
||||
const emailInput = document.getElementById("email");
|
||||
const usernameInput = document.getElementById("username");
|
||||
const passwordInput = document.getElementById("password");
|
||||
const passwordStrength = document.getElementById("passwordStrength");
|
||||
|
||||
// UPDATED: Role information with new roles
|
||||
const rolePermissions = {
|
||||
staff: {
|
||||
title: "Staff User Permissions",
|
||||
permissions: [
|
||||
"Create and edit QR codes",
|
||||
"View all QR codes in the system",
|
||||
"Download QR code images",
|
||||
"Update personal profile information",
|
||||
"Access dashboard and reports",
|
||||
],
|
||||
restrictions: [
|
||||
"Cannot delete QR codes",
|
||||
"Cannot manage other users",
|
||||
"Cannot access admin settings",
|
||||
],
|
||||
},
|
||||
payroll: {
|
||||
title: "Payroll Specialist Permissions",
|
||||
permissions: [
|
||||
"Create and edit QR codes",
|
||||
"View all QR codes in the system",
|
||||
"Download QR code images",
|
||||
"Update personal profile information",
|
||||
"Access dashboard and reports",
|
||||
"Same permissions as Staff (additional features coming soon)",
|
||||
],
|
||||
restrictions: [
|
||||
"Cannot delete QR codes",
|
||||
"Cannot manage other users",
|
||||
"Cannot access admin settings",
|
||||
],
|
||||
},
|
||||
project_manager: {
|
||||
title: "Project Manager Permissions",
|
||||
permissions: [
|
||||
"View assigned projects only",
|
||||
"View assigned locations only",
|
||||
"Create and edit QR codes for assigned projects",
|
||||
"View attendance data for assigned projects/locations",
|
||||
"Download QR code images",
|
||||
"Update personal profile information",
|
||||
"Access dashboard with filtered data",
|
||||
],
|
||||
restrictions: [
|
||||
"Cannot delete QR codes",
|
||||
"Cannot manage other users",
|
||||
"Cannot access admin settings",
|
||||
"Can only view data for assigned projects and locations",
|
||||
],
|
||||
},
|
||||
admin: {
|
||||
title: "Administrator Permissions",
|
||||
permissions: [
|
||||
"Full QR code management (create, edit, delete)",
|
||||
"Complete user management capabilities",
|
||||
"System configuration access",
|
||||
"View all system analytics",
|
||||
"Bulk operations and data export",
|
||||
"Access to all admin features",
|
||||
],
|
||||
restrictions: ["With great power comes great responsibility!"],
|
||||
},
|
||||
};
|
||||
|
||||
// Role selection handler
|
||||
roleSelect.addEventListener("change", function () {
|
||||
const selectedRole = this.value;
|
||||
|
||||
if (selectedRole && rolePermissions[selectedRole]) {
|
||||
const roleData = rolePermissions[selectedRole];
|
||||
let permissionsHtml = `
|
||||
<h4>${roleData.title}</h4>
|
||||
<div class="permissions-section">
|
||||
<h5><i class="fas fa-check-circle text-success"></i> Permissions</h5>
|
||||
<ul class="permissions-list">
|
||||
`;
|
||||
roleData.permissions.forEach((permission) => {
|
||||
permissionsHtml += `<li><i class="fas fa-check"></i> ${permission}</li>`;
|
||||
});
|
||||
permissionsHtml += `
|
||||
</ul>
|
||||
<h5><i class="fas fa-times-circle text-warning"></i> Restrictions</h5>
|
||||
<ul class="restrictions-list">
|
||||
`;
|
||||
roleData.restrictions.forEach((restriction) => {
|
||||
permissionsHtml += `<li><i class="fas fa-times"></i> ${restriction}</li>`;
|
||||
});
|
||||
permissionsHtml += `</ul></div>`;
|
||||
|
||||
roleContent.innerHTML = permissionsHtml;
|
||||
roleInfo.style.display = "block";
|
||||
setTimeout(() => roleInfo.classList.add("fade-in"), 100);
|
||||
} else {
|
||||
roleInfo.style.display = "none";
|
||||
roleInfo.classList.remove("fade-in");
|
||||
}
|
||||
|
||||
// Show/hide Project Manager permissions section
|
||||
if (selectedRole === 'project_manager') {
|
||||
pmSection.style.display = 'block';
|
||||
setupPermissionFlow();
|
||||
} else {
|
||||
pmSection.style.display = 'none';
|
||||
resetPermissionFlow();
|
||||
}
|
||||
});
|
||||
|
||||
// Setup cascading permission flow
|
||||
function setupPermissionFlow() {
|
||||
// Reset state
|
||||
locationStep.style.display = 'none';
|
||||
permissionsOverview.style.display = 'none';
|
||||
locationCheckboxGroup.innerHTML = '';
|
||||
|
||||
// Add event listeners to project checkboxes
|
||||
projectCheckboxes.forEach(checkbox => {
|
||||
checkbox.addEventListener('change', handleProjectSelection);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle project selection changes
|
||||
function handleProjectSelection() {
|
||||
const selectedProjects = Array.from(projectCheckboxes)
|
||||
.filter(cb => cb.checked)
|
||||
.map(cb => ({
|
||||
id: cb.value,
|
||||
name: cb.dataset.projectName
|
||||
}));
|
||||
|
||||
// Update project summary
|
||||
if (selectedProjects.length > 0) {
|
||||
projectSummary.innerHTML = `
|
||||
<i class="fas fa-check-circle" style="color: #10b981;"></i>
|
||||
<span><strong>${selectedProjects.length}</strong> project${selectedProjects.length > 1 ? 's' : ''} selected</span>
|
||||
`;
|
||||
|
||||
// Show location step and load locations
|
||||
locationStep.style.display = 'block';
|
||||
loadLocationsByProjects(selectedProjects.map(p => p.id));
|
||||
} else {
|
||||
projectSummary.innerHTML = `
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>No projects selected</span>
|
||||
`;
|
||||
locationStep.style.display = 'none';
|
||||
permissionsOverview.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Load locations for selected projects
|
||||
async function loadLocationsByProjects(projectIds) {
|
||||
locationLoading.style.display = 'flex';
|
||||
locationCheckboxGroup.innerHTML = '';
|
||||
locationEmpty.style.display = 'none';
|
||||
locationSummary.innerHTML = `
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>Loading locations...</span>
|
||||
`;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/locations-by-projects', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': (window.qrConfig && window.qrConfig.csrfToken) || '',
|
||||
},
|
||||
body: JSON.stringify({ project_ids: projectIds })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
locationLoading.style.display = 'none';
|
||||
|
||||
if (data.success && data.locations.length > 0) {
|
||||
// Populate location checkboxes
|
||||
locationCheckboxGroup.innerHTML = data.locations.map(location => `
|
||||
<label class="checkbox-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="assigned_locations"
|
||||
value="${location}"
|
||||
class="checkbox-input location-checkbox"
|
||||
>
|
||||
<span class="checkbox-text">${location}</span>
|
||||
</label>
|
||||
`).join('');
|
||||
|
||||
// Add event listeners to location checkboxes
|
||||
document.querySelectorAll('.location-checkbox').forEach(cb => {
|
||||
cb.addEventListener('change', handleLocationSelection);
|
||||
});
|
||||
|
||||
locationSummary.innerHTML = `
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>${data.count} location${data.count > 1 ? 's' : ''} available</span>
|
||||
`;
|
||||
} else {
|
||||
locationEmpty.style.display = 'block';
|
||||
locationSummary.innerHTML = `
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
<span>No locations available</span>
|
||||
`;
|
||||
}
|
||||
|
||||
updatePermissionsOverview();
|
||||
} catch (error) {
|
||||
console.error('Error loading locations:', error);
|
||||
locationLoading.style.display = 'none';
|
||||
locationEmpty.style.display = 'block';
|
||||
locationSummary.innerHTML = `
|
||||
<i class="fas fa-exclamation-triangle" style="color: #ef4444;"></i>
|
||||
<span>Error loading locations</span>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle location selection changes
|
||||
function handleLocationSelection() {
|
||||
const selectedLocations = Array.from(document.querySelectorAll('.location-checkbox:checked'));
|
||||
|
||||
if (selectedLocations.length > 0) {
|
||||
locationSummary.innerHTML = `
|
||||
<i class="fas fa-check-circle" style="color: #10b981;"></i>
|
||||
<span><strong>${selectedLocations.length}</strong> location${selectedLocations.length > 1 ? 's' : ''} selected</span>
|
||||
`;
|
||||
} else {
|
||||
const totalLocations = document.querySelectorAll('.location-checkbox').length;
|
||||
locationSummary.innerHTML = `
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>${totalLocations} location${totalLocations > 1 ? 's' : ''} available</span>
|
||||
`;
|
||||
}
|
||||
|
||||
updatePermissionsOverview();
|
||||
}
|
||||
|
||||
// Update permissions overview
|
||||
function updatePermissionsOverview() {
|
||||
const selectedProjects = Array.from(projectCheckboxes)
|
||||
.filter(cb => cb.checked)
|
||||
.map(cb => cb.dataset.projectName);
|
||||
|
||||
const selectedLocations = Array.from(document.querySelectorAll('.location-checkbox:checked'))
|
||||
.map(cb => cb.value);
|
||||
|
||||
if (selectedProjects.length > 0 || selectedLocations.length > 0) {
|
||||
permissionsOverview.style.display = 'block';
|
||||
|
||||
document.getElementById('overviewProjects').textContent =
|
||||
selectedProjects.length > 0
|
||||
? selectedProjects.join(', ')
|
||||
: 'All projects';
|
||||
|
||||
document.getElementById('overviewLocations').textContent =
|
||||
selectedLocations.length > 0
|
||||
? selectedLocations.join(', ')
|
||||
: 'All locations in selected projects';
|
||||
} else {
|
||||
permissionsOverview.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Reset permission flow
|
||||
function resetPermissionFlow() {
|
||||
projectCheckboxes.forEach(cb => {
|
||||
cb.checked = false;
|
||||
cb.removeEventListener('change', handleProjectSelection);
|
||||
});
|
||||
locationStep.style.display = 'none';
|
||||
permissionsOverview.style.display = 'none';
|
||||
locationCheckboxGroup.innerHTML = '';
|
||||
}
|
||||
|
||||
// Password strength indicator
|
||||
passwordInput.addEventListener("input", function () {
|
||||
const password = this.value;
|
||||
const strength = calculatePasswordStrength(password);
|
||||
|
||||
passwordStrength.className = `password-strength ${strength.class}`;
|
||||
passwordStrength.textContent = strength.text;
|
||||
});
|
||||
|
||||
// Preview user functionality
|
||||
previewBtn.addEventListener("click", function () {
|
||||
const fullName = fullNameInput.value.trim();
|
||||
const email = emailInput.value.trim();
|
||||
const username = usernameInput.value.trim();
|
||||
const role = roleSelect.value;
|
||||
|
||||
if (!fullName || !email || !username || !role) {
|
||||
alert("Please fill in all required fields before previewing.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update summary
|
||||
document.getElementById("summaryName").textContent = fullName;
|
||||
document.getElementById("summaryEmail").textContent = email;
|
||||
document.getElementById("summaryUsername").textContent = username;
|
||||
|
||||
// Get role display name
|
||||
const roleDisplayNames = {
|
||||
staff: "Staff User",
|
||||
payroll: "Payroll Specialist",
|
||||
project_manager: "Project Manager",
|
||||
admin: "Administrator",
|
||||
};
|
||||
document.getElementById("summaryRole").textContent =
|
||||
roleDisplayNames[role] || role;
|
||||
|
||||
creationSummary.style.display = "block";
|
||||
setTimeout(() => creationSummary.classList.add("fade-in"), 100);
|
||||
|
||||
// Scroll to summary
|
||||
creationSummary.scrollIntoView({ behavior: "smooth" });
|
||||
});
|
||||
|
||||
// Form validation
|
||||
form.addEventListener("submit", function (e) {
|
||||
const password = passwordInput.value;
|
||||
|
||||
if (password.length < 6) {
|
||||
e.preventDefault();
|
||||
alert("Password must be at least 6 characters long.");
|
||||
passwordInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!roleSelect.value) {
|
||||
e.preventDefault();
|
||||
alert("Please select a user role.");
|
||||
roleSelect.focus();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// Username validation
|
||||
usernameInput.addEventListener("input", function () {
|
||||
this.value = this.value.replace(/[^a-zA-Z0-9_]/g, "");
|
||||
});
|
||||
});
|
||||
|
||||
function calculatePasswordStrength(password) {
|
||||
if (password.length === 0) {
|
||||
return { class: "", text: "" };
|
||||
}
|
||||
|
||||
let score = 0;
|
||||
|
||||
// Length
|
||||
if (password.length >= 6) score += 1;
|
||||
if (password.length >= 8) score += 1;
|
||||
if (password.length >= 12) score += 1;
|
||||
|
||||
// Character variety
|
||||
if (/[a-z]/.test(password)) score += 1;
|
||||
if (/[A-Z]/.test(password)) score += 1;
|
||||
if (/[0-9]/.test(password)) score += 1;
|
||||
if (/[^a-zA-Z0-9]/.test(password)) score += 1;
|
||||
|
||||
if (score < 3) {
|
||||
return { class: "weak", text: "Weak password" };
|
||||
} else if (score < 5) {
|
||||
return { class: "medium", text: "Medium strength" };
|
||||
} else {
|
||||
return { class: "strong", text: "Strong password" };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user