powr-sdk-api
Version:
Shared API core library for PowrStack projects. Zero dependencies - works with Express, Next.js API routes, and other frameworks. All features are optional and install only what you need.
352 lines (341 loc) • 7.8 kB
JavaScript
"use strict";
const express = require('express');
const router = express.Router();
const {
getDb
} = require('../services/mongo');
const {
ObjectId
} = require('mongodb');
// Create new post
router.post('/', async (req, res) => {
try {
const {
content,
media,
isPublic = true,
tags,
mentions
} = req.body;
const projectId = req.projectId;
const userId = req.user.powrId;
if (!content && (!media || media.length === 0)) {
return res.status(400).json({
success: false,
message: 'Content or media is required'
});
}
const db = await getDb();
const newPost = {
projectId,
authorId: new ObjectId(userId),
content: content || '',
media: media || [],
likesCount: 0,
commentsCount: 0,
isPublic,
tags: tags || [],
mentions: mentions ? mentions.map(id => new ObjectId(id)) : [],
createdAt: new Date(),
updatedAt: new Date()
};
const result = await db.collection('feeds').insertOne(newPost);
// Populate author info
const author = await db.collection('users').findOne({
_id: new ObjectId(userId)
}, {
projection: {
fullName: 1,
email: 1,
avatar: 1
}
});
const createdPost = {
...newPost,
_id: result.insertedId,
author
};
return res.status(201).json({
success: true,
message: 'Post created successfully',
data: createdPost
});
} catch (error) {
console.error('Error creating post:', error);
return res.status(500).json({
success: false,
message: 'Failed to create post'
});
}
});
// Get feed with pagination and filters
router.get('/', async (req, res) => {
try {
const {
page = 1,
limit = 10,
userId,
tag,
search
} = req.query;
const projectId = req.projectId;
const skip = (parseInt(page) - 1) * parseInt(limit);
const query = {
projectId
};
if (userId) {
query.authorId = new ObjectId(userId);
}
if (tag) {
query.tags = {
$in: [tag]
};
}
if (search) {
query.$or = [{
content: {
$regex: search,
$options: 'i'
}
}, {
tags: {
$in: [new RegExp(search, 'i')]
}
}];
}
const db = await getDb();
// Get posts with author info
const posts = await db.collection('feeds').aggregate([{
$match: query
}, {
$sort: {
createdAt: -1
}
}, {
$skip: skip
}, {
$limit: parseInt(limit)
}, {
$lookup: {
from: 'users',
localField: 'authorId',
foreignField: '_id',
as: 'author'
}
}, {
$unwind: {
path: '$author',
preserveNullAndEmptyArrays: true
}
}, {
$project: {
'author.password': 0,
'author.access': 0
}
}]).toArray();
const total = await db.collection('feeds').countDocuments(query);
return res.json({
success: true,
data: posts,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total,
pages: Math.ceil(total / parseInt(limit))
}
});
} catch (error) {
console.error('Error fetching feed:', error);
return res.status(500).json({
success: false,
message: 'Failed to fetch feed'
});
}
});
// Get single post
router.get('/:id', async (req, res) => {
try {
const {
id
} = req.params;
const projectId = req.projectId;
const db = await getDb();
const post = await db.collection('feeds').aggregate([{
$match: {
_id: new ObjectId(id),
projectId
}
}, {
$lookup: {
from: 'users',
localField: 'authorId',
foreignField: '_id',
as: 'author'
}
}, {
$unwind: {
path: '$author',
preserveNullAndEmptyArrays: true
}
}, {
$project: {
'author.password': 0,
'author.access': 0
}
}]).next();
if (!post) {
return res.status(404).json({
success: false,
message: 'Post not found'
});
}
return res.json({
success: true,
data: post
});
} catch (error) {
console.error('Error fetching post:', error);
return res.status(500).json({
success: false,
message: 'Failed to fetch post'
});
}
});
// Update post
router.put('/:id', async (req, res) => {
try {
const {
id
} = req.params;
const {
content,
media,
isPublic,
tags,
mentions
} = req.body;
const projectId = req.projectId;
const userId = req.user.powrId;
const db = await getDb();
const post = await db.collection('feeds').findOne({
_id: new ObjectId(id),
projectId,
authorId: new ObjectId(userId)
});
if (!post) {
return res.status(404).json({
success: false,
message: 'Post not found or unauthorized'
});
}
const updateData = {
updatedAt: new Date()
};
if (content !== undefined) updateData.content = content;
if (media !== undefined) updateData.media = media;
if (isPublic !== undefined) updateData.isPublic = isPublic;
if (tags !== undefined) updateData.tags = tags;
if (mentions !== undefined) updateData.mentions = mentions.map(id => new ObjectId(id));
await db.collection('feeds').updateOne({
_id: new ObjectId(id)
}, {
$set: updateData
});
return res.json({
success: true,
message: 'Post updated successfully'
});
} catch (error) {
console.error('Error updating post:', error);
return res.status(500).json({
success: false,
message: 'Failed to update post'
});
}
});
// Delete post
router.delete('/:id', async (req, res) => {
try {
const {
id
} = req.params;
const projectId = req.projectId;
const userId = req.user.powrId;
const db = await getDb();
const post = await db.collection('feeds').findOne({
_id: new ObjectId(id),
projectId,
authorId: new ObjectId(userId)
});
if (!post) {
return res.status(404).json({
success: false,
message: 'Post not found or unauthorized'
});
}
await db.collection('feeds').deleteOne({
_id: new ObjectId(id)
});
return res.json({
success: true,
message: 'Post deleted successfully'
});
} catch (error) {
console.error('Error deleting post:', error);
return res.status(500).json({
success: false,
message: 'Failed to delete post'
});
}
});
// Like/unlike post
router.post('/:id/like', async (req, res) => {
try {
const {
id
} = req.params;
const {
liked
} = req.body;
const projectId = req.projectId;
const userId = req.user.powrId;
const db = await getDb();
// Update like count
const updateOperation = liked ? {
$inc: {
likesCount: 1
}
} : {
$inc: {
likesCount: -1
}
};
await db.collection('feeds').updateOne({
_id: new ObjectId(id),
projectId
}, updateOperation);
// Update user's like status
await db.collection('likes').updateOne({
userId: new ObjectId(userId),
contentId: id,
projectId
}, {
$set: {
liked
}
}, {
upsert: true
});
return res.json({
success: true,
message: liked ? 'Post liked' : 'Post unliked'
});
} catch (error) {
console.error('Error updating like:', error);
return res.status(500).json({
success: false,
message: 'Failed to update like'
});
}
});
module.exports = router;