Added Notes feature (#8)
Also: - Moved buttons to top of request - Tweaked layout of full request view - Added code to ensure that users may only add history and notes to their own requests; security FTW!
This commit is contained in:
@@ -46,6 +46,17 @@ const ddl = [
|
||||
PRIMARY KEY ("requestId", "asOf"));
|
||||
COMMENT ON TABLE mpj.history IS 'Request update history'`
|
||||
},
|
||||
{
|
||||
name: 'note Table',
|
||||
check: tableSql('note'),
|
||||
fix: `
|
||||
CREATE TABLE mpj.note (
|
||||
"requestId" varchar(25) NOT NULL REFERENCES mpj.request,
|
||||
"asOf" bigint NOT NULL,
|
||||
"notes" text NOT NULL,
|
||||
PRIMARY KEY ("requestId", "asOf"));
|
||||
COMMENT ON TABLE mpj.note IS 'Notes regarding a request'`
|
||||
},
|
||||
{
|
||||
name: 'request.userId Index',
|
||||
check: indexSql('request', 'idx_request_userId'),
|
||||
|
||||
@@ -18,21 +18,41 @@ const requestNotFound = {
|
||||
}
|
||||
|
||||
export default function (pool) {
|
||||
|
||||
/**
|
||||
* Retrieve basic information about a single request
|
||||
* @param {string} requestId The Id of the request to retrieve
|
||||
* @param {string} userId The Id of the user to whom the request belongs
|
||||
*/
|
||||
let retrieveRequest = (requestId, userId) =>
|
||||
pool.query(`
|
||||
SELECT "requestId", "enteredOn"
|
||||
FROM mpj.request
|
||||
WHERE "requestId" = $1
|
||||
AND "userId" = $2`,
|
||||
[ requestId, userId ])
|
||||
|
||||
return {
|
||||
/**
|
||||
* Add a history entry for this request
|
||||
* @param {string} requestId The Id of the request
|
||||
* @param {string} userId The Id of the user to whom this request belongs
|
||||
* @param {string} requestId The Id of the request to which the update applies
|
||||
* @param {string} status The status for this history entry
|
||||
* @param {string} updateText The updated text for the request (pass blank if no update)
|
||||
* @return {number} 404 if the request is not found or does not belong to the given user, 204 if successful
|
||||
*/
|
||||
addHistory: async (requestId, status, updateText) => {
|
||||
const asOf = Date.now()
|
||||
addHistory: async (userId, requestId, status, updateText) => {
|
||||
const req = retrieveRequest(requestId, userId)
|
||||
if (req.rowCount === 0) {
|
||||
return 404
|
||||
}
|
||||
await pool.query(`
|
||||
INSERT INTO mpj.history
|
||||
("requestId", "asOf", "status", "text")
|
||||
VALUES
|
||||
($1, $2, $3, NULLIF($4, ''))`,
|
||||
[ requestId, asOf, status, updateText ])
|
||||
[ requestId, Date.now(), status, updateText ])
|
||||
return 204
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -68,6 +88,27 @@ export default function (pool) {
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a note about a prayer request
|
||||
* @param {string} userId The Id of the user to whom the request belongs
|
||||
* @param {string} requestId The Id of the request to which the note applies
|
||||
* @param {string} note The notes to add
|
||||
* @return {number} 404 if the request is not found or does not belong to the given user, 204 if successful
|
||||
*/
|
||||
addNote: async (userId, requestId, note) => {
|
||||
const req = retrieveRequest(requestId, userId)
|
||||
if (req.rowCount === 0) {
|
||||
return 404
|
||||
}
|
||||
await pool.query(`
|
||||
INSERT INTO mpj.note
|
||||
("requestId", "asOf", "notes")
|
||||
VALUES
|
||||
($1, $2, $3)`,
|
||||
[ requestId, Date.now(), note ])
|
||||
return 204
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all answered requests with their text as of the "Answered" status
|
||||
* @param {string} userId The Id of the user for whom requests should be retrieved
|
||||
@@ -101,12 +142,7 @@ export default function (pool) {
|
||||
* @return The request, or a request-like object indicating that the request was not found
|
||||
*/
|
||||
fullById: async (userId, requestId) => {
|
||||
const reqResults = await pool.query(`
|
||||
SELECT "requestId", "enteredOn"
|
||||
FROM mpj.request
|
||||
WHERE "requestId" = $1
|
||||
AND "userId" = $2`,
|
||||
[ requestId, userId ])
|
||||
const reqResults = await retrieveRequest(requestId, userId)
|
||||
if (0 === reqResults.rowCount) {
|
||||
return requestNotFound
|
||||
}
|
||||
@@ -126,7 +162,27 @@ export default function (pool) {
|
||||
* @param {string} userId The Id of the user
|
||||
* @return The requests that make up the current journal
|
||||
*/
|
||||
journal: async userId => (await pool.query(`${journalSql} ORDER BY "asOf"`, [ userId ])).rows
|
||||
journal: async userId => (await pool.query(`${journalSql} ORDER BY "asOf"`, [ userId ])).rows,
|
||||
|
||||
/**
|
||||
* Get the notes for a request, most recent first
|
||||
* @param {string} userId The Id of the user to whom the request belongs
|
||||
* @param {string} requestId The Id of the request whose notes should be retrieved
|
||||
* @return The notes for the request
|
||||
*/
|
||||
notesById: async (userId, requestId) => {
|
||||
const reqResults = await retrieveRequest(requestId, userId)
|
||||
if (0 === reqResults.rowCount) {
|
||||
return requestNotFound
|
||||
}
|
||||
const notes = await pool.query(`
|
||||
SELECT "asOf", "notes"
|
||||
FROM mpj.note
|
||||
WHERE "requestId" = $1
|
||||
ORDER BY "asOf" DESC`,
|
||||
[ requestId ])
|
||||
return notes.rows
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,13 @@ export default function (checkJwt) {
|
||||
// Add a request history entry (prayed, updated, answered, etc.)
|
||||
.post('/:id/history', checkJwt, async (ctx, next) => {
|
||||
const body = ctx.request.body
|
||||
await db.request.addHistory(ctx.params.id, body.status, body.updateText)
|
||||
ctx.response.status = 204
|
||||
ctx.response.status = await db.request.addHistory(ctx.state.user.sub, ctx.params.id, body.status, body.updateText)
|
||||
await next()
|
||||
})
|
||||
// Add a note to a request
|
||||
.post('/:id/note', checkJwt, async (ctx, next) => {
|
||||
const body = ctx.request.body
|
||||
ctx.response.status = await db.request.addNote(ctx.state.user.sub, ctx.params.id, body.notes)
|
||||
await next()
|
||||
})
|
||||
// Get a journal-style request by its Id
|
||||
@@ -40,6 +45,17 @@ export default function (checkJwt) {
|
||||
}
|
||||
await next()
|
||||
})
|
||||
// Get the notes for a request
|
||||
.get('/:id/notes', checkJwt, async (ctx, next) => {
|
||||
const notes = await db.request.notesById(ctx.state.user.sub, ctx.params.id)
|
||||
if (notes.text && 'Not Found' === notes.text) {
|
||||
ctx.response.status = 404
|
||||
} else {
|
||||
ctx.body = notes
|
||||
ctx.response.status = 200
|
||||
}
|
||||
await next()
|
||||
})
|
||||
.get('/answered', checkJwt, async (ctx, next) => {
|
||||
ctx.body = await db.request.answered(ctx.state.user.sub)
|
||||
ctx.response.status = 200
|
||||
|
||||
Reference in New Issue
Block a user