-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(api,dashboard): passages migration cherry picked (#493)
* feat(api): add migrating field to prevent double migration * api: add passage model/controller/api * dashboard: handle new passage ongoing * migration: first step * can edit passage * reception ongoing * reception ongoing * good passage management * delete stale comments / update reports to remove passages from each * fix tests * migrate passages in stats * chore: comment inclusive to `isBetween` from dayjs * chore: rename validateOrganisationEncryption to validateEncryptionAndMigrations * chore: clean * fix: up filename * Update api/src/controllers/migration.js Co-authored-by: Raphaël Huchet <rap2hpoutre@users.noreply.github.com> * Update api/src/controllers/migration.js Co-authored-by: Raphaël Huchet <rap2hpoutre@users.noreply.github.com> * Update dashboard/src/components/Passage.js Co-authored-by: Raphaël Huchet <rap2hpoutre@users.noreply.github.com> * Update api/src/db/migrations/2022-03-14_add_passage_table.js Co-authored-by: Raphaël Huchet <rap2hpoutre@users.noreply.github.com> * fix: move middlewarable code to middleware * dix: grammar * fix: set anonymous passage time to start of day Co-authored-by: Raphaël Huchet <raph@selego.co> Co-authored-by: Raphaël Huchet <rap2hpoutre@users.noreply.github.com>
- Loading branch information
1 parent
d976261
commit 32b940e
Showing
46 changed files
with
943 additions
and
357 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
const express = require("express"); | ||
const router = express.Router(); | ||
const passport = require("passport"); | ||
const { Op } = require("sequelize"); | ||
const { z } = require("zod"); | ||
const { catchErrors } = require("../errors"); | ||
const Passage = require("../models/passage"); | ||
const validateEncryptionAndMigrations = require("../middleware/validateEncryptionAndMigrations"); | ||
const validateUser = require("../middleware/validateUser"); | ||
const { looseUuidRegex, positiveIntegerRegex } = require("../utils"); | ||
|
||
router.post( | ||
"/", | ||
passport.authenticate("user", { session: false }), | ||
validateUser(["admin", "normal"]), | ||
validateEncryptionAndMigrations, | ||
catchErrors(async (req, res, next) => { | ||
try { | ||
z.string().parse(req.body.encrypted); | ||
z.string().parse(req.body.encryptedEntityKey); | ||
} catch (e) { | ||
const error = new Error(`Invalid request in passage creation: ${e}`); | ||
error.status = 400; | ||
return next(error); | ||
} | ||
|
||
const data = await Passage.create( | ||
{ | ||
organisation: req.user.organisation, | ||
encrypted: req.body.encrypted, | ||
encryptedEntityKey: req.body.encryptedEntityKey, | ||
}, | ||
{ returning: true } | ||
); | ||
|
||
return res.status(200).send({ | ||
ok: true, | ||
data: { | ||
_id: data._id, | ||
encrypted: data.encrypted, | ||
encryptedEntityKey: data.encryptedEntityKey, | ||
organisation: data.organisation, | ||
createdAt: data.createdAt, | ||
updatedAt: data.updatedAt, | ||
}, | ||
}); | ||
}) | ||
); | ||
|
||
router.get( | ||
"/", | ||
passport.authenticate("user", { session: false }), | ||
validateUser(["admin", "normal"]), | ||
catchErrors(async (req, res, next) => { | ||
try { | ||
z.optional(z.string().regex(positiveIntegerRegex)).parse(req.query.limit); | ||
z.optional(z.string().regex(positiveIntegerRegex)).parse(req.query.page); | ||
z.optional(z.string().regex(positiveIntegerRegex)).parse(req.query.lastRefresh); | ||
} catch (e) { | ||
const error = new Error(`Invalid request in passage get: ${e}`); | ||
error.status = 400; | ||
return next(error); | ||
} | ||
const { limit, page, lastRefresh } = req.query; | ||
|
||
const query = { | ||
where: { organisation: req.user.organisation }, | ||
order: [["createdAt", "DESC"]], | ||
}; | ||
|
||
const total = await Passage.count(query); | ||
if (limit) query.limit = Number(limit); | ||
if (page) query.offset = Number(page) * limit; | ||
if (lastRefresh) query.where.updatedAt = { [Op.gte]: new Date(Number(lastRefresh)) }; | ||
|
||
const data = await Passage.findAll({ | ||
...query, | ||
attributes: ["_id", "encrypted", "encryptedEntityKey", "organisation", "createdAt", "updatedAt"], | ||
}); | ||
return res.status(200).send({ ok: true, data, hasMore: data.length === Number(limit), total }); | ||
}) | ||
); | ||
|
||
router.put( | ||
"/:_id", | ||
passport.authenticate("user", { session: false }), | ||
validateUser(["admin", "normal"]), | ||
validateEncryptionAndMigrations, | ||
catchErrors(async (req, res, next) => { | ||
try { | ||
z.string().regex(looseUuidRegex).parse(req.params._id); | ||
if (req.body.createdAt) z.preprocess((input) => new Date(input), z.date()).parse(req.body.createdAt); | ||
z.string().parse(req.body.encrypted); | ||
z.string().parse(req.body.encryptedEntityKey); | ||
} catch (e) { | ||
const error = new Error(`Invalid request in passage put: ${e}`); | ||
error.status = 400; | ||
return next(error); | ||
} | ||
const query = { where: { _id: req.params._id, organisation: req.user.organisation } }; | ||
const passage = await Passage.findOne(query); | ||
if (!passage) return res.status(404).send({ ok: false, error: "Not Found" }); | ||
|
||
const { encrypted, encryptedEntityKey } = req.body; | ||
|
||
const updatePassage = { | ||
encrypted: encrypted, | ||
encryptedEntityKey: encryptedEntityKey, | ||
}; | ||
|
||
await Passage.update(updatePassage, query, { silent: false }); | ||
const newPassage = await Passage.findOne(query); | ||
|
||
return res.status(200).send({ | ||
ok: true, | ||
data: { | ||
_id: newPassage._id, | ||
encrypted: newPassage.encrypted, | ||
encryptedEntityKey: newPassage.encryptedEntityKey, | ||
organisation: newPassage.organisation, | ||
createdAt: newPassage.createdAt, | ||
updatedAt: newPassage.updatedAt, | ||
}, | ||
}); | ||
}) | ||
); | ||
|
||
router.delete( | ||
"/:_id", | ||
passport.authenticate("user", { session: false }), | ||
validateUser(["admin", "normal"]), | ||
catchErrors(async (req, res, next) => { | ||
try { | ||
z.string().regex(looseUuidRegex).parse(req.params._id); | ||
} catch (e) { | ||
const error = new Error(`Invalid request in passage delete: ${e}`); | ||
error.status = 400; | ||
return next(error); | ||
} | ||
const query = { where: { _id: req.params._id, organisation: req.user.organisation } }; | ||
|
||
const passage = await Passage.findOne(query); | ||
if (!passage) return res.status(200).send({ ok: true }); | ||
|
||
await passage.destroy(); | ||
res.status(200).send({ ok: true }); | ||
}) | ||
); | ||
|
||
module.exports = router; |
Oops, something went wrong.