Skip to content

Commit

Permalink
feat: add geoip and update migration and repository export
Browse files Browse the repository at this point in the history
  • Loading branch information
ruiming committed Mar 12, 2018
1 parent 0875010 commit 66503c4
Show file tree
Hide file tree
Showing 16 changed files with 245 additions and 28 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
},
"dependencies": {
"@types/crypto-js": "^3.1.38",
"@types/geoip-lite": "^1.1.29",
"@types/ioredis": "^3.2.5",
"class-transformer": "^0.1.9",
"class-validator": "^0.8.1",
"config": "^1.30.0",
"crypto-js": "^3.1.9-1",
"geoip-lite": "^1.2.1",
"ioredis": "^3.2.2",
"kcors": "^2.2.1",
"koa": "^2.5.0",
Expand Down
6 changes: 4 additions & 2 deletions src/controllers/Log.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Service, Inject } from 'typedi';
import { JsonController, Post, Body, HeaderParam, State, UseBefore } from 'routing-controllers';
import { JsonController, Post, Body, HeaderParam, State, UseBefore, Ctx } from 'routing-controllers';
import { IInitialize, IPageInfo, IAssetsInfo, IExit } from '../interfaces/Log';
import { Description, ResType } from 'routing-controllers-openapi-v3';
import { LogService } from '../services/LogService';
import { IToken, IPageId } from '../interfaces/Helper';
import hostInject from '../middlewares/hostInject';
import sessionInject from '../middlewares/sessionInject';
import { Context } from 'koa';

