425 lines
9.9 KiB
JavaScript
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,
|
||
|
}
|