diff --git a/src/models/communities.js b/src/models/communities.js index a911486..ddb24a0 100644 --- a/src/models/communities.js +++ b/src/models/communities.js @@ -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() { diff --git a/src/services/miiverse-api/routes/communities.js b/src/services/miiverse-api/routes/communities.js index cbd69ed..c0e94e3 100644 --- a/src/services/miiverse-api/routes/communities.js +++ b/src/services/miiverse-api/routes/communities.js @@ -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) diff --git a/src/services/miiverse-api/routes/discovery.js b/src/services/miiverse-api/routes/discovery.js index 2566052..f0be50c 100644 --- a/src/services/miiverse-api/routes/discovery.js +++ b/src/services/miiverse-api/routes/discovery.js @@ -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) { diff --git a/src/services/miiverse-api/routes/message.js b/src/services/miiverse-api/routes/message.js index 644e48d..3c05d91 100644 --- a/src/services/miiverse-api/routes/message.js +++ b/src/services/miiverse-api/routes/message.js @@ -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("\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) { diff --git a/src/services/miiverse-api/routes/people.js b/src/services/miiverse-api/routes/people.js index e66dc4d..7c0b5d7 100644 --- a/src/services/miiverse-api/routes/people.js +++ b/src/services/miiverse-api/routes/people.js @@ -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; diff --git a/src/services/miiverse-api/routes/ping.js b/src/services/miiverse-api/routes/ping.js index 46b11f6..9c425f8 100644 --- a/src/services/miiverse-api/routes/ping.js +++ b/src/services/miiverse-api/routes/ping.js @@ -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'); diff --git a/src/services/miiverse-api/routes/post.js b/src/services/miiverse-api/routes/post.js index 58b13b9..14569c8 100644 --- a/src/services/miiverse-api/routes/post.js +++ b/src/services/miiverse-api/routes/post.js @@ -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("\n" + xml(response)); + return res.send("\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) { diff --git a/src/services/miiverse-api/routes/topics.js b/src/services/miiverse-api/routes/topics.js index 2db8f6f..e6fb6ec 100644 --- a/src/services/miiverse-api/routes/topics.js +++ b/src/services/miiverse-api/routes/topics.js @@ -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) { diff --git a/src/services/miiverse-api/routes/users.js b/src/services/miiverse-api/routes/users.js index 4227866..e938d65 100644 --- a/src/services/miiverse-api/routes/users.js +++ b/src/services/miiverse-api/routes/users.js @@ -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); diff --git a/src/util/CommunityPostGen.js b/src/util/CommunityPostGen.js index b24837a..5149ad4 100644 --- a/src/util/CommunityPostGen.js +++ b/src/util/CommunityPostGen.js @@ -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() diff --git a/src/util/peoplePostGen.js b/src/util/peoplePostGen.js index 6ce90b0..ecb6777 100644 --- a/src/util/peoplePostGen.js +++ b/src/util/peoplePostGen.js @@ -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") {