Skip to content

Commit 4e5e6a9

Browse files
Add leaderboard
1 parent 324623f commit 4e5e6a9

File tree

5 files changed

+59
-1
lines changed

5 files changed

+59
-1
lines changed

openapi.yaml

+25
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,31 @@ paths:
828828
type: string
829829
example: '[email protected]'
830830
minLength: 1
831+
/api/v1/statistics/leaderboard:
832+
get:
833+
summary: Get top list of rv users, requires RV-Terminal-Secret header
834+
operationId: leaderboard
835+
tags:
836+
- normal
837+
responses:
838+
200:
839+
description: Check success.
840+
content:
841+
application/json:
842+
schema:
843+
type: array
844+
required:
845+
- name
846+
- saldo
847+
properties:
848+
name:
849+
type: string
850+
saldo:
851+
type: integer
852+
403:
853+
'$ref': '#/components/responses/NotAuthorizedErrorResponse'
854+
400:
855+
'$ref': '#/components/responses/BadRequestErrorResponse'
831856
/api/v1/user/user_exists:
832857
post:
833858
summary: Check if an user with the given username exists

src/app.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ import auth_route from './routes/auth.js';
1717
import user_categories from './routes/categories.js';
1818
import user_products from './routes/products.js';
1919
import register_route from './routes/register.js';
20+
import statistics_route from './routes/statistics.js';
2021
import api_reset_route from './routes/test_env/api_data_reset.js';
2122
import user_route from './routes/user.js';
2223
import user_deposit_history_route from './routes/userDepositHistory.js';
2324
import user_purchase_history_route from './routes/userPurchaseHistory.js';
24-
2525
const app = express();
2626

2727
app.use(express.urlencoded({ extended: false }));
@@ -48,6 +48,7 @@ app.use('/api/v1/user', user_route);
4848
app.use('/api/v1/register', register_route);
4949
app.use('/api/v1/products', user_products);
5050
app.use('/api/v1/categories', user_categories);
51+
app.use('/api/v1/statistics', statistics_route);
5152

5253
app.use('/api/v1/admin/defaultMargin', admin_default_margin);
5354
app.use('/api/v1/admin/products', admin_products);

src/db/userStore.ts

+5
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ export const verifyRfid = async (rfid, rfidHash) => {
174174
return await bcrypt.compare(rfid, rfidHash);
175175
};
176176

177+
export const leaderboard = async () => {
178+
const result = await knex.raw('SELECT name, saldo FROM "RVPERSON" ORDER BY saldo DESC limit 50;');
179+
return result.rows;
180+
};
181+
177182
export const recordDeposit = async (userId, amount, type) => {
178183
if (type != 'cash' && type != 'banktransfer') {
179184
throw new Error(`Unknown deposit type: ${type}`);

src/routes/authMiddleware.ts

+15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@ export interface Authenticated_request extends Request {
88
user?: userStore.user;
99
}
1010

11+
export const requireRvTerminalSecretMiddleware = () => {
12+
return async (req, res, next) => {
13+
const authHeader = req.get('RV-Terminal-Secret');
14+
if (authHeader !== process.env.RV_TERMINAL_SECRET) {
15+
logger.warn('Request is not authorized for %s %s, missing rv terminal secret', req.method, req.originalUrl);
16+
res.status(403).json({
17+
error_code: 'not_authorized',
18+
message: 'Not authorized',
19+
});
20+
return;
21+
}
22+
next();
23+
};
24+
};
25+
1126
const authMiddleware = ({
1227
requiredRole = null,
1328
tokenSecret = process.env.JWT_SECRET,

src/routes/statistics.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import express from 'express';
2+
import { leaderboard } from '../db/userStore.js';
3+
import { requireRvTerminalSecretMiddleware } from './authMiddleware.js';
4+
const router = express.Router();
5+
6+
router.get('/leaderboard', requireRvTerminalSecretMiddleware(), async (_, res) => {
7+
const lb = await leaderboard();
8+
console.log(lb);
9+
res.json(lb);
10+
});
11+
12+
export default router;

0 commit comments

Comments
 (0)