feat(expiration): add validation for expiration days and update user interface

This commit is contained in:
ReturnFI
2025-12-19 19:33:10 +00:00
parent 1a017216e0
commit b84ec1a9ac
3 changed files with 47 additions and 10 deletions

View File

@ -17,6 +17,7 @@ $(function () {
const passwordRegex = /^[a-zA-Z0-9]+$/;
let cachedUserData = [];
let searchTimeout = null;
const PRACTICAL_MAX_DAYS = 36500;
function setCookie(name, value, days) {
let expires = "";
@ -63,6 +64,7 @@ $(function () {
const isValid = usernameRegex.test(username);
$(errorElement).text(isValid ? "" : "Usernames can only contain letters, numbers, and underscores.");
$(inputElement).closest('form').find('button[type="submit"]').prop('disabled', !isValid);
return isValid;
}
function validatePassword(inputElement, errorElement) {
@ -70,6 +72,24 @@ $(function () {
const isValid = password === '' || passwordRegex.test(password);
$(errorElement).text(isValid ? "" : "Password can only contain letters and numbers.");
$('#editSubmitButton').prop('disabled', !isValid);
return isValid;
}
function validateExpirationDays(inputElement, errorElement) {
const days = parseInt($(inputElement).val(), 10);
let isValid = !isNaN(days) && days >= 0;
let errorMessage = "";
if (!isValid) {
errorMessage = "Please enter a non-negative number.";
} else if (days > PRACTICAL_MAX_DAYS) {
isValid = false;
errorMessage = `For unlimited duration, please use 0. Values above ${PRACTICAL_MAX_DAYS} are not practical.`;
}
$(errorElement).text(errorMessage);
$(inputElement).closest('form').find('button[type="submit"]').prop('disabled', !isValid);
return isValid;
}
function refreshUserList() {
@ -149,6 +169,10 @@ $(function () {
validateUsername(this, `#${this.id}Error`);
});
$('#addExpirationDays, #addBulkExpirationDays, #editExpirationDays').on('input', function() {
validateExpirationDays(this, `#${this.id}Error`);
});
$(".filter-button").on("click", function (e) {
e.preventDefault();
const filter = $(this).data("filter");
@ -260,6 +284,7 @@ $(function () {
const statusText = dataRow.find("td:eq(3)").text().trim();
$('#editPasswordError').text('');
$('#editExpirationDaysError').text('');
$('#editSubmitButton').prop('disabled', false);
$("#originalUsername").val(user);
@ -480,7 +505,7 @@ $(function () {
$('#addUserModal').on('show.bs.modal', function () {
$('#addUserForm, #addBulkUsersForm').trigger('reset');
$('#addUsernameError, #addBulkPrefixError').text('');
$('#addUsernameError, #addBulkPrefixError, #addExpirationDaysError, #addBulkExpirationDaysError').text('');
Object.assign(document.getElementById('addTrafficLimit'), {value: 30});
Object.assign(document.getElementById('addExpirationDays'), {value: 30});
Object.assign(document.getElementById('addBulkTrafficLimit'), {value: 30});

View File

@ -52,12 +52,21 @@ class User(BaseModel):
display_expiry_days = "On-hold"
display_expiry_date = "On-hold"
# 100 years. This cap exists for two critical reasons:
# 1. Technical: Prevents an OverflowError, as Python's `datetime` library has an existential crisis
# when confronted with any date beyond the year 9999.
# 2. Philosophical: We assume any user needing a subscription longer than a century is a vampire,
# a time-traveler, or a very optimistic cyborg. Our customer support policy does not cover
# the undead or temporal paradoxes. This is a feature, not a bug, designed to prevent
# inter-millennial bug reports.
PRACTICAL_MAX_DAYS = 36500
if creation_date_str:
try:
creation_date = datetime.strptime(creation_date_str, "%Y-%m-%d")
day_usage = str((datetime.now() - creation_date).days)
if expiration_days <= 0:
if expiration_days <= 0 or expiration_days > PRACTICAL_MAX_DAYS:
display_expiry_days = "Unlimited"
display_expiry_date = "Unlimited"
else:

View File

@ -252,7 +252,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-database"></i></span>
</div>
<input type="number" class="form-control" id="addTrafficLimit" name="traffic_limit" required>
<input type="number" class="form-control" id="addTrafficLimit" name="traffic_limit" required min="0">
</div>
</div>
<div class="form-group">
@ -261,8 +261,9 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-calendar-alt"></i></span>
</div>
<input type="number" class="form-control" id="addExpirationDays" name="expiration_days" required>
<input type="number" class="form-control" id="addExpirationDays" name="expiration_days" required min="0">
</div>
<small class="form-text text-danger" id="addExpirationDaysError"></small>
</div>
<div class="form-group">
<label for="addNote">Note (Optional)</label>
@ -301,7 +302,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-hashtag"></i></span>
</div>
<input type="number" class="form-control" id="addBulkCount" name="count" value="10" required>
<input type="number" class="form-control" id="addBulkCount" name="count" value="10" required min="1">
</div>
</div>
<div class="form-group col-md-6">
@ -310,7 +311,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-play-circle"></i></span>
</div>
<input type="number" class="form-control" id="addBulkStartNumber" name="start_number" value="1" required>
<input type="number" class="form-control" id="addBulkStartNumber" name="start_number" value="1" required min="0">
</div>
</div>
</div>
@ -321,7 +322,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-database"></i></span>
</div>
<input type="number" class="form-control" id="addBulkTrafficLimit" name="traffic_gb" required>
<input type="number" class="form-control" id="addBulkTrafficLimit" name="traffic_gb" required min="0">
</div>
</div>
<div class="form-group col-md-6">
@ -330,8 +331,9 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-calendar-alt"></i></span>
</div>
<input type="number" class="form-control" id="addBulkExpirationDays" name="expiration_days" required>
<input type="number" class="form-control" id="addBulkExpirationDays" name="expiration_days" required min="0">
</div>
<small class="form-text text-danger" id="addBulkExpirationDaysError"></small>
</div>
</div>
<div class="form-check mb-3 requires-iplimit-service" style="display: none;">
@ -395,7 +397,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-database"></i></span>
</div>
<input type="number" class="form-control" id="editTrafficLimit" name="new_traffic_limit">
<input type="number" class="form-control" id="editTrafficLimit" name="new_traffic_limit" min="0">
</div>
</div>
<div class="form-group">
@ -404,8 +406,9 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-calendar-alt"></i></span>
</div>
<input type="number" class="form-control" id="editExpirationDays" name="new_expiration_days">
<input type="number" class="form-control" id="editExpirationDays" name="new_expiration_days" min="0">
</div>
<small class="form-text text-danger" id="editExpirationDaysError"></small>
</div>
<div class="form-group">
<label for="editNote">Note</label>