dsec-discord-bot/src/commands/weather.rs
Sam Limbu 150fa8f314 SEC-01: make cargo fmt and clippy clean so the CI job can go green
The CI workflow added in #5 fails on code that predates it: three files were
unformatted and `cargo clippy --all-targets -- -D warnings` reported 26 errors.
A red check cannot be made a required status check on the protect-main ruleset,
which is what this unblocks.

`cargo fmt --all` over three files, and 26 clippy errors resolved: 18 via
`cargo clippy --all-targets --fix`, the rest by hand. Two fixes uncovered lints
that had been masked (an `unnecessary_unwrap` in info.rs behind the needless
borrow on the line above, and two `unnecessary_to_owned` at the call sites of a
signature that moved from `&String` to `&str`), so 28 fixes for 26 warnings.

Three `#[allow]`s where the only real fix would change a signature or a public
API: `result_large_err` on `AppState::new` (the large variant is
`supabase::Error`, owned by supabase-lib-rs) and `too_many_arguments` on
`log_embed` and on the `embed` slash command.

No behaviour change. src/ only; .github/, Dockerfile, .dockerignore, Cargo.toml
and Cargo.lock are untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 22:24:54 +10:00

56 lines
2.2 KiB
Rust

use crate::{Context, Error};
use poise::CreateReply;
use serenity::{all::CreateEmbed, json::Value};
async fn get_weather(location: String) -> Result<String, Error> {
let weather_api_key = std::env::var("WEATHER_TOKEN").expect("missing WEATHER_TOKEN");
let request_url = format!(
"https://api.weatherapi.com/v1/current.json?key={key}&q={location}",
key = weather_api_key,
location = location
);
// retrieve weather data
let response = reqwest::get(request_url).await?.text().await?;
Ok(response)
}
/// Shows weather information
#[poise::command(slash_command)]
pub async fn weather(
ctx: Context<'_>,
#[description = "Location (City or Country)"] location: String,
) -> Result<(), Error> {
let weather_response = get_weather(location).await?;
let value: Value = serde_json::from_str(&weather_response)?;
let location_name = value["location"]["name"].as_str().unwrap();
let location_region = value["location"]["region"].as_str().unwrap();
let location_country = value["location"]["country"].as_str().unwrap();
let weather_condition = value["current"]["condition"]["text"].as_str().unwrap();
let weather_temp = &value["current"]["temp_c"];
let weather_feels_like = &value["current"]["feelslike_c"];
let weather_wind_kph = &value["current"]["wind_kph"];
let weather_humidity = &value["current"]["humidity"];
let weather_cloud = &value["current"]["cloud"];
let weather_icon = value["current"]["condition"]["icon"].as_str().unwrap();
let embed = CreateEmbed::new()
.field("Name", location_name.to_string(), true)
.field("Region", location_region.to_string(), true)
.field("Country", location_country.to_string(), true)
.field("Condition", weather_condition.to_string(), true)
.field("Temperature", format!("{} °C", weather_temp), true)
.field("Feels like", format!("{} °C", weather_feels_like), true)
.field("Wind", format!("{} kph", weather_wind_kph), true)
.field("Humidity", format!("{}%", weather_humidity), true)
.field("Cloud", format!("{}%", weather_cloud), true)
.thumbnail(format!("https:{}", weather_icon));
ctx.send(CreateReply::default().embed(embed)).await?;
Ok(())
}