diff --git a/crates/app/src/public/css/root.css b/crates/app/src/public/css/root.css index 08437da..686cd49 100644 --- a/crates/app/src/public/css/root.css +++ b/crates/app/src/public/css/root.css @@ -250,7 +250,8 @@ svg.icon { height: 1em; } -svg.icon.filled { +svg.icon.filled, +.filled svg.icon { fill: currentColor; } diff --git a/crates/app/src/public/html/components.lisp b/crates/app/src/public/html/components.lisp index 0a03300..900116a 100644 --- a/crates/app/src/public/html/components.lisp +++ b/crates/app/src/public/html/components.lisp @@ -6,7 +6,6 @@ ("class" "avatar shadow") ("loading" "lazy") ("style" "--size: {{ size }}")) - (text "{%- endmacro %} {% macro community_avatar(id, community=false, size=\"24px\") -%} {% if community -%}") (img ("src" "/api/v1/communities/{{ id }}/avatar") @@ -14,7 +13,6 @@ ("class" "avatar shadow") ("loading" "lazy") ("style" "--size: {{ size }}")) - (text "{% else %}") (img ("src" "/api/v1/communities/{{ id }}/avatar") @@ -22,7 +20,6 @@ ("class" "avatar shadow") ("loading" "lazy") ("style" "--size: {{ size }}")) - (text "{%- endif %} {%- endmacro %} {% macro banner(username, border_radius=\"var(--radius)\") -%}") (img ("title" "{{ username }}'s banner") @@ -31,21 +28,18 @@ ("class" "banner shadow w_full") ("loading" "lazy") ("style" "border-radius: {{ border_radius }};")) - (text "{%- endmacro %} {% macro community_banner(id, community=false) -%} {% if community %}") (img ("src" "/api/v1/communities/{{ id }}/banner") ("alt" "{{ community.title }}'s banner") ("class" "banner shadow") ("loading" "lazy")) - (text "{% else %}") (img ("src" "/api/v1/communities/{{ id }}/banner") ("alt" "{{ id }}'s banner") ("class" "banner shadow") ("loading" "lazy")) - (text "{%- endif %} {%- endmacro %} {% macro community_listing_card(community) -%}") (a ("class" "card secondary w_full flex items_center gap_4") @@ -69,12 +63,10 @@ (b (text "{{ community.member_count }} ")) (text "members")))) - (text "{%- endmacro %} {% macro username(user) -%}") (div ("style" "display: contents") (text "{% if user.settings.display_name -%} {{ user.settings.display_name }} {% else %} {{ user.username }} {%- endif %}")) - (text "{%- endmacro %} {% macro likes(id, asset_type, likes=0, dislikes=0, secondary=false, disable_dislikes=false) -%}") (button ("title" "Like") @@ -85,7 +77,6 @@ (span (text "{{ likes }}")) (text "{%- endif %}")) - (text "{% if not user or not user.settings.hide_dislikes and not disable_dislikes -%}") (button ("title" "Dislike") @@ -96,15 +87,21 @@ (span (text "{{ dislikes }}")) (text "{%- endif %}")) - (text "{%- endif %} {%- endmacro %} {% macro full_username(user) -%} {% if user and user.username -%}") (div ("class" "flex items_center") (a ("href" "/@{{ user.username }}") - ("class" "flush") + ("class" "flush flex gap_1") ("style" "font-weight: 600") ("target" "_top") + (text "{% if user.settings.private_profile -%}") + (span + ("title" "Private") + ("class" "flex items_center") + (icon (text "lock"))) + (text "{%- endif %}") + (text "{% if user.permissions|has_banned -%}") (del ("class" "fade") (text "{{ self::username(user=user) }}")) (text "{% else %}") @@ -134,7 +131,6 @@ ("style" "display: contents") (text "{{ self::post(post=post, owner=owner, secondary=secondary, community=community, show_community=show_community, can_manage_post=can_manage_post, repost=repost, expect_repost=true) }}")) (text "{%- endmacro %}") - (text "{% macro post_info(post, community) -%}") ; info about the post: edited, date, etc. (text "{% if post.context.edited != 0 -%}") @@ -200,7 +196,6 @@ (text "{{ icon \"trash-2\" }}")) (text "{%- endif %}") (text "{%- endmacro %}") - (text "{% macro post_buttons_box(post, community, owner, can_manage_post, show_comments=true) -%}") (div ("class" "flex justify_between items_center gap_2 w_full") diff --git a/crates/app/src/routes/api/v1/economy.rs b/crates/app/src/routes/api/v1/economy.rs new file mode 100644 index 0000000..fa7bf4a --- /dev/null +++ b/crates/app/src/routes/api/v1/economy.rs @@ -0,0 +1,28 @@ +use crate::{get_user_from_token, State, cookie::CookieJar}; +use axum::{response::IntoResponse, Extension, Json}; +use tetratto_core::model::{economy::CoinTransfer, oauth, ApiReturn, Error}; +use super::CreateCoinTransfer; + +pub async fn create_request( + jar: CookieJar, + Extension(data): Extension, + Json(req): Json, +) -> impl IntoResponse { + let data = &(data.read().await).0; + let user = match get_user_from_token!(jar, data, oauth::AppScope::UserSendCoins) { + Some(ua) => ua, + None => return Json(Error::NotAllowed.into()), + }; + + match data + .create_transfer(CoinTransfer::new(user.id, req.receiver, req.amount)) + .await + { + Ok(s) => Json(ApiReturn { + ok: true, + message: "Stack created".to_string(), + payload: s.id.to_string(), + }), + Err(e) => Json(e.into()), + } +} diff --git a/crates/app/src/routes/api/v1/mod.rs b/crates/app/src/routes/api/v1/mod.rs index 5e5ddb4..2dc9d6c 100644 --- a/crates/app/src/routes/api/v1/mod.rs +++ b/crates/app/src/routes/api/v1/mod.rs @@ -4,6 +4,7 @@ pub mod auth; pub mod channels; pub mod communities; pub mod domains; +pub mod economy; pub mod journals; pub mod letters; pub mod notes; @@ -705,6 +706,8 @@ pub fn routes() -> Router { .route("/letters/{id}/read", post(letters::add_read_request)) .route("/letters/sent", get(letters::list_sent_request)) .route("/letters/received", get(letters::list_received_request)) + // economy + .route("/transfers", post(economy::create_request)) } pub fn lw_routes() -> Router { @@ -1212,3 +1215,9 @@ pub struct CreateLetter { pub content: String, pub replying_to: String, } + +#[derive(Deserialize)] +pub struct CreateCoinTransfer { + pub receiver: usize, + pub amount: i32, +} diff --git a/crates/core/src/database/economy.rs b/crates/core/src/database/economy.rs index f652e22..f8efce4 100644 --- a/crates/core/src/database/economy.rs +++ b/crates/core/src/database/economy.rs @@ -4,7 +4,7 @@ use crate::{auto_method, DataManager}; use oiseau::{cache::Cache, execute, get, params, query_rows, PostgresRow}; impl DataManager { - /// Get a [`Letter`] from an SQL row. + /// Get a [`CoinTransfer`] from an SQL row. pub(crate) fn get_transfer_from_row(x: &PostgresRow) -> CoinTransfer { CoinTransfer { id: get!(x->0(i64)) as usize, @@ -51,7 +51,7 @@ impl DataManager { /// Create a new transfer in the database. /// /// # Arguments - /// * `data` - a mock [`Letter`] object to insert + /// * `data` - a mock [`CoinTransfer`] object to insert pub async fn create_transfer(&self, data: CoinTransfer) -> Result { // check values let mut sender = self.get_user_by_id(data.sender).await?; diff --git a/crates/core/src/model/oauth.rs b/crates/core/src/model/oauth.rs index 62fd0c1..357e4ea 100644 --- a/crates/core/src/model/oauth.rs +++ b/crates/core/src/model/oauth.rs @@ -106,6 +106,8 @@ pub enum AppScope { UserCreateProducts, /// Create letters on behalf of the user. UserCreateLetters, + /// Send coins on behalf of the user. + UserSendCoins, /// Delete posts owned by the user. UserDeletePosts, /// Delete messages owned by the user.