- Replace PosterStorage with generic ImageStorage port (IMAGE_STORAGE_BACKEND/PATH env vars)
- Rename poster-storage crate to image-storage; serve at /images/{*key}
- Add bio and avatar_path to User model (migration 0009_user_profile)
- update_profile use case with avatar upload, mime validation, old avatar cleanup
- GET/PUT /api/v1/profile and GET/POST /settings/profile HTML page
- Enrich AP Person actor with summary, icon, url, discoverable fields
- Store remote actor avatar_url (migration 0010_ap_remote_actor_avatar)
- Shared inbox delivery via collect_inboxes deduplication
- Broadcast Update(Person) to followers on UserUpdated event
- Paginated outbox: OrderedCollection + OrderedCollectionPage with cursor
- Announce/boost tracking in ap_announces table (migration 0011_ap_announces)
26 lines
754 B
HTML
26 lines
754 B
HTML
{% extends "base.html" %}
|
|
{% block content %}
|
|
<h1>Profile Settings</h1>
|
|
{% if saved %}
|
|
<p class="success">Saved.</p>
|
|
{% endif %}
|
|
<form method="post" action="/settings/profile" enctype="multipart/form-data">
|
|
<input type="hidden" name="_csrf" value="{{ ctx.csrf_token }}">
|
|
<label>
|
|
Bio<br>
|
|
<textarea name="bio">{% if let Some(b) = bio %}{{ b }}{% endif %}</textarea>
|
|
</label>
|
|
{% if let Some(url) = avatar_url %}
|
|
<div>
|
|
<p>Current avatar:</p>
|
|
<img src="{{ url }}" alt="Current avatar" style="max-width:128px;max-height:128px;">
|
|
</div>
|
|
{% endif %}
|
|
<label>
|
|
Avatar image<br>
|
|
<input type="file" name="avatar" accept="image/jpeg,image/png,image/webp">
|
|
</label>
|
|
<button type="submit">Save</button>
|
|
</form>
|
|
{% endblock %}
|