Implement basic CommentService

This commit is contained in:
Jerko Steiner 2019-01-22 11:57:15 +01:00
parent 6e94b68598
commit 2e0402b189
4 changed files with 160 additions and 6 deletions

View File

@ -2,7 +2,9 @@ export interface IComment {
id: number
storyId: number
message: string
score: number
votes: number
spams: number
parentId: number
children: IComment[]
userId: number
childrenIds?: number[]
}

View File

@ -1,4 +1,4 @@
import {Column, Entity, ManyToOne} from 'typeorm'
import {Column, Entity, Index, ManyToOne} from 'typeorm'
import {User} from './User'
import {Story} from './Story'
import {BaseEntity} from './BaseEntity'
@ -12,6 +12,7 @@ export class Comment extends BaseEntity {
story?: Story
@Column()
@Index()
storyId!: number
@ManyToOne(type => User, user => user.comments)

View File

@ -1,34 +1,176 @@
import {BaseService} from './BaseService'
import {Comment} from '../entities/Comment'
import {ICommentService, ICommentTree} from './ICommentService'
import {IComment} from '@rondo/common'
import {ICommentService} from'./ICommentService'
import {Spam} from '../entities/Spam'
import {Validator} from '../validator'
import {Vote} from '../entities/Vote'
export class CommentService extends BaseService implements ICommentService {
async find(storyId: number) {
const comments = await this.getRepository(Comment).find({
where: {
storyId,
},
})
const commentTree: ICommentTree = {
rootIds: [],
commentsById: {},
}
comments.reduce((obj, comment) => {
obj[comment.id] = comment
const {parentId} = comment
if (!parentId) {
commentTree.rootIds.push(comment.id)
return obj
}
const children =
obj[parentId].childrenIds =
obj[parentId].childrenIds || []
children.push(comment.id)
return obj
}, commentTree.commentsById)
return commentTree
}
async findOne(commentId: number) {
return this.getRepository(Comment).findOne(commentId)
}
async saveRoot(comment: IComment, userId: number) {
new Validator(comment)
.ensure('storyId')
.throw()
comment.parentId = 0
comment.userId = userId
comment.votes = 0
comment.spams = 0
return this.getRepository(Comment).save(comment)
}
async save(comment: IComment, userId: number) {
comment.votes = 0
comment.spams = 0
comment.userId = userId
new Validator(comment)
.ensure('message')
.ensure('userId')
.ensure('storyId')
.ensure('parentId')
.throw()
return this.getRepository(Comment).save(comment)
}
async edit(comment: IComment, userId: number) {
new Validator(comment)
.ensure('id')
.ensure('message')
.throw()
await this.getRepository(Comment)
.update(comment.id, {
message: comment.message,
userId,
})
const editedComment = await this.findOne(comment.id)
if (!editedComment) {
throw new Error('Comment not found')
}
return editedComment
}
async delete(comment: IComment, userId: number) {
new Validator(comment)
.ensure('id')
.throw()
await this.getRepository(Comment)
.update({
id: comment.id,
userId,
}, {
message: '(this message has been removed by the user)',
})
return this.findOne(comment.id)
}
async upVote(commentId: number, userId: number) {
await this.getRepository(Vote)
.save({
commentId,
userId,
})
await this.getRepository(Comment)
.createQueryBuilder()
.update()
.where({ id: commentId })
.set({
score: () => 'score + 1',
})
.execute()
}
async deleteVote(commentId: number, userId: number) {
const result = await this.getRepository(Vote)
.delete({
commentId,
userId,
})
if (result.affected && result.affected === 1) {
await this.getRepository(Comment)
.createQueryBuilder()
.update()
.where({ id: commentId })
.set({
score: () => 'score - 1',
})
}
}
async markAsSpam(commentId: number, userId: number) {
await this.getRepository(Spam)
.save({
commentId,
userId,
})
await this.getRepository(Comment)
.createQueryBuilder()
.update()
.where({ id: commentId })
.set({
spams: () => 'spams + 1',
})
.execute()
}
async unmarkAsSpam(commentId: number, userId: number) {
const result = await this.getRepository(Spam)
.delete({
commentId,
userId,
})
if (result.affected && result.affected === 1) {
await this.getRepository(Comment)
.createQueryBuilder()
.update()
.where({ id: commentId })
.set({
spams: () => 'spams - 1',
})
}
}
}

View File

@ -1,7 +1,16 @@
import {IComment} from '@rondo/common'
export interface ICommentTree {
rootIds: number[],
commentsById: {
[key: number]: IComment
}
}
export interface ICommentService {
find(storyId: number): Promise<IComment>
find(storyId: number): Promise<ICommentTree>
findOne(commentId: number): Promise<IComment | undefined>
saveRoot(comment: IComment, userId: number): Promise<IComment>
@ -9,7 +18,7 @@ export interface ICommentService {
edit(comment: IComment, userId: number): Promise<IComment>
delete(comment: IComment, userId: number): Promise<IComment>
delete(comment: IComment, userId: number): Promise<IComment | undefined>
upVote(commentId: number, userId: number): Promise<void>