mwbot 0.7.1

A MediaWiki bot framework
Documentation
// SPDX-FileCopyrightText: 2024 Misato Kano <me@mirror-kt.dev>
// SPDX-License-Identifier: GPL-3.0-or-later
//! Generators to get revisions (e.g. page history)
//!
//! See the [`Revisions`] type documentation for specifics.

use super::{Generator, ParamValue};
use crate::{Bot, Page, Result};
use mwapi_responses::query;
use mwtimestamp::Timestamp;

#[query(prop = "revisions", rvprop = "ids|flags|timestamp|user|comment|tags")]
pub struct RevisionsResponse {}

/// Get revision information of page(s).
///
/// See [API documentation](https://www.mediawiki.org/wiki/API:Revisions) for more details.
#[derive(Generator)]
#[generator(
    return_type = "(Page, RevisionsResponseItemrevisions)",
    response_type = "RevisionsResponse",
    transform_fn = "transform",
    wrap_in_vec = true
)]
#[params(prop = "revisions", rvlimit = "max", rvdir = "newer")]
pub struct Revisions {
    #[param("titles")]
    titles: Vec<String>,
    #[param("rvslots")]
    slots: Option<Vec<String>>,
    // TODO: support rvcontentformat-{slot} templated-parameter
    #[param("rvstartid")]
    start_id: Option<u64>,
    #[param("rvendid")]
    end_id: Option<u64>,
    #[param("rvstart")]
    start: Option<Timestamp>,
    #[param("rvend")]
    end: Option<Timestamp>,
    #[param("rvdir")]
    dir: Option<Direction>,
    #[param("rvuser")]
    user: Option<String>,
    #[param("rvexcludeuser")]
    exclude_user: Option<String>,
    #[param("rvtag")]
    tag: Option<String>,
}

pub enum Direction {
    Newer,
    Older,
}

impl ParamValue for Direction {
    fn stringify(&self) -> String {
        match *self {
            Self::Newer => "newer",
            Self::Older => "older",
        }
        .to_string()
    }
}

fn transform(
    bot: &Bot,
    item: RevisionsResponseItem,
) -> Result<Vec<(Page, RevisionsResponseItemrevisions)>> {
    let page = bot.page(&item.title)?;
    Ok(item
        .revisions
        .into_iter()
        .map(|rev| (page.clone(), rev))
        .collect())
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::testwp;

    #[tokio::test]
    async fn test_revisions() {
        let bot = testwp().await;
        let gen = Revisions::new(vec!["Main Page".to_string()]);
        let mut recv = gen.generate(&bot);

        let mut count = 0;

        while let Some(revisions) = recv.recv().await {
            let _revisions = revisions.unwrap();
            if count >= 10 {
                break;
            }
            count += 1;
        }
    }
}