mirror of
https://github.com/mikedilger/chorus.git
synced 2026-04-03 06:41:16 +00:00
Consistently use store from GLOBALS (fixes a chorus_moderate bug too)
This commit is contained in:
parent
4e5d7ef9fe
commit
ba7f22dfd3
@ -28,8 +28,7 @@ async fn main() -> Result<(), Error> {
|
|||||||
// Log host name
|
// Log host name
|
||||||
log::info!(target: "Server", "HOSTNAME = {}", config.hostname);
|
log::info!(target: "Server", "HOSTNAME = {}", config.hostname);
|
||||||
|
|
||||||
let store = chorus::setup_store(&config)?;
|
chorus::setup_store(&config)?;
|
||||||
let _ = GLOBALS.store.set(store);
|
|
||||||
|
|
||||||
if let Some(ref blossom_directory) = config.blossom_directory {
|
if let Some(ref blossom_directory) = config.blossom_directory {
|
||||||
let filestore = chorus::filestore::FileStore::new(blossom_directory).await?;
|
let filestore = chorus::filestore::FileStore::new(blossom_directory).await?;
|
||||||
@ -101,7 +100,7 @@ async fn main() -> Result<(), Error> {
|
|||||||
if ! GLOBALS.config.read().chorus_is_behind_a_proxy
|
if ! GLOBALS.config.read().chorus_is_behind_a_proxy
|
||||||
&& GLOBALS.config.read().enable_ip_blocking
|
&& GLOBALS.config.read().enable_ip_blocking
|
||||||
{
|
{
|
||||||
let ip_data = chorus::get_ip_data(GLOBALS.store.get().unwrap(), hashed_peer.ip())?;
|
let ip_data = chorus::get_ip_data(hashed_peer.ip())?;
|
||||||
if ip_data.is_banned() {
|
if ip_data.is_banned() {
|
||||||
log::debug!(target: "Client",
|
log::debug!(target: "Client",
|
||||||
"{}: Blocking reconnection until {}",
|
"{}: Blocking reconnection until {}",
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use chorus::error::{ChorusError, Error};
|
use chorus::error::{ChorusError, Error};
|
||||||
|
use chorus::globals::GLOBALS;
|
||||||
use pocket_db::ScreenResult;
|
use pocket_db::ScreenResult;
|
||||||
use pocket_types::{Filter, Id, Pubkey, Tags};
|
use pocket_types::{Filter, Id, Pubkey, Tags};
|
||||||
use std::env;
|
use std::env;
|
||||||
@ -21,11 +22,8 @@ fn main() -> Result<(), Error> {
|
|||||||
// Force allow of scraping (this program is a scraper)
|
// Force allow of scraping (this program is a scraper)
|
||||||
config.allow_scraping = true;
|
config.allow_scraping = true;
|
||||||
|
|
||||||
// Setup store
|
|
||||||
let store = chorus::setup_store(&config)?;
|
|
||||||
|
|
||||||
// Setup logging
|
|
||||||
chorus::setup_logging(&config);
|
chorus::setup_logging(&config);
|
||||||
|
chorus::setup_store(&config)?;
|
||||||
|
|
||||||
// Handle command
|
// Handle command
|
||||||
let command = args
|
let command = args
|
||||||
@ -37,7 +35,7 @@ fn main() -> Result<(), Error> {
|
|||||||
.next()
|
.next()
|
||||||
.ok_or::<Error>(ChorusError::General("ID argument missing".to_owned()).into())?;
|
.ok_or::<Error>(ChorusError::General("ID argument missing".to_owned()).into())?;
|
||||||
let id: Id = Id::read_hex(idstr.as_bytes())?;
|
let id: Id = Id::read_hex(idstr.as_bytes())?;
|
||||||
store.remove_event(id)?;
|
GLOBALS.store.get().unwrap().remove_event(id)?;
|
||||||
println!("Done.");
|
println!("Done.");
|
||||||
}
|
}
|
||||||
"delete_by_pubkey" => {
|
"delete_by_pubkey" => {
|
||||||
@ -52,9 +50,13 @@ fn main() -> Result<(), Error> {
|
|||||||
let filter =
|
let filter =
|
||||||
Filter::from_parts(&[], &[pk], &[], tags, None, None, None, &mut filter_buffer)?;
|
Filter::from_parts(&[], &[pk], &[], tags, None, None, None, &mut filter_buffer)?;
|
||||||
let (events, _redacted) =
|
let (events, _redacted) =
|
||||||
store.find_events(filter, true, 0, 0, |_| ScreenResult::Match)?;
|
GLOBALS
|
||||||
|
.store
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.find_events(filter, true, 0, 0, |_| ScreenResult::Match)?;
|
||||||
for event in events.iter() {
|
for event in events.iter() {
|
||||||
store.remove_event(event.id())?;
|
GLOBALS.store.get().unwrap().remove_event(event.id())?;
|
||||||
}
|
}
|
||||||
println!("Done.");
|
println!("Done.");
|
||||||
}
|
}
|
||||||
@ -63,14 +65,14 @@ fn main() -> Result<(), Error> {
|
|||||||
.next()
|
.next()
|
||||||
.ok_or::<Error>(ChorusError::General("ID argument missing".to_owned()).into())?;
|
.ok_or::<Error>(ChorusError::General("ID argument missing".to_owned()).into())?;
|
||||||
let id: Id = Id::read_hex(idstr.as_bytes())?;
|
let id: Id = Id::read_hex(idstr.as_bytes())?;
|
||||||
if let Some(event) = store.get_event_by_id(id)? {
|
if let Some(event) = GLOBALS.store.get().unwrap().get_event_by_id(id)? {
|
||||||
println!("{event}");
|
println!("{event}");
|
||||||
} else {
|
} else {
|
||||||
println!("Not found.");
|
println!("Not found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"dump_users" => {
|
"dump_users" => {
|
||||||
let users = chorus::dump_authorized_users(&store)?;
|
let users = chorus::dump_authorized_users()?;
|
||||||
for (pubkey, moderator) in users.iter() {
|
for (pubkey, moderator) in users.iter() {
|
||||||
println!("{} {}", pubkey, if *moderator { "moderator" } else { "" });
|
println!("{} {}", pubkey, if *moderator { "moderator" } else { "" });
|
||||||
}
|
}
|
||||||
@ -86,7 +88,7 @@ fn main() -> Result<(), Error> {
|
|||||||
)?;
|
)?;
|
||||||
let moderator: bool = moderator == "1";
|
let moderator: bool = moderator == "1";
|
||||||
|
|
||||||
chorus::add_authorized_user(&store, pk, moderator)?;
|
chorus::add_authorized_user(pk, moderator)?;
|
||||||
}
|
}
|
||||||
"rm_user" => {
|
"rm_user" => {
|
||||||
let pubstr = args.next().ok_or::<Error>(
|
let pubstr = args.next().ok_or::<Error>(
|
||||||
@ -94,7 +96,7 @@ fn main() -> Result<(), Error> {
|
|||||||
)?;
|
)?;
|
||||||
let pk: Pubkey = Pubkey::read_hex(pubstr.as_bytes())?;
|
let pk: Pubkey = Pubkey::read_hex(pubstr.as_bytes())?;
|
||||||
|
|
||||||
chorus::rm_authorized_user(&store, pk)?;
|
chorus::rm_authorized_user(pk)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ChorusError::General("Unknown command.".to_owned()).into());
|
return Err(ChorusError::General("Unknown command.".to_owned()).into());
|
||||||
|
|||||||
@ -19,12 +19,14 @@ fn main() -> Result<(), Error> {
|
|||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
let _ = stdin.lock().lines().next().unwrap().unwrap();
|
let _ = stdin.lock().lines().next().unwrap().unwrap();
|
||||||
|
|
||||||
let store = chorus::setup_store(&config)?;
|
let store = chorus::setup_store_and_return(&config)?;
|
||||||
|
|
||||||
let pre_stats = store.stats()?;
|
let pre_stats = store.stats()?;
|
||||||
println!("{:?}", pre_stats);
|
println!("{:?}", pre_stats);
|
||||||
|
|
||||||
let store = unsafe { store.rebuild()? };
|
let new_store = unsafe { store.rebuild()? };
|
||||||
let post_stats = store.stats()?;
|
|
||||||
|
let post_stats = new_store.stats()?;
|
||||||
println!("{:?}", post_stats);
|
println!("{:?}", post_stats);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use chorus::error::Error;
|
use chorus::error::Error;
|
||||||
|
use chorus::globals::GLOBALS;
|
||||||
use pocket_db::ScreenResult;
|
use pocket_db::ScreenResult;
|
||||||
use pocket_types::{Event, Filter};
|
use pocket_types::{Event, Filter};
|
||||||
use std::env;
|
use std::env;
|
||||||
@ -18,15 +19,13 @@ fn main() -> Result<(), Error> {
|
|||||||
config.allow_scraping = true;
|
config.allow_scraping = true;
|
||||||
|
|
||||||
chorus::setup_logging(&config);
|
chorus::setup_logging(&config);
|
||||||
|
chorus::setup_store(&config)?;
|
||||||
// Setup store
|
|
||||||
let store = chorus::setup_store(&config)?;
|
|
||||||
|
|
||||||
let mut buffer: [u8; 128] = [0; 128];
|
let mut buffer: [u8; 128] = [0; 128];
|
||||||
let (_incount, _outcount, filter) = Filter::from_json(b"{}", &mut buffer)?;
|
let (_incount, _outcount, filter) = Filter::from_json(b"{}", &mut buffer)?;
|
||||||
let screen = |_: &Event| -> ScreenResult { ScreenResult::Match };
|
let screen = |_: &Event| -> ScreenResult { ScreenResult::Match };
|
||||||
|
|
||||||
let (mut events, _redacted) = store.find_events(
|
let (mut events, _redacted) = GLOBALS.store.get().unwrap().find_events(
|
||||||
filter,
|
filter,
|
||||||
config.allow_scraping,
|
config.allow_scraping,
|
||||||
config.allow_scrape_if_limited_to,
|
config.allow_scrape_if_limited_to,
|
||||||
|
|||||||
@ -16,15 +16,13 @@ fn main() -> Result<(), Error> {
|
|||||||
config.allow_scraping = true;
|
config.allow_scraping = true;
|
||||||
|
|
||||||
chorus::setup_logging(&config);
|
chorus::setup_logging(&config);
|
||||||
|
chorus::setup_store(&config)?;
|
||||||
|
|
||||||
// Setup store
|
for (id, approved) in chorus::dump_event_approvals()? {
|
||||||
let store = chorus::setup_store(&config)?;
|
|
||||||
|
|
||||||
for (id, approved) in chorus::dump_event_approvals(&store)? {
|
|
||||||
println!("ID {} = {}", id, approved);
|
println!("ID {} = {}", id, approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pubkey, approved) in chorus::dump_pubkey_approvals(&store)? {
|
for (pubkey, approved) in chorus::dump_pubkey_approvals()? {
|
||||||
println!("PUBKEY {} = {}", pubkey, approved);
|
println!("PUBKEY {} = {}", pubkey, approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use chorus::error::Error;
|
use chorus::error::Error;
|
||||||
|
use chorus::globals::GLOBALS;
|
||||||
use pocket_db::ScreenResult;
|
use pocket_db::ScreenResult;
|
||||||
use pocket_types::{Event, Filter, Kind};
|
use pocket_types::{Event, Filter, Kind};
|
||||||
use std::env;
|
use std::env;
|
||||||
@ -30,13 +31,13 @@ fn main() -> Result<(), Error> {
|
|||||||
Kind::from(7), // Reaction
|
Kind::from(7), // Reaction
|
||||||
];
|
];
|
||||||
|
|
||||||
let store = chorus::setup_store(&config)?;
|
chorus::setup_store(&config)?;
|
||||||
|
|
||||||
let mut buffer: [u8; 128] = [0; 128];
|
let mut buffer: [u8; 128] = [0; 128];
|
||||||
let (_incount, _outcount, filter) = Filter::from_json(b"{}", &mut buffer)?;
|
let (_incount, _outcount, filter) = Filter::from_json(b"{}", &mut buffer)?;
|
||||||
let screen = |_: &Event| -> ScreenResult { ScreenResult::Match };
|
let screen = |_: &Event| -> ScreenResult { ScreenResult::Match };
|
||||||
|
|
||||||
let (mut events, _redacted) = store.find_events(
|
let (mut events, _redacted) = GLOBALS.store.get().unwrap().find_events(
|
||||||
filter,
|
filter,
|
||||||
config.allow_scraping,
|
config.allow_scraping,
|
||||||
config.allow_scrape_if_limited_to,
|
config.allow_scrape_if_limited_to,
|
||||||
@ -68,27 +69,18 @@ fn main() -> Result<(), Error> {
|
|||||||
//println!("{s}");
|
//println!("{s}");
|
||||||
|
|
||||||
// Skip if event marked approved
|
// Skip if event marked approved
|
||||||
if matches!(
|
if matches!(chorus::get_event_approval(event.id()), Ok(Some(true))) {
|
||||||
chorus::get_event_approval(&store, event.id()),
|
|
||||||
Ok(Some(true))
|
|
||||||
) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip if pubkey marked approved
|
// Skip if pubkey marked approved
|
||||||
if matches!(
|
if matches!(chorus::get_pubkey_approval(event.pubkey()), Ok(Some(true))) {
|
||||||
chorus::get_pubkey_approval(&store, event.pubkey()),
|
|
||||||
Ok(Some(true))
|
|
||||||
) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete if pubkey marked banned
|
// Delete if pubkey marked banned
|
||||||
if matches!(
|
if matches!(chorus::get_pubkey_approval(event.pubkey()), Ok(Some(false))) {
|
||||||
chorus::get_pubkey_approval(&store, event.pubkey()),
|
GLOBALS.store.get().unwrap().remove_event(event.id())?;
|
||||||
Ok(Some(false))
|
|
||||||
) {
|
|
||||||
store.remove_event(event.id())?;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,24 +103,24 @@ fn main() -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
match input.bytes().next().unwrap() {
|
match input.bytes().next().unwrap() {
|
||||||
b'p' => {
|
b'p' => {
|
||||||
chorus::mark_pubkey_approval(&store, event.pubkey(), true)?;
|
chorus::mark_pubkey_approval(event.pubkey(), true)?;
|
||||||
println!("User approved.");
|
println!("User approved.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
b'P' => {
|
b'P' => {
|
||||||
chorus::mark_pubkey_approval(&store, event.pubkey(), false)?;
|
chorus::mark_pubkey_approval(event.pubkey(), false)?;
|
||||||
store.remove_event(event.id())?;
|
GLOBALS.store.get().unwrap().remove_event(event.id())?;
|
||||||
println!("User banned.");
|
println!("User banned.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
b'i' => {
|
b'i' => {
|
||||||
chorus::mark_event_approval(&store, event.id(), true)?;
|
chorus::mark_event_approval(event.id(), true)?;
|
||||||
println!("Event approved.");
|
println!("Event approved.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
b'I' => {
|
b'I' => {
|
||||||
chorus::mark_event_approval(&store, event.id(), false)?;
|
chorus::mark_event_approval(event.id(), false)?;
|
||||||
store.remove_event(event.id())?;
|
GLOBALS.store.get().unwrap().remove_event(event.id())?;
|
||||||
println!("Event banned.");
|
println!("Event banned.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
68
src/lib.rs
68
src/lib.rs
@ -118,9 +118,7 @@ impl Service<Request<Incoming>> for ChorusService {
|
|||||||
|
|
||||||
// Possibly IP block late (if behind a proxy)
|
// Possibly IP block late (if behind a proxy)
|
||||||
if GLOBALS.config.read().enable_ip_blocking {
|
if GLOBALS.config.read().enable_ip_blocking {
|
||||||
if let Ok(ip_data) =
|
if let Ok(ip_data) = crate::get_ip_data(hashed_peer.ip()) {
|
||||||
crate::get_ip_data(GLOBALS.store.get().unwrap(), hashed_peer.ip())
|
|
||||||
{
|
|
||||||
if ip_data.is_banned() {
|
if ip_data.is_banned() {
|
||||||
log::debug!(target: "Client",
|
log::debug!(target: "Client",
|
||||||
"{}: Blocking reconnection until {}",
|
"{}: Blocking reconnection until {}",
|
||||||
@ -324,10 +322,10 @@ async fn websocket_thread(peer: HashedPeer, websocket: HyperWebsocket, origin: S
|
|||||||
let minimum_ban_seconds = GLOBALS.config.read().minimum_ban_seconds;
|
let minimum_ban_seconds = GLOBALS.config.read().minimum_ban_seconds;
|
||||||
let ban_seconds = if GLOBALS.config.read().enable_ip_blocking {
|
let ban_seconds = if GLOBALS.config.read().enable_ip_blocking {
|
||||||
let mut ban_seconds = 0;
|
let mut ban_seconds = 0;
|
||||||
if let Ok(mut ip_data) = get_ip_data(GLOBALS.store.get().unwrap(), peer.ip()) {
|
if let Ok(mut ip_data) = get_ip_data(peer.ip()) {
|
||||||
ban_seconds =
|
ban_seconds =
|
||||||
ip_data.update_on_session_close(session_exit, minimum_ban_seconds);
|
ip_data.update_on_session_close(session_exit, minimum_ban_seconds);
|
||||||
let _ = update_ip_data(GLOBALS.store.get().unwrap(), peer.ip(), &ip_data);
|
let _ = update_ip_data(peer.ip(), &ip_data);
|
||||||
}
|
}
|
||||||
ban_seconds
|
ban_seconds
|
||||||
} else {
|
} else {
|
||||||
@ -672,7 +670,14 @@ pub fn setup_logging(config: &Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Setup storage
|
/// Setup storage
|
||||||
pub fn setup_store(config: &Config) -> Result<Store, Error> {
|
pub fn setup_store(config: &Config) -> Result<(), Error> {
|
||||||
|
let store = setup_store_and_return(config)?;
|
||||||
|
let _ = GLOBALS.store.set(store);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Setup storage and return it
|
||||||
|
pub fn setup_store_and_return(config: &Config) -> Result<Store, Error> {
|
||||||
let store = Store::new(
|
let store = Store::new(
|
||||||
&config.data_directory,
|
&config.data_directory,
|
||||||
vec![
|
vec![
|
||||||
@ -686,7 +691,8 @@ pub fn setup_store(config: &Config) -> Result<Store, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get IpData from storage about this remote HashedIp
|
/// Get IpData from storage about this remote HashedIp
|
||||||
pub fn get_ip_data(store: &Store, ip: HashedIp) -> Result<IpData, Error> {
|
pub fn get_ip_data(ip: HashedIp) -> Result<IpData, Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let ip_data = store
|
let ip_data = store
|
||||||
.extra_table("ip_data")
|
.extra_table("ip_data")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable("ip_data")))?;
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable("ip_data")))?;
|
||||||
@ -700,7 +706,8 @@ pub fn get_ip_data(store: &Store, ip: HashedIp) -> Result<IpData, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get IpData in storage about this remote HashedIp
|
/// Get IpData in storage about this remote HashedIp
|
||||||
pub fn update_ip_data(store: &Store, ip: HashedIp, data: &IpData) -> Result<(), Error> {
|
pub fn update_ip_data(ip: HashedIp, data: &IpData) -> Result<(), Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let ip_data = store
|
let ip_data = store
|
||||||
.extra_table("ip_data")
|
.extra_table("ip_data")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable("ip_data")))?;
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable("ip_data")))?;
|
||||||
@ -713,7 +720,8 @@ pub fn update_ip_data(store: &Store, ip: HashedIp, data: &IpData) -> Result<(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Dump all IpData from storage
|
/// Dump all IpData from storage
|
||||||
pub fn dump_ip_data(store: &Store) -> Result<Vec<(HashedIp, IpData)>, Error> {
|
pub fn dump_ip_data() -> Result<Vec<(HashedIp, IpData)>, Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let ip_data = store
|
let ip_data = store
|
||||||
.extra_table("ip_data")
|
.extra_table("ip_data")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable("ip_data")))?;
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable("ip_data")))?;
|
||||||
@ -729,7 +737,8 @@ pub fn dump_ip_data(store: &Store) -> Result<Vec<(HashedIp, IpData)>, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Mark an event as approved or not
|
/// Mark an event as approved or not
|
||||||
pub fn mark_event_approval(store: &Store, id: Id, approval: bool) -> Result<(), Error> {
|
pub fn mark_event_approval(id: Id, approval: bool) -> Result<(), Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let approved_events = store
|
let approved_events = store
|
||||||
.extra_table("approved-events")
|
.extra_table("approved-events")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
||||||
@ -742,7 +751,8 @@ pub fn mark_event_approval(store: &Store, id: Id, approval: bool) -> Result<(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Clear an event approval status
|
/// Clear an event approval status
|
||||||
pub fn clear_event_approval(store: &Store, id: Id) -> Result<(), Error> {
|
pub fn clear_event_approval(id: Id) -> Result<(), Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let approved_events = store
|
let approved_events = store
|
||||||
.extra_table("approved-events")
|
.extra_table("approved-events")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
||||||
@ -755,7 +765,8 @@ pub fn clear_event_approval(store: &Store, id: Id) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch an event approval status
|
/// Fetch an event approval status
|
||||||
pub fn get_event_approval(store: &Store, id: Id) -> Result<Option<bool>, Error> {
|
pub fn get_event_approval(id: Id) -> Result<Option<bool>, Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let approved_events = store
|
let approved_events = store
|
||||||
.extra_table("approved-events")
|
.extra_table("approved-events")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
||||||
@ -768,7 +779,8 @@ pub fn get_event_approval(store: &Store, id: Id) -> Result<Option<bool>, Error>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Dump all event approval statuses
|
/// Dump all event approval statuses
|
||||||
pub fn dump_event_approvals(store: &Store) -> Result<Vec<(Id, bool)>, Error> {
|
pub fn dump_event_approvals() -> Result<Vec<(Id, bool)>, Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let mut output: Vec<(Id, bool)> = Vec::new();
|
let mut output: Vec<(Id, bool)> = Vec::new();
|
||||||
let approved_events = store
|
let approved_events = store
|
||||||
.extra_table("approved-events")
|
.extra_table("approved-events")
|
||||||
@ -786,7 +798,8 @@ pub fn dump_event_approvals(store: &Store) -> Result<Vec<(Id, bool)>, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Mark a pubkey as approved or not
|
/// Mark a pubkey as approved or not
|
||||||
pub fn mark_pubkey_approval(store: &Store, pubkey: Pubkey, approval: bool) -> Result<(), Error> {
|
pub fn mark_pubkey_approval(pubkey: Pubkey, approval: bool) -> Result<(), Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let approved_pubkeys = store
|
let approved_pubkeys = store
|
||||||
.extra_table("approved-pubkeys")
|
.extra_table("approved-pubkeys")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
||||||
@ -799,7 +812,8 @@ pub fn mark_pubkey_approval(store: &Store, pubkey: Pubkey, approval: bool) -> Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Clear a pubkey approval status
|
/// Clear a pubkey approval status
|
||||||
pub fn clear_pubkey_approval(store: &Store, pubkey: Pubkey) -> Result<(), Error> {
|
pub fn clear_pubkey_approval(pubkey: Pubkey) -> Result<(), Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let approved_pubkeys = store
|
let approved_pubkeys = store
|
||||||
.extra_table("approved-pubkeys")
|
.extra_table("approved-pubkeys")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
||||||
@ -812,7 +826,8 @@ pub fn clear_pubkey_approval(store: &Store, pubkey: Pubkey) -> Result<(), Error>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch a pubkey approval status
|
/// Fetch a pubkey approval status
|
||||||
pub fn get_pubkey_approval(store: &Store, pubkey: Pubkey) -> Result<Option<bool>, Error> {
|
pub fn get_pubkey_approval(pubkey: Pubkey) -> Result<Option<bool>, Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let approved_pubkeys = store
|
let approved_pubkeys = store
|
||||||
.extra_table("approved-pubkeys")
|
.extra_table("approved-pubkeys")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable(
|
||||||
@ -825,7 +840,8 @@ pub fn get_pubkey_approval(store: &Store, pubkey: Pubkey) -> Result<Option<bool>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Dump all pubkey approval statuses
|
/// Dump all pubkey approval statuses
|
||||||
pub fn dump_pubkey_approvals(store: &Store) -> Result<Vec<(Pubkey, bool)>, Error> {
|
pub fn dump_pubkey_approvals() -> Result<Vec<(Pubkey, bool)>, Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let mut output: Vec<(Pubkey, bool)> = Vec::new();
|
let mut output: Vec<(Pubkey, bool)> = Vec::new();
|
||||||
let approved_pubkeys = store
|
let approved_pubkeys = store
|
||||||
.extra_table("approved-pubkeys")
|
.extra_table("approved-pubkeys")
|
||||||
@ -843,7 +859,8 @@ pub fn dump_pubkey_approvals(store: &Store) -> Result<Vec<(Pubkey, bool)>, Error
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add authorized user (or change moderator flag)
|
/// Add authorized user (or change moderator flag)
|
||||||
pub fn add_authorized_user(store: &Store, pubkey: Pubkey, moderator: bool) -> Result<(), Error> {
|
pub fn add_authorized_user(pubkey: Pubkey, moderator: bool) -> Result<(), Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let users = store
|
let users = store
|
||||||
.extra_table("users")
|
.extra_table("users")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable("users")))?;
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable("users")))?;
|
||||||
@ -854,7 +871,8 @@ pub fn add_authorized_user(store: &Store, pubkey: Pubkey, moderator: bool) -> Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remove authorized user
|
/// Remove authorized user
|
||||||
pub fn rm_authorized_user(store: &Store, pubkey: Pubkey) -> Result<(), Error> {
|
pub fn rm_authorized_user(pubkey: Pubkey) -> Result<(), Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let users = store
|
let users = store
|
||||||
.extra_table("users")
|
.extra_table("users")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable("users")))?;
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable("users")))?;
|
||||||
@ -865,7 +883,8 @@ pub fn rm_authorized_user(store: &Store, pubkey: Pubkey) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get authorized user
|
/// Get authorized user
|
||||||
pub fn get_authorized_user(store: &Store, pubkey: Pubkey) -> Result<Option<bool>, Error> {
|
pub fn get_authorized_user(pubkey: Pubkey) -> Result<Option<bool>, Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let users = store
|
let users = store
|
||||||
.extra_table("users")
|
.extra_table("users")
|
||||||
.ok_or(Into::<Error>::into(ChorusError::MissingTable("users")))?;
|
.ok_or(Into::<Error>::into(ChorusError::MissingTable("users")))?;
|
||||||
@ -876,7 +895,8 @@ pub fn get_authorized_user(store: &Store, pubkey: Pubkey) -> Result<Option<bool>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Dump all authorized users
|
/// Dump all authorized users
|
||||||
pub fn dump_authorized_users(store: &Store) -> Result<Vec<(Pubkey, bool)>, Error> {
|
pub fn dump_authorized_users() -> Result<Vec<(Pubkey, bool)>, Error> {
|
||||||
|
let store = GLOBALS.store.get().unwrap();
|
||||||
let mut output: Vec<(Pubkey, bool)> = Vec::new();
|
let mut output: Vec<(Pubkey, bool)> = Vec::new();
|
||||||
let users = store
|
let users = store
|
||||||
.extra_table("users")
|
.extra_table("users")
|
||||||
@ -893,8 +913,7 @@ pub fn dump_authorized_users(store: &Store) -> Result<Vec<(Pubkey, bool)>, Error
|
|||||||
|
|
||||||
/// Is the pubkey an authorized user?
|
/// Is the pubkey an authorized user?
|
||||||
pub fn is_authorized_user(pubkey: Pubkey) -> bool {
|
pub fn is_authorized_user(pubkey: Pubkey) -> bool {
|
||||||
let store = GLOBALS.store.get().unwrap();
|
match get_authorized_user(pubkey) {
|
||||||
match get_authorized_user(store, pubkey) {
|
|
||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
Ok(None) => false,
|
Ok(None) => false,
|
||||||
Ok(Some(_)) => true,
|
Ok(Some(_)) => true,
|
||||||
@ -903,8 +922,7 @@ pub fn is_authorized_user(pubkey: Pubkey) -> bool {
|
|||||||
|
|
||||||
/// Is the pubkey a moderator?
|
/// Is the pubkey a moderator?
|
||||||
pub fn is_moderator(pubkey: Pubkey) -> bool {
|
pub fn is_moderator(pubkey: Pubkey) -> bool {
|
||||||
let store = GLOBALS.store.get().unwrap();
|
match get_authorized_user(pubkey) {
|
||||||
match get_authorized_user(store, pubkey) {
|
|
||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
Ok(None) => false,
|
Ok(None) => false,
|
||||||
Ok(Some(moderator)) => moderator,
|
Ok(Some(moderator)) => moderator,
|
||||||
|
|||||||
14
src/nostr.rs
14
src/nostr.rs
@ -335,13 +335,11 @@ impl WebSocketService {
|
|||||||
// Handle Request to Vanish events
|
// Handle Request to Vanish events
|
||||||
if event.kind() == Kind::from(62) {
|
if event.kind() == Kind::from(62) {
|
||||||
if let Ok(true) = verify_relay_tag(event, true) {
|
if let Ok(true) = verify_relay_tag(event, true) {
|
||||||
let store = GLOBALS.store.get().unwrap();
|
|
||||||
|
|
||||||
// Erase their events (and giftwraps to them)
|
// Erase their events (and giftwraps to them)
|
||||||
store.vanish(event)?;
|
GLOBALS.store.get().unwrap().vanish(event)?;
|
||||||
|
|
||||||
// Add their pubkey to the blocklist so their events cannot come back
|
// Add their pubkey to the blocklist so their events cannot come back
|
||||||
crate::mark_pubkey_approval(store, event.pubkey(), false)?;
|
crate::mark_pubkey_approval(event.pubkey(), false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -731,12 +729,12 @@ async fn screen_incoming_event(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reject if event approval is false
|
// Reject if event approval is false
|
||||||
if let Some(false) = crate::get_event_approval(GLOBALS.store.get().unwrap(), event.id())? {
|
if let Some(false) = crate::get_event_approval(event.id())? {
|
||||||
return Err(ChorusError::BannedEvent.into());
|
return Err(ChorusError::BannedEvent.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject if pubkey approval is false
|
// Reject if pubkey approval is false
|
||||||
if let Some(false) = crate::get_pubkey_approval(GLOBALS.store.get().unwrap(), event.pubkey())? {
|
if let Some(false) = crate::get_pubkey_approval(event.pubkey())? {
|
||||||
return Err(ChorusError::BannedUser.into());
|
return Err(ChorusError::BannedUser.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,8 +812,8 @@ pub fn screen_outgoing_event(
|
|||||||
return ScreenResult::Mismatch;
|
return ScreenResult::Mismatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
let event_approval = crate::get_event_approval(GLOBALS.store.get().unwrap(), event.id());
|
let event_approval = crate::get_event_approval(event.id());
|
||||||
let pubkey_approval = crate::get_pubkey_approval(GLOBALS.store.get().unwrap(), event.pubkey());
|
let pubkey_approval = crate::get_pubkey_approval(event.pubkey());
|
||||||
|
|
||||||
// Deny if it is marked approval:false (event or pubkey)
|
// Deny if it is marked approval:false (event or pubkey)
|
||||||
// (even for authorized users)
|
// (even for authorized users)
|
||||||
|
|||||||
@ -191,18 +191,12 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
|
|
||||||
for event in events.drain(..) {
|
for event in events.drain(..) {
|
||||||
// Skip if pubkey marked (either banned or approved)
|
// Skip if pubkey marked (either banned or approved)
|
||||||
if matches!(
|
if matches!(crate::get_pubkey_approval(event.pubkey()), Ok(Some(_))) {
|
||||||
crate::get_pubkey_approval(GLOBALS.store.get().unwrap(), event.pubkey()),
|
|
||||||
Ok(Some(_))
|
|
||||||
) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip if event marked (either banned or approved)
|
// Skip if event marked (either banned or approved)
|
||||||
if matches!(
|
if matches!(crate::get_event_approval(event.id()), Ok(Some(_))) {
|
||||||
crate::get_event_approval(GLOBALS.store.get().unwrap(), event.id()),
|
|
||||||
Ok(Some(_))
|
|
||||||
) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,17 +212,17 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
}
|
}
|
||||||
"allowevent" => {
|
"allowevent" => {
|
||||||
let id = get_id_param(obj)?;
|
let id = get_id_param(obj)?;
|
||||||
crate::mark_event_approval(GLOBALS.store.get().unwrap(), id, true)?;
|
crate::mark_event_approval(id, true)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
"banevent" => {
|
"banevent" => {
|
||||||
let id = get_id_param(obj)?;
|
let id = get_id_param(obj)?;
|
||||||
crate::mark_event_approval(GLOBALS.store.get().unwrap(), id, false)?;
|
crate::mark_event_approval(id, false)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
"clearevent" => {
|
"clearevent" => {
|
||||||
let id = get_id_param(obj)?;
|
let id = get_id_param(obj)?;
|
||||||
crate::clear_event_approval(GLOBALS.store.get().unwrap(), id)?;
|
crate::clear_event_approval(id)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
"removeevent" => {
|
"removeevent" => {
|
||||||
@ -239,22 +233,22 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
|
|
||||||
"allowpubkey" => {
|
"allowpubkey" => {
|
||||||
let pk = get_pubkey_param(obj)?;
|
let pk = get_pubkey_param(obj)?;
|
||||||
crate::mark_pubkey_approval(GLOBALS.store.get().unwrap(), pk, true)?;
|
crate::mark_pubkey_approval(pk, true)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
"banpubkey" => {
|
"banpubkey" => {
|
||||||
let pk = get_pubkey_param(obj)?;
|
let pk = get_pubkey_param(obj)?;
|
||||||
crate::mark_pubkey_approval(GLOBALS.store.get().unwrap(), pk, false)?;
|
crate::mark_pubkey_approval(pk, false)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
"clearpubkey" => {
|
"clearpubkey" => {
|
||||||
let pk = get_pubkey_param(obj)?;
|
let pk = get_pubkey_param(obj)?;
|
||||||
crate::clear_pubkey_approval(GLOBALS.store.get().unwrap(), pk)?;
|
crate::clear_pubkey_approval(pk)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
"listallowedevents" => {
|
"listallowedevents" => {
|
||||||
let approvals = crate::dump_event_approvals(GLOBALS.store.get().unwrap())?;
|
let approvals = crate::dump_event_approvals()?;
|
||||||
let ids: Vec<EventResult> = approvals
|
let ids: Vec<EventResult> = approvals
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(id, appr)| {
|
.filter_map(|(id, appr)| {
|
||||||
@ -273,7 +267,7 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"listbannedevents" => {
|
"listbannedevents" => {
|
||||||
let approvals = crate::dump_event_approvals(GLOBALS.store.get().unwrap())?;
|
let approvals = crate::dump_event_approvals()?;
|
||||||
let ids: Vec<EventResult> = approvals
|
let ids: Vec<EventResult> = approvals
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(id, appr)| {
|
.filter_map(|(id, appr)| {
|
||||||
@ -292,17 +286,15 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"listbannedevents2" => {
|
"listbannedevents2" => {
|
||||||
let approvals = crate::dump_event_approvals(GLOBALS.store.get().unwrap())?;
|
let approvals = crate::dump_event_approvals()?;
|
||||||
let mut results: Vec<FullEventResult> = Vec::new();
|
let mut results: Vec<FullEventResult> = Vec::new();
|
||||||
for (id, appr) in approvals.iter() {
|
for (id, appr) in approvals.iter() {
|
||||||
if ! *appr {
|
if !*appr {
|
||||||
if let Some(event) = GLOBALS.store.get().unwrap().get_event_by_id(*id)? {
|
if let Some(event) = GLOBALS.store.get().unwrap().get_event_by_id(*id)? {
|
||||||
results.push(
|
results.push(FullEventResult {
|
||||||
FullEventResult {
|
event: format!("{event}"),
|
||||||
event: format!("{event}"),
|
reason: None,
|
||||||
reason: None,
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,7 +303,7 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"listallowedpubkeys" => {
|
"listallowedpubkeys" => {
|
||||||
let approvals = crate::dump_pubkey_approvals(GLOBALS.store.get().unwrap())?;
|
let approvals = crate::dump_pubkey_approvals()?;
|
||||||
let pubkeys: Vec<PubkeyResult> = approvals
|
let pubkeys: Vec<PubkeyResult> = approvals
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(pk, appr)| {
|
.filter_map(|(pk, appr)| {
|
||||||
@ -330,7 +322,7 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"listbannedpubkeys" => {
|
"listbannedpubkeys" => {
|
||||||
let approvals = crate::dump_pubkey_approvals(GLOBALS.store.get().unwrap())?;
|
let approvals = crate::dump_pubkey_approvals()?;
|
||||||
let pubkeys: Vec<PubkeyResult> = approvals
|
let pubkeys: Vec<PubkeyResult> = approvals
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(pk, appr)| {
|
.filter_map(|(pk, appr)| {
|
||||||
@ -384,17 +376,16 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"listmoderators" => {
|
"listmoderators" => {
|
||||||
let moderators: Vec<String> =
|
let moderators: Vec<String> = crate::dump_authorized_users()?
|
||||||
crate::dump_authorized_users(GLOBALS.store.get().unwrap())?
|
.iter()
|
||||||
.iter()
|
.filter_map(|(pk, moderator)| {
|
||||||
.filter_map(|(pk, moderator)| {
|
if *moderator {
|
||||||
if *moderator {
|
Some(pk.as_hex_string())
|
||||||
Some(pk.as_hex_string())
|
} else {
|
||||||
} else {
|
None
|
||||||
None
|
}
|
||||||
}
|
})
|
||||||
})
|
.collect();
|
||||||
.collect();
|
|
||||||
Ok(Some(json!({
|
Ok(Some(json!({
|
||||||
"result": moderators
|
"result": moderators
|
||||||
})))
|
})))
|
||||||
@ -407,7 +398,7 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
})))
|
})))
|
||||||
} else {
|
} else {
|
||||||
let pk = get_pubkey_param(obj)?;
|
let pk = get_pubkey_param(obj)?;
|
||||||
crate::add_authorized_user(GLOBALS.store.get().unwrap(), pk, true)?;
|
crate::add_authorized_user(pk, true)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -424,13 +415,13 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
if !crate::is_authorized_user(pk) {
|
if !crate::is_authorized_user(pk) {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
crate::add_authorized_user(GLOBALS.store.get().unwrap(), pk, false)?;
|
crate::add_authorized_user(pk, false)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"listusers" => {
|
"listusers" => {
|
||||||
let users: Vec<String> = crate::dump_authorized_users(GLOBALS.store.get().unwrap())?
|
let users: Vec<String> = crate::dump_authorized_users()?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(pk, _moderator)| pk.as_hex_string())
|
.map(|(pk, _moderator)| pk.as_hex_string())
|
||||||
.collect();
|
.collect();
|
||||||
@ -446,7 +437,7 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
})))
|
})))
|
||||||
} else {
|
} else {
|
||||||
let pk = get_pubkey_param(obj)?;
|
let pk = get_pubkey_param(obj)?;
|
||||||
crate::add_authorized_user(GLOBALS.store.get().unwrap(), pk, false)?;
|
crate::add_authorized_user(pk, false)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,7 +449,7 @@ pub fn handle_inner(pubkey: Pubkey, command: Value) -> Result<Option<Value>, Err
|
|||||||
})))
|
})))
|
||||||
} else {
|
} else {
|
||||||
let pk = get_pubkey_param(obj)?;
|
let pk = get_pubkey_param(obj)?;
|
||||||
crate::rm_authorized_user(GLOBALS.store.get().unwrap(), pk)?;
|
crate::rm_authorized_user(pk)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user