Skip to content
Snippets Groups Projects
push.rs 17.2 KiB
Newer Older
Jonathan de Jong's avatar
Jonathan de Jong committed
use crate::{database::DatabaseGuard, ConduitResult, Error, Ruma};
use ruma::{
    api::client::{
        error::ErrorKind,
        r0::push::{
            delete_pushrule, get_pushers, get_pushrule, get_pushrule_actions, get_pushrule_enabled,
            get_pushrules_all, set_pusher, set_pushrule, set_pushrule_actions,
            set_pushrule_enabled, RuleKind,
    events::{push_rules, EventType},
Jonas Platte's avatar
Jonas Platte committed
    push::{ConditionalPushRuleInit, PatternedPushRuleInit, SimplePushRuleInit},
};

#[cfg(feature = "conduit_bin")]
use rocket::{delete, get, post, put};

#[cfg_attr(
    feature = "conduit_bin",
    get("/_matrix/client/r0/pushrules", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn get_pushrules_all_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<get_pushrules_all::Request>,
) -> ConduitResult<get_pushrules_all::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");

    let event = db
        .account_data
        .get::<push_rules::PushRulesEvent>(None, &sender_user, EventType::PushRules)?
        .ok_or(Error::BadRequest(
            ErrorKind::NotFound,
            "PushRules event not found.",
        ))?;

    Ok(get_pushrules_all::Response {
        global: event.content.global,
    }
    .into())
}

#[cfg_attr(
    feature = "conduit_bin",
    get("/_matrix/client/r0/pushrules/<_>/<_>/<_>", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn get_pushrule_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<get_pushrule::Request<'_>>,
) -> ConduitResult<get_pushrule::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");

    let event = db
        .account_data
        .get::<push_rules::PushRulesEvent>(None, &sender_user, EventType::PushRules)?
        .ok_or(Error::BadRequest(
            ErrorKind::NotFound,
            "PushRules event not found.",
        ))?;

    let global = event.content.global;
    let rule = match body.kind {
        RuleKind::Override => global
            .override_
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.clone().into()),
        RuleKind::Underride => global
            .underride
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.clone().into()),
        RuleKind::Sender => global
            .sender
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.clone().into()),
        RuleKind::Room => global
            .room
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.clone().into()),
        RuleKind::Content => global
            .content
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.clone().into()),
Timo Kösters's avatar
Timo Kösters committed
        _ => None,
    };

    if let Some(rule) = rule {
        Ok(get_pushrule::Response { rule }.into())
    } else {
        Err(Error::BadRequest(
            ErrorKind::NotFound,
            "Push rule not found.",
        ))
    }
}

#[cfg_attr(
    feature = "conduit_bin",
Jonas Platte's avatar
Jonas Platte committed
    put("/_matrix/client/r0/pushrules/<_>/<_>/<_>", data = "<req>")
