Skip to content

Commit

Permalink
Fixed missing logo link. Implemented custom voucher type. Implemented…
Browse files Browse the repository at this point in the history
… custom voucher fields. Fixed divider visibility on dark mode. Changed default VOUCHER_TYPES to single-use voucher type. Implemented VOUCHER_CUSTOM environment variable.
  • Loading branch information
glenndehaan committed Apr 7, 2024
1 parent 8756452 commit a80f533
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 14 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ services:
# 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)
# 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,0,,,;'
VOUCHER_TYPES: '480,1,,,;'
# Allow users to create custom vouchers types within the UI
VOUCHER_CUSTOM: 'true'
# Enable/disable the Web UI
SERVICE_WEB: 'true'
# Enable/disable the API
Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ services:
UNIFI_SITE_ID: 'default'
SECURITY_CODE: '0000'
DISABLE_AUTH: 'false'
VOUCHER_TYPES: '480,0,,,;'
VOUCHER_TYPES: '480,1,,,;'
VOUCHER_CUSTOM: 'true'
SERVICE_WEB: 'true'
SERVICE_API: 'false'
18 changes: 11 additions & 7 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ const app = express();
/**
* Define global functions and variables
*/
const voucherTypes = types(config('voucher_types') || process.env.VOUCHER_TYPES || '480,0,,,;');
const voucherTypes = types(config('voucher_types') || process.env.VOUCHER_TYPES || '480,1,,,;');
const voucherCustom = (process.env.VOUCHER_CUSTOM === 'true') || true;
const webService = (process.env.SERVICE_WEB === 'true') || true;
const apiService = (process.env.SERVICE_API === 'true') || false;
const authDisabled = (process.env.DISABLE_AUTH === 'true') || false;
Expand Down Expand Up @@ -182,15 +183,17 @@ if(webService) {
return;
}

const typeCheck = (process.env.VOUCHER_TYPES || '480,0,,,;').split(';').includes(req.body['voucher-type']);
if(req.body['voucher-type'] !== 'custom') {
const typeCheck = (process.env.VOUCHER_TYPES || '480,1,,,;').split(';').includes(req.body['voucher-type']);

if(!typeCheck) {
res.cookie('flashMessage', JSON.stringify({type: 'error', message: 'Unknown Type!'}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
return;
if (!typeCheck) {
res.cookie('flashMessage', JSON.stringify({type: 'error', message: 'Unknown Type!'}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`);
return;
}
}

// Create voucher code
const voucherCode = await unifi.create(types(req.body['voucher-type'], true), parseInt(req.body['voucher-amount'])).catch((e) => {
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'])).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`);
});

Expand Down Expand Up @@ -377,6 +380,7 @@ if(webService) {
error_text: req.flashMessage.message || '',
timeConvert: time,
voucher_types: voucherTypes,
voucher_custom: voucherCustom,
vouchers: cache.vouchers,
updated: cache.updated
});
Expand Down Expand Up @@ -407,7 +411,7 @@ if(apiService) {
});
});
app.get('/api/voucher/:type', [authorization.api], async (req, res) => {
const typeCheck = (process.env.VOUCHER_TYPES || '480,0,,,;').split(';').includes(req.params.type);
const typeCheck = (process.env.VOUCHER_TYPES || '480,1,,,;').split(';').includes(req.params.type);

if(!typeCheck) {
res.json({
Expand Down
59 changes: 54 additions & 5 deletions template/voucher.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 justify-between">
<div class="flex">
<div class="flex flex-shrink-0 items-center">
<a href="<%= baseUrl %>/vouchers" class="flex flex-shrink-0 items-center">
<img class="h-12 w-auto" alt="UniFi Voucher Site Logo" src="<%= baseUrl %>/images/logo.png">
<div class="hidden sm:block ml-4 text-2xl font-semibold leading-7 text-gray-900 dark:text-white">
UniFi Voucher
</div>
</div>
</a>
</div>
<div class="flex items-center">
<div class="flex-shrink-0">
Expand Down Expand Up @@ -210,7 +210,7 @@
<div class="absolute inset-0 overflow-hidden">
<div class="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10 sm:pl-16">
<div class="pointer-events-auto w-screen max-w-md">
<form id="voucher-forum" class="flex h-full flex-col divide-y divide-black/5 dark:divide-white/5 bg-white dark:bg-gray-900 shadow-xl" action="<%= baseUrl %>/voucher" method="post" enctype="multipart/form-data">
<form id="voucher-forum" class="flex h-full flex-col divide-y divide-black/5 dark:divide-white/25 bg-white dark:bg-gray-900 shadow-xl" action="<%= baseUrl %>/voucher" method="post" enctype="multipart/form-data">
<div class="h-0 flex-1 overflow-y-auto">
<div class="bg-sky-700 px-4 py-6 sm:px-6">
<div class="flex items-center justify-between">
Expand All @@ -221,15 +221,18 @@
</div>
</div>
<div class="flex flex-1 flex-col justify-between">
<div class="divide-y divide-black/5 dark:divide-white/5 px-4 sm:px-6">
<div class="divide-y divide-black/5 dark:divide-white/25 px-4 sm:px-6">
<div class="space-y-6 pb-5 pt-6">
<div>
<label for="voucher-type" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Voucher Type</label>
<label for="voucher-type" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Preset Voucher Type</label>
<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">
<% 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>
<% }); %>
<% if(voucher_custom) { %>
<option value="custom">Custom</option>
<% } %>
</select>
</div>
</div>
Expand All @@ -239,6 +242,39 @@
<input type="number" min="1" step="1" value="1" id="voucher-amount" name="voucher-amount" 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">
</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">
</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">
<option value="0">Multi-use</option>
<option value="1">Single-use</option>
</select>
</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">
<input type="number" step="1" id="voucher-data-limit" name="voucher-data-limit" 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-download-limit" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Download Bandwidth Limit (in kb/s)</label>
<div class="mt-2">
<input type="number" step="1" id="voucher-download-limit" name="voucher-download-limit" 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-upload-limit" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Upload Bandwidth Limit (in kb/s)</label>
<div class="mt-2">
<input type="number" step="1" id="voucher-upload-limit" name="voucher-upload-limit" 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>
</div>
</div>
Expand Down Expand Up @@ -325,6 +361,8 @@
<script type="application/javascript">
const createDialog = document.querySelector('#create-dialog');
const createForum = document.querySelector("#voucher-forum");
const voucherTypeField = document.querySelector('#voucher-type');
const customVoucherFields = document.querySelectorAll('.custom-voucher-field');
const createButtonHeader = document.querySelector('#create-button-header');
const createButtonInfo = document.querySelector('#create-button-info');
const cancelButton = document.querySelector('#cancel');
Expand Down Expand Up @@ -372,6 +410,17 @@
spinnerRemove.style.display = '';
});
});
voucherTypeField.addEventListener('change', () => {
if(voucherTypeField.value === 'custom') {
customVoucherFields.forEach((el) => {
el.classList.remove('hidden');
});
} else {
customVoucherFields.forEach((el) => {
el.classList.add('hidden');
});
}
});
</script>
</body>
</html>

0 comments on commit a80f533

Please sign in to comment.