diff --git a/packages/client/src/comments/Comments.tsx b/packages/client/src/comments/Comments.tsx index fbaa833..1629dad 100644 --- a/packages/client/src/comments/Comments.tsx +++ b/packages/client/src/comments/Comments.tsx @@ -8,7 +8,6 @@ export interface ICommentProps { export class CommentVote extends React.PureComponent { render() { return ( - ) } } diff --git a/packages/client/src/http/HTTPClient.ts b/packages/client/src/http/HTTPClient.ts index eff5585..1854f9b 100644 --- a/packages/client/src/http/HTTPClient.ts +++ b/packages/client/src/http/HTTPClient.ts @@ -1,8 +1,7 @@ -import assert from 'assert' import axios from 'axios' import {IHTTPClient} from './IHTTPClient' import {IHeader} from './IHeader' -import {IMethod, IRoutes} from '@rondo/common' +import {IMethod, IRoutes, URLFormatter} from '@rondo/common' import {IRequest} from './IRequest' import {IResponse} from './IResponse' import {ITypedRequestParams} from './ITypedRequestParams' @@ -13,12 +12,14 @@ interface IRequestor { export class HTTPClient implements IHTTPClient { protected readonly requestor: IRequestor + protected readonly formatter: URLFormatter constructor( protected readonly baseURL = '', protected readonly headers?: IHeader, ) { this.requestor = this.createRequestor() + this.formatter = new URLFormatter() } protected createRequestor(): IRequestor { @@ -33,12 +34,7 @@ export class HTTPClient implements IHTTPClient { M extends IMethod, >(params: ITypedRequestParams): Promise { - const url = params.path.replace(/:[a-zA-Z0-9-]+/g, (match) => { - const key = match.substring(1) - assert(params.params, 'Params is required, but not defined') - assert(params.params!.hasOwnProperty(key)) - return params.params![key] - }) + const url = this.formatter.format(params.path, params.params) const response = await this.requestor.request({ method: params.method, diff --git a/packages/common/src/IRequestParams.ts b/packages/common/src/IRequestParams.ts new file mode 100644 index 0000000..1bd8d97 --- /dev/null +++ b/packages/common/src/IRequestParams.ts @@ -0,0 +1,3 @@ +export interface IRequestParams { + [key: string]: string | number +} diff --git a/packages/common/src/URLFormatter.ts b/packages/common/src/URLFormatter.ts new file mode 100644 index 0000000..c383c48 --- /dev/null +++ b/packages/common/src/URLFormatter.ts @@ -0,0 +1,27 @@ +import assert from 'assert' +import {IRequestParams} from './IRequestParams' + +export interface IURLFormatterOptions { + readonly baseURL: string + readonly regex: RegExp +} + +export class URLFormatter { + constructor(readonly params: IURLFormatterOptions = { + baseURL: '', + regex: /:[a-zA-Z0-9-]+/g, + }) {} + + format(url: string, params?: IRequestParams) { + if (!params) { + return url + } + const formattedUrl = url.replace(this.params.regex, match => { + const key = match.substring(1) + assert(params.hasOwnProperty(key)) + return String(params![key]) + }) + + return this.params.baseURL + formattedUrl + } +} diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 33594de..6940ecc 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -3,6 +3,8 @@ export * from './IComment' export * from './ICommentTree' export * from './ICredentials' export * from './IRoutes' +export * from './IRequestParams' export * from './ISite' export * from './ITeam' export * from './IUser' +export * from './URLFormatter' diff --git a/packages/server/src/application/Application.ts b/packages/server/src/application/Application.ts index dc53116..081db71 100644 --- a/packages/server/src/application/Application.ts +++ b/packages/server/src/application/Application.ts @@ -8,7 +8,7 @@ import {IDatabase} from '../database/IDatabase' import {ILogger} from '../logger/ILogger' import {IRoutes} from '@rondo/common' import {ITransactionManager} from '../database/ITransactionManager' -import {IUserService, UserService} from '../services' +import * as services from '../services' import {loggerFactory, LoggerFactory} from '../logger/LoggerFactory' import {urlencoded, json} from 'body-parser' @@ -16,14 +16,26 @@ export class Application implements IApplication { readonly transactionManager: ITransactionManager readonly server: express.Application - readonly userService: IUserService + readonly userService: services.IUserService + readonly teamService: services.ITeamService + readonly siteService: services.ISiteService + readonly storyService: services.IStoryService + readonly commentService: services.ICommentService + readonly authenticator: middleware.Authenticator readonly loggerFactory: LoggerFactory = loggerFactory constructor(readonly config: IConfig, readonly database: IDatabase) { this.transactionManager = database.transactionManager - this.userService = new UserService(this.transactionManager) + this.userService = new services.UserService(this.transactionManager) + + this.teamService = new services.TeamService(this.transactionManager) + this.siteService = new services.SiteService(this.transactionManager) + this.storyService = new services.StoryService( + this.transactionManager, this.siteService) + this.commentService = new services.CommentService(this.transactionManager) + this.authenticator = new middleware.Authenticator(this.userService) this.server = this.createServer() @@ -78,11 +90,32 @@ export class Application implements IApplication { router.use('/app', routes.application) router.use('/api', json()) + router.use('/api', new routes.UserRoutes( this.userService, this.createTransactionalRouter(), ).handle) + router.use('/api', new routes.TeamRoutes( + this.teamService, + this.createTransactionalRouter(), + ).handle) + + router.use('/api', new routes.SiteRoutes( + this.siteService, + this.createTransactionalRouter(), + ).handle) + + router.use('/api', new routes.StoryRoutes( + this.storyService, + this.createTransactionalRouter(), + ).handle) + + router.use('/api', new routes.CommentRoutes( + this.commentService, + this.createTransactionalRouter(), + ).handle) + router.use('/api', new middleware.ErrorApiHandler(apiLogger).handle) } diff --git a/packages/server/src/entities/Team.ts b/packages/server/src/entities/Team.ts index 3e23825..af9d508 100644 --- a/packages/server/src/entities/Team.ts +++ b/packages/server/src/entities/Team.ts @@ -14,7 +14,6 @@ export class Team extends BaseEntity { userId!: number @ManyToOne(type => User) - @Column() user?: User @OneToMany(type => Site, site => site.team) diff --git a/packages/server/src/migrations/1548347305012-indices.ts b/packages/server/src/migrations/1548347305012-indices.ts new file mode 100644 index 0000000..fcabda8 --- /dev/null +++ b/packages/server/src/migrations/1548347305012-indices.ts @@ -0,0 +1,101 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class test1548347305012 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_28c5d1d16da7908c97c9bc2f74"`); + 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 TABLE "temporary_site" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "name" varchar NOT NULL, "domain" varchar NOT NULL, "userId" integer NOT NULL, "teamId" integer NOT NULL, CONSTRAINT "FK_4a06baede7d9cf51aef879fb0e4" FOREIGN KEY ("teamId") REFERENCES "team" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e03827c061fbf85fd3aae454aec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "temporary_site"("id", "createDate", "updateDate", "name", "domain", "userId", "teamId") SELECT "id", "createDate", "updateDate", "name", "domain", "userId", "teamId" FROM "site"`); + await queryRunner.query(`DROP TABLE "site"`); + await queryRunner.query(`ALTER TABLE "temporary_site" RENAME TO "site"`); + await queryRunner.query(`CREATE TABLE "temporary_team" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')))`); + await queryRunner.query(`INSERT INTO "temporary_team"("id", "createDate", "updateDate") SELECT "id", "createDate", "updateDate" FROM "team"`); + await queryRunner.query(`DROP TABLE "team"`); + await queryRunner.query(`ALTER TABLE "temporary_team" RENAME TO "team"`); + await queryRunner.query(`CREATE TABLE "temporary_team" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "name" varchar NOT NULL, "userId" integer NOT NULL)`); + await queryRunner.query(`INSERT INTO "temporary_team"("id", "createDate", "updateDate") SELECT "id", "createDate", "updateDate" FROM "team"`); + await queryRunner.query(`DROP TABLE "team"`); + await queryRunner.query(`ALTER TABLE "temporary_team" RENAME TO "team"`); + await queryRunner.query(`CREATE TABLE "temporary_site" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "name" varchar NOT NULL, "domain" varchar NOT NULL, "userId" integer NOT NULL, "teamId" integer NOT NULL, CONSTRAINT "UQ_a8c109f03677d373ab0256f82c6" UNIQUE ("domain"), CONSTRAINT "FK_4a06baede7d9cf51aef879fb0e4" FOREIGN KEY ("teamId") REFERENCES "team" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e03827c061fbf85fd3aae454aec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "temporary_site"("id", "createDate", "updateDate", "name", "domain", "userId", "teamId") SELECT "id", "createDate", "updateDate", "name", "domain", "userId", "teamId" FROM "site"`); + await queryRunner.query(`DROP TABLE "site"`); + await queryRunner.query(`ALTER TABLE "temporary_site" RENAME TO "site"`); + 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"`); + await queryRunner.query(`DROP INDEX "IDX_55a938fda82579fd3ec29b3c28"`); + await queryRunner.query(`CREATE TABLE "temporary_team" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "name" varchar NOT NULL, "userId" integer NOT NULL, CONSTRAINT "FK_55a938fda82579fd3ec29b3c28e" FOREIGN KEY ("userId") REFERENCES "user" ("id"))`); + await queryRunner.query(`INSERT INTO "temporary_team"("id", "createDate", "updateDate", "name", "userId") SELECT "id", "createDate", "updateDate", "name", "userId" FROM "team"`); + await queryRunner.query(`DROP TABLE "team"`); + await queryRunner.query(`ALTER TABLE "temporary_team" RENAME TO "team"`); + await queryRunner.query(`CREATE INDEX "IDX_55a938fda82579fd3ec29b3c28" ON "team" ("userId") `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_55a938fda82579fd3ec29b3c28"`); + await queryRunner.query(`ALTER TABLE "team" RENAME TO "temporary_team"`); + await queryRunner.query(`CREATE TABLE "team" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "name" varchar NOT NULL, "userId" integer NOT NULL)`); + await queryRunner.query(`INSERT INTO "team"("id", "createDate", "updateDate", "name", "userId") SELECT "id", "createDate", "updateDate", "name", "userId" FROM "temporary_team"`); + await queryRunner.query(`DROP TABLE "temporary_team"`); + await queryRunner.query(`CREATE INDEX "IDX_55a938fda82579fd3ec29b3c28" ON "team" ("userId") `); + 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 "site" RENAME TO "temporary_site"`); + await queryRunner.query(`CREATE TABLE "site" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "name" varchar NOT NULL, "domain" varchar NOT NULL, "userId" integer NOT NULL, "teamId" integer NOT NULL, CONSTRAINT "FK_4a06baede7d9cf51aef879fb0e4" FOREIGN KEY ("teamId") REFERENCES "team" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e03827c061fbf85fd3aae454aec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "site"("id", "createDate", "updateDate", "name", "domain", "userId", "teamId") SELECT "id", "createDate", "updateDate", "name", "domain", "userId", "teamId" FROM "temporary_site"`); + await queryRunner.query(`DROP TABLE "temporary_site"`); + await queryRunner.query(`ALTER TABLE "team" RENAME TO "temporary_team"`); + await queryRunner.query(`CREATE TABLE "team" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')))`); + await queryRunner.query(`INSERT INTO "team"("id", "createDate", "updateDate") SELECT "id", "createDate", "updateDate" FROM "temporary_team"`); + await queryRunner.query(`DROP TABLE "temporary_team"`); + await queryRunner.query(`ALTER TABLE "team" RENAME TO "temporary_team"`); + await queryRunner.query(`CREATE TABLE "team" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "url" varchar NOT NULL)`); + await queryRunner.query(`INSERT INTO "team"("id", "createDate", "updateDate") SELECT "id", "createDate", "updateDate" FROM "temporary_team"`); + await queryRunner.query(`DROP TABLE "temporary_team"`); + await queryRunner.query(`ALTER TABLE "site" RENAME TO "temporary_site"`); + await queryRunner.query(`CREATE TABLE "site" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "createDate" datetime NOT NULL DEFAULT (datetime('now')), "updateDate" datetime NOT NULL DEFAULT (datetime('now')), "name" varchar NOT NULL, "domain" varchar NOT NULL, "userId" integer NOT NULL, "teamId" integer NOT NULL, CONSTRAINT "FK_4a06baede7d9cf51aef879fb0e4" FOREIGN KEY ("teamId") REFERENCES "team" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e03827c061fbf85fd3aae454aec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "site"("id", "createDate", "updateDate", "name", "domain", "userId", "teamId") SELECT "id", "createDate", "updateDate", "name", "domain", "userId", "teamId" FROM "temporary_site"`); + await queryRunner.query(`DROP TABLE "temporary_site"`); + 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_28c5d1d16da7908c97c9bc2f74" ON "session" ("expiredAt") `); + } + +} diff --git a/packages/server/src/routes/LoginRoutes.ts b/packages/server/src/routes/LoginRoutes.ts index a80ef44..7221b45 100644 --- a/packages/server/src/routes/LoginRoutes.ts +++ b/packages/server/src/routes/LoginRoutes.ts @@ -33,7 +33,7 @@ export class LoginRoutes extends BaseRoute { } await req.logInPromise(user) res.redirect(req.baseUrl) - // TODO return user + return user }) t.get('/auth/logout', async (req, res) => { diff --git a/packages/server/src/routes/TeamRoutes.test.ts b/packages/server/src/routes/TeamRoutes.test.ts new file mode 100644 index 0000000..2d43655 --- /dev/null +++ b/packages/server/src/routes/TeamRoutes.test.ts @@ -0,0 +1,61 @@ +import {test} from '../test' + +describe('team', () => { + + test.withDatabase() + const t = test.request('/api') + + let cookie!: string + let token!: string + beforeEach(async () => { + const session = await test.registerAccount() + cookie = session.cookie + token = session.token + t.setHeaders({ cookie, 'x-csrf-token': token }) + }) + + async function createTeam(name: string) { + const response = await t + .post('/teams') + .send({ + name: 'test', + }) + .expect(200) + expect(response.body.id).toBeTruthy() + return response.body + } + + describe('POST /teams', () => { + it('creates a new team', async () => { + const team = await createTeam('test') + expect(team.name).toEqual('test') + }) + }) + + describe('GET /teams/:id', () => { + it('retrieves a team by id', async () => { + const team = await createTeam('test') + const response = await t + .get('/teams/:id', { + id: team.id, + }) + .expect(200) + expect(response.body).toEqual(team) + }) + }) + + describe('GET /my/teams', () => { + it('retrieves all teams belonging to current user', async () => { + const team = await createTeam('test') + const response = await t + .get('/my/teams') + .expect(200) + expect(response.body).toContainEqual(team) + }) + }) + + // describe('GET /my/teams', () => { + + // }) + +}) diff --git a/packages/server/src/routes/index.ts b/packages/server/src/routes/index.ts index b24ca65..8475fcc 100644 --- a/packages/server/src/routes/index.ts +++ b/packages/server/src/routes/index.ts @@ -1,4 +1,8 @@ -export * from './application' export * from './BaseRoute' +export * from './CommentRoutes' export * from './LoginRoutes' +export * from './SiteRoutes' +export * from './StoryRoutes' +export * from './TeamRoutes' export * from './UserRoutes' +export * from './application' diff --git a/packages/server/src/services/index.ts b/packages/server/src/services/index.ts index 4012b9e..5ca110e 100644 --- a/packages/server/src/services/index.ts +++ b/packages/server/src/services/index.ts @@ -1,2 +1,10 @@ -export * from './UserService' +export * from './CommentService' +export * from './ICommentService' +export * from './ISiteService' +export * from './IStoryService' +export * from './ITeamService' export * from './IUserService' +export * from './SiteService' +export * from './StoryService' +export * from './TeamService' +export * from './UserService' diff --git a/packages/server/src/test-utils/RequestTester.ts b/packages/server/src/test-utils/RequestTester.ts index e9d3c1e..ed0836c 100644 --- a/packages/server/src/test-utils/RequestTester.ts +++ b/packages/server/src/test-utils/RequestTester.ts @@ -1,5 +1,10 @@ import supertest from 'supertest' -import {IMethod, IRoutes} from '@rondo/common' +import { + IMethod, + IRequestParams, + IRoutes, + URLFormatter, +} from '@rondo/common' // https://stackoverflow.com/questions/48215950/exclude-property-from-type type Omit = Pick> @@ -37,6 +42,7 @@ export interface IHeaders { export class RequestTester { protected headers: IHeaders = {} + protected formatter: URLFormatter = new URLFormatter() constructor( readonly app: Express.Application, @@ -49,21 +55,22 @@ export class RequestTester { } request( - method: M, path: P, + method: M, path: P, params?: IRequestParams, ) : IRequest { - const test = supertest(this.app)[method](`${this.baseUrl}${path}`) + const url = this.formatter.format(path, params) + const test = supertest(this.app)[method](`${this.baseUrl}${url}`) Object.keys(this.headers).forEach(key => { test.set(key, this.headers[key]) }) return test } - get

(path: P) { - return this.request('get', path) + get

(path: P, params?: IRequestParams) { + return this.request('get', path, params) } - post

(path: P) { + post

(path: P, params?: IRequestParams) { return this.request('post', path) } } diff --git a/packages/server/src/test-utils/TestUtils.ts b/packages/server/src/test-utils/TestUtils.ts index fbcf96e..bc5fc63 100644 --- a/packages/server/src/test-utils/TestUtils.ts +++ b/packages/server/src/test-utils/TestUtils.ts @@ -101,6 +101,7 @@ export class TestUtils { return { cookie: response.header['set-cookie'] as string, userId: response.body.userId, + token, } }