Finished implementing sub-community support. Added support for the followed users endpoint. Fixed a number of inconsistencies in different endpoints. Fixed messages sent via the API not storing the correct Mii face URL. General code cleanup.

This commit is contained in:
Jemma Poffinbarger
2023-03-20 21:40:55 -05:00
parent a3799e8a11
commit 71245c41b3
11 changed files with 186 additions and 179 deletions

View File

@@ -1,5 +1,4 @@
const { Schema, model } = require('mongoose');
const moment = require("moment");
const CommunitySchema = new Schema({
platform_id: Number,
@@ -65,6 +64,8 @@ const CommunitySchema = new Schema({
browser_thumbnail: String,
CTR_browser_header: String,
WiiU_browser_header: String,
app_data: String,
app_id: String
});
CommunitySchema.methods.upEmpathy = async function() {

View File

@@ -1,5 +1,5 @@
var express = require('express');
var router = express.Router();
const express = require('express');
const router = express.Router();
const database = require('../../../database');
const comPostGen = require('../../../util/CommunityPostGen');
const processHeaders = require('../../../util/util');
@@ -8,14 +8,14 @@ const processHeaders = require('../../../util/util');
router.get('/', 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 response = await comPostGen.Communities(community);
res.contentType("application/xml");
res.send(response);
} else {
res.status(404);
res.send();
}
if(!community) res.sendStatus(404);
let communities = await database.getSubCommunities(community.community_id);
if(!communities) res.sendStatus(404);
communities.unshift(community);
let response = await comPostGen.Communities(communities);
res.contentType("application/xml");
res.send(response);
});
router.get('/popular', async function (req, res) {
@@ -50,7 +50,6 @@ router.get('/0/posts', async function (req, res) {
posts = await database.getPostsByCommunityKey(community, parseInt(req.query.limit), req.query.search_key);
else
posts = await database.getPostsByCommunity(community, parseInt(req.query.limit));
console.log(posts);
/* Build formatted response and send it off. */
let response;
if(req.query.with_mii === 1)

View File

@@ -1,7 +1,7 @@
var express = require('express');
var xml = require('object-to-xml');
const express = require('express');
const xml = require('object-to-xml');
const database = require('../../../database');
var router = express.Router();
const router = express.Router();
/* GET discovery server. */
router.get('/', async function (req, res) {

View File

@@ -1,16 +1,16 @@
var express = require('express');
var router = express.Router();
const express = require('express');
const router = express.Router();
const moment = require('moment');
var xml = require('object-to-xml');
const xml = require('object-to-xml');
const { POST } = require('../../../models/post');
const { CONVERSATION } = require('../../../models/conversation');
const util = require('../../../util/util');
const database = require('../../../database');
var multer = require('multer');
const multer = require('multer');
const snowflake = require('node-snowflake').Snowflake;
var upload = multer();
const upload = multer();
router.post('/', upload.none(), async function (req, res, next) {
router.post('/', upload.none(), async function (req, res) {
let user = await database.getPNID(req.pid);
let user2 = await database.getPNID(req.body.message_to_pid);
let conversation = await database.getConversationByUsers([user.pid, user2.pid]);
@@ -38,6 +38,27 @@ router.post('/', upload.none(), async function (req, res, next) {
}
if(!conversation)
return res.sendStatus(404);
let miiFace;
switch (parseInt(req.body.feeling_id)) {
case 1:
miiFace = 'smile_open_mouth.png';
break;
case 2:
miiFace = 'wink_left.png';
break;
case 3:
miiFace = 'surprise_open_mouth.png';
break;
case 4:
miiFace = 'frustrated.png';
break;
case 5:
miiFace = 'sorrow.png';
break;
default:
miiFace = 'normal_face.png';
break;
}
let document = {
screen_name: user.mii.name,
body: req.body.body,
@@ -45,7 +66,7 @@ router.post('/', upload.none(), async function (req, res, next) {
created_at: new Date(),
id: snowflake.nextId(),
mii: user.mii.data,
mii_face_url: `https://mii.olv.pretendo.cc/${user.pid}/normal_face.png`,
mii_face_url: `http://mii.olv.pretendo.cc/mii/${PNID.pid}/${miiFace}`,
pid: user.pid,
verified: (user.access_level === 2 || user.access_level === 3),
parent: null,
@@ -68,10 +89,9 @@ router.post('/', upload.none(), async function (req, res, next) {
await conversation.newMessage(postPreviewText, document.message_to_pid);
});
router.get('/', async function(req, res, next) {
let limit = parseInt(req.query.limit), type = req.query.type, search_key = req.query.search_key, by = req.query.by;
router.get('/', async function(req, res) {
let limit = parseInt(req.query.limit), search_key = req.query.search_key;
let posts = await database.getFriendMessages(req.pid, search_key, limit);
console.log(posts)
posts = posts.length === 0 ? " " : posts
let postBody = [];
for(let post of posts) {
@@ -117,7 +137,7 @@ router.get('/', async function(req, res, next) {
return res.send("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xml(response));
});
router.post('/:post_id/empathies', upload.none(), async function (req, res, next) {
router.post('/:post_id/empathies', upload.none(), async function (req, res) {
let pid = util.data.processServiceToken(req.headers["x-nintendo-servicetoken"]);
const post = await database.getPostByID(req.params.post_id);
if(pid === null) {

View File

@@ -1,8 +1,7 @@
var express = require('express');
var router = express.Router();
const express = require('express');
const router = express.Router();
const database = require('../../../database');
const pplPostGen = require('../../../util/peoplePostGen');
const processHeaders = require('../../../util/util');
/* GET post titles. */
router.get('/', async function (req, res) {
@@ -31,4 +30,12 @@ router.get('/', async function (req, res) {
}
});
router.get('/:pid/following', async function (req, res) {
let user = await database.getUserContent(req.params.pid);
if(!user) res.sendStatus(404);
let people = await database.getFollowedUsers(user);
if(!people) res.sendStatus(404);
res.send(await pplPostGen.People(people));
});
module.exports = router;

View File

@@ -1,12 +1,12 @@
var express = require('express');
var router = express.Router();
const express = require('express');
const router = express.Router();
const database = require('../../../database');
router.get('/', async function(req, res, next) {
router.get('/', async function(req, res) {
res.send('Pong!');
});
router.get('/database', async function(req, res, next) {
router.get('/database', async function(req, res) {
let document = await database.getEndpoints();
if(document)
res.send('DB Connection Working! :D');

View File

@@ -1,97 +1,91 @@
var express = require('express');
var router = express.Router();
const moment = require('moment');
var xml = require('object-to-xml');
const express = require('express');
const router = express.Router();
const xml = require('object-to-xml');
const { POST } = require('../../../models/post');
const util = require('../../../util/util');
const database = require('../../../database');
var multer = require('multer');
const multer = require('multer');
const snowflake = require('node-snowflake').Snowflake;
var upload = multer();
const communityPostGen = require('../../../util/CommunityPostGen');
const upload = multer();
/* GET post titles. */
router.post('/', upload.none(), async function (req, res, next) {
try
{
let PNID = await database.getPNID(req.pid), userSettings = await database.getUserSettings(req.pid), parentPost = null, postID = snowflake.nextId();
let paramPackData = util.data.decodeParamPack(req.headers["x-nintendo-parampack"]);
let community = await database.getCommunityByTitleID(paramPackData.title_id)
if(userSettings.account_status !== 0 || community.community_id === 'announcements')
throw new Error('User not allowed to post')
let appData = "", painting = "", paintingURI = "", screenshot = null;
if (req.body.app_data)
appData = req.body.app_data.replace(/\0/g, "").trim();
if (req.body.painting && req.body.painting !== 'eJztwTEBACAMA7DCNRlIQRbu4ZoEviTJTNvjZNUFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL55fYLL3w==') {
painting = req.body.painting.replace(/\0/g, "").trim();
paintingURI = await util.data.processPainting(painting, true);
await util.data.uploadCDNAsset('pn-cdn', `paintings/${req.pid}/${postID}.png`, paintingURI, 'public-read');
}
if (req.body.screenshot) {
screenshot = req.body.screenshot.replace(/\0/g, "").trim();
await util.data.uploadCDNAsset('pn-cdn', `screenshots/${req.pid}/${postID}.jpg`, Buffer.from(screenshot, 'base64'), 'public-read');
}
let miiFace;
switch (parseInt(req.body.feeling_id)) {
case 1:
miiFace = 'smile_open_mouth.png';
break;
case 2:
miiFace = 'wink_left.png';
break;
case 3:
miiFace = 'surprise_open_mouth.png';
break;
case 4:
miiFace = 'frustrated.png';
break;
case 5:
miiFace = 'sorrow.png';
break;
default:
miiFace = 'normal_face.png';
break;
}
let body = req.body.body;
if(body)
body = req.body.body.replace(/[^A-Za-z\d\s-_!@#$%^&*(){}‛¨ƒºª«»“”„¿¡←→↑↓√§¶†‡¦–—⇒⇔¤¢€£¥™©®+×÷=±∞ˇ˘˙¸˛˜′″µ°¹²³♭♪•…¬¯‰¼½¾♡♥●◆■▲▼☆★♀♂,./?;:'"\[\]]/g, "");
if(body && body.length > 280)
body = body.substring(0,280);
const document = {
title_id: paramPackData.title_id,
community_id: community.community_id,
screen_name: userSettings.screen_name,
body: body,
app_data: appData,
painting: painting,
screenshot: screenshot ? `/screenshots/${req.pid}/${postID}.jpg`: "",
country_id: paramPackData.country_id,
created_at: new Date(),
feeling_id: req.body.emotion,
id: postID,
search_key: req.body.search_key,
is_autopost: req.body.is_autopost,
is_spoiler: (req.body.spoiler) ? 1 : 0,
is_app_jumpable: req.body.is_app_jumpable,
language_id: req.body.language_id,
mii: PNID.mii.data,
mii_face_url: `http://mii.olv.pretendo.cc/mii/${PNID.pid}/${miiFace}`,
pid: req.pid,
platform_id: paramPackData.platform_id,
region_id: paramPackData.region_id,
verified: (PNID.access_level === 2 || PNID.access_level === 3),
parent: null
};
const newPost = new POST(document);
newPost.save();
res.sendStatus(200);
router.post('/', upload.none(), async function (req, res) {
let PNID = await database.getPNID(req.pid), userSettings = await database.getUserSettings(req.pid), postID = snowflake.nextId();
let paramPackData = util.data.decodeParamPack(req.headers["x-nintendo-parampack"]);
let community = await database.getCommunityByTitleID(paramPackData.title_id)
if(!community || userSettings.account_status !== 0 || community.community_id === 'announcements')
return res.sendStatus(403);
let appData = "", painting = "", paintingURI = "", screenshot = null;
if (req.body.app_data)
appData = req.body.app_data.replace(/\0/g, "").trim();
if (req.body._post_type === 'painting' && req.body.painting) {
painting = req.body.painting.replace(/\0/g, "").trim();
paintingURI = await util.data.processPainting(painting, true);
await util.data.uploadCDNAsset('pn-cdn', `paintings/${req.pid}/${postID}.png`, paintingURI, 'public-read');
}
catch (e)
{
console.error(e);
if (req.body.screenshot) {
screenshot = req.body.screenshot.replace(/\0/g, "").trim();
await util.data.uploadCDNAsset('pn-cdn', `screenshots/${req.pid}/${postID}.jpg`, Buffer.from(screenshot, 'base64'), 'public-read');
}
let miiFace;
switch (parseInt(req.body.feeling_id)) {
case 1:
miiFace = 'smile_open_mouth.png';
break;
case 2:
miiFace = 'wink_left.png';
break;
case 3:
miiFace = 'surprise_open_mouth.png';
break;
case 4:
miiFace = 'frustrated.png';
break;
case 5:
miiFace = 'sorrow.png';
break;
default:
miiFace = 'normal_face.png';
break;
}
let body = req.body.body;
if(body)
body = req.body.body.replace(/[^A-Za-z\d\s-_!@#$%^&*(){}‛¨ƒºª«»“”„¿¡←→↑↓√§¶†‡¦–—⇒⇔¤¢€£¥™©®+×÷=±∞ˇ˘˙¸˛˜′″µ°¹²³♭♪•…¬¯‰¼½¾♡♥●◆■▲▼☆★♀♂,./?;:'"\\<>]/g, "");
if(body.length > 280)
body = body.substring(0,280);
const document = {
title_id: paramPackData.title_id,
community_id: community.community_id,
screen_name: userSettings.screen_name,
body: body,
app_data: appData,
painting: painting,
screenshot: screenshot ? `/screenshots/${req.pid}/${postID}.jpg`: "",
country_id: paramPackData.country_id,
created_at: new Date(),
feeling_id: req.body.feeling_id,
id: postID,
search_key: req.body.search_key,
is_autopost: req.body.is_autopost,
is_spoiler: (req.body.spoiler) ? 1 : 0,
is_app_jumpable: req.body.is_app_jumpable,
language_id: req.body.language_id,
mii: PNID.mii.data,
mii_face_url: `http://mii.olv.pretendo.cc/mii/${PNID.pid}/${miiFace}`,
pid: req.pid,
platform_id: paramPackData.platform_id,
region_id: paramPackData.region_id,
verified: (PNID.access_level === 2 || PNID.access_level === 3),
parent: null,
removed: false
};
let duplicatePost = await database.getDuplicatePosts(req.pid, document);
if(duplicatePost || document.body === '' && document.painting === '' && document.screenshot === '') {
res.set("Content-Type", "application/xml");
res.statusCode = 400;
response = {
let response = {
result: {
has_error: 1,
version: 1,
@@ -100,11 +94,14 @@ router.post('/', upload.none(), async function (req, res, next) {
message: "POSTING_FROM_NNID"
}
};
res.send("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xml(response));
return res.send("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xml(response));
}
const newPost = new POST(document);
newPost.save();
res.send(await communityPostGen.SinglePostResponse(newPost));
});
router.post('/:post_id/empathies', upload.none(), async function (req, res, next) {
router.post('/:post_id/empathies', upload.none(), async function (req, res) {
let pid = util.data.processServiceToken(req.headers["x-nintendo-servicetoken"]);
const post = await database.getPostByID(req.params.post_id);
if(pid === null) {

View File

@@ -1,10 +1,7 @@
var express = require('express');
var router = express.Router();
const express = require('express');
const router = express.Router();
const database = require('../../../database');
const comPostGen = require('../../../util/CommunityPostGen');
const processHeaders = require('../../../util/util');
const xmlbuilder = require("xmlbuilder");
const moment = require("moment");
/* GET post titles. */
router.get('/', async function (req, res) {

View File

@@ -1,16 +1,8 @@
var express = require('express');
var router = express.Router();
const moment = require('moment');
var xml = require('object-to-xml');
const { POST } = require('../../../models/post');
const { CONVERSATION } = require('../../../models/conversation');
const util = require('../../../util/util');
const database = require('../../../database');
var multer = require('multer');
const snowflake = require('node-snowflake').Snowflake;
var upload = multer();
const express = require('express');
const router = express.Router();
const xml = require('object-to-xml');
router.get('/:pid/notifications', async function(req, res, next) {
router.get('/:pid/notifications', async function(req, res) {
let type = req.query.type, title_id = req.query.title_id;
console.log(type);
console.log(title_id);

View File

@@ -5,7 +5,7 @@ const database = require('../database');
class CommunityPostGen {
/* TODO lots of stubs and constants in here */
static async PostsResponse(posts, community) {
let xml = xmlbuilder.create("result")
let xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up()
.e("request_name", "posts").up()
@@ -50,7 +50,7 @@ class CommunityPostGen {
}
static async PostsResponseWithMii(posts, community) {
let xml = xmlbuilder.create("result")
let xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up()
.e("request_name", "posts").up()
@@ -97,57 +97,36 @@ class CommunityPostGen {
}
static async EmptyResponse() {
const xml = xmlbuilder.create("result")
const xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up();
return xml.end({ pretty: true, allowEmpty: true });
}
static async Communities(community) {
const xml = xmlbuilder.create("result")
static async Communities(communities) {
let xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up()
.e("request_name", "communities").up()
.e("communities")
.e("community")
.e('olive_community_id', community.community_id).up()
.e('community_id', community.community_id).up()
.e("name", community.name).up()
.e("description", community.description).up()
.e("icon").up()
.e("icon_3ds").up()
.e("pid").up()
.e("app_data").up()
.e("is_user_community", 0).up()
.e("communities");
for(let community of communities) {
xml = xml.e("community")
.e('olive_community_id', community.community_id.padStart(20, '0')).up()
.e('community_id', community.app_id.padStart(6, '0')).up()
.e("name", community.name).up()
.e("description", community.description).up()
.e("icon").up()
.e("icon_3ds").up()
.e("pid").up()
.e("app_data", community.app_data).up()
.e("is_user_community", 0).up()
.up()
.e("community")
.e('olive_community_id', community.community_id + 100).up()
.e('community_id', community.community_id + 100).up()
.e("name", community.name + '- Nintendo Levels').up()
.e("description", community.description).up()
.e("icon").up()
.e("icon_3ds").up()
.e("pid").up()
.e("app_data", 'TVZNSQI').up()
.e("is_user_community", 0).up()
.up()
.e("community")
.e('olive_community_id', community.community_id + 200).up()
.e('community_id', community.community_id + 200).up()
.e("name", community.name + '- User Levels').up()
.e("description", community.description).up()
.e("icon").up()
.e("icon_3ds").up()
.e("pid").up()
.e("app_data", 'TVZNSQE').up()
.e("is_user_community", 0).up()
.up()
.up();
return xml.end({ pretty: true, allowEmpty: true });
}
return xml.up().end({ pretty: true, allowEmpty: true});
}
/* TODO Again, some constants */
static async SinglePostResponse(post) {
let xml = xmlbuilder.create("result")
let xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up()
.e("post");
@@ -187,7 +166,7 @@ class CommunityPostGen {
static async topics(communities) {
const expirationDate = moment().add(1, 'days');
let xml = xmlbuilder.create("result")
let xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up()
.e("request_name", "topics").up()

View File

@@ -143,6 +143,21 @@ class CommunityPostGen {
.up();
return xml.end({ pretty: true, allowEmpty: true });
}
static async People(people) {
let xml = xmlbuilder.create("result", { encoding: 'UTF-8' })
.e("has_error", "0").up()
.e("version", "1").up()
.e("request_name", "user_infos").up()
.e("people");
for(let person of people) {
xml = xml.e("person")
.e('pid', person.pid).up()
.e('screen_name', person.screen_name).up()
.up()
}
return xml.up().end({ pretty: true, allowEmpty: true});
}
}
if (typeof module !== "undefined") {