Compare commits

...

10 commits

28 changed files with 406 additions and 353 deletions

View file

@ -2,7 +2,7 @@ arch: null
artifacts: []
environment:
BUILD_SUBMITTER: git.sr.ht
image: alpine/3.16
image: alpine/3.18
packages:
- rust
- cargo

View file

@ -1,3 +1,4 @@
.idea/
.github/
**/.env
**/.env
target

58
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,58 @@
name: Docker Build and Push with Version
on:
push:
branches:
- master
env:
DOCKER_REGISTRY: r.regnault.dev
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
PORTAINER_API_WEBHOOK: ${{ secrets.PORTAINER_API_WEBHOOK }}
jobs:
build_and_push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ env.DOCKER_USERNAME }}
password: ${{ env.DOCKER_PASSWORD }}
- name: Install cargo-semver
uses: actions-rs/install@v0.1.2
with:
crate: cargo-get
version: latest
- name: Semver
run:
echo "VERSION=$(cargo get package.version --pretty)" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: |
${{ env.DOCKER_REGISTRY }}/drunk-venti-rust:latest
${{ env.DOCKER_REGISTRY }}/drunk-venti-rust:${{ env.VERSION }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Deploy to production
uses: fjogeleit/http-request-action@v1.14.1
with:
url: ${{ format('{0}?BOT_TAG={1}',env.PORTAINER_API_WEBHOOK, env.VERSION) }}
method: 'POST'
preventFailureOnNoResponse: true

View file

@ -1,22 +0,0 @@
name: Rust
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose
- name: Run test
run: cargo test --verbose

8
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Drunk-Venti-Rust.iml" filepath="$PROJECT_DIR$/.idea/Drunk-Venti-Rust.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View file

@ -1,6 +1,6 @@
[package]
name = "drunk-venti-rust"
version = "1.0.3"
version = "1.2.2"
edition = "2021"
authors = ["Evann Regnault"]
license = "MIT"
@ -8,7 +8,7 @@ license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serenity = { version = "0.10.9", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "unstable_discord_api", "collector"] }
serenity = { version = "0.11.6", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "unstable_discord_api", "collector"] }
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
reqwest = "0.11.7"
serde_derive = "1.0.140"

View file

@ -1,15 +1,21 @@
FROM rust:1.65.0
FROM rust:slim-bookworm AS base
RUN apt-get update
RUN apt-get install libssl-dev pkg-config -y
RUN cargo install cargo-chef
WORKDIR app
WORKDIR /app
FROM base AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
COPY . /app
FROM base AS builder
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
COPY . .
RUN cargo build --release --bin drunk-venti-rust
RUN cargo install --path .
#ENV DISCORD_TOKEN=token
#ENV MONGO_HOST=host
#ENV MONGO_PORT=port
#ENV API_HOST=host
#ENV API_PORT=port
ENTRYPOINT ["drunk-venti-rust"]
FROM debian:bookworm-slim
RUN apt-get update && apt-get install ca-certificates libssl3 -y && apt-get clean autoclean && apt-get autoremove --yes && rm -rf /var/lib/{apt,dpkg,cache,log}/
WORKDIR /root/
COPY --from=builder /app/target/release/drunk-venti-rust .
CMD ["./drunk-venti-rust"]

View file

