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 serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
use crate::{room_version::RoomVersion, Error, Event, PowerLevelsContentFields, Result};
|
use crate::{
|
||||||
|
power_levels::{
|
||||||
mod int_power_levels;
|
deserialize_power_levels, deserialize_power_levels_content_fields,
|
||||||
|
deserialize_power_levels_content_invite, deserialize_power_levels_content_redact,
|
||||||
use int_power_levels::IntRoomPowerLevelsEventContent;
|
},
|
||||||
|
room_version::RoomVersion,
|
||||||
|
Error, Event, Result,
|
||||||
|
};
|
||||||
|
|
||||||
// FIXME: field extracting could be bundled for `content`
|
// FIXME: field extracting could be bundled for `content`
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -37,11 +40,6 @@ struct RoomMemberContentFields {
|
|||||||
join_authorised_via_users_server: Option<Raw<OwnedUserId>>,
|
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
|
/// For the given event `kind` what are the relevant auth events that are needed to authenticate
|
||||||
/// this `content`.
|
/// this `content`.
|
||||||
///
|
///
|
||||||
@ -337,15 +335,12 @@ pub fn auth_check<E: Event>(
|
|||||||
|
|
||||||
// If type is m.room.third_party_invite
|
// If type is m.room.third_party_invite
|
||||||
let sender_power_level = if let Some(pl) = &power_levels_event {
|
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) {
|
if let Some(level) = content.users.get(sender) {
|
||||||
*level
|
*level
|
||||||
} else {
|
} else {
|
||||||
content.users_default
|
content.users_default
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
int!(0) // TODO if this fails DB error?
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// If no power level event found the creator gets 100 everyone else gets 0
|
// If no power level event found the creator gets 100 everyone else gets 0
|
||||||
from_json_str::<RoomCreateEventContent>(room_create_event.content().get())
|
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 {
|
if *incoming_event.event_type() == RoomEventType::RoomThirdPartyInvite {
|
||||||
let invite_level = match &power_levels_event {
|
let invite_level = match &power_levels_event {
|
||||||
Some(power_levels) => {
|
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),
|
None => int!(0),
|
||||||
};
|
};
|
||||||
@ -408,15 +404,12 @@ pub fn auth_check<E: Event>(
|
|||||||
if room_version.extra_redaction_checks
|
if room_version.extra_redaction_checks
|
||||||
&& *incoming_event.event_type() == RoomEventType::RoomRedaction
|
&& *incoming_event.event_type() == RoomEventType::RoomRedaction
|
||||||
{
|
{
|
||||||
#[derive(Deserialize)]
|
let redact_level = match power_levels_event {
|
||||||
struct PowerLevelsContentRedact {
|
Some(pl) => {
|
||||||
redact: Int,
|
deserialize_power_levels_content_redact(pl.content().get(), room_version)?.redact
|
||||||
}
|
}
|
||||||
|
None => int!(50),
|
||||||
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));
|
|
||||||
|
|
||||||
if !check_redaction(room_version, incoming_event, sender_power_level, redact_level)? {
|
if !check_redaction(room_version, incoming_event, sender_power_level, redact_level)? {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
@ -500,12 +493,11 @@ fn valid_membership_change(
|
|||||||
// Is the authorised user allowed to invite users into this room
|
// Is the authorised user allowed to invite users into this room
|
||||||
let (auth_user_pl, invite_level) = if let Some(pl) = &power_levels_event {
|
let (auth_user_pl, invite_level) = if let Some(pl) = &power_levels_event {
|
||||||
// TODO Refactor all powerlevel parsing
|
// TODO Refactor all powerlevel parsing
|
||||||
let invite = match from_json_str::<PowerLevelsContentInvite>(pl.content().get()) {
|
let invite =
|
||||||
Ok(power_levels) => power_levels.invite,
|
deserialize_power_levels_content_invite(pl.content().get(), room_version)?.invite;
|
||||||
_ => int!(0),
|
|
||||||
};
|
|
||||||
|
|
||||||
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) {
|
let user_pl = if let Some(level) = content.users.get(user_for_join_auth) {
|
||||||
*level
|
*level
|
||||||
} else {
|
} else {
|
||||||
@ -513,9 +505,6 @@ fn valid_membership_change(
|
|||||||
};
|
};
|
||||||
|
|
||||||
(user_pl, invite)
|
(user_pl, invite)
|
||||||
} else {
|
|
||||||
(int!(0), invite)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
(int!(0), int!(0))
|
(int!(0), int!(0))
|
||||||
};
|
};
|
||||||
@ -877,31 +866,6 @@ fn check_power_levels(
|
|||||||
Some(true)
|
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(
|
fn get_deserialize_levels(
|
||||||
old: &serde_json::Value,
|
old: &serde_json::Value,
|
||||||
new: &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::{
|
use std::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
cmp::Reverse,
|
cmp::Reverse,
|
||||||
collections::{BTreeMap, BinaryHeap, HashMap, HashSet},
|
collections::{BinaryHeap, HashMap, HashSet},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12,14 +12,14 @@ use ruma_common::{
|
|||||||
room::member::{MembershipState, RoomMemberEventContent},
|
room::member::{MembershipState, RoomMemberEventContent},
|
||||||
RoomEventType, StateEventType,
|
RoomEventType, StateEventType,
|
||||||
},
|
},
|
||||||
EventId, MilliSecondsSinceUnixEpoch, OwnedUserId, RoomVersionId,
|
EventId, MilliSecondsSinceUnixEpoch, RoomVersionId,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
|
||||||
use serde_json::from_str as from_json_str;
|
use serde_json::from_str as from_json_str;
|
||||||
use tracing::{debug, info, trace, warn};
|
use tracing::{debug, info, trace, warn};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
pub mod event_auth;
|
pub mod event_auth;
|
||||||
|
mod power_levels;
|
||||||
pub mod room_version;
|
pub mod room_version;
|
||||||
mod state_event;
|
mod state_event;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -27,6 +27,7 @@ mod test_utils;
|
|||||||
|
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
pub use event_auth::{auth_check, auth_types_for_event};
|
pub use event_auth::{auth_check, auth_types_for_event};
|
||||||
|
use power_levels::PowerLevelsContentFields;
|
||||||
pub use room_version::RoomVersion;
|
pub use room_version::RoomVersion;
|
||||||
pub use state_event::Event;
|
pub use state_event::Event;
|
||||||
|
|
||||||
@ -335,18 +336,6 @@ where
|
|||||||
Ok(sorted)
|
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.
|
/// 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
|
/// 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