Commit 7138f267 authored by nanahira's avatar nanahira

manager things of vip

parent 9f6fbc0d
......@@ -14,12 +14,33 @@ const underscore_1 = __importDefault(require("underscore"));
const DuelLog_1 = require("./entities/DuelLog");
const DuelLogPlayer_1 = require("./entities/DuelLogPlayer");
const User_1 = require("./entities/User");
const VipKey_1 = require("./entities/VipKey");
const UserDialog_1 = require("./entities/UserDialog");
class DataManager {
constructor(config, log) {
this.config = config;
this.ready = false;
this.log = log;
}
async transaction(fun) {
const runner = await this.db.createQueryRunner();
await runner.connect();
await runner.startTransaction();
let result = false;
try {
result = await fun(runner.manager);
}
catch (e) {
result = false;
this.log.warn(`Failed running transaction: ${e.toString()}`);
}
if (result) {
await runner.commitTransaction();
}
else {
await runner.rollbackTransaction();
}
}
async init() {
this.db = await typeorm_1.createConnection({
type: "mysql",
......@@ -75,16 +96,18 @@ class DataManager {
const player = CloudReplayPlayer_1.CloudReplayPlayer.fromPlayerInfo(p);
return player;
});
await this.db.transaction(async (mdb) => {
await this.transaction(async (mdb) => {
try {
const nreplay = await mdb.save(replay);
for (let player of players) {
player.cloudReplay = nreplay;
}
await mdb.save(players);
return true;
}
catch (e) {
this.log.warn(`Failed to save replay R#${replay.id}: ${e.toString()}`);
return false;
}
});
}
......@@ -233,7 +256,6 @@ class DataManager {
return allDuelLogs.map(duelLog => duelLog.replayFileName);
}
async clearDuelLog() {
//await this.db.transaction(async (mdb) => {
const runner = this.db.createQueryRunner();
try {
await runner.connect();
......@@ -248,7 +270,6 @@ class DataManager {
await runner.rollbackTransaction();
this.log.warn(`Failed to clear duel logs: ${e.toString()}`);
}
//});
}
async saveDuelLog(name, roomId, cloudReplayId, replayFilename, roomMode, duelCount, playerInfos) {
const duelLog = new DuelLog_1.DuelLog();
......@@ -260,23 +281,25 @@ class DataManager {
duelLog.roomMode = roomMode;
duelLog.duelCount = duelCount;
const players = playerInfos.map(p => DuelLogPlayer_1.DuelLogPlayer.fromDuelLogPlayerInfo(p));
await this.db.transaction(async (mdb) => {
await this.transaction(async (mdb) => {
try {
const savedDuelLog = await mdb.save(duelLog);
for (let player of players) {
player.duelLog = savedDuelLog;
}
await mdb.save(players);
return true;
}
catch (e) {
this.log.warn(`Failed to save duel log ${name}: ${e.toString()}`);
return false;
}
});
}
async getUser(key) {
const repo = this.db.getRepository(User_1.User);
try {
const user = await repo.findOne(key);
const user = await repo.findOne(key, { relations: ["dialogues", "usedKeys"] });
return user;
}
catch (e) {
......@@ -300,7 +323,7 @@ class DataManager {
}
catch (e) {
this.log.warn(`Failed to save user: ${e.toString()}`);
return null;
return user;
}
}
async getUserChatColor(key) {
......@@ -308,16 +331,47 @@ class DataManager {
return user ? user.chatColor : null;
}
async setUserChatColor(key, color) {
let user = await this.getUser(key);
if (!user) {
user = new User_1.User();
user.key = key;
}
const user = await this.getOrCreateUser(key);
user.chatColor = color;
return await this.saveUser(user);
}
async getUserDialogues(key, cardCode) {
try {
const dialogue = await this.db.getRepository(UserDialog_1.UserDialog)
.createQueryBuilder("dialog")
.where("dialog.cardCode = :cardCode and ", { cardCode, key })
.getOne();
if (dialogue) {
return dialogue.text;
}
else {
return null;
}
}
catch (e) {
this.log.warn(`Failed to find user dualogue ${key} ${cardCode}: ${e.toString()}`);
return null;
}
}
async getUserWords(key) {
const user = await this.getUser(key);
return user ? user.words : null;
}
async getUserVictoryWords(key) {
const user = await this.getUser(key);
return user ? user.victory : null;
}
async setUserDialogues(key, cardCode) {
const user = await this.getOrCreateUser(key);
try {
}
catch (e) {
this.log.warn(`Failed to save dialogue: ${e.toString()}`);
return user;
}
}
async migrateChatColors(data) {
await this.db.transaction(async (mdb) => {
await this.transaction(async (mdb) => {
try {
const users = [];
for (let key in data) {
......@@ -331,12 +385,75 @@ class DataManager {
users.push(user);
}
await mdb.save(users);
return true;
}
catch (e) {
this.log.warn(`Failed to migrate chat color data: ${e.toString()}`);
return null;
return false;
}
});
}
async getVipKeys(keyType) {
const repo = this.db.getRepository(VipKey_1.VipKey);
const queryCondition = {
type: keyType,
isUsed: 0
};
try {
const keys = await repo.find(queryCondition);
return keys.map(k => k.toJSON());
}
catch (e) {
this.log.warn(`Failed to fetch keys of keyType ${keyType}: ${e.toString()}`);
return [];
}
}
async generateVipKeys(keyType, count) {
const vipKeys = underscore_1.default.range(count).map(() => {
const keyText = Math.floor(Math.random() * 10000000000000000).toString();
const key = new VipKey_1.VipKey();
key.key = keyText;
key.type = keyType;
return key;
});
try {
await this.db.manager.save(vipKeys);
}
catch (e) {
this.log.warn(`Failed to generate keys of keyType ${keyType}: ${e.toString()}`);
}
}
async useVipKey(userKey, vipKeyText) {
let user = await this.getOrCreateUser(userKey);
let result = 0;
await this.transaction(async (mdb) => {
try {
const vipKey = await mdb.findOne(VipKey_1.VipKey, { key: vipKeyText, isUsed: 0 });
if (!vipKey) {
return false;
}
const keyType = vipKey.type;
const previousDate = user.vipExpireDate;
if (previousDate && moment_1.default().isBefore(previousDate)) {
user.vipExpireDate = moment_1.default(previousDate).add(keyType, "d").toDate();
}
else {
user.vipExpireDate = moment_1.default().add(keyType, "d").toDate();
}
user = await mdb.save(user);
vipKey.isUsed = 1;
vipKey.usedBy = user;
await mdb.save(vipKey);
result = previousDate ? 2 : 1;
return true;
}
catch (e) {
this.log.warn(`Failed to use VIP key for user ${userKey} ${vipKeyText}: ${e.toString()}`);
result = 0;
return false;
}
});
return result;
}
}
exports.DataManager = DataManager;
......
......@@ -11,6 +11,7 @@ import {Deck} from "./DeckEncoder";
import {DuelLogPlayer} from "./entities/DuelLogPlayer";
import {User} from "./entities/User";
import {VipKey} from "./entities/VipKey";
import {UserDialog} from "./entities/UserDialog";
interface BasePlayerInfo {
name: string;
......@@ -324,7 +325,7 @@ export class DataManager {
async getUser(key: string) {
const repo = this.db.getRepository(User);
try {
const user = await repo.findOne(key, {relations: ["dialogues"]});
const user = await repo.findOne(key, {relations: ["dialogues", "usedKeys"]});
return user;
} catch (e) {
this.log.warn(`Failed to fetch user: ${e.toString()}`);
......@@ -346,7 +347,7 @@ export class DataManager {
return await repo.save(user);
} catch (e) {
this.log.warn(`Failed to save user: ${e.toString()}`);
return null;
return user;
}
}
async getUserChatColor(key: string) {
......@@ -354,14 +355,68 @@ export class DataManager {
return user ? user.chatColor : null;
}
async setUserChatColor(key: string, color: string) {
let user = await this.getUser(key);
if(!user) {
user = new User();
user.key = key;
}
const user = await this.getOrCreateUser(key);
user.chatColor = color;
return await this.saveUser(user);
}
async getUserDialogueText(key: string, cardCode: number) {
try {
const dialogue = await this.db.getRepository(UserDialog)
.createQueryBuilder("dialog")
.where("cardCode = :cardCode and userKey = :key", {cardCode, key})
.getOne();
if(dialogue) {
return dialogue.text;
} else {
return null;
}
} catch(e) {
this.log.warn(`Failed to find user dualogue ${key} ${cardCode}: ${e.toString()}`);
return null;
}
}
async getUserWords(key: string) {
const user = await this.getUser(key);
return user ? user.words : null;
}
async getUserVictoryWords(key: string) {
const user = await this.getUser(key);
return user ? user.victory : null;
}
async setUserWords(key: string, word: string) {
const user = await this.getOrCreateUser(key);
user.words = word;
return await this.saveUser(user);
}
async setUserVictoryWords(key: string, word: string) {
const user = await this.getOrCreateUser(key);
user.victory = word;
return await this.saveUser(user);
}
async setUserDialogues(key: string, cardCode: number, text: string) {
const user = await this.getOrCreateUser(key);
await this.transaction(async mdb => {
try {
let dialogue = await mdb.getRepository(UserDialog)
.createQueryBuilder("dialog")
.where("cardCode = :cardCode and userKey = :key", {cardCode, key})
.innerJoinAndSelect("dialog.user", "user")
.getOne();
if(!dialogue) {
dialogue = new UserDialog();
dialogue.user = user;
dialogue.cardCode = cardCode;
}
dialogue.text = text;
await mdb.save(dialogue);
return true;
} catch (e) {
this.log.warn(`Failed to save dialogue: ${e.toString()}`);
return false;
}
});
}
async migrateChatColors(data: any) {
await this.transaction(async (mdb) => {
......@@ -402,14 +457,29 @@ export class DataManager {
}
}
async generateVipKeys(keyType: number, count: number){
const vipKeys = _.range(count).map(() => {
const keyText = Math.floor(Math.random() * 10000000000000000).toString();
const key = new VipKey();
key.key = keyText;
key.type = keyType;
return key;
});
try {
await this.db.manager.save(vipKeys);
} catch (e) {
this.log.warn(`Failed to generate keys of keyType ${keyType}: ${e.toString()}`);
}
}
async useVipKey(userKey: string, vipKeyText: string) {
let user = await this.getOrCreateUser(userKey);
let result = 0;
await this.db.transaction(async (mdb) => {
await this.transaction(async (mdb) => {
try {
const vipKey = await mdb.findOne(VipKey, {key: vipKeyText, isUsed: 0});
if(!vipKey) {
return;
return false;
}
const keyType = vipKey.type;
const previousDate = user.vipExpireDate;
......@@ -423,13 +493,64 @@ export class DataManager {
vipKey.usedBy = user;
await mdb.save(vipKey);
result = previousDate ? 2 : 1;
return true;
} catch (e) {
this.log.warn(`Failed to use VIP key for user ${userKey} ${vipKeyText}: ${e.toString()}`);
result = 0;
return;
return false;
}
});
return result;
}
async migrateFromOldVipInfo(vipInfo: any) {
await this.transaction(async (mdb) => {
try {
const vipKeyList = vipInfo.cdkeys;
const newKeys: VipKey[] = [];
for(let keyTypeString in vipKeyList) {
const keyType = parseInt(keyTypeString);
const keysTexts: string[] = vipKeyList[keyTypeString];
for(let keyText of keysTexts) {
const newKey = new VipKey()
newKey.type = keyType;
newKey.key = keyText;
newKeys.push(newKey);
}
}
await mdb.save(newKeys);
for(let vipUserName in vipInfo.players) {
const oldVipUserInfo = vipInfo.players[vipUserName];
const userKey = vipUserName + '$' + oldVipUserInfo.password;
let user = await mdb.findOne(User, userKey);
if(user && user.isVip()) {
continue;
}
if(!user) {
user = new User();
user.key = userKey;
}
user.vipExpireDate = moment(oldVipUserInfo.expire_date).toDate();
user.victory = oldVipUserInfo.victory || null;
user.words = oldVipUserInfo.words || null;
user = await mdb.save(user);
const newDialogues: UserDialog[] = [];
for(let dialogueCardCodeText in oldVipUserInfo.dialogues) {
const cardCode = parseInt(dialogueCardCodeText);
const dialogueText = oldVipUserInfo.dialogues[dialogueCardCodeText];
const dialogue = new UserDialog();
dialogue.text = dialogueText;
dialogue.cardCode = cardCode;
dialogue.user = user;
newDialogues.push(dialogue);
}
await mdb.save(newDialogues);
}
return true;
} catch (e) {
this.log.warn(`Failed to migrate vip info from previous one: ${e.toString()}`);
return false;
}
});
}
}
......@@ -8,11 +8,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.User = void 0;
const typeorm_1 = require("typeorm");
const UserDialog_1 = require("./UserDialog");
const VipKey_1 = require("./VipKey");
const moment_1 = __importDefault(require("moment"));
let User = class User {
isVip() {
return this.vipExpireDate && moment_1.default().isBefore(this.vipExpireDate);
}
};
__decorate([
typeorm_1.PrimaryColumn({ type: "varchar", length: 128 }),
......@@ -25,7 +33,7 @@ __decorate([
__decorate([
typeorm_1.Index(),
typeorm_1.Column("datetime", { nullable: true }),
__metadata("design:type", String)
__metadata("design:type", Date)
], User.prototype, "vipExpireDate", void 0);
__decorate([
typeorm_1.Column("text", { nullable: true }),
......@@ -39,6 +47,10 @@ __decorate([
typeorm_1.OneToMany(() => UserDialog_1.UserDialog, dialog => dialog.user),
__metadata("design:type", Array)
], User.prototype, "dialogues", void 0);
__decorate([
typeorm_1.OneToMany(() => VipKey_1.VipKey, vipKey => vipKey.usedBy),
__metadata("design:type", Array)
], User.prototype, "usedKeys", void 0);
User = __decorate([
typeorm_1.Entity()
], User);
......
import {Column, Entity, Index, OneToMany, PrimaryColumn} from "typeorm";
import {UserDialog} from "./UserDialog";
import {VipKey} from "./VipKey";
import moment from "moment";
@Entity()
export class User {
......@@ -14,6 +15,10 @@ export class User {
@Column("datetime", {nullable: true})
vipExpireDate: Date;
isVip() {
return this.vipExpireDate && moment().isBefore(this.vipExpireDate);
}
@Column("text", {nullable: true})
victory: string;
......
......@@ -15,4 +15,6 @@ export class UserDialog {
@ManyToOne(() => User, user => user.dialogues)
user: User;
}
......@@ -11,6 +11,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.VipKey = void 0;
const typeorm_1 = require("typeorm");
const User_1 = require("./User");
let VipKey = class VipKey {
toJSON() {
return { key: this.key, type: this.type };
......@@ -29,6 +30,14 @@ __decorate([
typeorm_1.Column("int", { unsigned: true }),
__metadata("design:type", Number)
], VipKey.prototype, "type", void 0);
__decorate([
typeorm_1.Column("tinyint", { unsigned: true, default: 0 }),
__metadata("design:type", Number)
], VipKey.prototype, "isUsed", void 0);
__decorate([
typeorm_1.ManyToOne(() => User_1.User, user => user.usedKeys),
__metadata("design:type", User_1.User)
], VipKey.prototype, "usedBy", void 0);
VipKey = __decorate([
typeorm_1.Entity()
], VipKey);
......
......@@ -13,7 +13,7 @@ export class VipKey {
@Column("int", {unsigned: true})
type: number;
@Column("tinyint", {unsigned: true})
@Column("tinyint", {unsigned: true, default: 0})
isUsed: number;
@ManyToOne(() => User, user => user.usedKeys)
......
......@@ -513,11 +513,6 @@
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
"denque": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
"integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
},
"detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
......@@ -1581,35 +1576,6 @@
}
}
},
"redis": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/redis/-/redis-3.0.2.tgz",
"integrity": "sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ==",
"requires": {
"denque": "^1.4.1",
"redis-commands": "^1.5.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0"
}
},
"redis-commands": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.6.0.tgz",
"integrity": "sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ=="
},
"redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
"integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60="
},
"redis-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
"integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=",
"requires": {
"redis-errors": "^1.0.0"
}
},
"reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
......
......@@ -29,7 +29,6 @@
"pg": "^6.4.2",
"q": "^1.5.1",
"querystring": "^0.2.0",
"redis": "latest",
"request": "latest",
"sqlite3": "latest",
"typeorm": "^0.2.29",
......
......@@ -1312,6 +1312,8 @@
return client.name_vpass;
} else if (settings.modules.mycard.enabled || settings.modules.tournament_mode.enabled || settings.modules.challonge.enabled || client.is_local) {
return client.name;
} else if (client.vip) {
return client.name + "$" + client.vpass;
} else {
return client.ip + ":" + client.name;
}
......@@ -4575,7 +4577,7 @@
ygopro.stoc_send_chat(client, "${chat_order_vip_help}");
ygopro.stoc_send_chat(client, "${chat_order_vip_status}");
ygopro.stoc_send_chat(client, "${chat_order_vip_buy}");
ygopro.stoc_send_chat(client, "${chat_order_vip_password}");
// ygopro.stoc_send_chat(client, "${chat_order_vip_password}")
ygopro.stoc_send_chat(client, "${chat_order_vip_dialogues}");
ygopro.stoc_send_chat(client, "${chat_order_vip_words}");
ygopro.stoc_send_chat(client, "${chat_order_vip_victory}");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment