Compare commits
50 commits
v0.19.2-al
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
92c3058485 | ||
|
6f4d5606a6 | ||
|
5db977d9f6 | ||
|
73dce15840 | ||
|
e7fe154df3 | ||
|
afcab93421 | ||
|
4ab7b39980 | ||
|
6132b8df31 | ||
|
f31616cbb7 | ||
|
8dca929d80 | ||
|
c98cfa01ba | ||
|
875578d6ee | ||
|
143a80cba0 | ||
|
eef1e190a7 | ||
|
c205f9fa94 | ||
|
2566265d1d | ||
|
8329eea3e0 | ||
|
67506ea201 | ||
|
a68b579b16 | ||
|
5f25ab401f | ||
|
44ee2bcb08 | ||
|
5e6bf6ccb5 | ||
|
3afec81b3d | ||
|
35908dbfcd | ||
|
13d2479e49 | ||
|
dcf88f4ab0 | ||
|
4d17a43c83 | ||
|
b80b5deb3a | ||
|
e07bb7fa55 | ||
|
d637773f85 | ||
|
24f051299a | ||
|
bf4c2fae35 | ||
|
86afdb6a68 | ||
|
6b9380a221 | ||
|
17de144df4 | ||
|
10ff959aee | ||
|
375f8940a8 | ||
|
ea6a412cf8 | ||
|
5be8ee0e21 | ||
|
35103c5744 | ||
|
6b31eaa81b | ||
|
a01d400b23 | ||
|
59fb294826 | ||
|
c4db5815b9 | ||
|
80e6564a3d | ||
|
aca3591c39 | ||
|
cc19d7c677 | ||
|
0d00969c61 | ||
|
b611a3df9c | ||
|
9e2cfbfcd4 |
23 changed files with 508 additions and 101 deletions
|
@ -10,7 +10,7 @@ build:
|
||||||
- cp config.json.example config.json
|
- cp config.json.example config.json
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd build
|
- cd build
|
||||||
- cmake ..
|
- cmake .. -DFORCE_SUBMODULE_CDLPP=Yes
|
||||||
- cmake .. -DCMAKE_BUILD_TYPE=Release
|
- cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
- make -j"$(nproc)"
|
- make -j"$(nproc)"
|
||||||
- cd ..
|
- cd ..
|
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -1,6 +1,6 @@
|
||||||
[submodule "lib/cdlpp"]
|
|
||||||
path = lib/cdlpp
|
|
||||||
url = https://gitlab.com/niansa/cdlpp.git
|
|
||||||
[submodule "lib/cdlpp-db"]
|
[submodule "lib/cdlpp-db"]
|
||||||
path = lib/cdlpp-db
|
path = lib/cdlpp-db
|
||||||
url = https://gitlab.com/niansa/cdlpp-db.git
|
url = https://gitlab.com/niansa/cdlpp-db.git
|
||||||
|
[submodule "lib/cdlpp"]
|
||||||
|
path = lib/cdlpp
|
||||||
|
url = https://gitlab.com/niansa/cdlpp.git
|
||||||
|
|
|
@ -5,37 +5,57 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
include(embed.cmake)
|
include(embed.cmake)
|
||||||
include(lib/cdlpp/use.cmake)
|
include(cdlpp.cmake)
|
||||||
include(lib/cdlpp-db/use.cmake)
|
|
||||||
|
|
||||||
cdlpp(lib/cdlpp)
|
|
||||||
cdlppdb(lib/cdlpp-db)
|
|
||||||
add_compile_definitions(COMPILER_ID="${CMAKE_CXX_COMPILER_ID}")
|
add_compile_definitions(COMPILER_ID="${CMAKE_CXX_COMPILER_ID}")
|
||||||
add_compile_definitions(COMPILER_VERSION="${CMAKE_CXX_COMPILER_VERSION}")
|
add_compile_definitions(COMPILER_VERSION="${CMAKE_CXX_COMPILER_VERSION}")
|
||||||
add_compile_definitions(COMPILER_PLATFORM="${CMAKE_CXX_PLATFORM_ID}")
|
add_compile_definitions(COMPILER_PLATFORM="${CMAKE_CXX_PLATFORM_ID}")
|
||||||
|
|
||||||
add_executable(tuxiflux
|
add_executable(tuxiflux
|
||||||
${CDLPP_SRC_FILES}
|
|
||||||
${CDLPPDB_SRC_FILES}
|
|
||||||
bot/src/cust.cpp
|
bot/src/cust.cpp
|
||||||
bot/src/help_pages.cpp
|
bot/src/help_pages.cpp
|
||||||
bot/modules/useful.cpp
|
bot/modules/useful.cpp
|
||||||
bot/modules/servermanagement.cpp
|
bot/modules/servermanagement.cpp
|
||||||
|
bot/modules/warns.cpp
|
||||||
bot/modules/misc.cpp
|
bot/modules/misc.cpp
|
||||||
bot/modules/help.cpp
|
bot/modules/help.cpp
|
||||||
bot/modules/money.cpp
|
bot/modules/money.cpp
|
||||||
bot/modules/fun.cpp
|
bot/modules/fun.cpp
|
||||||
|
bot/modules/eval.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(tuxiflux PRIVATE
|
include_directories(
|
||||||
${CDLPP_INCLUDE_DIRS}
|
|
||||||
${CDLPPDB_INCLUDE_DIRS}
|
|
||||||
bot/include/
|
bot/include/
|
||||||
|
lib/cdlpp-db/include/
|
||||||
${EMBED_OUTDIR}
|
${EMBED_OUTDIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
cdlpp_libs()
|
find_package(cpuid QUIET)
|
||||||
cdlppdb_libs()
|
if (cpuid_FOUND)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||||
|
cpuid::cpuid)
|
||||||
|
add_compile_definitions(HAS_CPUID)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(fmt REQUIRED IMPORTED_TARGET fmt)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||||
|
PkgConfig::fmt cdlpp-db)
|
||||||
|
|
||||||
|
use_cdlpp(${PROJECT_NAME} lib/cdlpp)
|
||||||
|
|
||||||
|
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
|
option(ENABLE_EVAL "ENABLE_EVAL" ON)
|
||||||
|
if (${ENABLE_EVAL})
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||||
|
dl)
|
||||||
|
add_compile_definitions(ENABLE_EVAL)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
configure_file(config.json ./ COPYONLY)
|
configure_file(config.json ./ COPYONLY)
|
||||||
embed(help/*)
|
embed(help/*)
|
||||||
|
|
||||||
|
add_subdirectory(lib/cdlpp-db)
|
||||||
|
add_compile_definitions(WITH_CDLPPDB)
|
||||||
|
|
25
README.md
Normal file
25
README.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Tuxiflux
|
||||||
|
A feature-filled free and open source Discord bot based on CDL++, Discord++ and Boost ASIO!
|
||||||
|
|
||||||
|
This bot is the first big bot written on CDL++, so in case you want to learn how to use that framework... Come on it's an open source project, just read the source code and learn!
|
||||||
|
|
||||||
|
## Default prefix
|
||||||
|
The default prefix is `t#`
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
For a list of commands, this out `help/help_1.txt`!
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
1. Install [CDL++](https://gitlab.com/niansa/cdlpp)
|
||||||
|
2. Copy `config.json.example` to `config.json` and fill it
|
||||||
|
3. Clone submodules: `git submodule update --init --depth 1 --recursive`
|
||||||
|
4. Make and chdir into build directory: `mkdir build && cd build`
|
||||||
|
5. Configure the project: `cmake ..`
|
||||||
|
6. Get everything compiled: `make -j$(nproc)`
|
||||||
|
7. Run the bot: `./tuxiflux`
|
||||||
|
8. Enjoy!
|
||||||
|
|
||||||
|
Hint: the database does not need any special setup. I can recommend [ElephantSQL](https://elephantsql.com) for simple setups.
|
||||||
|
|
||||||
|
## Living example
|
||||||
|
Here's a running instance of Tuxifan ready for daily use: [Discord Bot Invite](https://discordapp.com/api/oauth2/authorize?client_id=788310535799308288&permissions=8&scope=applications.commands%20bot)
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <cdlpp/bot.hpp>
|
||||||
|
#include <cdlpp/cdltypes-incomplete.hpp>
|
||||||
#include "database.hpp"
|
#include "database.hpp"
|
||||||
#include "bot.hpp"
|
|
||||||
#include "cdltypes.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
extern const std::string default_prefix;
|
extern const std::string default_prefix;
|
||||||
|
@ -14,3 +14,12 @@ void on_message(CDL::CMessage msg, std::function<void (CDL::CMessage)> cb);
|
||||||
void on_error(const std::string& message);
|
void on_error(const std::string& message);
|
||||||
void get_prefix(CDL::CChannel channel, std::function<void (const std::string&)> cb);
|
void get_prefix(CDL::CChannel channel, std::function<void (const std::string&)> cb);
|
||||||
bool is_globalchat(CDL::CChannel channel);
|
bool is_globalchat(CDL::CChannel channel);
|
||||||
|
|
||||||
|
|
||||||
|
constexpr uint32_t color_ok = 0x00ff00,
|
||||||
|
color_err = 0xff0000,
|
||||||
|
color_warn = 0xff6600;
|
||||||
|
|
||||||
|
inline nlohmann::json simpleEmbed(const std::string& msg, uint32_t color = color_ok) {
|
||||||
|
return {{"description", msg}, {"color", color}};
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace db_templates {
|
||||||
enum type {
|
enum type {
|
||||||
guild,
|
guild,
|
||||||
user,
|
user,
|
||||||
|
member,
|
||||||
_end [[maybe_unused]], // Must be last one before _default
|
_end [[maybe_unused]], // Must be last one before _default
|
||||||
_default = guild // Must be last one
|
_default = guild // Must be last one
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "cust.hpp"
|
||||||
|
|
||||||
#define NO_SUCH_USER ":warning: I couldn't find the user you've requested. It may not have been cached yet.\n:information_source: Try mentioning the user instead"
|
#define NO_SUCH_USER simpleEmbed(":warning: I couldn't find the user you've requested. It may not have been cached yet.\n:information_source: Try mentioning the user instead", color_err)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "bot.hpp"
|
#include <cdlpp/bot.hpp>
|
||||||
#include "abstract/channel.hpp"
|
#include <cdlpp/cdltypes-incomplete.hpp>
|
||||||
|
|
||||||
void send_badusage(CDL::CChannel channel, const std::string& command);
|
void send_badusage(CDL::CChannel channel, const std::string& command);
|
||||||
|
|
83
bot/modules/eval.cpp
Normal file
83
bot/modules/eval.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#ifdef ENABLE_EVAL
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <cdlpp/cdltypes.hpp>
|
||||||
|
#include <boost/process.hpp>
|
||||||
|
#include <dlhandle.hpp>
|
||||||
|
#include "permassert.hpp"
|
||||||
|
using namespace std;
|
||||||
|
using namespace CDL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Eval {
|
||||||
|
static void eval(CMessage msg, CChannel channel, cmdargs& args) {
|
||||||
|
std::error_code ec;
|
||||||
|
// Only bot owner may use this
|
||||||
|
if (msg->author->id != env.settings["owner"]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check args
|
||||||
|
if (args.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Generate code
|
||||||
|
filesystem::remove("./codef.cpp", ec);
|
||||||
|
ofstream codef("./codef.cpp");
|
||||||
|
codef << "#include <cdlpp/cdltypes.hpp>\n"
|
||||||
|
"#include <dlhandle.hpp>\n"
|
||||||
|
"extern \"C\"\n"
|
||||||
|
"void eval_main(CDL::CMessage msg, CDL::CChannel channel) {\n"
|
||||||
|
"using namespace CDL;"
|
||||||
|
<< args[0] <<
|
||||||
|
"}";
|
||||||
|
codef.close();
|
||||||
|
// Compile code
|
||||||
|
channel->start_typing([=] (const bool) {
|
||||||
|
string libnme = "./codef_"+to_string(msg->id)+".so";
|
||||||
|
boost::process::async_system(*env.aioc, [=] (boost::system::error_code, int code) {
|
||||||
|
std::error_code ec;
|
||||||
|
filesystem::remove("./codef.cpp", ec);
|
||||||
|
// Check compiler result
|
||||||
|
if (code != 0) {
|
||||||
|
channel->send(":warning: Compilation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Run code
|
||||||
|
try {
|
||||||
|
auto evalo = new Dlhandle(libnme);
|
||||||
|
auto fnc = evalo->get<void(CMessage, CChannel)>("eval_main");
|
||||||
|
remove(libnme.c_str()); // Yep we can safely delete the file; it's still in memory
|
||||||
|
if (not fnc) {
|
||||||
|
channel->send(":warning: Failed to find main function");
|
||||||
|
delete evalo; // Delete evalo directly
|
||||||
|
} else {
|
||||||
|
fnc(msg, channel);
|
||||||
|
// Delete evalo after a minute
|
||||||
|
/*auto t = new boost::asio::deadline_timer(*env.aioc, boost::posix_time::minutes(1));
|
||||||
|
t->async_wait([=] (const boost::system::error_code&) {
|
||||||
|
delete t;
|
||||||
|
delete evalo
|
||||||
|
});*/ // We could do this to not have memory leaks but I do not expect the owner to execute that many expressions anyways
|
||||||
|
}
|
||||||
|
} catch (Dlhandle::Exception&) {
|
||||||
|
channel->send(":warning: Loading failed");
|
||||||
|
}
|
||||||
|
}, "gcc -std=c++17 ./codef.cpp -shared -fPIC -l cdlpp -o "+libnme);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
Eval() {
|
||||||
|
using namespace CDL;
|
||||||
|
// Commands
|
||||||
|
register_command("eval", eval, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static Eval eval;
|
||||||
|
#endif
|
|
@ -1,11 +1,11 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <cdlpp/cdltypes.hpp>
|
||||||
#include "cust.hpp"
|
#include "cust.hpp"
|
||||||
#include "database.hpp"
|
#include "database.hpp"
|
||||||
#include "generic_msgs.h"
|
#include "generic_msgs.h"
|
||||||
#include "help.hpp"
|
#include "help.hpp"
|
||||||
#include "cdltypes.hpp"
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace CDL;
|
using namespace CDL;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class Fun {
|
||||||
min = stoi(args[0]);
|
min = stoi(args[0]);
|
||||||
max = stoi(args[1]);
|
max = stoi(args[1]);
|
||||||
} catch (exception&) {
|
} catch (exception&) {
|
||||||
channel->send(":warning: **Both arguments** have to be numbers in range!");
|
channel->send_embed(simpleEmbed(":warning: **Both arguments** have to be numbers in range!", color_err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check numbers
|
// Check numbers
|
||||||
|
@ -36,9 +36,7 @@ class Fun {
|
||||||
uniform_int_distribution<> distr(min, max);
|
uniform_int_distribution<> distr(min, max);
|
||||||
// Send result
|
// Send result
|
||||||
auto rndno = distr(gen);
|
auto rndno = distr(gen);
|
||||||
channel->send(":game_die:...", [rndno] (CMessage msg) {
|
channel->send_embed(simpleEmbed(":game_die: **"+to_string(rndno)+"**"));
|
||||||
msg->edit(":game_die: **"+to_string(rndno)+"**");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eightball(CMessage msg, CChannel channel, CDL::cmdargs& args) {
|
static void eightball(CMessage msg, CChannel channel, CDL::cmdargs& args) {
|
||||||
|
@ -51,13 +49,25 @@ class Fun {
|
||||||
send_badusage(channel, "8ball");
|
send_badusage(channel, "8ball");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get "random" answer
|
|
||||||
mt19937 gen(msg->id);
|
|
||||||
uniform_int_distribution<> distr(0, static_cast<int>(answers.size() - 1));
|
|
||||||
// Send answer
|
// Send answer
|
||||||
channel->send(":crystal_ball: "+answers[static_cast<uint64_t>(distr(gen))]);
|
channel->send_embed(simpleEmbed(":crystal_ball: "+answers[msg->id % (answers.size() - 1)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tpdne(CMessage msg, CChannel channel, CDL::cmdargs&) {
|
||||||
|
channel->send("https://thispersondoesnotexist.com/image?"+to_string(msg->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcdne(CMessage msg, CChannel channel, CDL::cmdargs&) {
|
||||||
|
channel->send("https://thiscatdoesnotexist.com/?"+to_string(msg->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trdne(CMessage msg, CChannel channel, CDL::cmdargs&) {
|
||||||
|
channel->send("https://thisrentaldoesnotexist.com/img-new/hero.jpg?"+to_string(msg->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void thdne(CMessage msg, CChannel channel, CDL::cmdargs&) {
|
||||||
|
channel->send("https://thishorsedoesnotexist.com/?"+to_string(msg->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -66,6 +76,10 @@ public:
|
||||||
// Commands
|
// Commands
|
||||||
register_command("random", random, 2);
|
register_command("random", random, 2);
|
||||||
register_command("8ball", eightball, 1);
|
register_command("8ball", eightball, 1);
|
||||||
|
register_command("notaperson", tpdne, NO_ARGS);
|
||||||
|
register_command("notacat", tcdne, NO_ARGS);
|
||||||
|
register_command("notahorse", thdne, NO_ARGS);
|
||||||
|
register_command("notarental", trdne, NO_ARGS);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include "extras.hpp"
|
#include <cdlpp/extras.hpp>
|
||||||
|
#include <cdlpp/cdltypes.hpp>
|
||||||
#include "cust.hpp"
|
#include "cust.hpp"
|
||||||
#include "help_pages.hpp"
|
#include "help_pages.hpp"
|
||||||
#include "cdltypes.hpp"
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace CDL;
|
using namespace CDL;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ static json syntaxes = json::parse(help_files.find("syntaxes")->second);
|
||||||
void send_badusage(CChannel channel, const string& command) {
|
void send_badusage(CChannel channel, const string& command) {
|
||||||
// Check if any usable syntax is listed to command
|
// Check if any usable syntax is listed to command
|
||||||
if (not syntaxes.contains(command)) {
|
if (not syntaxes.contains(command)) {
|
||||||
channel->send(":warning: Incorrect command usage");
|
channel->send_embed(simpleEmbed(":warning: Incorrect command usage", color_err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto syntax = syntaxes[command];
|
auto syntax = syntaxes[command];
|
||||||
|
@ -24,12 +24,12 @@ void send_badusage(CChannel channel, const string& command) {
|
||||||
get_prefix(channel, [=] (const std::string& prefix) {
|
get_prefix(channel, [=] (const std::string& prefix) {
|
||||||
// Check if badusage text exists
|
// Check if badusage text exists
|
||||||
if (syntax.contains("badusage_text")) {
|
if (syntax.contains("badusage_text")) {
|
||||||
channel->send(fmt::format(string(syntax["badusage_text"]), prefix+command, string(syntax["usage"])));
|
channel->send_embed(simpleEmbed(fmt::format(string(syntax["badusage_text"]), prefix+command, string(syntax["usage"])), color_err));
|
||||||
}
|
}
|
||||||
// Alternatively send usage
|
// Alternatively send usage
|
||||||
else {
|
else {
|
||||||
string x = fmt::format(":warning: Syntax: `{0} {1}`", prefix+command, string(syntax["usage"]));
|
string x = fmt::format(":warning: Syntax: `{0} {1}`", prefix+command, string(syntax["usage"]));
|
||||||
channel->send(x);
|
channel->send_embed(simpleEmbed(x, color_err));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,14 @@
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#ifdef HAS_CPUID
|
||||||
|
# include <libcpuid.h>
|
||||||
|
#endif
|
||||||
#include "cust.hpp"
|
#include "cust.hpp"
|
||||||
#include "help.hpp"
|
#include "help.hpp"
|
||||||
#include "generic_msgs.h"
|
#include "generic_msgs.h"
|
||||||
#include "permassert.hpp"
|
#include "permassert.hpp"
|
||||||
#include "cdltypes.hpp"
|
#include <cdlpp/cdltypes.hpp>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace CDL;
|
using namespace CDL;
|
||||||
|
|
||||||
|
@ -17,7 +20,7 @@ class Misc {
|
||||||
timer::time_point startup_time;
|
timer::time_point startup_time;
|
||||||
|
|
||||||
|
|
||||||
static void invite(CMessage , CChannel channel, CDL::cmdargs&) {
|
static void invite(CMessage, CChannel channel, CDL::cmdargs&) {
|
||||||
json embed = {
|
json embed = {
|
||||||
{"description", ":speech_balloon: You can invite me using [this]("+extras::get_bot_invite_link()+") link"},
|
{"description", ":speech_balloon: You can invite me using [this]("+extras::get_bot_invite_link()+") link"},
|
||||||
{"color", 0xffffff}
|
{"color", 0xffffff}
|
||||||
|
@ -51,17 +54,21 @@ class Misc {
|
||||||
// TODO
|
// TODO
|
||||||
};
|
};
|
||||||
// Create channel
|
// Create channel
|
||||||
Channel newchannel({});
|
using namespace Permissions;
|
||||||
{
|
BaseChannel newchannel = {
|
||||||
newchannel.name = "tuxiflux-globalchat";
|
.name = "tuxiflux-globalchat",
|
||||||
using namespace Permissions;
|
.overwrites = {
|
||||||
newchannel.overwrites[env.self->id] = {
|
{
|
||||||
env.self->id,
|
env.self->id,
|
||||||
PermissionOverwrite::member,
|
{
|
||||||
VIEW_CHANNEL | SEND_MESSAGES | MANAGE_MESSAGES,
|
.id = env.self->id,
|
||||||
0
|
.type = PermissionOverwrite::member,
|
||||||
};
|
.allow = VIEW_CHANNEL | SEND_MESSAGES | MANAGE_MESSAGES,
|
||||||
}
|
.deny = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
server->create_channel(newchannel, [channel] (CChannel newchannel) {
|
server->create_channel(newchannel, [channel] (CChannel newchannel) {
|
||||||
if (newchannel) {
|
if (newchannel) {
|
||||||
channel->send(":speech_balloon: "+newchannel->get_mention()+" was created and set up. Have fun!");
|
channel->send(":speech_balloon: "+newchannel->get_mention()+" was created and set up. Have fun!");
|
||||||
|
@ -78,16 +85,34 @@ class Misc {
|
||||||
auto uptime_hours = uptime.count() / 1000000000 / 60 / 60;
|
auto uptime_hours = uptime.count() / 1000000000 / 60 / 60;
|
||||||
// Get prefix
|
// Get prefix
|
||||||
get_prefix(channel, [=] (const std::string& prefix) {
|
get_prefix(channel, [=] (const std::string& prefix) {
|
||||||
|
# ifdef extras_get_mem_supported
|
||||||
// Get mem usage string
|
// Get mem usage string
|
||||||
ostringstream mem_use;
|
ostringstream mem_use;
|
||||||
# ifdef extras_get_mem_supported
|
mem_use << "Memory usage • **" << extras::get_mem::used() << "** MB / **" << extras::get_mem::total() << "** MB\n";
|
||||||
mem_use << "Memory usage • **" << extras::get_mem::used() << "** MB / **" << extras::get_mem::total() << "** MB\n";
|
# endif
|
||||||
# endif
|
# ifdef HAS_CPUID
|
||||||
|
// Get CPU data
|
||||||
|
string cpu_name;
|
||||||
|
if (cpuid_present()) {
|
||||||
|
cpu_raw_data_t cpuid_raw;
|
||||||
|
cpuid_get_raw_data(&cpuid_raw);
|
||||||
|
cpu_id_t cpuid;
|
||||||
|
cpu_identify(&cpuid_raw, &cpuid);
|
||||||
|
cpu_name = cpuid.brand_str;
|
||||||
|
} else {
|
||||||
|
cpu_name = "Unknown";
|
||||||
|
}
|
||||||
|
# endif
|
||||||
// Build info text
|
// Build info text
|
||||||
ostringstream text;
|
ostringstream text;
|
||||||
text << "Online since • **" << uptime_hours << "** hours\n"
|
text << "Online since • **" << uptime_hours << "** hours\n"
|
||||||
"\n" <<
|
"\n" <<
|
||||||
|
# ifdef extras_get_mem_supported
|
||||||
mem_use.str() <<
|
mem_use.str() <<
|
||||||
|
# endif
|
||||||
|
# ifdef HAS_CPUID
|
||||||
|
"CPU • **" << cpu_name << "**\n"
|
||||||
|
# endif
|
||||||
"C++ version • **" << __cplusplus << "**\n"
|
"C++ version • **" << __cplusplus << "**\n"
|
||||||
"Boost version • **" BOOST_LIB_VERSION "**\n"
|
"Boost version • **" BOOST_LIB_VERSION "**\n"
|
||||||
"Compiler • **" COMPILER_ID " " COMPILER_VERSION " (" COMPILER_PLATFORM ")**\n"
|
"Compiler • **" COMPILER_ID " " COMPILER_VERSION " (" COMPILER_PLATFORM ")**\n"
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <cdlpp/cdltypes.hpp>
|
||||||
#include "cust.hpp"
|
#include "cust.hpp"
|
||||||
#include "database.hpp"
|
#include "database.hpp"
|
||||||
#include "generic_msgs.h"
|
#include "generic_msgs.h"
|
||||||
#include "help.hpp"
|
#include "help.hpp"
|
||||||
#include "cdltypes.hpp"
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace CDL;
|
using namespace CDL;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class Money {
|
||||||
}
|
}
|
||||||
// Check if target user == bot
|
// Check if target user == bot
|
||||||
if (user_id == env.self->id) {
|
if (user_id == env.self->id) {
|
||||||
channel->send(":warning: Sadly, I am not allowed to have money :confused:");
|
channel->send_embed(simpleEmbed(":warning: Sadly, I am not allowed to have money :confused:", color_err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fetch::user(user_id, [channel] (CUser user) {
|
fetch::user(user_id, [channel] (CUser user) {
|
||||||
|
@ -37,7 +37,7 @@ class Money {
|
||||||
// Get values
|
// Get values
|
||||||
get_money(user->id, [=] (auto amount) {
|
get_money(user->id, [=] (auto amount) {
|
||||||
// Send
|
// Send
|
||||||
channel->send("**"+user->get_full_name()+"** currently has **"+to_string(amount)+"** :dollar:");
|
channel->send_embed(simpleEmbed("**"+user->get_full_name()+"** currently has **"+to_string(amount)+"** :dollar:"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,8 @@ class Money {
|
||||||
env.db->get<int>(to_dbid(msg->author->id), "LAST_DAILY", [=] (auto last_daily) {
|
env.db->get<int>(to_dbid(msg->author->id), "LAST_DAILY", [=] (auto last_daily) {
|
||||||
// Verify that next day was reached
|
// Verify that next day was reached
|
||||||
if (last_daily == time->tm_yday) {
|
if (last_daily == time->tm_yday) {
|
||||||
channel->send(":warning: You can't get your daily money twice a day\n"
|
channel->send_embed(simpleEmbed(":warning: You can't get your daily money twice a day\n"
|
||||||
":information_source: Please note that I'm running in GMT :wink:");
|
":information_source: Please note that I'm running in GMT :wink:", color_err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Update database
|
// Update database
|
||||||
|
@ -66,8 +66,8 @@ class Money {
|
||||||
get_money(msg->author->id, [=] (auto new_value) {
|
get_money(msg->author->id, [=] (auto new_value) {
|
||||||
auto old_value = new_value - daily_money;
|
auto old_value = new_value - daily_money;
|
||||||
// Send result
|
// Send result
|
||||||
channel->send(":dollar: You've received your daily money!\n"
|
channel->send_embed(simpleEmbed(":dollar: You've received your daily money!\n"
|
||||||
"**"+to_string(old_value)+"** + **"+to_string(daily_money)+"** = **"+to_string(new_value)+"**");
|
"**"+to_string(old_value)+"** + **"+to_string(daily_money)+"** = **"+to_string(new_value)+"**"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, to_string(daily_money));
|
}, to_string(daily_money));
|
||||||
|
@ -89,10 +89,10 @@ class Money {
|
||||||
}
|
}
|
||||||
// Check target user
|
// Check target user
|
||||||
if (target_user_id == env.self->id) {
|
if (target_user_id == env.self->id) {
|
||||||
channel->send(":warning: Why do you want to give me money?");
|
channel->send_embed(simpleEmbed(":warning: Why do you want to give me money?", color_err));
|
||||||
return;
|
return;
|
||||||
} else if (target_user_id == msg->author->id) {
|
} else if (target_user_id == msg->author->id) {
|
||||||
channel->send(":warning: That's yourself lol");
|
channel->send_embed(simpleEmbed(":warning: That's yourself lol", color_err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check if specified user ID actually exists and is fetchable
|
// Check if specified user ID actually exists and is fetchable
|
||||||
|
@ -104,17 +104,17 @@ class Money {
|
||||||
}
|
}
|
||||||
// Check if number is clean
|
// Check if number is clean
|
||||||
if (not extras::is_digits(amount_str)) {
|
if (not extras::is_digits(amount_str)) {
|
||||||
channel->send(":warning: The amount of money you've specified isn't valid :thinking:");
|
channel->send_embed(simpleEmbed(":warning: The amount of money you've specified isn't valid :thinking:", color_err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Pay out
|
// Pay out
|
||||||
mod_money(msg->author->id, [=] (const bool error) {
|
mod_money(msg->author->id, [=] (const bool error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
channel->send(":warning: I wasn't able to pay out... Are you sure you've got enough money?");
|
channel->send_embed(simpleEmbed(":warning: I wasn't able to pay out... Are you sure you've got enough money?", color_err));
|
||||||
} else {
|
} else {
|
||||||
mod_money(target_user->id, nullptr, amount_str);
|
mod_money(target_user->id, nullptr, amount_str);
|
||||||
// Report success
|
// Report success
|
||||||
channel->send("You've sent **"+amount_str+"** :dollar: to **"+target_user->get_full_name()+"**");
|
channel->send_embed(simpleEmbed("You've sent **"+amount_str+"** :dollar: to **"+target_user->get_full_name()+"**"));
|
||||||
}
|
}
|
||||||
}, string("-")+amount_str);
|
}, string("-")+amount_str);
|
||||||
});
|
});
|
||||||
|
@ -130,13 +130,13 @@ class Money {
|
||||||
auto insert_str = to_string(insert);
|
auto insert_str = to_string(insert);
|
||||||
// Check if insert is in range
|
// Check if insert is in range
|
||||||
if (not (insert != 0 and insert < 100)){
|
if (not (insert != 0 and insert < 100)){
|
||||||
channel->send(":warning: **"+insert_str+"** is not > **0** and < **100**!");
|
channel->send_embed(simpleEmbed(":warning: **"+insert_str+"** is not > **0** and < **100**!", color_err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check if user has enough money
|
// Check if user has enough money
|
||||||
get_money(msg->author->id, [=] (auto amount) {
|
get_money(msg->author->id, [=] (auto amount) {
|
||||||
if (amount < insert) {
|
if (amount < insert) {
|
||||||
channel->send(":warning: Excuse me, but you don't have enough money to do that!");
|
channel->send_embed(simpleEmbed(":warning: Excuse me, but you don't have enough money to do that!", color_err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get "random" value
|
// Get "random" value
|
||||||
|
@ -148,9 +148,9 @@ class Money {
|
||||||
mod_money(msg->author->id, nullptr, std::string(lost?"-":"")+insert_str);
|
mod_money(msg->author->id, nullptr, std::string(lost?"-":"")+insert_str);
|
||||||
// Report value of won
|
// Report value of won
|
||||||
if (lost) {
|
if (lost) {
|
||||||
channel->send(":thumbsdown: You've lost **"+insert_str+"** :dollar:");
|
channel->send_embed(simpleEmbed(":thumbsdown: You've lost **"+insert_str+"** :dollar:", color_warn));
|
||||||
} else {
|
} else {
|
||||||
channel->send(":thumbsup: You've won **"+insert_str+"** :dollar:");
|
channel->send_embed(simpleEmbed(":thumbsup: You've won **"+insert_str+"** :dollar:", color_ok));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include <cdlpp/cdltypes.hpp>
|
||||||
#include "database.hpp"
|
#include "database.hpp"
|
||||||
#include "permassert.hpp"
|
#include "permassert.hpp"
|
||||||
#include "help.hpp"
|
#include "help.hpp"
|
||||||
#include "cust.hpp"
|
#include "cust.hpp"
|
||||||
#include "generic_msgs.h"
|
#include "generic_msgs.h"
|
||||||
#include "cdltypes.hpp"
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace CDL;
|
using namespace CDL;
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class Basic {
|
||||||
if (args.empty()) {
|
if (args.empty()) {
|
||||||
// Get prefix
|
// Get prefix
|
||||||
get_prefix(channel, [=] (const std::string& prefix) {
|
get_prefix(channel, [=] (const std::string& prefix) {
|
||||||
channel->send(":paperclips: The individual prefix for **"+server->name+"** is `"+prefix+'`');
|
channel->send_embed(simpleEmbed(":paperclips: The individual prefix for **"+server->name+"** is `"+prefix+'`'));
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,9 @@ class Basic {
|
||||||
prefix_cache[server->id] = newprefix;
|
prefix_cache[server->id] = newprefix;
|
||||||
// Inform about success
|
// Inform about success
|
||||||
if (reset) {
|
if (reset) {
|
||||||
channel->send(":paperclips: Your individual prefix has been reset for your server!");
|
channel->send_embed(simpleEmbed(":paperclips: Your individual prefix has been reset for your server!"));
|
||||||
} else {
|
} else {
|
||||||
channel->send(":paperclips: Your individual prefix for your server was changed to **"+newprefix+"**.");
|
channel->send_embed(simpleEmbed(":paperclips: Your individual prefix for your server was changed to **"+newprefix+"**."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ class Basic {
|
||||||
});
|
});
|
||||||
welcomedm_set(server, newmsg);
|
welcomedm_set(server, newmsg);
|
||||||
} catch (fmt::format_error& e) {
|
} catch (fmt::format_error& e) {
|
||||||
channel->send(":warning: Failed to set welcome DM: "+string(e.what()));
|
channel->send_embed(simpleEmbed(":warning: Failed to set welcome DM: "+string(e.what()), color_err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,13 +114,13 @@ class Basic {
|
||||||
auto reason = args[1];
|
auto reason = args[1];
|
||||||
auto cb = [channel, id_str, id_int, reason, permanent] (const bool error) {
|
auto cb = [channel, id_str, id_int, reason, permanent] (const bool error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
channel->send(":warning: That didn't work. Please make sure I have the permission to ban (Use the `setup check` command) "
|
channel->send_embed(simpleEmbed(":warning: That didn't work. Please make sure I have the permission to ban (Use the `setup check` command) "
|
||||||
"and that the user you've specified actually exists.");
|
"and that the user you've specified actually exists.", color_err));
|
||||||
} else {
|
} else {
|
||||||
// If user is in cache, show its full name; else mention
|
// If user is in cache, show its full name; else mention
|
||||||
auto user = cache::get_user(id_int);
|
auto user = cache::get_user(id_int);
|
||||||
auto identifier = user?user->get_full_name():"<@"+id_str+">";
|
auto identifier = user?user->get_full_name():"<@"+id_str+">";
|
||||||
channel->send(":smiling_imp: **"+identifier+"** was "+string(permanent?"banned":"kicked")+". (**"+reason+"**)");
|
channel->send_embed(simpleEmbed(":smiling_imp: **"+identifier+"** was "+string(permanent?"banned":"kicked")+". (**"+reason+"**)"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (permanent) {
|
if (permanent) {
|
||||||
|
@ -156,9 +156,9 @@ class Basic {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (res->second->nick.empty()) {
|
if (res->second->nick.empty()) {
|
||||||
channel->send(":information_source: **"+args[0]+"** does not have a nickname");
|
channel->send_embed(simpleEmbed(":information_source: **"+args[0]+"** does not have a nickname"));
|
||||||
} else {
|
} else {
|
||||||
channel->send(":information_source: The nickname of **"+args[0]+"** is **"+res->second->nick+"**");
|
channel->send_embed(simpleEmbed(":information_source: The nickname of **"+args[0]+"** is **"+res->second->nick+"**"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -175,13 +175,13 @@ class Basic {
|
||||||
// Perform change
|
// Perform change
|
||||||
channel->get_guild()->set_nick(user_id, newnick, [args, newnick, channel] (const bool error) {
|
channel->get_guild()->set_nick(user_id, newnick, [args, newnick, channel] (const bool error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
channel->send(":warning: I couldn't change their nickname.\n"
|
channel->send_embed(simpleEmbed(":warning: I couldn't change their nickname.\n"
|
||||||
":information_source: Do I have enough permissions? Is the nick even valid?");
|
":information_source: Do I have enough permissions? Is the nick even valid?", color_err));
|
||||||
} else {
|
} else {
|
||||||
if (newnick.empty()) {
|
if (newnick.empty()) {
|
||||||
channel->send(":information_source: The nickname of **"+args[0]+"** was removed.");
|
channel->send_embed(simpleEmbed(":information_source: The nickname of **"+args[0]+"** was removed."));
|
||||||
} else {
|
} else {
|
||||||
channel->send(":information_source: The nickname of **"+args[0]+"** was changed to **"+newnick+"**");
|
channel->send_embed(simpleEmbed(":information_source: The nickname of **"+args[0]+"** was changed to **"+newnick+"**"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -205,13 +205,14 @@ class Basic {
|
||||||
}
|
}
|
||||||
static void autoroles_assign(CMember member) {
|
static void autoroles_assign(CMember member) {
|
||||||
env.db->get<string>(to_dbid(member->guild->id), "AUTOROLES", [=] (auto autoroles_str) {
|
env.db->get<string>(to_dbid(member->guild->id), "AUTOROLES", [=] (auto autoroles_str) {
|
||||||
|
auto member_cpy = *member;
|
||||||
// Parse and assign them
|
// Parse and assign them
|
||||||
auto autoroles = autoroles_get(member->guild, autoroles_str);
|
auto autoroles = autoroles_get(member_cpy.guild, autoroles_str);
|
||||||
if (not autoroles.empty()) {
|
if (not autoroles.empty()) {
|
||||||
for (const auto& autorole : autoroles) {
|
for (const auto& autorole : autoroles) {
|
||||||
member->roles.push_back(autorole->id);
|
member_cpy.roles.push_back(autorole->id);
|
||||||
}
|
}
|
||||||
member->commit();
|
member_cpy.commit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -255,10 +256,10 @@ class Basic {
|
||||||
autoroles = autoroles_get(guild, autoroles_str);
|
autoroles = autoroles_get(guild, autoroles_str);
|
||||||
} catch (std::invalid_argument&) {}
|
} catch (std::invalid_argument&) {}
|
||||||
if (autoroles.size() != args.size()) {
|
if (autoroles.size() != args.size()) {
|
||||||
channel->send(":warning: Not all roles could be located");
|
channel->send_embed(simpleEmbed(":warning: Not all roles could be located", color_err));
|
||||||
} else {
|
} else {
|
||||||
env.db->update(to_dbid(guild->id), "AUTOROLES", autoroles_str);
|
env.db->update(to_dbid(guild->id), "AUTOROLES", autoroles_str);
|
||||||
channel->send("Alright, done!");
|
channel->send_embed(simpleEmbed("Alright, done!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <array> // TODO: remove when no longer needed
|
#include <array> // TODO: remove when no longer needed
|
||||||
|
#include <cdlpp/cdltypes.hpp>
|
||||||
#include "cust.hpp"
|
#include "cust.hpp"
|
||||||
#include "generic_msgs.h"
|
#include "generic_msgs.h"
|
||||||
#include "help.hpp"
|
#include "help.hpp"
|
||||||
#include "permassert.hpp"
|
#include "permassert.hpp"
|
||||||
#include "cdltypes.hpp"
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace CDL;
|
using namespace CDL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Botinfo {
|
class Useful {
|
||||||
static void serverinfo_roles(CChannel channel) {
|
static void serverinfo_roles(CChannel channel) {
|
||||||
channel->get_guild([channel] (CGuild server) {
|
channel->get_guild([channel] (CGuild server) {
|
||||||
// Get info text
|
// Get info text
|
||||||
|
@ -67,7 +67,6 @@ class Botinfo {
|
||||||
server->get_bans([args, channel, server, server_owner] (const std::unordered_map<uint64_t, Ban*>& server_bans) {
|
server->get_bans([args, channel, server, server_owner] (const std::unordered_map<uint64_t, Ban*>& server_bans) {
|
||||||
ostringstream server_features;
|
ostringstream server_features;
|
||||||
auto server_avatar_url = extras::get_avatar_url(server);
|
auto server_avatar_url = extras::get_avatar_url(server);
|
||||||
auto server_creation_date = "not yet implemented";
|
|
||||||
size_t server_members = 0,
|
size_t server_members = 0,
|
||||||
server_bots = 0,
|
server_bots = 0,
|
||||||
server_humans = 0,
|
server_humans = 0,
|
||||||
|
@ -132,9 +131,6 @@ class Botinfo {
|
||||||
"**Features**\n"
|
"**Features**\n"
|
||||||
"• " << server_featuresstr << "\n"
|
"• " << server_featuresstr << "\n"
|
||||||
"\n"
|
"\n"
|
||||||
"**Server created**\n"
|
|
||||||
"• " << server_creation_date << "\n"
|
|
||||||
"\n"
|
|
||||||
"**Emojis**\n"
|
"**Emojis**\n"
|
||||||
"• Please use `" << prefix << "serverinfo emojis`\n"
|
"• Please use `" << prefix << "serverinfo emojis`\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -182,17 +178,32 @@ class Botinfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void opensource(CMessage, CChannel channel, CDL::cmdargs&) {
|
||||||
|
channel->send_embed(simpleEmbed("**Tuxiflux** is [FOSS](https://gitlab.com/niansa/tuxiflux) (**f**ree **o**pen **s**ource **s**oftware).\n"
|
||||||
|
"This means that you are free to view, modify, and redistribute the source code under the terms of the MIT license.\n"
|
||||||
|
"\n"
|
||||||
|
"Make your code open source today!\n"
|
||||||
|
" - Worried about people stealing the code? If that happens, be proud! Bad code doesn't get stolen, good code does!\n"
|
||||||
|
" - Your code style is so bad that you don't want anyone to see it? No problem! People might even help you improve it!\n"
|
||||||
|
" - Show people your open source project! If it's interesting and/or well documented enough, some will help!\n"
|
||||||
|
" - Help others - without doing anything! People learn a lot just by playing around with other open source projects!\n"
|
||||||
|
"Btw, [Fosshost](https://fosshost.org) offers free hosting for open source projects that need it!\n"
|
||||||
|
"\n"
|
||||||
|
" -> Didn't convince you? Read [this](https://www.codeproject.com/articles/5410/why-open-source) nice article!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Botinfo() {
|
Useful() {
|
||||||
using namespace CDL;
|
using namespace CDL;
|
||||||
// Commands
|
// Commands
|
||||||
register_command("serverinfo", serverinfo, 1);
|
register_command("serverinfo", serverinfo, 1);
|
||||||
register_command("avatar", avatar, 1);
|
register_command("avatar", avatar, 1);
|
||||||
|
register_command("opensource", opensource, 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static Botinfo botinfo;
|
static Useful botinfo;
|
||||||
|
|
165
bot/modules/warns.cpp
Normal file
165
bot/modules/warns.cpp
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <cdlpp/cdltypes.hpp>
|
||||||
|
#include "help.hpp"
|
||||||
|
#include "generic_msgs.h"
|
||||||
|
#include "permassert.hpp"
|
||||||
|
using namespace std;
|
||||||
|
using namespace CDL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Warns {
|
||||||
|
inline static string get_db_identifier(uint64_t user_id, uint64_t guild_id) {
|
||||||
|
return to_dbid(user_id)+' '+to_dbid(guild_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warns(CMessage msg, CChannel channel, cmdargs& args) {
|
||||||
|
auto guild = channel->get_guild();
|
||||||
|
// Get target member
|
||||||
|
uint64_t target_user;
|
||||||
|
if (args.size() == 1) {
|
||||||
|
target_user = extras::find_user_id(guild, args[0]);
|
||||||
|
// Check if member was found
|
||||||
|
if (not target_user) {
|
||||||
|
channel->send(NO_SUCH_USER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target_user = msg->author->id;
|
||||||
|
}
|
||||||
|
auto identifier = get_db_identifier(target_user, guild->id);
|
||||||
|
// Get amount of warnings
|
||||||
|
env.db->get<int>(identifier, "WARNS", [=] (int warns_a) {
|
||||||
|
// Check if member has any warnings
|
||||||
|
if (warns_a) {
|
||||||
|
// Create list of warnings in heap
|
||||||
|
auto warnings = make_shared<vector<string>>();
|
||||||
|
warnings->reserve(warns_a);
|
||||||
|
// Copy amount of warnings to heap
|
||||||
|
auto hwarns = make_shared<int>(warns_a);
|
||||||
|
// Define functionm that shows the result
|
||||||
|
auto show_warns = [=] () {
|
||||||
|
// Get user
|
||||||
|
fetch::user(target_user, [=] (CUser target) {
|
||||||
|
// Check if user could be found
|
||||||
|
if (not target_user) {
|
||||||
|
channel->send(NO_SUCH_USER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Generate string
|
||||||
|
ostringstream text;
|
||||||
|
for (const auto& reason : *warnings) {
|
||||||
|
text << " - " << reason << '\n';
|
||||||
|
}
|
||||||
|
// Send as embed
|
||||||
|
channel->send_embed({
|
||||||
|
{"title", "Warnings to "+target->get_full_name()},
|
||||||
|
{"description", text.str()}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// Define reader for next warning
|
||||||
|
auto next_warn = make_shared<function<void ()>>();
|
||||||
|
*next_warn = [=] () {
|
||||||
|
if ((*hwarns)--) {
|
||||||
|
env.db->get<string>(identifier, "WARN"+to_string(*hwarns), [=] (auto warnstr) {
|
||||||
|
warnings->push_back(warnstr);
|
||||||
|
(*next_warn)();
|
||||||
|
}, db_templates::member);
|
||||||
|
} else {
|
||||||
|
// Show warnings
|
||||||
|
show_warns();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(*next_warn)();
|
||||||
|
} else {
|
||||||
|
channel->send_embed(simpleEmbed(":warning: This user has no warnings!", color_warn));
|
||||||
|
}
|
||||||
|
}, db_templates::member);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warn(CMessage msg, CChannel channel, cmdargs& args) {
|
||||||
|
auto guild = channel->get_guild();
|
||||||
|
// Check permissions
|
||||||
|
permassert(msg, channel, Permissions::BAN_MEMBERS);
|
||||||
|
// Check arguments
|
||||||
|
if (args.size() != 2) {
|
||||||
|
send_badusage(channel, "warn");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check the mentioned user
|
||||||
|
auto target_user = extras::find_user_id(guild, args[0]);
|
||||||
|
// Check if user was found
|
||||||
|
if (not target_user) {
|
||||||
|
channel->send(NO_SUCH_USER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check how many time the user has been warned already
|
||||||
|
auto identifier = get_db_identifier(target_user, guild->id);
|
||||||
|
env.db->get<int>(identifier, "WARNS", [=] (auto warns_a) {
|
||||||
|
// Increase amount of warns, add warning and check if 3 warnings were reached
|
||||||
|
if (++warns_a <= 3) {
|
||||||
|
// Set reason
|
||||||
|
env.db->update(identifier, "WARN"+to_string(warns_a-1), args[1], [=] (const bool) {
|
||||||
|
// Update counter
|
||||||
|
env.db->update(identifier, "WARNS", warns_a, [=] (const bool) {
|
||||||
|
// Return list of warnings
|
||||||
|
cmdargs fakeargs = {to_string(target_user)};
|
||||||
|
warns(nullptr, channel, fakeargs);
|
||||||
|
// Ban the member if required
|
||||||
|
if (warns_a == 3) {
|
||||||
|
guild->ban(target_user, "3 warnings");
|
||||||
|
channel->send(args[0]+" was **banned**!");
|
||||||
|
}
|
||||||
|
}, db_templates::member);
|
||||||
|
}, db_templates::member);
|
||||||
|
} else {
|
||||||
|
channel->send_embed(simpleEmbed(":warning: The user already has 3 warnings!", color_err));
|
||||||
|
}
|
||||||
|
}, db_templates::member);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unwarn(CMessage msg, CChannel channel, cmdargs& args) {
|
||||||
|
auto guild = channel->get_guild();
|
||||||
|
// Check permissions
|
||||||
|
permassert(msg, channel, Permissions::BAN_MEMBERS);
|
||||||
|
// Check arguments
|
||||||
|
if (args.size() != 1) {
|
||||||
|
send_badusage(channel, "unwarn");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check the mentioned user
|
||||||
|
auto target_user = extras::find_user_id(guild, args[0]);
|
||||||
|
// Check if user was found
|
||||||
|
if (not target_user) {
|
||||||
|
channel->send(NO_SUCH_USER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Decrease warn counter
|
||||||
|
env.db->update(get_db_identifier(target_user, guild->id), "WARNS = WARNS - 1", [=] (const bool error) {
|
||||||
|
if (not error) {
|
||||||
|
channel->send_embed(simpleEmbed("This members last warning was removed"));
|
||||||
|
} else {
|
||||||
|
channel->send_embed(simpleEmbed(":warning: This member does not yet have any warnings", color_err));
|
||||||
|
}
|
||||||
|
}, db_templates::member);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
Warns() {
|
||||||
|
register_command("warns", warns, 1);
|
||||||
|
register_command("warn", warn, 2);
|
||||||
|
register_command("unwarn", unwarn, 1);
|
||||||
|
|
||||||
|
intents::guild_ban_remove.push_back([] (CGuild server, const Ban& ban) {
|
||||||
|
// Reset warnings for the unbanned user
|
||||||
|
env.db->update(get_db_identifier(ban.user->id, server->id), "WARNS", 0, nullptr, db_templates::member);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static Warns warns;
|
|
@ -3,9 +3,9 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <cdlpp/cdltypes.hpp>
|
||||||
#include "database.hpp"
|
#include "database.hpp"
|
||||||
#include "db_templates.hpp"
|
#include "db_templates.hpp"
|
||||||
#include "cdltypes.hpp"
|
|
||||||
#include "cust.hpp"
|
#include "cust.hpp"
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace CDL;
|
using namespace CDL;
|
||||||
|
@ -25,6 +25,11 @@ static const std::vector<std::string> get_table_tmpl(db_templates::type type) {
|
||||||
return {"BALANCE INT CHECK(BALANCE > -1) ",
|
return {"BALANCE INT CHECK(BALANCE > -1) ",
|
||||||
"LAST_DAILY INT ",
|
"LAST_DAILY INT ",
|
||||||
"GC_BLACKLISTED BOOLEAN "};
|
"GC_BLACKLISTED BOOLEAN "};
|
||||||
|
case member:
|
||||||
|
return {"WARN0 TEXT ",
|
||||||
|
"WARN1 TEXT ",
|
||||||
|
"WARN2 TEXT ",
|
||||||
|
"WARNS INT CHECK(WARNS >= 0) "};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -41,15 +46,22 @@ static const std::map<std::string, std::string> get_record_tmpl(db_templates::ty
|
||||||
return {
|
return {
|
||||||
{"BALANCE", env.settings.contains("start_money")?std::to_string(env.settings["start_money"].get<uint32_t>()):"0"},
|
{"BALANCE", env.settings.contains("start_money")?std::to_string(env.settings["start_money"].get<uint32_t>()):"0"},
|
||||||
{"LAST_DAILY", "-1"},
|
{"LAST_DAILY", "-1"},
|
||||||
{"GC_BLACKLISTED", "false"}
|
{"GC_BLACKLISTED", "false"},
|
||||||
};
|
};
|
||||||
|
case member:
|
||||||
|
return {
|
||||||
|
{"WARN0", ""},
|
||||||
|
{"WARN1", ""},
|
||||||
|
{"WARN2", ""},
|
||||||
|
{"WARNS", "0"},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void in_main() {
|
void in_main() {
|
||||||
// Initialise database client
|
// Initialise database client
|
||||||
env.db = new Database(*env.aioc, get_table_tmpl, get_record_tmpl);
|
env.db = new Database(get_table_tmpl, get_record_tmpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_prefix(CChannel channel, std::function<void (const std::string&)> cb) {
|
void get_prefix(CChannel channel, std::function<void (const std::string&)> cb) {
|
||||||
|
|
19
cdlpp.cmake
Normal file
19
cdlpp.cmake
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
function(use_cdlpp target cdlpp_src_dir)
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(cdlpp IMPORTED_TARGET cdlpp)
|
||||||
|
|
||||||
|
option(FORCE_SUBMODULE_CDLPP "Use CDLPP from submodule even if installed in system" No)
|
||||||
|
if(cdlpp_FOUND AND NOT FORCE_SUBMODULE_CDLPP)
|
||||||
|
set(CDLPP_LIB PkgConfig::cdlpp)
|
||||||
|
else()
|
||||||
|
execute_process(
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
COMMAND git submodule update --init --recursive --depth 1
|
||||||
|
)
|
||||||
|
add_subdirectory(${cdlpp_src_dir})
|
||||||
|
set(CDLPP_LIB "cdlpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||||
|
${CDLPP_LIB})
|
||||||
|
endfunction()
|
|
@ -6,6 +6,7 @@
|
||||||
"team": [
|
"team": [
|
||||||
<team member IDs as integers>
|
<team member IDs as integers>
|
||||||
],
|
],
|
||||||
|
"owner": <owner user ID>,
|
||||||
"start_money": <how much initial money the users receive; ommit to set to 0>,
|
"start_money": <how much initial money the users receive; ommit to set to 0>,
|
||||||
"daily_money": <how much daily money the users can receive; ommit to disable daily money>
|
"daily_money": <how much daily money the users can receive; ommit to disable daily money>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ Page **1/1**
|
||||||
• You can call up a page with `{0}help [page]`
|
• You can call up a page with `{0}help [page]`
|
||||||
|
|
||||||
:gear: **Useful**
|
:gear: **Useful**
|
||||||
• `serverinfo`, `avatar`
|
• `serverinfo`, `avatar`, `opensource`
|
||||||
|
|
||||||
:dollar: **Money**
|
:dollar: **Money**
|
||||||
• `balance/bal`, `pay`, `daily`, `bet`
|
• `balance/bal`, `pay`, `daily`, `bet`
|
||||||
|
|
||||||
:tools: **Servermanagement**
|
:tools: **Servermanagement**
|
||||||
• `kick`, `ban`, `prefix`, `nick`, `welcomedm`, `autoroles`
|
• `kick`, `ban`, `warn`, `unwarn`, `warns`, `prefix`, `nick`, `welcomedm`, `autoroles`
|
||||||
|
|
||||||
:smile: **Fun**
|
:smile: **Fun**
|
||||||
• `random`, `8ball`
|
• `random`, `8ball`, `notaperson`, `notacat`, `notahorse`, `notarental`
|
||||||
|
|
||||||
:speech_balloon: **Misc**
|
:speech_balloon: **Misc**
|
||||||
• `about`, `setup`, `invite`
|
• `about`, `setup`, `invite`
|
||||||
|
|
|
@ -38,6 +38,26 @@
|
||||||
"@EvilOne Scammer"
|
"@EvilOne Scammer"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"warn": {
|
||||||
|
"badusage_text": ":warning: I need to know who to warn.",
|
||||||
|
"usage": "<@member (mention)> <reason>",
|
||||||
|
"examples": [
|
||||||
|
"@EvilOne Scammer"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unwarn": {
|
||||||
|
"badusage_text": ":warning: I need to know who to unwarn.",
|
||||||
|
"usage": "<@member (mention)>",
|
||||||
|
"examples": [
|
||||||
|
"@GoodOne"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"warns": {
|
||||||
|
"usage": "<@member (mention)>",
|
||||||
|
"examples": [
|
||||||
|
"@tuxifan"
|
||||||
|
]
|
||||||
|
},
|
||||||
"balance": {
|
"balance": {
|
||||||
"usage": "[user]",
|
"usage": "[user]",
|
||||||
"examples": [
|
"examples": [
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit f2a8cf3eb1d1b489bdfe59484414c65e2a3d0cc2
|
Subproject commit 1ffb9581d40547bee82e193691c3eedb84746347
|
|
@ -1 +1 @@
|
||||||
Subproject commit d605e9e32f70bd08a143cb8f4ba6b1c0225a989a
|
Subproject commit ac425fd277f5e7c20951d102e391c229cbe499b8
|
Reference in a new issue