add: economy api

This commit is contained in:
trisua 2025-08-07 00:22:37 -04:00
parent 0a3ce3e9fe
commit 3c4ce1fae5
6 changed files with 51 additions and 16 deletions

View file

@ -250,7 +250,8 @@ svg.icon {
height: 1em; height: 1em;
} }
svg.icon.filled { svg.icon.filled,
.filled svg.icon {
fill: currentColor; fill: currentColor;
} }

View file

@ -6,7 +6,6 @@
("class" "avatar shadow") ("class" "avatar shadow")
("loading" "lazy") ("loading" "lazy")
("style" "--size: {{ size }}")) ("style" "--size: {{ size }}"))
(text "{%- endmacro %} {% macro community_avatar(id, community=false, size=\"24px\") -%} {% if community -%}") (text "{%- endmacro %} {% macro community_avatar(id, community=false, size=\"24px\") -%} {% if community -%}")
(img (img
("src" "/api/v1/communities/{{ id }}/avatar") ("src" "/api/v1/communities/{{ id }}/avatar")
@ -14,7 +13,6 @@
("class" "avatar shadow") ("class" "avatar shadow")
("loading" "lazy") ("loading" "lazy")
("style" "--size: {{ size }}")) ("style" "--size: {{ size }}"))
(text "{% else %}") (text "{% else %}")
(img (img
("src" "/api/v1/communities/{{ id }}/avatar") ("src" "/api/v1/communities/{{ id }}/avatar")
@ -22,7 +20,6 @@
("class" "avatar shadow") ("class" "avatar shadow")
("loading" "lazy") ("loading" "lazy")
("style" "--size: {{ size }}")) ("style" "--size: {{ size }}"))
(text "{%- endif %} {%- endmacro %} {% macro banner(username, border_radius=\"var(--radius)\") -%}") (text "{%- endif %} {%- endmacro %} {% macro banner(username, border_radius=\"var(--radius)\") -%}")
(img (img
("title" "{{ username }}'s banner") ("title" "{{ username }}'s banner")
@ -31,21 +28,18 @@
("class" "banner shadow w_full") ("class" "banner shadow w_full")
("loading" "lazy") ("loading" "lazy")
("style" "border-radius: {{ border_radius }};")) ("style" "border-radius: {{ border_radius }};"))
(text "{%- endmacro %} {% macro community_banner(id, community=false) -%} {% if community %}") (text "{%- endmacro %} {% macro community_banner(id, community=false) -%} {% if community %}")
(img (img
("src" "/api/v1/communities/{{ id }}/banner") ("src" "/api/v1/communities/{{ id }}/banner")
("alt" "{{ community.title }}'s banner") ("alt" "{{ community.title }}'s banner")
("class" "banner shadow") ("class" "banner shadow")
("loading" "lazy")) ("loading" "lazy"))
(text "{% else %}") (text "{% else %}")
(img (img
("src" "/api/v1/communities/{{ id }}/banner") ("src" "/api/v1/communities/{{ id }}/banner")
("alt" "{{ id }}'s banner") ("alt" "{{ id }}'s banner")
("class" "banner shadow") ("class" "banner shadow")
("loading" "lazy")) ("loading" "lazy"))
(text "{%- endif %} {%- endmacro %} {% macro community_listing_card(community) -%}") (text "{%- endif %} {%- endmacro %} {% macro community_listing_card(community) -%}")
(a (a
("class" "card secondary w_full flex items_center gap_4") ("class" "card secondary w_full flex items_center gap_4")
@ -69,12 +63,10 @@
(b (b
(text "{{ community.member_count }} ")) (text "{{ community.member_count }} "))
(text "members")))) (text "members"))))
(text "{%- endmacro %} {% macro username(user) -%}") (text "{%- endmacro %} {% macro username(user) -%}")
(div (div
("style" "display: contents") ("style" "display: contents")
(text "{% if user.settings.display_name -%} {{ user.settings.display_name }} {% else %} {{ user.username }} {%- endif %}")) (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) -%}") (text "{%- endmacro %} {% macro likes(id, asset_type, likes=0, dislikes=0, secondary=false, disable_dislikes=false) -%}")
(button (button
("title" "Like") ("title" "Like")
@ -85,7 +77,6 @@
(span (span
(text "{{ likes }}")) (text "{{ likes }}"))
(text "{%- endif %}")) (text "{%- endif %}"))
(text "{% if not user or not user.settings.hide_dislikes and not disable_dislikes -%}") (text "{% if not user or not user.settings.hide_dislikes and not disable_dislikes -%}")
(button (button
("title" "Dislike") ("title" "Dislike")
@ -96,15 +87,21 @@
(span (span
(text "{{ dislikes }}")) (text "{{ dislikes }}"))
(text "{%- endif %}")) (text "{%- endif %}"))
(text "{%- endif %} {%- endmacro %} {% macro full_username(user) -%} {% if user and user.username -%}") (text "{%- endif %} {%- endmacro %} {% macro full_username(user) -%} {% if user and user.username -%}")
(div (div
("class" "flex items_center") ("class" "flex items_center")
(a (a
("href" "/@{{ user.username }}") ("href" "/@{{ user.username }}")
("class" "flush") ("class" "flush flex gap_1")
("style" "font-weight: 600") ("style" "font-weight: 600")
("target" "_top") ("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 -%}") (text "{% if user.permissions|has_banned -%}")
(del ("class" "fade") (text "{{ self::username(user=user) }}")) (del ("class" "fade") (text "{{ self::username(user=user) }}"))
(text "{% else %}") (text "{% else %}")
@ -134,7 +131,6 @@
("style" "display: contents") ("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 "{{ 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 "{%- endmacro %}")
(text "{% macro post_info(post, community) -%}") (text "{% macro post_info(post, community) -%}")
; info about the post: edited, date, etc. ; info about the post: edited, date, etc.
(text "{% if post.context.edited != 0 -%}") (text "{% if post.context.edited != 0 -%}")
@ -200,7 +196,6 @@
(text "{{ icon \"trash-2\" }}")) (text "{{ icon \"trash-2\" }}"))
(text "{%- endif %}") (text "{%- endif %}")
(text "{%- endmacro %}") (text "{%- endmacro %}")
(text "{% macro post_buttons_box(post, community, owner, can_manage_post, show_comments=true) -%}") (text "{% macro post_buttons_box(post, community, owner, can_manage_post, show_comments=true) -%}")
(div (div
("class" "flex justify_between items_center gap_2 w_full") ("class" "flex justify_between items_center gap_2 w_full")

View file

@ -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<State>,
Json(req): Json<CreateCoinTransfer>,
) -> 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()),
}
}

View file

@ -4,6 +4,7 @@ pub mod auth;
pub mod channels; pub mod channels;
pub mod communities; pub mod communities;
pub mod domains; pub mod domains;
pub mod economy;
pub mod journals; pub mod journals;
pub mod letters; pub mod letters;
pub mod notes; pub mod notes;
@ -705,6 +706,8 @@ pub fn routes() -> Router {
.route("/letters/{id}/read", post(letters::add_read_request)) .route("/letters/{id}/read", post(letters::add_read_request))
.route("/letters/sent", get(letters::list_sent_request)) .route("/letters/sent", get(letters::list_sent_request))
.route("/letters/received", get(letters::list_received_request)) .route("/letters/received", get(letters::list_received_request))
// economy
.route("/transfers", post(economy::create_request))
} }
pub fn lw_routes() -> Router { pub fn lw_routes() -> Router {
@ -1212,3 +1215,9 @@ pub struct CreateLetter {
pub content: String, pub content: String,
pub replying_to: String, pub replying_to: String,
} }
#[derive(Deserialize)]
pub struct CreateCoinTransfer {
pub receiver: usize,
pub amount: i32,
}

View file

@ -4,7 +4,7 @@ use crate::{auto_method, DataManager};
use oiseau::{cache::Cache, execute, get, params, query_rows, PostgresRow}; use oiseau::{cache::Cache, execute, get, params, query_rows, PostgresRow};
impl DataManager { 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 { pub(crate) fn get_transfer_from_row(x: &PostgresRow) -> CoinTransfer {
CoinTransfer { CoinTransfer {
id: get!(x->0(i64)) as usize, id: get!(x->0(i64)) as usize,
@ -51,7 +51,7 @@ impl DataManager {
/// Create a new transfer in the database. /// Create a new transfer in the database.
/// ///
/// # Arguments /// # Arguments
/// * `data` - a mock [`Letter`] object to insert /// * `data` - a mock [`CoinTransfer`] object to insert
pub async fn create_transfer(&self, data: CoinTransfer) -> Result<CoinTransfer> { pub async fn create_transfer(&self, data: CoinTransfer) -> Result<CoinTransfer> {
// check values // check values
let mut sender = self.get_user_by_id(data.sender).await?; let mut sender = self.get_user_by_id(data.sender).await?;

View file

@ -106,6 +106,8 @@ pub enum AppScope {
UserCreateProducts, UserCreateProducts,
/// Create letters on behalf of the user. /// Create letters on behalf of the user.
UserCreateLetters, UserCreateLetters,
/// Send coins on behalf of the user.
UserSendCoins,
/// Delete posts owned by the user. /// Delete posts owned by the user.
UserDeletePosts, UserDeletePosts,
/// Delete messages owned by the user. /// Delete messages owned by the user.