federation improvements

This commit is contained in:
2026-05-09 15:45:08 +02:00
parent fa6eacb39f
commit 69f6587623
15 changed files with 241 additions and 24 deletions

View File

@@ -1,8 +1,8 @@
use askama::Template;
use chrono::Datelike;
use application::ports::{
ActivityFeedPageData, FollowingPageData, HtmlPageContext, HtmlRenderer, LoginPageData,
NewReviewPageData, ProfilePageData, RegisterPageData, UsersPageData,
ActivityFeedPageData, FollowersPageData, FollowingPageData, HtmlPageContext, HtmlRenderer,
LoginPageData, NewReviewPageData, ProfilePageData, RegisterPageData, UsersPageData,
};
use domain::models::{
DiaryEntry, FeedEntry, MonthActivity, MonthlyRating, ReviewSource, UserStats,
@@ -124,6 +124,7 @@ struct ProfileTemplate<'a> {
is_own_profile: bool,
error: Option<String>,
following_count: usize,
followers_count: usize,
pending_followers: Vec<RemoteActorData>,
}
@@ -142,6 +143,15 @@ struct FollowingTemplate {
error: Option<String>,
}
#[derive(Template)]
#[template(path = "followers.html")]
struct FollowersTemplate {
ctx: HtmlPageContext,
user_id: uuid::Uuid,
actors: Vec<RemoteActorData>,
error: Option<String>,
}
struct HeatmapCell {
month_label: String,
count: i64,
@@ -338,6 +348,7 @@ impl HtmlRenderer for AskamaHtmlRenderer {
is_own_profile: data.is_own_profile,
error: data.error,
following_count: data.following_count,
followers_count: data.followers_count,
pending_followers: data.pending_followers.into_iter().map(|a| RemoteActorData {
handle: a.handle,
url: a.url,
@@ -362,4 +373,19 @@ impl HtmlRenderer for AskamaHtmlRenderer {
.render()
.map_err(|e| e.to_string())
}
fn render_followers_page(&self, data: FollowersPageData) -> Result<String, String> {
FollowersTemplate {
ctx: data.ctx,
user_id: data.user_id,
actors: data.actors.into_iter().map(|a| RemoteActorData {
handle: a.handle,
display_name: a.display_name,
url: a.url,
}).collect(),
error: data.error,
}
.render()
.map_err(|e| e.to_string())
}
}

View File

@@ -0,0 +1,26 @@
{% extends "base.html" %}
{% block content %}
<h2>Followers</h2>
{% if let Some(err) = error %}
<p class="error">{{ err }}</p>
{% endif %}
{% if actors.is_empty() %}
<p>No followers yet.</p>
{% else %}
<ul class="following-list">
{% for actor in actors %}
<li class="following-item">
<strong>{{ actor.handle }}</strong>
{% if let Some(name) = actor.display_name %}
({{ name }})
{% endif %}
<a href="{{ actor.url }}" target="_blank" rel="noopener noreferrer">{{ actor.url }}</a>
<form method="POST" action="/users/{{ user_id }}/followers/remove" style="display:inline">
<input type="hidden" name="actor_url" value="{{ actor.url }}">
<button type="submit">Remove</button>
</form>
</li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}

View File

@@ -36,6 +36,7 @@
{% endif %}
</section>
<a href="/users/{{ profile_user_id }}/following-list">View following ({{ following_count }})</a>
<a href="/users/{{ profile_user_id }}/followers-list">View followers ({{ followers_count }})</a>
{% if !pending_followers.is_empty() %}
<section class="pending-followers">
<h3>Pending follow requests ({{ pending_followers.len() }})</h3>