Jonas Platte's avatar
Jonas Platte committed
#[tracing::instrument(skip(db, req))]
pub async fn set_pushrule_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
Jonas Platte's avatar
Jonas Platte committed
    req: Ruma<set_pushrule::Request<'_>>,
) -> ConduitResult<set_pushrule::Response> {
Jonas Platte's avatar
Jonas Platte committed
    let sender_user = req.sender_user.as_ref().expect("user is authenticated");
    let body = req.body;

    if body.scope != "global" {
        return Err(Error::BadRequest(
            ErrorKind::InvalidParam,
            "Scopes other than 'global' are not supported.",
        ));
    }

    let mut event = db
        .account_data
        .get::<push_rules::PushRulesEvent>(None, &sender_user, EventType::PushRules)?
        .ok_or(Error::BadRequest(
            ErrorKind::NotFound,
            "PushRules event not found.",
        ))?;

    let global = &mut event.content.global;
    match body.kind {
        RuleKind::Override => {
Jonas Platte's avatar
Jonas Platte committed
            global.override_.replace(
                ConditionalPushRuleInit {
Jonas Platte's avatar
Jonas Platte committed
                    actions: body.actions,
                    default: false,
                    enabled: true,
Jonas Platte's avatar
Jonas Platte committed
                    rule_id: body.rule_id,
                    conditions: body.conditions,
                }
                .into(),
Jonas Platte's avatar
Jonas Platte committed
            );
        }
        RuleKind::Underride => {
Jonas Platte's avatar
Jonas Platte committed
            global.underride.replace(
                ConditionalPushRuleInit {
Jonas Platte's avatar
Jonas Platte committed
                    actions: body.actions,
                    default: false,
                    enabled: true,
Jonas Platte's avatar
Jonas Platte committed
                    rule_id: body.rule_id,
                    conditions: body.conditions,
                }
                .into(),
Jonas Platte's avatar
Jonas Platte committed
            );
        }
        RuleKind::Sender => {
Jonas Platte's avatar
Jonas Platte committed
            global.sender.replace(
                SimplePushRuleInit {
Jonas Platte's avatar
Jonas Platte committed
                    actions: body.actions,
                    default: false,
                    enabled: true,
Jonas Platte's avatar
Jonas Platte committed
                    rule_id: body.rule_id,
                }
                .into(),
Jonas Platte's avatar
Jonas Platte committed
            );
        }
        RuleKind::Room => {
Jonas Platte's avatar
Jonas Platte committed
            global.room.replace(
                SimplePushRuleInit {
Jonas Platte's avatar
Jonas Platte committed
                    actions: body.actions,
                    default: false,
                    enabled: true,
Jonas Platte's avatar
Jonas Platte committed
                    rule_id: body.rule_id,
                }
                .into(),
Jonas Platte's avatar
Jonas Platte committed
            );
        }
        RuleKind::Content => {
Jonas Platte's avatar
Jonas Platte committed
            global.content.replace(
                PatternedPushRuleInit {
Jonas Platte's avatar
Jonas Platte committed
                    actions: body.actions,
                    default: false,
                    enabled: true,
Jonas Platte's avatar
Jonas Platte committed
                    rule_id: body.rule_id,
                    pattern: body.pattern.unwrap_or_default(),
                }
                .into(),
Jonas Platte's avatar
Jonas Platte committed
            );
Timo Kösters's avatar
Timo Kösters committed
        _ => {}
    }

    db.account_data.update(
        None,
        &sender_user,
        EventType::PushRules,
        &event,
        &db.globals,
    )?;
    Ok(set_pushrule::Response {}.into())
}

#[cfg_attr(
    feature = "conduit_bin",
    get("/_matrix/client/r0/pushrules/<_>/<_>/<_>/actions", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn get_pushrule_actions_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<get_pushrule_actions::Request<'_>>,
) -> ConduitResult<get_pushrule_actions::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");

    if body.scope != "global" {
        return Err(Error::BadRequest(
            ErrorKind::InvalidParam,
            "Scopes other than 'global' are not supported.",
        ));
    }

    let mut event = db
        .account_data
        .get::<push_rules::PushRulesEvent>(None, &sender_user, EventType::PushRules)?
        .ok_or(Error::BadRequest(
            ErrorKind::NotFound,
            "PushRules event not found.",
        ))?;

    let global = &mut event.content.global;
    let actions = match body.kind {
        RuleKind::Override => global
            .override_
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.actions.clone()),
        RuleKind::Underride => global
            .underride
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.actions.clone()),
        RuleKind::Sender => global
            .sender
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.actions.clone()),
        RuleKind::Room => global
            .room
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.actions.clone()),
        RuleKind::Content => global
            .content
Jonas Platte's avatar
Jonas Platte committed
            .get(body.rule_id.as_str())
            .map(|rule| rule.actions.clone()),
Timo Kösters's avatar
Timo Kösters committed
        _ => None,

    Ok(get_pushrule_actions::Response {
        actions: actions.unwrap_or_default(),
    }
    .into())
}

