megacommit
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
<body>
|
||||
<div class="signup-container">
|
||||
<div class="signup-header">
|
||||
<div class="logo">DC</div>
|
||||
<img src="/static/favicon.ico" class="logo"/>
|
||||
<h1>2FA Setup</h1>
|
||||
</div>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<div class="form-group">
|
||||
<input
|
||||
type="text"
|
||||
id="mfa_code"
|
||||
inputmode="numeric"
|
||||
pattern="[0-9]*"
|
||||
maxlength="6"
|
||||
@@ -38,10 +39,73 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
fetch('/api/totp.jpg')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('qr-code').src = data.qr_code;
|
||||
const form = {
|
||||
code: document.getElementById("mfa_code"),
|
||||
};
|
||||
|
||||
submitButton.addEventListener("click", async function () {
|
||||
submitButton.disabled = true;
|
||||
submitButton.innerHTML =
|
||||
'<span class="loading-spinner"></span>Creating Account...';
|
||||
|
||||
// Prepare data
|
||||
const formData = {
|
||||
code: form.code.value.trim(),
|
||||
};
|
||||
|
||||
try {
|
||||
// Replace with your actual backend endpoint
|
||||
const response = await fetch(
|
||||
"/api/totp",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
},
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
// Show success message
|
||||
successMessage.classList.add("show");
|
||||
submitButton.innerHTML = "2FA Enabled";
|
||||
|
||||
// Optional: Redirect after success
|
||||
setTimeout(() => {
|
||||
window.location.href = '/chat';
|
||||
// console.log("Redirecting to chat...");
|
||||
}, 2000);
|
||||
} else {
|
||||
const error = await response.text();
|
||||
throw new Error(error || "Login failed");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Login error:", error);
|
||||
alert(
|
||||
error.message ||
|
||||
"Failed to login. Please try again.",
|
||||
);
|
||||
submitButton.disabled = false;
|
||||
submitButton.innerHTML = "Login";
|
||||
}
|
||||
});
|
||||
|
||||
fetch('/api/totp.jpg')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('qr-code').src = data.qr_code;
|
||||
});
|
||||
|
||||
// Allow Enter key to submit
|
||||
Object.values(form).forEach((input) => {
|
||||
if (input.tagName === "INPUT") {
|
||||
input.addEventListener("keypress", function (e) {
|
||||
if (e.key === "Enter") {
|
||||
submitButton.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Concept Page</title>
|
||||
<link rel="stylesheet" href="static/css/index.css"/>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github.min.css">
|
||||
<script type="module" src="/static/js/chat.js"></script>
|
||||
<script>
|
||||
const user_id = {{ user_id }};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- content goes here -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,45 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{error_code}} Error - Discord Clone</title>
|
||||
<link rel="stylesheet" href="/static/css/index.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="signup-container">
|
||||
<div class="signup-header">
|
||||
<img src="/static/favicon.ico" class="logo"/>
|
||||
<h1>Error {{error_code}}</h1>
|
||||
</div>
|
||||
|
||||
<div class="signup-form">
|
||||
<div class="success-message" id="errorMessage">
|
||||
{{error_message}}
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<p>{{additional_info}}</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 40px;"></div>
|
||||
|
||||
{% if redirect %}
|
||||
<button type="button" class="submit-button" onclick="window.location.replace('{{redirect.url}}');">
|
||||
{{redirect.message}}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="signup-footer">
|
||||
If you think this is an error, contact an administrator.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Optional: Add some basic JavaScript for dynamic content if needed.
|
||||
// For example, to highlight the error code in the title.
|
||||
document.title = "Error " + "${error_code}";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,230 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Discord Clone - Create Access Token</title>
|
||||
<link rel="stylesheet" href="static/css/index.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="signup-container">
|
||||
<div class="signup-header">
|
||||
<img src="/static/favicon.ico" class="logo"/>
|
||||
<h1>Create Access Token</h1>
|
||||
<p>Generate a new invite token</p>
|
||||
</div>
|
||||
|
||||
<div class="signup-form">
|
||||
<div class="success-message" id="successMessage">
|
||||
<strong>Token Created Successfully!</strong>
|
||||
<div id="tokenDisplay" style="margin-top: 10px; word-break: break-all; font-family: monospace; background: rgba(0,0,0,0.2); padding: 10px; border-radius: 4px;"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="tokenName">Token Name</label>
|
||||
<input
|
||||
type="text"
|
||||
id="tokenName"
|
||||
name="tokenName"
|
||||
placeholder="e.g., January 2025 Invites"
|
||||
required
|
||||
/>
|
||||
<div class="error-message">Token name is required</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="maxUses">Max Uses</label>
|
||||
<input
|
||||
type="number"
|
||||
id="maxUses"
|
||||
name="maxUses"
|
||||
placeholder="Maximum number of uses (leave empty for unlimited)"
|
||||
min="1"
|
||||
/>
|
||||
<div class="error-message">Must be a positive number</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="startDate">Start Date</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
id="startDate"
|
||||
name="startDate"
|
||||
required
|
||||
/>
|
||||
<div class="error-message">Start date is required</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="expiryDate">Expiry Date</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
id="expiryDate"
|
||||
name="expiryDate"
|
||||
required
|
||||
/>
|
||||
<div class="error-message">Expiry date must be after start date</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="submit-button" id="submitButton">
|
||||
Generate Token
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="signup-footer">
|
||||
<a href="/chat">Back to Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const form = {
|
||||
tokenName: document.getElementById("tokenName"),
|
||||
maxUses: document.getElementById("maxUses"),
|
||||
startDate: document.getElementById("startDate"),
|
||||
expiryDate: document.getElementById("expiryDate"),
|
||||
};
|
||||
|
||||
const submitButton = document.getElementById("submitButton");
|
||||
const successMessage = document.getElementById("successMessage");
|
||||
const tokenDisplay = document.getElementById("tokenDisplay");
|
||||
|
||||
// Set default start date to now
|
||||
const now = new Date();
|
||||
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
|
||||
form.startDate.value = now.toISOString().slice(0, 16);
|
||||
|
||||
// Set default expiry date to 30 days from now
|
||||
const defaultExpiry = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
|
||||
form.expiryDate.value = defaultExpiry.toISOString().slice(0, 16);
|
||||
|
||||
// Validation functions
|
||||
function validateTokenName() {
|
||||
const value = form.tokenName.value.trim();
|
||||
const isValid = value.length >= 1;
|
||||
toggleError(form.tokenName, !isValid);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function validateMaxUses() {
|
||||
const value = form.maxUses.value;
|
||||
// Empty is valid (unlimited), otherwise must be positive number
|
||||
const isValid = value === "" || (parseInt(value) > 0);
|
||||
toggleError(form.maxUses, !isValid);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function validateStartDate() {
|
||||
const value = form.startDate.value;
|
||||
const isValid = value !== "";
|
||||
toggleError(form.startDate, !isValid);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function validateExpiryDate() {
|
||||
const startValue = form.startDate.value;
|
||||
const expiryValue = form.expiryDate.value;
|
||||
|
||||
if (expiryValue === "") {
|
||||
toggleError(form.expiryDate, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
const startDate = new Date(startValue);
|
||||
const expiryDate = new Date(expiryValue);
|
||||
const isValid = expiryDate > startDate;
|
||||
toggleError(form.expiryDate, !isValid);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function toggleError(input, hasError) {
|
||||
const formGroup = input.closest(".form-group");
|
||||
if (hasError) {
|
||||
formGroup.classList.add("error");
|
||||
} else {
|
||||
formGroup.classList.remove("error");
|
||||
}
|
||||
}
|
||||
|
||||
// Add blur validation
|
||||
form.tokenName.addEventListener("blur", validateTokenName);
|
||||
form.maxUses.addEventListener("blur", validateMaxUses);
|
||||
form.startDate.addEventListener("blur", validateStartDate);
|
||||
form.expiryDate.addEventListener("blur", validateExpiryDate);
|
||||
|
||||
// Form submission
|
||||
submitButton.addEventListener("click", async function () {
|
||||
// Validate all fields
|
||||
const isTokenNameValid = validateTokenName();
|
||||
const isMaxUsesValid = validateMaxUses();
|
||||
const isStartDateValid = validateStartDate();
|
||||
const isExpiryDateValid = validateExpiryDate();
|
||||
|
||||
if (
|
||||
!isTokenNameValid ||
|
||||
!isMaxUsesValid ||
|
||||
!isStartDateValid ||
|
||||
!isExpiryDateValid
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable button and show loading
|
||||
submitButton.disabled = true;
|
||||
submitButton.innerHTML =
|
||||
'<span class="loading-spinner"></span>Generating Token...';
|
||||
|
||||
// Prepare data
|
||||
const formData = {
|
||||
name: form.tokenName.value.trim(),
|
||||
max_uses: form.maxUses.value ? parseInt(form.maxUses.value) : null,
|
||||
start_date: new Date(form.startDate.value).getTime(),
|
||||
expiry_date: new Date(form.expiryDate.value).getTime(),
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
"/api/invite",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
},
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const token = await response.text();
|
||||
|
||||
// Show success message with token
|
||||
tokenDisplay.textContent = token;
|
||||
successMessage.classList.add("show");
|
||||
submitButton.innerHTML = "Token Generated!";
|
||||
} else {
|
||||
const error = await response.text();
|
||||
throw new Error(error || "Token generation failed");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Token generation error:", error);
|
||||
alert(
|
||||
error.message ||
|
||||
"Failed to generate token. Please try again.",
|
||||
);
|
||||
submitButton.disabled = false;
|
||||
submitButton.innerHTML = "Generate Token";
|
||||
}
|
||||
});
|
||||
|
||||
// Allow Enter key to submit
|
||||
Object.values(form).forEach((input) => {
|
||||
if (input.tagName === "INPUT") {
|
||||
input.addEventListener("keypress", function (e) {
|
||||
if (e.key === "Enter") {
|
||||
submitButton.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,7 +9,7 @@
|
||||
<body>
|
||||
<div class="signup-container">
|
||||
<div class="signup-header">
|
||||
<div class="logo">DC</div>
|
||||
<img src="/static/favicon.ico" class="logo"/>
|
||||
<h1>Login</h1>
|
||||
<p>Enter the chat</p>
|
||||
</div>
|
||||
@@ -98,7 +98,7 @@
|
||||
// Disable button and show loading
|
||||
submitButton.disabled = true;
|
||||
submitButton.innerHTML =
|
||||
'<span class="loading-spinner"></span>Creating Account...';
|
||||
'<span class="loading-spinner"></span>Logging In...';
|
||||
|
||||
// Prepare data
|
||||
const formData = {
|
||||
@@ -124,14 +124,12 @@
|
||||
successMessage.classList.add("show");
|
||||
submitButton.innerHTML = "Logged in!!";
|
||||
|
||||
// Optional: Redirect after success
|
||||
setTimeout(() => {
|
||||
window.location.href = '/chat';
|
||||
// console.log("Redirecting to chat...");
|
||||
}, 2000);
|
||||
window.location.replace('/chat');
|
||||
}, 1000);
|
||||
} else {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message || "Login failed");
|
||||
const error = await response.text();
|
||||
throw new Error(error || "Login failed");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Login error:", error);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<body>
|
||||
<div class="signup-container">
|
||||
<div class="signup-header">
|
||||
<div class="logo">DC</div>
|
||||
<img src="/static/favicon.ico" class="logo"/>
|
||||
<h1>Create Account</h1>
|
||||
<p>Join the conversation today</p>
|
||||
</div>
|
||||
@@ -87,6 +87,27 @@
|
||||
<div class="error-message">Passwords do not match</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="accessToken">Enter Access Token</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
type="password"
|
||||
id="accessToken"
|
||||
name="accessToken"
|
||||
placeholder="Enter your access token"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="password-toggle"
|
||||
id="accessTokenToggle"
|
||||
>
|
||||
SHOW
|
||||
</button>
|
||||
</div>
|
||||
<div class="error-message">Passwords do not match</div>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-group">
|
||||
<input type="checkbox" id="terms" name="terms" required />
|
||||
<label for="terms">
|
||||
@@ -111,6 +132,7 @@
|
||||
email: document.getElementById("email"),
|
||||
password: document.getElementById("password"),
|
||||
confirmPassword: document.getElementById("confirmPassword"),
|
||||
accessToken: document.getElementById("accessToken"),
|
||||
terms: document.getElementById("terms"),
|
||||
};
|
||||
|
||||
@@ -170,6 +192,13 @@
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function validateAccessToken() {
|
||||
const value = form.accessToken.value.trim();
|
||||
const isValid = value.length >= 3;
|
||||
toggleError(form.accessToken, !isValid);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function toggleError(input, hasError) {
|
||||
const formGroup = input.closest(".form-group");
|
||||
if (hasError) {
|
||||
@@ -183,6 +212,7 @@
|
||||
form.username.addEventListener("blur", validateUsername);
|
||||
form.email.addEventListener("blur", validateEmail);
|
||||
form.password.addEventListener("blur", validatePassword);
|
||||
form.password.addEventListener("blur", validateAccessToken);
|
||||
form.confirmPassword.addEventListener(
|
||||
"blur",
|
||||
validateConfirmPassword,
|
||||
@@ -194,6 +224,7 @@
|
||||
const isUsernameValid = validateUsername();
|
||||
const isEmailValid = validateEmail();
|
||||
const isPasswordValid = validatePassword();
|
||||
const isAccessTokenValid = validateAccessToken();
|
||||
const isConfirmPasswordValid = validateConfirmPassword();
|
||||
const areTermsAccepted = form.terms.checked;
|
||||
|
||||
@@ -201,6 +232,7 @@
|
||||
!isUsernameValid ||
|
||||
!isEmailValid ||
|
||||
!isPasswordValid ||
|
||||
!isAccessTokenValid ||
|
||||
!isConfirmPasswordValid ||
|
||||
!areTermsAccepted
|
||||
) {
|
||||
@@ -218,8 +250,9 @@
|
||||
// Prepare data
|
||||
const formData = {
|
||||
username: form.username.value.trim(),
|
||||
// email: form.email.value.trim(),
|
||||
password: form.password.value,
|
||||
email: form.email.value.trim(),
|
||||
password: form.password.value.trim(),
|
||||
access_token: form.accessToken.value.trim(),
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -242,12 +275,11 @@
|
||||
|
||||
// Optional: Redirect after success
|
||||
setTimeout(() => {
|
||||
window.location.href = '/chat';
|
||||
// console.log("Redirecting to chat...");
|
||||
}, 2000);
|
||||
window.location.replace('/chat');
|
||||
}, 1000);
|
||||
} else {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message || "Signup failed");
|
||||
const error = await response.text();
|
||||
throw new Error(error || "Signup failed");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Signup error:", error);
|
||||
|
||||
Reference in New Issue
Block a user