state-res: Enforce integer PLs for room v10 on custom types
According to MSC3667
This commit is contained in:
		
							parent
							
								
									da462adab1
								
							
						
					
					
						commit
						df821ab753
					
				@ -19,11 +19,14 @@ use serde::{de::IgnoredAny, Deserialize};
 | 
			
		||||
use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};
 | 
			
		||||
use tracing::{debug, error, info, warn};
 | 
			
		||||
 | 
			
		||||
use crate::{room_version::RoomVersion, Error, Event, PowerLevelsContentFields, Result};
 | 
			
		||||
 | 
			
		||||
mod int_power_levels;
 | 
			
		||||
 | 
			
		||||
use int_power_levels::IntRoomPowerLevelsEventContent;
 | 
			
		||||
use crate::{
 | 
			
		||||
    power_levels::{
 | 
			
		||||
        deserialize_power_levels, deserialize_power_levels_content_fields,
 | 
			
		||||
        deserialize_power_levels_content_invite, deserialize_power_levels_content_redact,
 | 
			
		||||
    },
 | 
			
		||||
    room_version::RoomVersion,
 | 
			
		||||
    Error, Event, Result,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// FIXME: field extracting could be bundled for `content`
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
@ -37,11 +40,6 @@ struct RoomMemberContentFields {
 | 
			
		||||
    join_authorised_via_users_server: Option<Raw<OwnedUserId>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
struct PowerLevelsContentInvite {
 | 
			
		||||
    invite: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// For the given event `kind` what are the relevant auth events that are needed to authenticate
 | 
			
		||||
/// this `content`.
 | 
			
		||||
///
 | 
			
		||||
@ -337,15 +335,12 @@ pub fn auth_check<E: Event>(
 | 
			
		||||
 | 
			
		||||
    // If type is m.room.third_party_invite
 | 
			
		||||
    let sender_power_level = if let Some(pl) = &power_levels_event {
 | 
			
		||||
        if let Ok(content) = from_json_str::<PowerLevelsContentFields>(pl.content().get()) {
 | 
			
		||||
        let content = deserialize_power_levels_content_fields(pl.content().get(), room_version)?;
 | 
			
		||||
        if let Some(level) = content.users.get(sender) {
 | 
			
		||||
            *level
 | 
			
		||||
        } else {
 | 
			
		||||
            content.users_default
 | 
			
		||||
        }
 | 
			
		||||
        } else {
 | 
			
		||||
            int!(0) // TODO if this fails DB error?
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // If no power level event found the creator gets 100 everyone else gets 0
 | 
			
		||||
        from_json_str::<RoomCreateEventContent>(room_create_event.content().get())
 | 
			
		||||
@ -359,7 +354,8 @@ pub fn auth_check<E: Event>(
 | 
			
		||||
    if *incoming_event.event_type() == RoomEventType::RoomThirdPartyInvite {
 | 
			
		||||
        let invite_level = match &power_levels_event {
 | 
			
		||||
            Some(power_levels) => {
 | 
			
		||||
                from_json_str::<PowerLevelsContentInvite>(power_levels.content().get())?.invite
 | 
			
		||||
                deserialize_power_levels_content_invite(power_levels.content().get(), room_version)?
 | 
			
		||||
                    .invite
 | 
			
		||||
            }
 | 
			
		||||
            None => int!(0),
 | 
			
		||||
        };
 | 
			
		||||
@ -408,15 +404,12 @@ pub fn auth_check<E: Event>(
 | 
			
		||||
    if room_version.extra_redaction_checks
 | 
			
		||||
        && *incoming_event.event_type() == RoomEventType::RoomRedaction
 | 
			
		||||
    {
 | 
			
		||||
        #[derive(Deserialize)]
 | 
			
		||||
        struct PowerLevelsContentRedact {
 | 
			
		||||
            redact: Int,
 | 
			
		||||
        let redact_level = match power_levels_event {
 | 
			
		||||
            Some(pl) => {
 | 
			
		||||
                deserialize_power_levels_content_redact(pl.content().get(), room_version)?.redact
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        let redact_level = power_levels_event
 | 
			
		||||
            .and_then(|pl| from_json_str::<PowerLevelsContentRedact>(pl.content().get()).ok())
 | 
			
		||||
            .map(|c| c.redact)
 | 
			
		||||
            .unwrap_or_else(|| int!(50));
 | 
			
		||||
            None => int!(50),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if !check_redaction(room_version, incoming_event, sender_power_level, redact_level)? {
 | 
			
		||||
            return Ok(false);
 | 
			
		||||
@ -500,12 +493,11 @@ fn valid_membership_change(
 | 
			
		||||
        // Is the authorised user allowed to invite users into this room
 | 
			
		||||
        let (auth_user_pl, invite_level) = if let Some(pl) = &power_levels_event {
 | 
			
		||||
            // TODO Refactor all powerlevel parsing
 | 
			
		||||
            let invite = match from_json_str::<PowerLevelsContentInvite>(pl.content().get()) {
 | 
			
		||||
                Ok(power_levels) => power_levels.invite,
 | 
			
		||||
                _ => int!(0),
 | 
			
		||||
            };
 | 
			
		||||
            let invite =
 | 
			
		||||
                deserialize_power_levels_content_invite(pl.content().get(), room_version)?.invite;
 | 
			
		||||
 | 
			
		||||
            if let Ok(content) = from_json_str::<PowerLevelsContentFields>(pl.content().get()) {
 | 
			
		||||
            let content =
 | 
			
		||||
                deserialize_power_levels_content_fields(pl.content().get(), room_version)?;
 | 
			
		||||
            let user_pl = if let Some(level) = content.users.get(user_for_join_auth) {
 | 
			
		||||
                *level
 | 
			
		||||
            } else {
 | 
			
		||||
@ -513,9 +505,6 @@ fn valid_membership_change(
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            (user_pl, invite)
 | 
			
		||||
            } else {
 | 
			
		||||
                (int!(0), invite)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            (int!(0), int!(0))
 | 
			
		||||
        };
 | 
			
		||||
@ -877,31 +866,6 @@ fn check_power_levels(
 | 
			
		||||
    Some(true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn deserialize_power_levels(
 | 
			
		||||
    content: &str,
 | 
			
		||||
    room_version: &RoomVersion,
 | 
			
		||||
) -> Option<RoomPowerLevelsEventContent> {
 | 
			
		||||
    if room_version.integer_power_levels {
 | 
			
		||||
        match from_json_str::<IntRoomPowerLevelsEventContent>(content) {
 | 
			
		||||
            Ok(content) => Some(content.into()),
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                error!("m.room.power_levels event is not valid with integer values");
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        match from_json_str(content) {
 | 
			
		||||
            Ok(content) => Some(content),
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                error!(
 | 
			
		||||
                    "m.room.power_levels event is not valid with integer or string integer values"
 | 
			
		||||
                );
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_deserialize_levels(
 | 
			
		||||
    old: &serde_json::Value,
 | 
			
		||||
    new: &serde_json::Value,
 | 
			
		||||
 | 
			
		||||
@ -1,94 +0,0 @@
 | 
			
		||||
use std::collections::BTreeMap;
 | 
			
		||||
 | 
			
		||||
use js_int::Int;
 | 
			
		||||
use ruma_common::{
 | 
			
		||||
    events::{room::power_levels::RoomPowerLevelsEventContent, RoomEventType},
 | 
			
		||||
    power_levels::{default_power_level, NotificationPowerLevels},
 | 
			
		||||
    OwnedUserId,
 | 
			
		||||
};
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
pub struct IntRoomPowerLevelsEventContent {
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub ban: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub events: BTreeMap<RoomEventType, Int>,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub events_default: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub invite: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub kick: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub redact: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub state_default: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub users: BTreeMap<OwnedUserId, Int>,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub users_default: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub notifications: IntNotificationPowerLevels,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IntRoomPowerLevelsEventContent> for RoomPowerLevelsEventContent {
 | 
			
		||||
    fn from(int_pl: IntRoomPowerLevelsEventContent) -> Self {
 | 
			
		||||
        let IntRoomPowerLevelsEventContent {
 | 
			
		||||
            ban,
 | 
			
		||||
            events,
 | 
			
		||||
            events_default,
 | 
			
		||||
            invite,
 | 
			
		||||
            kick,
 | 
			
		||||
            redact,
 | 
			
		||||
            state_default,
 | 
			
		||||
            users,
 | 
			
		||||
            users_default,
 | 
			
		||||
            notifications,
 | 
			
		||||
        } = int_pl;
 | 
			
		||||
 | 
			
		||||
        let mut pl = Self::new();
 | 
			
		||||
        pl.ban = ban;
 | 
			
		||||
        pl.events = events;
 | 
			
		||||
        pl.events_default = events_default;
 | 
			
		||||
        pl.invite = invite;
 | 
			
		||||
        pl.kick = kick;
 | 
			
		||||
        pl.redact = redact;
 | 
			
		||||
        pl.state_default = state_default;
 | 
			
		||||
        pl.users = users;
 | 
			
		||||
        pl.users_default = users_default;
 | 
			
		||||
        pl.notifications = notifications.into();
 | 
			
		||||
 | 
			
		||||
        pl
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
pub struct IntNotificationPowerLevels {
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub room: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for IntNotificationPowerLevels {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self { room: default_power_level() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IntNotificationPowerLevels> for NotificationPowerLevels {
 | 
			
		||||
    fn from(int_notif: IntNotificationPowerLevels) -> Self {
 | 
			
		||||
        let mut notif = Self::new();
 | 
			
		||||
        notif.room = int_notif.room;
 | 
			
		||||
 | 
			
		||||
        notif
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
use std::{
 | 
			
		||||
    borrow::Borrow,
 | 
			
		||||
    cmp::Reverse,
 | 
			
		||||
    collections::{BTreeMap, BinaryHeap, HashMap, HashSet},
 | 
			
		||||
    collections::{BinaryHeap, HashMap, HashSet},
 | 
			
		||||
    hash::Hash,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -12,14 +12,14 @@ use ruma_common::{
 | 
			
		||||
        room::member::{MembershipState, RoomMemberEventContent},
 | 
			
		||||
        RoomEventType, StateEventType,
 | 
			
		||||
    },
 | 
			
		||||
    EventId, MilliSecondsSinceUnixEpoch, OwnedUserId, RoomVersionId,
 | 
			
		||||
    EventId, MilliSecondsSinceUnixEpoch, RoomVersionId,
 | 
			
		||||
};
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
use serde_json::from_str as from_json_str;
 | 
			
		||||
use tracing::{debug, info, trace, warn};
 | 
			
		||||
 | 
			
		||||
mod error;
 | 
			
		||||
pub mod event_auth;
 | 
			
		||||
mod power_levels;
 | 
			
		||||
pub mod room_version;
 | 
			
		||||
mod state_event;
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
@ -27,6 +27,7 @@ mod test_utils;
 | 
			
		||||
 | 
			
		||||
pub use error::{Error, Result};
 | 
			
		||||
pub use event_auth::{auth_check, auth_types_for_event};
 | 
			
		||||
use power_levels::PowerLevelsContentFields;
 | 
			
		||||
pub use room_version::RoomVersion;
 | 
			
		||||
pub use state_event::Event;
 | 
			
		||||
 | 
			
		||||
@ -335,18 +336,6 @@ where
 | 
			
		||||
    Ok(sorted)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
struct PowerLevelsContentFields {
 | 
			
		||||
    #[serde(
 | 
			
		||||
        default,
 | 
			
		||||
        deserialize_with = "ruma_common::serde::btreemap_deserialize_v1_powerlevel_values"
 | 
			
		||||
    )]
 | 
			
		||||
    users: BTreeMap<OwnedUserId, Int>,
 | 
			
		||||
 | 
			
		||||
    #[serde(default, deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel")]
 | 
			
		||||
    users_default: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Find the power level for the sender of `event_id` or return a default value of zero.
 | 
			
		||||
///
 | 
			
		||||
/// Do NOT use this any where but topological sort, we find the power level for the eventId
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										220
									
								
								crates/ruma-state-res/src/power_levels.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								crates/ruma-state-res/src/power_levels.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,220 @@
 | 
			
		||||
use std::collections::BTreeMap;
 | 
			
		||||
 | 
			
		||||
use js_int::Int;
 | 
			
		||||
use ruma_common::{
 | 
			
		||||
    events::{room::power_levels::RoomPowerLevelsEventContent, RoomEventType},
 | 
			
		||||
    power_levels::{default_power_level, NotificationPowerLevels},
 | 
			
		||||
    serde::{btreemap_deserialize_v1_powerlevel_values, deserialize_v1_powerlevel},
 | 
			
		||||
    OwnedUserId,
 | 
			
		||||
};
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
use serde_json::{from_str as from_json_str, Error};
 | 
			
		||||
use tracing::error;
 | 
			
		||||
 | 
			
		||||
use crate::RoomVersion;
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
struct IntRoomPowerLevelsEventContent {
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub ban: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub events: BTreeMap<RoomEventType, Int>,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub events_default: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub invite: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub kick: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub redact: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub state_default: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub users: BTreeMap<OwnedUserId, Int>,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub users_default: Int,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub notifications: IntNotificationPowerLevels,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IntRoomPowerLevelsEventContent> for RoomPowerLevelsEventContent {
 | 
			
		||||
    fn from(int_pl: IntRoomPowerLevelsEventContent) -> Self {
 | 
			
		||||
        let IntRoomPowerLevelsEventContent {
 | 
			
		||||
            ban,
 | 
			
		||||
            events,
 | 
			
		||||
            events_default,
 | 
			
		||||
            invite,
 | 
			
		||||
            kick,
 | 
			
		||||
            redact,
 | 
			
		||||
            state_default,
 | 
			
		||||
            users,
 | 
			
		||||
            users_default,
 | 
			
		||||
            notifications,
 | 
			
		||||
        } = int_pl;
 | 
			
		||||
 | 
			
		||||
        let mut pl = Self::new();
 | 
			
		||||
        pl.ban = ban;
 | 
			
		||||
        pl.events = events;
 | 
			
		||||
        pl.events_default = events_default;
 | 
			
		||||
        pl.invite = invite;
 | 
			
		||||
        pl.kick = kick;
 | 
			
		||||
        pl.redact = redact;
 | 
			
		||||
        pl.state_default = state_default;
 | 
			
		||||
        pl.users = users;
 | 
			
		||||
        pl.users_default = users_default;
 | 
			
		||||
        pl.notifications = notifications.into();
 | 
			
		||||
 | 
			
		||||
        pl
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
struct IntNotificationPowerLevels {
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    pub room: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for IntNotificationPowerLevels {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self { room: default_power_level() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IntNotificationPowerLevels> for NotificationPowerLevels {
 | 
			
		||||
    fn from(int_notif: IntNotificationPowerLevels) -> Self {
 | 
			
		||||
        let mut notif = Self::new();
 | 
			
		||||
        notif.room = int_notif.room;
 | 
			
		||||
 | 
			
		||||
        notif
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn deserialize_power_levels(
 | 
			
		||||
    content: &str,
 | 
			
		||||
    room_version: &RoomVersion,
 | 
			
		||||
) -> Option<RoomPowerLevelsEventContent> {
 | 
			
		||||
    if room_version.integer_power_levels {
 | 
			
		||||
        match from_json_str::<IntRoomPowerLevelsEventContent>(content) {
 | 
			
		||||
            Ok(content) => Some(content.into()),
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                error!("m.room.power_levels event is not valid with integer values");
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        match from_json_str(content) {
 | 
			
		||||
            Ok(content) => Some(content),
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                error!(
 | 
			
		||||
                    "m.room.power_levels event is not valid with integer or string integer values"
 | 
			
		||||
                );
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
pub(crate) struct PowerLevelsContentFields {
 | 
			
		||||
    #[serde(default, deserialize_with = "btreemap_deserialize_v1_powerlevel_values")]
 | 
			
		||||
    pub(crate) users: BTreeMap<OwnedUserId, Int>,
 | 
			
		||||
 | 
			
		||||
    #[serde(default, deserialize_with = "deserialize_v1_powerlevel")]
 | 
			
		||||
    pub(crate) users_default: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
struct IntPowerLevelsContentFields {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    users: BTreeMap<OwnedUserId, Int>,
 | 
			
		||||
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    users_default: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IntPowerLevelsContentFields> for PowerLevelsContentFields {
 | 
			
		||||
    fn from(pl: IntPowerLevelsContentFields) -> Self {
 | 
			
		||||
        let IntPowerLevelsContentFields { users, users_default } = pl;
 | 
			
		||||
        Self { users, users_default }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn deserialize_power_levels_content_fields(
 | 
			
		||||
    content: &str,
 | 
			
		||||
    room_version: &RoomVersion,
 | 
			
		||||
) -> Result<PowerLevelsContentFields, Error> {
 | 
			
		||||
    if room_version.integer_power_levels {
 | 
			
		||||
        from_json_str::<IntPowerLevelsContentFields>(content).map(|r| r.into())
 | 
			
		||||
    } else {
 | 
			
		||||
        from_json_str(content)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
pub(crate) struct PowerLevelsContentInvite {
 | 
			
		||||
    #[serde(default, deserialize_with = "deserialize_v1_powerlevel")]
 | 
			
		||||
    pub(crate) invite: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
struct IntPowerLevelsContentInvite {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    invite: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IntPowerLevelsContentInvite> for PowerLevelsContentInvite {
 | 
			
		||||
    fn from(pl: IntPowerLevelsContentInvite) -> Self {
 | 
			
		||||
        let IntPowerLevelsContentInvite { invite } = pl;
 | 
			
		||||
        Self { invite }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn deserialize_power_levels_content_invite(
 | 
			
		||||
    content: &str,
 | 
			
		||||
    room_version: &RoomVersion,
 | 
			
		||||
) -> Result<PowerLevelsContentInvite, Error> {
 | 
			
		||||
    if room_version.integer_power_levels {
 | 
			
		||||
        from_json_str::<IntPowerLevelsContentInvite>(content).map(|r| r.into())
 | 
			
		||||
    } else {
 | 
			
		||||
        from_json_str(content)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
pub(crate) struct PowerLevelsContentRedact {
 | 
			
		||||
    #[serde(default = "default_power_level", deserialize_with = "deserialize_v1_powerlevel")]
 | 
			
		||||
    pub(crate) redact: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
pub(crate) struct IntPowerLevelsContentRedact {
 | 
			
		||||
    #[serde(default = "default_power_level")]
 | 
			
		||||
    redact: Int,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IntPowerLevelsContentRedact> for PowerLevelsContentRedact {
 | 
			
		||||
    fn from(pl: IntPowerLevelsContentRedact) -> Self {
 | 
			
		||||
        let IntPowerLevelsContentRedact { redact } = pl;
 | 
			
		||||
        Self { redact }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn deserialize_power_levels_content_redact(
 | 
			
		||||
    content: &str,
 | 
			
		||||
    room_version: &RoomVersion,
 | 
			
		||||
) -> Result<PowerLevelsContentRedact, Error> {
 | 
			
		||||
    if room_version.integer_power_levels {
 | 
			
		||||
        from_json_str::<IntPowerLevelsContentRedact>(content).map(|r| r.into())
 | 
			
		||||
    } else {
 | 
			
		||||
        from_json_str(content)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user