From 6d523d942312ac9e9a66c91298203875d85fb73a Mon Sep 17 00:00:00 2001 From: Pablo Corso Date: Wed, 28 Jun 2023 13:16:03 +0200 Subject: [PATCH] feat(settings): add battle notifier settings --- .prettierrc.json | 6 ++ src/api/player.js | 107 ++++++++++++++++++++++++++++++++- src/config.defaults.js | 6 +- src/data/models/BnKuskiRule.js | 53 ++++++++++++++++ src/data/models/Setting.js | 5 ++ src/data/models/index.js | 15 +++++ src/utils/auth.js | 12 ++-- 7 files changed, 197 insertions(+), 7 deletions(-) create mode 100644 src/data/models/BnKuskiRule.js diff --git a/.prettierrc.json b/.prettierrc.json index e69de29b..f97bdbe5 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "printWidth": 80, + "singleQuote": true, + "trailingComma": "all", + "arrowParens": "avoid" +} diff --git a/src/api/player.js b/src/api/player.js index bf2f2b73..a337098e 100644 --- a/src/api/player.js +++ b/src/api/player.js @@ -1,7 +1,7 @@ import express from 'express'; import { Op } from 'sequelize'; import { like, searchLimit, searchOffset } from '#utils/database'; -import { authContext } from '#utils/auth'; +import { authContext, authDiscord } from '#utils/auth'; import { pick, omit } from 'lodash-es'; import { Team, @@ -11,6 +11,7 @@ import { LevelStats, Level, Setting, + BnKuskiRule, } from '../data/models'; const router = express.Router(); @@ -88,6 +89,82 @@ const ChangeSettings = async data => { return 1; }; +const BnKuskiRuleAttributes = [ + 'BattleTypes', + 'Designers', + 'LevelPatterns', + 'BattleAttributes', + 'MinDuration', + 'MaxDuration', + 'IgnoreList', +]; + +const BnSettings = async DiscordId => { + const get = await Setting.findOne({ + where: { DiscordId }, + attributes: ['KuskiIndex', 'DiscordId', 'BnEnabled'], + include: [ + { + model: BnKuskiRule, + as: 'BnKuskiRules', + attributes: BnKuskiRuleAttributes, + }, + ], + }); + return get; +}; + +const AllActiveBnSettings = async () => { + const get = await Setting.findAll({ + attributes: ['KuskiIndex', 'DiscordId', 'BnEnabled'], + include: [ + { + model: BnKuskiRule, + as: 'BnKuskiRules', + attributes: BnKuskiRuleAttributes, + required: true, + }, + ], + }); + return get; +}; + +const ChangeBnEnabledSetting = async data => { + const setting = await Setting.findOne({ + where: { DiscordId: data.DiscordId }, + attributes: ['KuskiIndex'], + }); + if (setting?.KuskiIndex) { + await Setting.update( + { BnEnabled: data.BnEnabled }, + { where: { KuskiIndex: setting.KuskiIndex } }, + ); + } + return 1; +}; + +const ChangeBnSettings = async data => { + const setting = await Setting.findOne({ + where: { DiscordId: data.DiscordId }, + attributes: ['KuskiIndex'], + }); + const KuskiIndex = setting?.KuskiIndex; + if (KuskiIndex && data.BnKuskiRules.length > 0) { + // first time setup, turn notification on by default + const currentRules = await BnKuskiRule.findAll({ where: { KuskiIndex } }); + const isFirstTimeSetup = currentRules.length === 0; + if (isFirstTimeSetup) { + await Setting.update({ BnEnabled: 1 }, { where: { KuskiIndex } }); + } + + // override existing rules with new ones + await BnKuskiRule.destroy({ where: { KuskiIndex } }); + const newRules = data.BnKuskiRules.map(rule => ({ ...rule, KuskiIndex })); + await BnKuskiRule.bulkCreate(newRules); + } + return 1; +}; + const Player = async (IdentifierType, KuskiIdentifier, currentUser) => { const query = { where: {}, @@ -310,6 +387,34 @@ router res.sendStatus(401); } }) + .get('/bn/:DiscordId/linked', authDiscord, async (req, res) => { + const data = await Setting.findOne({ + where: { DiscordId: req.params.DiscordId }, + }); + res.json(Boolean(data)); + }) + .get('/bn/:DiscordId', authDiscord, async (req, res) => { + const data = await BnSettings(req.params.DiscordId); + res.json(data); + }) + .get('/bn', authDiscord, async (req, res) => { + const data = await AllActiveBnSettings(); + res.json(data); + }) + .post('/bn/:DiscordId/toggle/:BnEnabled', authDiscord, async (req, res) => { + const data = await ChangeBnEnabledSetting({ + DiscordId: req.params.DiscordId, + BnEnabled: Number(req.params.BnEnabled), + }); + res.json(data); + }) + .post('/bn/:DiscordId', authDiscord, async (req, res) => { + const data = await ChangeBnSettings({ + ...req.body, + DiscordId: req.params.DiscordId, + }); + res.json(data); + }) .post('/ignore/:Kuski', async (req, res) => { const auth = authContext(req); if (auth.auth) { diff --git a/src/config.defaults.js b/src/config.defaults.js index 1368c26d..ea665578 100644 --- a/src/config.defaults.js +++ b/src/config.defaults.js @@ -49,7 +49,8 @@ export default { // auth // eslint-disable-next-line prettier/prettier - jwtSecret: 'eAwI4zcTDd4Pvc8QtN9z57Fqsr4ENNcTpK1x4A1dCLj0Y44OravXZDzNbA-4VEwAIh1Hw3vn1nhB9ygWLqAGE4GiX6hjjLsJi8IJ', + jwtSecret: + 'eAwI4zcTDd4Pvc8QtN9z57Fqsr4ENNcTpK1x4A1dCLj0Y44OravXZDzNbA-4VEwAIh1Hw3vn1nhB9ygWLqAGE4GiX6hjjLsJi8IJ', jwtAlgo: 'HS256', recaptcha: { client: '6Le-n9QUAAAAAG-3bYyysXddxwD6I6iJeDBTHf2r', @@ -76,6 +77,7 @@ export default { admin: 'admin', }, apiAuth: '', // Authorization header sent by game events - url: 'https://test.elma.online/', // url used in discord messages + url: 'https://test.elma.online/', // url used in discord messages, + bnAuth: 'e5f13420-cf17-4fd5-8cc9-c96959d1048f', // Authorization header sent from BN }, }; diff --git a/src/data/models/BnKuskiRule.js b/src/data/models/BnKuskiRule.js new file mode 100644 index 00000000..24a885c9 --- /dev/null +++ b/src/data/models/BnKuskiRule.js @@ -0,0 +1,53 @@ +import DataType from 'sequelize'; +import Model from '../sequelize'; + +const Setting = Model.define('bn_kuski_rule', { + BnKuskiRuleIndex: { + type: DataType.INTEGER, + autoIncrement: true, + allowNull: false, + primaryKey: true, + }, + KuskiIndex: { + type: DataType.INTEGER, + allowNull: false, + defaultValue: 0, + }, + BattleTypes: { + type: DataType.STRING(255), + allowNull: true, + defaultValue: null, + }, + Designers: { + type: DataType.STRING(255), + allowNull: true, + defaultValue: null, + }, + LevelPatterns: { + type: DataType.STRING(255), + allowNull: true, + defaultValue: null, + }, + BattleAttributes: { + type: DataType.STRING(255), + allowNull: true, + defaultValue: null, + }, + MinDuration: { + type: DataType.INTEGER, + allowNull: true, + defaultValue: 0, + }, + MaxDuration: { + type: DataType.INTEGER, + allowNull: true, + defaultValue: 0, + }, + IgnoreList: { + type: DataType.INTEGER, + allowNull: false, + defaultValue: 0, + }, +}); + +export default Setting; diff --git a/src/data/models/Setting.js b/src/data/models/Setting.js index a1fac056..5a55200c 100644 --- a/src/data/models/Setting.js +++ b/src/data/models/Setting.js @@ -60,6 +60,11 @@ const Setting = Model.define( allowNull: false, defaultValue: 1, }, + BnEnabled: { + type: DataType.INTEGER, + allowNull: false, + defaultValue: 0, + }, }, { indexes: [ diff --git a/src/data/models/index.js b/src/data/models/index.js index 780542a4..54e787a4 100644 --- a/src/data/models/index.js +++ b/src/data/models/index.js @@ -59,6 +59,7 @@ import MultiTimeFile from './MultiTimeFile'; import Crippled from './Crippled'; import Recap from './Recap'; import ReplayLog from './ReplayLog'; +import BnKuskiRule from './BnKuskiRule'; Replay.belongsTo(Kuski, { foreignKey: 'DrivenBy', @@ -511,6 +512,18 @@ Recap.belongsTo(Replay, { as: 'ReplayData', }); +Setting.hasMany(BnKuskiRule, { + foreignKey: 'KuskiIndex', + sourceKey: 'KuskiIndex', + as: 'BnKuskiRules', +}); + +BnKuskiRule.belongsTo(Setting, { + foreignKey: 'KuskiIndex', + targetKey: 'KuskiIndex', + as: 'SettingData', +}); + function sync(...args) { return sequelize.sync(...args); } @@ -576,4 +589,6 @@ export { Crippled, Recap, ReplayLog, + ReplayTags, + BnKuskiRule, }; // add the data model here as well so it exports diff --git a/src/utils/auth.js b/src/utils/auth.js index 2b99addb..2f872dfe 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -80,10 +80,7 @@ export const auth = async body => { }; } if (kuskiData.dataValues.Password) { - const md5 = crypto - .createHash('md5') - .update(password) - .digest('hex'); + const md5 = crypto.createHash('md5').update(password).digest('hex'); if (md5 === kuskiData.dataValues.Password) { if (kuskiData.dataValues.Salt) { await addSha3( @@ -124,3 +121,10 @@ export function authContext(req) { } return { auth: false, userid: 0 }; } + +export function authDiscord(req, res, next) { + if (req.header('Authorization') === config.discord.bnAuth) { + return next(); + } + return res.sendStatus(401); +}