Skip to content

Commit

Permalink
Start with ModeratedReport and category parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
dcadenas committed Mar 29, 2024
1 parent ba4a1ee commit 368a1d3
Show file tree
Hide file tree
Showing 14 changed files with 386 additions and 122 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ path = "src/main.rs"
[[bin]]
name = "giftwrapper"
path = "src/bin/giftwrapper.rs"

[dev-dependencies]
pretty_assertions = "1.4.0"
2 changes: 1 addition & 1 deletion src/actors/event_enqueuer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ where

info!(
"Event {} enqueued for moderation",
report_request.reported_event.id()
report_request.reported_event().id()
);
}
}
Expand Down
48 changes: 6 additions & 42 deletions src/actors/gift_unwrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ impl Actor for GiftUnwrapper {

info!(
"Request from {} to moderate event {}",
report_request.reporter_pubkey,
report_request.reported_event.id()
report_request.reporter_pubkey(),
report_request.reported_event().id()
);

state.message_parsed_output_port.send(report_request)
Expand All @@ -68,45 +68,10 @@ impl Actor for GiftUnwrapper {
}
}

// NOTE: This roughly creates a message as described by nip 17 but it's still
// not ready, just for testing purposes. There are more details to consider to
// properly implement the nip like created_at treatment. The nip itself is not
// finished at this time so hopefully in the future this can be done through the
// nostr crate.
#[allow(dead_code)] // Besides the tests, it's used from the giftwrapper utility binary
pub async fn create_private_dm_message(
report_request: &ReportRequest,
reporter_keys: &Keys,
receiver_pubkey: &PublicKey,
) -> Result<Event> {
if report_request.reporter_pubkey != reporter_keys.public_key() {
return Err(anyhow::anyhow!(
"Reporter public key doesn't match the provided keys"
));
}
// Compose rumor
let kind_14_rumor =
EventBuilder::sealed_direct(receiver_pubkey.clone(), report_request.as_json())
.to_unsigned_event(reporter_keys.public_key());

// Compose seal
let content: String = NostrSigner::Keys(reporter_keys.clone())
.nip44_encrypt(receiver_pubkey.clone(), kind_14_rumor.as_json())
.await?;
let kind_13_seal = EventBuilder::new(Kind::Seal, content, []).to_event(&reporter_keys)?;

// Compose gift wrap
let kind_1059_gift_wrap: Event =
EventBuilder::gift_wrap_from_seal(&receiver_pubkey, &kind_13_seal, None)?;

Ok(kind_1059_gift_wrap)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::actors::TestActor;
use crate::domain_objects::GiftWrap;
use ractor::{cast, Actor};
use serde_json::json;
use std::sync::Arc;
Expand Down Expand Up @@ -138,11 +103,10 @@ mod tests {
.to_string();
let report_request: ReportRequest = serde_json::from_str(&report_request_string).unwrap();

let gift_wrapped_event = GiftWrap::new(
create_private_dm_message(&report_request, &sender_keys, &receiver_pubkey)
.await
.unwrap(),
);
let gift_wrapped_event = report_request
.as_gift_wrap(&sender_keys, &receiver_pubkey)
.await
.unwrap();

let messages_received = Arc::new(Mutex::new(Vec::<ReportRequest>::new()));
let (receiver_actor_ref, receiver_actor_handle) =
Expand Down
10 changes: 5 additions & 5 deletions src/actors/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ use std::fmt::Debug;
pub enum RelayEventDispatcherMessage {
Connect,
Reconnect,
SubscribeToEventReceived(OutputPortSubscriber<GiftWrap>),
EventReceived(GiftWrap),
SubscribeToEventReceived(OutputPortSubscriber<GiftWrappedReportRequest>),
EventReceived(GiftWrappedReportRequest),
}

#[derive(Debug)]
pub enum GiftUnwrapperMessage {
UnwrapEvent(GiftWrap),
UnwrapEvent(GiftWrappedReportRequest),
SubscribeToEventUnwrapped(OutputPortSubscriber<ReportRequest>),
}

// How to subscribe to actors that publish DM messages like RelayEventDispatcher
impl From<GiftWrap> for GiftUnwrapperMessage {
fn from(gift_wrap: GiftWrap) -> Self {
impl From<GiftWrappedReportRequest> for GiftUnwrapperMessage {
fn from(gift_wrap: GiftWrappedReportRequest) -> Self {
GiftUnwrapperMessage::UnwrapEvent(gift_wrap)
}
}
Expand Down
20 changes: 13 additions & 7 deletions src/actors/relay_event_dispatcher.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::actors::messages::RelayEventDispatcherMessage;
use crate::domain_objects::GiftWrap;
use crate::domain_objects::GiftWrappedReportRequest;
use crate::service_manager::ServiceManager;
use anyhow::Result;
use nostr_sdk::prelude::*;
Expand All @@ -19,7 +19,7 @@ impl<T: Subscribe> Default for RelayEventDispatcher<T> {
}
}
pub struct State<T: Subscribe> {
event_received_output_port: OutputPort<GiftWrap>,
event_received_output_port: OutputPort<GiftWrappedReportRequest>,
subscription_task_manager: Option<ServiceManager>,
nostr_client: T,
}
Expand Down Expand Up @@ -195,6 +195,7 @@ where
mod tests {
use super::*;
use crate::actors::TestActor;
use pretty_assertions::assert_eq;
use ractor::{cast, concurrency::Duration};
use std::sync::Arc;
use tokio::sync::mpsc;
Expand Down Expand Up @@ -245,7 +246,9 @@ mod tests {
while let Some(Some(event)) = self.event_receiver.lock().await.recv().await {
cast!(
dispatcher_actor,
RelayEventDispatcherMessage::EventReceived(GiftWrap::new(event))
RelayEventDispatcherMessage::EventReceived(GiftWrappedReportRequest::try_from(
event
)?)
)
.expect("Failed to cast event to dispatcher");
}
Expand All @@ -256,10 +259,10 @@ mod tests {

#[tokio::test]
async fn test_relay_event_dispatcher() {
let first_event = EventBuilder::text_note("First event", [])
let first_event = EventBuilder::new(Kind::GiftWrap, "First event", [])
.to_event(&Keys::generate())
.unwrap();
let second_event = EventBuilder::text_note("Second event", [])
let second_event = EventBuilder::new(Kind::GiftWrap, "Second event", [])
.to_event(&Keys::generate())
.unwrap();

Expand All @@ -275,7 +278,7 @@ mod tests {
.await
.unwrap();

let received_messages = Arc::new(Mutex::new(Vec::<GiftWrap>::new()));
let received_messages = Arc::new(Mutex::new(Vec::<GiftWrappedReportRequest>::new()));

let (receiver_ref, receiver_handle) =
Actor::spawn(None, TestActor::default(), received_messages.clone())
Expand Down Expand Up @@ -304,7 +307,10 @@ mod tests {

assert_eq!(
received_messages.lock().await.as_ref(),
[GiftWrap::new(first_event), GiftWrap::new(second_event)]
[
GiftWrappedReportRequest::try_from(first_event).unwrap(),
GiftWrappedReportRequest::try_from(second_event).unwrap()
]
);
}
}
34 changes: 21 additions & 13 deletions src/adapters/http_server/slack_interactions_route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ use super::app_errors::AppError;
use super::WebAppState;
use anyhow::{anyhow, Context, Result};
use axum::{extract::State, routing::post, Extension, Router};
use gcloud_sdk::tonic::IntoRequest;
use nostr_sdk::prelude::*;
use reportinator_server::domain_objects::{ModeratedReport, ModerationCategory, ReportRequest};
use reqwest::Client;
use serde_json::{json, Value};
use slack_morphism::prelude::*;
use std::env;
use std::sync::Arc;
use std::{env, str::FromStr};
use tracing::{error, info};

pub fn slack_interactions_route() -> Result<Router<WebAppState>> {
Expand Down Expand Up @@ -112,30 +114,36 @@ async fn slack_interaction_handler(
)
})?;

info!("Reported Event Block: {:?}", event);
// The slack payload is the category id in the action_id, and the reporter pubkey in the value
let reporter_pubkey = Keys::from_str(&value)?.public_key();
let report_request = ReportRequest::new(event, reporter_pubkey, None);
let category = ModerationCategory::from_str(&action_id).ok();
let moderated_report = report_request.moderate(category);

info!(
"Received interaction from {}. Action: {}, Value: {}",
username, action_id, value
);
respond_with_replace(&response_url.to_string(), username, text, event.id).await?;

let response_text = match moderated_report {
Some(moderated_report) => {
format!(
"Event reported by {} has been moderated with category: {}",
username, moderated_report
)
}
None => format!("{} skipped moderation for {}", username, report_request),
};
respond_with_replace(&response_url.to_string(), &response_text).await?;
}
_ => {}
}

Ok(())
}

async fn respond_with_replace(
response_url: &str,
username: &str,
text: &str,
event_id: EventId,
) -> Result<()> {
async fn respond_with_replace(response_url: &str, response_text: &str) -> Result<()> {
let client = Client::new();
let response_text = format!(
"`{}` selected `{}` for event id `{}`",
username, text, event_id
);

let res = client
.post(response_url)
Expand Down
5 changes: 3 additions & 2 deletions src/adapters/nostr_subscriber.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::actors::messages::RelayEventDispatcherMessage;
use crate::actors::Subscribe;
use crate::domain_objects::GiftWrap;
use crate::domain_objects::GiftWrappedReportRequest;
use nostr_sdk::prelude::*;
use ractor::{cast, concurrency::Duration, ActorRef};
use tokio_util::sync::CancellationToken;
Expand Down Expand Up @@ -58,9 +58,10 @@ impl Subscribe for NostrSubscriber {
}

if let RelayPoolNotification::Event { event, .. } = notification {
let gift_wrapped_report_request = GiftWrappedReportRequest::try_from(*event)?;
cast!(
dispatcher_actor,
RelayEventDispatcherMessage::EventReceived(GiftWrap::new(*event))
RelayEventDispatcherMessage::EventReceived(gift_wrapped_report_request)
)
.expect("Failed to cast event to dispatcher");
}
Expand Down
15 changes: 7 additions & 8 deletions src/bin/giftwrapper.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use anyhow::Result;
use nostr_sdk::prelude::*;
use reportinator_server::actors::gift_unwrapper::create_private_dm_message;
use reportinator_server::domain_objects::ReportRequest;
use std::env;
use std::io::{self, BufRead};
Expand Down Expand Up @@ -30,13 +29,13 @@ async fn main() -> Result<()> {
.expect("Failed to read line");

let sender_keys = Keys::generate();
let report_request = ReportRequest {
reported_event: EventBuilder::text_note(&message, []).to_event(&sender_keys)?,
reporter_pubkey: sender_keys.public_key(),
reporter_text: Some("This is wrong, report it!".to_string()),
};
let event_result =
create_private_dm_message(&report_request, &sender_keys, &receiver_pubkey).await;
let reported_event = EventBuilder::text_note(&message, []).to_event(&sender_keys)?;
let reporter_pubkey = sender_keys.public_key();
let reporter_text = Some("This is wrong, report it!".to_string());
let report_request = ReportRequest::new(reported_event, reporter_pubkey, reporter_text);
let event_result = report_request
.as_gift_wrap(&sender_keys, &receiver_pubkey)
.await;

match event_result {
Ok(event) => {
Expand Down
Loading

0 comments on commit 368a1d3

Please sign in to comment.