@Service()
@JsonController('/log')
Expand All @@ -17,11 +18,12 @@ export class LogController {
@Post('/initialize')
@UseBefore(hostInject())
async initialize(
@Ctx() ctx: Context,
@Body() body: IInitialize,
@State('hostId') hostId: string,
@HeaderParam('Authorization') token?: string
): Promise<IToken> {
return await this.logService.initialize(body, hostId, token);
return await this.logService.initialize(body, ctx.ip, hostId, token);
}

@Description(`页面数据`)
Expand Down
11 changes: 10 additions & 1 deletion src/entities/Visiter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,16 @@ export default class Visiter {
@Column() lang: string;

/** 地区 */
@Column() location: string;
@Column() region: string;

/** 国家 */
@Column() country: string;

/** LL */
@Column('json') ll: string[];

/** range */
@Column('json') range: string[];

/** 城市 */
@Column() city: string;
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ useContainerForOrm(Container);

const app = new Koa();

app.proxy = true;
app.use(logger());
app.use(errorCatch());

Expand Down
2 changes: 1 addition & 1 deletion src/middlewares/hostInject.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Context } from 'koa';
import Cache from '../libraries/Cache';
import { getCustomRepository } from 'typeorm';
import { HostRepository } from '../repositories/HostRepository';
import HostRepository from '../repositories/HostRepository';
import { BadRequestError } from 'routing-controllers';

/**
Expand Down
4 changes: 2 additions & 2 deletions src/migrations/1520751870576-Initialize.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MigrationInterface, QueryRunner, getCustomRepository } from 'typeorm';
import { HostRepository } from '../repositories/HostRepository';
import { UserRepository } from '../repositories/UserRepository';
import HostRepository from '../repositories/HostRepository';
import UserRepository from '../repositories/UserRepository';
import { SHA256 } from 'crypto-js';

export class Initialize1520751870576 implements MigrationInterface {
Expand Down
67 changes: 67 additions & 0 deletions src/migrations/1520833483738-Update.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class Update1520833483738 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query('ALTER TABLE `visiter` DROP COLUMN `location`');
await queryRunner.query('ALTER TABLE `visiter` ADD `region` varchar(255) NOT NULL');
await queryRunner.query('ALTER TABLE `visiter` ADD `country` varchar(255) NOT NULL');
await queryRunner.query('ALTER TABLE `visiter` ADD `ll` json NOT NULL');
await queryRunner.query('ALTER TABLE `visiter` ADD `range` json NOT NULL');
await queryRunner.query('ALTER TABLE `page` DROP FOREIGN KEY `FK_3b8c31625c102e69e9ba2563a6f`');
await queryRunner.query('ALTER TABLE `page` DROP FOREIGN KEY `FK_44c49cb9fa857c96310cc304a4f`');
await queryRunner.query('ALTER TABLE `page` DROP PRIMARY KEY');
await queryRunner.query('ALTER TABLE `page` ADD PRIMARY KEY (`id`, `visiterId`)');
await queryRunner.query('ALTER TABLE `page` DROP PRIMARY KEY');
await queryRunner.query('ALTER TABLE `page` ADD PRIMARY KEY (`id`, `hostId`)');
await queryRunner.query('ALTER TABLE `asset` DROP FOREIGN KEY `FK_877c8bfeaa7212ecd08b046a983`');
await queryRunner.query('ALTER TABLE `asset` DROP FOREIGN KEY `FK_8fca349ca0e1e30be543a8fd5e5`');
await queryRunner.query('ALTER TABLE `asset` DROP PRIMARY KEY');
await queryRunner.query('ALTER TABLE `asset` ADD PRIMARY KEY (`id`, `hostId`)');
await queryRunner.query('ALTER TABLE `asset` DROP PRIMARY KEY');
await queryRunner.query('ALTER TABLE `asset` ADD PRIMARY KEY (`id`, `visiterId`)');
await queryRunner.query(
'ALTER TABLE `page` ADD CONSTRAINT `FK_44c49cb9fa857c96310cc304a4f` FOREIGN KEY (`visiterId`) REFERENCES `visiter`(`id`)'
);
await queryRunner.query(
'ALTER TABLE `page` ADD CONSTRAINT `FK_3b8c31625c102e69e9ba2563a6f` FOREIGN KEY (`hostId`) REFERENCES `host`(`id`)'
);
await queryRunner.query(
'ALTER TABLE `asset` ADD CONSTRAINT `FK_877c8bfeaa7212ecd08b046a983` FOREIGN KEY (`visiterId`) REFERENCES `visiter`(`id`)'
);
await queryRunner.query(
'ALTER TABLE `asset` ADD CONSTRAINT `FK_8fca349ca0e1e30be543a8fd5e5` FOREIGN KEY (`hostId`) REFERENCES `host`(`id`)'
);
}

public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query('ALTER TABLE `asset` DROP FOREIGN KEY `FK_8fca349ca0e1e30be543a8fd5e5`');
await queryRunner.query('ALTER TABLE `asset` DROP FOREIGN KEY `FK_877c8bfeaa7212ecd08b046a983`');
await queryRunner.query('ALTER TABLE `page` DROP FOREIGN KEY `FK_3b8c31625c102e69e9ba2563a6f`');
await queryRunner.query('ALTER TABLE `page` DROP FOREIGN KEY `FK_44c49cb9fa857c96310cc304a4f`');
await queryRunner.query('ALTER TABLE `asset` DROP PRIMARY KEY');
await queryRunner.query('ALTER TABLE `asset` ADD PRIMARY KEY (`id`, `visiterId`, `hostId`)');
await queryRunner.query('ALTER TABLE `asset` DROP PRIMARY KEY');
await queryRunner.query('ALTER TABLE `asset` ADD PRIMARY KEY (`id`, `visiterId`, `hostId`)');
await queryRunner.query(
'ALTER TABLE `asset` ADD CONSTRAINT `FK_8fca349ca0e1e30be543a8fd5e5` FOREIGN KEY (`hostId`) REFERENCES `host`(`id`) ON DELETE RESTRICT ON UPDATE RESTRICT'
);
await queryRunner.query(
'ALTER TABLE `asset` ADD CONSTRAINT `FK_877c8bfeaa7212ecd08b046a983` FOREIGN KEY (`visiterId`) REFERENCES `visiter`(`id`) ON DELETE RESTRICT ON UPDATE RESTRICT'
);
await queryRunner.query('ALTER TABLE `page` DROP PRIMARY KEY');
await queryRunner.query('ALTER TABLE `page` ADD PRIMARY KEY (`id`, `hostId`, `visiterId`)');
await queryRunner.query('ALTER TABLE `page` DROP PRIMARY KEY');
await queryRunner.query('ALTER TABLE `page` ADD PRIMARY KEY (`id`, `hostId`, `visiterId`)');
await queryRunner.query(
'ALTER TABLE `page` ADD CONSTRAINT `FK_44c49cb9fa857c96310cc304a4f` FOREIGN KEY (`visiterId`) REFERENCES `visiter`(`id`) ON DELETE RESTRICT ON UPDATE RESTRICT'
);
await queryRunner.query(
'ALTER TABLE `page` ADD CONSTRAINT `FK_3b8c31625c102e69e9ba2563a6f` FOREIGN KEY (`hostId`) REFERENCES `host`(`id`) ON DELETE RESTRICT ON UPDATE RESTRICT'
);
await queryRunner.query('ALTER TABLE `visiter` DROP COLUMN `range`');
await queryRunner.query('ALTER TABLE `visiter` DROP COLUMN `ll`');
await queryRunner.query('ALTER TABLE `visiter` DROP COLUMN `country`');
await queryRunner.query('ALTER TABLE `visiter` DROP COLUMN `region`');
await queryRunner.query('ALTER TABLE `visiter` ADD `location` varchar(255) NOT NULL');
}
}
2 changes: 1 addition & 1 deletion src/repositories/AssetRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { EntityRepository, Repository } from 'typeorm';
import Asset from '../entities/Asset';

@EntityRepository(Asset)
export class AssetRepository extends Repository<Asset> {}
export default class AssetRepository extends Repository<Asset> {}
2 changes: 1 addition & 1 deletion src/repositories/HostRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { EntityRepository, Repository } from 'typeorm';
import Host from '../entities/Host';

@EntityRepository(Host)
export class HostRepository extends Repository<Host> {}
export default class HostRepository extends Repository<Host> {}
2 changes: 1 addition & 1 deletion src/repositories/PageRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { EntityRepository, Repository } from 'typeorm';
import Page from '../entities/Page';

@EntityRepository(Page)
export class PageRepository extends Repository<Page> {}
export default class PageRepository extends Repository<Page> {}
2 changes: 1 addition & 1 deletion src/repositories/SessionRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { MD5 } from 'crypto-js';
import Host from '../entities/Host';

@EntityRepository(Session)
export class SessionRepository extends Repository<Session> {
export default class SessionRepository extends Repository<Session> {
async newSession(visiter: Visiter, host: Host, referrer: string) {
const token = MD5(visiter.id + host.id + Date.now().toString()).toString();
const session = await this.create({
Expand Down
2 changes: 1 addition & 1 deletion src/repositories/UserRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { EntityRepository, Repository } from 'typeorm';
import User from '../entities/User';

@EntityRepository(User)
export class UserRepository extends Repository<User> {}
export default class UserRepository extends Repository<User> {}
9 changes: 6 additions & 3 deletions src/repositories/VisiterRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import Visiter from '../entities/Visiter';
import Cache from '../libraries/Cache';

@EntityRepository(Visiter)
export class VisiterRepository extends Repository<Visiter> {
async getVisiterByToken(token: string) {
export default class VisiterRepository extends Repository<Visiter> {
async getVisiterByToken(token: string, ip: string) {
const visiterId = await Cache.Instance.get(`TOKEN:${token}`);
if (!visiterId) {
return undefined;
}

return await this.findOne(visiterId);
return await this.findOne({
id: visiterId,
ip
});
}
}
24 changes: 16 additions & 8 deletions src/services/LogService.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Service } from 'typedi';
import * as geoip from 'geoip-lite';
import { IInitialize, IPageInfo, IAssetsInfo, IExit } from '../interfaces/Log';
import { SessionRepository } from '../repositories/SessionRepository';
import SessionRepository from '../repositories/SessionRepository';
import { getCustomRepository } from 'typeorm';
import { VisiterRepository } from '../repositories/VisiterRepository';
import VisiterRepository from '../repositories/VisiterRepository';
import { IToken, IPageId } from '../interfaces/Helper';
import { PageRepository } from '../repositories/PageRepository';
import PageRepository from '../repositories/PageRepository';
import { BadRequestError } from 'routing-controllers';
import { HostRepository } from '../repositories/HostRepository';
import { AssetRepository } from '../repositories/AssetRepository';
import HostRepository from '../repositories/HostRepository';
import AssetRepository from '../repositories/AssetRepository';

@Service()
export class LogService {
Expand All @@ -17,22 +18,29 @@ export class LogService {
hostRepository: HostRepository = getCustomRepository(HostRepository);
assetRepository: AssetRepository = getCustomRepository(AssetRepository);

async initialize(body: IInitialize, hostId: string, preToken?: string): Promise<IToken> {
async initialize(body: IInitialize, ip: string, hostId: string, preToken?: string): Promise<IToken> {
const host = await this.hostRepository.findOne(hostId);

if (!host) {
throw new BadRequestError('Host is not registed');
}

const visiter = preToken && (await this.visiterRepository.getVisiterByToken(preToken));
// TOKEN 有效(复用 Visiter)前提是 Token 正确且对应的 Visiter 的 IP 地址和现在的相同
const visiter = preToken && (await this.visiterRepository.getVisiterByToken(preToken, ip));

if (visiter) {
const token = await this.sessionRepository.newSession(visiter, host, body.referrer);
return {
token
};
} else {
const newVisiter = await this.visiterRepository.create(body);
const geo = geoip.lookup(ip);
const newVisiter = await this.visiterRepository.create({
lang: body.lang,
ua: body.ua,
os: body.os,
...geo
});
const token = await this.sessionRepository.newSession(newVisiter, host, body.referrer);
return {
token
Expand Down
3 changes: 2 additions & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"object-literal-sort-keys": false,
"member-access": false,
"semicolon": [true, "always"],
"max-classes-per-file": false
"max-classes-per-file": false,
"no-console": false
}
}

0 comments on commit 66503c4

Please sign in to comment.