Updated README.md. Updated dependencies. Implemented VOUCHER_NOTE_REQUIRED environment variable. Implemented required note checks

This commit is contained in:
Glenn de Haan
2026-02-09 17:59:04 +01:00
parent 5a71a5e799
commit b29150c15b
7 changed files with 30 additions and 19 deletions

View File

@@ -16,7 +16,7 @@ UniFi Voucher Site is a web-based platform for generating and managing UniFi net
- **OIDC Support**: Integrates OpenID Connect for secure user authentication and single sign-on (SSO). - **OIDC Support**: Integrates OpenID Connect for secure user authentication and single sign-on (SSO).
- **Web and API Services**: Access the service via a web interface or integrate with other systems using a REST API. - **Web and API Services**: Access the service via a web interface or integrate with other systems using a REST API.
- **Docker Support**: Easily deploy using Docker, with customizable environment settings. - **Docker Support**: Easily deploy using Docker, with customizable environment settings.
- **Home Assistant Add-on**: Seamlessly integrate with Home Assistant for centralized management. - **Home Assistant App**: Seamlessly integrate with Home Assistant for centralized management.
- **Receipt Printing**: Supports printing vouchers with 80mm thermal printers. Via compatible PDFs and/or ESC/POS enabled network printers. - **Receipt Printing**: Supports printing vouchers with 80mm thermal printers. Via compatible PDFs and/or ESC/POS enabled network printers.
- **Bulk Printing**: Export/print multiple Vouchers in one go. - **Bulk Printing**: Export/print multiple Vouchers in one go.
- **Email Functionality**: Automatically send vouchers via SMTP. - **Email Functionality**: Automatically send vouchers via SMTP.
@@ -124,6 +124,8 @@ services:
VOUCHER_TYPES: '480,1,,,;' VOUCHER_TYPES: '480,1,,,;'
# Allow users to create custom vouchers types within the UI # Allow users to create custom vouchers types within the UI
VOUCHER_CUSTOM: 'true' VOUCHER_CUSTOM: 'true'
# Force users to provide a note within the UI
VOUCHER_NOTE_REQUIRED: 'false'
# Enable/disable the Web UI # Enable/disable the Web UI
SERVICE_WEB: 'true' SERVICE_WEB: 'true'
# Enable/disable the API # Enable/disable the API
@@ -212,6 +214,7 @@ The structure of the file should use lowercase versions of the environment varia
"auth_disable": false, "auth_disable": false,
"voucher_types": "480,1,,,;", "voucher_types": "480,1,,,;",
"voucher_custom": true, "voucher_custom": true,
"voucher_note_required": false,
"service_web": true, "service_web": true,
"service_api": false, "service_api": false,
"printers": "", "printers": "",
@@ -256,20 +259,21 @@ services:
> If both environment variables and `options.json` are provided, values from `options.json` will take precedence. > If both environment variables and `options.json` are provided, values from `options.json` will take precedence.
### Home Assistant Add-on ### Home Assistant App
For users of Home Assistant, we provide a dedicated add-on to seamlessly integrate the UniFi Voucher Site with your Home Assistant instance. This add-on simplifies the setup process and allows you to manage UniFi vouchers directly from your Home Assistant dashboard. For users of Home Assistant, we provide a dedicated app to seamlessly integrate the UniFi Voucher Site with your Home Assistant instance.
This app simplifies the setup process and allows you to manage UniFi vouchers directly from your Home Assistant dashboard.
[![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Fglenndehaan%2Fha-addons) [![Open your Home Assistant instance and show the add app repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Fglenndehaan%2Fha-addons)
#### Manual Installation #### Manual Installation
To install the UniFi Voucher Site add-on for Home Assistant, follow these steps: To install the UniFi Voucher Site app for Home Assistant, follow these steps:
1. Open the Supervisor panel in your Home Assistant instance. 1. Open the Supervisor panel in your Home Assistant instance.
2. Navigate to the "Add-on Store." 2. Navigate to the "App Store."
3. Add our repository to the list of repositories by clicking the three dots in the upper-right corner, then selecting "Repositories," and entering the URL of our repository: `https://github.com/glenndehaan/ha-addons`. 3. Add our repository to the list of repositories by clicking the three dots in the upper-right corner, then selecting "Repositories," and entering the URL of our repository: `https://github.com/glenndehaan/ha-addons`.
4. Once the repository is added, you will find the "UniFi Voucher Site" add-on in the add-on store. Click on it. 4. Once the repository is added, you will find the "UniFi Voucher Site" app in the app store. Click on it.
5. Click "Install" and wait for the installation to complete. 5. Click "Install" and wait for the installation to complete.
--- ---

View File

@@ -72,6 +72,11 @@ module.exports = {
} }
} }
if(variables.voucherNoteRequired && req.body['voucher-note'] === '') {
res.cookie('flashMessage', JSON.stringify({type: 'error', message: 'Notes are required!'}), {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(req.body['voucher-note'] !== '' && req.body['voucher-note'].includes('||;;||')) { if(req.body['voucher-note'] !== '' && req.body['voucher-note'].includes('||;;||')) {
res.cookie('flashMessage', JSON.stringify({type: 'error', message: 'Invalid Notes!'}), {httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000)}).redirect(302, `${req.headers['x-ingress-path'] ? req.headers['x-ingress-path'] : ''}/vouchers`); res.cookie('flashMessage', JSON.stringify({type: 'error', message: 'Invalid Notes!'}), {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; return;

View File

@@ -80,6 +80,7 @@ module.exports = {
printer_enabled: variables.printers !== '', printer_enabled: variables.printers !== '',
voucher_types: types(variables.voucherTypes), voucher_types: types(variables.voucherTypes),
voucher_custom: variables.voucherCustom, voucher_custom: variables.voucherCustom,
voucher_note_required: variables.voucherNoteRequired,
vouchers: cache.vouchers.filter((item) => { vouchers: cache.vouchers.filter((item) => {
if(variables.authOidcRestrictVisibility && req.oidc) { if(variables.authOidcRestrictVisibility && req.oidc) {
return item.name && notes(item.name).auth_oidc_domain === user.email.split('@')[1].toLowerCase(); return item.name && notes(item.name).auth_oidc_domain === user.email.split('@')[1].toLowerCase();

View File

@@ -20,6 +20,7 @@ module.exports = {
unifiSsidPassword: config('unifi_ssid_password') || process.env.UNIFI_SSID_PASSWORD || '', unifiSsidPassword: config('unifi_ssid_password') || process.env.UNIFI_SSID_PASSWORD || '',
voucherTypes: config('voucher_types') || process.env.VOUCHER_TYPES || '480,1,,,;', voucherTypes: config('voucher_types') || process.env.VOUCHER_TYPES || '480,1,,,;',
voucherCustom: config('voucher_custom') !== null ? config('voucher_custom') : process.env.VOUCHER_CUSTOM ? process.env.VOUCHER_CUSTOM !== 'false' : true, voucherCustom: config('voucher_custom') !== null ? config('voucher_custom') : process.env.VOUCHER_CUSTOM ? process.env.VOUCHER_CUSTOM !== 'false' : true,
voucherNoteRequired: config('voucher_note_required') !== null ? config('voucher_note_required') : (process.env.VOUCHER_NOTE_REQUIRED === 'true') || false,
serviceWeb: config('service_web') !== null ? config('service_web') : process.env.SERVICE_WEB ? process.env.SERVICE_WEB !== 'false' : true, serviceWeb: config('service_web') !== null ? config('service_web') : process.env.SERVICE_WEB ? process.env.SERVICE_WEB !== 'false' : true,
serviceApi: config('service_api') || (process.env.SERVICE_API === 'true') || false, serviceApi: config('service_api') || (process.env.SERVICE_API === 'true') || false,
authInternalEnabled: config('auth_internal_enabled') !== null ? config('auth_internal_enabled') : process.env.AUTH_INTERNAL_ENABLED ? process.env.AUTH_INTERNAL_ENABLED !== 'false' : true, authInternalEnabled: config('auth_internal_enabled') !== null ? config('auth_internal_enabled') : process.env.AUTH_INTERNAL_ENABLED ? process.env.AUTH_INTERNAL_ENABLED !== 'false' : true,

16
package-lock.json generated
View File

@@ -18,10 +18,10 @@
"jsonwebtoken": "^9.0.3", "jsonwebtoken": "^9.0.3",
"multer": "^2.0.2", "multer": "^2.0.2",
"node-thermal-printer": "^4.6.0", "node-thermal-printer": "^4.6.0",
"nodemailer": "^7.0.13", "nodemailer": "^8.0.1",
"pdfkit": "^0.17.2", "pdfkit": "^0.17.2",
"qrcode": "^1.5.4", "qrcode": "^1.5.4",
"undici": "^7.19.2" "undici": "^7.21.0"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/cli": "^4.1.18", "@tailwindcss/cli": "^4.1.18",
@@ -3491,9 +3491,9 @@
} }
}, },
"node_modules/nodemailer": { "node_modules/nodemailer": {
"version": "7.0.13", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.13.tgz", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.1.tgz",
"integrity": "sha512-PNDFSJdP+KFgdsG3ZzMXCgquO7I6McjY2vlqILjtJd0hy8wEvtugS9xKRF2NWlPNGxvLCXlTNIae4serI7dinw==", "integrity": "sha512-5kcldIXmaEjZcHR6F28IKGSgpmZHaF1IXLWFTG+Xh3S+Cce4MiakLtWY+PlBU69fLbRa8HlaGIrC/QolUpHkhg==",
"license": "MIT-0", "license": "MIT-0",
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
@@ -4571,9 +4571,9 @@
} }
}, },
"node_modules/undici": { "node_modules/undici": {
"version": "7.19.2", "version": "7.21.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.19.2.tgz", "resolved": "https://registry.npmjs.org/undici/-/undici-7.21.0.tgz",
"integrity": "sha512-4VQSpGEGsWzk0VYxyB/wVX/Q7qf9t5znLRgs0dzszr9w9Fej/8RVNQ+S20vdXSAyra/bJ7ZQfGv6ZMj7UEbzSg==", "integrity": "sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=20.18.1" "node": ">=20.18.1"

View File

@@ -24,10 +24,10 @@
"jsonwebtoken": "^9.0.3", "jsonwebtoken": "^9.0.3",
"multer": "^2.0.2", "multer": "^2.0.2",
"node-thermal-printer": "^4.6.0", "node-thermal-printer": "^4.6.0",
"nodemailer": "^7.0.13", "nodemailer": "^8.0.1",
"pdfkit": "^0.17.2", "pdfkit": "^0.17.2",
"qrcode": "^1.5.4", "qrcode": "^1.5.4",
"undici": "^7.19.2" "undici": "^7.21.0"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/cli": "^4.1.18", "@tailwindcss/cli": "^4.1.18",

View File

@@ -282,9 +282,9 @@
</div> </div>
</div> </div>
<div> <div>
<label for="voucher-note" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Note <em class="text-xs">(Optional)</em></label> <label for="voucher-note" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Note <% if(!voucher_note_required) { %><em class="text-xs">(Optional)</em><% } %></label>
<div class="mt-2"> <div class="mt-2">
<input type="text" id="voucher-note" name="voucher-note" 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"> <input type="text" id="voucher-note" name="voucher-note" <% if(voucher_note_required) { %>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> </div>
<div class="custom-voucher-field hidden border-t border-black/5 dark:border-white/25"> <div class="custom-voucher-field hidden border-t border-black/5 dark:border-white/25">