Skip to content
This repository was archived by the owner on Dec 8, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions backend/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,11 @@ Example request:
]
}
```

## Users

### GET /shop/:shop/user/:id

### POST /shop/:shop/user/

### PUT /shop/:shop/user/:id
9 changes: 9 additions & 0 deletions backend/docs/data-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,12 @@ See the create script for more details about the data types and keys.
- `customers`: Maximum number of customers for this time slot.
- `min_duration`: Minimum duration time to issue a ticket.
- `max_duration`: Maximum duration time to issue a ticket.

### users

`users` contains all registered users.

- `id`: Id of the user as an integer.
- `label`: Name of the user as string.
- `token`: Bearer token for login using `access_token` query parameter.
- `admin`: Flag if the user has admin right as boolean.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions backend/examples/user-get.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

BASE_URL=$(cat baseUrl.txt)

curl -v $BASE_URL/shop/default/user/owner -H "accept: application/json"
5 changes: 5 additions & 0 deletions backend/examples/user-post.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "owner",
"label": "Shop Owner",
"admin": true
}
6 changes: 6 additions & 0 deletions backend/examples/user-post.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

BASE_URL=$(cat baseUrl.txt)
DATA=$(cat user-post.json)

curl -v $BASE_URL/shop/default/user/ -X POST -H "content-type: application/json" -H "accept: application/json" --data "$DATA"
30 changes: 30 additions & 0 deletions backend/lib/Database.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,36 @@ ORDER BY "range"."start"

return result.rows
}

async addUser ({ id, label, token, admin }) {
const query = 'INSERT INTO users("id", "label", "token", "admin") VALUES ($1, $2, $3, $4) RETURNING *'
const values = [id, label, token, admin]
const result = await this.client.query(query, values)

return result.rows[0]
}

async setUser ({ id, label, token, admin }) {
const query = 'UPDATE users SET "label"=$1, "token"=$2, "admin"=$3 WHERE "id"=$4'
const values = [label, token, admin, id]
await this.client.query(query, values)
}

async getUser (id) {
const query = 'SELECT * FROM users WHERE "id"=$1'
const values = [id]
const result = await this.client.query(query, values)

return result.rows[0]
}

async getUserByToken (token) {
const query = 'SELECT * FROM users WHERE "token"=$1'
const values = [token]
const result = await this.client.query(query, values)

return result.rows[0]
}
}

module.exports = Database
13 changes: 12 additions & 1 deletion backend/lib/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,18 @@ const defaults = {
host: 'localhost',
database: 'postgres',
password: null,
port: null
port: null,
},
express: {
session: {
key: 'random'
}
},
auth: {
operator: {
user: 'operator',
password: 'operator'
}
}
}

Expand Down
44 changes: 44 additions & 0 deletions backend/lib/middleware/authn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const express = require('express')
const passport = require('passport')
const { BasicStrategy } = require('passport-http')
const BearerStrategy = require('passport-http-bearer')

function auth ({ config, db }) {
const router = new express.Router()

router.use(passport.initialize())
router.use(passport.session())

passport.serializeUser((user, done) => done(null, user))
passport.deserializeUser((user, done) => done(null, user))

passport.use(new BasicStrategy((user, password, done) => {
if (user !== config.operator.user) {
return done(null, false)
}

if (password !== config.operator.password) {
return done(null, false)
}

done(null, { user, admin: true, operator: true })
}))

passport.use(new BearerStrategy(async (token, done) => {
if (!token) {
return done(null, false)
}

const user = await db.getUserByToken(token)

if (!user) {
return done(null, false)
}

done(null, user)
}))

return router
}

module.exports = auth
13 changes: 13 additions & 0 deletions backend/lib/middleware/authz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const HttpError = require('http-errors')

function requiresAdmin (req, res, next) {
if (req.user && req.user.admin) {
return next()
}

next(new HttpError(401))
}

module.exports = {
requiresAdmin
}
26 changes: 24 additions & 2 deletions backend/lib/middleware/shop.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
const absoluteUrl = require('absolute-url')
const express = require('express')
const bodyParser = require('body-parser')
const express = require('express')
const passport = require('passport')
const { requiresAdmin } = require('./authz')
const ticket = require('./ticket')
const timeslot = require('./timeslot')
const user = require('./user')

function shop ({ db }) {
const router = new express.Router()

router.use(absoluteUrl())

router.get('/', async (req, res, next) => {
console.log(req.user)

const config = await db.getConfig()

res.json({
Expand All @@ -18,14 +23,31 @@ function shop ({ db }) {
})
})

router.put('/', bodyParser.json(), async (req, res, next) => {
router.put('/', requiresAdmin, bodyParser.json(), async (req, res, next) => {
await db.setConfig(req.body)

res.status(201).end()
})

router.get('/login', passport.authenticate('basic'), (req, res) => {
if (!req.user) {
return next(new Error('auth failed'))
}

res.redirect('.')
})

router.get('/token', passport.authenticate('bearer'), (req, res, next) => {
if (!req.user) {
return next(new Error('auth failed'))
}

res.redirect('.')
})

router.use('/ticket', ticket({ db }))
router.use('/timeslot', timeslot({ db }))
router.use('/user', user({ db }))

return router
}
Expand Down
3 changes: 2 additions & 1 deletion backend/lib/middleware/ticket.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const absoluteUrl = require('absolute-url')
const bodyParser = require('body-parser')
const { requiresAdmin } = require('./authz')
const express = require('express')
const uuid = require('uuid').v4
const qrcode = require('./qrcode')
Expand Down Expand Up @@ -77,7 +78,7 @@ function ticket ({ db }) {
}
})

router.put('/:id', bodyParser.json(), async (req, res, next) => {
router.put('/:id', requiresAdmin, bodyParser.json(), async (req, res, next) => {
try {
await db.setTicket({
id: req.params.id,
Expand Down
4 changes: 3 additions & 1 deletion backend/lib/middleware/timeslot.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const absoluteUrl = require('absolute-url')
const bodyParser = require('body-parser')
const express = require('express')
const HttpError = require('http-errors')
const { requiresAdmin } = require('./authz')

function timeslot ({ db }) {
const router = new express.Router()
Expand Down Expand Up @@ -30,7 +32,7 @@ function timeslot ({ db }) {
}
})

router.put('/', bodyParser.json(), async (req, res, next) => {
router.put('/', requiresAdmin, bodyParser.json(), async (req, res, next) => {

try {
await db.replaceTimeslots(req.body.member.map(member => ({
Expand Down
60 changes: 60 additions & 0 deletions backend/lib/middleware/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const absoluteUrl = require('absolute-url')
const express = require('express')
const bodyParser = require('body-parser')
const uuid = require('uuid').v4
const { requiresAdmin } = require('./authz')
const urlResolve = require('../urlResolve')

function user ({ db }) {
const router = new express.Router()

router.use(absoluteUrl())

router.post('/', requiresAdmin, bodyParser.json(), async (req, res, next) => {
if (req.accepts('html')) {
return next()
}

const result = await db.addUser({
id: req.body.id,
label: req.body.label,
token: uuid(),
admin: Boolean(req.body.admin)
})

res.status(201).set('location', urlResolve(req.absoluteUrl(), result.id)).end()
})

router.get('/:id', requiresAdmin, async (req, res, next) => {
if (req.accepts('html')) {
return next()
}

const user = await db.getUser(req.params.id)

if (!user) {
return next()
}

res.json(user)
})

router.put('/:id', requiresAdmin, bodyParser.json(), async (req, res, next) => {
if (req.accepts('html')) {
return next()
}

await db.setUser({
id: req.body.id,
label: req.body.label,
token: req.body.token,
admin: Boolean(req.body.admin)
})

res.status(201).end()
})

return router
}

module.exports = user
12 changes: 11 additions & 1 deletion backend/lib/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ const tables = {
"min_duration" integer,
"max_duration" integer
);`,
delete: 'DROP TABLE timeslots;'
delete: 'DROP TABLE timeslots;',
},
users: {
clear: 'TRUNCATE users;',
create: `CREATE TABLE users (
"id" character varying(1024),
"label" character varying(1024),
"token" character varying(1024),
"admin" boolean DEFAULT false
);`,
delete: 'DROP TABLE users;',
}
}

Expand Down
Loading