forked from natto1784/singh3
		
	Compare commits
	
		
			25 Commits
		
	
	
		
	
	| 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 | 
							
								
								
									
										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/
 | 
			
		||||
result
 | 
			
		||||
\#*\#
 | 
			
		||||
.\#*
 | 
			
		||||
.*~*~
 | 
			
		||||
*~
 | 
			
		||||
result-bin
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										714
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										714
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,19 +1,22 @@
 | 
			
		||||
cargo-features = ["edition2021"]
 | 
			
		||||
 | 
			
		||||
[package]
 | 
			
		||||
name = "singh3"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
authors = [ "Amneesh Singh <natto@weirdnatto.in>" ]
 | 
			
		||||
edition = "2018"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
tracing = "*"
 | 
			
		||||
regex = "*"
 | 
			
		||||
regex = "1"
 | 
			
		||||
tokio-postgres = "*"
 | 
			
		||||
rand = "*"
 | 
			
		||||
 | 
			
		||||
[dependencies.serenity]
 | 
			
		||||
version = "0.10.*"
 | 
			
		||||
version = "0.10.10"
 | 
			
		||||
features = ["cache", "framework", "standard_framework", "rustls_backend", "unstable_discord_api", "collector"]
 | 
			
		||||
 | 
			
		||||
[dependencies.tokio]
 | 
			
		||||
