add: more mod panel stats add: show user invite in mod panel add:
ability to share to twitter/bluesky
This commit is contained in:
parent
66beef6b1d
commit
2676340fba
8 changed files with 201 additions and 22 deletions
|
@ -182,6 +182,7 @@ version = "1.0.0"
|
||||||
"mod_panel:label.warnings" = "Warnings"
|
"mod_panel:label.warnings" = "Warnings"
|
||||||
"mod_panel:label.create_warning" = "Create warning"
|
"mod_panel:label.create_warning" = "Create warning"
|
||||||
"mod_panel:label.associations" = "Associations"
|
"mod_panel:label.associations" = "Associations"
|
||||||
|
"mod_panel:label.invited_by" = "Invited by"
|
||||||
|
|
||||||
"requests:label.requests" = "Requests"
|
"requests:label.requests" = "Requests"
|
||||||
"requests:label.community_join_request" = "Community join request"
|
"requests:label.community_join_request" = "Community join request"
|
||||||
|
|
|
@ -132,6 +132,7 @@
|
||||||
("class" "card flex flex-col post gap-2 post:{{ post.id }} {% if secondary -%}secondary{%- endif %}")
|
("class" "card flex flex-col post gap-2 post:{{ post.id }} {% if secondary -%}secondary{%- endif %}")
|
||||||
("data-community" "{{ post.community }}")
|
("data-community" "{{ post.community }}")
|
||||||
("data-ownsup" "{{ owner.permissions|has_supporter }}")
|
("data-ownsup" "{{ owner.permissions|has_supporter }}")
|
||||||
|
("data-id" "{{ post.id }}")
|
||||||
("hook" "verify_emojis")
|
("hook" "verify_emojis")
|
||||||
(div
|
(div
|
||||||
("class" "w-full flex gap-2")
|
("class" "w-full flex gap-2")
|
||||||
|
@ -214,7 +215,7 @@
|
||||||
("class" "flush")
|
("class" "flush")
|
||||||
("href" "/post/{{ post.id }}")
|
("href" "/post/{{ post.id }}")
|
||||||
(h2
|
(h2
|
||||||
("id" "post-content:{{ post.id }}")
|
("id" "post_content:{{ post.id }}")
|
||||||
("class" "no_p_margin post_content")
|
("class" "no_p_margin post_content")
|
||||||
("hook" "long")
|
("hook" "long")
|
||||||
(text "{{ post.title }}"))
|
(text "{{ post.title }}"))
|
||||||
|
@ -223,7 +224,6 @@
|
||||||
(text "{% else %}")
|
(text "{% else %}")
|
||||||
(text "{% if not post.context.content_warning -%}")
|
(text "{% if not post.context.content_warning -%}")
|
||||||
(span
|
(span
|
||||||
("id" "post-content:{{ post.id }}")
|
|
||||||
("class" "no_p_margin post_content")
|
("class" "no_p_margin post_content")
|
||||||
("hook" "long")
|
("hook" "long")
|
||||||
|
|
||||||
|
@ -234,7 +234,8 @@
|
||||||
(text "{%- endif %}")
|
(text "{%- endif %}")
|
||||||
|
|
||||||
; content
|
; content
|
||||||
(text "{{ post.content|markdown|safe }} {% if expect_repost -%} {% if repost -%} {{ self::post(post=repost[1], owner=repost[0], secondary=not secondary, community=false, show_community=false, can_manage_post=false) }} {% else %}")
|
(span ("id" "post_content:{{ post.id }}") (text "{{ post.content|markdown|safe }}"))
|
||||||
|
(text "{% if expect_repost -%} {% if repost -%} {{ self::post(post=repost[1], owner=repost[0], secondary=not secondary, community=false, show_community=false, can_manage_post=false) }} {% else %}")
|
||||||
(div
|
(div
|
||||||
("class" "card lowered red flex items-center gap-2")
|
("class" "card lowered red flex items-center gap-2")
|
||||||
(text "{{ icon \"frown\" }}")
|
(text "{{ icon \"frown\" }}")
|
||||||
|
@ -251,7 +252,6 @@
|
||||||
(div
|
(div
|
||||||
("class" "flex flex-col gap-2")
|
("class" "flex flex-col gap-2")
|
||||||
(span
|
(span
|
||||||
("id" "post-content:{{ post.id }}")
|
|
||||||
("class" "no_p_margin post_content")
|
("class" "no_p_margin post_content")
|
||||||
("hook" "long")
|
("hook" "long")
|
||||||
|
|
||||||
|
@ -261,7 +261,8 @@
|
||||||
(text "{% endif %}")
|
(text "{% endif %}")
|
||||||
|
|
||||||
; content
|
; content
|
||||||
(text "{{ post.content|markdown|safe }} {% if expect_repost -%} {% if repost -%} {{ self::post(post=repost[1], owner=repost[0], secondary=not secondary, community=false, show_community=false, can_manage_post=false) }} {% else %}")
|
(span ("id" "post_content:{{ post.id }}") (text "{{ post.content|markdown|safe }}"))
|
||||||
|
(text "{% if expect_repost -%} {% if repost -%} {{ self::post(post=repost[1], owner=repost[0], secondary=not secondary, community=false, show_community=false, can_manage_post=false) }} {% else %}")
|
||||||
(div
|
(div
|
||||||
("class" "card lowered red flex items-center gap-2")
|
("class" "card lowered red flex items-center gap-2")
|
||||||
(text "{{ icon \"frown\" }}")
|
(text "{{ icon \"frown\" }}")
|
||||||
|
@ -338,7 +339,32 @@
|
||||||
(text "{{ icon \"quote\" }}")
|
(text "{{ icon \"quote\" }}")
|
||||||
(span
|
(span
|
||||||
(text "{{ text \"communities:label.quote_post\" }}")))
|
(text "{{ text \"communities:label.quote_post\" }}")))
|
||||||
|
(button
|
||||||
|
("onclick" "trigger('me::intent_twitter', [trigger('me::gen_share', [{ q: '{{ post.context.answering }}', p: '{{ post.id }}' }, 280, true])])")
|
||||||
|
(icon (text "bird"))
|
||||||
|
(span
|
||||||
|
(text "Twitter")))
|
||||||
|
(button
|
||||||
|
("onclick" "trigger('me::intent_bluesky', [trigger('me::gen_share', [{ q: '{{ post.context.answering }}', p: '{{ post.id }}' }, 280, true])])")
|
||||||
|
(icon (text "cloud"))
|
||||||
|
(span
|
||||||
|
(text "BlueSky")))
|
||||||
(text "{%- endif %}")
|
(text "{%- endif %}")
|
||||||
|
(text "{% if user.id != post.owner -%}")
|
||||||
|
(b
|
||||||
|
("class" "title")
|
||||||
|
(text "{{ text \"general:label.safety\" }}"))
|
||||||
|
(button
|
||||||
|
("class" "red")
|
||||||
|
("onclick" "trigger('me::report', ['{{ post.id }}', 'post'])")
|
||||||
|
(text "{{ icon \"flag\" }}")
|
||||||
|
(span
|
||||||
|
(text "{{ text \"general:action.report\" }}")))
|
||||||
|
(text "{%- endif %} {% if (user.id == post.owner) or is_helper or can_manage_post %}")
|
||||||
|
(b
|
||||||
|
("class" "title")
|
||||||
|
(text "{{ text \"general:action.manage\" }}"))
|
||||||
|
; forge stuff
|
||||||
(text "{% if community and community.is_forge -%} {% if post.is_open -%}")
|
(text "{% if community and community.is_forge -%} {% if post.is_open -%}")
|
||||||
(button
|
(button
|
||||||
("class" "green")
|
("class" "green")
|
||||||
|
@ -354,20 +380,7 @@
|
||||||
(span
|
(span
|
||||||
(text "{{ text \"forge:action.reopen\" }}")))
|
(text "{{ text \"forge:action.reopen\" }}")))
|
||||||
(text "{%- endif %} {%- endif %}")
|
(text "{%- endif %} {%- endif %}")
|
||||||
(text "{% if user.id != post.owner -%}")
|
; owner stuff
|
||||||
(b
|
|
||||||
("class" "title")
|
|
||||||
(text "{{ text \"general:label.safety\" }}"))
|
|
||||||
(button
|
|
||||||
("class" "red")
|
|
||||||
("onclick" "trigger('me::report', ['{{ post.id }}', 'post'])")
|
|
||||||
(text "{{ icon \"flag\" }}")
|
|
||||||
(span
|
|
||||||
(text "{{ text \"general:action.report\" }}")))
|
|
||||||
(text "{%- endif %} {% if (user.id == post.owner) or is_helper or can_manage_post %}")
|
|
||||||
(b
|
|
||||||
("class" "title")
|
|
||||||
(text "{{ text \"general:action.manage\" }}"))
|
|
||||||
(text "{% if user.id == post.owner -%}")
|
(text "{% if user.id == post.owner -%}")
|
||||||
(a
|
(a
|
||||||
("href" "/post/{{ post.id }}#/edit")
|
("href" "/post/{{ post.id }}#/edit")
|
||||||
|
@ -675,6 +688,7 @@
|
||||||
(span
|
(span
|
||||||
("class" "no_p_margin")
|
("class" "no_p_margin")
|
||||||
("style" "font-weight: 500")
|
("style" "font-weight: 500")
|
||||||
|
("id" "question_content:{{ question.id }}")
|
||||||
(text "{{ question.content|markdown|safe }}"))
|
(text "{{ question.content|markdown|safe }}"))
|
||||||
; question drawings
|
; question drawings
|
||||||
(text "{{ self::post_media(upload_ids=question.drawings) }}")
|
(text "{{ self::post_media(upload_ids=question.drawings) }}")
|
||||||
|
|
|
@ -202,6 +202,20 @@
|
||||||
(text "{% for user in associations -%}")
|
(text "{% for user in associations -%}")
|
||||||
(text "{{ components::user_plate(user=user, show_menu=false) }}")
|
(text "{{ components::user_plate(user=user, show_menu=false) }}")
|
||||||
(text "{%- endfor %}")))
|
(text "{%- endfor %}")))
|
||||||
|
(text "{% if invite -%}")
|
||||||
|
(div
|
||||||
|
("class" "card-nest w-full")
|
||||||
|
(div
|
||||||
|
("class" "card small flex items-center justify-between gap-2")
|
||||||
|
(div
|
||||||
|
("class" "flex items-center gap-2")
|
||||||
|
(text "{{ icon \"ticket\" }}")
|
||||||
|
(span
|
||||||
|
(text "{{ text \"mod_panel:label.invited_by\" }}"))))
|
||||||
|
(div
|
||||||
|
("class" "card lowered flex flex-wrap gap-2")
|
||||||
|
(text "{{ components::user_plate(user=invite[0], show_menu=false) }}")))
|
||||||
|
(text "{%- endif %}")
|
||||||
(div
|
(div
|
||||||
("class" "card-nest w-full")
|
("class" "card-nest w-full")
|
||||||
(div
|
(div
|
||||||
|
|
|
@ -29,6 +29,15 @@
|
||||||
(b
|
(b
|
||||||
(text "Socket tasks: "))
|
(text "Socket tasks: "))
|
||||||
(span
|
(span
|
||||||
(text "{{ (active_users_chats + active_users) * 3 }}")))))))
|
(text "{{ (active_users_chats + active_users) * 3 }}"))))
|
||||||
|
|
||||||
|
(hr)
|
||||||
|
(ul
|
||||||
|
(li (b (text "Users: ")) (span (text "{{ table_users }}")))
|
||||||
|
(li (b (text "IP bans: ")) (span (text "{{ table_ipbans }}")))
|
||||||
|
(li (b (text "Invite codes: ")) (span (text "{{ table_invite_codes }}")))
|
||||||
|
(li (b (text "Posts: ")) (span (text "{{ table_posts }}")))
|
||||||
|
(li (b (text "Uploads: ")) (span (text "{{ table_uploads }}")))
|
||||||
|
(li (b (text "Communities: ")) (span (text "{{ table_communities }}")))))))
|
||||||
|
|
||||||
(text "{% endblock %}")
|
(text "{% endblock %}")
|
||||||
|
|
|
@ -1227,7 +1227,14 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
|
||||||
).text();
|
).text();
|
||||||
|
|
||||||
self.IO_DATA_WAITING = false;
|
self.IO_DATA_WAITING = false;
|
||||||
self.IO_DATA_ELEMENT.querySelector("[ui_ident=loading_skel]").remove();
|
|
||||||
|
const loading_skel = self.IO_DATA_ELEMENT.querySelector(
|
||||||
|
"[ui_ident=loading_skel]",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (loading_skel) {
|
||||||
|
loading_skel.remove();
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
text.includes(`!<!-- observer_disconnect_${window.BUILD_CODE} -->`)
|
text.includes(`!<!-- observer_disconnect_${window.BUILD_CODE} -->`)
|
||||||
|
|
|
@ -531,6 +531,78 @@
|
||||||
return out;
|
return out;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// share intents
|
||||||
|
self.define(
|
||||||
|
"gen_share",
|
||||||
|
(
|
||||||
|
_,
|
||||||
|
ids = { q: "0", p: "0" },
|
||||||
|
target_length = 280,
|
||||||
|
include_link = true,
|
||||||
|
) => {
|
||||||
|
const part_1 = (
|
||||||
|
document.getElementById(`question_content:${ids.q}`) || {
|
||||||
|
innerText: "",
|
||||||
|
}
|
||||||
|
).innerText;
|
||||||
|
|
||||||
|
const part_2 = document.getElementById(
|
||||||
|
`post_content:${ids.p}`,
|
||||||
|
).innerText;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
const link =
|
||||||
|
include_link !== false
|
||||||
|
? `${window.location.origin}/post/${ids.p}`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const link_size = link.length;
|
||||||
|
target_length -= link_size;
|
||||||
|
|
||||||
|
let out = "";
|
||||||
|
const separator = " — ";
|
||||||
|
|
||||||
|
const part_2_size = target_length / 2 - 1;
|
||||||
|
const sep_size = separator.length;
|
||||||
|
const part_1_size = target_length / 2 - sep_size;
|
||||||
|
|
||||||
|
if (part_1 !== "") {
|
||||||
|
out +=
|
||||||
|
part_1_size > part_1.length
|
||||||
|
? part_1
|
||||||
|
: part_1.substring(0, part_1_size);
|
||||||
|
|
||||||
|
out += separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part_2 !== "") {
|
||||||
|
out +=
|
||||||
|
part_2_size > part_2.length
|
||||||
|
? part_2
|
||||||
|
: part_2.substring(0, part_2_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
out += ` ${link}`;
|
||||||
|
return out;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.define("intent_twitter", (_, text) => {
|
||||||
|
window.open(
|
||||||
|
`https://twitter.com/intent/tweet?text=${encodeURIComponent(text)}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
trigger("atto::toast", ["success", "Opened intent!"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.define("intent_bluesky", (_, text) => {
|
||||||
|
window.open(
|
||||||
|
`https://bsky.app/intent/compose?text=${encodeURIComponent(text)}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
trigger("atto::toast", ["success", "Opened intent!"]);
|
||||||
|
});
|
||||||
|
|
||||||
// token switcher
|
// token switcher
|
||||||
self.define("append_associations", (_, tokens) => {
|
self.define("append_associations", (_, tokens) => {
|
||||||
fetch("/api/v1/auth/user/me/append_associations", {
|
fetch("/api/v1/auth/user/me/append_associations", {
|
||||||
|
|
|
@ -194,10 +194,23 @@ pub async fn manage_profile_request(
|
||||||
out
|
out
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let invite_code = if profile.invite_code != 0 {
|
||||||
|
match data.0.get_invite_code_by_id(profile.invite_code).await {
|
||||||
|
Ok(i) => match data.0.get_user_by_id(i.owner).await {
|
||||||
|
Ok(u) => Some((u, i)),
|
||||||
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||||
|
},
|
||||||
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let lang = get_lang!(jar, data.0);
|
let lang = get_lang!(jar, data.0);
|
||||||
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
|
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
|
||||||
|
|
||||||
context.insert("profile", &profile);
|
context.insert("profile", &profile);
|
||||||
|
context.insert("invite", &invite_code);
|
||||||
context.insert("associations", &associations);
|
context.insert("associations", &associations);
|
||||||
|
|
||||||
// return
|
// return
|
||||||
|
@ -298,6 +311,35 @@ pub async fn stats_request(jar: CookieJar, Extension(data): Extension<State>) ->
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
context.insert(
|
||||||
|
"table_users",
|
||||||
|
&data.0.get_table_row_count("users").await.unwrap_or(0),
|
||||||
|
);
|
||||||
|
context.insert(
|
||||||
|
"table_posts",
|
||||||
|
&data.0.get_table_row_count("posts").await.unwrap_or(0),
|
||||||
|
);
|
||||||
|
context.insert(
|
||||||
|
"table_invite_codes",
|
||||||
|
&data
|
||||||
|
.0
|
||||||
|
.get_table_row_count("invite_codes")
|
||||||
|
.await
|
||||||
|
.unwrap_or(0),
|
||||||
|
);
|
||||||
|
context.insert(
|
||||||
|
"table_uploads",
|
||||||
|
&data.0.get_table_row_count("uploads").await.unwrap_or(0),
|
||||||
|
);
|
||||||
|
context.insert(
|
||||||
|
"table_communities",
|
||||||
|
&data.0.get_table_row_count("communities").await.unwrap_or(0),
|
||||||
|
);
|
||||||
|
context.insert(
|
||||||
|
"table_ipbans",
|
||||||
|
&data.0.get_table_row_count("ipbans").await.unwrap_or(0),
|
||||||
|
);
|
||||||
|
|
||||||
// return
|
// return
|
||||||
Ok(Html(data.1.render("mod/stats.html", &context).unwrap()))
|
Ok(Html(data.1.render("mod/stats.html", &context).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::model::{Error, Result};
|
use crate::model::{Error, Result};
|
||||||
use super::{DataManager, drivers::common};
|
use super::{DataManager, drivers::common};
|
||||||
use oiseau::{cache::Cache, execute};
|
use oiseau::{cache::Cache, execute, query_row, params};
|
||||||
|
|
||||||
pub const NAME_REGEX: &str = r"[^\w_\-\.,!]+";
|
pub const NAME_REGEX: &str = r"[^\w_\-\.,!]+";
|
||||||
|
|
||||||
|
@ -52,6 +52,26 @@ impl DataManager {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_table_row_count(&self, table: &str) -> Result<i32> {
|
||||||
|
let conn = match self.0.connect().await {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = query_row!(
|
||||||
|
&conn,
|
||||||
|
&format!("SELECT COUNT(*)::int FROM {}", table),
|
||||||
|
params![],
|
||||||
|
|x| Ok(x.get::<usize, i32>(0))
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = res {
|
||||||
|
return Err(Error::DatabaseError(e.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res.unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue