From 3ad55cd36a0ca5bf6b33ba124e0a93cade0d7020 Mon Sep 17 00:00:00 2001 From: kajvans Date: Thu, 25 Jan 2024 16:25:03 +0100 Subject: [PATCH] tweaking and adding homepage with trending and so on --- index.js | 9 +++ jobs.js | 150 +++++++++++++++++++++++++++++++++++++++++++++ routes/create.js | 2 +- routes/homepage.js | 94 ++++++++++++++++++++++++++++ routes/posts.js | 3 + routes/register.js | 6 ++ routes/search.js | 43 +++++++++++++ routes/user.js | 46 +++++++++++++- 8 files changed, 351 insertions(+), 2 deletions(-) create mode 100644 jobs.js create mode 100644 routes/homepage.js create mode 100644 routes/search.js diff --git a/index.js b/index.js index fae8ea5..39b889b 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ const dotenv = require('dotenv'); const cors = require('cors'); const {auth} = require('./auth/middleware'); const cookieParser = require('cookie-parser'); +const {updateAll} = require('./jobs/jobs'); dotenv.config(); @@ -15,10 +16,18 @@ app.listen(process.env.PORT || 5000, () => { console.log(`Server is running on port ${process.env.PORT || 5000}`); }); +//run a function every 12 hours +setInterval(() => { + console.log('Updating homepage'); + updateAll(); +}, 43200000); + app.use('/register', require('./routes/register.js')); app.use('/login', require('./routes/login.js')); app.use('/user', require('./routes/user.js')); app.use('/create', auth, require('./routes/create.js')); app.use('/post', require('./routes/posts.js')); +app.use('/search', require('./routes/search.js')); +app.use('/home', require('./routes/homepage.js')); module.exports = app; \ No newline at end of file diff --git a/jobs.js b/jobs.js new file mode 100644 index 0000000..6c1f79f --- /dev/null +++ b/jobs.js @@ -0,0 +1,150 @@ +const db = require('../surreal'); + +async function SetTrending(){ + try{ + const posts = await db.query(`SELECT * FROM posts`); + const trending = []; + for(let i = 0; i < posts.length; i++){ + trending.push(posts[i]); + } + trending.sort((a, b) => { + return b.viewcount - a.viewcount; + }); + const trendingPosts = trending.slice(0, 20); + const trendingPostsDB = await db.query(`UPDATE homepage SET trending = "${trendingPosts}"`); + + if(trendingPostsDB) { + console.log("Trending posts updated"); + return true; + } + else { + console.log("Trending posts not updated"); + return false; + } + } + catch(err){ + console.log(err); + } +} + +async function UpdatePostRanking(){ + try{ + const posts = await db.query(`SELECT * FROM posts`); + //find posts with most likes + const mostLiked = []; + for(let i = 0; i < posts.length; i++){ + mostLiked.push(posts[i]); + } + mostLiked.sort((a, b) => { + return b.likes.length - a.likes.length; + }); + const mostLikedPosts = mostLiked.slice(0, 50); + const mostLikedPostsDB = await db.query(`UPDATE homepage SET mostLiked = "${mostLikedPosts}"`); + + //find posts with most comments + const mostCommented = []; + for(let i = 0; i < posts.length; i++){ + mostCommented.push(posts[i]); + } + mostCommented.sort((a, b) => { + return b.comments.length - a.comments.length; + }); + const mostCommentedPosts = mostCommented.slice(0, 50); + const mostCommentedPostsDB = await db.query(`UPDATE homepage SET mostCommented = "${mostCommentedPosts}"`); + + //find posts with most saves + const mostSaved = []; + for(let i = 0; i < posts.length; i++){ + mostSaved.push(posts[i]); + } + mostSaved.sort((a, b) => { + return b.saves.length - a.saves.length; + }); + const mostSavedPosts = mostSaved.slice(0, 50); + const mostSavedPostsDB = await db.query(`UPDATE homepage SET mostSaved = "${mostSavedPosts}"`); + + if(mostLikedPostsDB && mostCommentedPostsDB && mostSavedPostsDB) { + console.log("Post rankings updated"); + return true; + } + else { + console.log("Post rankings not updated"); + return false; + } + } + catch(err){ + console.log(err); + } +} + +async function UpdateUserRanking(){ + try{ + const users = await db.query(`SELECT activity FROM users`); + + //calculate user activity points do this by looking at activity array and looking at the date of each activity than use formula to calculate points + //then sort users by activity points + //then update homepage with top 20 users + + const MostPopularUsers = []; + + for(i = 0; i < users.length; i++){ + //calculate activity points + let tempPoints = 0; + for(j = 0; j < users[i].activity.length; j++){ + //calculate points + const actionDate = new Date(users[i].activity[j].date); + + const currentDate = new Date(); + + const timeDifference = currentDate - actionDate; + + const timeDifferenceInDays = timeDifference / (1000 * 3600 * 24); + + const points = Math.max(0, 100 - daysAgo); + + tempPoints += points; + } + //update activity points + const user = await db.query(`UPDATE users SET activityPoints = "${tempPoints}" WHERE username = "${users[i].username}"`); + //check if user is has more points than the last user in the array + if(MostPopularUsers.length == 0){ + MostPopularUsers.push(users[i]); + } + else if(MostPopularUsers[MostPopularUsers.length - 1].activityPoints < tempPoints){ + MostPopularUsers.push(users[i]); + } + + //sort array + MostPopularUsers.sort((a, b) => { + return b.activityPoints - a.activityPoints; + }); + + //remove last user in array if array is longer than 100 + if(MostPopularUsers.length > 100){ + MostPopularUsers.pop(); + } + } + + + } + catch(err){ + console.log(err); + } +} + +async function UpdateAll(){ + const trending = await SetTrending(); + const postRanking = await UpdatePostRanking(); + const userRanking = await UpdateUserRanking(); + + if(trending && postRanking && userRanking){ + console.log("All rankings updated"); + return true; + } + else{ + console.log("All rankings not updated"); + return false; + } +} + +module.exports = {SetTrending, UpdatePostRanking, UpdateUserRanking, UpdateAll}; \ No newline at end of file diff --git a/routes/create.js b/routes/create.js index b585e35..60197f8 100644 --- a/routes/create.js +++ b/routes/create.js @@ -19,7 +19,7 @@ router.post('/', async (req, res) => { const formattedDate = currentDate.toLocaleDateString('en-gb'); const date = formattedDateAndTime + " " + formattedDate; - const newPost = await db.create('posts', {category: category, title: title, content: content, author: username, date: date}); + const newPost = await db.create('posts', {category: category, title: title, content: content, author: username, date: date, likes: [], comments: [], saves: [], viewcount: 0}); postId = (newPost[0].id).slice(6); const update = await db.query(`UPDATE users SET posts += "${postId}" WHERE username = string::lowercase("${username}")`) diff --git a/routes/homepage.js b/routes/homepage.js new file mode 100644 index 0000000..ce0bd4e --- /dev/null +++ b/routes/homepage.js @@ -0,0 +1,94 @@ +const db = require('../surreal'); +const router = require('express').Router(); + +router.get('/', async (req, res) => { + try{ + const homepage = await db.query(`SELECT * FROM homepage`); + + if(homepage.length == 0) return res.status(400).json({error: "Homepage does not exist"}); + + const trending = homepage[0].trending; + const mostLiked = homepage[0].mostLiked; + const mostCommented = homepage[0].mostCommented; + const mostSaved = homepage[0].mostSaved; + + const returnData = { + trending: trending, + mostLiked: mostLiked, + mostCommented: mostCommented, + mostSaved: mostSaved + } + + res.status(200).json({returnData}); + } + catch(err){ + console.log(err); + res.status(500).json({error: "Internal server error"}); + } +}); + +router.get('/trending', async (req, res) => { + try{ + const homepage = await db.query(`SELECT * FROM homepage`); + + if(homepage.length == 0) return res.status(400).json({error: "Homepage does not exist"}); + + const trending = homepage[0].trending; + + res.status(200).json({trending}); + } + catch(err){ + console.log(err); + res.status(500).json({error: "Internal server error"}); + } +}); + +router.get('/mostLiked', async (req, res) => { + try{ + const homepage = await db.query(`SELECT * FROM homepage`); + + if(homepage.length == 0) return res.status(400).json({error: "Homepage does not exist"}); + + const mostLiked = homepage[0].mostLiked; + + res.status(200).json({mostLiked}); + } + catch(err){ + console.log(err); + res.status(500).json({error: "Internal server error"}); + } +}); + +router.get('/mostCommented', async (req, res) => { + try{ + const homepage = await db.query(`SELECT * FROM homepage`); + + if(homepage.length == 0) return res.status(400).json({error: "Homepage does not exist"}); + + const mostCommented = homepage[0].mostCommented; + + res.status(200).json({mostCommented}); + } + catch(err){ + console.log(err); + res.status(500).json({error: "Internal server error"}); + } +}); + +router.get('/mostSaved', async (req, res) => { + try{ + const homepage = await db.query(`SELECT * FROM homepage`); + + if(homepage.length == 0) return res.status(400).json({error: "Homepage does not exist"}); + + const mostSaved = homepage[0].mostSaved; + + res.status(200).json({mostSaved}); + } + catch(err){ + console.log(err); + res.status(500).json({error: "Internal server error"}); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/posts.js b/routes/posts.js index b25e3ab..ec30a90 100644 --- a/routes/posts.js +++ b/routes/posts.js @@ -11,6 +11,9 @@ router.get('/:id', async (req, res) => { const post = await db.query(`SELECT * FROM posts WHERE id = "${id}"`); if(post.length == 0) return res.status(400).json({error: "Post does not exist"}); + else { + const viewPost = await db.query(`UPDATE posts SET viewcount += 1 WHERE id = "${postId}"`); + } res.status(200).json({post}); } diff --git a/routes/register.js b/routes/register.js index 6f40339..c2622bd 100644 --- a/routes/register.js +++ b/routes/register.js @@ -42,6 +42,12 @@ router.post('/', async (req, res) => { username: username, password: hashedPassword, creation: currentDate.toLocaleDateString('en-gb'), + likedPosts: [], + savedPosts: [], + posts: [], + comments: [], + activity: [], + activityPoints: 0 } const newUser = await db.create('users', user); diff --git a/routes/search.js b/routes/search.js new file mode 100644 index 0000000..9c51abe --- /dev/null +++ b/routes/search.js @@ -0,0 +1,43 @@ +const db = require('../surreal'); +const router = require('express').Router(); + +router.post('/:search', async (req, res) => { + try{ + const {type, category} = req.body; + const search = req.params.search; + + if (type === 'user') { + const users = await db.query(`SELECT username, array::len(posts) AS posts_len, search::score(1) AS score FROM users WHERE username @1@ '${search}' ORDER BY score DESC;`); + res.status(200).json(users); + } + + else if (type === 'post') { + let query = `SELECT category, title, content, author, date, array::len(likes) AS likes_len, array::len(comments) AS comments_len, array::len(saves) AS saves_len, search::score(1) AS score FROM posts WHERE title @1@ '${search}')`; + if (category) { + //check if category is json array + if(category instanceof Array) { + query += ' AND ('; + for(let i = 0; i < category.length; i++) { + if(i != 0) query += ' OR '; + query += `category = '${category[i]}'`; + } + query += ')'; + } + else query += ` AND category = '${category}'`; + } + console.log(query) + query += ' ORDER BY score DESC;'; + const posts = await db.query(query); + res.status(200).json(posts); + } + + else { + res.status(400).json({error: 'Invalid type'}); + } + } + catch(err){ + res.status(500).json({error: err}); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/user.js b/routes/user.js index 50e81da..005ee46 100644 --- a/routes/user.js +++ b/routes/user.js @@ -23,7 +23,8 @@ router.get('/:username',publicauth, async (req, res) => { likedPosts: user[0].likedPosts, comments: user[0].comments, savedPosts: user[0].savedPosts, - visibility: user[0].visibility + visibility: user[0].visibility, + activity: user[0].activity } res.status(200).json({returnData}); @@ -209,4 +210,47 @@ router.get('/visibility', auth, async (req, res) => { } }); +router.get('/activity/:type', auth, async (req, res) => { + try{ + const type = req.params.type; + const username = req.user; + + if(!type) return res.status(400).json({error: "Missing type"}); + if(!username) return res.status(400).json({error: "Missing username"}); + + const user = await db.query(`SELECT activity FROM users WHERE username = string::lowercase("${username}")`); + + if(user.length == 0) return res.status(400).json({error: "User does not exist"}); + + const activity = user[0].activity; + + if(activity.length > 100){ + //remove oldest activity until length is 100 + while(activity.length > 100 - 1){ + activity.shift(); + } + } + + const currentDate = new Date(); + const formattedDateAndTime = currentDate.toLocaleTimeString('en-gb', { timeStyle: 'short' }); + const formattedDate = currentDate.toLocaleDateString('en-gb'); + const date = formattedDateAndTime + " " + formattedDate; + + const newActivity = { + type: type, + date: date + } + + activity.push(newActivity); + + const newActivityDB = await db.query(`UPDATE users SET activity = "${activity}" WHERE username = string::lowercase("${username}")`); + + res.status(200).json({message: "Activity updated"}); + } + catch(err){ + console.log(err); + res.status(500).json({error: "Internal server error"}); + } +}); + module.exports = router; \ No newline at end of file