diff --git a/backend/canisters/proposals_bot/CHANGELOG.md b/backend/canisters/proposals_bot/CHANGELOG.md index ba5dda7762..f778ce5b4e 100644 --- a/backend/canisters/proposals_bot/CHANGELOG.md +++ b/backend/canisters/proposals_bot/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Use canister timer rather than heartbeat to update proposals ([#4507](https://github.com/open-chat-labs/open-chat/pull/4507)) - Refund deposit if user submitted proposal is successful ([#4509](https://github.com/open-chat-labs/open-chat/pull/4509)) - Top up neuron if user submitted proposal is rejected ([#4510](https://github.com/open-chat-labs/open-chat/pull/4510)) +- Add 'Submitted by @Username on OpenChat' suffix to proposals ([#4511](https://github.com/open-chat-labs/open-chat/pull/4511)) ## [[2.0.843](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.843-proposals_bot)] - 2023-09-11 diff --git a/backend/canisters/proposals_bot/impl/src/updates/c2c_submit_proposal.rs b/backend/canisters/proposals_bot/impl/src/updates/c2c_submit_proposal.rs index 119c076c45..2346230154 100644 --- a/backend/canisters/proposals_bot/impl/src/updates/c2c_submit_proposal.rs +++ b/backend/canisters/proposals_bot/impl/src/updates/c2c_submit_proposal.rs @@ -3,40 +3,46 @@ use crate::{mutate_state, read_state, RuntimeState}; use candid::Principal; use canister_api_macros::update_msgpack; use canister_tracing_macros::trace; -use local_user_index_canister_c2c_client::{lookup_user, LookupUserError}; use proposals_bot_canister::c2c_submit_proposal::{Response::*, *}; use proposals_bot_canister::{ProposalToSubmit, ProposalToSubmitAction, Treasury}; use sns_governance_canister::types::manage_neuron::Command; use sns_governance_canister::types::proposal::Action; use sns_governance_canister::types::{manage_neuron_response, Motion, Proposal, Subaccount, TransferSnsTreasuryFunds}; -use types::{CanisterId, SnsNeuronId, UserId}; +use types::{CanisterId, MultiUserChat, SnsNeuronId, UserDetails, UserId}; +use user_index_canister_c2c_client::{lookup_user, LookupUserError}; use utils::time::SECOND_IN_MS; +const OC_ROOT_URL: &str = "https://oc.app/"; + #[update_msgpack] #[trace] async fn c2c_submit_proposal(args: Args) -> Response { let PrepareResult { caller, - local_user_index_canister_id, + user_index_canister_id, neuron_id, + chat, } = match read_state(|state| prepare(&args, state)) { Ok(ok) => ok, Err(response) => return response, }; - let user_id = match lookup_user(caller, local_user_index_canister_id).await { - Ok(u) => u.user_id, + let UserDetails { user_id, username, .. } = match lookup_user(caller, user_index_canister_id).await { + Ok(u) => u, Err(LookupUserError::UserNotFound) => unreachable!(), Err(LookupUserError::InternalError(error)) => return InternalError(error), }; - submit_proposal(user_id, args.governance_canister_id, neuron_id, args.proposal).await + let proposal = prepare_proposal(args.proposal, user_id, username, chat); + + submit_proposal(user_id, args.governance_canister_id, neuron_id, proposal).await } struct PrepareResult { caller: Principal, - local_user_index_canister_id: CanisterId, + user_index_canister_id: CanisterId, neuron_id: SnsNeuronId, + chat: MultiUserChat, } fn prepare(args: &Args, state: &RuntimeState) -> Result { @@ -47,14 +53,39 @@ fn prepare(args: &Args, state: &RuntimeState) -> Result { Ok(PrepareResult { caller: state.env.caller(), - local_user_index_canister_id: state.data.local_user_index_canister_id, + user_index_canister_id: state.data.user_index_canister_id, neuron_id, + chat: state.data.nervous_systems.get_chat_id(&args.governance_canister_id).unwrap(), }) } else { Err(GovernanceCanisterNotSupported) } } +fn prepare_proposal( + mut proposal: ProposalToSubmit, + user_id: UserId, + username: String, + chat: MultiUserChat, +) -> ProposalToSubmit { + proposal.title = proposal.title.trim().to_string(); + proposal.summary = proposal.summary.trim().to_string(); + proposal.url = proposal.url.trim().to_string(); + + let chat_url = match chat { + MultiUserChat::Group(group_id) => format!("{OC_ROOT_URL}group/{group_id}"), + MultiUserChat::Channel(community_id, channel_id) => { + format!("{OC_ROOT_URL}community/{community_id}/channel/{channel_id}") + } + }; + let user_url = format!("{OC_ROOT_URL}user/{user_id}"); + + let suffix = format!("\n\n> Submitted by [@{username}]({user_url}) on [OpenChat]({chat_url})"); + proposal.summary.push_str(&suffix); + + proposal +} + pub(crate) async fn submit_proposal( user_id: UserId, governance_canister_id: CanisterId, diff --git a/backend/canisters/user_index/CHANGELOG.md b/backend/canisters/user_index/CHANGELOG.md index f47a8b4418..ad50ee5d18 100644 --- a/backend/canisters/user_index/CHANGELOG.md +++ b/backend/canisters/user_index/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [unreleased] +### Changed + +- Add `username` to `c2c_lookup_user` response ([#4511](https://github.com/open-chat-labs/open-chat/pull/4511)) + ## [[2.0.873](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.873-user_index)] - 2023-10-06 ### Changed diff --git a/backend/canisters/user_index/impl/src/queries/c2c_lookup_user.rs b/backend/canisters/user_index/impl/src/queries/c2c_lookup_user.rs index 0524681411..b405d3af62 100644 --- a/backend/canisters/user_index/impl/src/queries/c2c_lookup_user.rs +++ b/backend/canisters/user_index/impl/src/queries/c2c_lookup_user.rs @@ -18,6 +18,7 @@ fn c2c_lookup_user_impl(args: Args, state: &RuntimeState) -> Response { Success(UserDetails { principal: user.principal, user_id: user.user_id, + username: user.username.clone(), is_bot: user.is_bot, is_platform_moderator, is_platform_operator, diff --git a/backend/libraries/types/src/user.rs b/backend/libraries/types/src/user.rs index 0af38be2e0..33ae87b484 100644 --- a/backend/libraries/types/src/user.rs +++ b/backend/libraries/types/src/user.rs @@ -46,6 +46,7 @@ pub struct User { pub struct UserDetails { pub principal: Principal, pub user_id: UserId, + pub username: String, pub is_bot: bool, pub is_platform_moderator: bool, pub is_platform_operator: bool,