ecliptica/server/routers/coder/controllers.js

425 lines
9.9 KiB
JavaScript

const { getDB } = require('../../utils/mongo')
let db = null
// Database Name
const dbName = 'coder'
// Collections constant
const TOPIC_TAGS_COLLECTION = 'topic-tags'
const TOPIC_CATEGORIES_COLLECTION = 'topic-categories'
const TOPIC_LIST_COLLECTION = 'topic-list'
const TOPIC_COMMENTS_COLLECTION = 'topic-comments'
const USERS_COLLECTION = 'users'
// page size
const PAGE_SIZE = 2
// TODO убрать из export?
const connect = async () => {
db = await getDB(dbName)
}
const getCategories = async () => {
// TODO при первом запросе db = null
if (db === null) {
throw new Error('no db connection')
}
const collection = db.collection(TOPIC_CATEGORIES_COLLECTION)
const categories = await collection.find({
}).project({
_id: 0,
}).toArray()
if (categories.length === 0) {
const newCategories = require('./forum/categories.json').body
collection.insertMany(newCategories)
return newCategories
}
return categories
}
const getCategoryByPath = async (path) => {
if (db === null) {
throw new Error('no db connection')
}
const collection = db.collection(TOPIC_CATEGORIES_COLLECTION)
const category = await collection.findOne({
path,
}, {
projection: {
_id: 0,
},
})
if (!category) {
throw new Error('No data')
}
return category
}
const getTopicById = async (id) => {
if (db === null) {
throw new Error('no db connection')
}
const topicsCollection = db.collection(TOPIC_LIST_COLLECTION)
const topic = await topicsCollection
.aggregate([
{
$match: {
id: Number(id),
},
},
{
$limit: 1,
},
{
$lookup: {
from: USERS_COLLECTION, localField: 'authorId', foreignField: 'id', as: 'author',
},
},
{
$unwind: '$author',
},
{
$lookup: {
from: TOPIC_TAGS_COLLECTION, localField: 'tagsId', foreignField: 'id', as: 'tags',
},
},
{
$project: {
id: 0,
categoryId: 0,
authorId: 0,
tagsId: 0,
'author.id': 0,
'author._id': 0,
'tags.id': 0,
'tags._id': 0,
_id: 0,
},
},
])
.toArray()
if (topic.length === 0) {
throw new Error('No data')
}
return topic[0]
}
const getCommentsByTopicId = async (id, page) => {
if (db === null) {
throw new Error('no db connection')
}
if (page === undefined) {
page = 1
}
const commentsCollection = db.collection(TOPIC_COMMENTS_COLLECTION)
let count = await commentsCollection.count({
}, {
limit: 1,
})
if (count === 0) {
const newComments = require('./forum/topic-comments.json').body
commentsCollection.insertMany(newComments)
}
const comments = await commentsCollection
.aggregate([
{
$match: {
topicId: Number(id),
},
},
{
$skip: PAGE_SIZE * Number(page) - PAGE_SIZE,
},
{
$limit: PAGE_SIZE,
},
{
$lookup: {
from: USERS_COLLECTION, localField: 'authorId', foreignField: 'id', as: 'author',
},
},
{
$unwind: '$author',
},
{
$project: {
topicId: 0,
authorId: 0,
'author.id': 0,
'author._id': 0,
_id: 0,
},
},
])
.toArray()
// pagination
count = await commentsCollection.count({
topicId: Number(id),
})
const result = {
page,
pageSize: PAGE_SIZE,
total: count,
totalPages: Math.ceil(count / PAGE_SIZE),
comments,
}
return result
}
const getTopicsByCategoryId = async (id, page) => {
if (db === null) {
throw new Error('no db connection')
}
if (page === undefined) {
page = 1
}
const topicsCollection = db.collection(TOPIC_LIST_COLLECTION)
let count = await topicsCollection.count({
}, {
limit: 1,
})
if (count === 0) {
const newTopics = require('./forum/topic-list.json').body.items
topicsCollection.insertMany(newTopics)
}
// TODO delete after auth implementation
const usersCollection = db.collection(USERS_COLLECTION)
const usersCount = await usersCollection.count({
}, {
limit: 1,
})
if (usersCount === 0) {
const newUsers = require('./forum/users.json').body
usersCollection.insertMany(newUsers)
}
const topics = await topicsCollection
.aggregate([
{
$match: {
categoryId: Number(id),
},
},
{
$skip: PAGE_SIZE * Number(page) - PAGE_SIZE,
},
{
$limit: PAGE_SIZE,
},
{
$lookup: {
from: USERS_COLLECTION, localField: 'authorId', foreignField: 'id', as: 'author',
},
},
{
$unwind: '$author',
},
{
$project: {
id: 1,
title: 1,
commentCount: 1,
viewCount: 1,
voteCount: 1,
creationDate: 1,
'author.name': 1,
'author.avatar': 1,
_id: 0,
},
},
])
.toArray()
if (topics.length === 0) {
throw new Error('No data')
}
// pagination
count = await topicsCollection.count({
categoryId: Number(id),
})
const result = {
page,
pageSize: PAGE_SIZE,
total: count,
totalPages: Math.ceil(count / PAGE_SIZE),
topics,
}
return result
}
const getTags = async () => {
if (db === null) {
throw new Error('no db connection')
}
const tagsCollection = db.collection(TOPIC_TAGS_COLLECTION)
const count = await tagsCollection.count({
}, {
limit: 1,
})
if (count === 0) {
const newTags = require('./forum/topic-tags.json').body
tagsCollection.insertMany(newTags)
}
const tags = await tagsCollection.find({
}).project({
_id: 0,
}).toArray()
if (tags.length === 0) {
throw new Error('No data')
}
return tags
}
const findTags = async (value) => {
if (db === null) {
throw new Error('no db connection')
}
const tagsCollection = db.collection(TOPIC_TAGS_COLLECTION)
const tags = await tagsCollection
.find({
name: {
$regex: `${value}`,
},
})
.project({
_id: 0,
})
.toArray()
return tags
}
const insertTag = async (value) => {
if (db === null) {
throw new Error('no db connection')
}
const tagsCollection = db.collection(TOPIC_TAGS_COLLECTION)
// TODO no fast, reimplement
const count = await tagsCollection.estimatedDocumentCount()
await tagsCollection.insertOne({
id: count + 1,
name: value,
numTopics: 0,
})
return count + 1
}
const insertComment = async (comment) => {
if (db === null) {
throw new Error('no db connection')
}
const commentsCollection = db.collection(TOPIC_COMMENTS_COLLECTION)
// TODO no fast, reimplement
// TODO может перейти на _id?
const count = await commentsCollection.estimatedDocumentCount()
const currentTime = Math.round(new Date().getTime() / 1000)
await commentsCollection.insertOne({
id: count + 1,
topicId: comment.topicId,
voteCount: 0,
content: comment.content,
updationDate: currentTime,
creationDate: currentTime,
authorId: comment.authorId,
authorIsModerator: false,
isOwnPost: false,
})
return comment
}
const insertTopic = async (topic) => {
if (db === null) {
throw new Error('no db connection')
}
const topicsCollection = db.collection(TOPIC_LIST_COLLECTION)
// TODO no fast, reimplement
// TODO может перейти на _id?
const count = await topicsCollection.estimatedDocumentCount()
const currentTime = Math.round(new Date().getTime() / 1000)
const tagsId = []
if (topic.tags) {
for (let index = 0; index < topic.tags.length; index++) {
const tag = topic.tags[index]
if (tag.id === 0) {
const tagId = await insertTag(tag.name)
tagsId.push(tagId)
} else {
tagsId.push(tag.id)
}
}
}
const result = await topicsCollection.insertOne({
id: count + 1,
categoryId: topic.categoryId,
title: topic.title,
commentCount: 0,
viewCount: 0,
tagsId,
voteCount: 0,
voteStatus: 0,
content: topic.content,
updationDate: currentTime,
creationDate: currentTime,
authorId: topic.authorId,
isOwnPost: true,
})
if (!result.insertedId) {
throw new Error('Insert data failed, try again later')
}
return count + 1
}
module.exports = {
connect,
getTags,
findTags,
insertTag,
getCategories,
getTopicsByCategoryId,
getTopicById,
getCommentsByTopicId,
insertComment,
insertTopic,
getCategoryByPath,
}