Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report btn #241

Merged
merged 9 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ fn build_gprc_client() -> Result<(), Box<dyn std::error::Error>> {
let proto_file = "contracts/projects/warehouse_events/warehouse_events.proto";
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

tonic_build::configure()
.build_client(true)
.build_server(false)
.out_dir(out_dir)
.compile(&[proto_file], &["proto"])?;

let proto_file = "contracts/projects/off_chain/off_chain.proto";
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

tonic_build::configure()
.build_client(true)
.build_server(false)
Expand Down
2 changes: 1 addition & 1 deletion contracts
1 change: 1 addition & 0 deletions src/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod modal;
pub mod nav;
pub mod nav_icons;
pub mod no_more_posts;
pub mod option;
pub mod overlay;
pub mod scrolling_post_view;
pub mod social;
Expand Down
15 changes: 15 additions & 0 deletions src/component/option.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use leptos::*;

#[component]
pub fn SelectOption(#[prop(into)] is: String, value: ReadSignal<String>) -> impl IntoView {
let is_copy = is.clone();

view! {
<option
value=is.clone()
selected=move || value() == is_copy
>
{is}
</option>
}
}
19 changes: 18 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ use axum::{
};
use axum::{routing::get, Router};
use axum_extra::extract::cookie::Key;
use hot_or_not_web_leptos_ssr::state::canisters::Canisters;
use hot_or_not_web_leptos_ssr::{app::App, state::server::AppState};
use hot_or_not_web_leptos_ssr::{
auth::server_impl::store::KVStoreImpl, fallback::file_and_error_handler,
};
use hot_or_not_web_leptos_ssr::{consts::OFF_CHAIN_AGENT_GRPC_URL, state::canisters::Canisters};
use leptos::{get_configuration, logging::log, provide_context};
use leptos_axum::handle_server_fns_with_context;
use leptos_axum::{generate_route_list, LeptosRoutes};
Expand All @@ -35,6 +35,8 @@ pub async fn server_fn_handler(
provide_context(app_state.cookie_key.clone());
#[cfg(feature = "oauth-ssr")]
provide_context(app_state.google_oauth.clone());
#[cfg(feature = "ga4")]
provide_context(app_state.grpc_offchain_channel.clone());
},
request,
)
Expand All @@ -58,6 +60,8 @@ pub async fn leptos_routes_handler(
provide_context(app_state.cookie_key.clone());
#[cfg(feature = "oauth-ssr")]
provide_context(app_state.google_oauth.clone());
#[cfg(feature = "ga4")]
provide_context(app_state.grpc_offchain_channel.clone());
},
App,
);
Expand Down Expand Up @@ -136,6 +140,17 @@ fn init_google_oauth() -> openidconnect::core::CoreClient {
.set_redirect_uri(RedirectUrl::new(redirect_uri).unwrap())
}

#[cfg(feature = "ga4")]
async fn init_grpc_offchain_channel() -> tonic::transport::Channel {
use tonic::transport::Channel;

let off_chain_agent_url = OFF_CHAIN_AGENT_GRPC_URL.as_ref();
Channel::from_static(off_chain_agent_url)
.connect()
.await
.expect("Couldn't connect to off-chain agent")
}

#[tokio::main]
async fn main() {
simple_logger::init_with_level(log::Level::Debug).expect("couldn't initialize logging");
Expand Down Expand Up @@ -163,6 +178,8 @@ async fn main() {
cookie_key: init_cookie_key(),
#[cfg(feature = "oauth-ssr")]
google_oauth: init_google_oauth(),
#[cfg(feature = "ga4")]
grpc_offchain_channel: init_grpc_offchain_channel().await,
};

// build our application with a route
Expand Down
65 changes: 62 additions & 3 deletions src/page/post_view/overlay.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::{
component::{canisters_prov::WithAuthCans, modal::Modal},
component::{canisters_prov::WithAuthCans, modal::Modal, option::SelectOption},
state::canisters::{auth_canisters_store, Canisters},
utils::{
event_streaming::events::{LikeVideo, ShareVideo},
posts::PostDetails,
report::ReportOption,
route::failure_redirect,
user::UserDetails,
web::{copy_to_clipboard, share_url},
},
};
Expand Down Expand Up @@ -110,6 +112,9 @@ fn LikeAndAuthCanLoader(post: PostDetails) -> impl IntoView {
#[component]
pub fn VideoDetailsOverlay(post: PostDetails) -> impl IntoView {
let show_share = create_rw_signal(false);
let show_report = create_rw_signal(false);
let (report_option, set_report_option) =
create_signal(ReportOption::Nudity.as_str().to_string());
let show_copied_popup = create_rw_signal(false);
let base_url = || {
use_window()
Expand All @@ -122,11 +127,12 @@ pub fn VideoDetailsOverlay(post: PostDetails) -> impl IntoView {
.unwrap_or_default()
};

let post_details = post.clone();
let post_details_share = post.clone();
let canisters = auth_canisters_store();
let canisters_copy = canisters;

let share = move || {
let post_details = post_details.clone();
let post_details = post_details_share.clone();
let url = video_url();
if share_url(&url).is_some() {
return;
Expand All @@ -144,6 +150,35 @@ pub fn VideoDetailsOverlay(post: PostDetails) -> impl IntoView {
Timeout::new(1200, move || show_copied_popup.set(false)).forget();
};

let post_details_report = post.clone();
let click_report = create_action(move |()| {
#[cfg(feature = "ga4")]
{
use crate::utils::report::send_report_offchain;

let post_details = post_details_report.clone();
let user_details = UserDetails::try_get_from_canister_store(canisters_copy).unwrap();

spawn_local(async move {
send_report_offchain(
user_details.details.principal.to_string(),
post_details.poster_principal.to_string(),
post_details.canister_id.to_string(),
post_details.post_id.to_string(),
post_details.uid,
report_option.get_untracked(),
video_url(),
)
.await
.unwrap();
});
}

async move {
show_report.set(false);
}
});

view! {
<div class="flex flex-row flex-nowrap justify-between items-end pb-20 px-2 md:px-6 w-full text-white absolute bottom-0 left-0 bg-transparent z-[4]">
<div class="flex flex-col gap-2 w-9/12">
Expand All @@ -167,6 +202,9 @@ pub fn VideoDetailsOverlay(post: PostDetails) -> impl IntoView {
<ExpandableText description=post.description/>
</div>
<div class="flex flex-col gap-8 pb-10 items-end w-3/12 text-4xl">
<button on:click=move |_| show_report.set(true)>
<Icon class="drop-shadow-lg" icon=icondata::TbMessageReport/>
</button>
<a href="/refer-earn">
<Icon class="drop-shadow-lg" icon=icondata::AiGiftFilled/>
</a>
Expand Down Expand Up @@ -197,6 +235,27 @@ pub fn VideoDetailsOverlay(post: PostDetails) -> impl IntoView {
</div>
</Show>
</Modal>
<Modal show=show_report>
<div class="flex flex-col justify-center items-center gap-4 text-white">
<span class="text-lg">Report Post</span>
<span class="text-lg">Please select a reason:</span>
<div class="max-w-full text-md text-black">
<select class="p-2 w-full block rounded-lg text-sm" on:change=move |ev| {
let new_value = event_target_value(&ev);
set_report_option(new_value);
}>
<SelectOption value=report_option is=format!("{}",ReportOption::Nudity.as_str())/>
<SelectOption value=report_option is=format!("{}",ReportOption::Violence.as_str())/>
<SelectOption value=report_option is=format!("{}",ReportOption::Offensive.as_str())/>
<SelectOption value=report_option is=format!("{}",ReportOption::Spam.as_str())/>
<SelectOption value=report_option is=format!("{}",ReportOption::Other.as_str())/>
</select>
</div>
<button on:click=move |_| click_report.dispatch(())>
<div class="rounded-lg bg-pink-500 p-1">Submit</div>
</button>
</div>
</Modal>
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod server {
use axum_extra::extract::cookie::Key;
use leptos::LeptosOptions;
use leptos_router::RouteListing;
use tonic::transport::Channel;

#[derive(FromRef, Clone)]
pub struct AppState {
Expand All @@ -28,5 +29,7 @@ pub mod server {
pub cookie_key: Key,
#[cfg(feature = "oauth-ssr")]
pub google_oauth: openidconnect::core::CoreClient,
#[cfg(feature = "ga4")]
pub grpc_offchain_channel: Channel,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ga4 feature flag

}
}
5 changes: 2 additions & 3 deletions src/utils/event_streaming/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use leptos::*;
use serde_json::json;
use wasm_bindgen::prelude::*;

use crate::consts::{GTAG_MEASUREMENT_ID, OFF_CHAIN_AGENT_GRPC_URL};
use crate::consts::GTAG_MEASUREMENT_ID;

pub mod events;

Expand Down Expand Up @@ -71,8 +71,7 @@ pub async fn stream_to_offchain_agent(event: String, params: String) -> Result<(
use tonic::transport::Channel;
use tonic::Request;

let off_chain_agent_url = OFF_CHAIN_AGENT_GRPC_URL.as_ref();
let channel = Channel::from_static(off_chain_agent_url).connect().await?;
let channel: Channel = expect_context();

let mut off_chain_agent_grpc_auth_token = env::var("GRPC_AUTH_TOKEN").expect("GRPC_AUTH_TOKEN");
// removing whitespaces and new lines for proper parsing
Expand Down
6 changes: 6 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod event_streaming;
pub mod icon;
pub mod posts;
pub mod profile;
pub mod report;
pub mod route;
pub mod timestamp;
pub mod user;
Expand All @@ -27,3 +28,8 @@ impl<T> PartialEq for MockPartialEq<T> {
false
}
}

#[cfg(all(feature = "ga4", feature = "ssr"))]
pub mod off_chain {
tonic::include_proto!("off_chain");
}
70 changes: 70 additions & 0 deletions src/utils/report.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::{env, fmt::Display};

use leptos::{expect_context, server, ServerFnError};

pub enum ReportOption {
Nudity,
Violence,
Offensive,
Spam,
Other,
}

impl ReportOption {
pub fn as_str(&self) -> impl Display {
match self {
ReportOption::Nudity => "Nudity/Porn",
ReportOption::Violence => "Violence/Gore",
ReportOption::Offensive => "Offensive",
ReportOption::Spam => "Spam/Ad",
ReportOption::Other => "Others",
}
}
}

#[cfg(feature = "ga4")]
#[server]
pub async fn send_report_offchain(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also add a mock (or make reporting no-op locally)

reporter_id: String,
publisher_id: String,
publisher_canister_id: String,
post_id: String,
video_id: String,
reason: String,
video_url: String,
) -> Result<(), ServerFnError> {
use crate::utils::off_chain;
use tonic::metadata::MetadataValue;
use tonic::transport::Channel;
use tonic::Request;

let channel: Channel = expect_context();

let mut off_chain_agent_grpc_auth_token = env::var("GRPC_AUTH_TOKEN").expect("GRPC_AUTH_TOKEN");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we migrate off chain client to AppState instead of constructing every time?
https://github.com/go-bazzinga/hot-or-not-web-leptos-ssr/blob/main/src/state/mod.rs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

// removing whitespaces and new lines for proper parsing
off_chain_agent_grpc_auth_token.retain(|c| !c.is_whitespace());

let token: MetadataValue<_> = format!("Bearer {}", off_chain_agent_grpc_auth_token).parse()?;

let mut client = off_chain::off_chain_client::OffChainClient::with_interceptor(
channel,
move |mut req: Request<()>| {
req.metadata_mut().insert("authorization", token.clone());
Ok(req)
},
);

let request = tonic::Request::new(off_chain::ReportPostRequest {
reporter_id,
publisher_id,
publisher_canister_id,
post_id,
video_id,
reason,
video_url,
});

client.report_post(request).await?;

Ok(())
}
Loading