Статистика пользователя и сервера на сайте
Удалён лишний файл
Отключена комадна someone
Фикс currentURL в переменных страниц
Обновлена локализация
This commit is contained in:
JonnyBro 2022-01-13 18:55:13 +05:00
parent 373c861a10
commit b0deb2e447
27 changed files with 520 additions and 156 deletions

View file

@ -63,6 +63,7 @@ class Profile extends Command {
}) })
}) })
.setImage("attachment://achievements.png") .setImage("attachment://achievements.png")
.addField(this.client.customEmojis.link + " " + message.translate("economy/profile:LINK"), `[${message.translate("economy/profile:LINK_TEXT")}](https://jaba.pp.ua/user/${member.user.id}/${message.guild.id})`)
.addField(message.translate("economy/profile:BIO"), userData.bio ? userData.bio : message.translate("economy/profile:NO_BIO")) .addField(message.translate("economy/profile:BIO"), userData.bio ? userData.bio : message.translate("economy/profile:NO_BIO"))
.addField(message.translate("economy/profile:CASH"), `**${memberData.money}** ${message.getNoun(memberData.money, message.translate("misc:NOUNS:CREDIT:1"), message.translate("misc:NOUNS:CREDIT:2"), message.translate("misc:NOUNS:CREDIT:5"))}`, true) .addField(message.translate("economy/profile:CASH"), `**${memberData.money}** ${message.getNoun(memberData.money, message.translate("misc:NOUNS:CREDIT:1"), message.translate("misc:NOUNS:CREDIT:2"), message.translate("misc:NOUNS:CREDIT:5"))}`, true)
.addField(message.translate("economy/profile:BANK"), `**${memberData.bankSold}** ${message.getNoun(memberData.bankSold, message.translate("misc:NOUNS:CREDIT:1"), message.translate("misc:NOUNS:CREDIT:2"), message.translate("misc:NOUNS:CREDIT:5"))}`, true) .addField(message.translate("economy/profile:BANK"), `**${memberData.bankSold}** ${message.getNoun(memberData.bankSold, message.translate("misc:NOUNS:CREDIT:1"), message.translate("misc:NOUNS:CREDIT:2"), message.translate("misc:NOUNS:CREDIT:5"))}`, true)

View file

