mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 04:55:42 +09:00
fix(push): drop Fluxer badge on self-hosted instances (#3400)
This commit is contained in:
1 parent
be314788b3
commit
af7724dbf6
5 files changed
+104
-20
No files matched your search
@@ -28,6 +28,7 @@ load() ->
|
||||
env_config() ->
|
||||
#{
|
||||
<<"env">> => env_binary("FLUXER_ENV", <<"development">>),
|
||||
<<"instance">> => #{<<"self_hosted">> => env_bool("FLUXER_SELF_HOSTED", false)},
|
||||
<<"internal">> => env_internal_config(),
|
||||
<<"public">> => env_public_config(),
|
||||
<<"proxy">> => env_proxy_config(),
|
||||
@@ -147,9 +148,10 @@ build_config(RawConfig) ->
|
||||
Nats = get_map(RawConfig, [<<"services">>, <<"nats">>]),
|
||||
Proxy = get_map(RawConfig, [<<"proxy">>]),
|
||||
Public = get_map(RawConfig, [<<"public">>]),
|
||||
Instance = get_map(RawConfig, [<<"instance">>]),
|
||||
lists:foldl(fun maps:merge/2, #{}, [
|
||||
build_core_config(Service, Internal, Nats, Proxy),
|
||||
build_push_config(Service, Public),
|
||||
build_push_config(Service, Public, Instance),
|
||||
build_sharding_config(Service),
|
||||
build_http_config(Service),
|
||||
build_cluster_config(Service, Public),
|
||||
@@ -176,10 +178,11 @@ build_core_config(Service, Internal, Nats, Proxy) ->
|
||||
)
|
||||
}.
|
||||
|
||||
-spec build_push_config(map(), map()) -> config().
|
||||
build_push_config(Service, Public) ->
|
||||
-spec build_push_config(map(), map(), map()) -> config().
|
||||
build_push_config(Service, Public, Instance) ->
|
||||
#{
|
||||
push_enabled => get_bool(Service, <<"push_enabled">>, true),
|
||||
self_hosted => get_bool(Instance, <<"self_hosted">>, false),
|
||||
static_cdn_endpoint => public_endpoint(
|
||||
get_binary(Service, <<"static_cdn_endpoint">>, <<"http://localhost:8088">>), Public
|
||||
),
|
||||
|
||||
@@ -231,7 +231,7 @@ notification_fields(
|
||||
),
|
||||
ChannelIdBin = integer_to_binary(ChannelId),
|
||||
MessageIdBin = integer_to_binary(MessageId),
|
||||
#{
|
||||
with_badge(#{
|
||||
<<"title">> => push_notification:build_notification_title(
|
||||
AuthorName, MessageData, GuildId, GuildName, ChannelName
|
||||
),
|
||||
@@ -239,14 +239,24 @@ notification_fields(
|
||||
MessageData, MarkdownContext
|
||||
),
|
||||
<<"icon">> => push_notification_format:resolve_author_avatar_url(AuthorData),
|
||||
<<"badge">> => push_utils:construct_static_asset_url(
|
||||
<<"marketing/branding/symbol-white.svg">>
|
||||
),
|
||||
<<"tag">> => <<"channel:", ChannelIdBin/binary, ":", MessageIdBin/binary>>,
|
||||
<<"notification_tag">> => <<"channel:", ChannelIdBin/binary>>,
|
||||
<<"url">> => push_notification_format:build_url(GuildId, ChannelId, MessageId),
|
||||
<<"image_url">> => nullable(push_notification_format:extract_image_url(MessageData))
|
||||
}.
|
||||
}).
|
||||
|
||||
-spec with_badge(map()) -> map().
|
||||
with_badge(Fields) ->
|
||||
case fluxer_gateway_env:get(self_hosted) of
|
||||
true ->
|
||||
Fields;
|
||||
_ ->
|
||||
Fields#{
|
||||
<<"badge">> => push_utils:construct_static_asset_url(
|
||||
<<"marketing/branding/symbol-white.svg">>
|
||||
)
|
||||
}
|
||||
end.
|
||||
|
||||
-spec thread_job_fields(map(), binary() | undefined) -> map().
|
||||
thread_job_fields(MessageData, ChannelName) ->
|
||||
@@ -329,9 +339,15 @@ outbox_job(Subject, Job, Body, Meta) ->
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
with_endpoint_env(Fun) ->
|
||||
with_endpoint_env(false, Fun).
|
||||
|
||||
with_endpoint_env(SelfHosted, Fun) ->
|
||||
ok = meck:new(fluxer_gateway_env, [passthrough, no_link]),
|
||||
try
|
||||
ok = meck:expect(fluxer_gateway_env, get, fun endpoint_env_meck/1),
|
||||
ok = meck:expect(fluxer_gateway_env, get, fun
|
||||
(self_hosted) -> SelfHosted;
|
||||
(Key) -> endpoint_env_meck(Key)
|
||||
end),
|
||||
Fun()
|
||||
after
|
||||
meck:unload(fluxer_gateway_env)
|
||||
@@ -397,7 +413,9 @@ encoded_message_job(MessageData, ChannelName) ->
|
||||
push_notification_format, resolve_author_avatar_url, fun(_) -> <<"icon">> end
|
||||
),
|
||||
ok = meck:expect(push_utils, construct_static_asset_url, fun(_) -> <<"badge">> end),
|
||||
Job = message_job(MessageData, #{}, 5, 6, 7, <<"Guild">>, ChannelName),
|
||||
Job = with_endpoint_env(fun() ->
|
||||
message_job(MessageData, #{}, 5, 6, 7, <<"Guild">>, ChannelName)
|
||||
end),
|
||||
json:decode(iolist_to_binary(json:encode(Job)))
|
||||
after
|
||||
meck:unload(push_utils),
|
||||
@@ -507,12 +525,34 @@ notification_fields_omit_sensitive_attachment_image_test() ->
|
||||
Fields = test_notification_fields(MessageData, 123, <<"Server">>, <<"general">>),
|
||||
?assertEqual(null, maps:get(<<"image_url">>, Fields)).
|
||||
|
||||
notification_fields_include_the_fluxer_badge_test() ->
|
||||
MessageData = #{<<"content">> => <<"Hi">>, <<"mentions">> => []},
|
||||
Fields = test_notification_fields(MessageData, 123, <<"Server">>, <<"general">>),
|
||||
?assertEqual(
|
||||
<<"https://static.example/marketing/branding/symbol-white.svg">>,
|
||||
maps:get(<<"badge">>, Fields)
|
||||
).
|
||||
|
||||
notification_fields_omit_the_badge_on_self_hosted_instances_test() ->
|
||||
MessageData = #{<<"content">> => <<"Hi">>, <<"mentions">> => []},
|
||||
Fields = test_notification_fields(
|
||||
MessageData, 123, <<"Server">>, <<"general">>, #{}, true
|
||||
),
|
||||
?assertNot(maps:is_key(<<"badge">>, Fields)).
|
||||
|
||||
test_notification_fields(MessageData, GuildId, GuildName, ChannelName) ->
|
||||
test_notification_fields(MessageData, GuildId, GuildName, ChannelName, #{}).
|
||||
|
||||
test_notification_fields(MessageData, GuildId, GuildName, ChannelName, MarkdownContext) ->
|
||||
test_notification_fields(
|
||||
MessageData, GuildId, GuildName, ChannelName, MarkdownContext, false
|
||||
).
|
||||
|
||||
test_notification_fields(
|
||||
MessageData, GuildId, GuildName, ChannelName, MarkdownContext, SelfHosted
|
||||
) ->
|
||||
Author = #{<<"id">> => <<"42">>, <<"username">> => <<"Alice">>, <<"avatar">> => null},
|
||||
with_endpoint_env(fun() ->
|
||||
with_endpoint_env(SelfHosted, fun() ->
|
||||
notification_fields(
|
||||
MessageData#{<<"author">> => Author},
|
||||
MarkdownContext,
|
||||
|
||||
@@ -74,6 +74,14 @@ blank_env_values_fall_back_to_the_defaults_test() ->
|
||||
end
|
||||
).
|
||||
|
||||
self_hosted_follows_the_fluxer_self_hosted_env_test() ->
|
||||
with_env("FLUXER_SELF_HOSTED", "", fun() ->
|
||||
?assertEqual(false, maps:get(self_hosted, fluxer_gateway_config:load()))
|
||||
end),
|
||||
with_env("FLUXER_SELF_HOSTED", "true", fun() ->
|
||||
?assertEqual(true, maps:get(self_hosted, fluxer_gateway_config:load()))
|
||||
end).
|
||||
|
||||
pinned_guild_ids_reject_non_snowflakes_test() ->
|
||||
with_env("FLUXER_GATEWAY_PINNED_GUILD_IDS", "1100000000000000001,ab", fun() ->
|
||||
?assertError({invalid_pinned_guild_id, "ab"}, fluxer_gateway_config:load())
|
||||
|
||||
+11
-1
@@ -36,7 +36,8 @@ pub struct NotificationFields {
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub icon: String,
|
||||
pub badge: String,
|
||||
#[serde(default)]
|
||||
pub badge: Option<String>,
|
||||
pub tag: String,
|
||||
pub notification_tag: String,
|
||||
pub url: String,
|
||||
@@ -165,6 +166,15 @@ mod tests {
|
||||
assert_eq!(job.channel_name, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_job_without_a_badge_decodes() {
|
||||
let job = decode_message(
|
||||
br#"{"v":1,"guild_id":"5","channel_id":"6","message_id":"7","notification":{"title":"t","body":"b","icon":"i","tag":"x","notification_tag":"y","url":"/u"},"user_ids":["8"]}"#,
|
||||
)
|
||||
.expect("the job decodes");
|
||||
assert_eq!(job.notification.badge, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_thread_job_decodes_its_optional_fields() {
|
||||
let job = decode_message(
|
||||
|
||||
@@ -65,27 +65,28 @@ pub fn web_push_message(job: &MessageJob, target_user_id: &str, badge_count: u32
|
||||
"has_media": image_url.is_some(),
|
||||
});
|
||||
merge_thread_fields(&mut data, job);
|
||||
let notification = json!({
|
||||
let badge = fields.badge.as_deref();
|
||||
let mut notification = json!({
|
||||
"title": fields.title,
|
||||
"body": fields.body,
|
||||
"icon": fields.icon,
|
||||
"badge": fields.badge,
|
||||
"tag": fields.tag,
|
||||
"navigate": fields.url,
|
||||
"app_badge": badge_count.to_string(),
|
||||
"data": data,
|
||||
});
|
||||
insert_present(&mut notification, "badge", badge);
|
||||
let mut envelope = json!({
|
||||
"web_push": WEB_PUSH_MARKER,
|
||||
"notification": notification,
|
||||
"title": fields.title,
|
||||
"body": fields.body,
|
||||
"icon": fields.icon,
|
||||
"badge": fields.badge,
|
||||
"tag": fields.tag,
|
||||
"data": data,
|
||||
});
|
||||
merge_image_fields(&mut envelope, image_url);
|
||||
insert_present(&mut envelope, "badge", badge);
|
||||
insert_present(&mut envelope, "image_url", image_url);
|
||||
envelope
|
||||
}
|
||||
|
||||
@@ -617,11 +618,11 @@ fn first_text<'a>(envelope: &'a Value, key: &str) -> Option<&'a str> {
|
||||
.or_else(|| envelope.get("notification")?.get(key).and_then(non_empty))
|
||||
}
|
||||
|
||||
fn merge_image_fields(target: &mut Value, image_url: Option<&str>) {
|
||||
let (Some(image_url), Some(object)) = (image_url, target.as_object_mut()) else {
|
||||
fn insert_present(target: &mut Value, key: &str, value: Option<&str>) {
|
||||
let (Some(value), Some(object)) = (value, target.as_object_mut()) else {
|
||||
return;
|
||||
};
|
||||
object.insert("image_url".to_owned(), image_url.into());
|
||||
object.insert(key.to_owned(), value.into());
|
||||
}
|
||||
|
||||
fn non_empty(value: &Value) -> Option<&str> {
|
||||
@@ -651,7 +652,7 @@ mod tests {
|
||||
title: "Elias".to_owned(),
|
||||
body: "see you tomorrow".to_owned(),
|
||||
icon: "https://media.fluxer.app/avatars/1/a.webp".to_owned(),
|
||||
badge: "https://media.fluxer.app/badge.png".to_owned(),
|
||||
badge: Some("https://media.fluxer.app/badge.png".to_owned()),
|
||||
tag: format!("channel:{CHANNEL_ID}:{MESSAGE_ID}"),
|
||||
notification_tag: format!("channel:{CHANNEL_ID}"),
|
||||
url: format!("/channels/@me/{CHANNEL_ID}"),
|
||||
@@ -726,6 +727,28 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_message_with_a_badge_sends_it_in_both_places() {
|
||||
let envelope = web_push_message(&message_job(None), USER_ID, 3);
|
||||
assert_eq!(
|
||||
envelope["badge"],
|
||||
json!("https://media.fluxer.app/badge.png")
|
||||
);
|
||||
assert_eq!(
|
||||
envelope["notification"]["badge"],
|
||||
json!("https://media.fluxer.app/badge.png")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_message_without_a_badge_leaves_the_key_out() {
|
||||
let mut job = message_job(None);
|
||||
job.notification.badge = None;
|
||||
let envelope = web_push_message(&job, USER_ID, 3);
|
||||
assert!(envelope.get("badge").is_none());
|
||||
assert!(envelope["notification"].get("badge").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_message_outside_a_thread_carries_no_thread_keys() {
|
||||
let envelope = web_push_message(&message_job(None), USER_ID, 3);
|
||||
|
||||
Reference in new issue
Block a user