Public Access
Recurring Visit Button
This commit is contained in:
1 parent
215c38849b
commit
1b1d950d71
4 files changed
+156
-1
No files matched your search
+92
-1
@@ -5,7 +5,13 @@ import fs from 'node:fs';
|
||||
import db from '../db.js';
|
||||
import config from '../config.js';
|
||||
import { decryptPin, encryptPin, generatePin, pinLookup } from '../pins.js';
|
||||
import { photoAbsolutePath, deletePhoto, purgeOldPhotos, savePhoto } from '../photos.js';
|
||||
import {
|
||||
photoAbsolutePath,
|
||||
deletePhoto,
|
||||
purgeOldPhotos,
|
||||
savePhoto,
|
||||
copyStoredPhoto,
|
||||
} from '../photos.js';
|
||||
import * as sheets from '../sheets.js';
|
||||
import * as tls from '../tls.js';
|
||||
import * as printer from '../printer.js';
|
||||
@@ -1116,6 +1122,91 @@ router.get('/visits', (req, res) => {
|
||||
res.json(db.prepare(sql).all(...params).map(shapeVisit));
|
||||
});
|
||||
|
||||
/**
|
||||
* Promotes someone who is signing in as a guest into a saved recurring visitor,
|
||||
* using the details they already gave at the kiosk. A random PIN is issued, and
|
||||
* their photo is carried across so the kiosk stops asking them to pose.
|
||||
*
|
||||
* The visit itself is left alone: it happened as a guest visit and the log should
|
||||
* go on saying so.
|
||||
*/
|
||||
router.post('/visits/:id/make-regular', (req, res) => {
|
||||
const visit = db.prepare('SELECT * FROM visits WHERE id = ?').get(req.params.id);
|
||||
if (!visit) return res.status(404).json({ error: 'Not found.' });
|
||||
|
||||
try {
|
||||
if (scopedSiteId(req)) assertSiteAllowed(req, visit.site_id);
|
||||
} catch (err) {
|
||||
return res.status(403).json({ error: err.message });
|
||||
}
|
||||
|
||||
if (!visit.phone) {
|
||||
return res.status(400).json({
|
||||
error: 'A mobile number is needed, because it becomes their sign in name. This visitor only left an email address.',
|
||||
});
|
||||
}
|
||||
|
||||
const phone = normalisePhone(visit.phone);
|
||||
const email = normaliseEmail(visit.email);
|
||||
|
||||
const byPhone = db
|
||||
.prepare('SELECT id, first_name, last_name FROM frequent_visitors WHERE phone = ?')
|
||||
.get(phone);
|
||||
if (byPhone) {
|
||||
return res.status(409).json({
|
||||
error: `${byPhone.first_name} ${byPhone.last_name} is already saved with that mobile number.`,
|
||||
existingId: byPhone.id,
|
||||
});
|
||||
}
|
||||
if (email) {
|
||||
const byEmail = db
|
||||
.prepare('SELECT id, first_name, last_name FROM frequent_visitors WHERE lower(email) = ?')
|
||||
.get(email);
|
||||
if (byEmail) {
|
||||
return res.status(409).json({
|
||||
error: `${byEmail.first_name} ${byEmail.last_name} is already saved with that email address.`,
|
||||
existingId: byEmail.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const pin = allocatePin(null);
|
||||
// Their sign-in photo becomes the one kept on file. Copied rather than shared,
|
||||
// so retention purging the visit cannot remove their profile photo.
|
||||
const photoPath = visit.photo_path ? copyStoredPhoto(visit.photo_path) : null;
|
||||
|
||||
const info = db
|
||||
.prepare(
|
||||
`INSERT INTO frequent_visitors
|
||||
(first_name, last_name, company, phone, email, check_type, check_number, check_expiry,
|
||||
default_host_id, site_id, pin_enc, pin_lookup, photo_path, notes, active)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)`
|
||||
)
|
||||
.run(
|
||||
visit.first_name,
|
||||
visit.last_name,
|
||||
visit.company || null,
|
||||
phone,
|
||||
email || null,
|
||||
visit.check_type || 'NONE',
|
||||
visit.check_number || null,
|
||||
visit.check_expiry || null,
|
||||
visit.host_id || null,
|
||||
visit.site_id || null,
|
||||
encryptPin(pin),
|
||||
pinLookup(pin),
|
||||
photoPath,
|
||||
null
|
||||
);
|
||||
|
||||
const created = db.prepare('SELECT * FROM frequent_visitors WHERE id = ?').get(info.lastInsertRowid);
|
||||
res.json({ ...shapeFrequent(created, true), photoCarriedOver: Boolean(photoPath) });
|
||||
} catch (err) {
|
||||
res.status(400).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/visits/:id/signout', (req, res) => {
|
||||
const visit = db
|
||||
.prepare('SELECT * FROM visits WHERE id = ? AND signed_out_at IS NULL')
|
||||
|
||||
Reference in new issue
Block a user