Fixed bugs in some xml responses for communities and posts. Added support for /v1/people endpoints. Added support for more search queries in posts requests. Fixed country_id not being stored in posts

This commit is contained in:
Jemma Poffinbarger
2023-04-05 22:41:08 -05:00
parent 0bab90ed09
commit 1d64d7621f
5 changed files with 123 additions and 57 deletions

View File

@@ -43,6 +43,10 @@ const PostSchema = new Schema({
type: Number,
default: 0
},
country_id: {
type: Number,
default: 49
},
language_id: {
type: Number,
default: 1

View File

@@ -36,27 +36,6 @@ router.get('/new', async function (req, res) {
} else res.sendStatus(404);
});
router.get('/0/posts', async function (req, res) {
const paramPack = processHeaders.data.decodeParamPack(req.headers["x-nintendo-parampack"]);
let community = await database.getCommunityByTitleID(paramPack.title_id);
if(community != null)
{
let posts;
if(req.query.search_key)
posts = await database.getPostsByCommunityKey(community, parseInt(req.query.limit), req.query.search_key);
else
posts = await database.getPostsByCommunity(community, parseInt(req.query.limit));
/* Build formatted response and send it off. */
let options = {
name: 'posts',
with_mii: req.query.with_mii === 1
}
res.contentType("application/xml");
res.send(await comPostGen.PostsResponse(posts, community, options));
}
else res.sendStatus(404);
});
router.get('/:appID/posts', async function (req, res) {
const paramPack = processHeaders.data.decodeParamPack(req.headers["x-nintendo-parampack"]);
let community = await COMMUNITY.findOne({ app_id: req.params.appID });
@@ -67,20 +46,35 @@ router.get('/:appID/posts', async function (req, res) {
let query = {
community_id: community.app_id ? community.app_id : community.community_id,
removed: false,
app_data: { $ne: null }
app_data: { $ne: null },
message_to_pid: { $eq: null }
}
if(req.query.search_key)
query.search_key = search_key;
query.search_key = req.query.search_key;
if(!req.query.allow_spoiler)
query.is_spoiler = 0;
if(req.query.by === 'followings') {
let userContent = await database.getUserContent(req.pid);
query.pid = userContent.following_users;
}
let posts = await POST.find(query).sort({ created_at: -1}).limit(parseInt(req.query.limit));
let posts;
if(req.query.distinct_pid === '1')
posts = await POST.aggregate([
{ $match: query }, // filter based on input query
{ $sort: { created_at: -1 } }, // sort by 'created_at' in descending order
{ $group: { _id: '$pid', doc: { $first: '$$ROOT' } } }, // remove any duplicate 'pid' elements
{ $replaceRoot: { newRoot: '$doc' } }, // replace the root with the 'doc' field
{ $limit: (req.query.limit ? Number(req.query.limit) : 10) } // only return the top 8 results
]);
else
posts = await POST.find(query).sort({ created_at: -1}).limit(parseInt(req.query.limit));
/* Build formatted response and send it off. */
let options = {
name: 'posts',
with_mii: req.query.with_mii === 1
with_mii: req.query.with_mii === '1'
}
res.contentType("application/xml");
res.send(await comPostGen.PostsResponse(posts, community, options));

View File

@@ -2,31 +2,51 @@ const express = require('express');
const router = express.Router();
const database = require('../../../database');
const xmlGenerator = require('../../../util/xmlResponseGenerator');
const processHeaders = require("../../../util/util");
const {COMMUNITY} = require("../../../models/communities");
const {POST} = require("../../../models/post");
const comPostGen = require("../../../util/xmlResponseGenerator");
/* GET post titles. */
router.get('/', async function (req, res) {
let community = await database.getCommunityByTitleID(1407375153321472);
if(community != null)
{
let posts;
if(req.query.search_key)
posts = await database.getPostsByCommunityKey(community, parseInt(req.query.limit), req.query.search_key);
else
posts = await database.getPostsByCommunity(community, parseInt(req.query.limit));
let userContent = await database.getUserContent(req.pid);
/* Build formatted response and send it off. */
let options = {
name: 'people',
with_mii: req.query.with_mii === 1
}
res.contentType("application/xml");
res.send(await xmlGenerator.PostsResponse(posts, community, options));
let query = {
removed: false,
app_data: { $eq: null },
message_to_pid: { $eq: null }
}
if(req.query.relation === 'friend') {
query.pid = { $in: userContent.following_users.map(i=>Number(i)) };
}
else if(req.query.relation === 'following') {
query.pid = { $in: userContent.followed_users.map(i=>Number(i)) };
}
else if(req.query.pid) {
query.pid = { $in: req.query.pid.map(i=>Number(i)) }
}
let posts;
if(req.query.distinct_pid === '1')
posts = await POST.aggregate([
{ $match: query }, // filter based on input query
{ $sort: { created_at: -1 } }, // sort by 'created_at' in descending order
{ $group: { _id: '$pid', doc: { $first: '$$ROOT' } } }, // remove any duplicate 'pid' elements
{ $replaceRoot: { newRoot: '$doc' } }, // replace the root with the 'doc' field
{ $limit: (req.query.limit ? Number(req.query.limit) : 10) } // only return the top 8 results
]);
else if(req.query.is_hot === '1')
posts = await POST.find(query).sort({ empathy_count: -1}).limit(parseInt(req.query.limit));
else
{
res.status(404);
res.send();
posts = await POST.find(query).sort({ created_at: -1}).limit(parseInt(req.query.limit));
/* Build formatted response and send it off. */
let options = {
name: 'posts',
with_mii: req.query.with_mii === '1'
}
res.contentType("application/xml");
res.send(await comPostGen.People(posts, options));
});
router.get('/:pid/following', async function (req, res) {
@@ -34,7 +54,7 @@ router.get('/:pid/following', async function (req, res) {
if(!user) res.sendStatus(404);
let people = await database.getFollowedUsers(user);
if(!people) res.sendStatus(404);
res.send(await xmlGenerator.People(people));
res.send(await xmlGenerator.Following(people));
});
module.exports = router;

View File

@@ -35,15 +35,38 @@ router.post('/:post_id/empathies', upload.none(), async function (req, res) {
res.sendStatus(403);
return;
}
let user = await database.getUserContent(pid);
if(user.likes.indexOf(post.id) === -1 && user.id !== post.pid)
let userContent = await database.getUserContent(req.pid);
if(userContent.likes.indexOf(post.id) === -1 && userContent.pid !== post.pid)
{
post.upEmpathy();
user.addToLikes(post.id)
res.sendStatus(200);
if(post.empathy_count < 0) {
await POST.updateOne(
{ id: post.id },
{ $set: { empathy_count: 1 } }
);
}
else {
await POST.updateOne(
{ id: post.id },
{ $inc: { empathy_count: 1 } }
);
}
userContent.addToLikes(post.id);
} else if(userContent.likes.indexOf(post.id) !== -1 && userContent.pid !== post.pid) {
if(post.empathy_count < 0) {
await POST.updateOne(
{ id: post.id },
{ $set: { empathy_count: 0 } }
);
}
else {
await POST.updateOne(
{ id: post.id },
{ $inc: { empathy_count: -1 } }
);
}
userContent.removeFromLike(post.id);
}
else
res.sendStatus(200);
res.sendStatus(200);
});
router.get('/:post_id/replies', async function (req, res) {

View File

@@ -163,12 +163,12 @@ class XmlResponseGenerator {
}
/**
* Generate response to /v1/people
* Generate response to /v1/users/:pid/following
* @param people
* @returns xml
* @constructor
*/
static async People(people) {
static async Following(people) {
let xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up()
@@ -182,6 +182,31 @@ class XmlResponseGenerator {
}
return xml.up().end({ pretty: true, allowEmpty: true});
}
/**
* Generate response to /v1/people
* @param posts
* @param options
* @returns xml
* @constructor
*/
static async People(posts, options) {
const expirationDate = moment().add(1, 'days');
let xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up()
.e("expire", expirationDate.format('YYYY-MM-DD HH:MM:SS')).up()
.e("request_name", options.name).up()
.e("people");
for (const post of posts) {
xml = xml.e("person")
.e("posts")
postObj(xml, post, options);
xml = xml.up().up();
}
xml = xml.up();
return xml.end({ pretty: true, allowEmpty: true });
}
}
/**
@@ -197,8 +222,8 @@ function postObj(xml, post, options) {
}
xml.e("body", post.body ? post.body.replace(/[^A-Za-z\d\s-_!@#$%^&*(){}+=,.<>/?;:'"\[\]]/g, "") : "").up()
.e("community_id", post.community_id).up()
.e("country_id", post.country_id).up()
.e("created_at", post.created_at).up()
.e("country_id", post.country_id ? post.country_id : 254).up()
.e("created_at", new moment(post.created_at).format('YYYY-MM-DD HH:MM:SS')).up()
.e("feeling_id", post.feeling_id).up()
.e("id", post.id).up()
.e("is_autopost", post.is_autopost).up()
@@ -207,7 +232,7 @@ function postObj(xml, post, options) {
.e("is_app_jumpable", post.is_app_jumpable).up()
.e("empathy_count", post.empathy_count).up()
.e("language_id", post.language_id).up();
if(post.mii && options.with_mii) {
if(options.with_mii) {
xml.e("mii", post.mii.replace(/[^A-Za-z0-9+/=]/g, "").replace(/[\n\r]+/gm, '').trim()).up()
.e("mii_face_url", post.mii_face_url).up()
}
@@ -215,7 +240,7 @@ function postObj(xml, post, options) {
if (post.painting) {
xml.e("painting")
.e("format", "tga").up()
.e("content", post.painting.replace(/\r?\n|\r/g, "").trim()).up()
.e("content", post.painting.replace(/[\n\r]+/gm, '').trim()).up()
.e("size", post.painting.length).up()
.e("url", `https://pretendo-cdn.b-cdn.net/paintings/${post.pid}/${post.id}.png`).up()
.up();