Updated screenshots. Fixed inconsistent 'unlimited' messaging. Implemented direct usage without overrides within unifi.js. Implemented voucher duration type dropdown during custom voucher creation. Implemented Multi-use (Limited/Quota) option during custom voucher creation. Updated README.md to reflect multi-use quota function within voucher type presets.
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 59 KiB |
@@ -98,7 +98,7 @@ services:
|
||||
AUTH_OIDC_CLIENT_SECRET: ''
|
||||
# Disables the login/authentication for the portal and API
|
||||
AUTH_DISABLE: 'false'
|
||||
# Voucher Types, format: expiration in minutes (required),single-use or multi-use vouchers value - '0' is for multi-use - '1' is for single-use (optional),upload speed limit in kbps (optional),download speed limit in kbps (optional),data transfer limit in MB (optional)
|
||||
# Voucher Types, format: expiration in minutes (required),single-use or multi-use vouchers value - '0' is for multi-use (unlimited) - '1' is for single-use - 'N' is for multi-use (Nx) (optional),upload speed limit in kbps (optional),download speed limit in kbps (optional),data transfer limit in MB (optional)
|
||||
# To skip a parameter just but nothing in between the comma's
|
||||
# After a voucher type add a semicolon, after the semicolon you can start a new voucher type
|
||||
VOUCHER_TYPES: '480,1,,,;'
|
||||
|
||||
@@ -69,7 +69,7 @@ module.exports = () => {
|
||||
*/
|
||||
log.info('[Voucher] Loaded the following types:');
|
||||
types(variables.voucherTypes).forEach((type, key) => {
|
||||
log.info(`[Voucher][Type][${key}] ${time(type.expiration)}, ${type.usage === '1' ? 'single-use' : 'multi-use'}${typeof type.upload === "undefined" && typeof type.download === "undefined" && typeof type.megabytes === "undefined" ? ', no limits' : `${typeof type.upload !== "undefined" ? `, upload bandwidth limit: ${type.upload} kb/s` : ''}${typeof type.download !== "undefined" ? `, download bandwidth limit: ${type.download} kb/s` : ''}${typeof type.megabytes !== "undefined" ? `, quota limit: ${type.megabytes} mb` : ''}`}`);
|
||||
log.info(`[Voucher][Type][${key}] ${time(type.expiration)}, ${type.usage === '1' ? 'single-use' : type.usage === '0' ? 'multi-use (unlimited)' : `multi-use (${type.usage}x)`}${typeof type.upload === "undefined" && typeof type.download === "undefined" && typeof type.megabytes === "undefined" ? ', no limits' : `${typeof type.upload !== "undefined" ? `, upload bandwidth limit: ${type.upload} kb/s` : ''}${typeof type.download !== "undefined" ? `, download bandwidth limit: ${type.download} kb/s` : ''}${typeof type.megabytes !== "undefined" ? `, quota limit: ${type.megabytes} mb` : ''}`}`);
|
||||
});
|
||||
log.info(`[Voucher][Custom] ${variables.voucherCustom ? 'Enabled!' : 'Disabled!'}`);
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ const unifiModule = {
|
||||
create: (type, amount = 1, note = null, retry = true) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
startSession().then(() => {
|
||||
controller.createVouchers(type.expiration, amount, parseInt(type.usage) === 1 ? 1 : 0, note, typeof type.upload !== "undefined" ? type.upload : null, typeof type.download !== "undefined" ? type.download : null, typeof type.megabytes !== "undefined" ? type.megabytes : null).then((voucher_data) => {
|
||||
controller.createVouchers(type.expiration, amount, parseInt(type.usage), note, typeof type.upload !== "undefined" ? type.upload : null, typeof type.download !== "undefined" ? type.download : null, typeof type.megabytes !== "undefined" ? type.megabytes : null).then((voucher_data) => {
|
||||
if(amount > 1) {
|
||||
log.info(`[UniFi] Created ${amount} vouchers`);
|
||||
resolve(true);
|
||||
|
||||
@@ -203,7 +203,7 @@ if(variables.serviceWeb) {
|
||||
}
|
||||
|
||||
// Create voucher code
|
||||
const voucherCode = await unifi.create(types(req.body['voucher-type'] === 'custom' ? `${req.body['voucher-duration']},${req.body['voucher-usage']},${req.body['voucher-upload-limit']},${req.body['voucher-download-limit']},${req.body['voucher-data-limit']};` : req.body['voucher-type'], true), parseInt(req.body['voucher-amount']), req.body['voucher-note'] !== '' ? req.body['voucher-note'] : null).catch((e) => {
|
||||
const voucherCode = await unifi.create(types(req.body['voucher-type'] === 'custom' ? `${req.body['voucher-duration-type'] === 'day' ? (parseInt(req.body['voucher-duration']) * 24 * 60) : req.body['voucher-duration-type'] === 'hour' ? (parseInt(req.body['voucher-duration']) * 60) : parseInt(req.body['voucher-duration'])},${req.body['voucher-usage'] === '-1' ? req.body['voucher-quota'] : req.body['voucher-usage']},${req.body['voucher-upload-limit']},${req.body['voucher-download-limit']},${req.body['voucher-data-limit']};` : req.body['voucher-type'], true), parseInt(req.body['voucher-amount']), req.body['voucher-note'] !== '' ? req.body['voucher-note'] : null).catch((e) => {
|
||||
res.cookie('flashMessage', JSON.stringify({type: 'error', message: e}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
|
||||
});
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@
|
||||
<div class="mt-2">
|
||||
<select id="voucher-type" name="voucher-type" class="mt-2 block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 dark:text-white dark:bg-white/5 ring-1 ring-inset ring-gray-300 dark:ring-white/10 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6 [&_*]:text-black">
|
||||
<% voucher_types.forEach((type) => { %>
|
||||
<option value="<%= type.raw %>"><%= timeConvert(type.expiration) %>, <%= type.usage === '1' ? 'single-use' : 'multi-use' %><%= typeof type.upload === "undefined" && typeof type.download === "undefined" && typeof type.megabytes === "undefined" ? ', no limits' : '' %><%= typeof type.upload !== "undefined" ? `, upload bandwidth limit: ${type.upload} kb/s` : '' %><%= typeof type.download !== "undefined" ? `, download bandwidth limit: ${type.download} kb/s` : '' %><%= typeof type.megabytes !== "undefined" ? `, quota limit: ${type.megabytes} mb` : '' %></option>
|
||||
<option value="<%= type.raw %>"><%= timeConvert(type.expiration) %>, <%= type.usage === '1' ? 'single-use' : type.usage === '0' ? 'multi-use (unlimited)' : `multi-use (${type.usage}x)` %><%= typeof type.upload === "undefined" && typeof type.download === "undefined" && typeof type.megabytes === "undefined" ? ', no limits' : '' %><%= typeof type.upload !== "undefined" ? `, upload bandwidth limit: ${type.upload} kb/s` : '' %><%= typeof type.download !== "undefined" ? `, download bandwidth limit: ${type.download} kb/s` : '' %><%= typeof type.megabytes !== "undefined" ? `, quota limit: ${type.megabytes} mb` : '' %></option>
|
||||
<% }); %>
|
||||
<% if(voucher_custom) { %>
|
||||
<option value="custom">Custom</option>
|
||||
@@ -288,20 +288,32 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-voucher-field hidden border-t border-black/5 dark:border-white/25">
|
||||
<label for="voucher-duration" class="mt-4 block text-sm font-medium leading-6 text-gray-900 dark:text-white">Duration (in Minutes)</label>
|
||||
<div class="mt-2">
|
||||
<input type="number" min="1" step="1" value="60" id="voucher-duration" name="voucher-duration" required class="mt-2 block w-full rounded-md border-0 py-1.5 text-gray-900 dark:text-white dark:bg-white/5 ring-1 ring-inset ring-gray-300 dark:ring-white/10 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6">
|
||||
<label for="voucher-duration" class="mt-4 block text-sm font-medium leading-6 text-gray-900 dark:text-white">Duration</label>
|
||||
<div class="mt-2 grid grid-cols-2 gap-2">
|
||||
<input type="number" min="1" step="1" value="8" id="voucher-duration" name="voucher-duration" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 dark:text-white dark:bg-white/5 ring-1 ring-inset ring-gray-300 dark:ring-white/10 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6">
|
||||
<select id="voucher-duration-type" name="voucher-duration-type" class="block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 dark:text-white dark:bg-white/5 ring-1 ring-inset ring-gray-300 dark:ring-white/10 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6 [&_*]:text-black">
|
||||
<option value="minute">Minute(s)</option>
|
||||
<option value="hour" selected>Hour(s)</option>
|
||||
<option value="day">Day(s)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-voucher-field hidden">
|
||||
<label for="voucher-usage" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Voucher Usage</label>
|
||||
<div class="mt-2">
|
||||
<select id="voucher-usage" name="voucher-usage" class="mt-2 block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 dark:text-white dark:bg-white/5 ring-1 ring-inset ring-gray-300 dark:ring-white/10 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6 [&_*]:text-black">
|
||||
<option value="0">Multi-use</option>
|
||||
<option value="0">Multi-use (Unlimited)</option>
|
||||
<option value="-1">Multi-use (Limited/Quota)</option>
|
||||
<option value="1">Single-use</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-voucher-field-quota hidden">
|
||||
<label for="voucher-quota" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Voucher Limit/Quota</label>
|
||||
<div class="mt-2">
|
||||
<input type="number" min="2" step="1" value="2" id="voucher-quota" name="voucher-quota" class="mt-2 block w-full rounded-md border-0 py-1.5 text-gray-900 dark:text-white dark:bg-white/5 ring-1 ring-inset ring-gray-300 dark:ring-white/10 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-voucher-field hidden">
|
||||
<label for="voucher-data-limit" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Data Limit (in MB)</label>
|
||||
<div class="mt-2">
|
||||
@@ -423,7 +435,9 @@
|
||||
const bulkPrintDialog = document.querySelector('#bulk-print-dialog');
|
||||
const createForm = document.querySelector('#voucher-form');
|
||||
const voucherTypeField = document.querySelector('#voucher-type');
|
||||
const voucherUsageField = document.querySelector('#voucher-usage');
|
||||
const customVoucherFields = document.querySelectorAll('.custom-voucher-field');
|
||||
const customVoucherFieldQuota = document.querySelectorAll('.custom-voucher-field-quota');
|
||||
const createButtonHeader = document.querySelector('#create-button-header');
|
||||
const createButtonInfo = document.querySelector('#create-button-info');
|
||||
const cancelButton = document.querySelector('#cancel');
|
||||
@@ -523,6 +537,17 @@
|
||||
});
|
||||
}
|
||||
});
|
||||
voucherUsageField.addEventListener('change', () => {
|
||||
if(voucherUsageField.value === '-1') {
|
||||
customVoucherFieldQuota.forEach((el) => {
|
||||
el.classList.remove('hidden');
|
||||
});
|
||||
} else {
|
||||
customVoucherFieldQuota.forEach((el) => {
|
||||
el.classList.add('hidden');
|
||||
});
|
||||
}
|
||||
});
|
||||
vouchers.forEach((el) => {
|
||||
el.addEventListener('click', async () => {
|
||||
const htmlRes = await fetch(`<%= baseUrl %>/voucher/${el.dataset.id}`);
|
||||
|
||||