#[cfg_attr(
    feature = "conduit_bin",
    put("/_matrix/client/r0/pushrules/<_>/<_>/<_>/actions", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn set_pushrule_actions_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<set_pushrule_actions::Request<'_>>,
) -> ConduitResult<set_pushrule_actions::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");

    if body.scope != "global" {
        return Err(Error::BadRequest(
            ErrorKind::InvalidParam,
            "Scopes other than 'global' are not supported.",
        ));
    }

    let mut event = db
        .account_data
        .get::<push_rules::PushRulesEvent>(None, &sender_user, EventType::PushRules)?
        .ok_or(Error::BadRequest(
            ErrorKind::NotFound,
            "PushRules event not found.",
        ))?;

    let global = &mut event.content.global;
    match body.kind {
        RuleKind::Override => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.override_.get(body.rule_id.as_str()).cloned() {
                rule.actions = body.actions.clone();
                global.override_.replace(rule);
            }
        }
        RuleKind::Underride => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.underride.get(body.rule_id.as_str()).cloned() {
                rule.actions = body.actions.clone();
                global.underride.replace(rule);
            }
        }
        RuleKind::Sender => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.sender.get(body.rule_id.as_str()).cloned() {
                rule.actions = body.actions.clone();
                global.sender.replace(rule);
            }
        }
        RuleKind::Room => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.room.get(body.rule_id.as_str()).cloned() {
                rule.actions = body.actions.clone();
                global.room.replace(rule);
            }
        }
        RuleKind::Content => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.content.get(body.rule_id.as_str()).cloned() {
                rule.actions = body.actions.clone();
                global.content.replace(rule);
Timo Kösters's avatar
Timo Kösters committed
        _ => {}
    };

    db.account_data.update(
        None,
        &sender_user,
        EventType::PushRules,
        &event,
        &db.globals,
    )?;

    Ok(set_pushrule_actions::Response {}.into())
}

#[cfg_attr(
    feature = "conduit_bin",
    get("/_matrix/client/r0/pushrules/<_>/<_>/<_>/enabled", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn get_pushrule_enabled_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<get_pushrule_enabled::Request<'_>>,
) -> ConduitResult<get_pushrule_enabled::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");

    if body.scope != "global" {
        return Err(Error::BadRequest(
            ErrorKind::InvalidParam,
            "Scopes other than 'global' are not supported.",
        ));
    }

    let mut event = db
        .account_data
        .get::<push_rules::PushRulesEvent>(None, &sender_user, EventType::PushRules)?
        .ok_or(Error::BadRequest(
            ErrorKind::NotFound,
            "PushRules event not found.",
        ))?;

    let global = &mut event.content.global;
    let enabled = match body.kind {
        RuleKind::Override => global
            .override_
            .iter()
Jonas Platte's avatar
Jonas Platte committed
            .find(|rule| rule.rule_id == body.rule_id)
            .map_or(false, |rule| rule.enabled),
        RuleKind::Underride => global
            .underride
            .iter()
Jonas Platte's avatar
Jonas Platte committed
            .find(|rule| rule.rule_id == body.rule_id)
            .map_or(false, |rule| rule.enabled),
        RuleKind::Sender => global
            .sender
            .iter()
Jonas Platte's avatar
Jonas Platte committed
            .find(|rule| rule.rule_id == body.rule_id)
            .map_or(false, |rule| rule.enabled),
        RuleKind::Room => global
            .room
            .iter()
Jonas Platte's avatar
Jonas Platte committed
            .find(|rule| rule.rule_id == body.rule_id)
            .map_or(false, |rule| rule.enabled),
        RuleKind::Content => global
            .content
            .iter()
Jonas Platte's avatar
Jonas Platte committed
            .find(|rule| rule.rule_id == body.rule_id)
            .map_or(false, |rule| rule.enabled),
Timo Kösters's avatar
Timo Kösters committed
        _ => false,

    Ok(get_pushrule_enabled::Response { enabled }.into())
}

#[cfg_attr(
    feature = "conduit_bin",
    put("/_matrix/client/r0/pushrules/<_>/<_>/<_>/enabled", data = "<body>")