version = "1.0"
 | 
			
		||||
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": {
 | 
			
		||||
    "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": {
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1614513358,
 | 
			
		||||
        "narHash": "sha256-LakhOx3S1dRjnh0b5Dg3mbZyH0ToC9I8Y2wKSkBaTzU=",
 | 
			
		||||
        "lastModified": 1638122382,
 | 
			
		||||
        "narHash": "sha256-sQzZzAbvKEqN9s0bzWuYmRaA03v40gaJ4+iL1LXjaeI=",
 | 
			
		||||
        "owner": "numtide",
 | 
			
		||||
        "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"
 | 
			
		||||
      },
 | 
			
		||||
      "original": {
 | 
			
		||||
@@ -16,6 +51,22 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "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": {
 | 
			
		||||
        "lastModified": 1622966049,
 | 
			
		||||
        "narHash": "sha256-6g+28v94ISkVk9TBSsITVOnB2slK8plieWPIF2jo/l0=",
 | 
			
		||||
@@ -31,39 +82,66 @@
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "nixpkgs_2": {
 | 
			
		||||
    "nixpkgs_3": {
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1617325113,
 | 
			
		||||
        "narHash": "sha256-GksR0nvGxfZ79T91UUtWjjccxazv6Yh/MvEJ82v1Xmw=",
 | 
			
		||||
        "owner": "nixos",
 | 
			
		||||
        "lastModified": 1637453606,
 | 
			
		||||
        "narHash": "sha256-Gy6cwUswft9xqsjWxFYEnx/63/qzaFUwatcbV5GF/GQ=",
 | 
			
		||||
        "owner": "NixOS",
 | 
			
		||||
        "repo": "nixpkgs",
 | 
			
		||||
        "rev": "54c1e44240d8a527a8f4892608c4bce5440c3ecb",
 | 
			
		||||
        "rev": "8afc4e543663ca0a6a4f496262cd05233737e732",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      },
 | 
			
		||||
      "original": {
 | 
			
		||||
        "owner": "NixOS",
 | 
			
		||||
        "ref": "nixpkgs-unstable",
 | 
			
		||||
        "repo": "nixpkgs",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "root": {
 | 
			
		||||
      "inputs": {
 | 
			
		||||
        "nixpkgs": "nixpkgs",
 | 
			
		||||
        "rust-overlay": "rust-overlay",
 | 
			
		||||
        "cargo2nix": "cargo2nix",
 | 
			
		||||
        "nixpkgs": "nixpkgs_2",
 | 
			
		||||
        "rust-overlay": "rust-overlay_2",
 | 
			
		||||
        "utils": "utils"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "rust-overlay": {
 | 
			
		||||
      "inputs": {
 | 
			
		||||
        "flake-utils": "flake-utils",
 | 
			
		||||
        "nixpkgs": "nixpkgs_2"
 | 
			
		||||
        "flake-utils": [
 | 
			
		||||
          "cargo2nix",
 | 
			
		||||
          "flake-utils"
 | 
			
		||||
        ],
 | 
			
		||||
        "nixpkgs": [
 | 
			
		||||
          "cargo2nix",
 | 
			
		||||
          "nixpkgs"
 | 
			
		||||
        ]
 | 
			
		||||
      },
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1623034161,
 | 
			
		||||
        "narHash": "sha256-cbw9X+nVFcpIuBga0hkbtzXbW2fyDWBon6oUN/uQmu0=",
 | 
			
		||||
        "lastModified": 1638152159,
 | 
			
		||||
        "narHash": "sha256-Q0UHsm36cCxk16I/bF1rHJHxjIflESKk2ej76P39j90=",
 | 
			
		||||
        "owner": "oxalica",
 | 
			
		||||
        "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"
 | 
			
		||||
      },
 | 
			
		||||
      "original": {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								flake.nix
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								flake.nix
									
									
									
									
									
								
							@@ -1,37 +1,54 @@
 | 
			
		||||
{
 | 
			
		||||
  description = "A simple filehost written in rust";
 | 
			
		||||
  description = "singh3 discord bot";
 | 
			
		||||
 | 
			
		||||
  inputs = {
 | 
			
		||||
    nixpkgs.url = github:nixos/nixpkgs/nixos-unstable;
 | 
			
		||||
    utils.url = github:numtide/flake-utils;
 | 
			
		||||
    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
 | 
			
		||||
      (system:
 | 
			
		||||
        let
 | 
			
		||||
      overlays = [ (import rust-overlay) ];
 | 
			
		||||
          overlays =
 | 
			
		||||
            [
 | 
			
		||||
              (import "${cargo2nix}/overlay")
 | 
			
		||||
              rust-overlay.overlay
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
          pkgs = import nixpkgs {
 | 
			
		||||
            inherit system overlays;
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          rustPkgs = pkgs.rustBuilder.makePackageSet' {
 | 
			
		||||
            rustChannel = "latest";
 | 
			
		||||
            packageFun = import ./Cargo.nix;
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
        in
 | 
			
		||||
    {
 | 
			
		||||
        rec {
 | 
			
		||||
          devShell = with pkgs; mkShell {
 | 
			
		||||
            buildInputs = [
 | 
			
		||||
              rust-bin.nightly.latest.default
 | 
			
		||||
              rust-analyzer
 | 
			
		||||
              postgresql
 | 
			
		||||
            ];
 | 
			
		||||
          };
 | 
			
		||||
      defaultPackage = pkgs.rustPlatform.buildRustPackage rec {
 | 
			
		||||
        pname = "singh3";
 | 
			
		||||
        version = "0.1.0";
 | 
			
		||||
        src = ./. ;
 | 
			
		||||
        nativeBuildInputs = with pkgs; [
 | 
			
		||||
          rust-bin.nightly.latest.default
 | 
			
		||||
        ];
 | 
			
		||||
        cargoSha256 = "sha256-K+WHOEo6reNfcs7pOZZmHZfZl4pUqlykfTdqgSyVURU=";
 | 
			
		||||
 | 
			
		||||
          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;
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								init.sql
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								init.sql
									
									
									
									
									
								
							@@ -3,3 +3,11 @@ CREATE TABLE IF NOT EXISTS words (
 | 
			
		||||
  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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								singh3.nomad
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								singh3.nomad
									
									
									
									
									
								
							@@ -1,52 +1,71 @@
 | 
			
		||||
job "singh3" {
 | 
			
		||||
  region      = "global"
 | 
			
		||||
  datacenters = [ "nazrin" ]
 | 
			
		||||
  datacenters = ["nazrin"]
 | 
			
		||||
  type        = "service"
 | 
			
		||||
 | 
			
		||||
  group "svc" {
 | 
			
		||||
    count = 1
 | 
			
		||||
 | 
			
		||||
    network {
 | 
			
		||||
      mode = "bridge"
 | 
			
		||||
 | 
			
		||||
      port "db" {
 | 
			
		||||
        static = 5454
 | 
			
		||||
        to     = 5432
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vault {
 | 
			
		||||
      policies = [ "singh3-policy" ]
 | 
			
		||||
      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" ]
 | 
			
		||||
        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    = 256
 | 
			
		||||
        memory = 128
 | 
			
		||||
        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"}}
 | 
			
		||||
@@ -57,6 +76,7 @@ DISCORD_TOKEN="{{.Data.data.token}}"
 | 
			
		||||
{{end}}
 | 
			
		||||
RUST_BACKTRACE=1
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
        destination = "${NOMAD_SECRETS_DIR}/data.env"
 | 
			
		||||
        env         = true
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,50 +1,65 @@
 | 
			
		||||
use crate::lib::components::make_terminal_components;
 | 
			
		||||
use core::time::Duration;
 | 
			
		||||
use regex::Regex;
 | 
			
		||||
use serenity::{
 | 
			
		||||
    builder::CreateEmbed,
 | 
			
		||||
    collector::component_interaction_collector::ComponentInteractionCollectorBuilder,
 | 
			
		||||
    framework::standard::{macros::command, Args, CommandResult},
 | 
			
		||||
    futures::StreamExt,
 | 
			
		||||
    model::{
 | 
			
		||||
        channel::ReactionType,
 | 
			
		||||
        interactions::{ButtonStyle, InteractionData},
 | 
			
		||||
        prelude::*,
 | 
			
		||||
    },
 | 
			
		||||
    model::{interactions::InteractionResponseType, prelude::*},
 | 
			
		||||
    prelude::*,
 | 
			
		||||
    utils::Colour,
 | 
			
		||||
};
 | 
			
		||||
use tokio_postgres::Row;
 | 
			
		||||
 | 
			
		||||
#[command]
 | 
			
		||||
pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
 | 
			
		||||
    let query: String = args.raw().collect::<Vec<&str>>().join(" ");
 | 
			
		||||
    if query == "" {
 | 
			
		||||
        msg.reply(ctx, "bruh kitna kya?").await?;
 | 
			
		||||
#[aliases("kitna", "c")]
 | 
			
		||||
pub async fn count(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
 | 
			
		||||
    if args.len() > 2 || args.len() == 0 {
 | 
			
		||||
        msg.reply(ctx, "Please use `,count <word> <user>`").await?;
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let query = args.single::<String>().unwrap();
 | 
			
		||||
    let user = if args.len() == 2 {
 | 
			
		||||
        let user = args.single::<UserId>();
 | 
			
		||||
        match user {
 | 
			
		||||
            Ok(id) => match id.to_user(&ctx.http).await {
 | 
			
		||||
                Ok(u) => u,
 | 
			
		||||
                Err(_) => {
 | 
			
		||||
                    msg.reply(ctx, "No such user").await?;
 | 
			
		||||
                    return Ok(());
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                msg.reply(ctx, "No such user").await?;
 | 
			
		||||
                return Ok(());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        msg.author.clone()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let data_read = ctx.data.read().await;
 | 
			
		||||
    let db = data_read
 | 
			
		||||
        .get::<crate::Database>()
 | 
			
		||||
        .expect("Expected Database in TypeMap.")
 | 
			
		||||
        .clone();
 | 
			
		||||
 | 
			
		||||
    let id = msg.author.id.to_string();
 | 
			
		||||
    let id = user.id.to_string();
 | 
			
		||||
    let mut query_helper = db
 | 
			
		||||
        .query(
 | 
			
		||||
            format!("select name from words where '{}' ~ reg", query).as_str(),
 | 
			
		||||
            &[],
 | 
			
		||||
        )
 | 
			
		||||
        .query("SELECT name FROM words WHERE $1 ~ reg", &[&query])
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
    if query_helper.is_empty() {
 | 
			
		||||
        query_helper = db
 | 
			
		||||
            .query(
 | 
			
		||||
                format!("select name from words where name='{}'", query).as_str(),
 | 
			
		||||
                &[],
 | 
			
		||||
            )
 | 
			
		||||
            .query("SELECT name FROM words WHERE name=$1", &[&query])
 | 
			
		||||
            .await?;
 | 
			
		||||
        if query_helper.is_empty() {
 | 
			
		||||
            msg.reply(
 | 
			
		||||
                ctx,
 | 
			
		||||
                format!(
 | 
			
		||||
                    "No entry for '{}' found. If you want to add it, run ',count add {}&<regex>'",
 | 
			
		||||
                    "No entry for '{}' found. If you want to add it, run `,cadd {} <regex>`",
 | 
			
		||||
                    query, query
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
@@ -59,42 +74,49 @@ pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
 | 
			
		||||
    };
 | 
			
		||||
    for row in query_helper {
 | 
			
		||||
        let name: &str = row.get(0);
 | 
			
		||||
        let query_result: i32 = db
 | 
			
		||||
            .query_one(
 | 
			
		||||
                format!("select count from user{} where name='{}'", id, name).as_str(),
 | 
			
		||||
                &[],
 | 
			
		||||
        let count_query = db
 | 
			
		||||
            .query(
 | 
			
		||||
                format!("SELECT count FROM user{} WHERE name=$1", id).as_str(),
 | 
			
		||||
                &[&name],
 | 
			
		||||
            )
 | 
			
		||||
            .await?
 | 
			
		||||
            .get(0);
 | 
			
		||||
        reply = reply + &format!("\n{} count for you: {}", name, query_result);
 | 
			
		||||
            .await?;
 | 
			
		||||
        let query_result: i32 = if count_query.is_empty() {
 | 
			
		||||
            0
 | 
			
		||||
        } else {
 | 
			
		||||
            count_query[0].get(0)
 | 
			
		||||
        };
 | 
			
		||||
        reply += &format!("\n{} count for {}: {}", name, user.name, query_result);
 | 
			
		||||
    }
 | 
			
		||||
    msg.reply(ctx, reply).await?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[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 queries = query.splitn(2, "&").collect::<Vec<&str>>();
 | 
			
		||||
    let queries = query.splitn(2, " ").collect::<Vec<&str>>();
 | 
			
		||||
    if queries.len() != 2 {
 | 
			
		||||
        msg.reply(ctx, "Please use the proper syntax: `,count add <name>&<regex>`\nIf you don't know what regex is, just do: `,count add <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?;
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
    if queries[1].contains(" ") {
 | 
			
		||||
        msg.reply(ctx, "Not a valid regex").await?;
 | 
			
		||||
    let r = Regex::new(&format!("(?i){}", queries[1]));
 | 
			
		||||
 | 
			
		||||
    if r.is_err() {
 | 
			
		||||
        msg.reply(ctx, "Please enter a valid regex").await?;
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let reg = r.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(
 | 
			
		||||
            format!("select name, reg from words where name='{}'", queries[0]).as_str(),
 | 
			
		||||
            &[],
 | 
			
		||||
        )
 | 
			
		||||
        .query("SELECT name, reg FROM words WHERE name=$1", &[&queries[0]])
 | 
			
		||||
        .await?;
 | 
			
		||||
    if check_existense.len() != 0 {
 | 
			
		||||
        let reg: String = check_existense[0].get(1);
 | 
			
		||||
@@ -106,14 +128,8 @@ pub async fn add(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
    db.execute(
 | 
			
		||||
        format!(
 | 
			
		||||
            "insert into words(name, reg, owner) values('{}','(?i){}', '{}')",
 | 
			
		||||
            queries[0],
 | 
			
		||||
            queries[1],
 | 
			
		||||
            msg.author.id.to_string()
 | 
			
		||||
        )
 | 
			
		||||
        .as_str(),
 | 
			
		||||
        &[],
 | 
			
		||||
        "INSERT INTO words(name, reg, owner) VALUES($1, $2, $3)",
 | 
			
		||||
        &[&queries[0], ®.to_string(), &msg.author.id.to_string()],
 | 
			
		||||
    )
 | 
			
		||||
    .await?;
 | 
			
		||||
    msg.reply(ctx, "Added").await?;
 | 
			
		||||
@@ -121,7 +137,8 @@ pub async fn add(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[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(" ");
 | 
			
		||||
    if query == "" {
 | 
			
		||||
        msg.reply(ctx, "remove what?").await?;
 | 
			
		||||
@@ -133,10 +150,7 @@ pub async fn rm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
 | 
			
		||||
        .expect("Expected Database in TypeMap.")
 | 
			
		||||
        .clone();
 | 
			
		||||
    let owner = db
 | 
			
		||||
        .query(
 | 
			
		||||
            format!("select owner from words where name = '{}'", query).as_str(),
 | 
			
		||||
            &[],
 | 
			
		||||
        )
 | 
			
		||||
        .query("SELECT owner FROM words WHERE name=$1", &[&query])
 | 
			
		||||
        .await?;
 | 
			
		||||
    if owner.len() == 1 {
 | 
			
		||||
        let owner_id: String = owner[0].get(0);
 | 
			
		||||
@@ -145,24 +159,18 @@ pub async fn rm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    db.execute(
 | 
			
		||||
        format!("delete from words where name='{}'", query,).as_str(),
 | 
			
		||||
        &[],
 | 
			
		||||
    )
 | 
			
		||||
    db.execute("DELETE FROM words WHERE name=$1", &[&query])
 | 
			
		||||
        .await?;
 | 
			
		||||
    msg.reply(ctx, "Deleted if it existed").await?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[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 queries = query.splitn(2, "&").collect::<Vec<&str>>();
 | 
			
		||||
    if queries.len() != 2 {
 | 
			
		||||
        msg.reply(
 | 
			
		||||
            ctx,
 | 
			
		||||
            "Please use the proper syntax\n,count change <name>&<regex>",
 | 
			
		||||
        )
 | 
			
		||||
        msg.reply(ctx, "Please use the proper syntax\n,cedit <name>&<regex>")
 | 
			
		||||
            .await?;
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
@@ -176,10 +184,7 @@ pub async fn change(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
 | 
			
		||||
        .expect("Expected Database in TypeMap.")
 | 
			
		||||
        .clone();
 | 
			
		||||
    let owner = db
 | 
			
		||||
        .query(
 | 
			
		||||
            format!("select owner from words where name = '{}'", queries[0]).as_str(),
 | 
			
		||||
            &[],
 | 
			
		||||
        )
 | 
			
		||||
        .query("SELECT owner FROM words WHERE name=$1", &[&queries[0]])
 | 
			
		||||
        .await?;
 | 
			
		||||
    if owner.len() == 1 {
 | 
			
		||||
        let owner_id: String = owner[0].get(0);
 | 
			
		||||
@@ -189,106 +194,93 @@ pub async fn change(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    db.execute(
 | 
			
		||||
        format!(
 | 
			
		||||
            "update words set reg='(?i){}' where name='{}'",
 | 
			
		||||
            queries[1], queries[0]
 | 
			
		||||
        )
 | 
			
		||||
        .as_str(),
 | 
			
		||||
        &[],
 | 
			
		||||
        "UPDATE words SET reg=$1 WHERE name=$2",
 | 
			
		||||
        &[&("(?i)".to_string() + queries[1]), &queries[0]],
 | 
			
		||||
    )
 | 
			
		||||
    .await?;
 | 
			
		||||
    msg.reply(ctx, "Changed the value if it existed").await?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
macro_rules! make_embed {
 | 
			
		||||
    ($e: expr, $cur: expr, $group: expr) => {{
 | 
			
		||||
        $e = $e
 | 
			
		||||
            .title(format!("List of words: Page {}", $cur))
 | 
			
		||||
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: i32 = row.get(0);
 | 
			
		||||
    for row in group {
 | 
			
		||||
        let idx: i64 = row.get(0);
 | 
			
		||||
        let name: String = row.get(1);
 | 
			
		||||
            let owner_id: String = row.get(3);
 | 
			
		||||
            $e = $e.field(
 | 
			
		||||
        let owner_id: String = row.get(2);
 | 
			
		||||
        e.field(
 | 
			
		||||
            format!("{}. {}", idx, name),
 | 
			
		||||
            format!(" by <@{}>", owner_id),
 | 
			
		||||
                true,
 | 
			
		||||
            false,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
        $e
 | 
			
		||||
    }};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
macro_rules! make_terminal_components {
 | 
			
		||||
    ($c: expr, $terminal: expr ) => {{
 | 
			
		||||
        $c.create_action_row(|ar| {
 | 
			
		||||
            ar.create_button(|b| {
 | 
			
		||||
                b.style(ButtonStyle::Primary)
 | 
			
		||||
                    .label("Prev")
 | 
			
		||||
                    .emoji(ReactionType::Unicode("\u{2B05}".to_string()))
 | 
			
		||||
                    .custom_id("prev")
 | 
			
		||||
                    .disabled($terminal == "first")
 | 
			
		||||
            })
 | 
			
		||||
            .create_button(|b| {
 | 
			
		||||
                b.style(ButtonStyle::Primary)
 | 
			
		||||
                    .label("Next")
 | 
			
		||||
                    .emoji(ReactionType::Unicode("\u{27A1}".to_string()))
 | 
			
		||||
                    .custom_id("next")
 | 
			
		||||
                    .disabled($terminal == "last")
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
    }};
 | 
			
		||||
    e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[command]
 | 
			
		||||
pub async fn ls(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
 | 
			
		||||
#[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 * from words", &[]).await?;
 | 
			
		||||
 | 
			
		||||
    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(5).collect();
 | 
			
		||||
    let mut cur = 1;
 | 
			
		||||
 | 
			
		||||
    let groups: Vec<&[Row]> = rows.chunks(size).collect();
 | 
			
		||||
    let mut cur = 1;
 | 
			
		||||
    let message = msg
 | 
			
		||||
        .channel_id
 | 
			
		||||
        .send_message(ctx, |m| {
 | 
			
		||||
            m.embed(|mut e| make_embed!(e, cur, groups[cur - 1]))
 | 
			
		||||
                .components(|c| make_terminal_components!(c, "first"))
 | 
			
		||||
            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 {
 | 
			
		||||
        if let InteractionData::MessageComponent(component) = interaction.data.as_ref().unwrap() {
 | 
			
		||||
            match component.custom_id.as_ref() {
 | 
			
		||||
        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| {
 | 
			
		||||
                                        cur += 1;
 | 
			
		||||
                                        m.create_embed(|mut e| make_embed!(e, cur, groups[cur - 1]))
 | 
			
		||||
                                            .components(|c| {
 | 
			
		||||
                                                make_terminal_components!(
 | 
			
		||||
                                                    c,
 | 
			
		||||
                                                    if cur == groups.len() {
 | 
			
		||||
                                                        "last"
 | 
			
		||||
                                                    } else {
 | 
			
		||||
                                                        "mid"
 | 
			
		||||
                                                    }
 | 
			
		||||
                                                )
 | 
			
		||||
                                            })
 | 
			
		||||
                                    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;
 | 
			
		||||
@@ -296,25 +288,71 @@ pub async fn ls(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
 | 
			
		||||
            }
 | 
			
		||||
            "prev" => {
 | 
			
		||||
                if cur != 1 {
 | 
			
		||||
                    cur -= 1;
 | 
			
		||||
                    let _ = interaction
 | 
			
		||||
                        .create_interaction_response(&ctx, |r| {
 | 
			
		||||
                            r.kind(InteractionResponseType::UpdateMessage)
 | 
			
		||||
                                .interaction_response_data(|m| {
 | 
			
		||||
                                        cur -= 1;
 | 
			
		||||
                                        m.create_embed(|mut e| make_embed!(e, cur, groups[cur - 1]))
 | 
			
		||||
                                            .components(|c| {
 | 
			
		||||
                                                make_terminal_components!(
 | 
			
		||||
                                                    c,
 | 
			
		||||
                                                    if cur == 1 { "first" } else { "mid" }
 | 
			
		||||
                                                )
 | 
			
		||||
                                            })
 | 
			
		||||
                                    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::framework::standard::{
 | 
			
		||||
    CommandResult,
 | 
			
		||||
    macros::command
 | 
			
		||||
};
 | 
			
		||||
use serenity::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[command]
 | 
			
		||||
pub async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
pub mod general;
 | 
			
		||||
pub mod count;
 | 
			
		||||
pub mod general;
 | 
			
		||||
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(())
 | 
			
		||||
}
 | 
			
		||||
@@ -18,46 +18,38 @@ pub async fn count(msg: Message, db: std::sync::Arc<Client>) {
 | 
			
		||||
        &[],
 | 
			
		||||
    )
 | 
			
		||||
    .await
 | 
			
		||||
    .expect("cant create a user table");
 | 
			
		||||
    .expect("Can't create a user table");
 | 
			
		||||
 | 
			
		||||
    for row in db
 | 
			
		||||
        .query("SELECT name, reg FROM words", &[])
 | 
			
		||||
        .await
 | 
			
		||||
        .expect("can't get the words to count")
 | 
			
		||||
        .expect("Can't get the words to count")
 | 
			
		||||
    {
 | 
			
		||||
        let name: &str = row.get(0);
 | 
			
		||||
        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 {
 | 
			
		||||
            let query_result = db
 | 
			
		||||
                .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
 | 
			
		||||
                .expect("cant select the count");
 | 
			
		||||
                .expect("Can't select count");
 | 
			
		||||
            if query_result.is_empty() {
 | 
			
		||||
                db.execute(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "insert into user{} (name, count) values ('{}', 0)",
 | 
			
		||||
                        id, name
 | 
			
		||||
                    )
 | 
			
		||||
                    .as_str(),
 | 
			
		||||
                    &[],
 | 
			
		||||
                    format!("INSERT INTO user{} (name, count) values ($1, 0)", id).as_str(),
 | 
			
		||||
                    &[&name],
 | 
			
		||||
                )
 | 
			
		||||
                .await
 | 
			
		||||
                .expect("cant insert shit");
 | 
			
		||||
                .expect("Can't insert count");
 | 
			
		||||
            }
 | 
			
		||||
            db.execute(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "UPDATE user{} SET count = count + {} where name='{}'",
 | 
			
		||||
                    id, count, name
 | 
			
		||||
                )
 | 
			
		||||
                .as_str(),
 | 
			
		||||
                &[],
 | 
			
		||||
                format!("UPDATE user{} SET count = count + $1 WHERE name=$2", id).as_str(),
 | 
			
		||||
                &[&count, &name],
 | 
			
		||||
            )
 | 
			
		||||
            .await
 | 
			
		||||
            .expect("cant update");
 | 
			
		||||
            .expect("Can't update count");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,7 @@ mod count;
 | 
			
		||||
mod interactions;
 | 
			
		||||
use serenity::{
 | 
			
		||||
    async_trait,
 | 
			
		||||
    model::{
 | 
			
		||||
        channel::Message,
 | 
			
		||||
        event::ResumedEvent,
 | 
			
		||||
        gateway::Ready,
 | 
			
		||||
        interactions::{
 | 
			
		||||
            ApplicationCommand, Interaction, InteractionData, InteractionResponseType,
 | 
			
		||||
            InteractionType,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    model::{channel::Message, event::ResumedEvent, gateway::Ready},
 | 
			
		||||
    prelude::*,
 | 
			
		||||
};
 | 
			
		||||
use tracing::info;
 | 
			
		||||
@@ -19,12 +11,8 @@ pub struct Handler;
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl EventHandler for Handler {
 | 
			
		||||
    async fn ready(&self, ctx: Context, ready: Ready) {
 | 
			
		||||
        info!("{} connected bhay", ready.user.name);
 | 
			
		||||
        let _ = ApplicationCommand::create_global_application_commands(&ctx.http, |commands| {
 | 
			
		||||
            commands.set_application_commands(interactions::general())
 | 
			
		||||
        })
 | 
			
		||||
        .await;
 | 
			
		||||
    async fn ready(&self, _: Context, ready: Ready) {
 | 
			
		||||
        println!("{} connected bhay", ready.user.name);
 | 
			
		||||
    }
 | 
			
		||||
    async fn resume(&self, _: Context, _: ResumedEvent) {
 | 
			
		||||
        info!("how th when the");
 | 
			
		||||
@@ -37,23 +25,4 @@ impl EventHandler for Handler {
 | 
			
		||||
            .clone();
 | 
			
		||||
        count::count(msg, db_client).await;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
 | 
			
		||||
        if interaction.kind == InteractionType::ApplicationCommand {
 | 
			
		||||
            if let Some(InteractionData::ApplicationCommand(data)) = interaction.data.as_ref() {
 | 
			
		||||
                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;
 | 
			
		||||
							
								
								
									
										10
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,8 +1,10 @@
 | 
			
		||||
mod commands;
 | 
			
		||||
mod handler;
 | 
			
		||||
mod lib;
 | 
			
		||||
use commands::count::*;
 | 
			
		||||
use commands::general::*;
 | 
			
		||||
use commands::minigames::*;
 | 
			
		||||
use commands::tags::*;
 | 
			
		||||
use handler::Handler;
 | 
			
		||||
use serenity::{
 | 
			
		||||
    client::bridge::gateway::ShardManager,
 | 
			
		||||
@@ -36,10 +38,13 @@ impl TypeMapKey for Database {
 | 
			
		||||
struct General;
 | 
			
		||||
 | 
			
		||||
#[group]
 | 
			
		||||
#[prefix = "count"]
 | 
			
		||||
#[commands(kitna, add, rm, change, ls)]
 | 
			
		||||
#[commands(count, cadd, cremove, cedit, clist)]
 | 
			
		||||
struct Count;
 | 
			
		||||
 | 
			
		||||
#[group]
 | 
			
		||||
#[commands(tag, tadd, tcopy, tremove, tedit, tlist, trandom)]
 | 
			
		||||
pub struct Tags;
 | 
			
		||||
 | 
			
		||||
#[group]
 | 
			
		||||
#[commands(challenge)]
 | 
			
		||||
struct Minigames;
 | 
			
		||||
@@ -82,6 +87,7 @@ async fn main() {
 | 
			
		||||
        .help(&MY_HELP)
 | 
			
		||||
        .group(&GENERAL_GROUP)
 | 
			
		||||
        .group(&COUNT_GROUP)
 | 
			
		||||
        .group(&TAGS_GROUP)
 | 
			
		||||
        .group(&MINIGAMES_GROUP);
 | 
			
		||||
 | 
			
		||||
    let mut client = Client::builder(&token)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user