Add more tests for Comments

This commit is contained in:
Jerko Steiner 2019-03-10 19:40:06 +05:00
parent 234db553b1
commit 051208753b
15 changed files with 426 additions and 49 deletions

View File

@ -1,11 +1,12 @@
import {ICommentTree} from './ICommentTree' import {ICommentTree} from './ICommentTree'
import {IComment} from './IComment' import {IComment} from './IComment'
import {ICredentials} from './ICredentials' import {ICredentials} from './ICredentials'
import {INewComment} from './INewComment'
import {ISite} from './ISite' import {ISite} from './ISite'
import {IStory} from './IStory' import {IStory} from './IStory'
import {ITeam} from './ITeam' import {ITeam} from './ITeam'
import {IUser} from './IUser'
import {IUserTeam} from './IUserTeam' import {IUserTeam} from './IUserTeam'
import {IUser} from './IUser'
export interface IAPIDef { export interface IAPIDef {
'/auth/register': { '/auth/register': {
@ -157,30 +158,37 @@ export interface IAPIDef {
} }
'post': { 'post': {
response: IComment, response: IComment,
body: IComment, body: INewComment,
params: { params: {
storyId: number storyId: number
} }
} }
} }
'/comments/:parentId': { '/stories/:storyId/comments/:parentId': {
'post': { post: {
response: IComment, response: IComment,
params: { params: {
parentId: number parentId: number
storyId: number
}, },
body: IComment, body: INewComment,
} }
} }
'/comments/:commentId': { '/comments/:commentId': {
'put': { get: {
response: IComment
params: {
commentId: number
}
}
put: {
response: IComment, response: IComment,
body: IComment, body: IComment,
params: { params: {
commentId: number commentId: number
} }
} }
'delete': { delete: {
params: { params: {
commentId: number commentId: number
} }

View File

@ -0,0 +1,3 @@
export interface INewComment {
message: string
}

View File

@ -2,10 +2,12 @@ export * from './IAPIDef'
export * from './IComment' export * from './IComment'
export * from './ICommentTree' export * from './ICommentTree'
export * from './ICredentials' export * from './ICredentials'
export * from './INewComment'
export * from './IRequestParams' export * from './IRequestParams'
export * from './IRole' export * from './IRole'
export * from './IRoutes' export * from './IRoutes'
export * from './ISite' export * from './ISite'
export * from './IStory'
export * from './ITeam' export * from './ITeam'
export * from './IUser' export * from './IUser'
export * from './URLFormatter' export * from './URLFormatter'

View File

@ -0,0 +1,110 @@
import * as CommentTestUtils from './CommentTestUtils'
import {IStory} from '@rondo/common'
import {createSite} from '../site/SiteTestUtils'
import {getStory} from '../story/StoryTestUtils'
import {test} from '../test'
describe('comment', () => {
test.withDatabase()
const t = test.request('/api')
let cookie!: string
let token!: string
let story!: IStory
const storyUrl = 'https://test.example.com/my/story'
beforeEach(async () => {
const session = await test.registerAccount()
cookie = session.cookie
token = session.token
t.setHeaders({cookie, 'x-csrf-token': token})
await createSite(t, 'test.example.com')
story = await getStory(t, storyUrl)
})
async function createChildComment() {
const parent = await CommentTestUtils.createRootComment(t, {
storyId: story.id,
message: 'this is a parent comment',
})
const child = await CommentTestUtils.createComment(t, {
storyId: story.id,
parentId: parent.id,
message: 'this is a child comment',
})
expect(child.id).toBeGreaterThan(0)
return child
}
describe('GET /stories/:storyId/comments', () => {
it('retrieves comments by story id', async () => {
const comments = await CommentTestUtils.getComments(t, story.id)
expect(comments.rootIds).toEqual(jasmine.any(Array))
})
})
describe('POST /stories/:storyId/comments', () => {
it('adds a new root comment', async () => {
const message = 'this is a comment'
const comment = await CommentTestUtils.createRootComment(t, {
storyId: story.id,
message,
})
expect(comment.id).toBeGreaterThan(0)
expect(comment.message).toEqual(message)
})
})
describe('POST /stories/:storyId/comments/:parentId', () => {
it('adds a new child comment', async () => {
await createChildComment()
const comments = await CommentTestUtils.getComments(t, story.id)
expect(comments.rootIds).toEqual([
jasmine.any(Number),
])
const id = comments.rootIds[0]
const parent = comments.commentsById[id]
expect(parent).toBeTruthy()
expect(parent.message).toMatch(/parent/)
expect(parent.childrenIds).toEqual([jasmine.any(Number)])
const child = comments.commentsById[parent.childrenIds![0]]
expect(child).toBeTruthy()
expect(child.message).toMatch(/child/)
expect(child.childrenIds).toBe(undefined)
})
})
describe('PUT /comments/:commentId', () => {
it('updates a comment', () => {
})
it('fails to update a comment if user is not the owner')
it('updates a comment if user is site moderator') // TODO later
})
describe('DELETE /comments/:commentId', () => {
})
describe('POST /comments/:commentId/vote', () => {
})
describe('DELETE /comments/:commentId/vote', () => {
})
describe('POST /comments/:commentId/spam', () => {
})
describe('DELETE /comments/:commentId/spam', () => {
})
})

View File

@ -22,17 +22,34 @@ export class CommentRoutes extends BaseRoute<IAPIDef> {
t.use(ensureLoggedInApi) t.use(ensureLoggedInApi)
t.post('/stories/:storyId/comments', async req => { t.post('/stories/:storyId/comments', async req => {
const {storyId} = req.params const userId = req.user!.id
const comment = req.body const storyId = Number(req.params.storyId)
comment.storyId = storyId const {message} = req.body
return this.commentService.saveRoot(comment, req.user!.id) return this.commentService.saveRoot({
message,
storyId,
userId,
})
}) })
t.post('/comments/:parentId', async req => { t.post('/stories/:storyId/comments/:parentId', async req => {
const {parentId} = req.params const userId = req.user!.id
const comment = req.body const parentId = Number(req.params.parentId)
comment.parentId = parentId const storyId = Number(req.params.storyId)
return this.commentService.save(comment, req.user!.id) const {message} = req.body
return this.commentService.save({
message,
userId,
parentId,
storyId,
})
})
t.get('/comments/:commentId', async req => {
const commentId = req.params.commentId
const comment = await this.commentService.findOne(commentId)
// TODO return status code 404 when not found
return comment!
}) })
t.put('/comments/:commentId', async req => { t.put('/comments/:commentId', async req => {

View File

@ -1,7 +1,9 @@
import {BaseService} from '../services/BaseService' import {BaseService} from '../services/BaseService'
import {Comment} from '../entities/Comment' import {Comment} from '../entities/Comment'
import {ICommentService} from './ICommentService'
import {IComment, ICommentTree} from '@rondo/common' import {IComment, ICommentTree} from '@rondo/common'
import {ICommentService} from './ICommentService'
import {INewCommentParams} from './INewCommentParams'
import {INewRootCommentParams} from './INewRootCommentParams'
import {Spam} from '../entities/Spam' import {Spam} from '../entities/Spam'
import {Validator} from '../validator' import {Validator} from '../validator'
import {Vote} from '../entities/Vote' import {Vote} from '../entities/Vote'
@ -40,20 +42,31 @@ export class CommentService extends BaseService implements ICommentService {
return this.getRepository(Comment).findOne(commentId) return this.getRepository(Comment).findOne(commentId)
} }
async saveRoot(comment: IComment, userId: number) { async saveRoot(comment: INewRootCommentParams) {
new Validator(comment) new Validator(comment)
.ensure('message')
.ensure('storyId') .ensure('storyId')
.ensure('userId')
.throw() .throw()
delete comment.id const {
comment.parentId = 0 message,
comment.userId = userId userId,
comment.votes = 0 storyId,
comment.spams = 0 } = comment
return this.getRepository(Comment).save(comment)
return this.getRepository(Comment).save({
message: message.trim(),
userId,
storyId,
parentId: undefined,
votes: 0,
spams: 0,
})
} }
async save(comment: IComment, userId: number) { async save(comment: INewCommentParams) {
new Validator(comment) new Validator(comment)
.ensure('message') .ensure('message')
.ensure('userId') .ensure('userId')
@ -61,13 +74,22 @@ export class CommentService extends BaseService implements ICommentService {
.ensure('parentId') .ensure('parentId')
.throw() .throw()
delete comment.id const {
message,
userId,
storyId,
parentId,
} = comment
comment.votes = 0 return this.getRepository(Comment).save({
comment.spams = 0 message: message.trim(),
comment.userId = userId userId,
storyId,
parentId,
return this.getRepository(Comment).save(comment) votes: 0,
spams: 0,
})
} }
async edit(comment: IComment, userId: number) { async edit(comment: IComment, userId: number) {
@ -77,9 +99,11 @@ export class CommentService extends BaseService implements ICommentService {
.throw() .throw()
await this.getRepository(Comment) await this.getRepository(Comment)
.update(comment.id, { .update({
message: comment.message, id: comment.id,
userId, userId,
}, {
message: comment.message,
}) })
const editedComment = await this.findOne(comment.id) const editedComment = await this.findOne(comment.id)

View File

@ -0,0 +1,54 @@
import {RequestTester} from '../test-utils'
import {IAPIDef} from '@rondo/common'
export async function createRootComment(
t: RequestTester<IAPIDef>,
{storyId, message}: {
storyId: number,
message: string,
},
) {
const response = await t
.post('/stories/:storyId/comments', {
params: {storyId},
})
.send({
message,
})
.expect(200)
return response.body!
}
export async function createComment(
t: RequestTester<IAPIDef>,
{storyId, parentId, message}: {
storyId: number,
parentId: number,
message: string,
},
) {
const response = await t
.post('/stories/:storyId/comments/:parentId', {
params: {storyId, parentId},
})
.send({
message,
})
.expect(200)
return response.body!
}
export async function getComments(
t: RequestTester<IAPIDef>,
storyId: number,
) {
const response = await t
.get('/stories/:storyId/comments', {
params: {storyId},
})
.expect(200)
return response.body!
}

View File

@ -1,13 +1,15 @@
import {IComment, ICommentTree} from '@rondo/common' import {IComment, ICommentTree} from '@rondo/common'
import {INewCommentParams} from './INewCommentParams'
import {INewRootCommentParams} from './INewRootCommentParams'
export interface ICommentService { export interface ICommentService {
find(storyId: number): Promise<ICommentTree> find(storyId: number): Promise<ICommentTree>
findOne(commentId: number): Promise<IComment | undefined> findOne(commentId: number): Promise<IComment | undefined>
saveRoot(comment: IComment, userId: number): Promise<IComment> saveRoot(comment: INewRootCommentParams): Promise<IComment>
save(comment: IComment, userId: number): Promise<IComment> save(comment: INewCommentParams): Promise<IComment>
edit(comment: IComment, userId: number): Promise<IComment> edit(comment: IComment, userId: number): Promise<IComment>

View File

@ -0,0 +1,6 @@
export interface INewCommentParams {
message: string
userId: number
parentId: number
storyId: number
}

View File

@ -0,0 +1,5 @@
export interface INewRootCommentParams {
message: string
userId: number
storyId: number
}

View File

@ -21,7 +21,7 @@ export class Comment extends BaseEntity {
@Column() @Column()
userId!: number userId!: number
@Column() @Column({nullable: true})
parentId!: number parentId!: number
@Column() @Column()

View File

@ -0,0 +1,63 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class commentParentidNullable1552227347990 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`DROP INDEX "IDX_28c5d1d16da7908c97c9bc2f74"`);
await queryRunner.query(`DROP INDEX "IDX_55a938fda82579fd3ec29b3c28"`);
await queryRunner.query(`DROP INDEX "IDX_4a06baede7d9cf51aef879fb0e"`);
await queryRunner.query(`DROP INDEX "IDX_e03827c061fbf85fd3aae454ae"`);
await queryRunner.query(`DROP INDEX "IDX_fe13edd1431a248a0eeac11ae4"`);
await queryRunner.query(`CREATE TABLE "temporary_spam" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "FK_ec8bc4fa789466cf62f5949f5cc" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_1bf468db8f4d18b424bb3eafae5" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_spam"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "spam"`);
await queryRunner.query(`DROP TABLE "spam"`);
await queryRunner.query(`ALTER TABLE "temporary_spam" RENAME TO "spam"`);
await queryRunner.query(`CREATE TABLE "temporary_vote" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "FK_f5de237a438d298031d11a57c3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ad37adcff60fdb9670a97868ab1" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_vote"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "vote"`);
await queryRunner.query(`DROP TABLE "vote"`);
await queryRunner.query(`ALTER TABLE "temporary_vote" RENAME TO "vote"`);
await queryRunner.query(`CREATE INDEX "IDX_28c5d1d16da7908c97c9bc2f74" ON "session" ("expiredAt") `);
await queryRunner.query(`CREATE INDEX "IDX_55a938fda82579fd3ec29b3c28" ON "team" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_e03827c061fbf85fd3aae454ae" ON "site" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_4a06baede7d9cf51aef879fb0e" ON "site" ("teamId") `);
await queryRunner.query(`CREATE INDEX "IDX_fe13edd1431a248a0eeac11ae4" ON "comment" ("storyId") `);
await queryRunner.query(`CREATE TABLE "temporary_spam" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "spam_userid_commentid" UNIQUE ("userId", "commentId"), CONSTRAINT "FK_ec8bc4fa789466cf62f5949f5cc" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_1bf468db8f4d18b424bb3eafae5" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_spam"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "spam"`);
await queryRunner.query(`DROP TABLE "spam"`);
await queryRunner.query(`ALTER TABLE "temporary_spam" RENAME TO "spam"`);
await queryRunner.query(`CREATE TABLE "temporary_vote" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "vote_userid_commentid" UNIQUE ("userId", "commentId"), CONSTRAINT "FK_f5de237a438d298031d11a57c3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ad37adcff60fdb9670a97868ab1" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_vote"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "vote"`);
await queryRunner.query(`DROP TABLE "vote"`);
await queryRunner.query(`ALTER TABLE "temporary_vote" RENAME TO "vote"`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "vote" RENAME TO "temporary_vote"`);
await queryRunner.query(`CREATE TABLE "vote" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "FK_f5de237a438d298031d11a57c3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ad37adcff60fdb9670a97868ab1" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "vote"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "temporary_vote"`);
await queryRunner.query(`DROP TABLE "temporary_vote"`);
await queryRunner.query(`ALTER TABLE "spam" RENAME TO "temporary_spam"`);
await queryRunner.query(`CREATE TABLE "spam" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "FK_ec8bc4fa789466cf62f5949f5cc" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_1bf468db8f4d18b424bb3eafae5" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "spam"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "temporary_spam"`);
await queryRunner.query(`DROP TABLE "temporary_spam"`);
await queryRunner.query(`DROP INDEX "IDX_fe13edd1431a248a0eeac11ae4"`);
await queryRunner.query(`DROP INDEX "IDX_4a06baede7d9cf51aef879fb0e"`);
await queryRunner.query(`DROP INDEX "IDX_e03827c061fbf85fd3aae454ae"`);
await queryRunner.query(`DROP INDEX "IDX_55a938fda82579fd3ec29b3c28"`);
await queryRunner.query(`DROP INDEX "IDX_28c5d1d16da7908c97c9bc2f74"`);
await queryRunner.query(`ALTER TABLE "vote" RENAME TO "temporary_vote"`);
await queryRunner.query(`CREATE TABLE "vote" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "UQ_5ef3b030c86a67d7c3cce97a978" UNIQUE ("userId", "commentId"), CONSTRAINT "FK_f5de237a438d298031d11a57c3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ad37adcff60fdb9670a97868ab1" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "vote"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "temporary_vote"`);
await queryRunner.query(`DROP TABLE "temporary_vote"`);
await queryRunner.query(`ALTER TABLE "spam" RENAME TO "temporary_spam"`);
await queryRunner.query(`CREATE TABLE "spam" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "UQ_885dac94f112af83664ccd06dd9" UNIQUE ("userId", "commentId"), CONSTRAINT "FK_ec8bc4fa789466cf62f5949f5cc" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_1bf468db8f4d18b424bb3eafae5" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "spam"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "temporary_spam"`);
await queryRunner.query(`DROP TABLE "temporary_spam"`);
await queryRunner.query(`CREATE INDEX "IDX_fe13edd1431a248a0eeac11ae4" ON "comment" ("storyId") `);
await queryRunner.query(`CREATE INDEX "IDX_e03827c061fbf85fd3aae454ae" ON "site" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_4a06baede7d9cf51aef879fb0e" ON "site" ("teamId") `);
await queryRunner.query(`CREATE INDEX "IDX_55a938fda82579fd3ec29b3c28" ON "team" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_28c5d1d16da7908c97c9bc2f74" ON "session" ("expiredAt") `);
}
}

View File

@ -0,0 +1,79 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class nullable1552227652042 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`DROP INDEX "IDX_28c5d1d16da7908c97c9bc2f74"`);
await queryRunner.query(`DROP INDEX "IDX_55a938fda82579fd3ec29b3c28"`);
await queryRunner.query(`DROP INDEX "IDX_4a06baede7d9cf51aef879fb0e"`);
await queryRunner.query(`DROP INDEX "IDX_e03827c061fbf85fd3aae454ae"`);
await queryRunner.query(`DROP INDEX "IDX_fe13edd1431a248a0eeac11ae4"`);
await queryRunner.query(`CREATE TABLE "temporary_spam" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "FK_1bf468db8f4d18b424bb3eafae5" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ec8bc4fa789466cf62f5949f5cc" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_spam"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "spam"`);
await queryRunner.query(`DROP TABLE "spam"`);
await queryRunner.query(`ALTER TABLE "temporary_spam" RENAME TO "spam"`);
await queryRunner.query(`CREATE TABLE "temporary_vote" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "FK_ad37adcff60fdb9670a97868ab1" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_f5de237a438d298031d11a57c3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_vote"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "vote"`);
await queryRunner.query(`DROP TABLE "vote"`);
await queryRunner.query(`ALTER TABLE "temporary_vote" RENAME TO "vote"`);
await queryRunner.query(`CREATE TABLE "temporary_comment" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "message" text NOT NULL, "storyId" integer NOT NULL, "userId" integer NOT NULL, "parentId" integer NOT NULL, "spams" integer NOT NULL, "votes" integer NOT NULL, CONSTRAINT "FK_c0354a9a009d3bb45a08655ce3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_fe13edd1431a248a0eeac11ae43" FOREIGN KEY ("storyId") REFERENCES "story" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_comment"("id", "createDate", "updateDate", "message", "storyId", "userId", "parentId", "spams", "votes") SELECT "id", "createDate", "updateDate", "message", "storyId", "userId", "parentId", "spams", "votes" FROM "comment"`);
await queryRunner.query(`DROP TABLE "comment"`);
await queryRunner.query(`ALTER TABLE "temporary_comment" RENAME TO "comment"`);
await queryRunner.query(`CREATE TABLE "temporary_comment" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "message" text NOT NULL, "storyId" integer NOT NULL, "userId" integer NOT NULL, "parentId" integer, "spams" integer NOT NULL, "votes" integer NOT NULL, CONSTRAINT "FK_c0354a9a009d3bb45a08655ce3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_fe13edd1431a248a0eeac11ae43" FOREIGN KEY ("storyId") REFERENCES "story" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_comment"("id", "createDate", "updateDate", "message", "storyId", "userId", "parentId", "spams", "votes") SELECT "id", "createDate", "updateDate", "message", "storyId", "userId", "parentId", "spams", "votes" FROM "comment"`);
await queryRunner.query(`DROP TABLE "comment"`);
await queryRunner.query(`ALTER TABLE "temporary_comment" RENAME TO "comment"`);
await queryRunner.query(`CREATE INDEX "IDX_28c5d1d16da7908c97c9bc2f74" ON "session" ("expiredAt") `);
await queryRunner.query(`CREATE INDEX "IDX_55a938fda82579fd3ec29b3c28" ON "team" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_e03827c061fbf85fd3aae454ae" ON "site" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_4a06baede7d9cf51aef879fb0e" ON "site" ("teamId") `);
await queryRunner.query(`CREATE INDEX "IDX_fe13edd1431a248a0eeac11ae4" ON "comment" ("storyId") `);
await queryRunner.query(`CREATE TABLE "temporary_spam" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "spam_userid_commentid" UNIQUE ("userId", "commentId"), CONSTRAINT "FK_1bf468db8f4d18b424bb3eafae5" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ec8bc4fa789466cf62f5949f5cc" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_spam"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "spam"`);
await queryRunner.query(`DROP TABLE "spam"`);
await queryRunner.query(`ALTER TABLE "temporary_spam" RENAME TO "spam"`);
await queryRunner.query(`CREATE TABLE "temporary_vote" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "vote_userid_commentid" UNIQUE ("userId", "commentId"), CONSTRAINT "FK_ad37adcff60fdb9670a97868ab1" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_f5de237a438d298031d11a57c3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_vote"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "vote"`);
await queryRunner.query(`DROP TABLE "vote"`);
await queryRunner.query(`ALTER TABLE "temporary_vote" RENAME TO "vote"`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "vote" RENAME TO "temporary_vote"`);
await queryRunner.query(`CREATE TABLE "vote" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "FK_ad37adcff60fdb9670a97868ab1" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_f5de237a438d298031d11a57c3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "vote"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "temporary_vote"`);
await queryRunner.query(`DROP TABLE "temporary_vote"`);
await queryRunner.query(`ALTER TABLE "spam" RENAME TO "temporary_spam"`);
await queryRunner.query(`CREATE TABLE "spam" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "FK_1bf468db8f4d18b424bb3eafae5" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ec8bc4fa789466cf62f5949f5cc" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "spam"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "temporary_spam"`);
await queryRunner.query(`DROP TABLE "temporary_spam"`);
await queryRunner.query(`DROP INDEX "IDX_fe13edd1431a248a0eeac11ae4"`);
await queryRunner.query(`DROP INDEX "IDX_4a06baede7d9cf51aef879fb0e"`);
await queryRunner.query(`DROP INDEX "IDX_e03827c061fbf85fd3aae454ae"`);
await queryRunner.query(`DROP INDEX "IDX_55a938fda82579fd3ec29b3c28"`);
await queryRunner.query(`DROP INDEX "IDX_28c5d1d16da7908c97c9bc2f74"`);
await queryRunner.query(`ALTER TABLE "comment" RENAME TO "temporary_comment"`);
await queryRunner.query(`CREATE TABLE "comment" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "message" text NOT NULL, "storyId" integer NOT NULL, "userId" integer NOT NULL, "parentId" integer NOT NULL, "spams" integer NOT NULL, "votes" integer NOT NULL, CONSTRAINT "FK_c0354a9a009d3bb45a08655ce3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_fe13edd1431a248a0eeac11ae43" FOREIGN KEY ("storyId") REFERENCES "story" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "comment"("id", "createDate", "updateDate", "message", "storyId", "userId", "parentId", "spams", "votes") SELECT "id", "createDate", "updateDate", "message", "storyId", "userId", "parentId", "spams", "votes" FROM "temporary_comment"`);
await queryRunner.query(`DROP TABLE "temporary_comment"`);
await queryRunner.query(`ALTER TABLE "comment" RENAME TO "temporary_comment"`);
await queryRunner.query(`CREATE TABLE "comment" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "message" text NOT NULL, "storyId" integer NOT NULL, "userId" integer NOT NULL, "parentId" integer NOT NULL, "spams" integer NOT NULL, "votes" integer NOT NULL, CONSTRAINT "FK_c0354a9a009d3bb45a08655ce3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_fe13edd1431a248a0eeac11ae43" FOREIGN KEY ("storyId") REFERENCES "story" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "comment"("id", "createDate", "updateDate", "message", "storyId", "userId", "parentId", "spams", "votes") SELECT "id", "createDate", "updateDate", "message", "storyId", "userId", "parentId", "spams", "votes" FROM "temporary_comment"`);
await queryRunner.query(`DROP TABLE "temporary_comment"`);
await queryRunner.query(`ALTER TABLE "vote" RENAME TO "temporary_vote"`);
await queryRunner.query(`CREATE TABLE "vote" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "UQ_5ef3b030c86a67d7c3cce97a978" UNIQUE ("userId", "commentId"), CONSTRAINT "FK_ad37adcff60fdb9670a97868ab1" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_f5de237a438d298031d11a57c3b" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "vote"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "temporary_vote"`);
await queryRunner.query(`DROP TABLE "temporary_vote"`);
await queryRunner.query(`ALTER TABLE "spam" RENAME TO "temporary_spam"`);
await queryRunner.query(`CREATE TABLE "spam" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer NOT NULL, "commentId" integer NOT NULL, CONSTRAINT "UQ_885dac94f112af83664ccd06dd9" UNIQUE ("userId", "commentId"), CONSTRAINT "FK_1bf468db8f4d18b424bb3eafae5" FOREIGN KEY ("commentId") REFERENCES "comment" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ec8bc4fa789466cf62f5949f5cc" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "spam"("id", "createDate", "updateDate", "userId", "commentId") SELECT "id", "createDate", "updateDate", "userId", "commentId" FROM "temporary_spam"`);
await queryRunner.query(`DROP TABLE "temporary_spam"`);
await queryRunner.query(`CREATE INDEX "IDX_fe13edd1431a248a0eeac11ae4" ON "comment" ("storyId") `);
await queryRunner.query(`CREATE INDEX "IDX_e03827c061fbf85fd3aae454ae" ON "site" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_4a06baede7d9cf51aef879fb0e" ON "site" ("teamId") `);
await queryRunner.query(`CREATE INDEX "IDX_55a938fda82579fd3ec29b3c28" ON "team" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_28c5d1d16da7908c97c9bc2f74" ON "session" ("expiredAt") `);
}
}

View File

@ -1,5 +1,6 @@
import {ISite} from '@rondo/common' import {ISite} from '@rondo/common'
import {createSite} from '../site/SiteTestUtils' import {createSite} from '../site/SiteTestUtils'
import {getStory} from './StoryTestUtils'
import {test} from '../test' import {test} from '../test'
describe('story', () => { describe('story', () => {
@ -22,15 +23,6 @@ describe('story', () => {
const invalidUrl = 'https://invalid.example.com/test' const invalidUrl = 'https://invalid.example.com/test'
const validUrl = 'https://test.example.com/test' const validUrl = 'https://test.example.com/test'
async function getStory() {
const response = await t
.get('/stories/by-url', {
query: { url: validUrl },
})
.expect(200)
return response.body!
}
describe('/stories/by-url', () => { describe('/stories/by-url', () => {
it('returns undefined when a site is not configured', async () => { it('returns undefined when a site is not configured', async () => {
const response = await t const response = await t
@ -42,21 +34,21 @@ describe('story', () => {
}) })
it('creates a story when it does not exist', async () => { it('creates a story when it does not exist', async () => {
const story = await getStory() const story = await getStory(t, validUrl)
expect(story.id).toBeTruthy() expect(story.id).toBeTruthy()
expect(story.siteId).toEqual(site.id) expect(story.siteId).toEqual(site.id)
}) })
it('retrieves existing story after it is created', async () => { it('retrieves existing story after it is created', async () => {
const story1 = await getStory() const story1 = await getStory(t, validUrl)
const story2 = await getStory() const story2 = await getStory(t, validUrl)
expect(story1.id).toBeTruthy() expect(story1.id).toBeTruthy()
expect(story1).toEqual(story2) expect(story1).toEqual(story2)
}) })
it('prevents unique exceptions', async () => { it('prevents unique exceptions', async () => {
const p1 = getStory() const p1 = getStory(t, validUrl)
const p2 = getStory() const p2 = getStory(t, validUrl)
const [story1, story2] = await Promise.all([p1, p2]) const [story1, story2] = await Promise.all([p1, p2])
expect(story1.id).toBeTruthy() expect(story1.id).toBeTruthy()
expect(story1).toEqual(story2) expect(story1).toEqual(story2)

View File

@ -0,0 +1,12 @@
import {IAPIDef} from '@rondo/common'
import {RequestTester} from '../test-utils'
export async function getStory(t: RequestTester<IAPIDef>, url: string) {
const response = await t
.get('/stories/by-url', {
query: {url},
})
.expect(200)
return response.body!
}