#[tracing::instrument(skip(db, body))]
pub async fn set_pushrule_enabled_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<set_pushrule_enabled::Request<'_>>,
) -> ConduitResult<set_pushrule_enabled::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");

    if body.scope != "global" {
        return Err(Error::BadRequest(
            ErrorKind::InvalidParam,
            "Scopes other than 'global' are not supported.",
        ));
    }

    let mut event = db
        .account_data
        .get::<ruma::events::push_rules::PushRulesEvent>(None, &sender_user, EventType::PushRules)?
        .ok_or(Error::BadRequest(
            ErrorKind::NotFound,
            "PushRules event not found.",
        ))?;

    let global = &mut event.content.global;
    match body.kind {
        RuleKind::Override => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.override_.get(body.rule_id.as_str()).cloned() {
                global.override_.remove(&rule);
Jonas Platte's avatar
Jonas Platte committed
                rule.enabled = body.enabled;
                global.override_.insert(rule);
            }
        }
        RuleKind::Underride => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.underride.get(body.rule_id.as_str()).cloned() {
                global.underride.remove(&rule);
Jonas Platte's avatar
Jonas Platte committed
                rule.enabled = body.enabled;
                global.underride.insert(rule);
            }
        }
        RuleKind::Sender => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.sender.get(body.rule_id.as_str()).cloned() {
                global.sender.remove(&rule);
Jonas Platte's avatar
Jonas Platte committed
                rule.enabled = body.enabled;
                global.sender.insert(rule);
            }
        }
        RuleKind::Room => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.room.get(body.rule_id.as_str()).cloned() {
                global.room.remove(&rule);
Jonas Platte's avatar
Jonas Platte committed
                rule.enabled = body.enabled;
                global.room.insert(rule);
            }
        }
        RuleKind::Content => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(mut rule) = global.content.get(body.rule_id.as_str()).cloned() {
                global.content.remove(&rule);
Jonas Platte's avatar
Jonas Platte committed
                rule.enabled = body.enabled;
                global.content.insert(rule);
            }
        }
Timo Kösters's avatar
Timo Kösters committed
        _ => {}
    }

    db.account_data.update(
        None,
        &sender_user,
        EventType::PushRules,
        &event,
        &db.globals,
    )?;
    Ok(set_pushrule_enabled::Response {}.into())
#[cfg_attr(
    feature = "conduit_bin",
    delete("/_matrix/client/r0/pushrules/<_>/<_>/<_>", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn delete_pushrule_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<delete_pushrule::Request<'_>>,
) -> ConduitResult<delete_pushrule::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");

    if body.scope != "global" {
        return Err(Error::BadRequest(
            ErrorKind::InvalidParam,
            "Scopes other than 'global' are not supported.",
        ));
    }

    let mut event = db
        .account_data
        .get::<push_rules::PushRulesEvent>(None, &sender_user, EventType::PushRules)?
        .ok_or(Error::BadRequest(
            ErrorKind::NotFound,
            "PushRules event not found.",
        ))?;

    let global = &mut event.content.global;
    match body.kind {
        RuleKind::Override => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(rule) = global.override_.get(body.rule_id.as_str()).cloned() {
                global.override_.remove(&rule);
            }
        }
        RuleKind::Underride => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(rule) = global.underride.get(body.rule_id.as_str()).cloned() {
                global.underride.remove(&rule);
            }
        }
        RuleKind::Sender => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(rule) = global.sender.get(body.rule_id.as_str()).cloned() {
                global.sender.remove(&rule);
            }
        }
        RuleKind::Room => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(rule) = global.room.get(body.rule_id.as_str()).cloned() {
                global.room.remove(&rule);
            }
        }
        RuleKind::Content => {
Jonas Platte's avatar
Jonas Platte committed
            if let Some(rule) = global.content.get(body.rule_id.as_str()).cloned() {
                global.content.remove(&rule);
            }
        }
Timo Kösters's avatar
Timo Kösters committed
        _ => {}
    }

    db.account_data.update(
        None,
        &sender_user,
        EventType::PushRules,
        &event,
        &db.globals,
    )?;

    Ok(delete_pushrule::Response {}.into())
#[cfg_attr(
    feature = "conduit_bin",
    get("/_matrix/client/r0/pushers", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn get_pushers_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<get_pushers::Request>,
) -> ConduitResult<get_pushers::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");
    Ok(get_pushers::Response {
        pushers: db.pusher.get_pushers(sender_user)?,
#[cfg_attr(
    feature = "conduit_bin",
    post("/_matrix/client/r0/pushers/set", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn set_pushers_route(
Jonathan de Jong's avatar
Jonathan de Jong committed
    db: DatabaseGuard,
    body: Ruma<set_pusher::Request>,
) -> ConduitResult<set_pusher::Response> {
    let sender_user = body.sender_user.as_ref().expect("user is authenticated");
    let pusher = body.pusher.clone();

    db.pusher.set_pusher(sender_user, pusher)?;
    Ok(set_pusher::Response::default().into())