From d1c8ad1598916b311f661e4032a7f36faac26eb3 Mon Sep 17 00:00:00 2001 From: Francesco Baldino Date: Mon, 28 Aug 2023 23:43:37 +0200 Subject: [PATCH] Aggiunto comments a User + sistemati bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Aggiunto "comments" al modello di User - UserPage adesso visualizza solo i commenti di "comments" - Il CommentWidget in UserPage aggiorna il campo "comments" dell'utente - Sistemato bug di "carica più righe" - Sistemato bug della direzione di sort in QueryTable - Resi più coerenti i metodi di ModelController --- api/controllers/AttachmentController.js | 17 ++++---- api/controllers/CommentController.js | 33 +++------------- api/controllers/CurriculaController.js | 14 +++---- api/controllers/DegreesController.js | 14 +++---- api/controllers/ExamsController.js | 20 ++++------ api/controllers/FormTemplates.js | 14 +++---- api/controllers/FormsController.js | 13 +++--- api/controllers/ModelController.js | 48 +++++++++++------------ api/controllers/ProposalsController.js | 12 ++---- api/controllers/UsersController.js | 24 +++++++----- api/models/User.js | 5 ++- api/router.js | 7 ++-- frontend/src/components/CommentWidget.js | 2 +- frontend/src/components/QueryTable.js | 12 +++++- frontend/src/pages/UserPage.js | 50 +++++++++++++----------- 15 files changed, 128 insertions(+), 157 deletions(-) diff --git a/api/controllers/AttachmentController.js b/api/controllers/AttachmentController.js index 39d237d5..1e7c15da 100644 --- a/api/controllers/AttachmentController.js +++ b/api/controllers/AttachmentController.js @@ -34,17 +34,13 @@ const attachmentHandler = multer({ const AttachmentController = { index: async req => { - return await ModelController.index(req, { - Model: Attachment, - fields - }); + const query = req.query + return await ModelController.index(Attachment, query, fields); }, view: async req => { - return await ModelController.view(req, { - Model: Attachment, - fields - }) + const { id } = req.params + return await ModelController.view(Attachment, id) }, viewContent: async (req, res, next) => { @@ -81,14 +77,15 @@ const AttachmentController = { post: async req => { let reply = [] for (const file of req.files) { - const attachment_id = await ModelController.insert(Attachment, { + const data = { filename: file.originalname, mimetype: file.mimetype, encoding: file.encoding, size: file.size, content: file.filename, uploader_id: req.body.uploader_id - }) + } + const attachment_id = await ModelController.insert(Attachment, data) reply.push(attachment_id) } return reply diff --git a/api/controllers/CommentController.js b/api/controllers/CommentController.js index b2cb17f0..3f376759 100644 --- a/api/controllers/CommentController.js +++ b/api/controllers/CommentController.js @@ -1,9 +1,6 @@ const ModelController = require('./ModelController'); const Comment = require('../models/Comment'); -const { BadRequestError } = require('../exceptions/ApiException'); -const AttachmentController = require('./AttachmentController'); - const fields = { "creator_id": { can_filter: true, @@ -25,40 +22,22 @@ const fields = { const CommentController = { index: async req => { - return await ModelController.index(req, { - Model: Comment, - fields, - populate: 'attachments creator_id' - }); + const query = req.query + return await ModelController.index(Comment, query, fields, { populate: 'attachments creator_id' }); }, view: async req => { - return await ModelController.view(req, { - Model: Comment, - fields - }) + const { id } = req.params + return await ModelController.view(Comment, id) }, post: async req => { - return await ModelController.insert(Comment, req.body) + const data = req.body + return await ModelController.insert(Comment, data) }, delete: async req => { const { id } = req.params; - try { - const comment = await ModelController.view(req, { Model: Comment }) - for (const attachment_id of comment.attachments) { - const attachmentOccurrence = await ModelController.index({ query: { attachments: attachment_id }}, { - Model: Comment, - fields - }) - if (attachmentOccurrence.total === 1) { - await AttachmentController.delete({ params: { id: attachment_id }}) - } - } - } catch(e) { - throw new BadRequestError(e) - } return await ModelController.delete(Comment, id); } } diff --git a/api/controllers/CurriculaController.js b/api/controllers/CurriculaController.js index 9627669d..e0323793 100644 --- a/api/controllers/CurriculaController.js +++ b/api/controllers/CurriculaController.js @@ -20,17 +20,13 @@ const fields = { const CurriculaController = { index: async req => { - return await ModelController.index(req, { - Model: Curriculum, - fields - }); + const query = req.query + return await ModelController.index(Curriculum, query, fields); }, view: async req => { - return await ModelController.view(req, { - Model: Curriculum, - fields - }) + const { id } = req.params + return await ModelController.view(Curriculum, id) }, post: async req => { @@ -39,4 +35,4 @@ const CurriculaController = { } } -module.exports = CurriculaController; \ No newline at end of file +module.exports = CurriculaController; diff --git a/api/controllers/DegreesController.js b/api/controllers/DegreesController.js index db023a32..8772bd85 100644 --- a/api/controllers/DegreesController.js +++ b/api/controllers/DegreesController.js @@ -21,17 +21,13 @@ const fields = { const DegreesController = { index: async req => { - return await ModelController.index(req, { - Model: Degree, - fields - }); + const query = req.query + return await ModelController.index(Degree, query, fields); }, view: async req => { - return await ModelController.view(req, { - Model: Degree, - fields - }) + const { id } = req.params + return await ModelController.view(Degree, id) }, post: async req => { @@ -40,4 +36,4 @@ const DegreesController = { } } -module.exports = DegreesController; \ No newline at end of file +module.exports = DegreesController; diff --git a/api/controllers/ExamsController.js b/api/controllers/ExamsController.js index c5e41160..e016cac1 100644 --- a/api/controllers/ExamsController.js +++ b/api/controllers/ExamsController.js @@ -28,28 +28,24 @@ const fields = { const ExamsController = { index: async req => { - return await ModelController.index(req, { - Model: Exam, - fields - }); + const query = req.query + return await ModelController.index(Exam, query, fields); }, view: async req => { - return await ModelController.view(req, { - Model: Exam, - fields - }) + const { id } = req.params + return await ModelController.view(Exam, id) }, update: async req => { const { id } = req.params; - // Some pre-processing might be needed here on req.body - // for tags (eg remove duplicate etc) - return await ModelController.update(Exam, id, req.body); + const data = req.body + return await ModelController.update(Exam, id, data); }, insert: async req => { - return await ModelController.insert(Exam, req.body); + const data = req.body + return await ModelController.insert(Exam, data); }, delete: async req => { diff --git a/api/controllers/FormTemplates.js b/api/controllers/FormTemplates.js index c8d7121d..465b527a 100644 --- a/api/controllers/FormTemplates.js +++ b/api/controllers/FormTemplates.js @@ -16,17 +16,13 @@ const fields = { const FormTemplatesController = { index: async req => { - return await ModelController.index(req, { - Model: FormTemplate, - fields - }); + const query = req.query + return await ModelController.index(FormTemplate, query, fields); }, view: async req => { - return await ModelController.view(req, { - Model: FormTemplate, - fields - }) + const { id } = req.params + return await ModelController.view(FormTemplate, id) }, post: async req => { @@ -35,4 +31,4 @@ const FormTemplatesController = { } } -module.exports = FormTemplatesController; \ No newline at end of file +module.exports = FormTemplatesController; diff --git a/api/controllers/FormsController.js b/api/controllers/FormsController.js index 18128de0..74387b09 100644 --- a/api/controllers/FormsController.js +++ b/api/controllers/FormsController.js @@ -22,16 +22,13 @@ const fields = { const FormsController = { index: async req => { - return await ModelController.index(req, { - Model: Form, fields - }); + const query = req.query + return await ModelController.index(Form, query, fields); }, view: async req => { - return await ModelController.view(req, { - Model: Form, - fields - }) + const { id } = req.params + return await ModelController.view(Form, id) }, post: async req => { @@ -40,4 +37,4 @@ const FormsController = { } } -module.exports = FormsController; \ No newline at end of file +module.exports = FormsController; diff --git a/api/controllers/ModelController.js b/api/controllers/ModelController.js index 23040464..a8721824 100644 --- a/api/controllers/ModelController.js +++ b/api/controllers/ModelController.js @@ -6,30 +6,17 @@ const { default: mongoose } = require("mongoose"); const { BadRequestError, ValidationError, NotImplementedError } = require("../exceptions/ApiException"); -const validateModel = (Model, data) => { - const validationTest = (new Model(data)).validateSync() - if (validationTest) { - let errors = {} - for (const err in validationTest.errors) { - errors[err] = validationTest.errors[err].message - } - throw new ValidationError(errors) - } -} - const ModelController = { - index: async (req, { - Model, fields, populate } - ) => { + index: async (Model, query, fields, { populate } = {}) => { let $match = {}; let filter = {}; let sort = "_id"; let direction = 1; let limit = 100; - for (key in req.query) { - const value = req.query[key]; + for (key in query) { + const value = query[key]; if (key == '_direction') { if (value=="1") direction = 1; else if (value=="-1") direction = -1; @@ -102,11 +89,10 @@ const ModelController = { }; }, - view: async (req, { Model, populate }) => { - const { id } = req.params + view: async (Model, id, { populate } = {}) => { try { const obj = await Model.findById(id) - if (populate) return await obj.populate(populate) + if (populate !== undefined) return await obj.populate(populate) else return obj } catch(err) { console.log(`not found ${id}`) @@ -115,22 +101,36 @@ const ModelController = { }, update: async (Model, id, data) => { - validateModel(Model, data) try { - await Model.findByIdAndUpdate(id, { $set: data}) + await Model.findByIdAndUpdate(id, data, { runValidators: true }) } catch(err) { - throw new BadRequestError() + if (err instanceof mongoose.Error.ValidationError) { + let validationErrors = {} + for (const field in err.errors) { + validationErrors[field] = err.errors[field].message + } + throw new ValidationError(validationErrors) + } else { + throw new BadRequestError() + } } }, insert: async (Model, data) => { - validateModel(Model, data) try { const entry = new Model(data) await entry.save() return entry._id } catch (err) { - throw new BadRequestError() + if (err instanceof mongoose.Error.ValidationError) { + let validationErrors = {} + for (const field in err.errors) { + validationErrors[field] = err.errors[field].message + } + throw new ValidationError(validationErrors) + } else { + throw new BadRequestError() + } } }, diff --git a/api/controllers/ProposalsController.js b/api/controllers/ProposalsController.js index 4783af04..6d437541 100644 --- a/api/controllers/ProposalsController.js +++ b/api/controllers/ProposalsController.js @@ -54,17 +54,13 @@ const fields = { const ProposalsController = { index: async req => { - return await ModelController.index(req, { - Model: Proposal, - fields - }); + const query = req.query + return await ModelController.index(Proposal, query, fields); }, view: async req => { - return await ModelController.view(req, { - Model: Proposal, - fields - }) + const { id } = req.params + return await ModelController.view(Proposal, id) }, post: async req => { diff --git a/api/controllers/UsersController.js b/api/controllers/UsersController.js index 96e436ac..3a0249ae 100644 --- a/api/controllers/UsersController.js +++ b/api/controllers/UsersController.js @@ -40,21 +40,25 @@ const fields = { const UsersController = { index: async req => { - return await ModelController.index(req, { - Model: User, fields - }); + const query = req.query + return await ModelController.index(User, query, fields); }, view: async req => { - return await ModelController.view(req, { - Model: User, fields - }) + const { id } = req.params + return await ModelController.view(User, id, { populate: { path: 'comments', populate: { path: 'attachments creator_id' } } }) }, - post: async req => { - const item = new User(req.body); - return await item.save(); + update: async req => { + const { id } = req.params + const data = req.body + return await ModelController.update(User, id, data) + }, + + insert: async req => { + const data = req.body + return await ModelController.insert(User, data) } } -module.exports = UsersController; \ No newline at end of file +module.exports = UsersController; diff --git a/api/models/User.js b/api/models/User.js index e7227c3b..53a94923 100644 --- a/api/models/User.js +++ b/api/models/User.js @@ -32,11 +32,12 @@ const userSchema = new mongoose.Schema({ }, password: { type: String - } + }, + comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }] }) userSchema.plugin(passportLocalMongoose) const User = mongoose.model('User', userSchema) -module.exports = User; \ No newline at end of file +module.exports = User; diff --git a/api/router.js b/api/router.js index 1007a3d2..ef7171e2 100644 --- a/api/router.js +++ b/api/router.js @@ -112,9 +112,10 @@ router.get('/exams/:id', response_envelope(Exams.view)) router.post('/exams/:id', response_envelope(Exams.update)) router.get('/exams', response_envelope(Exams.index)) router.post('/exams', response_envelope(Exams.insert)) -router.get('/users', response_envelope(Users.index)) router.get('/users/:id', response_envelope(Users.view)) -router.post('/users', response_envelope(Users.post)) +router.get('/users', response_envelope(Users.index)) +router.post('/users/:id', response_envelope(Users.update)) +router.post('/users', response_envelope(Users.insert)) router.get('/attachments', response_envelope(Attachments.index)) // Queste route sono leggermente diverse rispetto alle altre perché si occupano @@ -123,9 +124,9 @@ router.post('/attachments', Attachments.postMiddleware, response_envelope(Attach router.get('/attachments/:id/content', Attachments.viewContent) router.get('/attachments/:id', response_envelope(Attachments.view)) +router.get('/comments/:id', response_envelope(Comments.view)) router.get('/comments', response_envelope(Comments.index)) router.post('/comments/delete/:id', response_envelope(Comments.delete)) -router.get('/comments/:id', response_envelope(Comments.view)) router.post('/comments', response_envelope(Comments.post)) router.all(/.*/, response_envelope((req) => {throw new NotFoundError()})) diff --git a/frontend/src/components/CommentWidget.js b/frontend/src/components/CommentWidget.js index 6fc29b43..01b5a075 100644 --- a/frontend/src/components/CommentWidget.js +++ b/frontend/src/components/CommentWidget.js @@ -60,10 +60,10 @@ export default function CommentWidget({ } commentInserter.mutate(comment, { onSuccess: (commentId) => { + afterCommentPost(commentId) setText("") setFiles([]) setError({}) - afterCommentPost(commentId) }, onError: (err) => { engine.flashError(err) diff --git a/frontend/src/components/QueryTable.js b/frontend/src/components/QueryTable.js index 1dc0e338..cc4feae6 100644 --- a/frontend/src/components/QueryTable.js +++ b/frontend/src/components/QueryTable.js @@ -65,7 +65,7 @@ function FilterBadges() { function Table({ Model }) { const engine = useEngine() - const { query } = useQuery() + const { query, setQuery } = useQuery() const indexQuery = engine.useIndex(Model, query) const [ selectedIds, setSelectedIds ] = useState([]) const data = indexQuery.data @@ -90,6 +90,14 @@ function Table({ Model }) { }) } + function increaseLimit(d) { + setQuery(q => { + return {...q, + _limit: q._limit + d + } + }) + } + function Header({ field, label, enable_sort }) { if (enable_sort) { return toggleSort(field)}> @@ -120,7 +128,7 @@ function Table({ Model }) {

