add: store ad clicked state in cookies
This commit is contained in:
parent
83971b3d20
commit
befd9096b1
5 changed files with 119 additions and 65 deletions
|
@ -24,32 +24,18 @@
|
|||
(text "{{ icon \"ellipsis\" }}"))
|
||||
(div
|
||||
("class" "inner")
|
||||
(text "{% if user.id == channel.owner -%} {% if selected_community == 0 %}")
|
||||
(button
|
||||
("class" "lowered small")
|
||||
("onclick" "trigger('atto::copy_text', ['{{ channel.id }}'])")
|
||||
(icon (text "copy"))
|
||||
(str (text "general:action.copy_id")))
|
||||
(text "{% if user.id == channel.owner or can_manage_channels -%}")
|
||||
; owner/manager controls
|
||||
(button
|
||||
("onclick" "add_member('{{ channel.id }}')")
|
||||
(text "{{ icon \"user-plus\" }}")
|
||||
(span
|
||||
(text "{{ text \"chats:action.add_someone\" }}")))
|
||||
; mute/unmute
|
||||
(button
|
||||
("class" "lowered small {% if channel.id in user.channel_mutes -%} hidden {%- endif %}")
|
||||
("ui_ident" "channel.mute:{{ channel.id }}")
|
||||
("onclick" "mute_channel('{{ channel.id }}')")
|
||||
(icon (text "bell-off"))
|
||||
(span
|
||||
(str (text "chats:action.mute"))))
|
||||
(button
|
||||
("class" "lowered small {% if not channel.id in user.channel_mutes -%} hidden {%- endif %}")
|
||||
("ui_ident" "channel.unmute:{{ channel.id }}")
|
||||
("onclick" "mute_channel('{{ channel.id }}', false)")
|
||||
(icon (text "bell-ring"))
|
||||
(span
|
||||
(str (text "chats:action.unmute"))))
|
||||
; ...
|
||||
(text "{%- endif %}")
|
||||
(button
|
||||
("class" "lowered small")
|
||||
("onclick" "update_channel_title('{{ channel.id }}')")
|
||||
(text "{{ icon \"pencil\" }}")
|
||||
(span
|
||||
|
@ -60,14 +46,32 @@
|
|||
(text "{{ icon \"trash\" }}")
|
||||
(span
|
||||
(text "{{ text \"general:action.delete\" }}")))
|
||||
(text "{% elif selected_community == 0 %}")
|
||||
(text "{%- endif %} {% if selected_community == 0 %}")
|
||||
; mute/unmute
|
||||
(button
|
||||
("class" "{% if channel.id in user.channel_mutes -%} hidden {%- endif %}")
|
||||
("ui_ident" "channel.mute:{{ channel.id }}")
|
||||
("onclick" "mute_channel('{{ channel.id }}')")
|
||||
(icon (text "bell-off"))
|
||||
(span
|
||||
(str (text "chats:action.mute"))))
|
||||
(button
|
||||
("class" "{% if not channel.id in user.channel_mutes -%} hidden {%- endif %}")
|
||||
("ui_ident" "channel.unmute:{{ channel.id }}")
|
||||
("onclick" "mute_channel('{{ channel.id }}', false)")
|
||||
(icon (text "bell-ring"))
|
||||
(span
|
||||
(str (text "chats:action.unmute"))))
|
||||
; ...
|
||||
(text "{% if user.id != channel.owner -%}")
|
||||
; group chat member controls
|
||||
(button
|
||||
("onclick" "kick_member('{{ channel.id }}', '{{ user.id }}')")
|
||||
("class" "red")
|
||||
(text "{{ icon \"door-open\" }}")
|
||||
(span
|
||||
(text "{{ text \"chats:action.leave\" }}")))
|
||||
(text "{%- endif %}"))))
|
||||
(text "{%- endif %} {%- endif %}"))))
|
||||
(text "{% endfor %}"))
|
||||
(text "{% if selected_community == 0 and selected_channel -%}")
|
||||
(div
|
||||
|
|
|
@ -1210,6 +1210,8 @@
|
|||
(text "{%- endif %}"))
|
||||
(div
|
||||
("class" "flex gap_2 hidden")
|
||||
("onclick" "window.EMOJI_PICKER_REACTION_MESSAGE_ID = '{{ message.id }}'")
|
||||
(text "{{ self::emoji_picker(element_id=\"react_emoji_picker_field\", render_dialog=false, render_button=true, small=true) }}")
|
||||
(text "{{ self::message_actions(owner=user, message=message, can_manage_message=can_manage_message) }}")))
|
||||
(text "{%- endif %}")
|
||||
(div
|
||||
|
@ -1232,14 +1234,12 @@
|
|||
("ui_ident" "emoji_{{ emoji }}")
|
||||
("onclick" "trigger('me::message_react', [event.target.parentElement.parentElement, '{{ message.id }}', '{{ emoji }}'])")
|
||||
(span (text "{{ emoji|emojis|safe }} {{ num }}")))
|
||||
(text "{%- endfor %}")
|
||||
|
||||
(div
|
||||
("class" "hidden")
|
||||
(text "{{ self::emoji_picker(element_id=\"react_emoji_picker_field\", render_dialog=false, render_button=true, small=true) }}"))))
|
||||
(text "{%- endfor %}")))
|
||||
(text "{% if grouped -%}")
|
||||
(div
|
||||
("class" "hidden")
|
||||
("class" "hidden flex gap_2 items_center")
|
||||
("onclick" "window.EMOJI_PICKER_REACTION_MESSAGE_ID = '{{ message.id }}'")
|
||||
(text "{{ self::emoji_picker(element_id=\"react_emoji_picker_field\", render_dialog=false, render_button=true, small=true) }}")
|
||||
(text "{{ self::message_actions(owner=user, message=message, can_manage_message=can_manage_message) }}"))
|
||||
(text "{%- endif %}"))))
|
||||
|
||||
|
@ -2740,7 +2740,7 @@
|
|||
(text "{%- endmacro %}")
|
||||
|
||||
(text "{% macro advertisement(size=\"Leaderboard\") -%}")
|
||||
(text "{% if not is_supporter and config.enable_user_ads -%}")
|
||||
(text "{% if user and not is_supporter and config.enable_user_ads -%}")
|
||||
(object ("class" "tetratto_ad") ("data-ad-size" "{{ size }}"))
|
||||
(text "{%- endif %}")
|
||||
(text "{%- endmacro %}")
|
||||
|
|
|
@ -6,8 +6,9 @@ use crate::{
|
|||
};
|
||||
use axum::{
|
||||
extract::Path,
|
||||
response::{IntoResponse, Redirect},
|
||||
response::{Html, IntoResponse},
|
||||
Extension, Json,
|
||||
http::StatusCode,
|
||||
};
|
||||
use tetratto_core::model::{
|
||||
economy::UserAd,
|
||||
|
@ -139,8 +140,56 @@ pub async fn click_request(
|
|||
let data = &(data.read().await).0;
|
||||
let user = get_user_from_token!(jar, data);
|
||||
|
||||
let bad_return = (
|
||||
StatusCode::FOUND,
|
||||
[
|
||||
(
|
||||
"Set-Cookie".to_string(),
|
||||
format!(
|
||||
"Atto-Clicked=true; Path=/api/v1/ads/host/{host}/{id}/click; Max-Age=86400"
|
||||
),
|
||||
),
|
||||
("Location".to_string(), data.0.0.host.clone()),
|
||||
],
|
||||
Html(""),
|
||||
);
|
||||
|
||||
if jar.get("Atto-Clicked").is_some() {
|
||||
// we've already clicked this ad, don't charge
|
||||
match data.get_ad_by_id(id).await {
|
||||
Ok(x) => {
|
||||
return (
|
||||
StatusCode::FOUND,
|
||||
[
|
||||
(
|
||||
"Set-Cookie".to_string(),
|
||||
format!(
|
||||
"Atto-Clicked=true; Path=/api/v1/ads/host/{host}/{id}/click; Max-Age=86400"
|
||||
),
|
||||
),
|
||||
("Location".to_string(), x.target),
|
||||
],
|
||||
Html(""),
|
||||
);
|
||||
}
|
||||
Err(_) => return bad_return,
|
||||
}
|
||||
}
|
||||
|
||||
match data.ad_click(host, id, user).await {
|
||||
Ok(t) => Redirect::to(&t),
|
||||
Err(_) => Redirect::to(&data.0.0.host),
|
||||
Ok(t) => (
|
||||
StatusCode::FOUND,
|
||||
[
|
||||
(
|
||||
"Set-Cookie".to_string(),
|
||||
format!(
|
||||
"Atto-Clicked=true; Path=/api/v1/ads/host/{host}/{id}/click; Max-Age=86400"
|
||||
),
|
||||
),
|
||||
("Location".to_string(), t),
|
||||
],
|
||||
Html(""),
|
||||
),
|
||||
Err(_) => bad_return,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -348,12 +348,25 @@ pub async fn channels_request(
|
|||
None
|
||||
};
|
||||
|
||||
let membership = match data
|
||||
.0
|
||||
.get_membership_by_owner_community(user.id, community)
|
||||
.await
|
||||
{
|
||||
Ok(m) => m,
|
||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||
};
|
||||
|
||||
let can_manage_channels = membership.role.check(CommunityPermission::MANAGE_CHANNELS)
|
||||
| user.permissions.check(FinePermission::MANAGE_CHANNELS);
|
||||
|
||||
let lang = get_lang!(jar, data.0);
|
||||
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
|
||||
|
||||
context.insert("channels", &channels);
|
||||
context.insert("page", &props.page);
|
||||
|
||||
context.insert("can_manage_channels", &can_manage_channels);
|
||||
context.insert("members", &members);
|
||||
context.insert("channel", &channel);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
|||
};
|
||||
use crate::cookie::CookieJar;
|
||||
use tetratto_core::model::{
|
||||
economy::{CoinTransferMethod, UserAd, UserAdSize},
|
||||
economy::{CoinTransferMethod, UserAdSize},
|
||||
Error,
|
||||
};
|
||||
use crate::{assets::initial_context, get_lang, get_user_from_token, State};
|
||||
|
@ -254,18 +254,17 @@ pub async fn random_ad_request(
|
|||
Query(props): Query<RandomAdQuery>,
|
||||
) -> impl IntoResponse {
|
||||
let data = data.read().await;
|
||||
let headers = [(
|
||||
"content-security-policy",
|
||||
"default-src 'self' *.spotify.com musicbrainz.org; img-src * data:; media-src *; font-src *; style-src 'unsafe-inline' 'self' *; script-src 'self' 'unsafe-inline' *; worker-src * blob:; object-src 'self' *; upgrade-insecure-requests; connect-src * localhost; frame-src 'self' blob: *; frame-ancestors *",
|
||||
)];
|
||||
|
||||
let ad = match data.0.random_ad_charged(props.size.clone()).await {
|
||||
Ok(x) => x,
|
||||
Err(_) => UserAd {
|
||||
id: 0,
|
||||
created: 0,
|
||||
upload_id: 0,
|
||||
owner: data.0.0.0.system_user,
|
||||
target: data.0.0.0.host.clone(),
|
||||
last_charge_time: 0,
|
||||
is_running: true,
|
||||
size: props.size,
|
||||
},
|
||||
Err(_) => {
|
||||
// no ad found, show nothing
|
||||
return (headers, Html(String::new()));
|
||||
}
|
||||
};
|
||||
|
||||
let mut context = tera::Context::new();
|
||||
|
@ -276,10 +275,7 @@ pub async fn random_ad_request(
|
|||
|
||||
// return
|
||||
(
|
||||
[(
|
||||
"content-security-policy",
|
||||
"default-src 'self' *.spotify.com musicbrainz.org; img-src * data:; media-src *; font-src *; style-src 'unsafe-inline' 'self' *; script-src 'self' 'unsafe-inline' *; worker-src * blob:; object-src 'self' *; upgrade-insecure-requests; connect-src * localhost; frame-src 'self' blob: *; frame-ancestors *",
|
||||
)],
|
||||
headers,
|
||||
Html(data.1.render("economy/ad.html", &context).unwrap()),
|
||||
)
|
||||
}
|
||||
|
@ -291,19 +287,17 @@ pub async fn known_ad_request(
|
|||
Path(id): Path<usize>,
|
||||
) -> impl IntoResponse {
|
||||
let data = data.read().await;
|
||||
let headers = [
|
||||
(
|
||||
"content-security-policy",
|
||||
"default-src 'self' *.spotify.com musicbrainz.org; img-src * data:; media-src *; font-src *; style-src 'unsafe-inline' 'self' *; script-src 'self' 'unsafe-inline' *; worker-src * blob:; object-src 'self' *; upgrade-insecure-requests; connect-src * localhost; frame-src 'self' blob: *; frame-ancestors *",
|
||||
),
|
||||
("Cache-Control", "no-cache"),
|
||||
];
|
||||
|
||||
let ad = match data.0.get_ad_by_id(id).await {
|
||||
Ok(x) => x,
|
||||
Err(_) => UserAd {
|
||||
// polyfill ad
|
||||
id: 0,
|
||||
created: 0,
|
||||
upload_id: 0,
|
||||
owner: data.0.0.0.system_user,
|
||||
target: data.0.0.0.host.clone(),
|
||||
last_charge_time: 0,
|
||||
is_running: true,
|
||||
size: props.size,
|
||||
},
|
||||
Err(_) => return (headers, Html(String::new())),
|
||||
};
|
||||
|
||||
let mut context = tera::Context::new();
|
||||
|
@ -314,13 +308,7 @@ pub async fn known_ad_request(
|
|||
|
||||
// return
|
||||
(
|
||||
[
|
||||
(
|
||||
"content-security-policy",
|
||||
"default-src 'self' *.spotify.com musicbrainz.org; img-src * data:; media-src *; font-src *; style-src 'unsafe-inline' 'self' *; script-src 'self' 'unsafe-inline' *; worker-src * blob:; object-src 'self' *; upgrade-insecure-requests; connect-src * localhost; frame-src 'self' blob: *; frame-ancestors *",
|
||||
),
|
||||
("Cache-Control", "no-cache"),
|
||||
],
|
||||
headers,
|
||||
Html(data.1.render("economy/ad.html", &context).unwrap()),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue