3 Commits

Author SHA1 Message Date
Lukas Wölfer
eb88c041f6 Depedency on release CI
All checks were successful
Rust / build_and_test (push) Successful in 1m14s
Release / build_release (push) Successful in 2m26s
2026-01-17 23:40:49 +01:00
Lukas Wölfer
596f1b3a6b Version bump
Some checks failed
Release / build_release (push) Has been cancelled
Rust / build_and_test (push) Has been cancelled
2026-01-17 23:39:18 +01:00
Lukas Wölfer
6f332b314d Added subcommands 2026-01-17 23:34:24 +01:00
5 changed files with 57 additions and 27 deletions

View File

@@ -11,6 +11,7 @@ env:
jobs: jobs:
build_release: build_release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build_and_test
env: env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_SERVER: ${{ secrets.GITEA_SERVER }} GITEA_SERVER: ${{ secrets.GITEA_SERVER }}

2
Cargo.lock generated
View File

@@ -3201,7 +3201,7 @@ dependencies = [
[[package]] [[package]]
name = "teachertracker-rs" name = "teachertracker-rs"
version = "0.1.5" version = "0.1.6"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"chrono", "chrono",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "teachertracker-rs" name = "teachertracker-rs"
version = "0.1.5" version = "0.1.6"
edition = "2024" edition = "2024"
authors = ["Lukas Wölfer <coding@thasky.one>"] authors = ["Lukas Wölfer <coding@thasky.one>"]
description = "A MediaWiki bot that updates score information of teachers" description = "A MediaWiki bot that updates score information of teachers"
@@ -14,8 +14,7 @@ categories = ["web-programming", "api-bindings", "automation"]
chrono = "0.4.41" chrono = "0.4.41"
clap = { version = "4.5.54", features = ["derive"] } clap = { version = "4.5.54", features = ["derive"] }
futures = "0.3.31" futures = "0.3.31"
# mwbot = { git = "https://gitlab.wikimedia.org/repos/mwbot-rs/mwbot.git", rev = "05cbb12188f18e2da710de158d89a9a4f1b42689", default-features = false, features = ["generators", "mwbot_derive"] } mwbot = { version = "0.7.1", default-features = false, features = ["generators", "mwbot_derive"] }
mwbot = { version = "0.7.0", default-features = false, features = ["generators", "mwbot_derive"] }
rand = "0.9.2" rand = "0.9.2"
reqwest = "0.12.22" reqwest = "0.12.22"
scraper = "0.24.0" scraper = "0.24.0"

View File

@@ -26,8 +26,8 @@ use std::path::Path;
use tracing::level_filters::LevelFilter; use tracing::level_filters::LevelFilter;
use tracing_subscriber::{Layer, layer::SubscriberExt, util::SubscriberInitExt}; use tracing_subscriber::{Layer, layer::SubscriberExt, util::SubscriberInitExt};
use crate::fetching::{DynWsdcFetcher, ScoringDanceFetcher, WorldsdcFetcher};
use crate::watchdog::{update_wanted_ids, watch_wanted}; use crate::watchdog::{update_wanted_ids, watch_wanted};
use crate::fetching::{DynWsdcFetcher, WorldsdcFetcher, ScoringDanceFetcher};
mod dance_info; mod dance_info;
mod fetching; mod fetching;
@@ -128,8 +128,19 @@ enum WsdcPointsBackend {
#[derive(Subcommand)] #[derive(Subcommand)]
enum Commands { enum Commands {
/// Continuously watch for missing or outdated teachers and update them
Watch,
/// Build pages for all missing teachers /// Build pages for all missing teachers
Missing, FixMissing,
/// List all missing teachers
ListMissing,
/// Update info for all teachers
FetchInfo(FetchInfoArgs),
}
#[derive(Parser)]
struct FetchInfoArgs {
id: u32,
} }
fn main() -> Result<(), AppError> { fn main() -> Result<(), AppError> {
@@ -149,9 +160,10 @@ fn main() -> Result<(), AppError> {
WsdcPointsBackend::ScoringDance => std::sync::Arc::new(ScoringDanceFetcher {}), WsdcPointsBackend::ScoringDance => std::sync::Arc::new(ScoringDanceFetcher {}),
WsdcPointsBackend::WorldSDC => std::sync::Arc::new(WorldsdcFetcher {}), WsdcPointsBackend::WorldSDC => std::sync::Arc::new(WorldsdcFetcher {}),
}; };
let command = cli.command.as_ref().map_or(&Commands::Watch, |cmd| cmd);
match &cli.command { match command {
Some(Commands::Missing) => { Commands::ListMissing => {
rt.block_on(async { rt.block_on(async {
let wanted = wikiinfo::wanted_ids(bot.clone(), fetcher.clone()).await; let wanted = wikiinfo::wanted_ids(bot.clone(), fetcher.clone()).await;
tracing::info!( tracing::info!(
@@ -165,18 +177,48 @@ fn main() -> Result<(), AppError> {
); );
update_wanted_ids(&wanted, &[], fetcher.clone()).await; update_wanted_ids(&wanted, &[], fetcher.clone()).await;
}); });
return Ok(());
} }
None => { Commands::FetchInfo(args) => {
rt.block_on(async {
let info = fetcher.fetch(args.id).await;
#[allow(
clippy::print_stdout,
clippy::print_stderr,
reason = "We want to print here"
)]
match info {
Ok(info) => println!("Fetched info: {info:?}"),
Err(err) => eprintln!("Error fetching info: {err}"),
}
});
}
Commands::FixMissing => {
rt.block_on(async {
let wanted = wikiinfo::wanted_ids(bot.clone(), fetcher.clone()).await;
tracing::info!(
"Missing ids: {}",
wanted
.iter()
.map(|(v, _)| v)
.map(u32::to_string)
.collect::<Vec<_>>()
.join("\n")
);
update_wanted_ids(&wanted, &[], fetcher.clone()).await;
});
}
Commands::Watch => {
#[allow( #[allow(
unreachable_code, unreachable_code,
reason = "This is a false positive I think, I just want to loop infinitely on two futures" reason = "This is a false positive I think, I just want to loop infinitely on two futures"
)] )]
rt.block_on(async { rt.block_on(async {
futures::join!(watch_wanted(bot.clone(), fetcher.clone()), updater::update_wsdc(bot, fetcher.clone())) futures::join!(
watch_wanted(bot.clone(), fetcher.clone()),
updater::update_wsdc(bot, fetcher.clone())
)
}); });
} }
} }
unreachable!(); Ok(())
} }

View File

@@ -4,8 +4,8 @@ use mwbot::{
}; };
use crate::fetching::DynWsdcFetcher; use crate::fetching::DynWsdcFetcher;
pub async fn wanted_ids(_bot: Bot, _fetcher: DynWsdcFetcher) -> Vec<(u32, Page)> { pub async fn wanted_ids(bot: Bot, _fetcher: DynWsdcFetcher) -> Vec<(u32, Page)> {
let mut gene = QueryPage::new("Wantedpages").generate(&_bot); let mut gene = QueryPage::new("Wantedpages").generate(&bot);
let mut result = vec![]; let mut result = vec![];
while let Some(x) = gene.recv().await { while let Some(x) = gene.recv().await {
let p = match x { let p = match x {
@@ -51,18 +51,6 @@ fn parse_wsdc_page_name(name: &str) -> Result<u32, TitleParseError> {
} }
} }
// fn get_wsdc_page_date(bot: &Bot, page: &Page) -> Option<SystemTime> {
// todo!();
// let prefix = "Updated-On: ";
// page.filter_comments()
// .iter()
// .filter_map(|x| {
// let c = x.text_contents();
// if c.starts_with(prefix) { Some(c) } else { None }
// })
// .map(|x| x.trim_start_matches(prefix).parse::<u64>());
// }
#[allow(dead_code)] #[allow(dead_code)]
pub async fn index_wsdc_ids(bot: &Bot, _fetcher: DynWsdcFetcher) -> Vec<(u32, Page)> { pub async fn index_wsdc_ids(bot: &Bot, _fetcher: DynWsdcFetcher) -> Vec<(u32, Page)> {
let mut gene = Search::new("WSDC/").generate(bot); let mut gene = Search::new("WSDC/").generate(bot);