{ data.items.length < data.total - ? : null diff --git a/frontend/src/pages/UserPage.js b/frontend/src/pages/UserPage.js index 160c4a2b..62c8fc3f 100644 --- a/frontend/src/pages/UserPage.js +++ b/frontend/src/pages/UserPage.js @@ -77,7 +77,7 @@ function ProposalCard({proposal}) { } -function CommentCard({comment}) { +function CommentCard({ comment, userUpdater }) { const engine = useEngine() const deleter = engine.useDelete(Comment, comment._id) @@ -85,7 +85,16 @@ function CommentCard({comment}) { engine.modalConfirm("Elimina commento", "confermi di voler eliminare il commento?") .then(confirm => { if (confirm) { - deleter.mutate(null, {}) + deleter.mutate(null, { + onSuccess: () => { + const data = { + $pull: { + comments: comment._id + } + } + userUpdater(data, {}) + } + }) } }) @@ -104,25 +113,24 @@ function CommentCard({comment}) { export default function UserPage() { const { id } = useParams() - const [ user, setUser ] = useState(null) - const [ proposals, setProposals ] = useState(null) - const [ comments, setComments ] = useState(null) const engine = useEngine() const userQuery = engine.useGet(User, id) + const userUpdater = engine.useUpdate(User, id) const proposalsQuery = engine.useIndex(Proposal, { user_id: id }) - const commentsQuery = engine.useIndex(Comment, { creator_id: id }) - if (user !== userQuery.data) { - if (userQuery.isSuccess) setUser(userQuery.data) - return caricamento utente... + function addPostedCommentToUser(comment_id) { + const data = { $addToSet: { comments: comment_id } } + userUpdater.mutate(data, {}) } - if (proposals !== proposalsQuery.data) { - if (proposalsQuery.isSuccess) setProposals(proposalsQuery.data) - } - if (comments !== commentsQuery.data) { - if (commentsQuery.isSuccess) setComments(commentsQuery.data) + + if (!userQuery.isSuccess) { + return caricamento utente... } + const user = userQuery.data + const comments = user.comments + const proposals = proposalsQuery.data + return <>

@@ -139,7 +147,7 @@ export default function UserPage() {

{ - proposalsQuery.isSuccess && proposals === proposalsQuery.data + proposalsQuery.isSuccess ? ( proposals.length == 0 ?
Nessun piano di studi presentato.
@@ -155,15 +163,11 @@ export default function UserPage() {

I documenti e le annotazioni inserite in questa sezione sono associate allo studente, ma visibili solo per gli amministratori.

{ - commentsQuery.isSuccess && comments === commentsQuery.data - ? ( - comments.items.length === 0 - ?

Nessun documento allegato.

- : comments.items.map(comment => ) - ) - : caricamento commenti e allegati... + comments.length === 0 + ?

Nessun documento allegato.

+ : comments.map(comment => ) } - +
}