UI improvements
parent
f66e3f3995
commit
4f1b51f7d5
|
@ -47,6 +47,10 @@ class Actor:
|
||||||
def preferred_username(self) -> str:
|
def preferred_username(self) -> str:
|
||||||
return self.ap_actor["preferredUsername"]
|
return self.ap_actor["preferredUsername"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display_name(self) -> str:
|
||||||
|
return self.name or self.preferred_username
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def handle(self) -> str:
|
def handle(self) -> str:
|
||||||
return _handle(self.ap_actor)
|
return _handle(self.ap_actor)
|
||||||
|
|
|
@ -19,6 +19,14 @@ class Object:
|
||||||
def is_from_db(self) -> bool:
|
def is_from_db(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_from_outbox(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_from_inbox(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ap_type(self) -> str:
|
def ap_type(self) -> str:
|
||||||
return self.ap_object["type"]
|
return self.ap_object["type"]
|
||||||
|
|
10
app/boxes.py
10
app/boxes.py
|
@ -237,6 +237,11 @@ def send_create(
|
||||||
raise ValueError("Object has no context")
|
raise ValueError("Object has no context")
|
||||||
context = in_reply_to_object.ap_context
|
context = in_reply_to_object.ap_context
|
||||||
|
|
||||||
|
if in_reply_to_object.is_from_outbox:
|
||||||
|
db.query(models.OutboxObject).filter(
|
||||||
|
models.OutboxObject.ap_id == in_reply_to,
|
||||||
|
).update({"replies_count": models.OutboxObject.replies_count + 1})
|
||||||
|
|
||||||
for (upload, filename) in uploads:
|
for (upload, filename) in uploads:
|
||||||
attachments.append(upload_to_attachment(upload, filename))
|
attachments.append(upload_to_attachment(upload, filename))
|
||||||
|
|
||||||
|
@ -501,6 +506,11 @@ def _handle_create_activity(
|
||||||
logger.info(f"Invalid tags: {tags}")
|
logger.info(f"Invalid tags: {tags}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if created_object.in_reply_to and created_object.in_reply_to.startswith(BASE_URL):
|
||||||
|
db.query(models.OutboxObject).filter(
|
||||||
|
models.OutboxObject.ap_id == created_object.in_reply_to,
|
||||||
|
).update({"replies_count": models.OutboxObject.replies_count + 1})
|
||||||
|
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
if tag.get("name") == LOCAL_ACTOR.handle or tag.get("href") == LOCAL_ACTOR.url:
|
if tag.get("name") == LOCAL_ACTOR.handle or tag.get("href") == LOCAL_ACTOR.url:
|
||||||
notif = models.Notification(
|
notif = models.Notification(
|
||||||
|
|
10
app/main.py
10
app/main.py
|
@ -59,9 +59,6 @@ from app.uploads import UPLOAD_DIR
|
||||||
# - inbox/outbox in the admin (as in show every objects)
|
# - inbox/outbox in the admin (as in show every objects)
|
||||||
# - show likes/announces counter for outbox activities
|
# - show likes/announces counter for outbox activities
|
||||||
# - update actor support
|
# - update actor support
|
||||||
# - replies support
|
|
||||||
# - file upload + place/exif extraction (or not) support
|
|
||||||
# - custom emoji support
|
|
||||||
# - hash config/profile to detect when to send Update actor
|
# - hash config/profile to detect when to send Update actor
|
||||||
#
|
#
|
||||||
# - [ ] block support
|
# - [ ] block support
|
||||||
|
@ -72,13 +69,6 @@ from app.uploads import UPLOAD_DIR
|
||||||
# - [ ] custom emoji
|
# - [ ] custom emoji
|
||||||
# - [ ] poll/questions support
|
# - [ ] poll/questions support
|
||||||
# - [ ] cleanup tasks
|
# - [ ] cleanup tasks
|
||||||
# - notifs:
|
|
||||||
# - MENTIONED
|
|
||||||
# - LIKED
|
|
||||||
# - ANNOUNCED
|
|
||||||
# - FOLLOWED
|
|
||||||
# - UNFOLLOWED
|
|
||||||
# - POLL_ENDED
|
|
||||||
|
|
||||||
app = FastAPI(docs_url=None, redoc_url=None)
|
app = FastAPI(docs_url=None, redoc_url=None)
|
||||||
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
||||||
|
|
|
@ -114,6 +114,14 @@ class InboxObject(Base, BaseObject):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_from_db(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_from_inbox(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class OutboxObject(Base, BaseObject):
|
class OutboxObject(Base, BaseObject):
|
||||||
__tablename__ = "outbox"
|
__tablename__ = "outbox"
|
||||||
|
@ -221,6 +229,14 @@ class OutboxObject(Base, BaseObject):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_from_db(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_from_outbox(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Follower(Base):
|
class Follower(Base):
|
||||||
__tablename__ = "follower"
|
__tablename__ = "follower"
|
||||||
|
|
|
@ -133,3 +133,10 @@ nav.flexbox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.actor-action {
|
||||||
|
padding-left:70px;
|
||||||
|
margin-top:20px;
|
||||||
|
span {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -183,8 +183,21 @@ def _has_media_type(attachment: Attachment, media_type_prefix: str) -> bool:
|
||||||
return attachment.media_type.startswith(media_type_prefix)
|
return attachment.media_type.startswith(media_type_prefix)
|
||||||
|
|
||||||
|
|
||||||
|
def _format_date(dt: datetime) -> str:
|
||||||
|
return dt.strftime("%b %d, %Y, %H:%M")
|
||||||
|
|
||||||
|
|
||||||
|
def _pluralize(count: int, singular: str = "", plural: str = "s") -> str:
|
||||||
|
if count > 1:
|
||||||
|
return plural
|
||||||
|
else:
|
||||||
|
return singular
|
||||||
|
|
||||||
|
|
||||||
_templates.env.filters["domain"] = _filter_domain
|
_templates.env.filters["domain"] = _filter_domain
|
||||||
_templates.env.filters["media_proxy_url"] = _media_proxy_url
|
_templates.env.filters["media_proxy_url"] = _media_proxy_url
|
||||||
_templates.env.filters["clean_html"] = _clean_html
|
_templates.env.filters["clean_html"] = _clean_html
|
||||||
_templates.env.filters["timeago"] = _timeago
|
_templates.env.filters["timeago"] = _timeago
|
||||||
|
_templates.env.filters["format_date"] = _format_date
|
||||||
_templates.env.filters["has_media_type"] = _has_media_type
|
_templates.env.filters["has_media_type"] = _has_media_type
|
||||||
|
_templates.env.filters["pluralize"] = _pluralize
|
||||||
|
|
|
@ -7,13 +7,8 @@
|
||||||
{{ utils.display_object(inbox_object.relates_to_anybox_object) }}
|
{{ utils.display_object(inbox_object.relates_to_anybox_object) }}
|
||||||
{% elif inbox_object.ap_type in ["Article", "Note", "Video"] %}
|
{% elif inbox_object.ap_type in ["Article", "Note", "Video"] %}
|
||||||
{{ utils.display_object(inbox_object) }}
|
{{ utils.display_object(inbox_object) }}
|
||||||
{% if inbox_object.liked_via_outbox_object_ap_id %}
|
{% elif inbox_object.ap_type == "Follow" %}
|
||||||
{{ utils.admin_undo_button(inbox_object.liked_via_outbox_object_ap_id, "Unlike") }}
|
{{ utils.display_object(inbox_object) }}
|
||||||
{% else %}
|
|
||||||
{{ utils.admin_like_button(inbox_object.ap_id) }}
|
|
||||||
{% endif %}
|
|
||||||
{{ utils.admin_announce_button(inbox_object.ap_id) }}
|
|
||||||
{{ utils.admin_reply_button(inbox_object.ap_id) }}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
Implement {{ inbox_object.ap_type }}
|
Implement {{ inbox_object.ap_type }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -8,13 +8,6 @@
|
||||||
{{ utils.display_object(outbox_object.relates_to_anybox_object) }}
|
{{ utils.display_object(outbox_object.relates_to_anybox_object) }}
|
||||||
{% elif outbox_object.ap_type in ["Article", "Note", "Video"] %}
|
{% elif outbox_object.ap_type in ["Article", "Note", "Video"] %}
|
||||||
{{ utils.display_object(outbox_object) }}
|
{{ utils.display_object(outbox_object) }}
|
||||||
{% if outbox_object.liked_via_outbox_object_ap_id %}
|
|
||||||
{{ utils.admin_undo_button(outbox_object.liked_via_outbox_object_ap_id, "Unlike") }}
|
|
||||||
{% else %}
|
|
||||||
{{ utils.admin_like_button(outbox_object.ap_id) }}
|
|
||||||
{% endif %}
|
|
||||||
{{ utils.admin_announce_button(outbox_object.ap_id) }}
|
|
||||||
{{ utils.admin_reply_button(outbox_object.ap_id) }}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
Implement {{ outbox_object.ap_type }}
|
Implement {{ outbox_object.ap_type }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -7,13 +7,6 @@
|
||||||
{{ utils.display_object(inbox_object.relates_to_anybox_object) }}
|
{{ utils.display_object(inbox_object.relates_to_anybox_object) }}
|
||||||
{% elif inbox_object.ap_type in ["Article", "Note", "Video"] %}
|
{% elif inbox_object.ap_type in ["Article", "Note", "Video"] %}
|
||||||
{{ utils.display_object(inbox_object) }}
|
{{ utils.display_object(inbox_object) }}
|
||||||
{% if inbox_object.liked_via_outbox_object_ap_id %}
|
|
||||||
{{ utils.admin_undo_button(inbox_object.liked_via_outbox_object_ap_id, "Unlike") }}
|
|
||||||
{% else %}
|
|
||||||
{{ utils.admin_like_button(inbox_object.ap_id) }}
|
|
||||||
{% endif %}
|
|
||||||
{{ utils.admin_announce_button(inbox_object.ap_id) }}
|
|
||||||
{{ utils.admin_reply_button(inbox_object.ap_id) }}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{%- import "utils.html" as utils -%}
|
{%- import "utils.html" as utils with context -%}
|
||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include "header.html" %}
|
{% include "header.html" %}
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{%- macro header_link(url, text) -%}
|
{%- macro header_link(url, text) -%}
|
||||||
{% set url_for = request.url_for(url) %}
|
{% set url_for = request.app.router.url_path_for(url) %}
|
||||||
<a href="{{ url_for }}" {% if request.url == url_for %}class="active"{% endif %}>{{ text }}</a>
|
<a href="{{ url_for }}" {% if request.url.path == url_for %}class="active"{% endif %}>{{ text }}</a>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
<div style="margin:30px 0;">
|
<div style="margin:30px 0;">
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
{% include "header.html" %}
|
{% include "header.html" %}
|
||||||
|
|
||||||
{% for outbox_object in objects %}
|
{% for outbox_object in objects %}
|
||||||
{{ outbox_object.likes_count }}
|
|
||||||
{{ outbox_object.announces_count }}
|
|
||||||
{{ utils.display_object(outbox_object) }}
|
{{ utils.display_object(outbox_object) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,12 @@
|
||||||
|
|
||||||
{% macro display_replies_tree(replies_tree_node) %}
|
{% macro display_replies_tree(replies_tree_node) %}
|
||||||
|
|
||||||
{{ utils.display_object(replies_tree_node.ap_object) }}
|
{% if replies_tree_node.is_requested %}
|
||||||
|
{{ utils.display_object_expanded(replies_tree_node.ap_object) }}
|
||||||
|
{% else %}
|
||||||
|
{{ utils.display_object(replies_tree_node.ap_object) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% for child in replies_tree_node.children %}
|
{% for child in replies_tree_node.children %}
|
||||||
{{ display_replies_tree(child) }}
|
{{ display_replies_tree(child) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -60,7 +60,6 @@
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro display_actor(actor, actors_metadata) %}
|
{% macro display_actor(actor, actors_metadata) %}
|
||||||
{{ actors_metadata }}
|
|
||||||
{% set metadata = actors_metadata.get(actor.ap_id) %}
|
{% set metadata = actors_metadata.get(actor.ap_id) %}
|
||||||
<div style="display: flex;column-gap: 20px;margin:20px 0 10px 0;" class="actor-box">
|
<div style="display: flex;column-gap: 20px;margin:20px 0 10px 0;" class="actor-box">
|
||||||
<div style="flex: 0 0 48px;">
|
<div style="flex: 0 0 48px;">
|
||||||
|
@ -71,19 +70,20 @@
|
||||||
<div>{{ actor.handle }}</div>
|
<div>{{ actor.handle }}</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% if metadata %}
|
{% if is_admin and metadata %}
|
||||||
<div>
|
<div>
|
||||||
<nav class="flexbox">
|
<nav class="flexbox">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
{% if metadata.is_following %}
|
||||||
{% if metadata.is_following %}already following {{ admin_undo_button(metadata.outbox_follow_ap_id, "Unfollow")}}
|
<li>already following</li>
|
||||||
{% elif metadata.is_follow_request_sent %}follow request sent
|
<li>{{ admin_undo_button(metadata.outbox_follow_ap_id, "Unfollow")}}</li>
|
||||||
|
{% elif metadata.is_follow_request_sent %}
|
||||||
|
<li>follow request sent</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ admin_follow_button(actor) }}
|
<li>{{ admin_follow_button(actor) }}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
{% if metadata.is_follower %}
|
||||||
<li>
|
<li>follows you</li>
|
||||||
{% if metadata.is_follower %}follows you{% else %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -93,6 +93,31 @@
|
||||||
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro display_object_expanded(object) %}
|
||||||
|
|
||||||
|
<div class="activity-expanded">
|
||||||
|
|
||||||
|
{{ display_actor(object.actor, {}) }}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{{ object.content | clean_html | safe }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="{{ object.url }}">{{ object.ap_published_at | format_date }}</a>
|
||||||
|
{{ object.visibility.value }}
|
||||||
|
{% if object.is_from_outbox %}
|
||||||
|
{{ object.likes_count }} likes
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if object.is_from_outbox %}
|
||||||
|
{{ object.announces_count }} shares
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro display_object(object) %}
|
{% macro display_object(object) %}
|
||||||
{% if object.ap_type in ["Note", "Article", "Video"] %}
|
{% if object.ap_type in ["Note", "Article", "Video"] %}
|
||||||
<div class="activity-wrap" id="{{ object.permalink_id }}">
|
<div class="activity-wrap" id="{{ object.permalink_id }}">
|
||||||
|
@ -132,21 +157,57 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="activity-bar">
|
<div class="activity-bar">
|
||||||
|
{% if object.is_from_outbox %}
|
||||||
<div class="bar-item">
|
<div class="bar-item">
|
||||||
<div class="comment-count">33</div>
|
<div class="comment-count">{{ object.likes_count }} like{{ object.likes_count | pluralize }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bar-item">
|
<div class="bar-item">
|
||||||
<div class="retweet-count">397</div>
|
<div class="retweet-count">{{ object.announces_count }} share{{ object.announces_count | pluralize }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bar-item">
|
<div class="bar-item">
|
||||||
<div class="likes-count">
|
<div class="retweet-count">{{ object.replies_count }} repl{{ object.replies_count | pluralize("y", "ies") }}</div>
|
||||||
2.6k
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if is_admin %}
|
||||||
|
<div class="bar-item">
|
||||||
|
{{ admin_reply_button(object.ap_id) }}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if object.is_from_inbox %}
|
||||||
|
{% if object.liked_via_outbox_object_ap_id %}
|
||||||
|
<div class="bar-item">
|
||||||
|
{{ admin_undo_button(object.liked_via_outbox_object_ap_id, "Unlike") }}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="bar-item">
|
||||||
|
{{ admin_like_button(object.ap_id) }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="bar-item">
|
||||||
|
{{ admin_announce_button(object.ap_id) }}
|
||||||
|
</div>
|
||||||
|
<div class="bar-item">
|
||||||
|
{{ admin_reply_button(object.ap_id) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% elif object.ap_type == "Follow" %}
|
||||||
|
|
||||||
|
{% if object.is_from_inbox %}
|
||||||
|
<div class="actor-action">
|
||||||
|
{{ object.actor.display_name }} followed you
|
||||||
|
<span>{{ object.ap_published_at | timeago }}</span>
|
||||||
|
</div>
|
||||||
|
{{ display_actor(object.actor, {}) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
Loading…
Reference in New Issue