farheen-psql 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/constants/modules.js +3 -0
- package/src/controllers/commentController.js +61 -0
- package/src/controllers/permissionController.js +6 -6
- package/src/controllers/postController.js +80 -0
- package/src/controllers/userController.js +7 -7
- package/src/models/Comment.js +28 -0
- package/src/models/Permission.js +12 -7
- package/src/models/Post.js +20 -0
- package/src/models/index.js +19 -1
- package/src/repositories/commentRepository.js +22 -0
- package/src/repositories/postRepository.js +54 -0
- package/src/repositories/userRepository.js +6 -6
- package/src/routes/commentRoutes.js +14 -0
- package/src/routes/postRoutes.js +25 -0
- package/src/routes/routes.js +4 -0
- package/src/services/authService.js +10 -1
- package/src/services/commentService.js +24 -0
- package/src/services/postService.js +64 -0
package/package.json
CHANGED
package/src/constants/modules.js
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as commentService from '../services/commentService.js';
|
|
2
|
+
|
|
3
|
+
export const createComment = async (req, res) => {
|
|
4
|
+
try {
|
|
5
|
+
const { content, post_id, parent_id } = req.body;
|
|
6
|
+
const user_id = req.user.id;
|
|
7
|
+
|
|
8
|
+
if (!content || !post_id) {
|
|
9
|
+
return res.status(400).json({ error: 'Content and post_id are required' });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const commentData = {
|
|
13
|
+
content,
|
|
14
|
+
user_id,
|
|
15
|
+
post_id,
|
|
16
|
+
parent_id: parent_id || null
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const newComment = await commentService.createComment(commentData);
|
|
20
|
+
res.status(201).json({ message: 'Comment created successfully', comment: newComment });
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error('Error creating comment:', error);
|
|
23
|
+
if (error.message === 'Parent comment not found' || error.message === 'Parent comment does not belong to the specified post') {
|
|
24
|
+
return res.status(400).json({ error: error.message });
|
|
25
|
+
}
|
|
26
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const updateComment = async (req, res) => {
|
|
31
|
+
try {
|
|
32
|
+
const { id } = req.params;
|
|
33
|
+
const { content } = req.body;
|
|
34
|
+
|
|
35
|
+
const updatedComment = await commentService.updateComment(id, { content });
|
|
36
|
+
if (!updatedComment) {
|
|
37
|
+
return res.status(404).json({ error: 'Comment not found' });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
res.status(200).json({ message: 'Comment updated successfully', comment: updatedComment });
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('Error updating comment:', error);
|
|
43
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const deleteComment = async (req, res) => {
|
|
48
|
+
try {
|
|
49
|
+
const { id } = req.params;
|
|
50
|
+
|
|
51
|
+
const deletedComment = await commentService.deleteComment(id);
|
|
52
|
+
if (!deletedComment) {
|
|
53
|
+
return res.status(404).json({ error: 'Comment not found' });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
res.status(200).json({ message: 'Comment deleted successfully', comment: deletedComment });
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error('Error deleting comment:', error);
|
|
59
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
60
|
+
}
|
|
61
|
+
};
|
|
@@ -26,11 +26,11 @@ export const getPermissionById = async (req, res) => {
|
|
|
26
26
|
|
|
27
27
|
export const createPermission = async (req, res) => {
|
|
28
28
|
try {
|
|
29
|
-
const { module, action } = req.body;
|
|
30
|
-
if (!module || !action) {
|
|
31
|
-
return res.status(400).json({ error: 'module and action are required' });
|
|
29
|
+
const { name, module, action } = req.body;
|
|
30
|
+
if (!name || !module || !action) {
|
|
31
|
+
return res.status(400).json({ error: 'name, module and action are required' });
|
|
32
32
|
}
|
|
33
|
-
const newPermission = await permissionService.createPermission({ module, action });
|
|
33
|
+
const newPermission = await permissionService.createPermission({ name, module, action });
|
|
34
34
|
res.status(201).json(newPermission);
|
|
35
35
|
} catch (error) {
|
|
36
36
|
console.error('Error creating permission:', error);
|
|
@@ -41,9 +41,9 @@ export const createPermission = async (req, res) => {
|
|
|
41
41
|
export const updatePermission = async (req, res) => {
|
|
42
42
|
try {
|
|
43
43
|
const { id } = req.params;
|
|
44
|
-
const { module, action } = req.body;
|
|
44
|
+
const { name, module, action } = req.body;
|
|
45
45
|
|
|
46
|
-
const updatedPermission = await permissionService.updatePermission(id, { module, action });
|
|
46
|
+
const updatedPermission = await permissionService.updatePermission(id, { name, module, action });
|
|
47
47
|
if (!updatedPermission) {
|
|
48
48
|
return res.status(404).json({ error: 'Permission not found' });
|
|
49
49
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as postService from '../services/postService.js';
|
|
2
|
+
|
|
3
|
+
export const createPost = async (req, res) => {
|
|
4
|
+
try {
|
|
5
|
+
const { content } = req.body;
|
|
6
|
+
// Assume user is authenticated and req.user exists from authMiddleware
|
|
7
|
+
const user_id = req.user.id;
|
|
8
|
+
|
|
9
|
+
if (!content) {
|
|
10
|
+
return res.status(400).json({ error: 'Content is required' });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const newPost = await postService.createPost({ content, user_id });
|
|
14
|
+
res.status(201).json({ message: 'Post created successfully', post: newPost });
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error('Error creating post:', error);
|
|
17
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const getAllPosts = async (req, res) => {
|
|
22
|
+
try {
|
|
23
|
+
const posts = await postService.getAllPosts();
|
|
24
|
+
res.status(200).json(posts);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error('Error fetching posts:', error);
|
|
27
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const getPostById = async (req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
const { id } = req.params;
|
|
34
|
+
const post = await postService.getPostById(id);
|
|
35
|
+
|
|
36
|
+
if (!post) {
|
|
37
|
+
return res.status(404).json({ error: 'Post not found' });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
res.status(200).json(post);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('Error fetching post:', error);
|
|
43
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const updatePost = async (req, res) => {
|
|
48
|
+
try {
|
|
49
|
+
const { id } = req.params;
|
|
50
|
+
const { content } = req.body;
|
|
51
|
+
|
|
52
|
+
// In a real app, you should check if req.user.id matches post.user_id before updating!
|
|
53
|
+
const updatedPost = await postService.updatePost(id, { content });
|
|
54
|
+
if (!updatedPost) {
|
|
55
|
+
return res.status(404).json({ error: 'Post not found' });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
res.status(200).json({ message: 'Post updated successfully', post: updatedPost });
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('Error updating post:', error);
|
|
61
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const deletePost = async (req, res) => {
|
|
66
|
+
try {
|
|
67
|
+
const { id } = req.params;
|
|
68
|
+
|
|
69
|
+
// Check if the user is the author or an admin
|
|
70
|
+
const deletedPost = await postService.deletePost(id);
|
|
71
|
+
if (!deletedPost) {
|
|
72
|
+
return res.status(404).json({ error: 'Post not found' });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
res.status(200).json({ message: 'Post deleted successfully', post: deletedPost });
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('Error deleting post:', error);
|
|
78
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
79
|
+
}
|
|
80
|
+
};
|
|
@@ -26,12 +26,12 @@ export const getUserById = async (req, res) => {
|
|
|
26
26
|
|
|
27
27
|
export const createUser = async (req, res) => {
|
|
28
28
|
try {
|
|
29
|
-
const { name, email, age } = req.body;
|
|
29
|
+
const { name, email, age, role_id } = req.body;
|
|
30
30
|
if (!name || !email) {
|
|
31
31
|
return res.status(400).json({ error: 'Name and email are required' });
|
|
32
32
|
}
|
|
33
|
-
const newUser = await userService.createUser({ name, email, age });
|
|
34
|
-
res.status(201).json(newUser);
|
|
33
|
+
const newUser = await userService.createUser({ name, email, age, role_id });
|
|
34
|
+
res.status(201).json({ message: 'User created successfully', user: newUser });
|
|
35
35
|
} catch (error) {
|
|
36
36
|
console.error('Error creating user:', error);
|
|
37
37
|
// Handle specific service errors
|
|
@@ -45,13 +45,13 @@ export const createUser = async (req, res) => {
|
|
|
45
45
|
export const updateUser = async (req, res) => {
|
|
46
46
|
try {
|
|
47
47
|
const { id } = req.params;
|
|
48
|
-
const { name, email, age } = req.body;
|
|
49
|
-
|
|
50
|
-
const updatedUser = await userService.updateUser(id, { name, email, age });
|
|
48
|
+
const { name, email, age, role_id } = req.body;
|
|
49
|
+
|
|
50
|
+
const updatedUser = await userService.updateUser(id, { name, email, age, role_id });
|
|
51
51
|
if (!updatedUser) {
|
|
52
52
|
return res.status(404).json({ error: 'User not found' });
|
|
53
53
|
}
|
|
54
|
-
res.status(200).json(updatedUser);
|
|
54
|
+
res.status(200).json({ message: 'User updated successfully', user: updatedUser });
|
|
55
55
|
} catch (error) {
|
|
56
56
|
console.error('Error updating user:', error);
|
|
57
57
|
if (error.message === 'Age cannot be negative') {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DataTypes } from 'sequelize';
|
|
2
|
+
import sequelize from '../config/db.js';
|
|
3
|
+
|
|
4
|
+
const Comment = sequelize.define('Comment', {
|
|
5
|
+
content: {
|
|
6
|
+
type: DataTypes.TEXT,
|
|
7
|
+
allowNull: false,
|
|
8
|
+
},
|
|
9
|
+
user_id: {
|
|
10
|
+
type: DataTypes.INTEGER,
|
|
11
|
+
allowNull: false,
|
|
12
|
+
},
|
|
13
|
+
post_id: {
|
|
14
|
+
type: DataTypes.INTEGER,
|
|
15
|
+
allowNull: false,
|
|
16
|
+
},
|
|
17
|
+
parent_id: {
|
|
18
|
+
type: DataTypes.INTEGER,
|
|
19
|
+
allowNull: true, // Null for top-level comments, populated for replies
|
|
20
|
+
}
|
|
21
|
+
}, {
|
|
22
|
+
tableName: 'comments',
|
|
23
|
+
timestamps: true,
|
|
24
|
+
createdAt: 'created_at',
|
|
25
|
+
updatedAt: 'updated_at',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export default Comment;
|
package/src/models/Permission.js
CHANGED
|
@@ -3,25 +3,30 @@ import sequelize from '../config/db.js';
|
|
|
3
3
|
|
|
4
4
|
// This is exactly like mongoose.Schema({ ... })
|
|
5
5
|
const Permission = sequelize.define('Permission', {
|
|
6
|
+
name: {
|
|
7
|
+
type: DataTypes.STRING(100),
|
|
8
|
+
allowNull: false,
|
|
9
|
+
},
|
|
6
10
|
module: {
|
|
7
11
|
type: DataTypes.STRING(50),
|
|
8
12
|
allowNull: false,
|
|
9
13
|
},
|
|
10
14
|
action: {
|
|
11
|
-
type: DataTypes.STRING
|
|
15
|
+
type: DataTypes.ARRAY(DataTypes.STRING),
|
|
12
16
|
allowNull: false,
|
|
17
|
+
defaultValue: []
|
|
13
18
|
}
|
|
14
19
|
}, {
|
|
15
20
|
tableName: 'permissions',
|
|
16
21
|
timestamps: true,
|
|
17
22
|
createdAt: 'created_at',
|
|
18
23
|
updatedAt: false,
|
|
19
|
-
indexes: [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
]
|
|
24
|
+
// indexes: [
|
|
25
|
+
// {
|
|
26
|
+
// unique: true,
|
|
27
|
+
// fields: ['module', 'action']
|
|
28
|
+
// }
|
|
29
|
+
// ]
|
|
25
30
|
});
|
|
26
31
|
|
|
27
32
|
export default Permission;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DataTypes } from 'sequelize';
|
|
2
|
+
import sequelize from '../config/db.js';
|
|
3
|
+
|
|
4
|
+
const Post = sequelize.define('Post', {
|
|
5
|
+
content: {
|
|
6
|
+
type: DataTypes.TEXT,
|
|
7
|
+
allowNull: false,
|
|
8
|
+
},
|
|
9
|
+
user_id: {
|
|
10
|
+
type: DataTypes.INTEGER,
|
|
11
|
+
allowNull: false,
|
|
12
|
+
}
|
|
13
|
+
}, {
|
|
14
|
+
tableName: 'posts',
|
|
15
|
+
timestamps: true,
|
|
16
|
+
createdAt: 'created_at',
|
|
17
|
+
updatedAt: 'updated_at',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export default Post;
|
package/src/models/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import User from './User.js';
|
|
2
2
|
import Role from './Role.js';
|
|
3
3
|
import Permission from './Permission.js';
|
|
4
|
+
import Post from './Post.js';
|
|
5
|
+
import Comment from './Comment.js';
|
|
4
6
|
|
|
5
7
|
// ---------------------------------------------------------
|
|
6
8
|
// RELATIONSHIPS
|
|
@@ -25,5 +27,21 @@ Permission.belongsToMany(Role, {
|
|
|
25
27
|
timestamps: false
|
|
26
28
|
});
|
|
27
29
|
|
|
30
|
+
// User and Post
|
|
31
|
+
User.hasMany(Post, { foreignKey: 'user_id' });
|
|
32
|
+
Post.belongsTo(User, { foreignKey: 'user_id' });
|
|
33
|
+
|
|
34
|
+
// User and Comment
|
|
35
|
+
User.hasMany(Comment, { foreignKey: 'user_id' });
|
|
36
|
+
Comment.belongsTo(User, { foreignKey: 'user_id' });
|
|
37
|
+
|
|
38
|
+
// Post and Comment
|
|
39
|
+
Post.hasMany(Comment, { foreignKey: 'post_id' });
|
|
40
|
+
Comment.belongsTo(Post, { foreignKey: 'post_id' });
|
|
41
|
+
|
|
42
|
+
// Comment Replies (Self-referencing)
|
|
43
|
+
Comment.hasMany(Comment, { as: 'Replies', foreignKey: 'parent_id' });
|
|
44
|
+
Comment.belongsTo(Comment, { as: 'Parent', foreignKey: 'parent_id' });
|
|
45
|
+
|
|
28
46
|
// Export all models so they can be imported together from this file
|
|
29
|
-
export { User, Role, Permission };
|
|
47
|
+
export { User, Role, Permission, Post, Comment };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Comment } from '../models/index.js';
|
|
2
|
+
|
|
3
|
+
export const create = async (commentData) => {
|
|
4
|
+
return await Comment.create(commentData);
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const findById = async (id) => {
|
|
8
|
+
return await Comment.findByPk(id);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const update = async (id, commentData) => {
|
|
12
|
+
const comment = await Comment.findByPk(id);
|
|
13
|
+
if (!comment) return null;
|
|
14
|
+
return await comment.update(commentData);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const remove = async (id) => {
|
|
18
|
+
const comment = await Comment.findByPk(id);
|
|
19
|
+
if (!comment) return null;
|
|
20
|
+
await comment.destroy();
|
|
21
|
+
return comment;
|
|
22
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Post, Comment, User } from '../models/index.js';
|
|
2
|
+
|
|
3
|
+
export const create = async (postData) => {
|
|
4
|
+
return await Post.create(postData);
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const findAll = async () => {
|
|
8
|
+
return await Post.findAll({
|
|
9
|
+
order: [['created_at', 'DESC']],
|
|
10
|
+
include: [
|
|
11
|
+
{
|
|
12
|
+
model: User,
|
|
13
|
+
attributes: ['id', 'name', 'email'] // Don't send passwords!
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const findByIdWithComments = async (id) => {
|
|
20
|
+
return await Post.findByPk(id, {
|
|
21
|
+
include: [
|
|
22
|
+
{
|
|
23
|
+
model: User,
|
|
24
|
+
attributes: ['id', 'name', 'email']
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
model: Comment,
|
|
28
|
+
attributes: ['id', 'content', 'parent_id'],
|
|
29
|
+
// Include the author of the comment
|
|
30
|
+
include: [
|
|
31
|
+
{
|
|
32
|
+
model: User,
|
|
33
|
+
attributes: ['id', 'name', 'email']
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
// Order comments by creation time
|
|
37
|
+
order: [['created_at', 'ASC']]
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const update = async (id, postData) => {
|
|
44
|
+
const post = await Post.findByPk(id);
|
|
45
|
+
if (!post) return null;
|
|
46
|
+
return await post.update(postData);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const remove = async (id) => {
|
|
50
|
+
const post = await Post.findByPk(id);
|
|
51
|
+
if (!post) return null;
|
|
52
|
+
await post.destroy();
|
|
53
|
+
return post;
|
|
54
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { User } from '../models/index.js';
|
|
2
2
|
|
|
3
3
|
export const findAll = async () => {
|
|
4
|
-
return await User.findAll({
|
|
4
|
+
return await User.findAll({
|
|
5
5
|
order: [['created_at', 'DESC']],
|
|
6
6
|
attributes: { exclude: ['password'] }
|
|
7
7
|
});
|
|
@@ -19,7 +19,7 @@ export const findByEmail = async (email) => {
|
|
|
19
19
|
|
|
20
20
|
export const create = async (userData) => {
|
|
21
21
|
const user = await User.create(userData);
|
|
22
|
-
const userObj = user
|
|
22
|
+
const userObj = user;
|
|
23
23
|
delete userObj.password;
|
|
24
24
|
return userObj;
|
|
25
25
|
};
|
|
@@ -27,9 +27,9 @@ export const create = async (userData) => {
|
|
|
27
27
|
export const update = async (id, userData) => {
|
|
28
28
|
const user = await User.findByPk(id);
|
|
29
29
|
if (!user) return null;
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
await user.update(userData);
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
const userObj = user.toJSON();
|
|
34
34
|
delete userObj.password;
|
|
35
35
|
return userObj;
|
|
@@ -38,9 +38,9 @@ export const update = async (id, userData) => {
|
|
|
38
38
|
export const remove = async (id) => {
|
|
39
39
|
const user = await User.findByPk(id);
|
|
40
40
|
if (!user) return null;
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
await user.destroy();
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
const userObj = user.toJSON();
|
|
45
45
|
delete userObj.password;
|
|
46
46
|
return userObj;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import * as commentController from '../controllers/commentController.js';
|
|
3
|
+
import { authMiddleware } from '../middlewares/authMiddleware.js';
|
|
4
|
+
|
|
5
|
+
const router = express.Router();
|
|
6
|
+
|
|
7
|
+
// Apply authMiddleware to all comment routes
|
|
8
|
+
router.use(authMiddleware);
|
|
9
|
+
|
|
10
|
+
router.post('/', commentController.createComment);
|
|
11
|
+
router.put('/:id', commentController.updateComment);
|
|
12
|
+
router.delete('/:id', commentController.deleteComment);
|
|
13
|
+
|
|
14
|
+
export default router;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import * as postController from '../controllers/postController.js';
|
|
3
|
+
import { authMiddleware } from '../middlewares/authMiddleware.js';
|
|
4
|
+
import { authorizeMiddleware } from '../middlewares/authorizeMiddleware.js';
|
|
5
|
+
import { MODULES } from '../constants/modules.js';
|
|
6
|
+
import { ACTIONS } from '../constants/actions.js';
|
|
7
|
+
|
|
8
|
+
const router = express.Router();
|
|
9
|
+
|
|
10
|
+
// Apply authMiddleware to all post routes
|
|
11
|
+
router.use(authMiddleware);
|
|
12
|
+
|
|
13
|
+
// If you want to require specific permissions to view/create posts, use authorizeMiddleware.
|
|
14
|
+
// For now, we will allow any authenticated user to create a post and read posts.
|
|
15
|
+
// If you uncomment these, you will need to assign POSTS permissions to the users/roles.
|
|
16
|
+
// router.post('/', authorizeMiddleware(MODULES.POSTS, ACTIONS.CREATE), postController.createPost);
|
|
17
|
+
// router.get('/', authorizeMiddleware(MODULES.POSTS, ACTIONS.READ), postController.getAllPosts);
|
|
18
|
+
|
|
19
|
+
router.post('/', postController.createPost);
|
|
20
|
+
router.get('/', postController.getAllPosts);
|
|
21
|
+
router.get('/:id', postController.getPostById);
|
|
22
|
+
router.put('/:id', postController.updatePost);
|
|
23
|
+
router.delete('/:id', postController.deletePost);
|
|
24
|
+
|
|
25
|
+
export default router;
|
package/src/routes/routes.js
CHANGED
|
@@ -3,6 +3,8 @@ import authRoutes from './authRoutes.js';
|
|
|
3
3
|
import userRoutes from './userRoutes.js';
|
|
4
4
|
import roleRoutes from './roleRoutes.js';
|
|
5
5
|
import permissionRoutes from './permissionRoutes.js';
|
|
6
|
+
import postRoutes from './postRoutes.js';
|
|
7
|
+
import commentRoutes from './commentRoutes.js';
|
|
6
8
|
|
|
7
9
|
const router = express.Router();
|
|
8
10
|
|
|
@@ -10,5 +12,7 @@ router.use('/auth', authRoutes);
|
|
|
10
12
|
router.use('/user', userRoutes);
|
|
11
13
|
router.use('/roles', roleRoutes);
|
|
12
14
|
router.use('/permissions', permissionRoutes);
|
|
15
|
+
router.use('/posts', postRoutes);
|
|
16
|
+
router.use('/comments', commentRoutes);
|
|
13
17
|
|
|
14
18
|
export default router;
|
|
@@ -51,7 +51,16 @@ export const login = async (email, password) => {
|
|
|
51
51
|
const permissions = await roleRepository.getRolePermissions(user.role_id);
|
|
52
52
|
|
|
53
53
|
// Format permissions into an array of string identifiers (e.g. ['USERS:READ'])
|
|
54
|
-
const permissionStrings =
|
|
54
|
+
const permissionStrings = [];
|
|
55
|
+
permissions.forEach(p => {
|
|
56
|
+
if (Array.isArray(p.action)) {
|
|
57
|
+
p.action.forEach(act => {
|
|
58
|
+
permissionStrings.push(`${p.module}:${act}`);
|
|
59
|
+
});
|
|
60
|
+
} else if (p.action) {
|
|
61
|
+
permissionStrings.push(`${p.module}:${p.action}`);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
55
64
|
|
|
56
65
|
const token = jwt.sign(
|
|
57
66
|
{
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as commentRepository from '../repositories/commentRepository.js';
|
|
2
|
+
|
|
3
|
+
export const createComment = async (commentData) => {
|
|
4
|
+
// If this is a reply, we could verify the parent comment exists and belongs to the same post
|
|
5
|
+
if (commentData.parent_id) {
|
|
6
|
+
const parentComment = await commentRepository.findById(commentData.parent_id);
|
|
7
|
+
if (!parentComment) {
|
|
8
|
+
throw new Error('Parent comment not found');
|
|
9
|
+
}
|
|
10
|
+
if (parentComment.post_id !== commentData.post_id) {
|
|
11
|
+
throw new Error('Parent comment does not belong to the specified post');
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return await commentRepository.create(commentData);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const updateComment = async (id, commentData) => {
|
|
19
|
+
return await commentRepository.update(id, commentData);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const deleteComment = async (id) => {
|
|
23
|
+
return await commentRepository.remove(id);
|
|
24
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as postRepository from '../repositories/postRepository.js';
|
|
2
|
+
|
|
3
|
+
export const createPost = async (postData) => {
|
|
4
|
+
return await postRepository.create(postData);
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const getAllPosts = async () => {
|
|
8
|
+
return await postRepository.findAll();
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const getPostById = async (id) => {
|
|
12
|
+
const post = await postRepository.findByIdWithComments(id);
|
|
13
|
+
|
|
14
|
+
if (!post) return null;
|
|
15
|
+
|
|
16
|
+
// Convert Sequelize model to plain JSON object so we can manipulate it easily
|
|
17
|
+
const postJson = post.toJSON();
|
|
18
|
+
|
|
19
|
+
// The comments are currently a flat array attached to the post.
|
|
20
|
+
// We need to build a nested tree structure out of it.
|
|
21
|
+
postJson.Comments = buildCommentTree(postJson.Comments || []);
|
|
22
|
+
|
|
23
|
+
return postJson;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const updatePost = async (id, postData) => {
|
|
27
|
+
return await postRepository.update(id, postData);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const deletePost = async (id) => {
|
|
31
|
+
return await postRepository.remove(id);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Helper function to turn flat comments array into a nested tree structure
|
|
35
|
+
function buildCommentTree(comments) {
|
|
36
|
+
const commentMap = {};
|
|
37
|
+
const rootComments = [];
|
|
38
|
+
|
|
39
|
+
// First pass: put all comments in a map by their ID
|
|
40
|
+
comments.forEach(comment => {
|
|
41
|
+
// Initialize Replies array
|
|
42
|
+
comment.Replies = [];
|
|
43
|
+
commentMap[comment.id] = comment;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Second pass: attach comments to their parent or push to root array
|
|
47
|
+
comments.forEach(comment => {
|
|
48
|
+
if (comment.parent_id) {
|
|
49
|
+
// It's a reply! Attach to parent.
|
|
50
|
+
// Make sure the parent actually exists in the map (it should, unless deleted/orphaned)
|
|
51
|
+
if (commentMap[comment.parent_id]) {
|
|
52
|
+
commentMap[comment.parent_id].Replies.push(comment);
|
|
53
|
+
} else {
|
|
54
|
+
// Parent doesn't exist, maybe deleted? Treat as top level or ignore.
|
|
55
|
+
rootComments.push(comment);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
// It's a top-level comment
|
|
59
|
+
rootComments.push(comment);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return rootComments;
|
|
64
|
+
}
|