-
- {{ comment.user.username }}
-
-
- {{ comment.user.username }}
-
+
{{ comment.user.username }}
{{ formatDate(comment.createdAt) }}
diff --git a/client/pages/user/_id/index.vue b/client/pages/user/_id/index.vue
new file mode 100644
index 000000000..52652928c
--- /dev/null
+++ b/client/pages/user/_id/index.vue
@@ -0,0 +1,103 @@
+
+
+
+
+
{{ user.username }}'s Profile
+
Member since {{ formatDate(user.createdAt) }}
+
+
+
+
Reviews
+
+
+
+
+
+
+
+
+ {{ review.libraryItem?.title || 'Unknown Book' }}
+
+
+
+
+
+
+
{{ review.text }}
+
{{ formatDate(review.createdAt) }}
+
+
+
+
+
{{ user.username }} hasn't written any reviews yet.
+
Loading...
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/controllers/UserController.js b/server/controllers/UserController.js
index 0fb105133..9a0e7f9ec 100644
--- a/server/controllers/UserController.js
+++ b/server/controllers/UserController.js
@@ -489,5 +489,72 @@ class UserController {
next()
}
+
+ /**
+ * GET: /api/users/:id/reviews
+ * Get reviews for a user with associated library items
+ *
+ * @param {UserControllerRequest} req
+ * @param {Response} res
+ */
+ async getUserReviews(req, res) {
+ try {
+ // First get all reviews for the user
+ const reviews = await Database.commentModel.findAll({
+ where: { userId: req.params.id },
+ include: [{
+ model: Database.userModel,
+ as: 'user',
+ attributes: ['id', 'username']
+ }],
+ order: [['createdAt', 'DESC']]
+ })
+
+ // Get all libraryItemIds from the reviews
+ const libraryItemIds = reviews.map(review => review.libraryItemId)
+
+ // Get all library items with their books
+ const libraryItems = await Database.libraryItemModel.findAll({
+ where: {
+ id: libraryItemIds
+ },
+ attributes: ['id', 'title', 'mediaType', 'path', 'relPath', 'libraryId', 'libraryFolderId', 'isFile', 'updatedAt'],
+ include: [{
+ model: Database.bookModel,
+ as: 'book',
+ attributes: ['id', 'title', 'coverPath']
+ }]
+ })
+
+ // Create a map of library items by id for easy lookup
+ const libraryItemsMap = libraryItems.reduce((map, item) => {
+ map[item.id] = item
+ return map
+ }, {})
+
+ // Merge the data
+ const reviewsWithItems = reviews.map(review => {
+ const reviewJson = review.toJSON()
+ const libraryItem = libraryItemsMap[reviewJson.libraryItemId]
+
+ if (libraryItem) {
+ const libraryItemJson = libraryItem.toJSON()
+ reviewJson.libraryItem = libraryItemJson
+ if (libraryItemJson.book) {
+ reviewJson.libraryItem.media = {
+ coverPath: libraryItemJson.book.coverPath
+ }
+ reviewJson.book = libraryItemJson.book
+ }
+ }
+ return reviewJson
+ })
+
+ res.json(reviewsWithItems)
+ } catch (error) {
+ Logger.error('[UserController] getUserReviews error:', error)
+ res.status(500).json({ error: 'Failed to get user reviews' })
+ }
+ }
}
module.exports = new UserController()
diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js
index 76a958bc6..58a404978 100644
--- a/server/routers/ApiRouter.js
+++ b/server/routers/ApiRouter.js
@@ -144,6 +144,7 @@ class ApiRouter {
this.router.patch('/users/:id/openid-unlink', UserController.middleware.bind(this), UserController.unlinkFromOpenID.bind(this))
this.router.get('/users/:id/listening-sessions', UserController.middleware.bind(this), UserController.getListeningSessions.bind(this))
this.router.get('/users/:id/listening-stats', UserController.middleware.bind(this), UserController.getListeningStats.bind(this))
+ this.router.get('/users/:id/reviews', UserController.middleware.bind(this), UserController.getUserReviews.bind(this))
//
// Collection Routes