add: better profile settings mobile ui

add: allow Atto-Grant cookie to act auth token for oauth grants
This commit is contained in:
trisua 2025-06-13 10:32:09 -04:00
parent 5844d23399
commit ca8f510a3a
4 changed files with 90 additions and 38 deletions

View file

@ -77,7 +77,26 @@ macro_rules! create_dir_if_not_exists {
#[macro_export]
macro_rules! get_user_from_token {
($jar:ident, $db:expr) => {{
if let Some(token) = $jar.get("__Secure-atto-token") {
if let Some(token) = $jar.get("Atto-Grant") {
// this allows us to ALSO authenticate with a grant token...
// TODO: require macro to pass a required AppScope to check permission
// TODO: check token verifier
match $db
.get_user_by_grant_token(&tetratto_shared::hash::hash(
token.to_string().replace("Atto-Grant=", ""),
))
.await
{
Ok((_, ua)) => {
if ua.permissions.check_banned() {
Some(tetratto_core::model::auth::User::banned())
} else {
Some(ua)
}
}
Err(_) => None,
}
} else if let Some(token) = $jar.get("__Secure-atto-token") {
match $db
.get_user_by_token(&tetratto_shared::hash::hash(
token.to_string().replace("__Secure-atto-token=", ""),

View file

@ -268,3 +268,37 @@
(icon (text "circle-dot"))
(str (text "forge:tab.tickets"))))
(text "{%- endmacro %}")
(text "{% macro profile_settings_nav_options() -%}")
(a
("data-tab-button" "account")
("class" "active")
("href" "#/account")
(text "{{ icon \"smile\" }}")
(span
(text "{{ text \"settings:tab.account\" }}")))
(a
("data-tab-button" "profile")
("href" "#/profile")
(text "{{ icon \"user-round\" }}")
(span
(text "{{ text \"settings:tab.profile\" }}")))
(a
("data-tab-button" "theme")
("href" "#/theme")
(text "{{ icon \"paint-bucket\" }}")
(span
(text "{{ text \"settings:tab.theme\" }}")))
(a
("data-tab-button" "sessions")
("href" "#/sessions")
(text "{{ icon \"cookie\" }}")
(span
(text "{{ text \"settings:tab.sessions\" }}")))
(a
("data-tab-button" "connections")
("href" "#/connections")
(text "{{ icon \"cable\" }}")
(span
(text "{{ text \"settings:tab.connections\" }}")))
(text "{%- endmacro %}")

View file

@ -1,7 +1,6 @@
(text "{% extends \"root.html\" %} {% block head %}")
(title
(text "Settings - {{ config.name }}"))
(text "{% endblock %} {% block body %} {{ macros::nav() }}")
(main
("class" "flex flex-col gap-2")
@ -12,39 +11,30 @@
(b
(text "Editing other user's settings! Please be careful.")))
(text "{%- endif %}")
; nav
(div
("class" "pillmenu")
(a
("data-tab-button" "account")
("class" "active")
("href" "#/account")
(text "{{ icon \"smile\" }}")
(span
(text "{{ text \"settings:tab.account\" }}")))
(a
("data-tab-button" "profile")
("href" "#/profile")
(text "{{ icon \"user-round\" }}")
(span
(text "{{ text \"settings:tab.profile\" }}")))
(a
("data-tab-button" "theme")
("href" "#/theme")
(text "{{ icon \"paint-bucket\" }}")
(span
(text "{{ text \"settings:tab.theme\" }}")))
(a
("data-tab-button" "sessions")
("href" "#/sessions")
(text "{{ icon \"cookie\" }}")
(span
(text "{{ text \"settings:tab.sessions\" }}")))
(a
("data-tab-button" "connections")
("href" "#/connections")
(text "{{ icon \"cable\" }}")
(span
(text "{{ text \"settings:tab.connections\" }}"))))
("class" "mobile_nav mobile")
; primary nav
(div
("class" "dropdown")
("style" "width: max-content")
(button
("class" "camo raised small")
("onclick" "trigger('atto::hooks::dropdown', [event])")
("exclude" "dropdown")
(icon (text "sliders-horizontal"))
(span ("class" "current_tab_text") (text "account")))
(div
("class" "inner left")
(text "{{ macros::profile_settings_nav_options() }}"))))
; nav desktop
(div
("class" "desktop pillmenu")
(text "{{ macros::profile_settings_nav_options() }}"))
; ...
(div
("class" "w-full flex flex-col gap-2")
("data-tab" "account")

View file

@ -704,12 +704,21 @@ media_theme_pref();
for (const element of Array.from(
document.querySelectorAll("[data-tab-button]"),
)) {
element.classList.remove("active");
if (element.getAttribute("data-tab-button") !== tab) {
element.classList.remove("active");
}
}
document
.querySelector(`[data-tab-button="${tab}"]`)
.classList.add("active");
for (const element of document.querySelectorAll(
`[data-tab-button="${tab}"]`,
)) {
element.classList.add("active");
}
}
// update text elements
for (const element of document.querySelectorAll(".current_tab_text")) {
element.innerText = tab;
}
});