mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
feat: Add a page with some information about the server
This commit is contained in:
@@ -4,7 +4,7 @@ use ruma::{
|
|||||||
api::client::discovery::{
|
api::client::discovery::{
|
||||||
discover_homeserver::{self, HomeserverInfo},
|
discover_homeserver::{self, HomeserverInfo},
|
||||||
discover_policy_server,
|
discover_policy_server,
|
||||||
discover_support::{self, Contact, ContactRole},
|
discover_support,
|
||||||
},
|
},
|
||||||
assign,
|
assign,
|
||||||
};
|
};
|
||||||
@@ -67,46 +67,7 @@ pub(crate) async fn well_known_support(
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(ToString::to_string);
|
.map(ToString::to_string);
|
||||||
|
|
||||||
let email_address = services.config.well_known.support_email.clone();
|
let contacts = services.admin.get_support_contacts().await;
|
||||||
let matrix_id = services.config.well_known.support_mxid.clone();
|
|
||||||
let pgp_key = services.config.well_known.support_pgp_key.clone();
|
|
||||||
|
|
||||||
// TODO: support defining multiple contacts in the config
|
|
||||||
let mut contacts: Vec<Contact> = vec![];
|
|
||||||
|
|
||||||
let role = services
|
|
||||||
.config
|
|
||||||
.well_known
|
|
||||||
.support_role
|
|
||||||
.clone()
|
|
||||||
.unwrap_or(ContactRole::Admin);
|
|
||||||
|
|
||||||
// Add configured contact if at least one contact method is specified
|
|
||||||
let configured_contact = match (matrix_id, email_address) {
|
|
||||||
| (Some(matrix_id), email_address) =>
|
|
||||||
Some(assign!(Contact::with_matrix_id(role, matrix_id), { email_address })),
|
|
||||||
| (None, Some(email_address)) => Some(Contact::with_email_address(role, email_address)),
|
|
||||||
| (None, None) => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(mut configured_contact) = configured_contact {
|
|
||||||
configured_contact.pgp_key = pgp_key;
|
|
||||||
|
|
||||||
contacts.push(configured_contact);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to add admin users as contacts if no contacts are configured
|
|
||||||
if contacts.is_empty() {
|
|
||||||
let admin_users = services.admin.get_admins().await;
|
|
||||||
|
|
||||||
for user_id in &admin_users {
|
|
||||||
if *user_id == services.globals.server_user {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
contacts.push(Contact::with_matrix_id(ContactRole::Admin, user_id.to_owned()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if contacts.is_empty() && support_page.is_none() {
|
if contacts.is_empty() && support_page.is_none() {
|
||||||
// No admin room, no configured contacts, and no support page
|
// No admin room, no configured contacts, and no support page
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#![type_length_limit = "16384"] //TODO: reduce me
|
#![type_length_limit = "16384"] //TODO: reduce me
|
||||||
|
#![recursion_limit = "256"] // My Giant Async Function
|
||||||
#![allow(clippy::toplevel_ref_arg)]
|
#![allow(clippy::toplevel_ref_arg)]
|
||||||
|
|
||||||
extern crate conduwuit_core as conduwuit;
|
extern crate conduwuit_core as conduwuit;
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ use futures::{Future, FutureExt, StreamExt, TryFutureExt};
|
|||||||
use loole::{Receiver, Sender};
|
use loole::{Receiver, Sender};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedUserId, RoomId, UInt, UserId,
|
OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedUserId, RoomId, UInt, UserId,
|
||||||
|
api::client::discovery::discover_support::{Contact, ContactRole},
|
||||||
|
assign,
|
||||||
events::{
|
events::{
|
||||||
Mentions,
|
Mentions,
|
||||||
room::message::{
|
room::message::{
|
||||||
@@ -28,7 +30,7 @@ use ruma::{
|
|||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Dep, account_data, globals,
|
Dep, account_data, config, globals,
|
||||||
media::{MXC_LENGTH, mxc::Mxc},
|
media::{MXC_LENGTH, mxc::Mxc},
|
||||||
rooms::{self, state::RoomMutexGuard},
|
rooms::{self, state::RoomMutexGuard},
|
||||||
};
|
};
|
||||||
@@ -44,6 +46,7 @@ pub struct Service {
|
|||||||
|
|
||||||
struct Services {
|
struct Services {
|
||||||
server: Arc<Server>,
|
server: Arc<Server>,
|
||||||
|
config: Dep<config::Service>,
|
||||||
globals: Dep<globals::Service>,
|
globals: Dep<globals::Service>,
|
||||||
alias: Dep<rooms::alias::Service>,
|
alias: Dep<rooms::alias::Service>,
|
||||||
timeline: Dep<rooms::timeline::Service>,
|
timeline: Dep<rooms::timeline::Service>,
|
||||||
@@ -115,6 +118,7 @@ impl crate::Service for Service {
|
|||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
services: Services {
|
services: Services {
|
||||||
server: args.server.clone(),
|
server: args.server.clone(),
|
||||||
|
config: args.depend::<config::Service>("config"),
|
||||||
globals: args.depend::<globals::Service>("globals"),
|
globals: args.depend::<globals::Service>("globals"),
|
||||||
alias: args.depend::<rooms::alias::Service>("rooms::alias"),
|
alias: args.depend::<rooms::alias::Service>("rooms::alias"),
|
||||||
timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"),
|
timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"),
|
||||||
@@ -619,4 +623,52 @@ impl Service {
|
|||||||
let weak = services.map(Arc::downgrade);
|
let weak = services.map(Arc::downgrade);
|
||||||
*receiver = weak;
|
*receiver = weak;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the server's configured support contacts.
|
||||||
|
pub async fn get_support_contacts(&self) -> Vec<Contact> {
|
||||||
|
let email_address = self.services.config.well_known.support_email.clone();
|
||||||
|
let matrix_id = self.services.config.well_known.support_mxid.clone();
|
||||||
|
let pgp_key = self.services.config.well_known.support_pgp_key.clone();
|
||||||
|
|
||||||
|
// TODO: support defining multiple contacts in the config
|
||||||
|
let mut contacts: Vec<Contact> = vec![];
|
||||||
|
|
||||||
|
let role = self
|
||||||
|
.services
|
||||||
|
.config
|
||||||
|
.well_known
|
||||||
|
.support_role
|
||||||
|
.clone()
|
||||||
|
.unwrap_or(ContactRole::Admin);
|
||||||
|
|
||||||
|
// Add configured contact if at least one contact method is specified
|
||||||
|
let configured_contact = match (matrix_id, email_address) {
|
||||||
|
| (Some(matrix_id), email_address) =>
|
||||||
|
Some(assign!(Contact::with_matrix_id(role, matrix_id), { email_address })),
|
||||||
|
| (None, Some(email_address)) =>
|
||||||
|
Some(Contact::with_email_address(role, email_address)),
|
||||||
|
| (None, None) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut configured_contact) = configured_contact {
|
||||||
|
configured_contact.pgp_key = pgp_key;
|
||||||
|
|
||||||
|
contacts.push(configured_contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to add admin users as contacts if no contacts are configured
|
||||||
|
if contacts.is_empty() {
|
||||||
|
let admin_users = self.get_admins().await;
|
||||||
|
|
||||||
|
for user_id in &admin_users {
|
||||||
|
if *user_id == self.services.globals.server_user {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
contacts.push(Contact::with_matrix_id(ContactRole::Admin, user_id.to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contacts
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ pub fn build(services: &Services) -> Router<state::State> {
|
|||||||
.nest(
|
.nest(
|
||||||
"/_continuwuity/",
|
"/_continuwuity/",
|
||||||
Router::new()
|
Router::new()
|
||||||
|
.nest("/about", about::build())
|
||||||
.nest("/account/", account::build())
|
.nest("/account/", account::build())
|
||||||
.merge(debug::build())
|
.merge(debug::build())
|
||||||
.nest("/oauth2/", oauth::build())
|
.nest("/oauth2/", oauth::build())
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use axum::{Extension, Router, extract::State, routing::get};
|
||||||
|
use conduwuit_core::config::TermsDocument;
|
||||||
|
use ruma::{
|
||||||
|
OwnedServerName,
|
||||||
|
api::client::discovery::discover_support::{Contact, ContactRole},
|
||||||
|
};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
pages::{Result, TemplateContext},
|
||||||
|
response, template,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) fn build() -> Router<crate::State> { Router::new().route("/", get(get_about)) }
|
||||||
|
|
||||||
|
template! {
|
||||||
|
struct About use "about.html.j2" {
|
||||||
|
server_name: OwnedServerName,
|
||||||
|
support_page: Option<Url>,
|
||||||
|
contacts: Vec<Contact>,
|
||||||
|
terms: BTreeMap<String, TermsDocument>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_about(
|
||||||
|
State(services): State<crate::State>,
|
||||||
|
Extension(context): Extension<TemplateContext>,
|
||||||
|
) -> Result {
|
||||||
|
response!(About::new(
|
||||||
|
context,
|
||||||
|
services.globals.server_name().to_owned(),
|
||||||
|
services.config.well_known.support_page.clone(),
|
||||||
|
services.admin.get_support_contacts().await,
|
||||||
|
services.config.registration_terms.documents.clone()
|
||||||
|
))
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ use conduwuit_core::utils;
|
|||||||
|
|
||||||
use crate::WebError;
|
use crate::WebError;
|
||||||
|
|
||||||
|
pub(super) mod about;
|
||||||
pub(super) mod account;
|
pub(super) mod account;
|
||||||
mod components;
|
mod components;
|
||||||
pub(super) mod debug;
|
pub(super) mod debug;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
--text-color: #f5ebeb;
|
--text-color: #f5ebeb;
|
||||||
--secondary: #888;
|
--secondary: #999;
|
||||||
--bg: oklch(0.15 0.042 317.27);
|
--bg: oklch(0.15 0.042 317.27);
|
||||||
--panel-bg: oklch(0.24 0.03 317.27);
|
--panel-bg: oklch(0.24 0.03 317.27);
|
||||||
|
|
||||||
@@ -94,6 +94,10 @@ p {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
}
|
}
|
||||||
@@ -125,38 +129,6 @@ small.error {
|
|||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
|
||||||
--preferred-width: 12rem + 40dvw;
|
|
||||||
--maximum-width: 48rem;
|
|
||||||
--minimum-width: 32rem;
|
|
||||||
|
|
||||||
width: min(clamp(var(--minimum-width), var(--preferred-width), var(--maximum-width)), calc(100dvw - 3rem));
|
|
||||||
border-radius: var(--border-radius-lg);
|
|
||||||
background-color: var(--panel-bg);
|
|
||||||
padding-inline: 1.5rem;
|
|
||||||
padding-block: 1rem;
|
|
||||||
margin-top: 1em;
|
|
||||||
margin-bottom: auto;
|
|
||||||
box-shadow: 0 0.25em 0.375em hsla(0, 0%, 0%, 0.1);
|
|
||||||
|
|
||||||
&.middle {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.narrow {
|
|
||||||
--preferred-width: 12rem + 20dvw;
|
|
||||||
--maximum-width: 36rem;
|
|
||||||
|
|
||||||
input, button, a.button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.narrow) form p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img.matrix-icon {
|
img.matrix-icon {
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
@@ -262,6 +234,22 @@ h1 {
|
|||||||
margin-bottom: 0.67em;
|
margin-bottom: 0.67em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul.bullet-separated {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline;
|
||||||
|
flex: 1;
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
&:not(:first-child)::before {
|
||||||
|
content: "• ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fullwidth {
|
.fullwidth {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
@@ -271,6 +259,52 @@ h1 {
|
|||||||
user-select: all;
|
user-select: all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
--preferred-width: 12rem + 40dvw;
|
||||||
|
--maximum-width: 48rem;
|
||||||
|
--minimum-width: 32rem;
|
||||||
|
|
||||||
|
width: min(clamp(var(--minimum-width), var(--preferred-width), var(--maximum-width)), calc(100dvw - 3rem));
|
||||||
|
border-radius: var(--border-radius-lg);
|
||||||
|
background-color: var(--panel-bg);
|
||||||
|
padding-inline: 1.5rem;
|
||||||
|
padding-block: 1rem;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: auto;
|
||||||
|
box-shadow: 0 0.25em 0.375em hsla(0, 0%, 0%, 0.1);
|
||||||
|
|
||||||
|
&.middle {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.narrow {
|
||||||
|
--preferred-width: 12rem + 20dvw;
|
||||||
|
--maximum-width: 36rem;
|
||||||
|
|
||||||
|
input, button, a.button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.narrow) form p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-name {
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none !important;
|
||||||
|
background: linear-gradient(
|
||||||
|
130deg,
|
||||||
|
oklch(from var(--c1) var(--name-lightness) c h),
|
||||||
|
oklch(from var(--c2) var(--name-lightness) c h)
|
||||||
|
);
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
filter: brightness(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 425px) {
|
@media (max-width: 425px) {
|
||||||
main {
|
main {
|
||||||
padding-block-start: 2rem;
|
padding-block-start: 2rem;
|
||||||
|
|||||||
@@ -34,17 +34,17 @@
|
|||||||
.info {
|
.info {
|
||||||
flex: 1 1;
|
flex: 1 1;
|
||||||
|
|
||||||
p {
|
.name {
|
||||||
margin: 0;
|
font-weight: bold;
|
||||||
|
|
||||||
&.name {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.id {
|
.id {
|
||||||
color: var(--secondary);
|
color: var(--secondary);
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "•";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,3 @@
|
|||||||
.project-name {
|
|
||||||
text-decoration: none;
|
|
||||||
background: linear-gradient(
|
|
||||||
130deg,
|
|
||||||
oklch(from var(--c1) var(--name-lightness) c h),
|
|
||||||
oklch(from var(--c2) var(--name-lightness) c h)
|
|
||||||
);
|
|
||||||
background-clip: text;
|
|
||||||
color: transparent;
|
|
||||||
filter: brightness(1.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,36 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
{{ avatar }}
|
{{ avatar }}
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<p class="name">
|
<div class="name">
|
||||||
{% if let Some(display_name) = display_name %}
|
<span>
|
||||||
{{ display_name }}
|
{% if let Some(display_name) = display_name %}
|
||||||
{% else %}
|
{{ display_name }}
|
||||||
Unknown device
|
{% else %}
|
||||||
{% endif %}
|
Unknown device
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
{% if style == DeviceCardStyle::Detailed %}
|
{% if style == DeviceCardStyle::Detailed %}
|
||||||
<span class="id">
|
<ul class="id bullet-separated">
|
||||||
• {{ device_id }}
|
<li>{{ device_id }}</li>
|
||||||
{% if let Some(metadata) = oauth_metadata %}
|
<li>
|
||||||
• <a href="{{ metadata.client_uri }}">Client website</a>
|
{% if let Some(metadata) = oauth_metadata %}
|
||||||
{% else %}
|
<a href="{{ metadata.client_uri }}">Client website</a>
|
||||||
(legacy)
|
{% else %}
|
||||||
{% endif %}
|
(legacy)
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</div>
|
||||||
<p>
|
<div>
|
||||||
Last active: {{ last_active }}
|
Last active: {{ last_active }}
|
||||||
</p>
|
</div>
|
||||||
<p>
|
<div>
|
||||||
{% if style == DeviceCardStyle::Detailed %}
|
{% if style == DeviceCardStyle::Detailed %}
|
||||||
<a href="{{ crate::ROUTE_PREFIX }}/account/device/{{ device_id }}/remove">Remove</a>
|
<a href="{{ crate::ROUTE_PREFIX }}/account/device/{{ device_id }}/remove">Remove</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ crate::ROUTE_PREFIX }}/account/device/{{ device_id }}/">Details</a>
|
<a href="{{ crate::ROUTE_PREFIX }}/account/device/{{ device_id }}/">Details</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,16 +19,8 @@
|
|||||||
{%~ block content %}{% endblock ~%}
|
{%~ block content %}{% endblock ~%}
|
||||||
{%~ block footer ~%}
|
{%~ block footer ~%}
|
||||||
<footer>
|
<footer>
|
||||||
<img class="logo" src="{{ crate::ROUTE_PREFIX }}/resources/logo.svg">
|
<a href="{{ crate::ROUTE_PREFIX }}/"><img class="logo" src="{{ crate::ROUTE_PREFIX }}/resources/logo.svg"></a>
|
||||||
<p>Powered by <a href="https://continuwuity.org">Continuwuity</a> {{ env!("CARGO_PKG_VERSION") }}
|
<p>Powered by <a href="https://continuwuity.org">Continuwuity</a> {{ env!("CARGO_PKG_VERSION") }} • <a href="{{ crate::ROUTE_PREFIX }}/about">About</a></p>
|
||||||
{%~ if let Some(version_info) = conduwuit_build_metadata::version_tag() ~%}
|
|
||||||
{%~ if let Some(url) = conduwuit_build_metadata::GIT_REMOTE_COMMIT_URL.or(conduwuit_build_metadata::GIT_REMOTE_WEB_URL) ~%}
|
|
||||||
(<a href="{{ url }}">{{ version_info }}</a>)
|
|
||||||
{%~ else ~%}
|
|
||||||
({{ version_info }})
|
|
||||||
{%~ endif ~%}
|
|
||||||
{%~ endif ~%}
|
|
||||||
</p>
|
|
||||||
</footer>
|
</footer>
|
||||||
{%~ endblock ~%}
|
{%~ endblock ~%}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
{% extends "_layout.html.j2" %}
|
||||||
|
|
||||||
|
{%- block title -%}
|
||||||
|
About server
|
||||||
|
{%- endblock -%}
|
||||||
|
|
||||||
|
{%- block content -%}
|
||||||
|
<div class="panel">
|
||||||
|
<h1>About {{ server_name }}</h1>
|
||||||
|
{% if let Some(support_page) = support_page %}
|
||||||
|
<p>
|
||||||
|
Support: <a href="{{ support_page }} target="_blank">{{ support_page }}</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if !contacts.is_empty() %}
|
||||||
|
<p>
|
||||||
|
Contact the operators of this server:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{% for contact in contacts %}
|
||||||
|
<li>
|
||||||
|
{%- match contact.role -%}
|
||||||
|
{%- when ContactRole::Admin -%}
|
||||||
|
Administrator
|
||||||
|
{%- when ContactRole::Security -%}
|
||||||
|
Security
|
||||||
|
{%- when ContactRole::Moderator -%}
|
||||||
|
Moderator
|
||||||
|
{%- when _ -%}
|
||||||
|
Contact
|
||||||
|
{%- endmatch -%}
|
||||||
|
: <ul class="bullet-separated">
|
||||||
|
{%- if let Some(matrix_id) = contact.matrix_id -%}
|
||||||
|
<li><a href="matrix:u/{{ matrix_id.localpart() }}:{{ matrix_id.server_name() }}?action=chat" target="_blank">{{ matrix_id }}</a></li>
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if let Some(email_address) = contact.email_address -%}
|
||||||
|
<li><a href="mailto:{{ email_address }}" target="_blank">{{ email_address }}</a>
|
||||||
|
{%- if let Some(pgp_key) = contact.pgp_key -%}
|
||||||
|
(<a href="{{ pgp_key }}" target="_blank">PGP</a>)
|
||||||
|
{%- endif -%}
|
||||||
|
</li>
|
||||||
|
{%- endif -%}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% if !terms.is_empty() %}
|
||||||
|
<p>
|
||||||
|
By using {{ server_name }} you agree to the following policies:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{% for (id, document) in terms %}
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="{{ document.url }}">{{ document.name }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
<p>
|
||||||
|
Server version {{ env!("CARGO_PKG_VERSION") }}
|
||||||
|
{%~ if let Some(version_info) = conduwuit_build_metadata::version_tag() ~%}
|
||||||
|
{%~ if let Some(url) = conduwuit_build_metadata::GIT_REMOTE_COMMIT_URL.or(conduwuit_build_metadata::GIT_REMOTE_WEB_URL) ~%}
|
||||||
|
(<a href="{{ url }}">{{ version_info }}</a>)
|
||||||
|
{%~ else ~%}
|
||||||
|
({{ version_info }})
|
||||||
|
{%~ endif ~%}
|
||||||
|
{%~ endif ~%}
|
||||||
|
</p>
|
||||||
|
<hr>
|
||||||
|
<p>
|
||||||
|
{{ server_name }} is powered by <a class="project-name" href="https://continuwuity.org">Continuwuity</a>,
|
||||||
|
a high-performance and community-driven <a href="https://matrix.org">Matrix</a> homeserver
|
||||||
|
maintained as an open source project by volunteers from around the world.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<ul class="bullet-separated">
|
||||||
|
<li><a href="https://forgejo.ellis.link/continuwuation/continuwuity">Source code</a></li>
|
||||||
|
<li><a href="https://matrix.to/#/#continuwuity:continuwuity.org">Official Matrix chatroom</a></li>
|
||||||
|
<li><span class="project-name">❤</span> <a href="https://opencollective.com/continuwuity">Support the project</a></li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -58,8 +58,10 @@ Your account
|
|||||||
<p>
|
<p>
|
||||||
Settings here <em class="negative">may affect the integrity of your account</em>.
|
Settings here <em class="negative">may affect the integrity of your account</em>.
|
||||||
</p>
|
</p>
|
||||||
<a href="cross_signing_reset">Reset your digital identity</a> •
|
<ul class="bullet-separated">
|
||||||
<a href="deactivate">Deactivate your account</a>
|
<li><a href="cross_signing_reset">Reset your digital identity</a></li>
|
||||||
|
<li><a href="deactivate">Deactivate your account</a></li>
|
||||||
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</section>
|
</section>
|
||||||
{% when AccountBody::Locked %}
|
{% when AccountBody::Locked %}
|
||||||
|
|||||||
@@ -9,16 +9,18 @@ Device information
|
|||||||
<h1>About device <a class="back" href="{{ crate::ROUTE_PREFIX }}/account/">Back</a></h1>
|
<h1>About device <a class="back" href="{{ crate::ROUTE_PREFIX }}/account/">Back</a></h1>
|
||||||
{{ device_card }}
|
{{ device_card }}
|
||||||
{% if let Some((client_metadata, _)) = client_metadata %}
|
{% if let Some((client_metadata, _)) = client_metadata %}
|
||||||
<section>
|
{% if client_metadata.tos_uri.is_some() || client_metadata.policy_uri.is_some() %}
|
||||||
<p>
|
<section>
|
||||||
{% if let Some(tos_uri) = &client_metadata.tos_uri %}
|
<ul class="bullet-separated">
|
||||||
<a href="{{ tos_uri }}">Terms of service</a>
|
{% if let Some(tos_uri) = &client_metadata.tos_uri %}
|
||||||
{% endif %}
|
<li><a href="{{ tos_uri }}">Terms of service</a></li>
|
||||||
{% if let Some(policy_uri) = &client_metadata.policy_uri %}
|
{% endif %}
|
||||||
• <a href="{{ policy_uri }}">Policies</a>
|
{% if let Some(policy_uri) = &client_metadata.policy_uri %}
|
||||||
{% endif %}
|
<li><a href="{{ policy_uri }}">Policies</a></li>
|
||||||
</p>
|
{% endif %}
|
||||||
</section>
|
</ul>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<section>
|
<section>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
Reference in New Issue
Block a user