@ -41,13 +41,14 @@ class Serverinfo extends Command {
.setThumbnail(guild.iconURL({ .setThumbnail(guild.iconURL({
dynamic: true dynamic: true
})) }))
.addField(this.client.customEmojis.link + " " + message.translate("general/serverinfo:LINK"), `[${message.translate("general/serverinfo:LINK_TEXT")}](https://jaba.pp.ua/stats/${guild.id})`)
.addField(this.client.customEmojis.title + message.translate("common:NAME"), guild.name, true) .addField(this.client.customEmojis.title + message.translate("common:NAME"), guild.name, true)
.addField(this.client.customEmojis.calendar + message.translate("common:CREATION"), message.printDate(guild.createdAt), true) .addField(this.client.customEmojis.calendar + message.translate("common:CREATION"), message.printDate(guild.createdAt), true)
.addField(this.client.customEmojis.users + message.translate("common:MEMBERS"), .addField(this.client.customEmojis.users + message.translate("common:MEMBERS"),
`${guild.members.cache.filter(m => !m.user.bot).size} ${message.getNoun(guild.members.cache.filter(m => !m.user.bot).size, message.translate("misc:NOUNS:MEMBERS:1"), message.translate("misc:NOUNS:MEMBERS:2"), message.translate("misc:NOUNS:MEMBERS:5"))}` + `${guild.members.cache.filter(m => !m.user.bot).size} ${message.getNoun(guild.members.cache.filter(m => !m.user.bot).size, message.translate("misc:NOUNS:MEMBERS:1"), message.translate("misc:NOUNS:MEMBERS:2"), message.translate("misc:NOUNS:MEMBERS:5"))}` +
"\n" + `${guild.members.cache.filter(m => m.user.bot).size} ${message.getNoun(guild.members.cache.filter(m => m.user.bot).size, message.translate("misc:NOUNS:BOTS:1"), message.translate("misc:NOUNS:BOTS:2"), message.translate("misc:NOUNS:BOTS:5"))}`, true "\n" + `${guild.members.cache.filter(m => m.user.bot).size} ${message.getNoun(guild.members.cache.filter(m => m.user.bot).size, message.translate("misc:NOUNS:BOTS:1"), message.translate("misc:NOUNS:BOTS:2"), message.translate("misc:NOUNS:BOTS:5"))}`, true
) )
.addField(this.client.customEmojis.afk + message.translate("general/serverinfo:AFK_CHANNEL"), guild.afkChannel.toString() || message.translate("general/serverinfo:NO_AFK_CHANNEL"), true) .addField(this.client.customEmojis.afk + message.translate("general/serverinfo:AFK_CHANNEL"), guild.afkChannel ? guild.afkChannel.toString() : message.translate("general/serverinfo:NO_AFK_CHANNEL"), true)
.addField(this.client.customEmojis.id + message.translate("common:ID"), guild.id, true) .addField(this.client.customEmojis.id + message.translate("common:ID"), guild.id, true)
.addField(this.client.customEmojis.crown + message.translate("common:OWNER"), owner.toString(), true) .addField(this.client.customEmojis.crown + message.translate("common:OWNER"), owner.toString(), true)
.addField(this.client.customEmojis.boost + message.translate("general/serverinfo:BOOSTS"), guild.premiumSubscriptionCount.toString() || "0", true) .addField(this.client.customEmojis.boost + message.translate("general/serverinfo:BOOSTS"), guild.premiumSubscriptionCount.toString() || "0", true)

View file

@ -6,7 +6,7 @@ class Someone extends Command {
super(client, { super(client, {
name: "someone", name: "someone",
dirname: __dirname, dirname: __dirname,
enabled: true, enabled: false,
guildOnly: true, guildOnly: true,
aliases: ["somebody"], aliases: ["somebody"],
memberPermissions: [], memberPermissions: [],

View file

@ -46,9 +46,8 @@ class Stats extends Command {
.addField(message.translate("general/stats:CREDITS_TITLE"), message.translate("general/stats:CREDITS_CONTENT", { .addField(message.translate("general/stats:CREDITS_TITLE"), message.translate("general/stats:CREDITS_CONTENT", {
donators: ["**`Добрый Спецназ#8801`** - Тестер, генератор идей"].join("\n"), donators: ["**`Добрый Спецназ#8801`** - Тестер, генератор идей"].join("\n"),
translators: ["**`Jonny_Bro#4226`** (:flag_ru:)"].join("\n") translators: ["**`Jonny_Bro#4226`** (:flag_ru:)"].join("\n")
})); }))
.addField(this.client.customEmojis.link + " " + message.translate("general/stats:LINKS_TITLE"), message.translate("misc:STATS_FOOTER", {
statsEmbed.addField(this.client.customEmojis.link + " " + message.translate("general/stats:LINKS_TITLE"), message.translate("misc:STATS_FOOTER", {
dashboardLink: "https://jaba.pp.ua/", dashboardLink: "https://jaba.pp.ua/",
docsLink: "https://jaba.pp.ua/docs/", docsLink: "https://jaba.pp.ua/docs/",
donateLink: "https://qiwi.com/n/JONNYBRO/", donateLink: "https://qiwi.com/n/JONNYBRO/",

View file

@ -1,3 +1,4 @@
/* eslint-disable no-unused-vars */
const Command = require("../../base/Command"); const Command = require("../../base/Command");
class Eval extends Command { class Eval extends Command {
@ -16,7 +17,7 @@ class Eval extends Command {
}); });
} }
async run(message) { async run(message, data) {
const content = message.content.split(" ").slice(1).join(" "); const content = message.content.split(" ").slice(1).join(" ");
const result = new Promise((resolve) => resolve(eval(content))); const result = new Promise((resolve) => resolve(eval(content)));

View file

@ -14,6 +14,7 @@ module.exports.load = async(client) => {
discordAPIRouter = require("./routes/discord"), discordAPIRouter = require("./routes/discord"),
logoutRouter = require("./routes/logout"), logoutRouter = require("./routes/logout"),
profileRouter = require("./routes/profile"), profileRouter = require("./routes/profile"),
userRouter = require("./routes/user"),
guildStatsRouter = require("./routes/guild-stats"), guildStatsRouter = require("./routes/guild-stats"),
guildManagerRouter = require("./routes/guild-manager"), guildManagerRouter = require("./routes/guild-manager"),
docsManagerRouter = require("./routes/docs"); docsManagerRouter = require("./routes/docs");
@ -52,6 +53,7 @@ module.exports.load = async(client) => {
.use("/manage", guildManagerRouter) .use("/manage", guildManagerRouter)
.use("/stats", guildStatsRouter) .use("/stats", guildStatsRouter)
.use("/profile", profileRouter) .use("/profile", profileRouter)
.use("/user", userRouter)
.use("/", mainRouter) .use("/", mainRouter)
.use("/docs", docsManagerRouter) .use("/docs", docsManagerRouter)
.use(CheckAuth, function(req, res) { .use(CheckAuth, function(req, res) {

View file

@ -1,3 +1,12 @@
### JaBa v3.2.7
* Добавлено
* Статистика сервера на сайте ([пример](https://jaba.pp.ua/stats/651412418202959872)).
* Профиль пользователя определённого сервера на сайте ([пример](https://jaba.pp.ua/user/281361531411890186/651412418202959872))
Ссылки на статистику сервера и профиль пользователя можно найти в *serverinfo* и *profile (@пользователь)* соответственно.
* Изменения
* Отключены команда *someone* и тэг *@someone*.
### JaBa v3.2.7 ### JaBa v3.2.7
* Добавлено * Добавлено
* Некоторая информация о вашем профиле на сайте, на страницах серверов и в настройках. * Некоторая информация о вашем профиле на сайте, на страницах серверов и в настройках.
@ -15,7 +24,6 @@
* Команда *setafk* и ответ бота автоматически удаляются через 10 секунд. * Команда *setafk* и ответ бота автоматически удаляются через 10 секунд.
* Новые карточки при входе и выходе пользователей * Новые карточки при входе и выходе пользователей
(Я не дизайнер, не бейте :(). (Я не дизайнер, не бейте :().
* Обновлена локализация для карточек.
### JaBa v3.2.5 ### JaBa v3.2.5
* Изменения * Изменения
@ -77,7 +85,6 @@
* Некорректное описание *seek*. * Некорректное описание *seek*.
* Некорректная работа *seek*. * Некорректная работа *seek*.
* Некорректное описание *unban*. * Некорректное описание *unban*.
* Мелкие правки в локализации.
### JaBa v3.1.5 ### JaBa v3.1.5
* Изменено * Изменено
@ -114,7 +121,7 @@
### JaBa v3.1 ### JaBa v3.1
* Изменено * Изменено
* Обновлена русская локализация, исправлены орфографические ошибки. * Исправлены орфографические ошибки в русской локализации.
* Отключёна английская локализация. * Отключёна английская локализация.
* Исправлены ошибки. * Исправлены ошибки.

View file

@ -1,19 +0,0 @@
const express = require("express"),
router = express.Router(),
fs = require("fs"),
marked = require("marked");
router.get("/", function (req, res) {
var md = function (filename) {
return marked.parse(fs.readFileSync("./dashboard/views/docs/" + filename, "utf8"));
};
res.render("commands", {
user: req.userInfos,
translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}`,
"md": md
});
});
module.exports = router;

View file

@ -5,7 +5,7 @@ router.get("/", function (req, res) {
res.render("docs", { res.render("docs", {
user: req.userInfos, user: req.userInfos,
translate: req.translate, translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}` currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
}); });
}); });

View file

@ -10,7 +10,7 @@ router.get("/:serverID", CheckAuth, async(req, res) => {
return res.render("404", { return res.render("404", {
user: req.userInfos, user: req.userInfos,
translate: req.translate, translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}` currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
}); });
} }
@ -25,7 +25,7 @@ router.get("/:serverID", CheckAuth, async(req, res) => {
translate: req.translate, translate: req.translate,
bot: req.client, bot: req.client,
convertTime: req.convertTime, convertTime: req.convertTime,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}` currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
}); });
}); });
@ -36,7 +36,7 @@ router.post("/:serverID", CheckAuth, async(req, res) => {
return res.render("404", { return res.render("404", {
user: req.userInfos, user: req.userInfos,
translate: req.translate, translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}` currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
}); });
} }
@ -44,7 +44,7 @@ router.post("/:serverID", CheckAuth, async(req, res) => {
const data = req.body; const data = req.body;
if (data.language) { if (data.language) {
const language = req.client.languages.find((language) => language.aliases[0].toLowerCase() === data.language.toLowerCase()); const language = req.client.languages.find((language) => language.nativeName.toLowerCase() === data.language.toLowerCase());
if (language) guildData.language = language.name; if (language) guildData.language = language.name;
if (data.prefix.length >= 1 && data.prefix.length < 2000) guildData.prefix = data.prefix; if (data.prefix.length >= 1 && data.prefix.length < 2000) guildData.prefix = data.prefix;

View file

@ -1,8 +1,7 @@
const express = require("express"), const express = require("express"),
utils = require("../utils"), utils = require("../utils"),
CheckAuth = require("../auth/CheckAuth"), CheckAuth = require("../auth/CheckAuth"),
router = express.Router(), router = express.Router();
generator = require("colors-generator");
router.get("/:serverID", CheckAuth, async (req, res) => { router.get("/:serverID", CheckAuth, async (req, res) => {
// Check if the user has the permissions to edit this guild // Check if the user has the permissions to edit this guild
@ -10,19 +9,19 @@ router.get("/:serverID", CheckAuth, async(req, res) => {
if (!guild || !req.userInfos.displayedGuilds || !req.userInfos.displayedGuilds.find((g) => g.id === req.params.serverID)) { if (!guild || !req.userInfos.displayedGuilds || !req.userInfos.displayedGuilds.find((g) => g.id === req.params.serverID)) {
return res.render("404", { return res.render("404", {
user: req.userInfos, user: req.userInfos,
language: req.language, translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}` currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
}); });
} }
// Fetch guild informations // Fetch guild informations
const guildInfos = await utils.fetchGuild(guild.id, req.client, req.user.guilds); const membersData = await req.client.membersData.find({
guildID: guild.id
const membersData = await req.client.membersData.find({ guildID: guild.id }).lean(); }).lean();
const leaderboards = { const leaderboards = {
money: sortArrayOfObjects("money", membersData), money: utils.sortArrayOfObjects("money", membersData),
level: sortArrayOfObjects("level", membersData) level: utils.sortArrayOfObjects("level", membersData)
}; };
for (const cat in leaderboards) { for (const cat in leaderboards) {
@ -36,77 +35,13 @@ router.get("/:serverID", CheckAuth, async(req, res) => {
}; };
res.render("stats/guild", { res.render("stats/guild", {
stats,
commands: getCommands(guildInfos.commands.filter((c) => c.date > Date.now()-604800000)),
commandsUsage: getCommandsUsage(guildInfos.commands),
user: req.userInfos, user: req.userInfos,
language: req.language, stats,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}`, bot: req.client,
guildID: guild.id,
translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`,
}); });
}); });
module.exports = router; module.exports = router;
function getCommands(commands) {
const aDateCommand = {};
commands.forEach((cmd) => {
const tDate = formatDate(new Date(cmd.date));
if (aDateCommand[tDate]) aDateCommand[tDate]++;
else aDateCommand[tDate] = 1;
});
return aDateCommand;
}
function getCommandsUsage(commands) {
const objectCount = commands.reduce((acc, curr) => {
if (typeof acc[curr.command] == "undefined") acc[curr.command] = 1;
else acc[curr.command] += 1;
return acc;
}, {});
const percentages = getPercentagePerKey(objectCount); // [ { key: "help", percentage: 20 } ]
const colors = generator.generate("#86bff2", percentages.length).get();
let i = 0;
percentages.forEach((p) => {
p.color = colors[i];
i++;
});
return percentages;
}
function getPercentagePerKey(myArray) {
const sum = getSum(myArray);
const arrayWithPercentages = [];
for (const key in myArray) {
const val = myArray[key];
const percentage = Math.round((val / sum) * 100);
arrayWithPercentages.push({key, percentage});
}
return arrayWithPercentages;
}
function getSum(myArray) {
let sum = 0;
for (const key in myArray) sum += myArray[key];
return sum;
}
function sortArrayOfObjects(key, arr) {
const array = arr.slice(0);
return array.sort((a, b) => {
return b[key] - a[key];
});
}
function formatDate(date) {
let dd = date.getDate();
let mm = date.getMonth() + 1;
if (dd < 10) dd = `0${dd}`;
if (mm < 10) mm = `0${mm}`;
date = `${mm}/${dd}`;
return date;
}

View file

@ -10,7 +10,7 @@ router.get("/selector", CheckAuth, async(req, res) => {
res.render("selector", { res.render("selector", {
user: req.userInfos, user: req.userInfos,
translate: req.translate, translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}` currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
}); });
}); });

View file

@ -6,9 +6,10 @@ const express = require("express"),
router.get("/", CheckAuth, async function(req, res) { router.get("/", CheckAuth, async function(req, res) {
res.render("profile", { res.render("profile", {
user: req.userInfos, user: req.userInfos,
bot: req.client,
translate: req.translate, translate: req.translate,
printDate: req.printDate, printDate: req.printDate,
currentURL: `${req.client.config.dashboard.baseURL}/${req.originalUrl}` currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
}); });
}); });

38
dashboard/routes/user.js Normal file
View file

@ -0,0 +1,38 @@
const express = require("express"),
utils = require("../utils"),
CheckAuth = require("../auth/CheckAuth"),
router = express.Router();
// Gets user page
router.get("/:userID/:serverID", CheckAuth, async function (req, res) {
const guild = req.client.guilds.cache.get(req.params.serverID);
if (!guild || !req.userInfos.displayedGuilds || !req.userInfos.displayedGuilds.find((g) => g.id === req.params.serverID)) {
return res.render("404", {
user: req.userInfos,
translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
});
}
const guildData = await req.client.findOrCreateGuild({ id: guild.id });
await utils.fetchUser({
id: req.params.userID
}, req.client).catch(() => {
res.render("404", {
user: req.userInfos,
translate: req.translate,
currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
});
});
res.render("user", {
user: req.userInfos,
guild: guildData,
bot: req.client,
translate: req.translate,
printDate: req.printDate,
currentURL: `${req.client.config.dashboard.baseURL}${req.originalUrl}`
});
});
module.exports = router;

View file

@ -1,18 +1,5 @@
const { Permissions } = require("discord.js"); const { Permissions } = require("discord.js");
/**
* Fetch guild informations
* @param {string} guildID The ID of the guild to fetch
* @param {object} client The discord client instance
* @param {array} guilds The user guilds
*/
async function fetchGuild(guildID, client, guilds) {
const guild = client.guilds.cache.get(guildID);
const conf = await client.findOrCreateGuild({ id:guild.id });
return { ...guild, ...conf.toJSON(), ...guilds.find((g) => g.id === guild.id) };
}
/** /**
* Fetch user informations (stats, guilds, etc...) * Fetch user informations (stats, guilds, etc...)
* @param {object} userData The oauth2 user informations * @param {object} userData The oauth2 user informations
@ -24,6 +11,7 @@ async function fetchUser(userData, client, query) {
if (userData.guilds) { if (userData.guilds) {
userData.guilds.forEach((guild) => { userData.guilds.forEach((guild) => {
if (!client.guilds.cache.get(guild.id)) return; if (!client.guilds.cache.get(guild.id)) return;
// eslint-disable-next-line no-undef
const perms = new Permissions(BigInt(guild.permissions)); const perms = new Permissions(BigInt(guild.permissions));
if (perms.has(Permissions.FLAGS.MANAGE_GUILD)) guild.admin = true; if (perms.has(Permissions.FLAGS.MANAGE_GUILD)) guild.admin = true;
@ -36,10 +24,72 @@ async function fetchUser(userData, client, query) {
if (userData.displayedGuilds.length < 1) delete userData.displayedGuilds; if (userData.displayedGuilds.length < 1) delete userData.displayedGuilds;
} }
const user = await client.users.fetch(userData.id); const user = await client.users.fetch(userData.id);
const userDb = await client.findOrCreateUser({ id: user.id }, true); const userDb = await client.findOrCreateUser({
const userInfos = { ...user.toJSON(), ...userDb, ...userData }; id: user.id
}, true);
const userInfos = {
...user.toJSON(),
...userDb,
...userData
};
return userInfos; return userInfos;
} }
module.exports = { fetchUser, fetchGuild }; /**
* Fetch users informations
* @param {object} array The array of users
* @param {object} client The discord client instance
* @returns {object} The user informations
*/
async function fetchUsers(array, client) {
return new Promise((resolve) => {
const users = [];
array.filter((e) => e.id).forEach((element) => {
client.users.fetch(element.id).then((user) => {
user.username = user.username.replace(/[\W_]+/g, " ");
if (user.username.length > 13) {
user.username = user.username.substr(0, 10) + "...";
}
users.push({
...{
money: element.money,
level: element.level,
rep: element.rep
},
...user.toJSON()
});
});
});
resolve(users);
});
}
/**
* Fetch guild informations
* @param {string} guildID The ID of the guild to fetch
* @param {object} client The discord client instance
* @param {array} guilds The user guilds
* @returns {object} The guild informations
*/
async function fetchGuild(guildID, client, guilds) {
const guild = client.guilds.cache.get(guildID);
const conf = await client.findOrCreateGuild({
id: guild.id
});
return {
...guild,
...conf.toJSON(),
...guilds.find((g) => g.id === guild.id)
};
}
function sortArrayOfObjects(key, arr) {
const array = arr.slice(0);
return array.sort((a, b) => {
return b[key] - a[key];
});
}
module.exports = { fetchUser, fetchUsers, fetchGuild, sortArrayOfObjects };

View file

@ -16,7 +16,7 @@
<!-- Content Header (Page header) --> <!-- Content Header (Page header) -->
<section class="content-header"> <section class="content-header">
<h1> <h1>
404 Error Page Ошибка 404
</h1> </h1>
</section> </section>

View file

@ -16,7 +16,7 @@
<!-- Content Header (Page header) --> <!-- Content Header (Page header) -->
<section class="content-header"> <section class="content-header">
<h1> <h1>
500 Error Page Ошибка 500
</h1> </h1>
</section> </section>

View file

@ -30,7 +30,7 @@
<div class="row"> <div class="row">
<div class="col-md-2 col-sm-6 col-xs-12"> <div class="col-md-2 col-sm-6 col-xs-12">
<div class="info-box"> <div class="info-box">
<span class="info-box-icon bg-green"><i class="fa fa-area-chart"></i></span> <span class="info-box-icon bg-red"><i class="fa fa-area-chart"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text"><%= translate("common:LEVEL") %></span> <span class="info-box-text"><%= translate("common:LEVEL") %></span>
<span class="info-box-number"><%= memberData.level %></span> <span class="info-box-number"><%= memberData.level %></span>
@ -42,9 +42,9 @@
<!-- /.col --> <!-- /.col -->
<div class="col-md-2 col-sm-6 col-xs-12"> <div class="col-md-2 col-sm-6 col-xs-12">
<div class="info-box"> <div class="info-box">
<span class="info-box-icon bg-green"><i class="fa fa-area-chart"></i></span> <span class="info-box-icon bg-red"><i class="fa fa-line-chart"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text"><%= translate("dashboard:EXP") %></span> <span class="info-box-text"><%= translate("economy/profile:EXP").substr(2) %></span>
<span class="info-box-number"><%= memberData.exp %> / <%= 5 * (memberData.level * memberData.level) + 80 * memberData.level + 100 %></span> <span class="info-box-number"><%= memberData.exp %> / <%= 5 * (memberData.level * memberData.level) + 80 * memberData.level + 100 %></span>
</div> </div>
<!-- /.info-box-content --> <!-- /.info-box-content -->
@ -56,7 +56,7 @@
<div class="info-box"> <div class="info-box">
<span class="info-box-icon bg-green"><i class="fa fa-money"></i></span> <span class="info-box-icon bg-green"><i class="fa fa-money"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text"><%= translate("common:CREDITS") %> / <%= translate("economy/transactions:BANK") %></span> <span class="info-box-text"><%= translate("economy/profile:CASH").substr(2) %> / <%= translate("economy/profile:BANK").substr(2) %></span>
<span class="info-box-number"><%= memberData.money %> / <%= memberData.bankSold %></span> <span class="info-box-number"><%= memberData.money %> / <%= memberData.bankSold %></span>
</div> </div>
<!-- /.info-box-content --> <!-- /.info-box-content -->
@ -66,7 +66,7 @@
<!-- /.col --> <!-- /.col -->
<div class="col-md-4 col-sm-6 col-xs-12"> <div class="col-md-4 col-sm-6 col-xs-12">
<div class="info-box"> <div class="info-box">
<span class="info-box-icon bg-green"><i class="fa fa-refresh"></i></span> <span class="info-box-icon bg-yellow"><i class="fa fa-refresh"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text"><%= translate("dashboard:COOLDOWNS") %></span> <span class="info-box-text"><%= translate("dashboard:COOLDOWNS") %></span>
<span class="info-box-number"><%= translate("dashboard:REP") %>: <%= user.cooldowns.rep > Date.now() ? convertTime(user.cooldowns.rep) : translate("dashboard:CAN_USE") %></span> <span class="info-box-number"><%= translate("dashboard:REP") %>: <%= user.cooldowns.rep > Date.now() ? convertTime(user.cooldowns.rep) : translate("dashboard:CAN_USE") %></span>

View file

@ -30,9 +30,9 @@
<div class="row"> <div class="row">
<div class="col-md-3 col-sm-6 col-xs-12"> <div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box"> <div class="info-box">
<span class="info-box-icon bg-green"><i class="fa fa-star-o"></i></span> <span class="info-box-icon bg-yellow"><i class="fa fa-star-o"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text"><%= translate("dashboard:REPUTATION") %></span> <span class="info-box-text"><%= translate("economy/profile:REPUTATION").substr(2) %></span>
<span class="info-box-number"><%= user.rep %></span> <span class="info-box-number"><%= user.rep %></span>
</div> </div>
<!-- /.info-box-content --> <!-- /.info-box-content -->
@ -42,11 +42,64 @@
</div> </div>
<!-- /.row --> <!-- /.row -->
<div class="row"> <div class="row">
<div class="col-md-12">
<!-- Widget: user widget style 1 -->
<div class="box box-widget widget-user">
<!-- Add the bg color to the header using any of the bg-* classes -->
<div class="widget-user-header bg-red">
<h3 class="widget-user-username"><%= user.tag %></h3>
</div>
<div class="widget-user-image">
<img class="img-circle" src="<%= user.displayAvatarURL %>" alt="User Avatar">
</div>
<div class="box-footer">
<div class="row">
<div class="col-sm-12">
<div class="description-block">
<span
class="description-text"><%= user.bio || translate("economy/profile:NO_BIO") %></span>
</div>
</div>
<div class="col-sm-4 border-right">
<div class="description-block">
<h5 class="description-header">
<%= translate("economy/profile:BIRTHDATE").substr(2) %></h5>
<span
class="description-text"><%= user.birthdate ? printDate(new Date(user.birthdate)) : translate("economy/profile:NO_BIRTHDATE") %></span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
<div class="col-sm-4 border-right">
<div class="description-block">
<h5 class="description-header"><%= translate("economy/profile:REGISTERED").substr(2) %></h5>
<span
class="description-text"><%= printDate(new Date(user.registeredAt)) %></span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
<div class="col-sm-4">
<div class="description-block">
<h5 class="description-header">
<%= translate("economy/profile:LOVER").substr(2) %></h5>
<span
class="description-text"><%= !user.lover ? translate("economy/profile:NO_LOVER") : bot.users.cache.get(user.lover).tag %></span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
</div>
</div>
<!-- /.widget-user -->
</div>
<div class="col-md-12"> <div class="col-md-12">
<!-- general form elements --> <!-- general form elements -->
<div class="box box-primary"> <div class="box box-primary">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title"><%= translate("economy/profile:YOUR_PROFILE") %></h3> <h3 class="box-title"><%= translate("common:CONFIGURATION") %></h3>
</div> </div>
<!-- /.box-header --> <!-- /.box-header -->
<!-- form start --> <!-- form start -->
@ -55,12 +108,12 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label><%= translate("economy/profile:BIO") %></label> <label><%= translate("economy/profile:BIO").substr(2) %></label>
<input name="bio" class="form-control" <input name="bio" class="form-control"
placeholder="<%= user.bio || translate("economy/profile:NO_BIO") %>"> placeholder="<%= user.bio || translate("economy/profile:NO_BIO") %>">
</div> </div>
<div class="form-group"> <div class="form-group">
<label><%= translate("economy/profile:BIRTHDATE") %></label> <label><%= translate("economy/profile:BIRTHDATE").substr(2) %></label>
<div class="input-group date"> <div class="input-group date">
<div class="input-group-addon"> <div class="input-group-addon">
<i class="fa fa-calendar"></i> <i class="fa fa-calendar"></i>

View file

@ -0,0 +1,157 @@
<!DOCTYPE html>
<html>
<%- include("../includes/head") %>
<!-- bootstrap datepicker -->
<link rel="stylesheet" href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css">
<body class="hold-transition skin-red sidebar-mini">
<div class="wrapper">
<!-- The header is the topbar -->
<%- include("../includes/header") %>
<!-- The sidebar includes the menu -->
<%- include("../includes/sidebar") %>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1> <%= translate("dashboard:STATS") %> <i> <%= bot.guilds.cache.get(guildID).name %> </i> <small> Dashboard v1.0 </small> </h1>
</section>
<!-- Main content -->
<section class="content">
<!-- Main row -->
<div class="row">
<!-- Left col -->
<section class="col-lg-8 col-sm-2 connectedSortable">
<!-- Custom tabs (Charts with tabs)-->
<div class="nav-tabs-custom">
<!-- Tabs within a box -->
<ul class="nav nav-tabs pull-right">
<li class="active"><a href="#rank-money" data-toggle="tab">
<%= translate("common:CREDITS") %></a></li>
<li><a href="#rank-level" data-toggle="tab">
<%= translate("common:LEVEL") %></a></li>
<li class="pull-left header"><i class="fa fa-trophy"></i>
<%= "Таблица лидеров" %></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="rank-money" style="position: relative; height: 300px;">
<div class="chart">
<canvas id="Crank-money" style="height:230px"></canvas>
</div>
</div>
<div class="tab-pane active" id="rank-level" style="position: relative; height: 300px;">
<div class="chart">
<canvas id="Crank-level" style="height:230px"></canvas>
</div>
</div>
</div>
</div>
<!-- /.nav-tabs-custom -->
</section>
<!-- /.col -->
<div class="col-md-4">
<!-- Widget: user widget style 1 -->
<div class="box box-widget widget-user-2">
<!-- Add the bg color to the header using any of the bg-* classes -->
<div class="widget-user-header bg-yellow">
<div class="widget-user-image">
<img class="img-circle" src="<%= stats.money[0].displayAvatarURL %>"
alt="User Avatar">
</div>
<!-- /.widget-user-image -->
<h3 class="widget-user-username"><a href="/user/<%= stats.money[0].id %>/<%= guildID %>"
style="color:white"><%= stats.money[0].username %></a></h3>
<h5 class="widget-user-desc"><%= translate("dashboard:TOP_CREDITS") %></h5>
</div>
</div>
<!-- /.widget-user -->
</div>
<!-- /.col -->
<div class="col-md-4">
<!-- Widget: user widget style 1 -->
<div class="box box-widget widget-user-2">
<!-- Add the bg color to the header using any of the bg-* classes -->
<div class="widget-user-header bg-red">
<div class="widget-user-image">
<img class="img-circle" src="<%= stats.level[0].displayAvatarURL %>"
alt="User Avatar">
</div>
<!-- /.widget-user-image -->
<h3 class="widget-user-username"><a href="/user/<%= stats.level[0].id %>/<%= guildID %>"
style="color:white"><%= stats.level[0].username %></a></h3>
<h5 class="widget-user-desc"><%= translate("dashboard:TOP_LEVEL") %></h5>
</div>
</div>
<!-- /.widget-user -->
</div>
<!-- ./box -->
</div>
</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<%- include("../includes/footer") %>
</div>
<!-- ./wrapper -->
<!-- bootstrap datepicker -->
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
<!-- ChartJS -->
<script src="/bower_components/chart.js/Chart.js"></script>
<script>
$(function () {
$("#datepicker").datepicker({
autoclose: true
});
/* LEADERBOARD */
let values = ["money", "level"];
values.forEach((value) => {
let members = JSON.parse(`<%- JSON.stringify(stats) %>`)[value];
let data = {
labels: members.map(a => a.username),
datasets: [{
label: "Leaderboard " + value,
fillColor: "#00a65a",
strokeColor: "#00a65a",
pointColor: "#00a65a",
pointStrokeColor: "rgba(60,141,188,1)",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(60,141,188,1)",
data: members.map(a => a[value])
}]
},
leaderboardCanvas = $("#Crank-" + value).get(0).getContext("2d"),
leaderboard = new Chart(leaderboardCanvas),
leaderboardData = data,
leaderboardOptions = {
scaleBeginAtZero: !0,
scaleShowGridLines: !0,
scaleGridLineColor: "rgba(0,0,0,.05)",
scaleGridLineWidth: 1,
scaleShowHorizontalLines: !0,
scaleShowVerticalLines: !0,
barShowStroke: !0,
barStrokeWidth: 2,
barValueSpacing: 5,
barDatasetSpacing: 1,
responsive: !0,
maintainAspectRatio: !0
};
leaderboardOptions.datasetFill = false
leaderboard.Bar(leaderboardData, leaderboardOptions);
});
$(`.tab-content > div[class="tab-pane active"]`).slice(1, 23).removeClass("active");
});
</script>
</body>
</html>

134
dashboard/views/user.ejs Normal file
View file

@ -0,0 +1,134 @@
<!DOCTYPE html>
<html>
<%- include("includes/head") %>
<body class="hold-transition skin-red sidebar-mini">
<div class="wrapper">
<!-- The header is the topbar -->
<%- include("includes/header") %>
<!-- The sidebar includes the menu -->
<%- include("includes/sidebar") %>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1> <%= user.username %> <small> Dashboard v1.0 </small> </h1>
</section>
<section class="content">
<div class="col-md-12">
<!-- Widget: user widget style 1 -->
<div class="box box-widget widget-user">
<!-- Add the bg color to the header using any of the bg-* classes -->
<div class="widget-user-header bg-red">
<h3 class="widget-user-username"><%= user.tag %></h3>
<i><%= bot.guilds.cache.get(guild.id).name %></i>
<p> <i>ID: <%= guild.id %></i> </p>
</div>
<div class="widget-user-image">
<img class="img-circle" src="<%= user.displayAvatarURL %>" alt="User Avatar">
</div>
<div class="box-footer">
<div class="row">
<div class="col-sm-12">
<div class="description-block">
<span
class="description-text"><%= user.bio || translate("economy/profile:NO_BIO") %></span>
</div>
</div>
<div class="col-sm-4 border-right">
<div class="description-block">
<h5 class="description-header">
<%= translate("economy/profile:BIRTHDATE").substr(2) %></h5>
<span
class="description-text"><%= user.birthdate ? printDate(new Date(user.birthdate)) : translate("economy/profile:NO_BIRTHDATE") %></span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
<div class="col-sm-4 border-right">
<div class="description-block">
<h5 class="description-header"><%= translate("economy/profile:REGISTERED").substr(2) %></h5>
<span
class="description-text"><%= printDate(new Date(user.registeredAt)) %></span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
<div class="col-sm-4">
<div class="description-block">
<h5 class="description-header">
<%= translate("economy/profile:LOVER").substr(2) %></h5>
<span
class="description-text"><%= !user.lover ? translate("economy/profile:NO_LOVER") : bot.users.cache.get(user.lover).tag %></span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
</div>
</div>
<!-- /.widget-user -->
</div>
<!-- /.col -->
<div class="row">
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-red"><i class="fa fa-area-chart"></i></span>
<div class="info-box-content">
<span
class="info-box-text"><%= translate("economy/profile:LEVEL").substr(2) %></span>
<span class="info-box-number"><%= guild.members.find(u => u.id === user.id).level %></span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-green"><i class="fa fa-money"></i></span>
<div class="info-box-content">
<span
class="info-box-text"><%= translate("economy/profile:CASH").substr(2) %> / <%= translate("economy/profile:BANK").substr(2) %></span>
<span class="info-box-number"><%= guild.members.find(u => u.id === user.id).money %> / <%= guild.members.find(u => u.id === user.id).bankSold %></span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="fa fa-star-o"></i></span>
<div class="info-box-content">
<span class="info-box-text"><%= translate("economy/profile:REPUTATION").substr(2) %></span>
<span class="info-box-number"><%= user.rep %></span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
</div>
</section>
</div>
<!-- /.content-wrapper -->
<!-- Footer includes credits and version -->
<%- include("includes/footer") %>
</div>
<!-- ./wrapper -->
</body>
</html>

View file

@ -33,7 +33,7 @@ module.exports = class {
else return message.sendT("misc:HELLO_DM"); else return message.sendT("misc:HELLO_DM");
} }
if (message.content.includes("@someone") && message.guild) return client.commands.get("someone").run(message, null, data); if (message.content.includes("@someone") && message.guild && client.commands.get("someone").conf.enabled) return client.commands.get("someone").run(message, null, data);
if (message.guild) { if (message.guild) {
// Gets the data of the member // Gets the data of the member

View file

@ -12,7 +12,7 @@
"MEMBERS": "Участники", "MEMBERS": "Участники",
"NAME": "Название", "NAME": "Название",
"CHANNELS": "Каналы", "CHANNELS": "Каналы",
"ID": "ID", "ID": "ID сервера",
"OWNER": "Владелец", "OWNER": "Владелец",
"USERNAME": "Имя пользователя", "USERNAME": "Имя пользователя",
"DISCRIMINATOR": "Тег", "DISCRIMINATOR": "Тег",
@ -48,7 +48,7 @@
"PAGE": "Страница", "PAGE": "Страница",
"MESSAGE": "Сообщение", "MESSAGE": "Сообщение",
"PROFILE": "Профиль", "PROFILE": "Профиль",
"CONFIGURATION": "Конфигурация", "CONFIGURATION": "Настройки",
"PREFIX": "Префикс", "PREFIX": "Префикс",
"LANGUAGE": "Язык", "LANGUAGE": "Язык",
"CHANNEL": "Канал", "CHANNEL": "Канал",

View file

@ -21,13 +21,14 @@
"ENABLE_AUTOROLE": "Включить", "ENABLE_AUTOROLE": "Включить",
"DISABLE_AUTOROLE": "Выключить", "DISABLE_AUTOROLE": "Выключить",
"SELECTOR": "Выбор серверов", "SELECTOR": "Выбор серверов",
"STATS": "Статистика",
"MANAGE": "Управление", "MANAGE": "Управление",
"EXP": "Опыт",
"REPUTATION": "Очки репутации",
"COOLDOWNS": "Откаты", "COOLDOWNS": "Откаты",
"REP": "Команда rep", "REP": "Команда rep",
"WORK": "Зарплата в work", "WORK": "Зарплата в work",
"ROB": "Защита от rob", "ROB": "Защита от rob",
"CAN_USE": "Можно использовать", "CAN_USE": "Можно использовать",
"NO_DEFENCE": "Вы беспомощны" "NO_DEFENCE": "Вы беспомощны",
"TOP_LEVEL": "Первый по уровню",
"TOP_CREDITS": "Первый по кредитам"
} }

View file

@ -4,7 +4,8 @@
"EXAMPLES": "{{prefix}}profile\n{{prefix}}profile @Jonny_Bro#4226", "EXAMPLES": "{{prefix}}profile\n{{prefix}}profile @Jonny_Bro#4226",
"BOT_USER": "У ботов нет профиля!", "BOT_USER": "У ботов нет профиля!",
"TITLE": "Профиль {{username}}", "TITLE": "Профиль {{username}}",
"YOUR_PROFILE": "Ваш профиль", "LINK": "Профиль",
"LINK_TEXT": "Нажмите сюда, чтобы открыть профиль на текущем сервере!",
"BIO": "🔖 Биография", "BIO": "🔖 Биография",
"NO_BIO": "Биография отсутствует", "NO_BIO": "Биография отсутствует",
"CASH": "💵 Кредиты", "CASH": "💵 Кредиты",

View file

@ -4,5 +4,7 @@
"EXAMPLES": "{{prefix}}serverinfo кык\n{{prefix}}serverinfo", "EXAMPLES": "{{prefix}}serverinfo кык\n{{prefix}}serverinfo",
"AFK_CHANNEL": "AFK канал", "AFK_CHANNEL": "AFK канал",
"NO_AFK_CHANNEL": "Нет AFK канала", "NO_AFK_CHANNEL": "Нет AFK канала",
"BOOSTS": "Кол-во бустов" "BOOSTS": "Кол-во бустов",
"LINK": "Статистика сервера",
"LINK_TEXT": "Нажмите сюда, чтобы открыть статистику сервера!"
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "jaba", "name": "jaba",
"version": "3.2.7", "version": "3.2.8",
"description": "A very complete Discord bot (more than 100 commands) that uses the Discord.js", "description": "A very complete Discord bot (more than 100 commands) that uses the Discord.js",
"main": "index.js", "main": "index.js",
"private": true, "private": true,