mirror of
https://github.com/glenndehaan/unifi-voucher-site.git
synced 2026-03-31 06:24:00 -04:00
Updated README.md. Implemented the /api/languages endpoint. Refactored the /api endpoint to return methods for each endpoint. Added the voucher id within /api/vouchers. Refactored the /api/voucher endpoint from GET to POST method. Implemented optional email sending within /api/voucher endpoint. Implemented missing comments within api code. Implemented missing HTTP status codes within api responses. Enabled JSON responses within Express
This commit is contained in:
234
README.md
234
README.md
@@ -6,7 +6,7 @@ UniFi Voucher Site is a web-based platform for generating and managing UniFi net
|
||||
|
||||

|
||||
|
||||
> Upgrading from 3.x to 4.x? Please take a look at the [migration guide](#migration-from-3x-to-4x)
|
||||
> Upgrading from 4.x to 5.x? Please take a look at the [migration guide](#migration-from-4x-to-5x)
|
||||
|
||||
## Features
|
||||
|
||||
@@ -181,20 +181,36 @@ the different endpoints available in the API:
|
||||
- Access: Open
|
||||
- Response Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"endpoints": [
|
||||
"/api",
|
||||
"/api/types",
|
||||
"/api/voucher/:type",
|
||||
"/api/vouchers"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"endpoints": [
|
||||
{
|
||||
"method": "GET",
|
||||
"endpoint": "/api"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"endpoint": "/api/types"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"endpoint": "/api/languages"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"endpoint": "/api/vouchers"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"endpoint": "/api/voucher"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **`/api/types`**
|
||||
- Method: GET
|
||||
@@ -203,44 +219,55 @@ the different endpoints available in the API:
|
||||
- Access: Open
|
||||
- Response Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"types": [
|
||||
{
|
||||
"expiration": "480",
|
||||
"usage": "0",
|
||||
"raw": "480,0,,,"
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"types": [
|
||||
{
|
||||
"expiration": "480",
|
||||
"usage": "0",
|
||||
"raw": "480,0,,,"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
}
|
||||
```
|
||||
|
||||
3. **`/api/voucher/:type`**
|
||||
3. **`/api/languages`**
|
||||
- Method: GET
|
||||
- Description: Generates a voucher of the specified type.
|
||||
- Parameters:
|
||||
- `type` (string): The type of voucher to generate.
|
||||
- Description: Retrieves a list of available languages supported by the system.
|
||||
- Response Format: JSON
|
||||
- Access: Protected by Bearer Token
|
||||
- Access: Open
|
||||
- Response Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"voucher": "12345-67890"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> This endpoint is protected by a security mechanism. To access it, users need to include a bearer token in the
|
||||
request authorization header. The token must match the value of the `AUTH_INTERNAL_BEARER_TOKEN` environment variable. Without
|
||||
this token, access to the endpoint will be denied.
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"languages": [
|
||||
{
|
||||
"code": "en",
|
||||
"name": "English"
|
||||
},
|
||||
{
|
||||
"code": "de",
|
||||
"name": "German"
|
||||
},
|
||||
{
|
||||
"code": "nl",
|
||||
"name": "Dutch"
|
||||
},
|
||||
{
|
||||
"code": "pl",
|
||||
"name": "Polish"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. **`/api/vouchers`**
|
||||
- Method: GET
|
||||
@@ -249,37 +276,88 @@ the different endpoints available in the API:
|
||||
- Access: Protected by Bearer Token
|
||||
- Response Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"vouchers": [
|
||||
{
|
||||
"code": "15695-53133",
|
||||
"type": "multi",
|
||||
"duration": 60,
|
||||
"data_limit": "200",
|
||||
"download_limit": "5000",
|
||||
"upload_limit": "2000"
|
||||
},
|
||||
{
|
||||
"code": "03004-59449",
|
||||
"type": "single",
|
||||
"duration": 480,
|
||||
"data_limit": null,
|
||||
"download_limit": null,
|
||||
"upload_limit": null
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"vouchers": [
|
||||
{
|
||||
"id": "67bded6766f89f2a7ba6731f",
|
||||
"code": "15695-53133",
|
||||
"type": "multi",
|
||||
"duration": 60,
|
||||
"data_limit": "200",
|
||||
"download_limit": "5000",
|
||||
"upload_limit": "2000"
|
||||
},
|
||||
{
|
||||
"id": "67bdecd166f89f2a7ba67317",
|
||||
"code": "03004-59449",
|
||||
"type": "single",
|
||||
"duration": 480,
|
||||
"data_limit": null,
|
||||
"download_limit": null,
|
||||
"upload_limit": null
|
||||
}
|
||||
],
|
||||
"updated": 1712934667937
|
||||
}
|
||||
],
|
||||
"updated": 1712934667937
|
||||
}
|
||||
}
|
||||
```
|
||||
}
|
||||
```
|
||||
|
||||
> This endpoint is protected by a security mechanism. To access it, users need to include a bearer token in the
|
||||
request authorization header. The token must match the value of the `AUTH_INTERNAL_BEARER_TOKEN` environment variable. Without
|
||||
this token, access to the endpoint will be denied.
|
||||
> This endpoint is protected by a security mechanism. To access it, users need to include a bearer token in the
|
||||
request authorization header. The token must match the value of the `AUTH_INTERNAL_BEARER_TOKEN` environment variable. Without
|
||||
this token, access to the endpoint will be denied.
|
||||
|
||||
5. **`/api/voucher`**
|
||||
- Method: POST
|
||||
- Description: Generates a voucher of the specified type. Optionally sends an email.
|
||||
- Response Format: JSON
|
||||
- Access: Protected by Bearer Token
|
||||
- Body:
|
||||
- Generate Voucher:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "480,0,,,"
|
||||
}
|
||||
```
|
||||
|
||||
- Generate Voucher and Send Email *(**Warning**: Email module needs to be setup!)*:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "480,0,,,",
|
||||
"email": {
|
||||
"language": "en",
|
||||
"address": "user@example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Response Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": null,
|
||||
"data": {
|
||||
"message": "OK",
|
||||
"voucher": {
|
||||
"id": "67bdf77b66f89f2a7ba678f7",
|
||||
"code": "02791-97992"
|
||||
},
|
||||
"email": {
|
||||
"status": "SENT",
|
||||
"address": "user@example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> This endpoint is protected by a security mechanism. To access it, users need to include a bearer token in the
|
||||
request authorization header. The token must match the value of the `AUTH_INTERNAL_BEARER_TOKEN` environment variable. Without
|
||||
this token, access to the endpoint will be denied.
|
||||
|
||||
## Authentication
|
||||
|
||||
@@ -518,6 +596,10 @@ Detailed information on the changes in each release can be found on the [GitHub
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Migration from 4.x to 5.x
|
||||
|
||||
When upgrading from 4.x to 5.x, the following changes need to be made:
|
||||
|
||||
### Migration from 3.x to 4.x
|
||||
|
||||
When upgrading from 3.x to 4.x, the following changes need to be made:
|
||||
|
||||
184
server.js
184
server.js
@@ -106,6 +106,11 @@ app.use(locale({
|
||||
"default": "en-GB"
|
||||
}));
|
||||
|
||||
/**
|
||||
* Enable JSON
|
||||
*/
|
||||
app.use(express.json());
|
||||
|
||||
/**
|
||||
* Enable multer
|
||||
*/
|
||||
@@ -591,10 +596,26 @@ if(variables.serviceApi) {
|
||||
data: {
|
||||
message: 'OK',
|
||||
endpoints: [
|
||||
'/api',
|
||||
'/api/types',
|
||||
'/api/voucher/:type',
|
||||
'/api/vouchers'
|
||||
{
|
||||
method: 'GET',
|
||||
endpoint: '/api'
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
endpoint: '/api/types'
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
endpoint: '/api/languages'
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
endpoint: '/api/vouchers'
|
||||
},
|
||||
{
|
||||
method: 'POST',
|
||||
endpoint: '/api/voucher'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
@@ -608,36 +629,19 @@ if(variables.serviceApi) {
|
||||
}
|
||||
});
|
||||
});
|
||||
app.get('/api/voucher/:type', [authorization.api], async (req, res) => {
|
||||
const typeCheck = (variables.voucherTypes).split(';').includes(req.params.type);
|
||||
|
||||
if(!typeCheck) {
|
||||
res.json({
|
||||
error: 'Unknown Type!',
|
||||
data: {}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Create voucher code
|
||||
const voucherCode = await unifi.create(types(req.params.type, true)).catch((e) => {
|
||||
res.json({
|
||||
error: e,
|
||||
data: {}
|
||||
});
|
||||
app.get('/api/languages', (req, res) => {
|
||||
res.json({
|
||||
error: null,
|
||||
data: {
|
||||
message: 'OK',
|
||||
languages: Object.keys(languages).map(language => {
|
||||
return {
|
||||
code: language,
|
||||
name: languages[language]
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
await updateCache();
|
||||
|
||||
if(voucherCode) {
|
||||
res.json({
|
||||
error: null,
|
||||
data: {
|
||||
message: 'OK',
|
||||
voucher: voucherCode
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
app.get('/api/vouchers', [authorization.api], async (req, res) => {
|
||||
res.json({
|
||||
@@ -646,6 +650,7 @@ if(variables.serviceApi) {
|
||||
message: 'OK',
|
||||
vouchers: cache.vouchers.map((voucher) => {
|
||||
return {
|
||||
id: voucher._id,
|
||||
code: `${voucher.code.slice(0, 5)}-${voucher.code.slice(5)}`,
|
||||
type: voucher.quota === 1 ? 'single' : voucher.quota === 0 ? 'multi' : 'multi',
|
||||
duration: voucher.duration,
|
||||
@@ -658,6 +663,119 @@ if(variables.serviceApi) {
|
||||
}
|
||||
});
|
||||
});
|
||||
app.post('/api/voucher', [authorization.api], async (req, res) => {
|
||||
// Verify valid body is sent
|
||||
if(!req.body || !req.body.type) {
|
||||
res.status(400).json({
|
||||
error: 'Invalid Body!',
|
||||
data: {}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if email body is set
|
||||
if(req.body.email) {
|
||||
// Check if email module is enabled
|
||||
if(variables.smtpFrom === '' || variables.smtpHost === '' || variables.smtpPort === '') {
|
||||
res.status(400).json({
|
||||
error: 'Email Not Configured!',
|
||||
data: {}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if email body is correct
|
||||
if(!req.body.email.language || !req.body.email.address) {
|
||||
res.status(400).json({
|
||||
error: 'Invalid Body!',
|
||||
data: {}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if language is available
|
||||
if(!Object.keys(languages).includes(req.body.email.language)) {
|
||||
res.status(400).json({
|
||||
error: 'Unknown Language!',
|
||||
data: {}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if type is implemented and valid
|
||||
const typeCheck = (variables.voucherTypes).split(';').includes(req.body.type);
|
||||
if(!typeCheck) {
|
||||
res.status(400).json({
|
||||
error: 'Unknown Type!',
|
||||
data: {}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Create voucher code
|
||||
const voucherCode = await unifi.create(types(req.body.type, true)).catch((e) => {
|
||||
res.status(500).json({
|
||||
error: e,
|
||||
data: {}
|
||||
});
|
||||
});
|
||||
|
||||
// Update application cache
|
||||
await updateCache();
|
||||
|
||||
if(voucherCode) {
|
||||
// Locate voucher data within cache
|
||||
const voucherData = cache.vouchers.find(voucher => voucher.code === voucherCode.replaceAll('-', ''));
|
||||
if(!voucherData) {
|
||||
res.status(500).json({
|
||||
error: 'Invalid application cache!',
|
||||
data: {}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we should send and email
|
||||
if(req.body.email) {
|
||||
// Send mail
|
||||
const emailResult = await mail.send(req.body.email.address, voucherData, req.body.email.language).catch((e) => {
|
||||
res.status(500).json({
|
||||
error: e,
|
||||
data: {}
|
||||
});
|
||||
});
|
||||
|
||||
// Verify is the email was sent successfully
|
||||
if(emailResult) {
|
||||
res.json({
|
||||
error: null,
|
||||
data: {
|
||||
message: 'OK',
|
||||
voucher: {
|
||||
id: voucherData._id,
|
||||
code: voucherCode
|
||||
},
|
||||
email: {
|
||||
status: 'SENT',
|
||||
address: req.body.email.address
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.json({
|
||||
error: null,
|
||||
data: {
|
||||
message: 'OK',
|
||||
voucher: {
|
||||
id: voucherData._id,
|
||||
code: voucherCode
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user