@ -1,9 +1,8 @@
![Build Status](https://github.com/Estyms/Drunk-Venti-Rust/actions/workflows/main.yml/badge.svg)
# Drunk-Venti-Rust
A discord bot that provides Genshin Impact data to users
[![builds.sr.ht status](https://builds.sr.ht/~estym/Drunk-Venti.svg)](https://sr.ht/~estym/Drunk-Venti?)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/Estyms/Drunk-Venti-Rust/Rust?label=github)](https://github.com/Estyms/Drunk-Venti-Rust)
## Features
@ -22,6 +21,6 @@ In that message you can see what events are currently going on as well as the ne
## APIs
- [Serenity](https://github.com/serenity-rs/serenity) ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/serenity-rs/serenity/CI?label=github)
- [Serenity](https://github.com/serenity-rs/serenity)
- [Paimon.moe](https://paimon.moe/) by [@MadeBaruna](https://github.com/MadeBaruna)
- Drunk-Venti-Api - [[SourceHut](https://git.sr.ht/~estym/Drunk-Venti-Api)] [[Github](https://github.com/Estyms/Drunk-Venti-Api)]
- Drunk-Venti-Api - [[SourceHut](https://git.sr.ht/~estym/Drunk-Venti-Api)] [[Github](https://github.com/Estyms/Drunk-Venti-Api)]

View file

@ -25,14 +25,29 @@ pub struct Artifact {
pub domain: Option<Box<str>>
}
pub fn get_real_artifact_name(artifact: &str) -> &str {
match artifact {
"+18%_atk_set" => "gladiators_finale",
"+20%_energy_recharge" => "emblem_of_severed_fate",
"+25%_physical_dmg" => "bloodstained_chivalry",
"+80_em" => "gilded_dreams",
"+15%_healing_bonus_set" => "ocean-hued_clam",
"+20%_hp_set" => "vourukashas_glow",
_ => artifact
}
}
impl Artifact{
#[allow(dead_code)]
pub async fn get(artifact: &str) -> Artifact {
let artifact = get_real_artifact_name(artifact);
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/artifacts/{}", host, port, artifact);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Artifact>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Artifact>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -40,24 +55,25 @@ impl Artifact{
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/artifacts", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
pub(crate) async fn search(artifact: &str) -> Vec<Artifact> {
let artifact = get_real_artifact_name(artifact);
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/artifacts/search/{}", host, port, artifact);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Artifact>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Artifact>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
pub async fn to_embed(&self) -> CreateEmbed {
let mut embed = CreateEmbed::default();
embed.title(format!("{} | {}", self.name, ":star:".repeat(self.rarity.get(0).expect("").to_owned() as usize)));
embed.title(format!("{} | {}", self.name, ":star:".repeat(self.rarity.first().expect("").to_owned() as usize)));
embed.thumbnail(format!("https://raw.githubusercontent.com/MadeBaruna/paimon-moe/main/static/images/artifacts/{}_circlet.png", self.id));
@ -68,15 +84,12 @@ impl Artifact{
);
}
match &self.domain {
Some(d) => {
let domain = Domain::get(d).await;
embed.field("Domain", domain.name(), true);
}
_ => {}
if let Some(d) = &self.domain {
let domain = Domain::get(d).await;
embed.field("Domain", domain.name(), true);
}
return embed;
embed
}
#[allow(dead_code)]
@ -94,4 +107,18 @@ impl Artifact{
fn test_artifact() {
let data = std::fs::read_to_string("test/artifact.json").expect("No Artifact test file");
serde_json::from_str::<Artifact>(&data).expect("Didn't work");
}
#[test]
fn test_real_artfifact_name() {
match get_real_artifact_name("+18%_atk_set") {
"gladiators_finale" => {}
_ => panic!()
};
match get_real_artifact_name("lasfhkalkfhafsk") {
"lasfhkalkfhafsk" => {}
_ => panic!()
};
}

View file

@ -26,7 +26,7 @@ pub struct Role{
pub main_stats: RoleStat,
pub sub_stats: Vec<Box<str>>,
pub talent: Vec<Box<str>>,
pub tip: Box<str>,
pub tip: Option<String>,
pub note: Box<str>,
pub name: Box<str>,
}
@ -43,8 +43,8 @@ impl Builds {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/builds/{}", host, port, build);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Builds>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Builds>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -52,8 +52,8 @@ impl Builds {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/builds", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format")
}
}

View file

@ -50,9 +50,8 @@ impl Character {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/characters/{}", host, port, character);
let url = Url::parse(&*url).expect("Can't convert url");
let a = reqwest::get(url.clone()).await.expect("Can't access Url");
return reqwest::get(url).await.expect("Can't access Url").json::<Character>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Character>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -60,8 +59,8 @@ impl Character {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/characters", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -69,8 +68,8 @@ impl Character {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/characters/search/{}", host, port, character);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Character>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Character>>().await.expect("Wrong json format")
}
}

View file

@ -45,8 +45,8 @@ impl Domain {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/domains/{}", host, port, domain);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Domain>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Domain>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -54,13 +54,13 @@ impl Domain {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/domains", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
pub fn name(&self) -> String {
return self.name.to_string();
self.name.to_string()
}
}

View file

@ -17,8 +17,8 @@ impl Element {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/elements/{}", host, port, element);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Element>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Element>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -26,8 +26,8 @@ impl Element {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/elements", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format")
}
}

View file

@ -30,8 +30,8 @@ impl Event {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/events/current", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -39,8 +39,8 @@ impl Event {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/events/upcoming", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -48,8 +48,8 @@ impl Event {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/events", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format")
}
}

View file

@ -18,16 +18,16 @@ impl Item{
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/items/{}", host, port, item);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Item>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Item>().await.expect("Wrong json format")
}
#[allow(dead_code)]
async fn get_all() -> Vec<Box<str>> {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/items", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -35,8 +35,8 @@ impl Item{
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/items/search/{}", host, port, item);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Item>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Item>>().await.expect("Wrong json format")
}
}

View file

@ -56,8 +56,8 @@ impl Weapon {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/weapons/{}", host, port, weapon);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Weapon>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Weapon>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -65,8 +65,8 @@ impl Weapon {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/weapons", host, port);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
@ -74,18 +74,18 @@ impl Weapon {
let host = env::var("API_HOST").unwrap();
let port = env::var("API_PORT").unwrap();
let url = format!("http://{}:{}/api/weapons/search/{}", host, port, weapon);
let url = Url::parse(&*url).expect("Can't convert url");
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Weapon>>().await.expect("Wrong json format");
let url = Url::parse(&url).expect("Can't convert url");
reqwest::get(url).await.expect("Can't access Url").json::<Vec<Weapon>>().await.expect("Wrong json format")
}
#[allow(dead_code)]
pub fn name(&self) -> &str {
return &self.name;
&self.name
}
#[allow(dead_code)]
pub fn id(&self) -> &str {
return &self.id;
&self.id
}
#[allow(dead_code)]
@ -98,17 +98,14 @@ impl Weapon {
embed.thumbnail(format!("https://raw.githubusercontent.com/MadeBaruna/paimon-moe/main/static/images/weapons/{}.png", self.id));
// Fields
match self.extras.skill.name.as_ref() {
Some(t) => {
let re = Regex::new("(<|</)span(?: [^>]*)?>").expect("Unknown regex");
embed.field(format!("Passive : {}", t),
format!("{}",
re.replace_all(self.extras.skill.description.as_ref()
.unwrap_or(&Box::from(""))
.to_string().as_str(), "**")).replace("\\n","\n"),
false);
}
_ => {}
if let Some(t) = self.extras.skill.name.as_ref() {
let re = Regex::new("(<|</)span(?: [^>]*)?>").expect("Unknown regex");
embed.field(format!("Passive : {}", t),
format!("{}",
re.replace_all(self.extras.skill.description.as_ref()
.unwrap_or(&Box::from(""))
.to_string().as_str(), "**")).replace("\\n","\n"),
false);
}
embed.field("Main Stat", format!("{}", self.secondary), true);
embed.field("Source", format!("{}", self.source), true);
@ -116,7 +113,7 @@ impl Weapon {
embed.field("Type", format!("{}", self.weapon_type.name), true);
embed.field("Ascension Item", format!("{}", self.ascension.get(0).expect("").items.get(0).expect("").item.name), true);
embed.field("\u{200b}", "\u{200b}", true);
return embed;
embed
}
}

View file

@ -1,12 +1,13 @@
use linked_hash_map::LinkedHashMap;
use serenity::client::Context;
use serenity::model::interactions::{InteractionApplicationCommandCallbackDataFlags, InteractionResponseType};
use serenity::model::interactions::application_command::{ApplicationCommandInteraction, ApplicationCommandInteractionDataOption};
use serenity::model::interactions::message_component::{MessageComponentInteraction};
use serenity::model::application::interaction::application_command::{ApplicationCommandInteraction, CommandDataOption};
use serenity::model::application::interaction::InteractionResponseType;
use serenity::model::application::interaction::MessageFlags;
use serenity::model::application::interaction::message_component::MessageComponentInteraction;
use crate::data::artifacts::Artifact;
use crate::interactions::utils::create_action_row_basic;
pub async fn genshin_artifact_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &ApplicationCommandInteractionDataOption) {
pub async fn genshin_artifact_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &CommandDataOption) {
let weapon = opt.options.get(0).expect("No argument for command Genshin artifact")
.value.as_ref().expect("").as_str().expect("Not a string");
@ -25,7 +26,7 @@ pub async fn genshin_artifact_interaction(ctx: &Context, command: &ApplicationCo
.interaction_response_data(|d| {
d.content("Select an Artifact")
.components(|c| c.add_action_row(ar))
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
.flags(MessageFlags::EPHEMERAL)
})
}).await.expect("Message didn't got sent");
}
@ -37,8 +38,8 @@ pub async fn show_artifact_embed(ctx: &Context, command: &MessageComponentIntera
command.create_interaction_response(&ctx.http, |res| {
res.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.embeds(vec!(embed).into_iter())
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
d.set_embeds(vec!(embed).into_iter())
.flags(MessageFlags::EPHEMERAL)
})
}).await.expect("Interaction failed");
}

View file

@ -1,17 +1,24 @@
use std::borrow::{Borrow};
use linked_hash_map::LinkedHashMap;
use serenity::builder::{CreateActionRow, CreateButton, CreateEmbed};
use serenity::builder::{CreateActionRow, CreateButton, CreateComponents, CreateEmbed};
use serenity::client::Context;
use serenity::model::interactions::{InteractionApplicationCommandCallbackDataFlags, InteractionResponseType};
use serenity::model::interactions::application_command::{ApplicationCommandInteraction, ApplicationCommandInteractionDataOption};
use serenity::model::interactions::message_component::{ButtonStyle, MessageComponentInteraction};
use serenity::model::application::component::ButtonStyle;
use serenity::model::application::interaction::{
MessageFlags,
InteractionResponseType,
application_command::{
ApplicationCommandInteraction,
CommandDataOption
},
message_component::MessageComponentInteraction
};
use crate::data::artifacts::Artifact;
use crate::data::builds::{Builds, Role};
use crate::data::characters::Character;
use crate::data::weapons::Weapon;
use crate::interactions::utils::create_action_row_basic;
pub async fn genshin_build_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &ApplicationCommandInteractionDataOption) {
pub async fn genshin_build_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &CommandDataOption) {
let char = opt.options.get(0).expect("No argument for command Genshin builds")
.value.as_ref().expect("").as_str().expect("Not a string");
@ -29,20 +36,17 @@ pub async fn genshin_build_interaction(ctx: &Context, command: &ApplicationComma
.interaction_response_data(|d| {
d.content("Select a Character")
.components(|c| c.add_action_row(ar))
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
.flags(MessageFlags::EPHEMERAL)
})
}).await.expect("Message didn't got sent");
}
fn is_menu(arg: &str) -> bool {
match arg {
"home" | "artifacts" | "weapons" | "notes" => true,
_ => false
}
matches!(arg, "home" | "artifacts" | "weapons" | "notes")
}
pub async fn build_interact(ctx: &Context, interaction: &MessageComponentInteraction, arguments: String) {
let mut args = arguments.split("_");
let mut args = arguments.split('_');
let command = args.next();
@ -74,8 +78,8 @@ pub async fn build_interact(ctx: &Context, interaction: &MessageComponentInterac
_ => {
let mut character = args.collect::<Vec<_>>().join("_");
character = [command.expect(""), character.as_str()].join("_");
character = character.strip_suffix("_").unwrap_or(character.as_str()).parse().unwrap();
build_select(&ctx, &interaction, character).await;
character = character.strip_suffix('_').unwrap_or(character.as_str()).parse().unwrap();
build_select(ctx, interaction, character).await;
}
}
}
@ -127,32 +131,41 @@ async fn build_select(ctx: &Context, command: &MessageComponentInteraction, char
let roles = &char.builds;
let roles = roles.into_iter().map(|c| c.name.to_string()).collect::<Vec<String>>();
let roles = roles.iter().map(|c| c.name.to_string()).collect::<Vec<String>>();
let mut rolemap = LinkedHashMap::<String, String>::new();
for i in 0..roles.len() {
rolemap.insert(format!("{}_{}", i, character), roles.get(i).expect("").to_string());
}
let ar = create_action_row_basic(rolemap, "build_home");
let ar = match roles.len() {
0 => CreateActionRow::default(),
_ =>create_action_row_basic(rolemap, "build_home")
};
command.create_interaction_response(&ctx.http, |res| {
res.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.components(|c| c.add_action_row(ar))
.create_embed(|e| {
e.title(format!("{}", char.name))
.thumbnail(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/characters/{}.png", char.id))
.color(char.element.color)
.description("Select a build !")
.footer(|f| {
f.text(format!("Data from : https://paimon.moe/characters/{}", char.id))
})
})
.interaction_response_data(|mut d| {
if !roles.is_empty() {
d = d.components(|c| c.add_action_row(ar))
} else {
d = d.set_components(CreateComponents::default())
}
d.embed(|mut e| {
e = e.title(format!("{}", char.name))
.thumbnail(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/characters/{}.png", char.id))
.color(char.element.color)
.description("Select a build !")
.footer(|f| {
f.text(format!("Data from : https://paimon.moe/characters/{}", char.id))
});
if roles.is_empty() {
e = e.description("No builds available yet !")
}
e
})
})
}).await.expect("Can't send response");
return;
}
@ -175,48 +188,15 @@ pub async fn home_embed(role: &Role, character: Character) -> CreateEmbed {
}
embed.field("Skill Order",
role.talent.to_owned().into_iter().map(|t| format!("- {}\n", t))
.collect::<Vec<String>>().join("").strip_suffix("\n").expect(""),
role.talent.iter().cloned().map(|t| format!("- {}\n", t))
.collect::<Vec<String>>().join("").strip_suffix('\n').expect(""),
true,
);
match role.artifacts.get(0) {
Some(a) => {
let mut artifact_string: Vec<String> = vec![];
let str;
match a.len() {
1 => {
let artifact_name = match a.get(0).expect("").to_string().as_str() {
"+18%_atk_set" => "+18% Atk Set".to_string(),
t => Artifact::get(t).await.name.to_string(),
};
str = format!("(4) {}", artifact_name);
}
2 => {
for art in a {
let artifact_name = match art.to_string().as_str() {
"+18%_atk_set" => "+18% Atk Set".to_string(),
t => Artifact::get(t).await.name.to_string(),
};
artifact_string.push(format!("(2) {}", artifact_name));
}
str = artifact_string.join(" & ");
}
_ => {
artifact_string.push("Choose 2 sets :".to_string());
for art in a {
let artifact_name = match art.to_string().as_str() {
"+18%_atk_set" => "+18% Atk Set".to_string(),
t => Artifact::get(t).await.name.to_string(),
};
artifact_string.push(format!("(2) {}", artifact_name));
}
str = artifact_string.join(", ")
}
}
embed.field("Best Artifacts", str, false);
embed.field("Best Artifacts", get_artifact_string(a).await, false);
}
_ => { embed.field("Best Artifacts", "TBD", false); }
}
@ -253,52 +233,19 @@ async fn artifact_embed(role: &Role, character: Character) -> CreateEmbed {
for i in 0..role.artifacts.len() {
match role.artifacts.get(i) {
Some(a) => {
let mut artifact_string: Vec<String> = vec![];
let str;
match a.len() {
1 => {
let artifact_name = match a.get(0).expect("").to_string().as_str() {
"+18%_atk_set" => "+18% Atk Set".to_string(),
t => Artifact::get(t).await.name.to_string(),
};
str = format!("(4) {}", artifact_name);
}
2 => {
for art in a {
let artifact_name = match art.to_string().as_str() {
"+18%_atk_set" => "+18% Atk Set".to_string(),
t => Artifact::get(t).await.name.to_string(),
};
artifact_string.push(format!("(2) {}", artifact_name));
}
str = artifact_string.join(" & ");
}
_ => {
artifact_string.push("Choose 2 sets :".to_string());
for art in a {
let artifact_name = match art.to_string().as_str() {
"+18%_atk_set" => "+18% Atk Set".to_string(),
t => Artifact::get(t).await.name.to_string(),
};
artifact_string.push(format!("(2) {}", artifact_name));
}
str = artifact_string.join(", ")
}
}
all_artefacts_string.push(format!("- {}", str));
all_artefacts_string.push(format!("- {}", get_artifact_string(a).await));
}
_ => { all_artefacts_string.push(format!("- TBD")); }
_ => { all_artefacts_string.push("- TBD".to_string()); }
}
}
if all_artefacts_string.len() > 0 {
if !all_artefacts_string.is_empty() {
embed.field("Best Artifacts", all_artefacts_string.join("\n"), false);
} else {
embed.field("Best Artifacts", "- TBD", false);
}
embed.field("Sub-stats", {
format!("- {}", role.sub_stats.join("\n-"))
format!("- {}", role.sub_stats.join("\n- "))
}, false);
embed.field("Circlet", &role.main_stats.circlet[0], true);
@ -312,6 +259,30 @@ async fn artifact_embed(role: &Role, character: Character) -> CreateEmbed {
embed
}
async fn get_artifact_string(artifacts: &Vec<Box<str>>) -> String {
let mut artifact_string: Vec<String> = vec![];
let x = artifacts.len();
for art in artifacts {
let artifact_name = match art.to_string().as_str() {
"+18%_atk_set" => "+18% Atk Set".to_string(),
"+20%_hp_set" => "+20% Hp Set".to_string(),
"+80_em" => "Elemental Mastery +80 Set".to_string(),
t => Artifact::get(t).await.name.to_string(),
};
artifact_string.push(format!("({}) {}", match x {
1 => 4,
_ => 2
}, artifact_name));
}
artifact_string.join(
match x {
1 | 2 => " & ",
_ => ", "
}
)
}
async fn weapons_embed(role: &Role, character: Character) -> CreateEmbed {
let mut embed = CreateEmbed::default();
embed.title(format!("{} | {}", character.name, role.name));
@ -335,10 +306,10 @@ async fn weapons_embed(role: &Role, character: Character) -> CreateEmbed {
let weapon = Weapon::get(a.id.borrow()).await;
all_weapons_string.push(format!("- {}", weapon.name));
}
_ => { all_weapons_string.push(format!("- TBD")); }
_ => { all_weapons_string.push("- TBD".to_string()); }
}
}
if all_weapons_string.len() > 0 {
if !all_weapons_string.is_empty() {
embed.field("Best Weapons", all_weapons_string.join("\n"), false);
} else {
embed.field("Best Weapons", "- TBD", false);
@ -358,51 +329,53 @@ async fn note_embed(role: &Role, character: Character) -> CreateEmbed {
embed.thumbnail(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/characters/{}.png", character.id));
embed.color(character.element.color);
match &role.note {
n=> {
let x = n.split("\n");
let mut first = true;
let mut add_before = "";
for note_paragraph in x.collect::<Vec<&str>>() {
if note_paragraph.len() == 0 {continue};
if note_paragraph.len() < 64 && add_before.len() == 0{
add_before = note_paragraph;
continue;
}
if add_before.len() > 0 {
let note_paragraph = format!("**{}**\n{}", add_before, note_paragraph);
embed.field(if first { "Notes" } else { "\u{200b}" }, note_paragraph, false);
add_before = "";
} else {
embed.field(if first { "Notes" } else { "\u{200b}" }, note_paragraph, false);
first = false;
}
let n = &role.note.replace("<b>", "").replace("</b>", "");
{
let x = n.split('\n');
let mut first = true;
let mut add_before = "";
for note_paragraph in x.collect::<Vec<&str>>() {
if note_paragraph.is_empty() {continue};
if note_paragraph.len() < 64 && add_before.is_empty(){
add_before = note_paragraph;
continue;
}
if !add_before.is_empty() {
let note_paragraph = format!("**{}**\n{}", add_before, note_paragraph);
embed.field(if first { "Notes" } else { "\u{200b}" }, note_paragraph, false);
add_before = "";
} else {
embed.field(if first { "Notes" } else { "\u{200b}" }, note_paragraph, false);
first = false;
}
}
};
match &role.tip {
n=> {
let x = n.split("\n");
let mut first = true;
let mut add_before = "";
for tip_paragraph in x.collect::<Vec<&str>>() {
if tip_paragraph.len() == 0 {continue};
if tip_paragraph.len() < 64 {
add_before = tip_paragraph;
continue;
}
if add_before.len() > 0 {
let tip_paragraph = format!("**{}**\n{}", add_before, tip_paragraph);
embed.field(if first { "Tips" } else { "\u{200b}" }, tip_paragraph, false);
add_before = "";
} else {
embed.field(if first { "Tips" } else { "\u{200b}" }, tip_paragraph, false);
first = false;
}
let a = role.tip.as_ref();
{
let y = match a {
None => { String::from("")}
Some(b) => { b.to_string().replace("<b>", "").replace("</b>", "") }
};
let x = y.split('\n');
let mut first = true;
let mut add_before = "";
for tip_paragraph in x.collect::<Vec<&str>>() {
if tip_paragraph.is_empty() {continue};
if tip_paragraph.len() < 64 {
add_before = tip_paragraph;
continue;
}
if !add_before.is_empty() {
let tip_paragraph = format!("**{}**\n{}", add_before, tip_paragraph);
embed.field(if first { "Tips" } else { "\u{200b}" }, tip_paragraph, false);
add_before = "";
} else {
embed.field(if first { "Tips" } else { "\u{200b}" }, tip_paragraph, false);
first = false;
}
}
};

View file

@ -1,5 +1,5 @@
use serenity::client::Context;
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
use serenity::model::application::interaction::application_command::ApplicationCommandInteraction;
use crate::interactions::genshin::artifacts::genshin_artifact_interaction;
use crate::interactions::genshin::build::genshin_build_interaction;
use crate::interactions::genshin::weapons::genshin_weapon_interaction;

View file

@ -1,14 +1,14 @@
use linked_hash_map::LinkedHashMap;
use serenity::client::Context;
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
use serenity::model::interactions::application_command::ApplicationCommandInteractionDataOption;
use serenity::model::interactions::InteractionResponseType;
use serenity::model::application::interaction::application_command::ApplicationCommandInteraction;
use serenity::model::application::interaction::InteractionResponseType;
use serenity::model::prelude::application_command::CommandDataOption;
use serenity::model::prelude::InteractionApplicationCommandCallbackDataFlags;
use serenity::model::prelude::message_component::MessageComponentInteraction;
use crate::data::weapons::Weapon;
use crate::interactions::utils::create_action_row_basic;
pub async fn genshin_weapon_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &ApplicationCommandInteractionDataOption) {
pub async fn genshin_weapon_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &CommandDataOption) {
let weapon = opt.options.get(0).expect("No argument for command Genshin build")
.value.as_ref().expect("").as_str().expect("Not a string");
@ -38,7 +38,7 @@ pub async fn show_weapon_embed(ctx: &Context, command: &MessageComponentInteract
command.create_interaction_response(&ctx.http, |res| {
res.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.embeds(vec!(weapon.to_embed()).into_iter())
d.set_embeds(vec!(weapon.to_embed()).into_iter())
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
})
}).await.expect("The message didn't got sent");

View file

@ -1,22 +1,19 @@
pub mod status_message;
pub mod genshin;
#[path = "../data/mod.rs"]
mod data;
#[path = "../utils/mod.rs"]
pub mod utils;
use crate::data;
use crate::utils;
use serenity::client::Context;
use serenity::model::interactions::{InteractionApplicationCommandCallbackDataFlags, InteractionResponseType};
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
use serenity::model::application::interaction::{MessageFlags, InteractionResponseType, application_command::ApplicationCommandInteraction};
pub async fn pong(ctx : Context, command : ApplicationCommandInteraction) {
let res = command.create_interaction_response(ctx.http, |res| {
res.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|response| {
response.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
response.flags(MessageFlags::EPHEMERAL)
.content("An error has occurred")
})
}).await;

View file

@ -1,4 +1,3 @@
use std::borrow::Borrow;
use std::time::Duration;
use rand::Rng;
use serenity::{
@ -7,10 +6,10 @@ use serenity::{
}
};
use serenity::builder::CreateEmbed;
use serenity::model::application::interaction::MessageFlags;
use serenity::model::id::{ChannelId, MessageId};
use serenity::model::application::interaction::application_command::ApplicationCommandInteraction;
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
use serenity::model::interactions::InteractionApplicationCommandCallbackDataFlags;
use serenity::model::prelude::{InteractionResponseType};
use serenity::utils::Colour;
use crate::interactions::data::events::Event;
@ -18,18 +17,18 @@ use crate::utils::mongo::{add_discord_status_message, get_all_status_messages, g
pub async fn update_status_message(ctx: Context) {
let forever = tokio::task::spawn(async move {
tokio::task::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(60*60));
loop {
let mut x = get_all_status_messages().await;
x.reverse();
let embeds = create_status_embed().await;
for sm in x {
let embeds : Vec<CreateEmbed> = (&embeds).clone();
let ctx = ctx.borrow().clone();
let embeds : Vec<CreateEmbed> = embeds.clone();
let ctx = ctx.clone();
tokio::spawn( async move {
if sm.channel_id == 0 { return }
let msg = ChannelId::from(sm.channel_id as u64).message(ctx.borrow().clone().http, sm.message_id as u64).await;
let msg = ChannelId::from(sm.channel_id as u64).message(ctx.clone().http, sm.message_id as u64).await;
match msg {
Ok(mut m) => {
match m.edit(&ctx.http, |f| {
@ -49,7 +48,6 @@ pub async fn update_status_message(ctx: Context) {
interval.tick().await;
}
});
forever.await.expect("Stopped for some reasons");
}
#[allow(dead_code)]
@ -58,10 +56,10 @@ pub async fn create_status_interaction(ctx: Context, command: ApplicationCommand
if !altcommand.member.unwrap().permissions.expect("No permissions").manage_messages() {
command.create_interaction_response(&ctx.http, |f| {
f.kind(InteractionResponseType::ChannelMessageWithSource).interaction_response_data(|r| {
r.create_embed(|e| {
r.embed(|e| {
e.title("Command Unsuccessful").description("You do not have the right to manage messages.")
.color(Colour::from(0xff0000))
}).flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
}).flags(MessageFlags::EPHEMERAL)
})
}).await.expect("Interaction didn't work");
return;
@ -73,19 +71,16 @@ pub async fn create_status_interaction(ctx: Context, command: ApplicationCommand
let channel_id = channel_option.keys().next().expect("No options passed");
let message = get_discord_status_message(&command.guild_id.expect("Not in guild").as_u64().to_owned()).await;
match message {
Some(e) => {
let rm = ChannelId::from(e.channel_id as u64)
.message(&ctx.http, MessageId::from(e.message_id as u64))
.await;
match rm {
msg if rm.is_ok() => {
msg.unwrap().delete(&ctx.http).await.unwrap();
}
_ => {}
if let Some(e) = message {
let rm = ChannelId::from(e.channel_id as u64)
.message(&ctx.http, MessageId::from(e.message_id as u64))
.await;
match rm {
msg if rm.is_ok() => {
msg.unwrap().delete(&ctx.http).await.unwrap();
}
_ => {}
}
_ => {}
};
let msg = channel_id.send_message(&ctx.http, |f| {
@ -104,12 +99,12 @@ pub async fn create_status_interaction(ctx: Context, command: ApplicationCommand
command.create_interaction_response(&ctx.http, |r| {
r.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|d| {
d.create_embed(|e| {
d.embed(|e| {
e.title("Command Successful !");
e.color(Colour::new(0x00ff00));
e.description(format!("Status message created !"))
e.description("Status message created !".to_string())
})
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
.flags(MessageFlags::EPHEMERAL)
})
}).await.unwrap();
}
@ -120,7 +115,7 @@ async fn create_status_embed() -> Vec<CreateEmbed> {
let mut current = Event::get_current().await;
let mut others = current.clone();
let mut question_marks = format!("");
let mut question_marks = String::new();
let mut upcoming = Event::get_upcoming().await;
@ -137,17 +132,11 @@ async fn create_status_embed() -> Vec<CreateEmbed> {
embed.title(e.name);
embed.color(Colour::new(rand::thread_rng().gen_range(0x000000..0xffffff)));
match &e.image {
Some(url) => {
embed.image(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/events/{}", url));
}
_ => {}
if let Some(url) = &e.image {
embed.image(format!("https://raw.githubusercontent.com/MadeBaruna/paimon-moe/main/static/images/events/{}", url.replace(' ', "%20")));
};
match e.url {
Some(t) => { embed.url(format!("{}{}", t, question_marks)); }
_ => {}
};
if let Some(t) = e.url { embed.url(format!("{}{}", t, question_marks)); };
embed.description(format!("Ends : <t:{}:R>", e.end_timestamp.expect("No End Timestamp")));
embeds.push(embed);
@ -164,28 +153,19 @@ async fn create_status_embed() -> Vec<CreateEmbed> {
}
embeds.push(other_embed);
match upcoming_event {
Some(e) => {
let mut upcoming_embed = CreateEmbed::default();
question_marks = format!("{}?", question_marks);
upcoming_embed.title(&e.name);
upcoming_embed.description(format!("Starts : <t:{}:R>", e.start_timestamp.expect("No Start Timestamp")));
upcoming_embed.color(Colour::new(rand::thread_rng().gen_range(0x000000..0xffffff)));
if let Some(e) = upcoming_event {
let mut upcoming_embed = CreateEmbed::default();
question_marks = format!("{}?", question_marks);
upcoming_embed.title(&e.name);
upcoming_embed.description(format!("Starts : <t:{}:R>", e.start_timestamp.expect("No Start Timestamp")));
upcoming_embed.color(Colour::new(rand::thread_rng().gen_range(0x000000..0xffffff)));
match &e.image {
Some(url) => {
upcoming_embed.image(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/events/{}", url));
}
_ => {}
};
if let Some(url) = &e.image {
upcoming_embed.image(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/events/{}", url.replace(' ', "%20")));
};
match &e.url {
Some(url) => { upcoming_embed.url(format!("{}{}", url, question_marks)); }
_ => {}
};
embeds.push(upcoming_embed);
}
_ => {}
if let Some(url) = &e.url { upcoming_embed.url(format!("{}{}", url, question_marks)); };
embeds.push(upcoming_embed);
};
embeds

View file

@ -8,18 +8,20 @@ use serenity::{
async_trait,
model::{
gateway::Ready,
interactions::{
application_command::{
ApplicationCommand,
ApplicationCommandOptionType,
application::{
command::{
Command,
CommandOptionType,
},
Interaction,
interaction::{
Interaction
}
},
},
prelude::*,
};
use serenity::client::bridge::gateway::GatewayIntents;
use serenity::model::gateway::Activity;
use serenity::model::prelude::OnlineStatus;
use crate::interactions::genshin::artifacts::show_artifact_embed;
use crate::interactions::genshin::build::build_interact;
use crate::interactions::genshin::weapons::show_weapon_embed;
@ -32,15 +34,18 @@ impl EventHandler for Handler {
async fn ready(&self, _ctx: Context, _bot: Ready) {
println!("{} connected!", _bot.user.name);
update_status_message(_ctx.clone()).await;
_ctx.set_activity(Activity::playing("Drinking")).await;
_ctx.set_presence(Some(Activity::playing("getting drunk with Kaeya")), OnlineStatus::Online).await;
let x = ApplicationCommand::get_global_application_commands(&_ctx.http).await.unwrap();
let x = Command::get_global_application_commands(&_ctx.http).await.unwrap();
for y in &x {
println!("{}", y.name);
}
for i in x {
match i.name.as_str() {
"genshin" => (),
"createstatusmessage" => (),
_ => {
let _result_delete = ApplicationCommand::delete_global_application_command(&_ctx.http, i.id).await;
let _result_delete = Command::delete_global_application_command(&_ctx.http, i.id).await;
match _result_delete {
Ok(()) => { println!("Deleted command {}", i.name) }
Err(f) => { println!("An error occurred deleting {} : {}", i.name, f) }
@ -49,35 +54,35 @@ impl EventHandler for Handler {
}
}
let x = ApplicationCommand::create_global_application_command(&_ctx.http, |command| {
let x = Command::create_global_application_command(&_ctx.http, |command| {
command.name("genshin").description("Get Informations about Genshin Impact.").create_option(|option| {
option.name("builds")
.description("Shows builds for a Genshin Impact Characters")
.kind(ApplicationCommandOptionType::SubCommand)
.kind(CommandOptionType::SubCommand)
.create_sub_option(|so| {
so.name("character").description("Character to get builds for")
.kind(ApplicationCommandOptionType::String)
.kind(CommandOptionType::String)
.required(true)
})
})
.create_option(|option| {
option.name("weapon")
.description("Shows infos on a Genshin Impact weapon.")
.kind(ApplicationCommandOptionType::SubCommand)
.kind(CommandOptionType::SubCommand)
.create_sub_option(|so| {
so.name("name").description("Weapon you want infos on.")
.kind(ApplicationCommandOptionType::String)
.kind(CommandOptionType::String)
.required(true)
})
})
.create_option(|option| {
option.name("artifact")
.description("Shows infos on a Genshin Impact artifact set.")
.kind(ApplicationCommandOptionType::SubCommand)
.kind(CommandOptionType::SubCommand)
.create_sub_option(|so| {
so.name("artifact")
.description("Artifact Set you want infos on.")
.kind(ApplicationCommandOptionType::String)
.kind(CommandOptionType::String)
.required(true)
})
})
@ -86,10 +91,10 @@ impl EventHandler for Handler {
println!("{}", x.unwrap_err());
}
ApplicationCommand::create_global_application_command(&_ctx.http, |command| {
Command::create_global_application_command(&_ctx.http, |command| {
command.name("createstatusmessage").create_option(|opt| {
opt.name("channel").description("Channel where to put the status message")
.kind(ApplicationCommandOptionType::Channel)
.kind(CommandOptionType::Channel)
.required(true)
}).description("Creates a status message of all the current events on Genshin Impact")
}).await.expect("Can't create the createstatusmessage command");
@ -106,7 +111,7 @@ impl EventHandler for Handler {
_ => interactions::pong(_ctx, command).await
}
} else if let Interaction::MessageComponent(component) = _interaction {
let mut args = component.data.custom_id.split("_");
let mut args = component.data.custom_id.split('_');
let command = args.next();
match command.unwrap() {
"weapon" => {
@ -130,7 +135,7 @@ impl EventHandler for Handler {
}
fn test_environment() {
env::var("DISCORD_TOKEN").expect("DISCORD_TOKEN needed");
env::var("TOKEN").expect("TOKEN needed");
env::var("MONGO_HOST").expect("MONGO_HOST needed");
env::var("MONGO_PORT").expect("MONGO_PORT needed");
env::var("API_HOST").expect("API_HOST needed");
@ -141,20 +146,19 @@ fn test_environment() {
async fn main() {
dotenv().ok();
test_environment();
let token= env::var("DISCORD_TOKEN").unwrap();
let token= env::var("TOKEN").unwrap();
let application_id: u64 = "860553396578811914".parse().expect("Wrong format");
let needed_intents = [
GatewayIntents::GUILDS,
GatewayIntents::GUILD_MESSAGES,
GatewayIntents::GUILD_EMOJIS,
GatewayIntents::GUILD_EMOJIS_AND_STICKERS,
GatewayIntents::GUILD_WEBHOOKS,
GatewayIntents::GUILD_INTEGRATIONS
];
let mut client = Client::builder(token)
let mut client = Client::builder(token, GatewayIntents::from_iter(needed_intents.into_iter()))
.event_handler(Handler)
.intents(GatewayIntents::from_iter(needed_intents.into_iter()))
.application_id(application_id)
.await
.expect("Error creating the client");

View file

@ -1,6 +1,6 @@
use linked_hash_map::LinkedHashMap;
use serenity::builder::{CreateActionRow, CreateButton};
use serenity::model::interactions::message_component::ButtonStyle;
use serenity::model::application::component::ButtonStyle;
pub mod mongo;

View file

@ -42,7 +42,7 @@ pub async fn get_discord_status_message(gid: &u64) -> Option<StatusMessage> {
match infos {
Some(i) => {
let m_infos: StatusMessage = from_bson(Bson::Document(i)).expect("Can't get");
return Some(m_infos);
Some(m_infos)
}
_ => None
}
@ -55,7 +55,7 @@ pub async fn get_all_status_messages() -> Vec<StatusMessage> {
let collection: Collection<StatusMessage> = client.database("drunk_venti").collection::<StatusMessage>("StatusMessages");
let documents = collection.find(None, None).await.expect("Can't get everything");
let all_docs: Vec<StatusMessage> = documents.try_collect().await.unwrap_or_else(|_| vec![]);
return all_docs;
all_docs
}
#[allow(dead_code)]