kopia lustrzana https://github.com/jointakahe/takahe
rodzic
d6f558f89a
commit
113db4ab3a
|
@ -125,10 +125,12 @@ class Emoji(StatorModel):
|
||||||
unique_together = ("domain", "shortcode")
|
unique_together = ("domain", "shortcode")
|
||||||
|
|
||||||
class urls(urlman.Urls):
|
class urls(urlman.Urls):
|
||||||
root = "/admin/emoji/"
|
admin = "/admin/emoji/"
|
||||||
create = "{root}/create/"
|
admin_create = "{admin}create/"
|
||||||
edit = "{root}{self.Emoji}/"
|
admin_edit = "{admin}{self.pk}/"
|
||||||
delete = "{edit}delete/"
|
admin_delete = "{admin}{self.pk}/delete/"
|
||||||
|
admin_enable = "{admin}{self.pk}/enable/"
|
||||||
|
admin_disable = "{admin}{self.pk}/disable/"
|
||||||
|
|
||||||
emoji_regex = re.compile(r"\B:([a-zA-Z0-9(_)-]+):\B")
|
emoji_regex = re.compile(r"\B:([a-zA-Z0-9(_)-]+):\B")
|
||||||
|
|
||||||
|
@ -172,8 +174,11 @@ class Emoji(StatorModel):
|
||||||
self.public is None and Config.system.emoji_unreviewed_are_public
|
self.public is None and Config.system.emoji_unreviewed_are_public
|
||||||
)
|
)
|
||||||
|
|
||||||
def full_url(self) -> RelativeAbsoluteUrl:
|
def full_url_admin(self) -> RelativeAbsoluteUrl:
|
||||||
if self.is_usable:
|
return self.full_url(always_show=True)
|
||||||
|
|
||||||
|
def full_url(self, always_show=False) -> RelativeAbsoluteUrl:
|
||||||
|
if self.is_usable or always_show:
|
||||||
if self.file:
|
if self.file:
|
||||||
return AutoAbsoluteUrl(self.file.url)
|
return AutoAbsoluteUrl(self.file.url)
|
||||||
elif self.remote_url:
|
elif self.remote_url:
|
||||||
|
|
|
@ -117,6 +117,8 @@ class Hashtag(StatorModel):
|
||||||
view = "/tags/{self.hashtag}/"
|
view = "/tags/{self.hashtag}/"
|
||||||
admin = "/admin/hashtags/"
|
admin = "/admin/hashtags/"
|
||||||
admin_edit = "{admin}{self.hashtag}/"
|
admin_edit = "{admin}{self.hashtag}/"
|
||||||
|
admin_enable = "{admin_edit}enable/"
|
||||||
|
admin_disable = "{admin_edit}disable/"
|
||||||
timeline = "/tags/{self.hashtag}/"
|
timeline = "/tags/{self.hashtag}/"
|
||||||
|
|
||||||
hashtag_regex = re.compile(r"\B#([a-zA-Z0-9(_)]+\b)(?!;)")
|
hashtag_regex = re.compile(r"\B#([a-zA-Z0-9(_)]+\b)(?!;)")
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -31,3 +32,18 @@ def timedeltashort(value: datetime.datetime):
|
||||||
years = max(days // 365.25, 1)
|
years = max(days // 365.25, 1)
|
||||||
text = f"{years:0n}y"
|
text = f"{years:0n}y"
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag(takes_context=True)
|
||||||
|
def urlparams(context, **kwargs):
|
||||||
|
"""
|
||||||
|
Generates a URL parameter string the same as the current page but with
|
||||||
|
the given items changed.
|
||||||
|
"""
|
||||||
|
params = dict(context["request"].GET.items())
|
||||||
|
for name, value in kwargs.items():
|
||||||
|
if value:
|
||||||
|
params[name] = value
|
||||||
|
elif name in params:
|
||||||
|
del params[name]
|
||||||
|
return urlencode(params)
|
||||||
|
|
|
@ -555,6 +555,92 @@ p.authorization-code {
|
||||||
color: var(--color-text-dull);
|
color: var(--color-text-dull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Item tables */
|
||||||
|
|
||||||
|
table.items {
|
||||||
|
margin: 10px 0;
|
||||||
|
border: 1px solid var(--color-bg-menu);
|
||||||
|
border-spacing: 0;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td {
|
||||||
|
padding: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 1.1em;
|
||||||
|
height: 55px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td small {
|
||||||
|
display: block;
|
||||||
|
color: var(--color-text-dull);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items tr:nth-of-type(2n+1) {
|
||||||
|
background-color: var(--color-bg-box);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.name {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.name a.overlay,
|
||||||
|
table.items td.icon a.overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.icon {
|
||||||
|
width: 40px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.icon img {
|
||||||
|
width: 32px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td .bad {
|
||||||
|
background: var(--color-delete);
|
||||||
|
padding: 4px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.stat {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.actions {
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.actions a {
|
||||||
|
color: var(--color-text-dull);
|
||||||
|
padding: 3px 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
margin: 0 0 0 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.actions a:hover {
|
||||||
|
color: var(--color-text-main);
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.items td.actions a.danger:hover {
|
||||||
|
background-color: var(--color-delete);
|
||||||
|
}
|
||||||
|
|
||||||
/* Forms */
|
/* Forms */
|
||||||
|
|
||||||
|
@ -1189,13 +1275,14 @@ table.metadata td .emoji {
|
||||||
|
|
||||||
.view-options {
|
.view-options {
|
||||||
margin: 0 0 10px 0px;
|
margin: 0 0 10px 0px;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-options.follows {
|
.view-options.follows {
|
||||||
margin: 0 0 20px 0px;
|
margin: 0 0 20px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-options a {
|
.view-options a:not(.button) {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 10px 5px 0;
|
margin: 0 10px 5px 0;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
|
@ -1204,11 +1291,17 @@ table.metadata td .emoji {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-options a:hover {
|
.view-options a.button {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 0 5px auto;
|
||||||
|
padding: 1px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-options a:not(.button):hover {
|
||||||
color: var(--color-text-dull);
|
color: var(--color-text-dull);
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-options a.selected {
|
.view-options a:not(.button).selected {
|
||||||
color: var(--color-text-highlight);
|
color: var(--color-text-highlight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1723,7 +1816,8 @@ form .post {
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
#image-viewer picture, #image-viewer img {
|
#image-viewer picture,
|
||||||
|
#image-viewer img {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,23 @@ urlpatterns = [
|
||||||
"admin/hashtags/<hashtag>/",
|
"admin/hashtags/<hashtag>/",
|
||||||
admin.HashtagEdit.as_view(),
|
admin.HashtagEdit.as_view(),
|
||||||
),
|
),
|
||||||
|
path("admin/hashtags/<hashtag>/enable/", admin.HashtagEnable.as_view()),
|
||||||
|
path(
|
||||||
|
"admin/hashtags/<hashtag>/disable/", admin.HashtagEnable.as_view(enable=False)
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"admin/emoji/",
|
||||||
|
admin.EmojiRoot.as_view(),
|
||||||
|
name="admin_emoji",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"admin/emoji/create/",
|
||||||
|
admin.EmojiCreate.as_view(),
|
||||||
|
name="admin_emoji_create",
|
||||||
|
),
|
||||||
|
path("admin/emoji/<id>/enable/", admin.EmojiEnable.as_view()),
|
||||||
|
path("admin/emoji/<id>/disable/", admin.EmojiEnable.as_view(enable=False)),
|
||||||
|
path("admin/emoji/<id>/delete/", admin.EmojiDelete.as_view()),
|
||||||
path(
|
path(
|
||||||
"admin/stator/",
|
"admin/stator/",
|
||||||
admin.Stator.as_view(),
|
admin.Stator.as_view(),
|
||||||
|
|
|
@ -15,14 +15,8 @@
|
||||||
and you will <b>not be able to delete a domain with identities on it</b>.
|
and you will <b>not be able to delete a domain with identities on it</b>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If you will be serving Takahē on the domain you choose, you can leave
|
For more information about domain setup, including what service
|
||||||
the "service domain" field blank. If you would like to let users create
|
domains are, see <a href="https://docs.jointakahe.org/en/latest/domains/">our documentation on domains</a>.
|
||||||
accounts on a domain serving something else, you must pick a unique
|
|
||||||
"service domain" that pairs up to your chosen domain name, make sure
|
|
||||||
Takahē is served on that, and add redirects
|
|
||||||
for <tt>/.well-known/webfinger</tt>, <tt>/.well-known/host-meta</tt>
|
|
||||||
and <tt>/.well-known/nodeinfo</tt> from the main domain to the
|
|
||||||
service domain.
|
|
||||||
</p>
|
</p>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
|
@ -3,26 +3,31 @@
|
||||||
{% block subtitle %}Domains{% endblock %}
|
{% block subtitle %}Domains{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="icon-menu">
|
<div class="view-options">
|
||||||
|
<span class="spacer"></span>
|
||||||
|
<a href="{% url "admin_domains_create" %}" class="button"><i class="fa-solid fa-plus"></i> Add Domain</a>
|
||||||
|
</div>
|
||||||
|
<table class="items">
|
||||||
{% for domain in domains %}
|
{% for domain in domains %}
|
||||||
<a class="option" href="{{ domain.urls.edit }}">
|
<tr>
|
||||||
<i class="fa-solid fa-globe"></i>
|
<td class="icon">
|
||||||
<span class="handle">
|
<a href="{{ domain.urls.edit }}" class="overlay"></a>
|
||||||
|
<i class="fa-solid fa-globe"></i>
|
||||||
|
</td>
|
||||||
|
<td class="name">
|
||||||
|
<a href="{{ domain.urls.edit }}" class="overlay"></a>
|
||||||
{{ domain.domain }}
|
{{ domain.domain }}
|
||||||
<small>
|
<small>
|
||||||
{% if domain.public %}Public{% else %}Private{% endif %}
|
{% if domain.service_domain %}{{ domain.service_domain }}{% endif %}
|
||||||
{% if domain.service_domain %}({{ domain.service_domain }}){% endif %}
|
|
||||||
</small>
|
</small>
|
||||||
</span>
|
</span>
|
||||||
{% if domain.default %}
|
<td class="stat">
|
||||||
<span class="pill">Default</span>
|
{% if domain.public %}Public{% else %}Private{% endif %}
|
||||||
{% endif %}
|
{% if domain.default %}(Default){% endif %}
|
||||||
</a>
|
</td>
|
||||||
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class="option empty">You have no domains set up.</p>
|
<tr class="empty"><td>You have no domains set up.</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<a href="{% url "admin_domains_create" %}" class="option new">
|
</table>
|
||||||
<i class="fa-solid fa-plus"></i> Add a domain
|
|
||||||
</a>
|
|
||||||
</section>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
{% extends "settings/base.html" %}
|
||||||
|
{% load activity_tags %}
|
||||||
|
|
||||||
|
{% block subtitle %}Emoji{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="." class="search">
|
||||||
|
<input type="search" name="query" value="{{ query }}" placeholder="Search by shortcode or domain">
|
||||||
|
{% if local_only %}
|
||||||
|
<input type="hidden" name="local_only" value="true">
|
||||||
|
{% endif %}
|
||||||
|
<button><i class="fa-solid fa-search"></i></button>
|
||||||
|
</form>
|
||||||
|
<div class="view-options">
|
||||||
|
{% if local_only %}
|
||||||
|
<a href=".?{% urlparams local_only=False %}" class="selected"><i class="fa-solid fa-check"></i> Local Only</a>
|
||||||
|
{% else %}
|
||||||
|
<a href=".?{% urlparams local_only=True %}"><i class="fa-solid fa-xmark"></i> Local Only</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{% url "admin_emoji_create" %}" class="button">Add Emoji</a>
|
||||||
|
</div>
|
||||||
|
<table class="items">
|
||||||
|
{% for emoji in page_obj %}
|
||||||
|
<tr>
|
||||||
|
<td class="icon">
|
||||||
|
<img src="{{ emoji.full_url_admin.relative }}" class="icon">
|
||||||
|
</td>
|
||||||
|
<td class="name">
|
||||||
|
{{ emoji.shortcode }}
|
||||||
|
{% if emoji.domain %}<small>{{ emoji.domain }}</small>{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td class="actions">
|
||||||
|
{% if not emoji.is_usable %}
|
||||||
|
<span class="bad">Disabled</span>
|
||||||
|
<a hx-post="{{ emoji.urls.admin_enable }}" title="Enable"><i class="fa-solid fa-circle-check"></i></a>
|
||||||
|
{% else %}
|
||||||
|
<a hx-post="{{ emoji.urls.admin_disable }}" class="danger" title="Disable"><i class="fa-solid fa-circle-xmark"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
<a hx-post="{{ emoji.urls.admin_delete }}" hx-confirm="Are you sure you want to delete :{{ emoji.shortcode }}:?" class="danger" title="Delete"><i class="fa-solid fa-trash"></i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr class="empty">
|
||||||
|
<td>
|
||||||
|
{% if query %}
|
||||||
|
No emoji match your query.
|
||||||
|
{% else %}
|
||||||
|
There are no emoji yet.
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
<div class="pagination">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a class="button" href=".?{% urlparams page=page_obj.previous_page_number %}">Previous Page</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if page_obj.paginator.count %}
|
||||||
|
<span class="count">{{ page_obj.paginator.count }} emoji</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a class="button" href=".?{% urlparams page=page_obj.next_page_number %}">Next Page</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends "settings/base.html" %}
|
||||||
|
|
||||||
|
{% block subtitle %}{{ emoji.shortcode }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="." method="POST" enctype="multipart/form-data">
|
||||||
|
{% csrf_token %}
|
||||||
|
<fieldset>
|
||||||
|
<legend>Emoji Details</legend>
|
||||||
|
{% include "forms/_field.html" with field=form.shortcode %}
|
||||||
|
{% include "forms/_field.html" with field=form.image hide_existing=True %}
|
||||||
|
</fieldset>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="{% url "admin_emoji" %}" class="button secondary left">Back</a>
|
||||||
|
<button>Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "settings/base.html" %}
|
{% extends "settings/base.html" %}
|
||||||
|
{% load activity_tags %}
|
||||||
|
|
||||||
{% block subtitle %}Federation{% endblock %}
|
{% block subtitle %}Federation{% endblock %}
|
||||||
|
|
||||||
|
@ -7,33 +8,49 @@
|
||||||
<input type="search" name="query" value="{{ query }}" placeholder="Search by domain">
|
<input type="search" name="query" value="{{ query }}" placeholder="Search by domain">
|
||||||
<button><i class="fa-solid fa-search"></i></button>
|
<button><i class="fa-solid fa-search"></i></button>
|
||||||
</form>
|
</form>
|
||||||
<section class="icon-menu">
|
<table class="items">
|
||||||
{% for domain in page_obj %}
|
{% for domain in page_obj %}
|
||||||
<a class="option" href="{{ domain.urls.edit_federation }}">
|
<tr>
|
||||||
<i class="fa-solid fa-globe"></i>
|
<td class="icon">
|
||||||
<span class="handle">
|
<a href="{{ domain.urls.edit_federation }}" class="overlay"></a>
|
||||||
|
<i class="fa-solid fa-globe"></i>
|
||||||
|
</td>
|
||||||
|
<td class="name">
|
||||||
|
<a href="{{ domain.urls.edit_federation }}" class="overlay"></a>
|
||||||
{{ domain.domain }}
|
{{ domain.domain }}
|
||||||
<small>
|
<small>{{ domain.software }}</small>
|
||||||
{{ domain.num_users }} remote identit{{ domain.num_users|pluralize:"y,ies" }}
|
</td>
|
||||||
</small>
|
<td>
|
||||||
</span>
|
{% if domain.blocked %}
|
||||||
{% if domain.blocked %}
|
<span class="bad">Blocked</span>
|
||||||
<span class="pill bad">Blocked</span>
|
{% endif %}
|
||||||
{% endif %}
|
</td>
|
||||||
</a>
|
<td class="stat">
|
||||||
|
{{ domain.num_users }}
|
||||||
|
<small>identit{{ domain.num_users|pluralize:"y,ies" }}</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class="option empty">There are no federation links yet.</p>
|
<tr class="empty">
|
||||||
|
<td>
|
||||||
|
{% if query %}
|
||||||
|
There are no domains matching your query.
|
||||||
|
{% else %}
|
||||||
|
There are no federation links yet.
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="pagination">
|
</table>
|
||||||
{% if page_obj.has_previous %}
|
<div class="pagination">
|
||||||
<a class="button" href=".?page={{ page_obj.previous_page_number }}">Previous Page</a>
|
{% if page_obj.has_previous %}
|
||||||
{% endif %}
|
<a class="button" href=".?{% urlparams page=page_obj.previous_page_number %}">Previous Page</a>
|
||||||
{% if page_obj.paginator.count %}
|
{% endif %}
|
||||||
<span class="count">{{ page_obj.paginator.count }} domain{{page_obj.paginator.count|pluralize }}</span>
|
{% if page_obj.paginator.count %}
|
||||||
{% endif %}
|
<span class="count">{{ page_obj.paginator.count }} domain{{page_obj.paginator.count|pluralize }}</span>
|
||||||
{% if page_obj.has_next %}
|
{% endif %}
|
||||||
<a class="button" href=".?page={{ page_obj.next_page_number }}">Next Page</a>
|
{% if page_obj.has_next %}
|
||||||
{% endif %}
|
<a class="button" href=".?{% urlparams page=page_obj.next_page_number %}">Next Page</a>
|
||||||
</div>
|
{% endif %}
|
||||||
</section>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
{% include "forms/_field.html" with field=form.blocked %}
|
{% include "forms/_field.html" with field=form.blocked %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<a href="{{ domain.urls.root }}" class="button secondary left">Back</a>
|
<a href="{{ domain.urls.root_federation }}" class="button secondary left">Back</a>
|
||||||
<a href="{{ domain.urls.delete }}" class="button delete">Delete</a>
|
<a href="{{ domain.urls.delete }}" class="button delete">Delete</a>
|
||||||
<button>Save</button>
|
<button>Save</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,50 +3,62 @@
|
||||||
{% block subtitle %}Hashtags{% endblock %}
|
{% block subtitle %}Hashtags{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="icon-menu">
|
<table class="items">
|
||||||
{% for hashtag in page_obj %}
|
{% for hashtag in page_obj %}
|
||||||
<a class="option hashtags" href="{{ hashtag.urls.admin_edit }}">
|
<tr>
|
||||||
<div class="tag">
|
<td class="icon">
|
||||||
|
<a href="{{ hashtag.urls.admin_edit }}" class="overlay"></a>
|
||||||
<i class="fa-solid fa-hashtag"></i>
|
<i class="fa-solid fa-hashtag"></i>
|
||||||
<span class="handle">
|
</td>
|
||||||
{{ hashtag.display_name }}
|
<td class="name">
|
||||||
<small>
|
<a href="{{ hashtag.urls.admin_edit }}" class="overlay"></a>
|
||||||
{% if hashtag.public %}Public{% elif hashtag.public is None %}Unreviewed{% else %}Private{% endif %}
|
{{ hashtag.display_name }}
|
||||||
</small>
|
<small>{% if hashtag.public %}Public{% elif hashtag.public is None %}Unreviewed{% else %}Private{% endif %}</small>
|
||||||
</span>
|
</td>
|
||||||
</div>
|
<td class="stat">
|
||||||
{% if hashtag.stats %}
|
{% if hashtag.stats %}
|
||||||
<div class="count">
|
{{ hashtag.stats.total }}
|
||||||
<span class="handle">
|
<small>post{{ hashtag.stats.total|pluralize }}</small>
|
||||||
{{ hashtag.stats.total }}
|
{% endif %}
|
||||||
<small>Total</small>
|
</td>
|
||||||
</span>
|
<td class="stat">
|
||||||
</div>
|
{% if hashtag.aliases %}
|
||||||
{% endif %}
|
{% for alias in hashtag.aliases %}
|
||||||
{% if hashtag.aliases %}
|
{{ alias }}{% if not forloop.last %}, {% endif %}
|
||||||
<div class="count">
|
{% endfor %}
|
||||||
<span class="handle">
|
<small>Aliases</small>
|
||||||
{% for alias in hashtag.aliases %}
|
{% endif %}
|
||||||
{{ alias }}{% if not forloop.last %}, {% endif %}
|
</td>
|
||||||
{% endfor %}
|
<td class="actions">
|
||||||
<small>Aliases</small>
|
{% if hashtag.public is not True %}
|
||||||
</span>
|
<a hx-post="{{ hashtag.urls.admin_enable }}" title="Make Public"><i class="fa-solid fa-circle-check"></i></a>
|
||||||
</div>
|
{% endif %}
|
||||||
{% endif %}
|
{% if hashtag.public is not False %}
|
||||||
</a>
|
<a hx-post="{{ hashtag.urls.admin_disable }}" title="Make Private"><i class="fa-solid fa-circle-xmark"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class="option empty">There are no hashtags yet.</p>
|
<tr class="empty">
|
||||||
|
<td>
|
||||||
|
{% if query %}
|
||||||
|
No hashtags match your query.
|
||||||
|
{% else %}
|
||||||
|
There are no hashtags yet.
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="pagination">
|
</table>
|
||||||
{% if page_obj.has_previous %}
|
<div class="pagination">
|
||||||
<a class="button" href=".?page={{ page_obj.previous_page_number }}">Previous Page</a>
|
{% if page_obj.has_previous %}
|
||||||
{% endif %}
|
<a class="button" href=".?page={{ page_obj.previous_page_number }}">Previous Page</a>
|
||||||
{% if page_obj.paginator.count %}
|
{% endif %}
|
||||||
<span class="count">{{ page_obj.paginator.count }} hashtag{{page_obj.paginator.count|pluralize }}</span>
|
{% if page_obj.paginator.count %}
|
||||||
{% endif %}
|
<span class="count">{{ page_obj.paginator.count }} hashtag{{page_obj.paginator.count|pluralize }}</span>
|
||||||
{% if page_obj.has_next %}
|
{% endif %}
|
||||||
<a class="button" href=".?page={{ page_obj.next_page_number }}">Next Page</a>
|
{% if page_obj.has_next %}
|
||||||
{% endif %}
|
<a class="button" href=".?page={{ page_obj.next_page_number }}">Next Page</a>
|
||||||
</div>
|
{% endif %}
|
||||||
</section>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "settings/base.html" %}
|
{% extends "settings/base.html" %}
|
||||||
|
{% load activity_tags %}
|
||||||
|
|
||||||
{% block subtitle %}Identities{% endblock %}
|
{% block subtitle %}Identities{% endblock %}
|
||||||
|
|
||||||
|
@ -12,42 +13,71 @@
|
||||||
</form>
|
</form>
|
||||||
<div class="view-options">
|
<div class="view-options">
|
||||||
{% if local_only %}
|
{% if local_only %}
|
||||||
<a href=".?{% if query %}query={{ query }}{% endif %}" class="selected"><i class="fa-solid fa-check"></i> Local Only</a>
|
<a href=".?{% urlparams local_only=False %}" class="selected"><i class="fa-solid fa-check"></i> Local Only</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href=".?local_only=true{% if query %}&query={{ query }}{% endif %}"><i class="fa-solid fa-xmark"></i> Local Only</a>
|
<a href=".?{% urlparams local_only=True %}"><i class="fa-solid fa-xmark"></i> Local Only</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<section class="icon-menu">
|
<table class="items">
|
||||||
{% for identity in page_obj %}
|
{% for identity in page_obj %}
|
||||||
<a class="option" href="{{ identity.urls.admin_edit }}">
|
<tr>
|
||||||
<div class="option-content">
|
<td class="icon">
|
||||||
{% include "identity/_identity_banner.html" with identity=identity link_avatar=False link_handle=False %}
|
<a href="{{ identity.urls.admin_edit }}" class="overlay"></a>
|
||||||
</div>
|
<img
|
||||||
<div class="option-actions">
|
src="{{ identity.local_icon_url.relative }}"
|
||||||
{% if identity.banned %}
|
class="icon"
|
||||||
<span class="pill bad">Banned</span>
|
alt="Avatar for {{ identity.name_or_handle }}"
|
||||||
|
loading="lazy"
|
||||||
|
data-handle="{{ identity.name_or_handle }}"
|
||||||
|
_="on error set my.src to generate_avatar(@data-handle)"
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td class="name">
|
||||||
|
<a href="{{ identity.urls.admin_edit }}" class="overlay"></a>
|
||||||
|
{{ identity.html_name_or_handle }}
|
||||||
|
<small>@{{ identity.handle }}</small>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if identity.restriction == 1 %}
|
||||||
|
<span class="bad">Limited</span>
|
||||||
|
{% elif identity.restriction == 2 %}
|
||||||
|
<span class="bad">Blocked</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</td>
|
||||||
</a>
|
<td class="stat">
|
||||||
|
{% if identity.local %}
|
||||||
|
Local
|
||||||
|
<small>{{ identity.followers_count }} follower{{ identity.followers_count|pluralize }}</small>
|
||||||
|
{% else %}
|
||||||
|
Remote
|
||||||
|
<small>{{ identity.followers_count }} local follower{{ identity.followers_count|pluralize }}</small>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="actions">
|
||||||
|
<a href="{{ identity.urls.admin_edit }}" title="View"><i class="fa-solid fa-eye"></i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class="option empty">
|
<tr class="empty">
|
||||||
{% if query %}
|
<td>
|
||||||
No identities match your query.
|
{% if query %}
|
||||||
{% else %}
|
No identities match your query.
|
||||||
There are no identities yet.
|
{% else %}
|
||||||
{% endif %}
|
There are no identities yet.
|
||||||
</p>
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="pagination">
|
</table>
|
||||||
{% if page_obj.has_previous %}
|
<div class="pagination">
|
||||||
<a class="button" href=".?page={{ page_obj.previous_page_number }}{% if local_only %}&local_only=true{% endif %}{% if query %}&query={{ query }}{% endif %}">Previous Page</a>
|
{% if page_obj.has_previous %}
|
||||||
{% endif %}
|
<a class="button" href=".?{% urlparams page=page_obj.previous_page_number %}">Previous Page</a>
|
||||||
{% if page_obj.paginator.count %}
|
{% endif %}
|
||||||
<span class="count">{{ page_obj.paginator.count }} identit{{page_obj.paginator.count|pluralize:"y,ies" }}</span>
|
{% if page_obj.paginator.count %}
|
||||||
{% endif %}
|
<span class="count">{{ page_obj.paginator.count }} identit{{page_obj.paginator.count|pluralize:"y,ies" }}</span>
|
||||||
{% if page_obj.has_next %}
|
{% endif %}
|
||||||
<a class="button" href=".?page={{ page_obj.next_page_number }}{% if local_only %}&local_only=true{% endif %}{% if query %}&query={{ query }}{% endif %}">Next Page</a>
|
{% if page_obj.has_next %}
|
||||||
{% endif %}
|
<a class="button" href=".?{% urlparams page=page_obj.next_page_number %}">Next Page</a>
|
||||||
</div>
|
{% endif %}
|
||||||
</section>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -4,51 +4,62 @@
|
||||||
{% block subtitle %}Invites{% endblock %}
|
{% block subtitle %}Invites{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<form>
|
<div class="view-options">
|
||||||
<div class="buttons">
|
<span class="spacer"></span>
|
||||||
<a href="{% url "admin_invite_create" %}" class="button">Create New</a>
|
<a href="{% url "admin_invite_create" %}" class="button">Create New</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<table class="items">
|
||||||
<section class="icon-menu">
|
|
||||||
{% for invite in page_obj %}
|
{% for invite in page_obj %}
|
||||||
<a class="option" href="{{ invite.urls.admin_view }}">
|
<tr>
|
||||||
<i class="fa-solid fa-envelope"></i>
|
<td class="icon">
|
||||||
<span class="handle">
|
<a href="{{ invite.urls.admin_view }}" class="overlay"></a>
|
||||||
|
<i class="fa-solid fa-envelope"></i>
|
||||||
|
</td>
|
||||||
|
<td class="name">
|
||||||
|
<a href="{{ invite.urls.admin_view }}" class="overlay"></a>
|
||||||
{{ invite.token }}
|
{{ invite.token }}
|
||||||
|
|
||||||
<small>
|
<small>
|
||||||
{% if invite.expires %}
|
|
||||||
Expires in {{ invite.expires|timeuntil }}
|
|
||||||
{% if invite.note %}|{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% if invite.note %}
|
{% if invite.note %}
|
||||||
{{ invite.note }}
|
{{ invite.note }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</small>
|
</small>
|
||||||
</span>
|
</td>
|
||||||
<time>
|
<td class="stat">
|
||||||
{% if invite.uses %}
|
{% if invite.expires %}
|
||||||
{{ invite.uses }} use{{ invite.uses|pluralize }} left
|
{% if invite.valid %}
|
||||||
{% else %}
|
{{ invite.expires|timeuntil }}
|
||||||
Infinite uses
|
<small>until expiry</small>
|
||||||
|
{% else %}
|
||||||
|
<span class="bad">Expired</span>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</time>
|
</time>
|
||||||
</a>
|
<td class="stat">
|
||||||
|
{% if invite.uses %}
|
||||||
|
{{ invite.uses }}
|
||||||
|
{% else %}
|
||||||
|
Infinite
|
||||||
|
{% endif %}
|
||||||
|
<small>use{{ invite.uses|pluralize }} left</small>
|
||||||
|
</time>
|
||||||
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class="option empty">
|
<tr class="empty">
|
||||||
There are no unused invites.
|
<td>
|
||||||
</p>
|
There are no invites yet.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="pagination">
|
</table>
|
||||||
{% if page_obj.has_previous %}
|
<div class="pagination">
|
||||||
<a class="button" href=".?page={{ page_obj.previous_page_number }}">Previous Page</a>
|
{% if page_obj.has_previous %}
|
||||||
{% endif %}
|
<a class="button" href=".?page={{ page_obj.previous_page_number }}">Previous Page</a>
|
||||||
{% if page_obj.paginator.count %}
|
{% endif %}
|
||||||
<span class="count">{{ page_obj.paginator.count }} invite{{page_obj.paginator.count|pluralize }}</span>
|
{% if page_obj.paginator.count %}
|
||||||
{% endif %}
|
<span class="count">{{ page_obj.paginator.count }} invite{{page_obj.paginator.count|pluralize }}</span>
|
||||||
{% if page_obj.has_next %}
|
{% endif %}
|
||||||
<a class="button" href=".?page={{ page_obj.next_page_number }}">Next Page</a>
|
{% if page_obj.has_next %}
|
||||||
{% endif %}
|
<a class="button" href=".?page={{ page_obj.next_page_number }}">Next Page</a>
|
||||||
</div>
|
{% endif %}
|
||||||
</section>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -11,36 +11,48 @@
|
||||||
<a href=".?all=true"><i class="fa-solid fa-xmark"></i> Show Resolved</a>
|
<a href=".?all=true"><i class="fa-solid fa-xmark"></i> Show Resolved</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<section class="icon-menu">
|
<table class="items">
|
||||||
{% for report in page_obj %}
|
{% for report in page_obj %}
|
||||||
<a class="option" href="{{ report.urls.admin_view }}">
|
<tr>
|
||||||
<img src="{{ report.subject_identity.local_icon_url.relative }}" class="icon" alt="Avatar for {{ report.subject_identity.name_or_handle }}">
|
<td class="icon">
|
||||||
<span class="handle">
|
<a href="{{ report.urls.admin_view }}" class="overlay"></a>
|
||||||
|
<img src="{{ report.subject_identity.local_icon_url.relative }}" class="icon" alt="Avatar for {{ report.subject_identity.name_or_handle }}">
|
||||||
|
</td>
|
||||||
|
<td class="name">
|
||||||
|
<a href="{{ report.urls.admin_view }}" class="overlay"></a>
|
||||||
{{ report.subject_identity.html_name_or_handle }}
|
{{ report.subject_identity.html_name_or_handle }}
|
||||||
{% if report.subject_post %}
|
{% if report.subject_post %}
|
||||||
(post {{ report.subject_post.pk }})
|
<small>
|
||||||
|
Post on {{ report.subject_post.published }}
|
||||||
|
</small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<small>
|
</td>
|
||||||
{{ report.type|title }}
|
<td class="stat">
|
||||||
</small>
|
{{ report.type|title }}
|
||||||
</span>
|
<small>Type</small>
|
||||||
<time>{{ report.created|timedeltashort }} ago</time>
|
</td>
|
||||||
</a>
|
<td class="stat">
|
||||||
|
{{ report.created|timedeltashort }}
|
||||||
|
<small>Reported</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class="option empty">
|
<tr class="empty">
|
||||||
There are no {% if all %}reports yet{% else %}unresolved reports{% endif %}.
|
<td>
|
||||||
</p>
|
There are no {% if all %}reports yet{% else %}unresolved reports{% endif %}.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="pagination">
|
</table>
|
||||||
{% if page_obj.has_previous %}
|
<div class="pagination">
|
||||||
<a class="button" href=".?page={{ page_obj.previous_page_number }}{% if all %}&all=true{% endif %}">Previous Page</a>
|
{% if page_obj.has_previous %}
|
||||||
{% endif %}
|
<a class="button" href=".?page={{ page_obj.previous_page_number }}{% if all %}&all=true{% endif %}">Previous Page</a>
|
||||||
{% if page_obj.paginator.count %}
|
{% endif %}
|
||||||
<span class="count">{{ page_obj.paginator.count }} report{{page_obj.paginator.count|pluralize }}</span>
|
{% if page_obj.paginator.count %}
|
||||||
{% endif %}
|
<span class="count">{{ page_obj.paginator.count }} report{{page_obj.paginator.count|pluralize }}</span>
|
||||||
{% if page_obj.has_next %}
|
{% endif %}
|
||||||
<a class="button" href=".?page={{ page_obj.next_page_number }}{% if all %}&all=true{% endif %}">Next Page</a>
|
{% if page_obj.has_next %}
|
||||||
{% endif %}
|
<a class="button" href=".?page={{ page_obj.next_page_number }}{% if all %}&all=true{% endif %}">Next Page</a>
|
||||||
</div>
|
{% endif %}
|
||||||
</section>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "settings/base.html" %}
|
{% extends "settings/base.html" %}
|
||||||
|
{% load activity_tags %}
|
||||||
|
|
||||||
{% block subtitle %}Users{% endblock %}
|
{% block subtitle %}Users{% endblock %}
|
||||||
|
|
||||||
|
@ -7,39 +8,51 @@
|
||||||
<input type="search" name="query" value="{{ query }}" placeholder="Search by email">
|
<input type="search" name="query" value="{{ query }}" placeholder="Search by email">
|
||||||
<button><i class="fa-solid fa-search"></i></button>
|
<button><i class="fa-solid fa-search"></i></button>
|
||||||
</form>
|
</form>
|
||||||
<section class="icon-menu">
|
<table class="items">
|
||||||
{% for user in page_obj %}
|
{% for user in page_obj %}
|
||||||
<a class="option" href="{{ user.urls.admin_edit }}">
|
<tr>
|
||||||
<i class="fa-solid fa-user"></i>
|
<td class="icon">
|
||||||
<span class="handle">
|
<a href="{{ user.urls.admin_edit }}" class="overlay"></a>
|
||||||
|
<i class="fa-solid fa-user"></i>
|
||||||
|
</td>
|
||||||
|
<td class="name">
|
||||||
|
<a href="{{ user.urls.admin_edit }}" class="overlay"></a>
|
||||||
{{ user.email }}
|
{{ user.email }}
|
||||||
|
<small>{% if user.admin %}Admin{% elif user.moderator %}Moderator{% endif %}</small>
|
||||||
|
</td>
|
||||||
|
<td class="stat">
|
||||||
|
{{ user.num_identities }}
|
||||||
<small>
|
<small>
|
||||||
{{ user.num_identities }} identit{{ user.num_identities|pluralize:"y,ies" }}
|
identit{{ user.num_identities|pluralize:"y,ies" }}
|
||||||
</small>
|
</small>
|
||||||
</span>
|
</span>
|
||||||
{% if user.banned %}
|
<td class="actions">
|
||||||
<span class="pill bad">Banned</span>
|
{% if user.banned %}
|
||||||
{% endif %}
|
<span class="bad">Banned</span>
|
||||||
</a>
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class="option empty">
|
<tr class="empty">
|
||||||
{% if query %}
|
<td>
|
||||||
No users match your query.
|
{% if query %}
|
||||||
{% else %}
|
No users match your query.
|
||||||
There are no users yet.
|
{% else %}
|
||||||
{% endif %}
|
There are no users yet.
|
||||||
</p>
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="pagination">
|
</table>
|
||||||
{% if page_obj.has_previous %}
|
<div class="pagination">
|
||||||
<a class="button" href=".?page={{ page_obj.previous_page_number }}">Previous Page</a>
|
{% if page_obj.has_previous %}
|
||||||
{% endif %}
|
<a class="button" href=".?{% urlparams page=page_obj.previous_page_number %}">Previous Page</a>
|
||||||
{% if page_obj.paginator.count %}
|
{% endif %}
|
||||||
<span class="count">{{ page_obj.paginator.count }} user{{page_obj.paginator.count|pluralize }}</span>
|
{% if page_obj.paginator.count %}
|
||||||
{% endif %}
|
<span class="count">{{ page_obj.paginator.count }} user{{page_obj.paginator.count|pluralize }}</span>
|
||||||
{% if page_obj.has_next %}
|
{% endif %}
|
||||||
<a class="button" href=".?page={{ page_obj.next_page_number }}">Next Page</a>
|
{% if page_obj.has_next %}
|
||||||
{% endif %}
|
<a class="button" href=".?{% urlparams page=page_obj.next_page_number %}">Next Page</a>
|
||||||
</div>
|
{% endif %}
|
||||||
</section>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ field.errors }}
|
{{ field.errors }}
|
||||||
{% if field.field.widget.input_type == "file" and field.value %}
|
{% if field.field.widget.input_type == "file" and field.value and not hide_existing %}
|
||||||
<div class="clear">
|
<div class="clear">
|
||||||
<input type="checkbox" class="clear" name="{{ field.name }}__clear"> Clear current value</input>
|
<input type="checkbox" class="clear" name="{{ field.name }}__clear"> Clear current value</input>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ field }}
|
{{ field }}
|
||||||
</div>
|
</div>
|
||||||
{% if field.field.widget.input_type == "file" and field.value %}
|
{% if field.field.widget.input_type == "file" and field.value and not hide_existing %}
|
||||||
<img class="preview" src="{{ field.value }}">
|
<img class="preview" src="{{ field.value }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
<a href="{% url "admin_hashtags" %}" {% if section == "hashtags" %}class="selected"{% endif %} title="Hashtags">
|
<a href="{% url "admin_hashtags" %}" {% if section == "hashtags" %}class="selected"{% endif %} title="Hashtags">
|
||||||
<i class="fa-solid fa-hashtag"></i> Hashtags
|
<i class="fa-solid fa-hashtag"></i> Hashtags
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{% url "admin_emoji" %}" {% if section == "emoji" %}class="selected"{% endif %} title="Emoji">
|
||||||
|
<i class="fa-solid fa-icons"></i> Emoji
|
||||||
|
</a>
|
||||||
<a href="{% url "admin_reports" %}" {% if section == "reports" %}class="selected"{% endif %} title="Reports">
|
<a href="{% url "admin_reports" %}" {% if section == "reports" %}class="selected"{% endif %} title="Reports">
|
||||||
<i class="fa-solid fa-flag"></i> Reports
|
<i class="fa-solid fa-flag"></i> Reports
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -203,3 +203,12 @@ class Domain(StatorModel):
|
||||||
f"Client error decoding nodeinfo: domain={self.domain}, error={str(ex)}"
|
f"Client error decoding nodeinfo: domain={self.domain}, error={str(ex)}"
|
||||||
)
|
)
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
@property
|
||||||
|
def software(self):
|
||||||
|
if self.nodeinfo:
|
||||||
|
software = self.nodeinfo.get("software", {})
|
||||||
|
name = software.get("name", "unknown")
|
||||||
|
version = software.get("version", "unknown")
|
||||||
|
return f"{name:.10} - {version:.10}"
|
||||||
|
return None
|
||||||
|
|
|
@ -8,8 +8,14 @@ from users.views.admin.domains import ( # noqa
|
||||||
DomainEdit,
|
DomainEdit,
|
||||||
Domains,
|
Domains,
|
||||||
)
|
)
|
||||||
|
from users.views.admin.emoji import ( # noqa
|
||||||
|
EmojiCreate,
|
||||||
|
EmojiDelete,
|
||||||
|
EmojiEnable,
|
||||||
|
EmojiRoot,
|
||||||
|
)
|
||||||
from users.views.admin.federation import FederationEdit, FederationRoot # noqa
|
from users.views.admin.federation import FederationEdit, FederationRoot # noqa
|
||||||
from users.views.admin.hashtags import HashtagEdit, Hashtags # noqa
|
from users.views.admin.hashtags import HashtagEdit, HashtagEnable, Hashtags # noqa
|
||||||
from users.views.admin.identities import IdentitiesRoot, IdentityEdit # noqa
|
from users.views.admin.identities import IdentitiesRoot, IdentityEdit # noqa
|
||||||
from users.views.admin.invites import InviteCreate, InvitesRoot, InviteView # noqa
|
from users.views.admin.invites import InviteCreate, InvitesRoot, InviteView # noqa
|
||||||
from users.views.admin.reports import ReportsRoot, ReportView # noqa
|
from users.views.admin.reports import ReportsRoot, ReportView # noqa
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
from django import forms
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import models
|
||||||
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
|
from django.utils.decorators import method_decorator
|
||||||
|
from django.views.generic import FormView, ListView, View
|
||||||
|
from django_htmx.http import HttpResponseClientRefresh
|
||||||
|
|
||||||
|
from activities.models import Emoji
|
||||||
|
from users.decorators import moderator_required
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(moderator_required, name="dispatch")
|
||||||
|
class EmojiRoot(ListView):
|
||||||
|
|
||||||
|
template_name = "admin/emoji.html"
|
||||||
|
paginate_by = 50
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
self.query = request.GET.get("query")
|
||||||
|
self.local_only = request.GET.get("local_only")
|
||||||
|
self.extra_context = {
|
||||||
|
"section": "emoji",
|
||||||
|
"query": self.query or "",
|
||||||
|
"local_only": self.local_only,
|
||||||
|
}
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = Emoji.objects.filter().order_by("shortcode", "domain_id")
|
||||||
|
if self.local_only:
|
||||||
|
queryset = queryset.filter(local=True)
|
||||||
|
if self.query:
|
||||||
|
query = self.query.lower().strip().lstrip("@")
|
||||||
|
queryset = queryset.filter(
|
||||||
|
models.Q(shortcode__icontains=query) | models.Q(domain_id=query)
|
||||||
|
)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(moderator_required, name="dispatch")
|
||||||
|
class EmojiCreate(FormView):
|
||||||
|
|
||||||
|
template_name = "admin/emoji_create.html"
|
||||||
|
extra_context = {"section": "emoji"}
|
||||||
|
|
||||||
|
class form_class(forms.Form):
|
||||||
|
shortcode = forms.SlugField(
|
||||||
|
help_text="What users type to use the emoji :likethis:",
|
||||||
|
)
|
||||||
|
image = forms.ImageField(
|
||||||
|
help_text="The emoji image\nShould be at least 40 x 40 pixels, and under 50kb",
|
||||||
|
)
|
||||||
|
|
||||||
|
def clean_image(self):
|
||||||
|
data = self.cleaned_data["image"]
|
||||||
|
if data.size > settings.SETUP.EMOJI_MAX_IMAGE_FILESIZE_KB:
|
||||||
|
raise forms.ValidationError("Image filesize is too large")
|
||||||
|
return data
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
Emoji.objects.create(
|
||||||
|
shortcode=form.cleaned_data["shortcode"],
|
||||||
|
file=form.cleaned_data["image"],
|
||||||
|
mimetype=form.cleaned_data["image"].image.get_format_mimetype(),
|
||||||
|
local=True,
|
||||||
|
public=True,
|
||||||
|
)
|
||||||
|
return redirect(Emoji.urls.admin)
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(moderator_required, name="dispatch")
|
||||||
|
class EmojiDelete(View):
|
||||||
|
"""
|
||||||
|
Deletes an emoji
|
||||||
|
"""
|
||||||
|
|
||||||
|
def post(self, request, id):
|
||||||
|
self.emoji = get_object_or_404(Emoji, pk=id)
|
||||||
|
self.emoji.delete()
|
||||||
|
return HttpResponseClientRefresh()
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(moderator_required, name="dispatch")
|
||||||
|
class EmojiEnable(View):
|
||||||
|
"""
|
||||||
|
Sets an emoji to be enabled (or not!)
|
||||||
|
"""
|
||||||
|
|
||||||
|
enable = True
|
||||||
|
|
||||||
|
def post(self, request, id):
|
||||||
|
self.emoji = get_object_or_404(Emoji, pk=id)
|
||||||
|
self.emoji.public = self.enable
|
||||||
|
self.emoji.save()
|
||||||
|
return HttpResponseClientRefresh()
|
|
@ -1,7 +1,8 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views.generic import FormView, ListView
|
from django.views.generic import FormView, ListView, View
|
||||||
|
from django_htmx.http import HttpResponseClientRefresh
|
||||||
|
|
||||||
from activities.models import Hashtag, HashtagStates
|
from activities.models import Hashtag, HashtagStates
|
||||||
from users.decorators import moderator_required
|
from users.decorators import moderator_required
|
||||||
|
@ -78,3 +79,18 @@ class HashtagEdit(FormView):
|
||||||
"name_override": self.hashtag.name_override,
|
"name_override": self.hashtag.name_override,
|
||||||
"public": self.hashtag.public,
|
"public": self.hashtag.public,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(moderator_required, name="dispatch")
|
||||||
|
class HashtagEnable(View):
|
||||||
|
"""
|
||||||
|
Sets a hashtag to be enabled (or not!)
|
||||||
|
"""
|
||||||
|
|
||||||
|
enable = True
|
||||||
|
|
||||||
|
def post(self, request, hashtag):
|
||||||
|
self.hashtag = get_object_or_404(Hashtag, hashtag=hashtag)
|
||||||
|
self.hashtag.public = self.enable
|
||||||
|
self.hashtag.save()
|
||||||
|
return HttpResponseClientRefresh()
|
||||||
|
|
|
@ -25,9 +25,11 @@ class IdentitiesRoot(ListView):
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
identities = Identity.objects.annotate(
|
identities = (
|
||||||
num_users=models.Count("users")
|
Identity.objects.annotate(num_users=models.Count("users"))
|
||||||
).order_by("created")
|
.annotate(followers_count=models.Count("inbound_follows"))
|
||||||
|
.order_by("created")
|
||||||
|
)
|
||||||
if self.local_only:
|
if self.local_only:
|
||||||
identities = identities.filter(local=True)
|
identities = identities.filter(local=True)
|
||||||
if self.query:
|
if self.query:
|
||||||
|
|
Ładowanie…
Reference in New Issue