Compare commits
30 Commits
7f0f85a7ad
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 60adc1e937 | |||
| af80a94cfb | |||
| cdf5c2bce6 | |||
| 25735e3581 | |||
| a3919853b0 | |||
| a4e7c64193 | |||
| 0453caee43 | |||
| 5779f54f2d | |||
| 1d63fc050c | |||
| 05dc40863e | |||
| c04ec75f3e | |||
| 5d24893af6 | |||
| cee2e47b6c | |||
| cffeff4e27 | |||
| d20326a846 | |||
| a7a15dc3b1 | |||
| 18b19f0695 | |||
| f59a2c1b7f | |||
| 9a01af14f7 | |||
| 8e732b34ca | |||
| 5c911042be | |||
| 8177787376 | |||
| 44aba55f5e | |||
| b43472227a | |||
| 5f8ceb94b2 | |||
| 6461fa4b94 | |||
| 9b8b2d28e5 | |||
| 17e98f9160 | |||
| 88b6b4fb8d | |||
| a070bdd528 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Cargo.nix linguist-generated
|
||||||
21
.github/workflows/main.yml
vendored
21
.github/workflows/main.yml
vendored
@@ -1,21 +0,0 @@
|
|||||||
name: main
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
jobs:
|
|
||||||
packages:
|
|
||||||
name: test packages
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2.3.4
|
|
||||||
- uses: cachix/install-nix-action@v13
|
|
||||||
with:
|
|
||||||
install_url: https://github.com/numtide/nix-flakes-installer/releases/download/nix-2.4pre20210429_d15a196/install
|
|
||||||
extra_nix_config: |
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
- uses: cachix/cachix-action@v10
|
|
||||||
with:
|
|
||||||
name: natto1784
|
|
||||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
|
||||||
- run: nix build
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,2 +1,7 @@
|
|||||||
target/
|
target/
|
||||||
result
|
result
|
||||||
|
\#*\#
|
||||||
|
.\#*
|
||||||
|
.*~*~
|
||||||
|
*~
|
||||||
|
result-bin
|
||||||
|
|||||||
714
Cargo.lock
generated
714
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
15
Cargo.toml
15
Cargo.toml
@@ -1,19 +1,22 @@
|
|||||||
|
cargo-features = ["edition2021"]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "singh3"
|
name = "singh3"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = [ "Amneesh Singh <natto@weirdnatto.in>" ]
|
authors = [ "Amneesh Singh <natto@weirdnatto.in>" ]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tracing = "0.1.22"
|
tracing = "*"
|
||||||
regex = "1.5.4"
|
regex = "1"
|
||||||
tokio-postgres = "0.7.2"
|
tokio-postgres = "*"
|
||||||
rand = "0.8.4"
|
rand = "*"
|
||||||
|
|
||||||
[dependencies.serenity]
|
[dependencies.serenity]
|
||||||
version = "0.10.8"
|
version = "0.10.10"
|
||||||
features = ["cache", "framework", "standard_framework", "rustls_backend", "unstable_discord_api", "collector"]
|
features = ["cache", "framework", "standard_framework", "rustls_backend", "unstable_discord_api", "collector"]
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
features = ["macros", "signal", "rt-multi-thread"]
|
features = ["macros", "signal", "rt-multi-thread"]
|
||||||
|
|
||||||
|
|||||||
10
README.md
Normal file
10
README.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[](https://ci.weirdnatto.in/teams/main/pipelines/singh3) [](https://hub.docker.com/repository/docker/natto17/singh3)
|
||||||
|
# Singh3
|
||||||
|
My stupid discord bot that I will probably stop maintaining again like I did for the past 8+ months
|
||||||
|
Real shit code
|
||||||
|
- Not really a useful bot, run at your own risk
|
||||||
|
- You need postgresql too
|
||||||
|
- Environment Variables
|
||||||
|
- DISCORD_TOKEN={{.your-discord-token}}
|
||||||
|
- DB_URL={{.your-postgresql-db-url}}
|
||||||
|
- Image size is kinda large cuz it uses ubuntu for libraries that are dynamically needed
|
||||||
85
ci/pipeline.yml
Normal file
85
ci/pipeline.yml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
resource_types:
|
||||||
|
- name: nomad
|
||||||
|
type: registry-image
|
||||||
|
source:
|
||||||
|
repository: natto17/concourse-nomad-resource
|
||||||
|
tag: latest
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- name: image
|
||||||
|
type: registry-image
|
||||||
|
icon: docker
|
||||||
|
source:
|
||||||
|
repository: ((docker.user))/singh3
|
||||||
|
tag: latest
|
||||||
|
username: ((docker.user))
|
||||||
|
password: ((docker.pass))
|
||||||
|
|
||||||
|
- name: nomad-job
|
||||||
|
type: nomad
|
||||||
|
source:
|
||||||
|
url: https://nomad.weirdnatto.in
|
||||||
|
name: singh3
|
||||||
|
token: ((nomad.token))
|
||||||
|
consul_token: ((nomad.consul))
|
||||||
|
vault_token: ((nomad.vault))
|
||||||
|
|
||||||
|
- name: repo
|
||||||
|
type: git
|
||||||
|
icon: discord
|
||||||
|
source:
|
||||||
|
uri: https://git.weirdnatto.in/natto1784/singh3.git
|
||||||
|
branch: master
|
||||||
|
|
||||||
|
- name: nix
|
||||||
|
type: registry-image
|
||||||
|
icon: docker
|
||||||
|
source:
|
||||||
|
repository: nixos/nix
|
||||||
|
tag: latest
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
- name: configure-self
|
||||||
|
public: true
|
||||||
|
plan:
|
||||||
|
- get: repo
|
||||||
|
trigger: true
|
||||||
|
- set_pipeline: self
|
||||||
|
file: repo/ci/pipeline.yml
|
||||||
|
- name: singh3
|
||||||
|
plan:
|
||||||
|
- get: repo
|
||||||
|
trigger: true
|
||||||
|
passed: [configure-self]
|
||||||
|
- get: nix
|
||||||
|
trigger: false
|
||||||
|
- task: build
|
||||||
|
image: nix
|
||||||
|
config:
|
||||||
|
params:
|
||||||
|
CACHIX_NAME: ((cachix.name))
|
||||||
|
CACHIX_AUTH_TOKEN: ((cachix.token))
|
||||||
|
inputs:
|
||||||
|
- name: repo
|
||||||
|
outputs:
|
||||||
|
- name: upload
|
||||||
|
platform: linux
|
||||||
|
run:
|
||||||
|
path: sh
|
||||||
|
args:
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
nix-env -iA nixpkgs.cachix nixpkgs.gzip
|
||||||
|
cachix use $CACHIX_NAME
|
||||||
|
cachix watch-exec pain nix -- --extra-experimental-features "nix-command flakes" build ./repo
|
||||||
|
nix --extra-experimental-features "nix-command flakes" build ./repo#image -o result
|
||||||
|
gzip -cd < $(readlink result) > ./upload/image.tar
|
||||||
|
- put: image
|
||||||
|
inputs: [upload]
|
||||||
|
params:
|
||||||
|
image: upload/image.tar
|
||||||
|
- put: nomad-job
|
||||||
|
params:
|
||||||
|
job_path: repo/singh3.nomad
|
||||||
|
templating: false
|
||||||
|
restart: true
|
||||||
10
default.nix
Normal file
10
default.nix
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
(import
|
||||||
|
(
|
||||||
|
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{ src = ./.; }
|
||||||
|
).defaultNix
|
||||||
108
flake.lock
generated
108
flake.lock
generated
@@ -1,12 +1,47 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"cargo2nix": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1648397583,
|
||||||
|
"narHash": "sha256-g1Ej9APkfHjGd9ExBDvpmyAvsKcfMOsNH6p95xc8E/Y=",
|
||||||
|
"owner": "cargo2nix",
|
||||||
|
"repo": "cargo2nix",
|
||||||
|
"rev": "4362ae00fe824d120e94dd5d6f6e63969dc3d264",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cargo2nix",
|
||||||
|
"repo": "cargo2nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1614513358,
|
"lastModified": 1638122382,
|
||||||
"narHash": "sha256-LakhOx3S1dRjnh0b5Dg3mbZyH0ToC9I8Y2wKSkBaTzU=",
|
"narHash": "sha256-sQzZzAbvKEqN9s0bzWuYmRaA03v40gaJ4+iL1LXjaeI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "5466c5bbece17adaab2d82fae80b46e807611bf3",
|
"rev": "74f7e4319258e287b0f9cb95426c9853b282730b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1637014545,
|
||||||
|
"narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "bba5dcc8e0b20ab664967ad83d24d64cb64ec4f4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -16,6 +51,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1638109994,
|
||||||
|
"narHash": "sha256-OpA37PTiPMIqoRJbufbl5rOLII7HeeGcA0yl7FoyCIE=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "a284564b7f75ac4db73607db02076e8da9d42c9d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "release-21.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1622966049,
|
"lastModified": 1622966049,
|
||||||
"narHash": "sha256-6g+28v94ISkVk9TBSsITVOnB2slK8plieWPIF2jo/l0=",
|
"narHash": "sha256-6g+28v94ISkVk9TBSsITVOnB2slK8plieWPIF2jo/l0=",
|
||||||
@@ -31,39 +82,66 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1617325113,
|
"lastModified": 1637453606,
|
||||||
"narHash": "sha256-GksR0nvGxfZ79T91UUtWjjccxazv6Yh/MvEJ82v1Xmw=",
|
"narHash": "sha256-Gy6cwUswft9xqsjWxFYEnx/63/qzaFUwatcbV5GF/GQ=",
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "54c1e44240d8a527a8f4892608c4bce5440c3ecb",
|
"rev": "8afc4e543663ca0a6a4f496262cd05233737e732",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs",
|
"cargo2nix": "cargo2nix",
|
||||||
"rust-overlay": "rust-overlay",
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"rust-overlay": "rust-overlay_2",
|
||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
"rust-overlay": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": [
|
||||||
"nixpkgs": "nixpkgs_2"
|
"cargo2nix",
|
||||||
|
"flake-utils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"cargo2nix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1623034161,
|
"lastModified": 1638152159,
|
||||||
"narHash": "sha256-cbw9X+nVFcpIuBga0hkbtzXbW2fyDWBon6oUN/uQmu0=",
|
"narHash": "sha256-Q0UHsm36cCxk16I/bF1rHJHxjIflESKk2ej76P39j90=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "0b952cdfa37f8b0fc70fc75fbd4605227cd0b272",
|
"rev": "d9a664513558376595e838b21348cdac0ba3115e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay_2": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_2",
|
||||||
|
"nixpkgs": "nixpkgs_3"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1648953213,
|
||||||
|
"narHash": "sha256-kXWcXFwqcvooHjcDoEK4mtvKU/8LuetwhrofU+9KMS0=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "caa1a7ea867138d4f4e05bd2f41d707df0a61cde",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
73
flake.nix
73
flake.nix
@@ -1,37 +1,54 @@
|
|||||||
{
|
{
|
||||||
description = "A simple filehost written in rust";
|
description = "singh3 discord bot";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = github:nixos/nixpkgs/nixos-unstable;
|
nixpkgs.url = github:nixos/nixpkgs/nixos-unstable;
|
||||||
utils.url = github:numtide/flake-utils;
|
utils.url = github:numtide/flake-utils;
|
||||||
rust-overlay.url = github:oxalica/rust-overlay;
|
rust-overlay.url = github:oxalica/rust-overlay;
|
||||||
|
cargo2nix.url = github:cargo2nix/cargo2nix;
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, utils, rust-overlay }:
|
outputs = { self, nixpkgs, utils, rust-overlay, cargo2nix }:
|
||||||
utils.lib.eachDefaultSystem
|
utils.lib.eachDefaultSystem
|
||||||
(system:
|
(system:
|
||||||
let
|
let
|
||||||
overlays = [ (import rust-overlay) ];
|
overlays =
|
||||||
pkgs = import nixpkgs {
|
[
|
||||||
inherit system overlays;
|
(import "${cargo2nix}/overlay")
|
||||||
};
|
rust-overlay.overlay
|
||||||
in
|
];
|
||||||
{
|
|
||||||
devShell = with pkgs; mkShell {
|
pkgs = import nixpkgs {
|
||||||
buildInputs = [
|
inherit system overlays;
|
||||||
rust-bin.nightly.latest.default
|
};
|
||||||
rust-analyzer
|
|
||||||
];
|
rustPkgs = pkgs.rustBuilder.makePackageSet' {
|
||||||
};
|
rustChannel = "latest";
|
||||||
defaultPackage = pkgs.rustPlatform.buildRustPackage rec {
|
packageFun = import ./Cargo.nix;
|
||||||
pname = "singh3";
|
};
|
||||||
version = "0.1.0";
|
|
||||||
src = ./. ;
|
in
|
||||||
nativeBuildInputs = with pkgs; [
|
rec {
|
||||||
rust-bin.nightly.latest.default
|
devShell = with pkgs; mkShell {
|
||||||
];
|
buildInputs = [
|
||||||
cargoSha256 = "sha256-K+WHOEo6reNfcs7pOZZmHZfZl4pUqlykfTdqgSyVURU=";
|
rust-bin.nightly.latest.default
|
||||||
};
|
rust-analyzer
|
||||||
}
|
postgresql
|
||||||
);
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
packages = {
|
||||||
|
default = (rustPkgs.workspace.singh3 { }).bin;
|
||||||
|
image = pkgs.dockerTools.buildImage {
|
||||||
|
name = "singh3";
|
||||||
|
tag = "latest";
|
||||||
|
created = "now";
|
||||||
|
contents = [ packages.default ];
|
||||||
|
config.Cmd = [ "/bin/singh3" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultPackage = packages.default;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
13
init.sql
Normal file
13
init.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS words (
|
||||||
|
id serial primary key,
|
||||||
|
name varchar not null,
|
||||||
|
reg varchar not null,
|
||||||
|
owner varchar );
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS tags (
|
||||||
|
id serial primary key,
|
||||||
|
name varchar unique not null,
|
||||||
|
value varchar not null,
|
||||||
|
owner varchar );
|
||||||
|
|
||||||
|
CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;
|
||||||
85
singh3.nomad
Normal file
85
singh3.nomad
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
job "singh3" {
|
||||||
|
region = "global"
|
||||||
|
datacenters = ["nazrin"]
|
||||||
|
type = "service"
|
||||||
|
|
||||||
|
group "svc" {
|
||||||
|
count = 1
|
||||||
|
|
||||||
|
network {
|
||||||
|
mode = "bridge"
|
||||||
|
|
||||||
|
port "db" {
|
||||||
|
static = 5454
|
||||||
|
to = 5432
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vault {
|
||||||
|
policies = ["singh3-policy"]
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
name = "singh3-db"
|
||||||
|
port = "db"
|
||||||
|
}
|
||||||
|
|
||||||
|
task "db" {
|
||||||
|
template {
|
||||||
|
data = <<EOF
|
||||||
|
{{with secret "kv/data/singh3/db"}}{{.Data.data.pass}}{{end}}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
destination = "${NOMAD_SECRETS_DIR}/db.pass"
|
||||||
|
}
|
||||||
|
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "postgres:alpine"
|
||||||
|
ports = ["db"]
|
||||||
|
volumes = ["/var/lib/nomad-st/postgres-singh3:/var/lib/postgresql/data"]
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
POSTGRES_USER = "singh3"
|
||||||
|
POSTGRES_PASSWORD_FILE = "${NOMAD_SECRETS_DIR}/db.pass"
|
||||||
|
POSTGRES_DB = "singh3"
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 128
|
||||||
|
memory = 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task "bot" {
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "natto17/singh3:latest"
|
||||||
|
force_pull = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 128
|
||||||
|
memory = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
data = <<EOF
|
||||||
|
{{with secret "kv/data/singh3/db"}}
|
||||||
|
DB_URL="postgresql://singh3:{{.Data.data.pass}}@localhost:5432/singh3"
|
||||||
|
{{end}}
|
||||||
|
{{with secret "kv/data/singh3/discord"}}
|
||||||
|
DISCORD_TOKEN="{{.Data.data.token}}"
|
||||||
|
{{end}}
|
||||||
|
RUST_BACKTRACE=1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
destination = "${NOMAD_SECRETS_DIR}/data.env"
|
||||||
|
env = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,48 +1,65 @@
|
|||||||
|
use crate::lib::components::make_terminal_components;
|
||||||
|
use core::time::Duration;
|
||||||
|
use regex::Regex;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
|
builder::CreateEmbed,
|
||||||
|
collector::component_interaction_collector::ComponentInteractionCollectorBuilder,
|
||||||
framework::standard::{macros::command, Args, CommandResult},
|
framework::standard::{macros::command, Args, CommandResult},
|
||||||
model::prelude::*,
|
futures::StreamExt,
|
||||||
|
model::{interactions::InteractionResponseType, prelude::*},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
utils::Colour,
|
||||||
};
|
};
|
||||||
use std::env;
|
use tokio_postgres::Row;
|
||||||
use tokio_postgres::NoTls;
|
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
#[aliases("kitna", "c")]
|
||||||
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
|
pub async fn count(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
if query == "" {
|
if args.len() > 2 || args.len() == 0 {
|
||||||
msg.reply(ctx, "bruh kitna kya?").await?;
|
msg.reply(ctx, "Please use `,count <word> <user>`").await?;
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
let db: String = env::var("DB_URL").expect("bhay DB_URL daal na");
|
|
||||||
let (client, conn) = tokio_postgres::connect(&db, NoTls)
|
let query = args.single::<String>().unwrap();
|
||||||
.await
|
let user = if args.len() == 2 {
|
||||||
.expect("cant connect bha");
|
let user = args.single::<UserId>();
|
||||||
tokio::spawn(async move {
|
match user {
|
||||||
if let Err(e) = conn.await {
|
Ok(id) => match id.to_user(&ctx.http).await {
|
||||||
eprintln!("connection error: {}", e);
|
Ok(u) => u,
|
||||||
|
Err(_) => {
|
||||||
|
msg.reply(ctx, "No such user").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
msg.reply(ctx, "No such user").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
let id = msg.author.id.as_u64().to_owned().to_string();
|
msg.author.clone()
|
||||||
let mut query_helper = client
|
};
|
||||||
.query(
|
|
||||||
format!("select name from words where '{}' ~ reg", query).as_str(),
|
let data_read = ctx.data.read().await;
|
||||||
&[],
|
let db = data_read
|
||||||
)
|
.get::<crate::Database>()
|
||||||
.await
|
.expect("Expected Database in TypeMap.")
|
||||||
.expect("helper query to select count failed");
|
.clone();
|
||||||
|
|
||||||
|
let id = user.id.to_string();
|
||||||
|
let mut query_helper = db
|
||||||
|
.query("SELECT name FROM words WHERE $1 ~ reg", &[&query])
|
||||||
|
.await?;
|
||||||
|
|
||||||
if query_helper.is_empty() {
|
if query_helper.is_empty() {
|
||||||
query_helper = client
|
query_helper = db
|
||||||
.query(
|
.query("SELECT name FROM words WHERE name=$1", &[&query])
|
||||||
format!("select name from words where name='{}'", query).as_str(),
|
.await?;
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("helper query to select count failed");
|
|
||||||
if query_helper.is_empty() {
|
if query_helper.is_empty() {
|
||||||
msg.reply(
|
msg.reply(
|
||||||
ctx,
|
ctx,
|
||||||
format!(
|
format!(
|
||||||
"No entry for '{}' found. If you want to add it, run 'xxadd {}&<regex>'",
|
"No entry for '{}' found. If you want to add it, run `,cadd {} <regex>`",
|
||||||
query, query
|
query, query
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -57,47 +74,49 @@ pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
|||||||
};
|
};
|
||||||
for row in query_helper {
|
for row in query_helper {
|
||||||
let name: &str = row.get(0);
|
let name: &str = row.get(0);
|
||||||
let query_result: i32 = client
|
let count_query = db
|
||||||
.query_one(
|
.query(
|
||||||
format!("select count from user{} where name='{}'", id, name).as_str(),
|
format!("SELECT count FROM user{} WHERE name=$1", id).as_str(),
|
||||||
&[],
|
&[&name],
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
.expect("cant select the count")
|
let query_result: i32 = if count_query.is_empty() {
|
||||||
.get(0);
|
0
|
||||||
reply = reply + &format!("\n{} count for you: {}", name, query_result);
|
} else {
|
||||||
|
count_query[0].get(0)
|
||||||
|
};
|
||||||
|
reply += &format!("\n{} count for {}: {}", name, user.name, query_result);
|
||||||
}
|
}
|
||||||
msg.reply(ctx, reply).await?;
|
msg.reply(ctx, reply).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn add(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
pub async fn cadd(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
|
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
|
||||||
let queries = query.split("&").collect::<Vec<&str>>();
|
let queries = query.splitn(2, " ").collect::<Vec<&str>>();
|
||||||
if queries.len() != 2 {
|
if queries.len() != 2 {
|
||||||
msg.reply(ctx, "Please use the proper syntax: xxadd <name>&<regex>\nIf you don't know what regex is, just do: xxadd <name>&<name>")
|
msg.reply(ctx, "Please use the proper syntax: `,cadd <name> <regex>`\nIf you don't know what regex is, just do: `,cadd <name> <name>`")
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if queries[1].contains(" ") {
|
let r = Regex::new(&format!("(?i){}", queries[1]));
|
||||||
msg.reply(ctx, "Not a valid regex").await?;
|
|
||||||
|
if r.is_err() {
|
||||||
|
msg.reply(ctx, "Please enter a valid regex").await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let db: String = env::var("DB_URL").expect("bhay DB_URL daal na");
|
|
||||||
let (client, conn) = tokio_postgres::connect(&db, NoTls)
|
let reg = r.unwrap();
|
||||||
.await
|
|
||||||
.expect("cant connect bha");
|
let data_read = ctx.data.read().await;
|
||||||
tokio::spawn(async move {
|
let db = data_read
|
||||||
if let Err(e) = conn.await {
|
.get::<crate::Database>()
|
||||||
eprintln!("connection error: {}", e);
|
.expect("Expected Database in TypeMap.")
|
||||||
}
|
.clone();
|
||||||
});
|
|
||||||
let check_existense = client
|
let check_existense = db
|
||||||
.query(
|
.query("SELECT name, reg FROM words WHERE name=$1", &[&queries[0]])
|
||||||
format!("select name, reg from words where name='{}'", queries[0]).as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
if check_existense.len() != 0 {
|
if check_existense.len() != 0 {
|
||||||
let reg: String = check_existense[0].get(1);
|
let reg: String = check_existense[0].get(1);
|
||||||
@@ -108,63 +127,50 @@ pub async fn add(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
|||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
client
|
db.execute(
|
||||||
.execute(
|
"INSERT INTO words(name, reg, owner) VALUES($1, $2, $3)",
|
||||||
format!(
|
&[&queries[0], ®.to_string(), &msg.author.id.to_string()],
|
||||||
"insert into words(name, reg, owner) values('{}','(?i){}', '{}')",
|
)
|
||||||
queries[0],
|
.await?;
|
||||||
queries[1],
|
|
||||||
msg.author.id.as_u64().to_owned().to_string()
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
msg.reply(ctx, "Added").await?;
|
msg.reply(ctx, "Added").await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn rm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
#[aliases("crm")]
|
||||||
|
pub async fn cremove(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
|
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
|
||||||
let db: String = env::var("DB_URL").expect("bhay DB_URL daal na");
|
if query == "" {
|
||||||
let (client, conn) = tokio_postgres::connect(&db, NoTls)
|
msg.reply(ctx, "remove what?").await?;
|
||||||
.await
|
return Ok(());
|
||||||
.expect("cant connect bha");
|
}
|
||||||
tokio::spawn(async move {
|
let data_read = ctx.data.read().await;
|
||||||
if let Err(e) = conn.await {
|
let db = data_read
|
||||||
eprintln!("connection error: {}", e);
|
.get::<crate::Database>()
|
||||||
}
|
.expect("Expected Database in TypeMap.")
|
||||||
});
|
.clone();
|
||||||
let owner = client
|
let owner = db
|
||||||
.query(
|
.query("SELECT owner FROM words WHERE name=$1", &[&query])
|
||||||
format!("select owner from words where name = '{}'", query).as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
if owner.len() == 1 {
|
if owner.len() == 1 {
|
||||||
let owner_id: String = owner[0].get(0);
|
let owner_id: String = owner[0].get(0);
|
||||||
if owner_id != msg.author.id.as_u64().to_owned().to_string() {
|
if owner_id != msg.author.id.to_string() {
|
||||||
msg.reply(ctx, "You don't even own this word").await?;
|
msg.reply(ctx, "You don't even own this word").await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client
|
db.execute("DELETE FROM words WHERE name=$1", &[&query])
|
||||||
.execute(
|
|
||||||
format!("delete from words where name='{}'", query,).as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
msg.reply(ctx, "Deleted if it existed").await?;
|
msg.reply(ctx, "Deleted if it existed").await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn change(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
pub async fn cedit(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
|
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
|
||||||
let queries = query.split("&").collect::<Vec<&str>>();
|
let queries = query.splitn(2, "&").collect::<Vec<&str>>();
|
||||||
if queries.len() != 2 {
|
if queries.len() != 2 {
|
||||||
msg.reply(ctx, "Please use the proper syntax\nxxchange <name>&<regex>")
|
msg.reply(ctx, "Please use the proper syntax\n,cedit <name>&<regex>")
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -172,38 +178,182 @@ pub async fn change(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
|||||||
msg.reply(ctx, "Not a valid regex").await?;
|
msg.reply(ctx, "Not a valid regex").await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let db: String = env::var("DB_URL").expect("bhay DB_URL daal na");
|
let data_read = ctx.data.read().await;
|
||||||
let (client, conn) = tokio_postgres::connect(&db, NoTls)
|
let db = data_read
|
||||||
.await
|
.get::<crate::Database>()
|
||||||
.expect("cant connect bha");
|
.expect("Expected Database in TypeMap.")
|
||||||
tokio::spawn(async move {
|
.clone();
|
||||||
if let Err(e) = conn.await {
|
let owner = db
|
||||||
eprintln!("connection error: {}", e);
|
.query("SELECT owner FROM words WHERE name=$1", &[&queries[0]])
|
||||||
}
|
|
||||||
});
|
|
||||||
let owner = client
|
|
||||||
.query(
|
|
||||||
format!("select owner from words where name = '{}'", queries[0]).as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
if owner.len() == 1 {
|
if owner.len() == 1 {
|
||||||
let owner_id: String = owner[0].get(0);
|
let owner_id: String = owner[0].get(0);
|
||||||
if owner_id != msg.author.id.as_u64().to_owned().to_string() {
|
if owner_id != msg.author.id.to_string() {
|
||||||
msg.reply(ctx, "You don't even own this word").await?;
|
msg.reply(ctx, "You don't even own this word").await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client
|
db.execute(
|
||||||
.execute(
|
"UPDATE words SET reg=$1 WHERE name=$2",
|
||||||
format!(
|
&[&("(?i)".to_string() + queries[1]), &queries[0]],
|
||||||
"update words set reg='(?i){}' where name='{}'",
|
)
|
||||||
queries[1], queries[0]
|
.await?;
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
msg.reply(ctx, "Changed the value if it existed").await?;
|
msg.reply(ctx, "Changed the value if it existed").await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_list_embed(cur: usize, group: &[Row]) -> CreateEmbed {
|
||||||
|
let mut e = CreateEmbed::default();
|
||||||
|
e.title(format!("List of words: Page {}", cur))
|
||||||
|
.color(Colour::TEAL);
|
||||||
|
for row in group {
|
||||||
|
let idx: i64 = row.get(0);
|
||||||
|
let name: String = row.get(1);
|
||||||
|
let owner_id: String = row.get(2);
|
||||||
|
e.field(
|
||||||
|
format!("{}. {}", idx, name),
|
||||||
|
format!(" by <@{}>", owner_id),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
e
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[aliases("cls")]
|
||||||
|
pub async fn clist(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
let size = if args.len() > 0 {
|
||||||
|
args.single::<usize>()?
|
||||||
|
} else {
|
||||||
|
5usize
|
||||||
|
};
|
||||||
|
|
||||||
|
if size > 15 {
|
||||||
|
msg.reply(ctx, "Please input a number less than 15").await?;
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
let db = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
|
.expect("Expected Database in TypeMap.")
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
let rows = db
|
||||||
|
.query(
|
||||||
|
"SELECT ROW_NUMBER() OVER (ORDER BY id), name, owner FROM words",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if rows.is_empty() {
|
||||||
|
msg.reply(ctx, "No words stored").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let groups: Vec<&[Row]> = rows.chunks(size).collect();
|
||||||
|
let mut cur = 1;
|
||||||
|
let message = msg
|
||||||
|
.channel_id
|
||||||
|
.send_message(ctx, |m| {
|
||||||
|
m.set_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components("first", groups.len()))
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut collector = ComponentInteractionCollectorBuilder::new(&ctx)
|
||||||
|
.timeout(Duration::from_secs(90))
|
||||||
|
.author_id(msg.author.id)
|
||||||
|
.message_id(message.id)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
while let Some(interaction) = collector.next().await {
|
||||||
|
match interaction.data.custom_id.as_ref() {
|
||||||
|
"next" => {
|
||||||
|
if cur != groups.len() {
|
||||||
|
cur += 1;
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components(
|
||||||
|
if cur == groups.len() { "last" } else { "mid" },
|
||||||
|
groups.len(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"prev" => {
|
||||||
|
if cur != 1 {
|
||||||
|
cur -= 1;
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components(
|
||||||
|
if cur == 1 { "first" } else { "mid" },
|
||||||
|
groups.len(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"first" => {
|
||||||
|
cur = 1;
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components("first", groups.len()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
"last" => {
|
||||||
|
cur = groups.len();
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components("last", groups.len()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
"delete" => {
|
||||||
|
message.delete(ctx).await?;
|
||||||
|
msg.delete(ctx).await?;
|
||||||
|
}
|
||||||
|
"range" => {
|
||||||
|
cur = interaction.data.values[0].parse().unwrap();
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components(
|
||||||
|
if cur == 1 {
|
||||||
|
"first"
|
||||||
|
} else if cur == groups.len() {
|
||||||
|
"last"
|
||||||
|
} else {
|
||||||
|
"mid"
|
||||||
|
},
|
||||||
|
groups.len(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
use serenity::prelude::*;
|
use serenity::framework::standard::{macros::command, CommandResult};
|
||||||
use serenity::model::prelude::*;
|
use serenity::model::prelude::*;
|
||||||
use serenity::framework::standard::{
|
use serenity::prelude::*;
|
||||||
CommandResult,
|
|
||||||
macros::command
|
|
||||||
};
|
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
|
pub async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
pub mod general;
|
|
||||||
pub mod count;
|
pub mod count;
|
||||||
|
pub mod general;
|
||||||
pub mod minigames;
|
pub mod minigames;
|
||||||
|
pub mod tags;
|
||||||
|
|||||||
394
src/commands/tags.rs
Normal file
394
src/commands/tags.rs
Normal file
@@ -0,0 +1,394 @@
|
|||||||
|
use crate::lib::{components::make_terminal_components, messages::ExtractInfo};
|
||||||
|
use core::time::Duration;
|
||||||
|
use serenity::{
|
||||||
|
builder::CreateEmbed,
|
||||||
|
collector::component_interaction_collector::ComponentInteractionCollectorBuilder,
|
||||||
|
framework::standard::{macros::command, Args, CommandResult},
|
||||||
|
futures::StreamExt,
|
||||||
|
model::{interactions::InteractionResponseType, prelude::*},
|
||||||
|
prelude::*,
|
||||||
|
utils::Colour,
|
||||||
|
};
|
||||||
|
use tokio_postgres::Row;
|
||||||
|
|
||||||
|
const GUILD_ID: u64 = 874699899067838535;
|
||||||
|
const ROLE_ID: u64 = 957155053184102400;
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[aliases("t")]
|
||||||
|
pub async fn tag(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
|
let query: String = args.raw().collect::<Vec<&str>>().join("");
|
||||||
|
if query == "" {
|
||||||
|
msg.reply(ctx, "Mention the tag retard").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
let db = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
|
.expect("Expected Database in TypeMap.")
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
let query_helper = db
|
||||||
|
.query("SELECT name, value FROM tags WHERE name=$1", &[&query])
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if query_helper.is_empty() {
|
||||||
|
const DIST_LIMIT: i32 = 2;
|
||||||
|
let leven = db
|
||||||
|
.query(
|
||||||
|
"SELECT name, levenshtein_less_equal(name, $1, $2) AS lev FROM tags ORDER BY lev LIMIT 1 ",
|
||||||
|
&[&query, &DIST_LIMIT],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let dist: i32 = leven[0].get(1);
|
||||||
|
|
||||||
|
let l = if dist > DIST_LIMIT {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
let leven_name: String = leven[0].get(0);
|
||||||
|
format!("\nDid you mean `{}`?", leven_name)
|
||||||
|
};
|
||||||
|
|
||||||
|
msg.reply(
|
||||||
|
ctx,
|
||||||
|
format!(
|
||||||
|
"No entry for '{}' found. If you want to add it, run `,tadd {} <value>`{}",
|
||||||
|
query, query, l
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let value: String = query_helper[0].get(1);
|
||||||
|
msg.reply(ctx, value).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
pub async fn tadd(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
let tag_value = msg.extract_text(2, true);
|
||||||
|
|
||||||
|
if tag_value.is_none() {
|
||||||
|
msg.reply(
|
||||||
|
ctx,
|
||||||
|
"Please use the proper syntax: `,tadd <name> <value>` or attach something",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let tag_name = args.single::<String>().unwrap();
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
let db = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
|
.expect("Expected Database in TypeMap.")
|
||||||
|
.clone();
|
||||||
|
let check_existense = db
|
||||||
|
.query("SELECT name FROM tags WHERE name=$1", &[&tag_name])
|
||||||
|
.await?;
|
||||||
|
if check_existense.len() != 0 {
|
||||||
|
msg.reply(ctx, format!("This tag already exists")).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
db.execute(
|
||||||
|
"INSERT INTO tags(name, value, owner) VALUES($1, $2, $3)",
|
||||||
|
&[&tag_name, &tag_value, &msg.author.id.to_string()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
msg.reply(ctx, "Added").await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[aliases("tcp")]
|
||||||
|
pub async fn tcopy(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
|
let queries: Vec<&str> = args.raw().collect::<Vec<&str>>();
|
||||||
|
if queries.len() != 2 {
|
||||||
|
msg.reply(
|
||||||
|
ctx,
|
||||||
|
"Please use the proper syntax: `,tcopy <original> <new>`",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
let db = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
|
.expect("Expected Database in TypeMap.")
|
||||||
|
.clone();
|
||||||
|
let check_existense = db
|
||||||
|
.query("SELECT name FROM tags WHERE name=$1", &[&queries[0]])
|
||||||
|
.await?;
|
||||||
|
if check_existense.len() == 0 {
|
||||||
|
msg.reply(ctx, format!("This tag does not exist")).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
db.execute(
|
||||||
|
"INSERT INTO tags(name, value, owner) SELECT $1, value, $2 FROM tags WHERE name=$3",
|
||||||
|
&[&queries[1], &msg.author.id.to_string(), &queries[0]],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
msg.reply(ctx, format!("Copied {} to {}", queries[0], queries[1]))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[aliases("trm")]
|
||||||
|
pub async fn tremove(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
|
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
|
||||||
|
if query == "" {
|
||||||
|
msg.reply(ctx, "remove what?").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
let db = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
|
.expect("Expected Database in TypeMap.")
|
||||||
|
.clone();
|
||||||
|
let owner = db
|
||||||
|
.query("SELECT owner FROM tags WHERE name=$1", &[&query])
|
||||||
|
.await?;
|
||||||
|
if owner.len() == 1 {
|
||||||
|
let owner_id: String = owner[0].get(0);
|
||||||
|
if owner_id != msg.author.id.to_string()
|
||||||
|
&& !msg.author.has_role(&ctx.http, GUILD_ID, ROLE_ID).await?
|
||||||
|
{
|
||||||
|
msg.reply(ctx, "You don't even own this tag").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.execute("DELETE FROM tags WHERE name=$1", &[&query])
|
||||||
|
.await?;
|
||||||
|
msg.reply(ctx, format!("Deleted {} if it existed", query))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
pub async fn tedit(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
let tag_value = msg.extract_text(2, true);
|
||||||
|
|
||||||
|
if tag_value.is_none() {
|
||||||
|
msg.reply(
|
||||||
|
ctx,
|
||||||
|
"Please use the proper syntax: `,tadd <name> <value>` or attach something",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let tag_name = args.single::<String>().unwrap();
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
let db = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
|
.expect("Expected Database in TypeMap.")
|
||||||
|
.clone();
|
||||||
|
let owner = db
|
||||||
|
.query("SELECT owner FROM tags WHERE name=$1", &[&tag_name])
|
||||||
|
.await?;
|
||||||
|
if owner.len() == 1 {
|
||||||
|
let owner_id: String = owner[0].get(0);
|
||||||
|
if owner_id != msg.author.id.to_string()
|
||||||
|
&& !msg.author.has_role(&ctx.http, GUILD_ID, ROLE_ID).await?
|
||||||
|
{
|
||||||
|
msg.reply(ctx, "You don't even own this tag").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.execute(
|
||||||
|
"UPDATE tags SET value=$1 WHERE name=$2",
|
||||||
|
&[&tag_value, &tag_name],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
msg.reply(ctx, "Changed the value if it existed").await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_list_embed(cur: usize, group: &[Row]) -> CreateEmbed {
|
||||||
|
let mut e = CreateEmbed::default();
|
||||||
|
e.title(format!("List of tags: Page {}", cur))
|
||||||
|
.color(Colour::FABLED_PINK);
|
||||||
|
for row in group {
|
||||||
|
let idx: i64 = row.get(0);
|
||||||
|
let name: String = row.get(1);
|
||||||
|
let owner_id: String = row.get(2);
|
||||||
|
e.field(
|
||||||
|
format!("{}. {}", idx, name),
|
||||||
|
format!(" by <@{}>", owner_id),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
e
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[aliases("tls")]
|
||||||
|
pub async fn tlist(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
let size = if args.len() > 0 {
|
||||||
|
args.single::<usize>()?
|
||||||
|
} else {
|
||||||
|
5usize
|
||||||
|
};
|
||||||
|
|
||||||
|
if size > 15 {
|
||||||
|
msg.reply(ctx, "Please input a number less than 15").await?;
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
let db = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
|
.expect("Expected Database in TypeMap.")
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
let rows = db
|
||||||
|
.query(
|
||||||
|
"SELECT ROW_NUMBER() OVER (ORDER BY id), name, owner FROM tags",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if rows.is_empty() {
|
||||||
|
msg.reply(ctx, "No tags stored").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let groups: Vec<&[Row]> = rows.chunks(size).collect();
|
||||||
|
let mut cur = 1;
|
||||||
|
let message = msg
|
||||||
|
.channel_id
|
||||||
|
.send_message(ctx, |m| {
|
||||||
|
m.set_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components("first", groups.len()))
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut collector = ComponentInteractionCollectorBuilder::new(&ctx)
|
||||||
|
.timeout(Duration::from_secs(90))
|
||||||
|
.author_id(msg.author.id)
|
||||||
|
.message_id(message.id)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
while let Some(interaction) = collector.next().await {
|
||||||
|
match interaction.data.custom_id.as_ref() {
|
||||||
|
"next" => {
|
||||||
|
if cur != groups.len() {
|
||||||
|
cur += 1;
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components(
|
||||||
|
if cur == groups.len() { "last" } else { "mid" },
|
||||||
|
groups.len(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"prev" => {
|
||||||
|
if cur != 1 {
|
||||||
|
cur -= 1;
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components(
|
||||||
|
if cur == 1 { "first" } else { "mid" },
|
||||||
|
groups.len(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"first" => {
|
||||||
|
cur = 1;
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components("first", groups.len()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
"last" => {
|
||||||
|
cur = groups.len();
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components("last", groups.len()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
"delete" => {
|
||||||
|
message.delete(ctx).await?;
|
||||||
|
msg.delete(ctx).await?;
|
||||||
|
}
|
||||||
|
"range" => {
|
||||||
|
cur = interaction.data.values[0].parse().unwrap();
|
||||||
|
let _ = interaction
|
||||||
|
.create_interaction_response(&ctx, |r| {
|
||||||
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|m| {
|
||||||
|
m.add_embed(make_list_embed(cur, groups[cur - 1]))
|
||||||
|
.set_components(make_terminal_components(
|
||||||
|
if cur == 1 {
|
||||||
|
"first"
|
||||||
|
} else if cur == groups.len() {
|
||||||
|
"last"
|
||||||
|
} else {
|
||||||
|
"mid"
|
||||||
|
},
|
||||||
|
groups.len(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[aliases(trand)]
|
||||||
|
pub async fn trandom(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
let db = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
|
.expect("Expected Database in TypeMap.")
|
||||||
|
.clone();
|
||||||
|
let rand = db
|
||||||
|
.query(
|
||||||
|
"SELECT name, value, owner FROM tags OFFSET floor(random() * (SELECT COUNT(*) FROM tags)) LIMIT 1",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let name: String = rand[0].get(0);
|
||||||
|
let value: String = rand[0].get(1);
|
||||||
|
let owner: String = rand[0].get(2);
|
||||||
|
let user_id = UserId::from(owner.parse::<u64>().unwrap());
|
||||||
|
msg.reply(
|
||||||
|
ctx,
|
||||||
|
format!(
|
||||||
|
"{}'s tag {}: \n{}",
|
||||||
|
user_id.to_user(&ctx.http).await?.name,
|
||||||
|
name,
|
||||||
|
value
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,77 +1,55 @@
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use std::env;
|
use tokio_postgres::Client;
|
||||||
use tokio_postgres::NoTls;
|
|
||||||
|
|
||||||
pub async fn count(msg: Message) {
|
pub async fn count(msg: Message, db: std::sync::Arc<Client>) {
|
||||||
let db: String = env::var("DB_URL").expect("bhay DB_URL daal na");
|
|
||||||
let (client, conn) = tokio_postgres::connect(&db, NoTls)
|
|
||||||
.await
|
|
||||||
.expect("cant connect bha");
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = conn.await {
|
|
||||||
eprintln!("connection error: {}", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let id = msg.author.id.as_u64().to_owned().to_string();
|
let id = msg.author.id.as_u64().to_owned().to_string();
|
||||||
client
|
db.execute(
|
||||||
.execute(
|
format!(
|
||||||
format!(
|
r#"
|
||||||
"
|
CREATE TABLE IF NOT EXISTS user{} (
|
||||||
CREATE TABLE IF NOT EXISTS user{} (
|
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR NOT NULL,
|
name VARCHAR NOT NULL,
|
||||||
count INTEGER NOT NULL
|
count INTEGER NOT NULL
|
||||||
)
|
)"#,
|
||||||
",
|
id
|
||||||
id
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
)
|
||||||
.await
|
.as_str(),
|
||||||
.expect("cant create table");
|
&[],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Can't create a user table");
|
||||||
|
|
||||||
for row in client
|
for row in db
|
||||||
.query("SELECT name, reg FROM words", &[])
|
.query("SELECT name, reg FROM words", &[])
|
||||||
.await
|
.await
|
||||||
.expect("can't get the words to count")
|
.expect("Can't get the words to count")
|
||||||
{
|
{
|
||||||
let name: &str = row.get(0);
|
let name: &str = row.get(0);
|
||||||
let regex: Regex = Regex::new(row.get(1)).unwrap();
|
let regex: Regex = Regex::new(row.get(1)).unwrap();
|
||||||
let count = regex.captures_iter(&msg.content).count();
|
let count: i32 = regex.captures_iter(&msg.content).count() as i32;
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
let query_result = client
|
let query_result = db
|
||||||
.query(
|
.query(
|
||||||
format!("SELECT count FROM user{} where name='{}'", id, name).as_str(),
|
format!("SELECT count FROM user{} WHERE name=$1", id).as_str(),
|
||||||
&[],
|
&[&name],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("cant select the count");
|
.expect("Can't select count");
|
||||||
if query_result.is_empty() {
|
if query_result.is_empty() {
|
||||||
client
|
db.execute(
|
||||||
.execute(
|
format!("INSERT INTO user{} (name, count) values ($1, 0)", id).as_str(),
|
||||||
format!(
|
&[&name],
|
||||||
"insert into user{} (name, count) values ('{}', 0)",
|
|
||||||
id, name
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("cant insert shit");
|
|
||||||
}
|
|
||||||
client
|
|
||||||
.execute(
|
|
||||||
format!(
|
|
||||||
"UPDATE user{} SET count = count + {} where name='{}'",
|
|
||||||
id, count, name
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
&[],
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("cant update");
|
.expect("Can't insert count");
|
||||||
|
}
|
||||||
|
db.execute(
|
||||||
|
format!("UPDATE user{} SET count = count + $1 WHERE name=$2", id).as_str(),
|
||||||
|
&[&count, &name],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Can't update count");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,8 @@
|
|||||||
mod interactions;
|
|
||||||
mod count;
|
mod count;
|
||||||
|
mod interactions;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
async_trait,
|
||||||
model::{
|
model::{channel::Message, event::ResumedEvent, gateway::Ready},
|
||||||
event::ResumedEvent,
|
|
||||||
gateway::Ready,
|
|
||||||
channel::Message,
|
|
||||||
interactions::{
|
|
||||||
ApplicationCommand, Interaction, InteractionData, InteractionResponseType,
|
|
||||||
InteractionType,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
@@ -19,34 +11,18 @@ pub struct Handler;
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EventHandler for Handler {
|
impl EventHandler for Handler {
|
||||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
async fn ready(&self, _: Context, ready: Ready) {
|
||||||
info!("{} connected bhay", ready.user.name);
|
println!("{} connected bhay", ready.user.name);
|
||||||
let _ = ApplicationCommand::create_global_application_commands(&ctx.http, |commands| {
|
|
||||||
commands.set_application_commands(interactions::general())
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
async fn resume(&self, _: Context, _: ResumedEvent) {
|
async fn resume(&self, _: Context, _: ResumedEvent) {
|
||||||
info!("how th when the");
|
info!("how th when the");
|
||||||
}
|
}
|
||||||
async fn message(&self, _: Context, msg: Message) {
|
async fn message(&self, ctx: Context, msg: Message) {
|
||||||
count::count(msg).await;
|
let data_read = ctx.data.read().await;
|
||||||
}
|
let db_client = data_read
|
||||||
|
.get::<crate::Database>()
|
||||||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
.expect("Expected Database in TypeMap.")
|
||||||
if interaction.kind == InteractionType::ApplicationCommand {
|
.clone();
|
||||||
if let Some(InteractionData::ApplicationCommand(data)) = interaction.data.as_ref() {
|
count::count(msg, db_client).await;
|
||||||
if let Err(why) = interaction
|
|
||||||
.create_interaction_response(&ctx.http, |response| {
|
|
||||||
response
|
|
||||||
.kind(InteractionResponseType::ChannelMessageWithSource)
|
|
||||||
.interaction_response_data(|message| interactions::responses(data.name.to_string(), message))
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
println!("Cannot respond to slash command: {}", why);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/lib/components.rs
Normal file
62
src/lib/components.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use serenity::{
|
||||||
|
builder::{CreateComponents, CreateSelectMenu},
|
||||||
|
model::{channel::ReactionType, interactions::message_component::ButtonStyle},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn make_range_select_menu(first: usize, last: usize) -> CreateSelectMenu {
|
||||||
|
let mut sm = CreateSelectMenu::default();
|
||||||
|
sm.custom_id("range")
|
||||||
|
.placeholder("Page No")
|
||||||
|
.options(|mut os| {
|
||||||
|
for x in first..=last {
|
||||||
|
os = os.create_option(|o| o.label(x).value(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
os
|
||||||
|
});
|
||||||
|
sm
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_terminal_components(terminal: &str, pages: usize) -> CreateComponents {
|
||||||
|
let mut c = CreateComponents::default();
|
||||||
|
c.create_action_row(|ar| {
|
||||||
|
ar.create_button(|b| {
|
||||||
|
b.style(ButtonStyle::Primary)
|
||||||
|
.label("First")
|
||||||
|
.emoji(ReactionType::Unicode("\u{23EA}".to_string()))
|
||||||
|
.custom_id("first")
|
||||||
|
.disabled(terminal == "first")
|
||||||
|
})
|
||||||
|
.create_button(|b| {
|
||||||
|
b.style(ButtonStyle::Primary)
|
||||||
|
.label("Prev")
|
||||||
|
.emoji(ReactionType::Unicode("\u{25C0}".to_string()))
|
||||||
|
.custom_id("prev")
|
||||||
|
.disabled(terminal == "first")
|
||||||
|
})
|
||||||
|
.create_button(|b| {
|
||||||
|
b.style(ButtonStyle::Primary)
|
||||||
|
.label("Next")
|
||||||
|
.emoji(ReactionType::Unicode("\u{25B6}".to_string()))
|
||||||
|
.custom_id("next")
|
||||||
|
.disabled(terminal == "last")
|
||||||
|
})
|
||||||
|
.create_button(|b| {
|
||||||
|
b.style(ButtonStyle::Primary)
|
||||||
|
.label("Last")
|
||||||
|
.emoji(ReactionType::Unicode("\u{23E9}".to_string()))
|
||||||
|
.custom_id("last")
|
||||||
|
.disabled(terminal == "last")
|
||||||
|
})
|
||||||
|
.create_button(|b| {
|
||||||
|
b.style(ButtonStyle::Danger)
|
||||||
|
.label("Delete")
|
||||||
|
.emoji(ReactionType::Unicode("\u{1F5D1}".to_string()))
|
||||||
|
.custom_id("delete")
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if pages <= 25 {
|
||||||
|
c.create_action_row(|ar| ar.add_select_menu(make_range_select_menu(1, pages)));
|
||||||
|
}
|
||||||
|
c
|
||||||
|
}
|
||||||
40
src/lib/messages.rs
Normal file
40
src/lib/messages.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
use serenity::model::channel::Message;
|
||||||
|
|
||||||
|
pub trait ExtractInfo {
|
||||||
|
fn extract_text(&self, skip: usize, with_ref: bool) -> Option<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExtractInfo for Message {
|
||||||
|
fn extract_text(&self, skip: usize, with_ref: bool) -> Option<String> {
|
||||||
|
let mut ret: String = String::from("");
|
||||||
|
|
||||||
|
let raw: Vec<&str> = self.content.splitn(skip + 1, " ").collect();
|
||||||
|
if raw.len() == skip + 1 {
|
||||||
|
ret += raw[skip];
|
||||||
|
ret += "\n";
|
||||||
|
} else if raw.len() < skip {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += &self
|
||||||
|
.attachments
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.url.clone())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
if let Some(msg) = &self.referenced_message {
|
||||||
|
let ref_text = msg.extract_text(0, false);
|
||||||
|
if with_ref && !ref_text.is_none() {
|
||||||
|
ret += "\n";
|
||||||
|
ret += &ref_text.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.is_empty() {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
return Some(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/lib/mod.rs
Normal file
2
src/lib/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod components;
|
||||||
|
pub mod messages;
|
||||||
69
src/main.rs
69
src/main.rs
@@ -1,35 +1,71 @@
|
|||||||
mod commands;
|
mod commands;
|
||||||
mod handler;
|
mod handler;
|
||||||
|
mod lib;
|
||||||
|
use commands::count::*;
|
||||||
|
use commands::general::*;
|
||||||
|
use commands::minigames::*;
|
||||||
|
use commands::tags::*;
|
||||||
|
use handler::Handler;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
client::bridge::gateway::ShardManager,
|
client::bridge::gateway::ShardManager,
|
||||||
framework::{standard::macros::group, StandardFramework},
|
framework::{
|
||||||
|
standard::{
|
||||||
|
help_commands,
|
||||||
|
macros::{group, help},
|
||||||
|
Args, CommandGroup, CommandResult, HelpOptions,
|
||||||
|
},
|
||||||
|
StandardFramework,
|
||||||
|
},
|
||||||
http::Http,
|
http::Http,
|
||||||
|
model::{channel::Message, id::UserId},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use std::{collections::HashSet, env, sync::Arc};
|
use std::{collections::HashSet, env, sync::Arc};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
pub struct ShardManagerContainer;
|
|
||||||
use commands::general::*;
|
|
||||||
use commands::count::*;
|
|
||||||
use commands::minigames::*;
|
|
||||||
use handler::Handler;
|
|
||||||
|
|
||||||
|
struct ShardManagerContainer;
|
||||||
impl TypeMapKey for ShardManagerContainer {
|
impl TypeMapKey for ShardManagerContainer {
|
||||||
type Value = Arc<Mutex<ShardManager>>;
|
type Value = Arc<Mutex<ShardManager>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Database;
|
||||||
|
impl TypeMapKey for Database {
|
||||||
|
type Value = Arc<tokio_postgres::Client>;
|
||||||
|
}
|
||||||
|
|
||||||
#[group]
|
#[group]
|
||||||
#[commands(ping)]
|
#[commands(ping)]
|
||||||
struct General;
|
struct General;
|
||||||
|
|
||||||
#[group]
|
#[group]
|
||||||
#[commands(kitna,add,rm,change)]
|
#[commands(count, cadd, cremove, cedit, clist)]
|
||||||
struct Count;
|
struct Count;
|
||||||
|
|
||||||
|
#[group]
|
||||||
|
#[commands(tag, tadd, tcopy, tremove, tedit, tlist, trandom)]
|
||||||
|
pub struct Tags;
|
||||||
|
|
||||||
#[group]
|
#[group]
|
||||||
#[commands(challenge)]
|
#[commands(challenge)]
|
||||||
struct Minigames;
|
struct Minigames;
|
||||||
|
|
||||||
|
#[help]
|
||||||
|
#[max_levenshtein_distance(2)]
|
||||||
|
#[indention_prefix = "+"]
|
||||||
|
#[lacking_role = "Nothing"]
|
||||||
|
#[wrong_channel = "Strike"]
|
||||||
|
async fn my_help(
|
||||||
|
context: &Context,
|
||||||
|
msg: &Message,
|
||||||
|
args: Args,
|
||||||
|
help_options: &'static HelpOptions,
|
||||||
|
groups: &[&'static CommandGroup],
|
||||||
|
owners: HashSet<UserId>,
|
||||||
|
) -> CommandResult {
|
||||||
|
let _ = help_commands::with_embeds(context, msg, args, help_options, groups, owners).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let token = env::var("DISCORD_TOKEN").expect("Token daal madarchod");
|
let token = env::var("DISCORD_TOKEN").expect("Token daal madarchod");
|
||||||
@@ -47,9 +83,11 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let framework = StandardFramework::new()
|
let framework = StandardFramework::new()
|
||||||
.configure(|c| c.owners(owners).prefix("xx"))
|
.configure(|c| c.owners(owners).prefix(","))
|
||||||
|
.help(&MY_HELP)
|
||||||
.group(&GENERAL_GROUP)
|
.group(&GENERAL_GROUP)
|
||||||
.group(&COUNT_GROUP)
|
.group(&COUNT_GROUP)
|
||||||
|
.group(&TAGS_GROUP)
|
||||||
.group(&MINIGAMES_GROUP);
|
.group(&MINIGAMES_GROUP);
|
||||||
|
|
||||||
let mut client = Client::builder(&token)
|
let mut client = Client::builder(&token)
|
||||||
@@ -60,7 +98,22 @@ async fn main() {
|
|||||||
.expect("Client no wokey");
|
.expect("Client no wokey");
|
||||||
|
|
||||||
{
|
{
|
||||||
|
let db_url: String = env::var("DB_URL").expect("DB_URL not found");
|
||||||
|
let (db_client, conn) = tokio_postgres::connect(&db_url, tokio_postgres::NoTls)
|
||||||
|
.await
|
||||||
|
.expect("cant connect bha");
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = conn.await {
|
||||||
|
eprintln!("connection error: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let init_script = std::include_str!("../init.sql");
|
||||||
|
db_client
|
||||||
|
.batch_execute(init_script)
|
||||||
|
.await
|
||||||
|
.expect("Couldn't run the init script");
|
||||||
let mut data = client.data.write().await;
|
let mut data = client.data.write().await;
|
||||||
|
data.insert::<Database>(Arc::new(db_client));
|
||||||
data.insert::<ShardManagerContainer>(client.shard_manager.clone());
|
data.insert::<ShardManagerContainer>(client.shard_manager.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user