forked from kaverti/website
189 lines
5.5 KiB
JavaScript
189 lines
5.5 KiB
JavaScript
const { Op } = require("sequelize");
|
|
|
|
let express = require('express')
|
|
let router = express.Router()
|
|
const auth = require('../lib/auth')
|
|
|
|
let { Post, Ban, Team, Thread, User, Category, Sequelize } = require('../models')
|
|
const Errors = require('../lib/errors')
|
|
const { setRandomFallback } = require('bcryptjs')
|
|
|
|
router.get('/thread', async(req, res, next) => {
|
|
try {
|
|
let searchString = req.query.q.trim()
|
|
|
|
if(searchString.length < 2) {
|
|
throw Errors.sequelizeValidation(Sequelize, {
|
|
error: 'search string must be at least 2 characters',
|
|
value: searchString
|
|
})
|
|
}
|
|
|
|
//Offset is really the previously lowest id
|
|
//(as a proxy for oldest thread of the previous search)
|
|
//if there is no offset, just use a clause that will always be true
|
|
//i.e. greater than 0 id
|
|
let offset = +req.query.offset ? { $lt: +req.query.offset } : { $gt: 0 }
|
|
let limit = 10
|
|
|
|
/*
|
|
Task is to find threads that either have the
|
|
string in the title or in the content of the first post
|
|
|
|
Method
|
|
1) Select first n items from each group (posts and threads), where n is the LIMIT,
|
|
greater than id x, where x is previous OFFSET
|
|
2) Merge results from both, remove duplicates and sort
|
|
3) Select first n items from merged group
|
|
4) Set x as the last item from merged group
|
|
*/
|
|
|
|
let threadTitles = await Thread.findAll({
|
|
where: {
|
|
name: { [Op.like]: '%' + searchString + '%' },
|
|
id: offset
|
|
},
|
|
order: [ ['id', 'DESC'] ],
|
|
include: [
|
|
{
|
|
model: Post,
|
|
include: [{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode', 'cookieOptOut', 'deleteCode', 'jwtOffset']} }],
|
|
where: {
|
|
postNumber: 0
|
|
}
|
|
},
|
|
{ model: Category },
|
|
{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode', 'cookieOptOut', 'deleteCode', 'jwtOffset'] } }
|
|
],
|
|
limit
|
|
})
|
|
|
|
let threadPosts = await Thread.findAll({
|
|
where: {
|
|
id: offset
|
|
},
|
|
order: [ ['id', 'DESC'] ],
|
|
include: [
|
|
{
|
|
model: Post,
|
|
include: [{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode', 'cookieOptOut', 'deleteCode', 'jwtOffset'] } }],
|
|
where: {
|
|
postNumber: 0,
|
|
plainText: { [Op.like]: '%' + searchString + '%' }
|
|
}
|
|
},
|
|
{ model: Category },
|
|
{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode', 'cookieOptOut', 'deleteCode', 'jwtOffset'] } }
|
|
],
|
|
limit
|
|
})
|
|
|
|
let merged = [...threadTitles, ...threadPosts];
|
|
let unique = [];
|
|
merged.forEach(thread => {
|
|
let includes = unique.filter(u => thread.id === u.id);
|
|
|
|
if(!includes.length) unique.push(thread);
|
|
});
|
|
|
|
let sorted = unique
|
|
.sort((a, b) => {
|
|
return b.id - a.id;
|
|
})
|
|
.slice(0, limit);
|
|
|
|
//To get latest post, find threads where
|
|
//the post number is equal to the overal posts count
|
|
//and the post number > 0 (i.e. there are replies)
|
|
let whereClause = sorted.reduce((arr, thread) => {
|
|
if(thread.postsCount > 1) {
|
|
let clause = {
|
|
$and: {
|
|
ThreadId: thread.id,
|
|
postNumber: thread.postsCount-1
|
|
}
|
|
}
|
|
|
|
return [...arr, clause];
|
|
} else {
|
|
return arr;
|
|
}
|
|
}, []);
|
|
|
|
let latestPosts = await Post.findAll({
|
|
where: {
|
|
[Op.or]: whereClause
|
|
},
|
|
order: [ ['ThreadId', 'DESC'] ],
|
|
include: [{ model: User, attributes: { exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode', 'cookieOptOut', 'deleteCode', 'jwtOffset'] } }]
|
|
})
|
|
|
|
//Merge latest posts with threads array
|
|
let ret = sorted.map(thread => {
|
|
if(thread.postsCount > 1) {
|
|
let post = latestPosts.filter(p => p.ThreadId === thread.id)[0];
|
|
thread.Posts.push(post);
|
|
}
|
|
|
|
return thread;
|
|
})
|
|
|
|
res.json({
|
|
threads: ret,
|
|
offset: ret.length ? ret.slice(-1)[0].id : null,
|
|
next: ret.length < limit ? null : limit
|
|
})
|
|
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/user', async(req, res, next) => {
|
|
try {
|
|
let searchString = req.query.q
|
|
let offset = +req.query.offset || 0
|
|
let limit = 10
|
|
let users = await User.findAll({
|
|
where: {
|
|
username: { [Op.like]: '%' + searchString + '%' }
|
|
},
|
|
order: [ ['username', 'DESC'] ],
|
|
attributes: {exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode', 'cookieOptOut', 'deleteCode', 'jwtOffset']},
|
|
limit,
|
|
offset
|
|
})
|
|
|
|
res.json({
|
|
users,
|
|
offset: users.length < limit ? null : offset + limit,
|
|
next: users.length < limit ? null : limit
|
|
})
|
|
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/team', async(req, res, next) => {
|
|
try {
|
|
let searchString = req.query.q
|
|
let offset = +req.query.offset || 0
|
|
let limit = 10
|
|
let teams = await Team.findAll({
|
|
where: {
|
|
username: { [Op.like]: '%' + searchString + '%' }
|
|
},
|
|
order: [ ['username', 'DESC'] ],
|
|
attributes: {exclude: ['banReason']},
|
|
limit,
|
|
offset
|
|
})
|
|
|
|
res.json({
|
|
teams,
|
|
offset: teams.length < limit ? null : offset + limit,
|
|
next: teams.length < limit ? null : limit
|
|
})
|
|
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
module.exports = router
|