stuff
parent
0b12528fc2
commit
6ec069a2f6
|
@ -101,6 +101,7 @@ class Config(pydantic.BaseModel):
|
|||
secret: str
|
||||
debug: bool = False
|
||||
trusted_hosts: list[str] = ["127.0.0.1"]
|
||||
tags: list[str] | None = None
|
||||
manually_approves_followers: bool = False
|
||||
privacy_replace: list[_PrivacyReplace] | None = None
|
||||
metadata: list[_ProfileMetadata] | None = None
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 154 KiB |
|
@ -433,6 +433,7 @@ _templates.env.filters["privacy_replace_url"] = privacy_replace.replace_url
|
|||
_templates.env.globals["JS_HASH"] = config.JS_HASH
|
||||
_templates.env.globals["CSS_HASH"] = config.CSS_HASH
|
||||
_templates.env.globals["BASE_URL"] = config.BASE_URL
|
||||
_templates.env.globals["TAGS"] = config.CONFIG.tags
|
||||
_templates.env.globals["HIDES_FOLLOWERS"] = config.HIDES_FOLLOWERS
|
||||
_templates.env.globals["HIDES_FOLLOWING"] = config.HIDES_FOLLOWING
|
||||
_templates.env.globals["NAVBAR_ITEMS"] = config.NavBarItems
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }} - Direct messages</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% for anybox_object, convo, actors in threads %}
|
||||
<div class="actor-action">
|
||||
With {% for actor in actors %}
|
||||
<a href="{{ url_for("admin_profile") }}?actor_id={{ actor.ap_id }}">
|
||||
{{ actor.handle }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{{ utils.display_object(anybox_object) }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
|
@ -1,46 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }} - Inbox</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if show_filters %}
|
||||
{{ utils.display_box_filters("admin_inbox") }}
|
||||
{% endif %}
|
||||
|
||||
{% if not inbox %}
|
||||
<div class="box">
|
||||
<p>Nothing to see yet, <a href="{{ url_for("get_lookup") }}">start following people in the lookup section</a>.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for inbox_object in inbox %}
|
||||
{% if inbox_object.ap_type == "Announce" %}
|
||||
{{ utils.actor_action(inbox_object, "shared", with_icon=True) }}
|
||||
{{ utils.display_object(inbox_object.relates_to_anybox_object) }}
|
||||
{% elif inbox_object.ap_type in ["Article", "Note", "Video", "Page", "Question"] %}
|
||||
{{ utils.display_object(inbox_object) }}
|
||||
{% elif inbox_object.ap_type == "Follow" %}
|
||||
{{ utils.actor_action(inbox_object, "followed you") }}
|
||||
{{ utils.display_actor(inbox_object.actor, actors_metadata) }}
|
||||
{% elif inbox_object.ap_type == "Like" %}
|
||||
{{ utils.actor_action(inbox_object, "liked one of your posts", with_icon=True) }}
|
||||
{{ utils.display_object(inbox_object.relates_to_anybox_object) }}
|
||||
{% else %}
|
||||
<p>
|
||||
Implement {{ inbox_object.ap_type }}
|
||||
{{ inbox_object.ap_object }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if next_cursor %}
|
||||
<div class="box">
|
||||
<p><a href="{{ request.url._path }}?cursor={{ next_cursor }}{% if request.query_params.filter_by %}&filter_by={{ request.query_params.filter_by }}{% endif %}">See more</a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,94 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }} - New</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if in_reply_to_object %}
|
||||
<div class="actor-action">In reply to:</div>
|
||||
{{ utils.display_object(in_reply_to_object) }}
|
||||
{% endif %}
|
||||
|
||||
<div class="box">
|
||||
<nav class="flexbox">
|
||||
<ul>
|
||||
{% for ap_type in ["Note", "Article", "Question"] %}
|
||||
<li><a href="?type={{ ap_type }}" {% if request.query_params.get("type", "Note") == ap_type %}class="active"{% endif %}>
|
||||
{{ ap_type }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
<form class="form admin-new" action="{{ request.url_for("admin_actions_new") }}" enctype="multipart/form-data" method="POST">
|
||||
{{ utils.embed_csrf_token() }}
|
||||
{{ utils.embed_redirect_url() }}
|
||||
<p>
|
||||
<select name="visibility">
|
||||
{% for (k, v) in visibility_choices %}
|
||||
<option value="{{ k }}" {% if visibility == k or in_reply_to_object and in_reply_to_object.visibility.name == k %}selected{% endif %}>{{ v }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</p>
|
||||
|
||||
{% if request.query_params.type == "Article" %}
|
||||
<p>
|
||||
<input type="text" class="width-95" name="name" placeholder="Title">
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% for emoji in emojis %}
|
||||
<span class="ji">{{ emoji | emojify(True) | safe }}</span>
|
||||
{% endfor %}
|
||||
{% for emoji in custom_emojis %}
|
||||
<span class="ji"><img src="{{ emoji.icon.url }}" alt="{{ emoji.name }}" title="{{ emoji.name }}" class="custom-emoji"></span>
|
||||
{% endfor %}
|
||||
|
||||
<textarea name="content" rows="10" cols="50" autofocus="autofocus" designMode="on" placeholder="Hey!">{{ content }}</textarea>
|
||||
|
||||
{% if request.query_params.type == "Question" %}
|
||||
<p>
|
||||
<select name="poll_type">
|
||||
<option value="oneOf">single choice</option>
|
||||
<option value="anyOf">multiple choices</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<select name="poll_duration">
|
||||
<option value="5">ends in 5 minutes</option>
|
||||
<option value="30">ends in 30 minutes</option>
|
||||
<option value="60">ends in 1 hour</option>
|
||||
<option value="360">ends in 6 hours</option>
|
||||
<option value="1440">ends in 1 day</option>
|
||||
</select>
|
||||
</p>
|
||||
{% for i in ["1", "2", "3", "4"] %}
|
||||
<p>
|
||||
<input type="text" name="poll_answer_{{ i }}" class="width-95" placeholder="Option {{ i }}, leave empty to disable">
|
||||
</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
<input type="text" name="content_warning" placeholder="content warning (will mark the post as sensitive)"{% if content_warning %} value="{{ content_warning }}"{% endif %} class="width-95">
|
||||
</p>
|
||||
<p>
|
||||
<input type="checkbox" name="is_sensitive" id="is_sensitive"> <label for="is_sensitive">Mark attachment(s) as sensitive</label>
|
||||
</p>
|
||||
<input type="hidden" name="in_reply_to" value="{{ request.query_params.in_reply_to }}">
|
||||
<p>
|
||||
<input id="files" name="files" type="file" class="width-95" multiple>
|
||||
</p>
|
||||
<div id="alts"></div>
|
||||
<p>
|
||||
<input type="submit" value="Publish">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<script src="{{ BASE_URL }}/static/new.js?v={{ JS_HASH }}"></script>
|
||||
{% endblock %}
|
|
@ -1,35 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }} - Outbox</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ utils.display_box_filters("admin_outbox") }}
|
||||
|
||||
{% for outbox_object in outbox %}
|
||||
|
||||
{% if outbox_object.ap_type == "Announce" %}
|
||||
<div class="actor-action">You shared <span title="{{ outbox_object.ap_published_at.isoformat() }}">{{ outbox_object.ap_published_at | timeago }}</span></div>
|
||||
{{ utils.display_object(outbox_object.relates_to_anybox_object) }}
|
||||
{% elif outbox_object.ap_type == "Like" %}
|
||||
<div class="actor-action">You liked <span title="{{ outbox_object.ap_published_at.isoformat() }}">{{ outbox_object.ap_published_at | timeago }}</span></div>
|
||||
{{ utils.display_object(outbox_object.relates_to_anybox_object) }}
|
||||
{% elif outbox_object.ap_type == "Follow" %}
|
||||
<div class="actor-action">You followed <span title="{{ outbox_object.ap_published_at.isoformat() }}">{{ outbox_object.ap_published_at | timeago }}</span></div>
|
||||
{{ utils.display_actor(outbox_object.relates_to_actor, actors_metadata) }}
|
||||
{% elif outbox_object.ap_type in ["Article", "Note", "Video", "Question"] %}
|
||||
{{ utils.display_object(outbox_object) }}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% if next_cursor %}
|
||||
<div class="box">
|
||||
<p><a href="{{ url_for("admin_outbox") }}?cursor={{ next_cursor }}{% if request.query_params.filter_by %}&filter_by={{ request.query_params.filter_by }}{% endif %}">See more</a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,29 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }} - {{ actor.display_name }}</title>
|
||||
{% endblock %}
|
||||
|
||||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
{{ utils.display_actor(actor, actors_metadata, with_details=True) }}
|
||||
{% for inbox_object in inbox_objects %}
|
||||
{% if inbox_object.ap_type == "Announce" %}
|
||||
{{ utils.actor_action(inbox_object, "shared", with_icon=True) }}
|
||||
{{ utils.display_object(inbox_object.relates_to_anybox_object) }}
|
||||
{% else %}
|
||||
{{ utils.display_object(inbox_object) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if next_cursor %}
|
||||
<div class="box">
|
||||
<p>
|
||||
<a href="{{ request.url._path }}?actor_id={{ request.query_params.actor_id }}&cursor={{ next_cursor }}">
|
||||
See more
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,18 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }} - Stream</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% for inbox_object in stream %}
|
||||
{% if inbox_object.ap_type == "Announce" %}
|
||||
{{ utils.display_object(inbox_object.relates_to_anybox_object) }}
|
||||
{% elif inbox_object.ap_type in ["Article", "Note", "Video"] %}
|
||||
{{ utils.display_object(inbox_object) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,20 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }}'s articles</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
|
||||
<ul class="h-feed" id="articles">
|
||||
<data class="p-name" value="{{ local_actor.display_name}}'s articles"></data>
|
||||
{% for outbox_object in objects %}
|
||||
<li class="h-entry">
|
||||
<time class="muted dt-published" datetime="{{ outbox_object.ap_published_at.isoformat() }}">{{ outbox_object.ap_published_at.strftime("%b %d, %Y") }}</time> <a href="{{ outbox_object.url }}" class="u-url u-uid p-name">{{ outbox_object.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
|
@ -1,30 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ title }}</title>
|
||||
{% if request.url.path == "/" %}
|
||||
<link rel="indieauth-metadata" href="{{ url_for("well_known_authorization_server") }}">
|
||||
<link rel="authorization_endpoint" href="{{ url_for("indieauth_authorization_endpoint") }}">
|
||||
<link rel="token_endpoint" href="{{ url_for("indieauth_token_endpoint") }}">
|
||||
<link rel="micropub" href="{{ url_for("micropub_endpoint") }}">
|
||||
<link rel="alternate" href="{{ local_actor.url }}" title="ActivityPub profile" type="application/activity+json">
|
||||
<meta content="profile" property="og:type" />
|
||||
<meta content="{{ local_actor.url }}" property="og:url" />
|
||||
<meta content="{{ local_actor.display_name }}'s microblog" property="og:site_name" />
|
||||
<meta content="Homepage" property="og:title" />
|
||||
<meta content="{{ local_actor.summary | html2text | trim }}" property="og:description" />
|
||||
<meta content="{{ ICON_URL }}" property="og:image" />
|
||||
<meta content="summary" property="twitter:card" />
|
||||
<meta content="{{ local_actor.handle }}" property="profile:username" />
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
|
||||
<div class="box">
|
||||
{{ page_content | safe }}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,12 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
{% block main_tag %} class="main-flex"{% endblock %}
|
||||
{% block head %}
|
||||
<title>{{ title }}</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="centered primary-color box">
|
||||
<h1 class="error-title">{{ title | safe }}</h1>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,32 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }}'s followers</title>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
<div id="followers">
|
||||
<ul>
|
||||
{% for follower in followers %}
|
||||
<li>{{ utils.display_actor(follower.actor, actors_metadata) }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% set x_more = followers_count - followers | length %}
|
||||
{% if x_more > 0 %}
|
||||
<div class="box">
|
||||
<p>And {{ x_more }} more.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if is_admin %}
|
||||
<div class="box">
|
||||
<p><a href="{{ url_for("admin_inbox") }}?filter_by=Follow">Manage followers</a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,32 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }}'s follows</title>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
<div id="following">
|
||||
<ul>
|
||||
{% for follow in following %}
|
||||
<li>{{ utils.display_actor(follow.actor, actors_metadata) }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% set x_more = following_count - following | length %}
|
||||
{% if x_more > 0 %}
|
||||
<div class="box">
|
||||
<p>And {{ x_more }} more.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if is_admin %}
|
||||
<div class="box">
|
||||
<p><a href="{{ url_for("admin_outbox") }}?filter_by=Follow">Manage follows</a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,62 +0,0 @@
|
|||
<header id="header">
|
||||
|
||||
<div class="h-card p-author">
|
||||
<data class="u-photo" value="{{ local_actor.icon_url }}"></data>
|
||||
<a href="{{ local_actor.url }}" class="u-url u-uid no-hover title">
|
||||
<span class="name">{{ local_actor.name }}</span>
|
||||
<span class="p-name handle">{{ local_actor.handle }}</span>
|
||||
</a>
|
||||
|
||||
<div class="p-note summary">
|
||||
{{ local_actor.summary | safe }}
|
||||
</div>
|
||||
|
||||
<div id="profile-props">
|
||||
{% for prop in local_actor.attachments %}
|
||||
<dl>
|
||||
{% if prop.type == "PropertyValue" %}
|
||||
<dt class="muted" title="{{ prop.name }}">{{ prop.name }}</dt>
|
||||
<dd>{{ prop.value | clean_html(local_actor) | safe }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{%- macro header_link(url, text) -%}
|
||||
{% set url_for = BASE_URL + request.app.router.url_path_for(url) %}
|
||||
<a href="{{ url_for }}" {% if BASE_URL + request.url.path == url_for %}class="active"{% endif %}>{{ text }}</a>
|
||||
{% endmacro %}
|
||||
|
||||
{%- macro navbar_item_link(navbar_item) -%}
|
||||
{% set url_for = BASE_URL + navbar_item[0] %}
|
||||
<a href="{{ navbar_item[0] }}" {% if BASE_URL + request.url.path == url_for %}class="active"{% endif %}>{{ navbar_item[1] }}</a>
|
||||
{% endmacro %}
|
||||
|
||||
<div class="public-top-menu">
|
||||
<nav class="flexbox">
|
||||
<ul>
|
||||
{% if NAVBAR_ITEMS.INDEX_NAVBAR_ITEM %}
|
||||
<li>{{ navbar_item_link(NAVBAR_ITEMS.INDEX_NAVBAR_ITEM) }}</li>
|
||||
{% endif %}
|
||||
<li>{{ header_link("index", "Notes") }}</li>
|
||||
{% if articles_count %}
|
||||
<li>{{ header_link("articles", "Articles") }}</li>
|
||||
{% endif %}
|
||||
{% if not HIDES_FOLLOWERS or is_admin %}
|
||||
<li>{{ header_link("followers", "Followers") }} <span class="counter">{{ followers_count }}</span></li>
|
||||
{% endif %}
|
||||
{% if not HIDES_FOLLOWING or is_admin %}
|
||||
<li>{{ header_link("following", "Following") }} <span class="counter">{{ following_count }}</span></li>
|
||||
{% endif %}
|
||||
<li>{{ header_link("get_remote_follow", "Remote follow") }}</li>
|
||||
{% for navbar_item in NAVBAR_ITEMS.EXTRA_NAVBAR_ITEMS %}
|
||||
{{ navbar_item_link(navbar_item) }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
</header>
|
|
@ -1,60 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }}'s microblog</title>
|
||||
<link rel="indieauth-metadata" href="{{ url_for("well_known_authorization_server") }}">
|
||||
<link rel="authorization_endpoint" href="{{ url_for("indieauth_authorization_endpoint") }}">
|
||||
<link rel="token_endpoint" href="{{ url_for("indieauth_token_endpoint") }}">
|
||||
<link rel="micropub" href="{{ url_for("micropub_endpoint") }}">
|
||||
<link rel="alternate" href="{{ local_actor.url }}" title="ActivityPub profile" type="application/activity+json">
|
||||
<meta content="profile" property="og:type" />
|
||||
<meta content="{{ local_actor.url }}" property="og:url" />
|
||||
<meta content="{{ local_actor.display_name }}'s microblog" property="og:site_name" />
|
||||
<meta content="Homepage" property="og:title" />
|
||||
<meta content="{{ local_actor.summary | html2text | trim }}" property="og:description" />
|
||||
<meta content="{{ ICON_URL }}" property="og:image" />
|
||||
<meta content="summary" property="twitter:card" />
|
||||
<meta content="{{ local_actor.handle }}" property="profile:username" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
|
||||
{% if objects %}
|
||||
|
||||
<div class="h-feed">
|
||||
<data class="p-name" value="{{ local_actor.display_name}}'s notes"></data>
|
||||
{% for outbox_object in objects %}
|
||||
{% if outbox_object.ap_type in ["Note", "Video", "Question"] %}
|
||||
{{ utils.display_object(outbox_object) }}
|
||||
{% elif outbox_object.ap_type == "Announce" %}
|
||||
<div class="h-entry" id="{{ outbox_object.permalink_id }}">
|
||||
<div class="shared-header"><strong><a class="p-author h-card" href="{{ local_actor.url }}">{{ utils.display_tiny_actor_icon(local_actor) }} {{ local_actor.display_name | clean_html(local_actor) | safe }}</a></strong> shared <span title="{{ outbox_object.ap_published_at.isoformat() }}">{{ outbox_object.ap_published_at | timeago }}</span></div>
|
||||
<div class="h-cite u-repost-of">
|
||||
{{ utils.display_object(outbox_object.relates_to_anybox_object, is_h_entry=False) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if has_previous_page or has_next_page %}
|
||||
<div class="box">
|
||||
{% if has_previous_page %}
|
||||
<a href="{{ url_for("index") }}?page={{ current_page - 1 }}">Previous</a>
|
||||
{% endif %}
|
||||
|
||||
{% if has_next_page %}
|
||||
<a href="{{ url_for("index") }}?page={{ current_page + 1 }}">Next</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>Nothing to see here yet!</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,45 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<div class="box">
|
||||
<div class"indieauth-box">
|
||||
{% if client.logo %}
|
||||
<div class="indieauth-logo">
|
||||
<img src="{{client.logo | media_proxy_url }}" alt="{{ client.name }} logo">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="indieauth-details">
|
||||
<div>
|
||||
{% if client.url %}
|
||||
<a class="scolor" href="{{ client.url }}">{{ client.name }}</a>
|
||||
{% else %}
|
||||
<span class="scolor">{{ client.name }}</span>
|
||||
{% endif %}
|
||||
<p>wants you to login{% if me %} as <strong class="lcolor">{{ me }}</strong>{% endif %} with the following redirect URI: <code>{{ redirect_uri }}</code>.</p>
|
||||
|
||||
|
||||
<form method="POST" action="{{ url_for('indieauth_flow') }}" class="form">
|
||||
{{ utils.embed_csrf_token() }}
|
||||
{% if scopes %}
|
||||
<h3>Scopes</h3>
|
||||
<ul>
|
||||
{% for scope in scopes %}
|
||||
<li><input type="checkbox" name="scopes" value="{{scope}}" id="scope-{{scope}}"><label for="scope-{{scope}}">{{ scope }}</label>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<input type="hidden" name="redirect_uri" value="{{ redirect_uri }}">
|
||||
<input type="hidden" name="state" value="{{ state }}">
|
||||
<input type="hidden" name="client_id" value="{{ client_id }}">
|
||||
<input type="hidden" name="me" value="{{ me }}">
|
||||
<input type="hidden" name="response_type" value="{{ response_type }}">
|
||||
<input type="hidden" name="code_challenge" value="{{ code_challenge }}">
|
||||
<input type="hidden" name="code_challenge_method" value="{{ code_challenge_method }}">
|
||||
<input type="submit" value="login">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,60 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="{{ BASE_URL }}/static/css/main.css?v={{ CSS_HASH }}">
|
||||
<link rel="alternate" title="{{ local_actor.display_name}}'s microblog" type="application/json" href="{{ url_for("json_feed") }}" />
|
||||
<link rel="alternate" href="{{ url_for("rss_feed") }}" type="application/rss+xml" title="{{ local_actor.display_name}}'s microblog">
|
||||
<link rel="alternate" href="{{ url_for("atom_feed") }}" type="application/atom+xml" title="{{ local_actor.display_name}}'s microblog">
|
||||
<link rel="icon" type="image/x-icon" href="{{ BASE_URL }}/static/favicon.ico">
|
||||
<style>{{ highlight_css }}</style>
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<main{%- block main_tag %}{%- endblock %}>
|
||||
{% if is_admin %}
|
||||
<div id="admin">
|
||||
{% macro admin_link(url, text) %}
|
||||
{% set url_for = BASE_URL + request.app.router.url_path_for(url) %}
|
||||
<a href="{{ url_for }}" {% if BASE_URL + request.url.path == url_for %}class="active"{% endif %}>{{ text }}</a>
|
||||
{% endmacro %}
|
||||
<div class="admin-menu">
|
||||
<nav class="flexbox">
|
||||
<ul>
|
||||
<li>{{ admin_link("index", "Public") }}</li>
|
||||
<li>{{ admin_link("admin_new", "New") }}</li>
|
||||
<li>{{ admin_link("admin_stream", "Stream") }}</li>
|
||||
<li>{{ admin_link("admin_inbox", "Inbox") }} / {{ admin_link("admin_outbox", "Outbox") }}</li>
|
||||
<li>{{ admin_link("admin_direct_messages", "DMs") }}</li>
|
||||
<li>{{ admin_link("get_notifications", "Notifications") }} {% if notifications_count %}({{ notifications_count }}){% endif %}</li>
|
||||
<li>{{ admin_link("get_lookup", "Lookup") }}</li>
|
||||
<li>{{ admin_link("admin_bookmarks", "Bookmarks") }}</li>
|
||||
<li><a href="{{ url_for("logout")}}">Logout</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="box">
|
||||
{% if custom_footer %}
|
||||
{{ custom_footer | safe }}
|
||||
{% else %}
|
||||
Powered by <a href="https://docs.microblog.pub">microblog.pub</a> <small class="microblogpub-version"><code>{{ microblogpub_version }}</code></small> and the <a href="https://activitypub.rocks/">ActivityPub</a> protocol. <a href="{{ url_for("login") }}">Admin</a>.
|
||||
{% endif %}
|
||||
</div>
|
||||
</footer>
|
||||
{% if is_admin %}
|
||||
<script src="{{ BASE_URL }}/static/common-admin.js?v={{ JS_HASH }}"></script>
|
||||
{% endif %}
|
||||
<script src="{{ BASE_URL }}/static/common.js?v={{ JS_HASH }}"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,21 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
{% block head %}
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{% endblock %}
|
||||
{% block main_tag %} class="main-flex"{% endblock %}
|
||||
{% block content %}
|
||||
<div class="centered">
|
||||
<div>
|
||||
{% if error %}
|
||||
<p class="primary-color">Invalid password.</p>
|
||||
{% endif %}
|
||||
<form class="form" action="{{ BASE_URL }}/admin/login" method="POST">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="redirect" value="{{ redirect }}">
|
||||
<input type="password" placeholder="password" name="password" autofocus>
|
||||
<input type="submit" value="login">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,38 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }} - Lookup</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="box">
|
||||
<p>Interact with an ActivityPub object via its URL or look for a user using <i>@user@domain.tld</i></p>
|
||||
|
||||
<form class="form" action="{{ url_for("get_lookup") }}" method="GET">
|
||||
<input type="text" name="query" value="{{ query if query else "" }}" autofocus>
|
||||
<input type="submit" value="Lookup">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if error %}
|
||||
<div class="box error-box">
|
||||
{% if error.value == "NOT_FOUND" %}
|
||||
<p>The remote object is unavailable.</p>
|
||||
{% elif error.value == "UNAUTHORIZED" %}
|
||||
<p>Missing permissions to fetch the remote object.</p>
|
||||
{% elif error.value == "TIMEOUT" %}
|
||||
<p>Lookup timed out, please try refreshing the page.</p>
|
||||
{% else %}
|
||||
<p>Unexpected error, please check the logs and report an issue if needed.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if ap_object and ap_object.ap_type in actor_types %}
|
||||
{{ utils.display_actor(ap_object, actors_metadata, with_details=True) }}
|
||||
{% elif ap_object %}
|
||||
{{ utils.display_object(ap_object, actors_metadata=actors_metadata) }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -1,126 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }} - Notifications</title>
|
||||
{% endblock %}
|
||||
|
||||
{% macro notif_actor_action(notif, text, with_icon=False) %}
|
||||
<div class="actor-action">
|
||||
<a href="{{ url_for("admin_profile") }}?actor_id={{ notif.actor.ap_id }}">
|
||||
{% if with_icon %}{{ utils.display_tiny_actor_icon(notif.actor) }}{% endif %} {{ notif.actor.display_name | clean_html(notif.actor) | safe }}</a> {{ text }}
|
||||
<span title="{{ notif.created_at.isoformat() }}">{{ notif.created_at | timeago }}</span>
|
||||
{% if notif.is_new %}
|
||||
<span class="new">new</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<div class="box">
|
||||
<h2>Notifications</h2>
|
||||
</div>
|
||||
<div id="notifications">
|
||||
{%- for notif in notifications %}
|
||||
<div>
|
||||
{%- if notif.notification_type.value == "new_follower" %}
|
||||
{{ notif_actor_action(notif, "followed you") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata) }}
|
||||
{%- elif notif.notification_type.value == "pending_incoming_follower" %}
|
||||
{{ notif_actor_action(notif, "sent a follow request") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata, pending_incoming_follow_notif=notif) }}
|
||||
{% elif notif.notification_type.value == "rejected_follower" %}
|
||||
{% elif notif.notification_type.value == "unfollow" %}
|
||||
{{ notif_actor_action(notif, "unfollowed you") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata) }}
|
||||
{%- elif notif.notification_type.value == "follow_request_accepted" %}
|
||||
{{ notif_actor_action(notif, "accepted your follow request") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata) }}
|
||||
{%- elif notif.notification_type.value == "follow_request_rejected" %}
|
||||
{{ notif_actor_action(notif, "rejected your follow request") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata) }}
|
||||
{% elif notif.notification_type.value == "blocked" %}
|
||||
{{ notif_actor_action(notif, "blocked you") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata) }}
|
||||
{% elif notif.notification_type.value == "unblocked" %}
|
||||
{{ notif_actor_action(notif, "unblocked you") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata) }}
|
||||
{% elif notif.notification_type.value == "block" %}
|
||||
{{ notif_actor_action(notif, "was blocked") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata) }}
|
||||
{% elif notif.notification_type.value == "unblock" %}
|
||||
{{ notif_actor_action(notif, "was unblocked") }}
|
||||
{{ utils.display_actor(notif.actor, actors_metadata) }}
|
||||
{%- elif notif.notification_type.value == "move" %}
|
||||
{# for move notif, the actor is the target and the inbox object the Move activity #}
|
||||
<div class="actor-action">
|
||||
<a href="{{ url_for("admin_profile") }}?actor_id={{ notif.inbox_object.actor.ap_id }}">
|
||||
{{ utils.display_tiny_actor_icon(notif.inbox_object.actor) }} {{ notif.inbox_object.actor.display_name | clean_html(notif.inbox_object.actor) | safe }}</a> has moved to
|
||||
<span title="{{ notif.created_at.isoformat() }}">{{ notif.created_at | timeago }}</span>
|
||||
</div>
|
||||
{{ utils.display_actor(notif.actor) }}
|
||||
{% elif notif.notification_type.value == "like" %}
|
||||
{{ notif_actor_action(notif, "liked a post", with_icon=True) }}
|
||||
{{ utils.display_object(notif.outbox_object) }}
|
||||
{% elif notif.notification_type.value == "undo_like" %}
|
||||
{{ notif_actor_action(notif, "unliked a post", with_icon=True) }}
|
||||
{{ utils.display_object(notif.outbox_object) }}
|
||||
{% elif notif.notification_type.value == "announce" %}
|
||||
{{ notif_actor_action(notif, "shared a post", with_icon=True) }}
|
||||
{{ utils.display_object(notif.outbox_object) }}
|
||||
{% elif notif.notification_type.value == "undo_announce" %}
|
||||
{{ notif_actor_action(notif, "unshared a post", with_icon=True) }}
|
||||
{{ utils.display_object(notif.outbox_object) }}
|
||||
{% elif notif.notification_type.value == "mention" %}
|
||||
{{ notif_actor_action(notif, "mentioned you") }}
|
||||
{{ utils.display_object(notif.inbox_object) }}
|
||||
{% elif notif.notification_type.value == "new_webmention" %}
|
||||
<div class="actor-action" title="{{ notif.created_at.isoformat() }}">
|
||||
new webmention from
|
||||
{% set facepile_item = notif.webmention.as_facepile_item %}
|
||||
{% if facepile_item %}
|
||||
<a href="{{ facepile_item.actor_url }}">{{ facepile_item.actor_name }}</a>
|
||||
{% endif %}
|
||||
<a class="bold" href="{{ notif.webmention.source }}">{{ notif.webmention.source }}</a>
|
||||
</div>
|
||||
{{ utils.display_object(notif.outbox_object) }}
|
||||
{% elif notif.notification_type.value == "updated_webmention" %}
|
||||
<div class="actor-action" title="{{ notif.created_at.isoformat() }}">
|
||||
updated webmention from
|
||||
{% set facepile_item = notif.webmention.as_facepile_item %}
|
||||
{% if facepile_item %}
|
||||
<a href="{{ facepile_item.actor_url }}">{{ facepile_item.actor_name }}</a>
|
||||
{% endif %}
|
||||
<a class="bold" href="{{ notif.webmention.source }}">{{ notif.webmention.source }}</a>
|
||||
</div>
|
||||
{{ utils.display_object(notif.outbox_object) }}
|
||||
{% elif notif.notification_type.value == "deleted_webmention" %}
|
||||
<div class="actor-action" title="{{ notif.created_at.isoformat() }}">
|
||||
deleted webmention from
|
||||
{% set facepile_item = notif.webmention.as_facepile_item %}
|
||||
{% if facepile_item %}
|
||||
<a href="{{ facepile_item.actor_url }}">{{ facepile_item.actor_name }}</a>
|
||||
{% endif %}
|
||||
<a class="bold" href="{{ notif.webmention.source }}">{{ notif.webmention.source }}</a>
|
||||
</div>
|
||||
{{ utils.display_object(notif.outbox_object) }}
|
||||
{% else %}
|
||||
<div class="actor-action">
|
||||
Implement {{ notif.notification_type }}
|
||||
</div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{%- endfor %}
|
||||
</div>
|
||||
|
||||
{% if next_cursor %}
|
||||
<div class="box">
|
||||
<p>
|
||||
<a href="{{ request.url._path }}?cursor={{ next_cursor }}">
|
||||
See more{% if more_unread_count %} ({{ more_unread_count }} unread left){% endif %}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,56 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
{% if outbox_object %}
|
||||
{% if outbox_object.content %}
|
||||
{% set excerpt = outbox_object.content | html2text | trim | truncate(50) %}
|
||||
{% else %}
|
||||
{% set excerpt = outbox_object.summary | html2text | trim | truncate(50) %}
|
||||
{% endif %}
|
||||
<title>{% if outbox_object.name %}{{ outbox_object.name }}{% else %}{{ local_actor.display_name }}: "{{ excerpt }}"{% endif %}</title>
|
||||
<link rel="webmention" href="{{ url_for("webmention_endpoint") }}">
|
||||
<link rel="alternate" href="{{ request.url }}" type="application/activity+json">
|
||||
<meta name="description" content="{{ excerpt }}">
|
||||
<meta content="article" property="og:type" />
|
||||
<meta content="{{ outbox_object.url }}" property="og:url" />
|
||||
<meta content="{{ local_actor.display_name }}'s microblog" property="og:site_name" />
|
||||
<meta content="{% if outbox_object.name %}{{ outbox_object.name }}{% else %}Note{% endif %}" property="og:title" />
|
||||
<meta content="{{ excerpt }}" property="og:description" />
|
||||
<meta content="{{ local_actor.icon_url }}" property="og:image" />
|
||||
<meta content="summary" property="twitter:card" />
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if outbox_object %}
|
||||
{% include "header.html" %}
|
||||
{% endif %}
|
||||
|
||||
{% macro display_replies_tree(replies_tree_node) %}
|
||||
|
||||
{% if replies_tree_node.is_requested %}
|
||||
{{ utils.display_object(replies_tree_node.ap_object, likes=likes, shares=shares, webmentions=webmentions, expanded=not replies_tree_node.is_root, is_object_page=True, is_h_entry=False) }}
|
||||
{% else %}
|
||||
{% if replies_tree_node.wm_reply %}
|
||||
{# u-comment h-cite is displayed by default for webmention #}
|
||||
{{ utils.display_webmention_reply(replies_tree_node.wm_reply) }}
|
||||
{% else %}
|
||||
<div class="u-comment h-cite">
|
||||
{{ utils.display_object(replies_tree_node.ap_object, is_h_entry=False) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% for child in replies_tree_node.children %}
|
||||
{{ display_replies_tree(child) }}
|
||||
{% endfor %}
|
||||
|
||||
{% endmacro %}
|
||||
|
||||
<div class="h-entry">
|
||||
{{ display_replies_tree(replies_tree) }}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,15 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }}'s microblog - Redirect</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
|
||||
<div class="box">
|
||||
<p>You are being redirected to: <a href="{{ url }}">{{ url }}</a></p>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,15 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>{{ local_actor.display_name }}'s microblog - Redirect</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
|
||||
<div class="box">
|
||||
<p>You are being redirected to your instance: <a href="{{ url }}">{{ url }}</a></p>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,21 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>Remote follow {{ local_actor.display_name }}</title>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
|
||||
<div class="box">
|
||||
<h2>Remotely follow {{ local_actor.display_name }}</h2>
|
||||
<form class="form" action="{{ url_for("post_remote_follow") }}" method="POST">
|
||||
{{ utils.embed_csrf_token() }}
|
||||
<input type="text" name="profile" placeholder="you@instance.tld" autofocus>
|
||||
<input type="submit" value="follow">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,27 +0,0 @@
|
|||
{%- import "utils.html" as utils with context -%}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
<title>Interact from your instance</title>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "header.html" %}
|
||||
|
||||
<div class="box">
|
||||
<h2>Interact with this object</h2>
|
||||
</div>
|
||||
|
||||
{{ utils.display_object(outbox_object) }}
|
||||
|
||||
<div class="box">
|
||||
<form class="form" action="{{ url_for("post_remote_interaction") }}" method="POST">
|
||||
{{ utils.embed_csrf_token() }}
|
||||
<input type="text" name="profile" placeholder="you@instance.tld" autofocus>
|
||||
<input type="hidden" name="ap_id" value="{{ outbox_object.ap_id }}">
|
||||
<input type="submit" value="interact from your instance">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,853 +0,0 @@
|
|||
{% macro embed_csrf_token() %}
|
||||
{% block embed_csrf_token scoped %}
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro embed_redirect_url(permalink_id=None) %}
|
||||
{% block embed_redirect_url scoped %}
|
||||
<input type="hidden" name="redirect_url" value="{{ request.url }}{% if permalink_id %}#{{ permalink_id }}{% endif %}">
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_block_button(actor) %}
|
||||
{% block admin_block_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_block") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url() }}
|
||||
<input type="hidden" name="ap_actor_id" value="{{ actor.ap_id }}">
|
||||
<input type="submit" value="block">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_unblock_button(actor) %}
|
||||
{% block admin_unblock_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_unblock") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url() }}
|
||||
<input type="hidden" name="ap_actor_id" value="{{ actor.ap_id }}">
|
||||
<input type="submit" value="unblock">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_hide_shares_button(actor) %}
|
||||
{% block admin_hide_shares_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_hide_announces") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url() }}
|
||||
<input type="hidden" name="ap_actor_id" value="{{ actor.ap_id }}">
|
||||
<input type="submit" value="hide shares">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_show_shares_button(actor) %}
|
||||
{% block admin_show_shares_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_show_announces") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url() }}
|
||||
<input type="hidden" name="ap_actor_id" value="{{ actor.ap_id }}">
|
||||
<input type="submit" value="show shares">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro admin_follow_button(actor) %}
|
||||
{% block admin_follow_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_follow") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url() }}
|
||||
<input type="hidden" name="ap_actor_id" value="{{ actor.ap_id }}">
|
||||
<input type="submit" value="follow">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_accept_incoming_follow_button(notif) %}
|
||||
{% block admin_accept_incoming_follow_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_accept_incoming_follow") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url() }}
|
||||
<input type="hidden" name="notification_id" value="{{ notif.id }}">
|
||||
<input type="submit" value="accept follow">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_reject_incoming_follow_button(notif) %}
|
||||
{% block admin_reject_incoming_follow_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_reject_incoming_follow") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url() }}
|
||||
<input type="hidden" name="notification_id" value="{{ notif.id }}">
|
||||
<input type="submit" value="reject follow">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_like_button(ap_object_id, permalink_id) %}
|
||||
{% block admin_like_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_like") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object_id }}">
|
||||
<input type="submit" value="like">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_bookmark_button(ap_object_id, permalink_id) %}
|
||||
{% block admin_bookmark_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_bookmark") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object_id }}">
|
||||
<input type="submit" value="bookmark">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_unbookmark_button(ap_object_id, permalink_id) %}
|
||||
{% block admin_unbookmark_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_unbookmark") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object_id }}">
|
||||
<input type="submit" value="unbookmark">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_pin_button(ap_object_id, permalink_id) %}
|
||||
{% block admin_pin_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_pin") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object_id }}">
|
||||
<input type="submit" value="pin">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_unpin_button(ap_object_id, permalink_id) %}
|
||||
{% block admin_unpin_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_unpin") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object_id }}">
|
||||
<input type="submit" value="unpin">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_delete_button(ap_object) %}
|
||||
{% block admin_delete_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_delete") }}" class="object-delete-form" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
<input type="hidden" name="redirect_url" value="{% if request.url.path.endswith("/" + ap_object.public_id) or (request.url.path == "/admin/object" and request.query_params.ap_id.endswith("/" + ap_object.public_id)) %}{{ request.base_url}}{% else %}{{ request.url }}{% endif %}">
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object.ap_id }}">
|
||||
<input type="submit" value="delete">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_force_delete_button(ap_object_id, permalink_id=None) %}
|
||||
{% block admin_force_delete_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_force_delete") }}" class="object-delete-form" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object_id }}">
|
||||
<input type="submit" value="local delete">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_force_delete_webmention_button(webmention_id, permalink_id=None) %}
|
||||
{% block admin_force_delete_webmention_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_force_delete_webmention") }}" class="object-delete-form" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="webmention_id" value="{{ webmention_id }}">
|
||||
<input type="submit" value="local delete">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_announce_button(ap_object_id, permalink_id=None) %}
|
||||
{% block admin_announce_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_announce") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object_id }}">
|
||||
<input type="submit" value="share">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_undo_button(ap_object_id, action="undo", permalink_id=None) %}
|
||||
{% block admin_undo_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_undo") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(permalink_id) }}
|
||||
<input type="hidden" name="ap_object_id" value="{{ ap_object_id }}">
|
||||
<input type="submit" value="{{ action }}">
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_reply_button(ap_object_id) %}
|
||||
{% block admin_reply_button scoped %}
|
||||
<form action="{{ BASE_URL }}/admin/new" method="GET">
|
||||
<input type="hidden" name="in_reply_to" value="{{ ap_object_id }}">
|
||||
<button type="submit">reply</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_dm_button(actor_handle) %}
|
||||
{% block admin_dm_button scoped %}
|
||||
<form action="{{ BASE_URL }}/admin/new" method="GET">
|
||||
<input type="hidden" name="with_content" value="{{ actor_handle }}">
|
||||
<input type="hidden" name="with_visibility" value="DIRECT">
|
||||
<button type="submit">direct message</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_mention_button(actor_handle) %}
|
||||
{% block admin_mention_button scoped %}
|
||||
<form action="{{ BASE_URL }}/admin/new" method="GET">
|
||||
<input type="hidden" name="with_content" value="{{ actor_handle }}">
|
||||
<button type="submit">mention</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
{% macro admin_profile_button(ap_actor_id) %}
|
||||
{% block admin_profile_button scoped %}
|
||||
<form action="{{ url_for("admin_profile") }}" method="GET">
|
||||
<input type="hidden" name="actor_id" value="{{ ap_actor_id }}">
|
||||
<button type="submit">profile</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro admin_expand_button(ap_object) %}
|
||||
{% block admin_expand_button scoped %}
|
||||
{# TODO turn these into a regular link and append permalink ID if it's a reply #}
|
||||
<form action="{{ url_for("admin_object") }}" method="GET">
|
||||
<input type="hidden" name="ap_id" value="{{ ap_object.ap_id }}">
|
||||
<button type="submit">expand</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro display_box_filters(route) %}
|
||||
{% block display_box_filters scoped %}
|
||||
<nav class="flexbox box">
|
||||
<ul>
|
||||
<li>Filter by</li>
|
||||
{% for ap_type in ["Note", "Article", "Page", "Question", "Like", "Announce", "Follow"] %}
|
||||
<li><a href="{{ url_for(route) }}?filter_by={{ ap_type }}" {% if request.query_params.filter_by == ap_type %}class="active"{% endif %}>
|
||||
{{ ap_type }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% if request.query_params.filter_by %}
|
||||
<li>
|
||||
<a href="{{ url_for(route) }}">Reset filter</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro display_tiny_actor_icon(actor) %}
|
||||
{% block display_tiny_actor_icon scoped %}
|
||||
<img class="tiny-actor-icon" src="{{ actor.resized_icon_url }}" alt="">
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro actor_action(inbox_object, text, with_icon=False) %}
|
||||
{% block actor_action scoped %}
|
||||
<div class="actor-action">
|
||||
<a href="{{ url_for("admin_profile") }}?actor_id={{ inbox_object.actor.ap_id }}">
|
||||
{% if with_icon %}{{ display_tiny_actor_icon(inbox_object.actor) }}{% endif %} {{ inbox_object.actor.display_name | clean_html(inbox_object.actor) | safe }}
|
||||
</a> {{ text }}
|
||||
<span title="{{ inbox_object.ap_published_at.isoformat() }}">{{ inbox_object.ap_published_at | timeago }}</span>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro display_actor(actor, actors_metadata={}, embedded=False, with_details=False, pending_incoming_follow_notif=None) %}
|
||||
{% block display_actor scoped %}
|
||||
{% set metadata = actors_metadata.get(actor.ap_id) %}
|
||||
|
||||
{% if not embedded %}
|
||||
<div class="ap-object">
|
||||
{% endif %}
|
||||
|
||||
<div class="actor-box h-card p-author">
|
||||
<div class="icon-box">
|
||||
<img src="{{ actor.resized_icon_url }}" alt="{{ actor.display_name }}'s avatar" class="actor-icon u-photo">
|
||||
</div>
|
||||
<a href="{{ actor.url }}" class="u-url">
|
||||
<div><strong>{{ actor.display_name | clean_html(actor) | safe }}</strong></div>
|
||||
<div class="actor-handle p-name">{{ actor.handle }}</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if is_admin and metadata %}
|
||||
<div>
|
||||
<nav class="flexbox actor-metadata">
|
||||
<ul>
|
||||
{% if metadata.has_blocked_local_actor %}
|
||||
<li>blocked you</li>
|
||||
{% endif %}
|
||||
{% if metadata.is_following %}
|
||||
<li>already following</li>
|
||||
<li>{{ admin_undo_button(metadata.outbox_follow_ap_id, "unfollow")}}</li>
|
||||
{% if not with_details %}
|
||||
<li>{{ admin_profile_button(actor.ap_id) }}</li>
|
||||
{% endif %}
|
||||
{% elif metadata.is_follow_request_sent %}
|
||||
{% if metadata.is_follow_request_rejected %}
|
||||
<li>follow request rejected</li>
|
||||
{% if not metadata.has_blocked_local_actor %}
|
||||
<li>{{ admin_follow_button(actor) }}</li>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<li>follow request sent</li>
|
||||
<li>{{ admin_undo_button(metadata.outbox_follow_ap_id, "undo follow") }}</li>
|
||||
{% endif %}
|
||||
{% elif not actor.moved_to %}
|
||||
<li>{{ admin_follow_button(actor) }}</li>
|
||||
{% endif %}
|
||||
{% if metadata.is_follower %}
|
||||
<li>follows you</li>
|
||||
{% if not metadata.is_following and not with_details %}
|
||||
<li>{{ admin_profile_button(actor.ap_id) }}</li>
|
||||
{% endif %}
|
||||
{% elif actor.is_from_db and not with_details and not metadata.is_following %}
|
||||
<li>{{ admin_profile_button(actor.ap_id) }}</li>
|
||||
{% endif %}
|
||||
{% if actor.moved_to %}
|
||||
<li>has moved to {% if metadata.moved_to %}<a href="{{ url_for("admin_profile") }}?actor_id={{ actor.moved_to }}">{{ metadata.moved_to.handle }}</a>{% else %}<a href="{{ url_for("get_lookup") }}?query={{ actor.moved_to }}">{{ actor.moved_to }}</a>{% endif %}</li>
|
||||
{% endif %}
|
||||
{% if actor.is_from_db %}
|
||||
{% if actor.is_blocked %}
|
||||
<li>blocked</li>
|
||||
<li>{{ admin_unblock_button(actor) }}</li>
|
||||
{% else %}
|
||||
<li>{{ admin_block_button(actor) }}</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li>{{ admin_dm_button(actor.handle) }}</li>
|
||||
<li>{{ admin_mention_button(actor.handle) }}</li>
|
||||
{% if pending_incoming_follow_notif %}
|
||||
{% if not pending_incoming_follow_notif.is_accepted and not pending_incoming_follow_notif.is_rejected %}
|
||||
<li>
|
||||
{{ admin_accept_incoming_follow_button(pending_incoming_follow_notif) }}
|
||||
</li>
|
||||
<li>
|
||||
{{ admin_reject_incoming_follow_button(pending_incoming_follow_notif) }}
|
||||
</li>
|
||||
{% elif pending_incoming_follow_notif.is_accepted %}
|
||||
<li>accepted</li>
|
||||
{% else %}
|
||||
<li>rejected</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if actor.are_announces_hidden_from_stream %}
|
||||
<li>{{ admin_show_shares_button(actor) }}</li>
|
||||
{% else %}
|
||||
<li>{{ admin_hide_shares_button(actor) }}</li>
|
||||
{% endif %}
|
||||
{% if with_details %}
|
||||
<li><a href="{{ actor.url }}" class="label-btn">remote profile</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if with_details %}
|
||||
{% if actor.summary %}
|
||||
<div class="p-note">
|
||||
{{ actor.summary | clean_html(actor) | safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if actor.attachments %}
|
||||
<div id="profile-props">
|
||||
{% for prop in actor.attachments %}
|
||||
<dl>
|
||||
{% if prop.type == "PropertyValue" %}
|
||||
<dt class="muted" title="{{ prop.name }}">{{ prop.name }}</dt>
|
||||
<dd>{{ prop.value | clean_html(actor) | safe }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if not embedded %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro display_og_meta(object) %}
|
||||
{% block display_og_meta scoped %}
|
||||
{% if object.og_meta %}
|
||||
{% for og_meta in object.og_meta[:1] %}
|
||||
<div class="activity-og-meta">
|
||||
{% if og_meta.image %}
|
||||
<div>
|
||||
<img src="{{ og_meta.image | media_proxy_url }}">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<a href="{{ og_meta.url | privacy_replace_url }}">{{ og_meta.title }}</a>
|
||||
{% if og_meta.site_name %}
|
||||
<small>{{ og_meta.site_name }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro display_attachments(object) %}
|
||||
{% block display_attachments scoped %}
|
||||
|
||||
{% for attachment in object.attachments %}
|
||||
{% if attachment.type != "PropertyValue" %}
|
||||
{% set orientation = "unknown" %}
|
||||
{% if attachment.width %}
|
||||
{% set orientation = "portrait" if attachment.width < attachment.height else "landscape" %}
|
||||
{% endif %}
|
||||
{% if object.sensitive and (attachment.type == "Image" or (attachment | has_media_type("image")) or attachment.type == "Video" or (attachment | has_media_type("video"))) %}
|
||||
<div class="attachment-wrapper">
|
||||
<label for="{{attachment.proxied_url}}" class="label-btn show-hide-sensitive-btn">show/hide sensitive content</label>
|
||||
<div>
|
||||
<div class="sensitive-attachment">
|
||||
<input class="sensitive-attachment-state" type="checkbox" id="{{attachment.proxied_url}}" aria-hidden="true">
|
||||
<div class="sensitive-attachment-box attachment-orientation-{{orientation}}">
|
||||
<div></div>
|
||||
{% else %}
|
||||
<div class="attachment-item attachment-orientation-{{orientation}}">
|
||||
{% endif %}
|
||||
|
||||
{% if attachment.type == "Image" or (attachment | has_media_type("image")) %}
|
||||
{% if attachment.url not in object.inlined_images %}
|
||||
<a class="media-link" href="{{ attachment.proxied_url }}" target="_blank">
|
||||
<img src="{{ attachment.resized_url or attachment.proxied_url }}"{% if attachment.name %} title="{{ attachment.name }}" alt="{{ attachment.name }}"{% endif %} class="attachment u-photo">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% elif attachment.type == "Video" or (attachment | has_media_type("video")) %}
|
||||
<div class="video-wrapper">
|
||||
<video controls preload="metadata" src="{{ attachment.url | media_proxy_url }}"{% if attachment.name %} title="{{ attachment.name }}"{% endif %} class="u-video"></video>
|
||||
<div class="video-gif-overlay">GIF</div>
|
||||
</div>
|
||||
{% elif attachment.type == "Audio" or (attachment | has_media_type("audio")) %}
|
||||
<audio controls preload="metadata" src="{{ attachment.url | media_proxy_url }}"{% if attachment.name%} title="{{ attachment.name }}"{% endif %} class="attachment u-audio"></audio>
|
||||
{% elif attachment.type == "Link" %}
|
||||
<a href="{{ attachment.url }}" class="attachment">{{ attachment.url | truncate(64, True) }}</a> ({{ attachment.mimetype}})
|
||||
{% else %}
|
||||
<a href="{{ attachment.url | media_proxy_url }}"{% if attachment.name %} title="{{ attachment.url }}"{% endif %} class="attachment">
|
||||
{% if attachment.name %}{{ attachment.name }}{% else %}{{ attachment.url | truncate(64, True) }}{% endif %}
|
||||
</a> ({{ attachment.mimetype }})
|
||||
{% endif %}
|
||||
{% if object.sensitive and (attachment.type == "Image" or (attachment | has_media_type("image")) or attachment.type == "Video" or (attachment | has_media_type("video"))) %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro display_webmention_reply(wm_reply) %}
|
||||
{% block display_webmention_reply scoped %}
|
||||
|
||||
<div class="ap-object u-comment h-cite">
|
||||
<div class="actor-box h-card p-author">
|
||||
<div class="icon-box">
|
||||
<img src="{{ wm_reply.face.picture_url }}" alt="{{ wm_reply.face.name }}'s avatar" class="actor-icon u-photo">
|
||||
</div>
|
||||
<a href="{{ wm_reply.face.url }}" class="u-url">
|
||||
<div><strong class="p-name">{{ wm_reply.face.name | clean_html_wm | safe }}</strong></div>
|
||||
<div class="actor-handle">{{ wm_reply.face.url | truncate(64, True) }}</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p class="in-reply-to">in reply to <a href="{{ wm_reply.in_reply_to }}" title="{{ wm_reply.in_reply_to }}" rel="nofollow">
|
||||
this object
|
||||
</a></p>
|
||||
|
||||
<div class="obj-content margin-top-20">
|
||||
<div class="e-content">
|
||||
{{ wm_reply.content | clean_html_wm | safe }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="flexbox activity-bar margin-top-20">
|
||||
<ul>
|
||||
<li>
|
||||
<div><a href="{{ wm_reply.url }}" rel="nofollow" class="object-permalink u-url u-uid">permalink</a></div>
|
||||
</li>
|
||||
<li>
|
||||
<time class="dt-published" datetime="{{ wm_reply.published_at.replace(microsecond=0).isoformat() }}" title="{{ wm_reply.published_at.replace(microsecond=0).isoformat() }}">{{ wm_reply.published_at | timeago }}</time>
|
||||
</li>
|
||||
{% if is_admin %}
|
||||
<li>
|
||||
{{ admin_force_delete_webmention_button(wm_reply.webmention_id) }}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro display_object(object, likes=[], shares=[], webmentions=[], expanded=False, actors_metadata={}, is_object_page=False, is_h_entry=True) %}
|
||||
{% block display_object scoped %}
|
||||
{% set is_article_mode = object.is_from_outbox and object.ap_type == "Article" and is_object_page %}
|
||||
{% if object.ap_type in ["Note", "Article", "Video", "Page", "Question", "Event"] %}
|
||||
<div class="ap-object {% if expanded %}ap-object-expanded {% endif %}{% if is_h_entry %}h-entry{% endif %}" id="{{ object.permalink_id }}">
|
||||
|
||||
{% if is_article_mode %}
|
||||
<data class="h-card">
|
||||
<data class="u-photo" value="{{ local_actor.icon_url }}"></data>
|
||||
<data class="u-url" value="{{ local_actor.url}}"></data>
|
||||
<data class="p-name" value="{{ local_actor.handle }}"></data>
|
||||
</data>
|
||||
{% else %}
|
||||
{{ display_actor(object.actor, actors_metadata, embedded=True) }}
|
||||
{% endif %}
|
||||
|
||||
{% if object.in_reply_to %}
|
||||
<p class="in-reply-to">in reply to <a href="{% if is_admin and object.is_in_reply_to_from_inbox %}{{ url_for("get_lookup") }}?query={% endif %}{{ object.in_reply_to }}" title="{{ object.in_reply_to }}" rel="nofollow">
|
||||
this object
|
||||
</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% if object.ap_type in ["Article", "Event"] %}
|
||||
<h2 class="p-name no-margin-top">{{ object.name }}</h2>
|
||||
{% endif %}
|
||||
|
||||
{% if object.ap_type == "Event" %}
|
||||
{% if object.ap_object.get("endTime") and object.ap_object.get("startTime") %}
|
||||
<p>On {{ object.ap_object.startTime | parse_datetime | format_date }}
|
||||
(ends {{ object.ap_object.endTime | parse_datetime | format_date }})</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if object.ap_object.get("location") %}
|
||||
{% set loc = object.ap_object.get("location") %}
|
||||
{% if loc.type == "Place" and loc.latitude and loc.longitude %}
|
||||
<div class="ap-place">
|
||||
<h3>Location</h3>
|
||||
{% if loc.name %}{{ loc.name }}{% endif %}
|
||||
<span class="h-geo">
|
||||
<data class="p-latitude" value="{{ loc.latitude}}"></data>
|
||||
<data class="p-longitude" value="{{ loc.longitude }}"></data>
|
||||
<a href="https://www.openstreetmap.org/?mlat={{ loc.latitude }}&mlon={{ loc.longitude }}#map=16/{{loc.latitude}}/{{loc.longitude}}">{{loc.latitude}},{{loc.longitude}}</a>
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_article_mode %}
|
||||
<time class="dt-published muted" datetime="{{ object.ap_published_at.replace(microsecond=0).isoformat() }}" title="{{ object.ap_published_at.replace(microsecond=0).isoformat() }}">{{ object.ap_published_at.strftime("%b %d, %Y") }}</time>
|
||||
{% endif %}
|
||||
|
||||
{% if object.summary %}
|
||||
<details class="show-more-wrapper">
|
||||
<summary>
|
||||
<div class="p-summary">
|
||||
<p>{{ object.summary | clean_html(object) | safe }}</p>
|
||||
</div>
|
||||
<span class="show-more-btn" aria-hidden="true"></span>
|
||||
</summary>
|
||||
{% endif %}
|
||||
<div class="obj-content">
|
||||
<div class="e-content">
|
||||
{{ object.content | clean_html(object) | safe }}
|
||||
</div>
|
||||
|
||||
{% if object.ap_type == "Question" %}
|
||||
{% set can_vote = is_admin and object.is_from_inbox and not object.is_poll_ended and not object.voted_for_answers %}
|
||||
{% if can_vote %}
|
||||
<form action="{{ request.url_for("admin_actions_vote") }}" method="POST">
|
||||
{{ embed_csrf_token() }}
|
||||
{{ embed_redirect_url(object.permalink_id) }}
|
||||
<input type="hidden" name="in_reply_to" value="{{ object.ap_id }}">
|
||||
{% endif %}
|
||||
|
||||
{% if object.poll_items %}
|
||||
<ul class="poll-items">
|
||||
{% for item in object.poll_items %}
|
||||
<li>
|
||||
{% set pct = item | poll_item_pct(object.poll_voters_count) %}
|
||||
<p>
|
||||
{% if can_vote %}
|
||||
<input type="{% if object.is_one_of_poll %}radio{% else %}checkbox{% endif %}" name="name" value="{{ item.name }}" id="{{object.permalink_id}}-{{item.name}}">
|
||||
<label for="{{object.permalink_id}}-{{item.name}}">
|
||||
{% endif %}
|
||||
|
||||
{{ item.name | clean_html(object) | safe }}
|
||||
|
||||
{% if object.voted_for_answers and item.name in object.voted_for_answers %}
|
||||
<span class="muted poll-vote">you voted for this answer</span>
|
||||
{% endif %}
|
||||
|
||||
{% if can_vote %}
|
||||
</label>
|
||||
{% endif %}
|
||||
|
||||
<span class="float-right">{{ pct }}% <span class="muted">({{ item.replies.totalItems }} votes)</span></span>
|
||||
</p>
|
||||
<svg class="poll-bar">
|
||||
<line x1="0" y1="10px" x2="{{ pct or 1 }}%" y2="10px"></line>
|
||||
</svg>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if can_vote %}
|
||||
<p class="form">
|
||||
<input type="submit" value="vote">
|
||||
</p>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
{{ display_og_meta(object) }}
|
||||
|
||||
</div>
|
||||
{% if object.summary %}
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
<div class="activity-attachment">
|
||||
{{ display_attachments(object) }}
|
||||
</div>
|
||||
|
||||
<nav class="flexbox activity-bar">
|
||||
<ul>
|
||||
<li>
|
||||
<div><a href="{{ object.url }}"{% if object.is_from_inbox %} rel="nofollow"{% endif %} class="object-permalink u-url u-uid">permalink</a></div>
|
||||
</li>
|
||||
|
||||
{% if object.is_from_outbox and is_object_page and not is_admin and not request.url.path.startswith("/remote_interaction") %}
|
||||
<li>
|
||||
<a class="label-btn" href="{{ request.url_for("remote_interaction") }}?ap_id={{ object.ap_id }}">
|
||||
interact from your instance
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if not is_article_mode %}
|
||||
<li>
|
||||
<time class="dt-published" datetime="{{ object.ap_published_at.replace(microsecond=0).isoformat() }}" title="{{ object.ap_published_at.replace(microsecond=0).isoformat() }}">{{ object.ap_published_at | timeago }}</time>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if object.ap_type == "Question" %}
|
||||
{% if object.poll_end_time %}
|
||||
<li>
|
||||
{% if object.is_poll_ended %}ended{% else %}ends{% endif %}
|
||||
<time title="{{ object.poll_end_time.replace(microsecond=0).isoformat() }}">
|
||||
{{ object.poll_end_time | timeago }}
|
||||
</time>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
{{ object.poll_voters_count }} voters
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if is_admin %}
|
||||
<li>
|
||||
{{ object.visibility.value }}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if object.is_from_outbox %}
|
||||
{% if object.likes_count %}
|
||||
<li>
|
||||
<a href="{{ object.url }}"><strong>{{ object.likes_count }}</strong> like{{ object.likes_count | pluralize }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if object.announces_count %}
|
||||
<li>
|
||||
<a href="{{ object.url }}"><strong>{{ object.announces_count }}</strong> share{{ object.announces_count | pluralize }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if object.webmentions_count %}
|
||||
<li>
|
||||
<a href="{{ object.url }}"><strong>{{ object.webmentions_count }}</strong> webmention{{ object.webmentions_count | pluralize }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if (object.is_from_outbox or is_admin) and object.replies_count %}
|
||||
<li>
|
||||
<a href="{% if is_admin and not object.is_from_outbox %}{{ url_for("admin_object") }}?ap_id={{ object.ap_id }}{% if object.in_reply_to %}#{{ object.permalink_id }}{% endif %}{% else %}{{ object.url }}{% endif %}"><strong>{{ object.replies_count }}</strong> repl{{ object.replies_count | pluralize("y", "ies") }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{% if is_admin %}
|
||||
<nav class="flexbox activity-bar">
|
||||
<ul>
|
||||
{% if object.is_from_outbox %}
|
||||
<li>
|
||||
{{ admin_delete_button(object) }}
|
||||
</li>
|
||||
|
||||
<li>
|
||||
{% if object.is_pinned %}
|
||||
{{ admin_unpin_button(object.ap_id, object.permalink_id) }}
|
||||
{% else %}
|
||||
{{ admin_pin_button(object.ap_id, object.permalink) }}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<li>
|
||||
{{ admin_reply_button(object.ap_id) }}
|
||||
</li>
|
||||
|
||||
{% if not object.is_from_outbox %}
|
||||
<li>
|
||||
{% if object.liked_via_outbox_object_ap_id %}
|
||||
{{ admin_undo_button(object.liked_via_outbox_object_ap_id, "unlike", object.permalink_id) }}
|
||||
{% else %}
|
||||
{{ admin_like_button(object.ap_id, object.permalink_id) }}
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<li>
|
||||
{% if object.is_bookmarked %}
|
||||
{{ admin_unbookmark_button(object.ap_id, object.permalink_id) }}
|
||||
{% else %}
|
||||
{{ admin_bookmark_button(object.ap_id, object.permalink_id) }}
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
{% if object.visibility in [visibility_enum.PUBLIC, visibility_enum.UNLISTED] %}
|
||||
<li>
|
||||
{% if object.announced_via_outbox_object_ap_id %}
|
||||
{{ admin_undo_button(object.announced_via_outbox_object_ap_id, "unshare") }}
|
||||
{% else %}
|
||||
{{ admin_announce_button(object.ap_id, permalink_id=object.permalink_id) }}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if object.is_from_inbox %}
|
||||
<li>
|
||||
{{ admin_profile_button(object.actor.ap_id) }}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if object.is_from_inbox or object.is_from_outbox %}
|
||||
<li>
|
||||
{{ admin_expand_button(object) }}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if object.is_from_inbox and not object.announced_via_outbox_object_ap_id and object.is_local_reply %}
|
||||
<li>
|
||||
{{ admin_force_delete_button(object.ap_id) }}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if likes or shares or webmentions %}
|
||||
<div class="public-interactions">
|
||||
{% if likes %}
|
||||
<div class="interactions-block">Likes
|
||||
<div class="facepile-wrapper">
|
||||
{% for like in likes %}
|
||||
<a href="{% if is_admin and like.ap_actor_id %}{{ url_for("admin_profile") }}?actor_id={{ like.ap_actor_id }}{% else %}{{ like.url }}{% endif %}" title="{{ like.name }}" rel="noreferrer">
|
||||
<img src="{{ like.picture_url }}" alt="{{ like.name }}">
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% if object.likes_count > likes | length %}
|
||||
<div class="and-x-more">
|
||||
and {{ object.likes_count - likes | length }} more.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if shares %}
|
||||
<div class="interactions-block">Shares
|
||||
<div class="facepile-wrapper">
|
||||
{% for share in shares %}
|
||||
<a href="{% if is_admin and share.ap_actor_id %}{{ url_for("admin_profile") }}?actor_id={{ share.ap_actor_id }}{% else %}{{ share.url }}{% endif %}" title="{{ share.name }}" rel="noreferrer">
|
||||
<img src="{{ share.picture_url }}" alt="{{ share.name }}">
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% if object.announces_count > shares | length %}
|
||||
<div class="and-x-more">
|
||||
and {{ object.announces_count - shares | length }} more.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if webmentions %}
|
||||
<div class="interactions-block">Webmentions
|
||||
<div class="facepile-wrapper">
|
||||
{% for webmention in webmentions %}
|
||||
{% set wm = webmention.as_facepile_item %}
|
||||
{% if wm %}
|
||||
<a href="{{ wm.url }}" title="{{ wm.actor_name }}" rel="noreferrer">
|
||||
<img src="{{ wm.actor_icon_url | media_proxy_url }}" alt="{{ wm.actor_name }}">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
|
@ -1,11 +1,11 @@
|
|||
// override vars for theming here
|
||||
$background: rgb(41, 41, 41);
|
||||
$light-background: #333333;
|
||||
$background: rgb(19, 19, 19);
|
||||
$light-background: #141414;
|
||||
$text-color: rgb(238, 238, 238);
|
||||
$primary-color: #dfd39d;
|
||||
$secondary-color: #e07127;
|
||||
$form-background-color: rgb(95, 95, 95);
|
||||
$form-background-color: rgb(39, 39, 39);
|
||||
$form-text-color: rgb(255, 255, 255);
|
||||
$muted-color: rgb(173, 173, 173); // solarized comment text
|
||||
$muted-color: rgb(156, 156, 156); // solarized comment text
|
||||
$primary-button-text-color: rgb(34, 34, 34);
|
||||
$code-highlight-background: #1d1d1d;
|
||||
$code-highlight-background: #1b1b1b;
|
|
@ -1 +0,0 @@
|
|||
../../app/templates/
|
|
@ -2,7 +2,8 @@ version: "3"
|
|||
|
||||
services:
|
||||
server:
|
||||
image: microblogpub/microblogpub:latest
|
||||
build: .
|
||||
image: microblogpub
|
||||
container_name: microblogpub
|
||||
user: 1000:1000
|
||||
restart: always
|
||||
|
|
Loading…
Reference in New Issue