feat: hide game masters
This commit is contained in:
parent
04ea344bb2
commit
1fd6b326dc
8 changed files with 201 additions and 4213 deletions
|
|
@ -1,10 +1,13 @@
|
||||||
{
|
{
|
||||||
"aowowUrl": "https://wotlkdb.com",
|
"aowowUrl": "https://wotlkdb.com",
|
||||||
"loadDbcs": true,
|
"loadDbcs": true,
|
||||||
|
"hideGameMasters": true,
|
||||||
"realms": [
|
"realms": [
|
||||||
{
|
{
|
||||||
"name": "AzerothCore",
|
"name": "AzerothCore",
|
||||||
"database": {
|
"realmId": 1,
|
||||||
|
"authDatabase": "acore_auth",
|
||||||
|
"charactersDatabase": {
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"user": "root",
|
"user": "root",
|
||||||
|
|
|
||||||
4308
package-lock.json
generated
4308
package-lock.json
generated
File diff suppressed because it is too large
Load diff
19
package.json
19
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "azerothcore-armory",
|
"name": "azerothcore-armory",
|
||||||
"version": "0.5.0",
|
"version": "0.6.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p tsconfig.json",
|
"build": "tsc -p tsconfig.json",
|
||||||
|
|
@ -18,26 +18,25 @@
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/glob": "^7.2.0",
|
"@types/glob": "^7.2.0",
|
||||||
"@types/mkdirp": "^1.0.2",
|
"@types/mkdirp": "^1.0.2",
|
||||||
"@types/node": "^17.0.5",
|
"@types/node": "^17.0.21",
|
||||||
"@types/node-fetch": "^2.5.12",
|
"@types/node-fetch": "^2.6.1",
|
||||||
"@types/pako": "^1.0.3",
|
"@types/pako": "^1.0.3",
|
||||||
"concurrently": "^6.5.1",
|
"concurrently": "^7.0.0",
|
||||||
"nodemon": "^2.0.15",
|
"nodemon": "^2.0.15",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"typescript": "^4.5.4"
|
"typescript": "^4.5.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@supercharge/promise-pool": "^2.1.0",
|
"@supercharge/promise-pool": "^2.1.0",
|
||||||
"camelcase": "^6.2.1",
|
"camelcase": "^6.3.0",
|
||||||
"cli-progress": "^3.9.1",
|
"cli-progress": "^3.10.0",
|
||||||
"express": "^4.17.2",
|
"express": "^4.17.3",
|
||||||
"express-handlebars": "^6.0.2",
|
"express-handlebars": "^6.0.2",
|
||||||
"glob": "^7.2.0",
|
"glob": "^7.2.0",
|
||||||
"glob-promise": "^4.2.2",
|
"glob-promise": "^4.2.2",
|
||||||
"handlebars-helpers": "^0.10.0",
|
|
||||||
"mkdirp": "^1.0.4",
|
"mkdirp": "^1.0.4",
|
||||||
"mysql2": "^2.3.3",
|
"mysql2": "^2.3.3",
|
||||||
"node-fetch": "^2.6.6",
|
"node-fetch": "^2.6.7",
|
||||||
"pako": "^2.0.4",
|
"pako": "^2.0.4",
|
||||||
"pretty-ms": "^7.0.1",
|
"pretty-ms": "^7.0.1",
|
||||||
"source-map-support": "^0.5.21"
|
"source-map-support": "^0.5.21"
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export class Armory {
|
||||||
console.log("Connecting to databases...");
|
console.log("Connecting to databases...");
|
||||||
this.worldDb = await createConnection(this.config.worldDatabase);
|
this.worldDb = await createConnection(this.config.worldDatabase);
|
||||||
for (const realm of this.config.realms) {
|
for (const realm of this.config.realms) {
|
||||||
this.charsDbs[realm.name.toLowerCase()] = await createConnection(realm.database);
|
this.charsDbs[realm.name.toLowerCase()] = await createConnection(realm.charactersDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Starting server...");
|
console.log("Starting server...");
|
||||||
|
|
@ -49,7 +49,6 @@ export class Armory {
|
||||||
partialsDir: path.join(process.cwd(), "static", "partials"),
|
partialsDir: path.join(process.cwd(), "static", "partials"),
|
||||||
layoutsDir: path.join(process.cwd(), "static"),
|
layoutsDir: path.join(process.cwd(), "static"),
|
||||||
defaultLayout: "layout.html",
|
defaultLayout: "layout.html",
|
||||||
helpers: require("handlebars-helpers")(),
|
|
||||||
}));
|
}));
|
||||||
app.set("view engine", "handlebars");
|
app.set("view engine", "handlebars");
|
||||||
app.set("views", path.join(process.cwd(), "static"));
|
app.set("views", path.join(process.cwd(), "static"));
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,15 @@ export interface IDatabaseConfig {
|
||||||
|
|
||||||
export interface IRealmConfig {
|
export interface IRealmConfig {
|
||||||
name: string;
|
name: string;
|
||||||
database: IDatabaseConfig;
|
realmId: number;
|
||||||
|
authDatabase: string;
|
||||||
|
charactersDatabase: IDatabaseConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Config {
|
export class Config {
|
||||||
public aowowUrl: string;
|
public aowowUrl: string;
|
||||||
public loadDbcs: boolean;
|
public loadDbcs: boolean;
|
||||||
|
public hideGameMasters: boolean;
|
||||||
public realms: IRealmConfig[];
|
public realms: IRealmConfig[];
|
||||||
public worldDatabase: IDatabaseConfig;
|
public worldDatabase: IDatabaseConfig;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export interface IColumnSettings {
|
||||||
collation?: string;
|
collation?: string;
|
||||||
formatter?: (data: string | number | null, row: any) => string;
|
formatter?: (data: string | number | null, row: any) => string;
|
||||||
table?: string;
|
table?: string;
|
||||||
|
database?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IColumnJoin {
|
export interface IColumnJoin {
|
||||||
|
|
@ -20,6 +21,7 @@ export interface IColumnJoin {
|
||||||
column1: string;
|
column1: string;
|
||||||
table2: string;
|
table2: string;
|
||||||
column2: string;
|
column2: string;
|
||||||
|
database2?: string;
|
||||||
kind: "INNER" | "FULL OUTER" | "LEFT" | "RIGHT";
|
kind: "INNER" | "FULL OUTER" | "LEFT" | "RIGHT";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +92,11 @@ export class DataTablesSsp {
|
||||||
this.columnSettings = columnSettings;
|
this.columnSettings = columnSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private colSettingsToStr(colSettings: IColumnSettings) {
|
||||||
|
const db = colSettings.database ? ("`" + colSettings.database + "`.") : "";
|
||||||
|
return `${db}\`${colSettings.table || this.table}\`.\`${colSettings.name}\``;
|
||||||
|
}
|
||||||
|
|
||||||
private limit() {
|
private limit() {
|
||||||
if (this.start !== undefined && this.length !== -1) {
|
if (this.start !== undefined && this.length !== -1) {
|
||||||
this.limitSql = `LIMIT ${this.length} OFFSET ${this.start}`;
|
this.limitSql = `LIMIT ${this.length} OFFSET ${this.start}`;
|
||||||
|
|
@ -110,7 +117,7 @@ export class DataTablesSsp {
|
||||||
}
|
}
|
||||||
|
|
||||||
const colSettings = this.columnSettings[requestColumn.data];
|
const colSettings = this.columnSettings[requestColumn.data];
|
||||||
orderBy.push(`\`${colSettings.table || this.table}\`.\`${colSettings.name}\` ${order.dir}`);
|
orderBy.push(`${this.colSettingsToStr(colSettings)} ${order.dir}`);
|
||||||
}
|
}
|
||||||
orderBy.push(`\`${this.table}\`.\`${this.primaryKey}\``);
|
orderBy.push(`\`${this.table}\`.\`${this.primaryKey}\``);
|
||||||
|
|
||||||
|
|
@ -123,7 +130,8 @@ export class DataTablesSsp {
|
||||||
|
|
||||||
private join() {
|
private join() {
|
||||||
for (const join of this.joins) {
|
for (const join of this.joins) {
|
||||||
this.joinSql += `${join.kind} JOIN \`${join.table2}\` ON \`${join.table2}\`.\`${join.column2}\` = \`${join.table1}\`.\`${join.column1}\`\n`;
|
const db2 = join.database2 ? "`" + join.database2 + "`." : "";
|
||||||
|
this.joinSql += `${join.kind} JOIN ${db2}\`${join.table2}\` ON ${db2}\`${join.table2}\`.\`${join.column2}\` = \`${join.table1}\`.\`${join.column1}\`\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -141,7 +149,7 @@ export class DataTablesSsp {
|
||||||
|
|
||||||
const colSettings = this.columnSettings[col.data];
|
const colSettings = this.columnSettings[col.data];
|
||||||
const collate = colSettings.collation !== undefined ? `COLLATE ${colSettings.collation} ` : "";
|
const collate = colSettings.collation !== undefined ? `COLLATE ${colSettings.collation} ` : "";
|
||||||
filterWheres.push(`\`${colSettings.table || this.table}\`.\`${colSettings.name}\` ${collate}LIKE ?`);
|
filterWheres.push(`${this.colSettingsToStr(colSettings)} ${collate}LIKE ?`);
|
||||||
this.filterBindings.push(`%${this.search.value}%`);
|
this.filterBindings.push(`%${this.search.value}%`);
|
||||||
}
|
}
|
||||||
if (filterWheres.length > 0) {
|
if (filterWheres.length > 0) {
|
||||||
|
|
@ -153,9 +161,9 @@ export class DataTablesSsp {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildSql(): string {
|
public sql(): string {
|
||||||
const columns = [
|
const columns = [
|
||||||
...this.columnSettings.map(c => `\`${c.table || this.table}\`.\`${c.name}\``),
|
...this.columnSettings.map(c => this.colSettingsToStr(c)),
|
||||||
...this.extraDataColumns,
|
...this.extraDataColumns,
|
||||||
];
|
];
|
||||||
return `
|
return `
|
||||||
|
|
@ -205,7 +213,7 @@ export class DataTablesSsp {
|
||||||
const recordsFiltered = rows[0].count;
|
const recordsFiltered = rows[0].count;
|
||||||
|
|
||||||
[rows, fields] = await this.db.query({
|
[rows, fields] = await this.db.query({
|
||||||
sql: this.buildSql(),
|
sql: this.sql(),
|
||||||
rowsAsArray: true,
|
rowsAsArray: true,
|
||||||
values: bindings,
|
values: bindings,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ export class CharacterController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const charData = await this.getCharacterData(realmName, charName);
|
const charData = await this.getCharacterData(realm, charName);
|
||||||
if (charData === null) {
|
if (charData === null) {
|
||||||
// Could not find character
|
// Could not find character
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
|
|
@ -203,7 +203,7 @@ export class CharacterController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const charData = await this.getCharacterData(realm.name, charName);
|
const charData = await this.getCharacterData(realm, charName);
|
||||||
if (charData === null) {
|
if (charData === null) {
|
||||||
// Could not find character
|
// Could not find character
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
|
|
@ -232,7 +232,7 @@ export class CharacterController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const charData = await this.getCharacterData(realm.name, charName);
|
const charData = await this.getCharacterData(realm, charName);
|
||||||
if (charData === null) {
|
if (charData === null) {
|
||||||
// Could not find character
|
// Could not find character
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
|
|
@ -256,7 +256,7 @@ export class CharacterController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const charData = await this.getCharacterData(realm.name, character);
|
const charData = await this.getCharacterData(realm, character);
|
||||||
if (charData === null) {
|
if (charData === null) {
|
||||||
// Could not find character
|
// Could not find character
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
|
|
@ -285,13 +285,16 @@ export class CharacterController {
|
||||||
return this.armory.config.realms.find(r => r.name.toLowerCase() === realm.toLowerCase());
|
return this.armory.config.realms.find(r => r.name.toLowerCase() === realm.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getCharacterData(realm: string, character: string | number): Promise<ICharacterData> {
|
private async getCharacterData(realm: IRealmConfig, character: string | number): Promise<ICharacterData> {
|
||||||
const where = typeof character === "string" ? "LOWER(name) = LOWER(?)" : "guid = ?";
|
const where = typeof character === "string" ? "LOWER(name) = LOWER(?)" : "guid = ?";
|
||||||
const [rows, fields] = await this.armory.getCharactersDb(realm).query(`
|
const [rows, fields] = await this.armory.getCharactersDb(realm.name).query(`
|
||||||
SELECT guid, name, race, class, gender, level, skin, face, hairStyle, hairColor, facialStyle, playerFlags, online
|
SELECT \`guid\`, \`name\`, \`race\`, \`class\`, \`gender\`, \`level\`, \`skin\`, \`face\`, \`hairStyle\`, \`hairColor\`, \`facialStyle\`, \`playerFlags\`, \`online\`
|
||||||
FROM characters
|
FROM \`characters\`
|
||||||
WHERE ${where}
|
LEFT JOIN \`${realm.authDatabase}\`.\`account_access\` ON \`account_access\`.\`id\` = \`characters\`.\`account\`
|
||||||
`, [character]);
|
WHERE
|
||||||
|
${where}
|
||||||
|
AND (\`account_access\`.\`id\` IS NULL OR \`account_access\`.\`RealmID\` NOT IN (-1, ${realm.realmId}) OR \`account_access\`.\`gmlevel\` = 0 OR ? = 0)
|
||||||
|
`, [character, this.armory.config.hideGameMasters ? 1 : 0]);
|
||||||
|
|
||||||
if ((rows as RowDataPacket[]).length === 0) {
|
if ((rows as RowDataPacket[]).length === 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,11 @@ const classFiles = {
|
||||||
|
|
||||||
export class IndexController {
|
export class IndexController {
|
||||||
private armory: Armory;
|
private armory: Armory;
|
||||||
|
private charsetCache: { [key: string]: string };
|
||||||
|
|
||||||
public constructor(armory: Armory) {
|
public constructor(armory: Armory) {
|
||||||
this.armory = armory;
|
this.armory = armory;
|
||||||
|
this.charsetCache = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async index(req: express.Request, res: express.Response): Promise<void> {
|
public async index(req: express.Request, res: express.Response): Promise<void> {
|
||||||
|
|
@ -53,18 +55,22 @@ export class IndexController {
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = this.armory.getCharactersDb(realm.name);
|
const db = this.armory.getCharactersDb(realm.name);
|
||||||
let [rows, fields] = await db.query(`
|
|
||||||
SELECT CCSA.character_set_name FROM information_schema.\`TABLES\` T,
|
|
||||||
information_schema.\`COLLATION_CHARACTER_SET_APPLICABILITY\` CCSA
|
|
||||||
WHERE CCSA.collation_name = T.table_collation
|
|
||||||
AND T.table_schema = "${db.config.database}"
|
|
||||||
AND T.table_name = "characters"
|
|
||||||
`);
|
|
||||||
const charSet = rows[0].character_set_name;
|
|
||||||
|
|
||||||
const ssp = new DataTablesSsp(req.query, db, "characters", "guid", [
|
if (!(realm.name in this.charsetCache)) {
|
||||||
|
let [rows, fields] = await db.query(`
|
||||||
|
SELECT CCSA.character_set_name FROM information_schema.\`TABLES\` T,
|
||||||
|
information_schema.\`COLLATION_CHARACTER_SET_APPLICABILITY\` CCSA
|
||||||
|
WHERE CCSA.collation_name = T.table_collation
|
||||||
|
AND T.table_schema = "${db.config.database}"
|
||||||
|
AND T.table_name = "characters"
|
||||||
|
`);
|
||||||
|
this.charsetCache[realm.name] = rows[0].character_set_name;
|
||||||
|
}
|
||||||
|
const charSet = this.charsetCache[realm.name];
|
||||||
|
|
||||||
|
let ssp = new DataTablesSsp(req.query, db, "characters", "guid", [
|
||||||
{ name: "name", collation: `${charSet}_general_ci` },
|
{ name: "name", collation: `${charSet}_general_ci` },
|
||||||
{ name: "name", table: "guild" },
|
{ table: "guild", name: "name" },
|
||||||
{ name: "level" },
|
{ name: "level" },
|
||||||
{ name: "race", formatter: (race, row) => `${raceFiles[race]}_${row[6] === 0 ? "male" : "female"}` },
|
{ name: "race", formatter: (race, row) => `${raceFiles[race]}_${row[6] === 0 ? "male" : "female"}` },
|
||||||
{ name: "class", formatter: cls => classFiles[cls] },
|
{ name: "class", formatter: cls => classFiles[cls] },
|
||||||
|
|
@ -76,6 +82,11 @@ export class IndexController {
|
||||||
];
|
];
|
||||||
ssp.extraDataColumns = ["`characters`.`gender`"];
|
ssp.extraDataColumns = ["`characters`.`gender`"];
|
||||||
|
|
||||||
|
if (this.armory.config.hideGameMasters) {
|
||||||
|
ssp.joins.push({ table1: "characters", column1: "account", table2: "account_access", column2: "id", database2: realm.authDatabase, kind: "LEFT" });
|
||||||
|
ssp = ssp.where(`\`account_access\`.\`id\` IS NULL OR \`account_access\`.\`RealmID\` NOT IN (-1, ${realm.realmId}) OR \`account_access\`.\`gmlevel\` = 0`);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await ssp
|
const result = await ssp
|
||||||
.where("`deleteInfos_Account` IS NULL")
|
.where("`deleteInfos_Account` IS NULL")
|
||||||
.run();
|
.run();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue