mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2024-11-21 22:17:59 +00:00
create admin instances page
This commit is contained in:
parent
7af3b9c20b
commit
e6831f04eb
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -1,5 +1,41 @@
|
||||||
-extends "base.haml"
|
-extends "base.haml"
|
||||||
-set page="Instances"
|
-set page="Instances"
|
||||||
-block content
|
-block content
|
||||||
.section
|
%details.section
|
||||||
UvU
|
%summary << Add Instance
|
||||||
|
%form(target="/admin/instances", method="POST")
|
||||||
|
#add-instance
|
||||||
|
%label(for="domain") << Domain
|
||||||
|
%input(type="domain", name="domain", placeholder="Domain")
|
||||||
|
%label(for="actor") << Actor URL
|
||||||
|
%input(type="url", name="actor", placeholder="Actor URL")
|
||||||
|
%label(for="inbox") << Inbox URL
|
||||||
|
%input(type="url", name="inbox", placeholder="Inbox URL")
|
||||||
|
%label(for="software") << Software
|
||||||
|
%input(name="software", placeholder="software")
|
||||||
|
|
||||||
|
%input(type="submit" value="Add Instance")
|
||||||
|
|
||||||
|
#instances.section
|
||||||
|
%table
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%td.instance << Instance
|
||||||
|
%td.software << Software
|
||||||
|
%td.date << Joined
|
||||||
|
%td.remove
|
||||||
|
|
||||||
|
%tbody
|
||||||
|
-for instance in instances
|
||||||
|
%tr
|
||||||
|
%td.instance
|
||||||
|
%a(href="https://{{instance.domain}}/" target="_new") -> =instance.domain
|
||||||
|
|
||||||
|
%td.software
|
||||||
|
=instance.software or "n/a"
|
||||||
|
|
||||||
|
%td.date
|
||||||
|
=instance.created.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
%td.remove
|
||||||
|
%a(href="/admin/instances/delete/{{instance.domain}}" title="Remove Instance") << ✖
|
||||||
|
|
|
@ -32,6 +32,10 @@ a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
details summary {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
form input[type="submit"] {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#instances table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#instances .instance {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#instances .software {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#instances .date {
|
||||||
|
width: max-content;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#instances thead td {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#add-instance {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content auto;
|
||||||
|
grid-gap: var(--spacing);
|
||||||
|
margin-top: var(--spacing);
|
||||||
|
margin-bottom: var(--spacing);
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ from . import logger as logging
|
||||||
from .application import Application
|
from .application import Application
|
||||||
from .compat import RelayConfig, RelayDatabase
|
from .compat import RelayConfig, RelayDatabase
|
||||||
from .database import RELAY_SOFTWARE, get_database
|
from .database import RELAY_SOFTWARE, get_database
|
||||||
from .misc import IS_DOCKER, Message
|
from .misc import ACTOR_FORMATS, SOFTWARE, IS_DOCKER, Message
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from tinysql import Row
|
from tinysql import Row
|
||||||
|
@ -33,23 +33,6 @@ CONFIG_IGNORE = (
|
||||||
'private-key'
|
'private-key'
|
||||||
)
|
)
|
||||||
|
|
||||||
ACTOR_FORMATS = {
|
|
||||||
'mastodon': 'https://{domain}/actor',
|
|
||||||
'akkoma': 'https://{domain}/relay',
|
|
||||||
'pleroma': 'https://{domain}/relay'
|
|
||||||
}
|
|
||||||
|
|
||||||
SOFTWARE = (
|
|
||||||
'mastodon',
|
|
||||||
'akkoma',
|
|
||||||
'pleroma',
|
|
||||||
'misskey',
|
|
||||||
'friendica',
|
|
||||||
'hubzilla',
|
|
||||||
'firefish',
|
|
||||||
'gotosocial'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def check_alphanumeric(text: str) -> str:
|
def check_alphanumeric(text: str) -> str:
|
||||||
if not text.isalnum():
|
if not text.isalnum():
|
||||||
|
|
|
@ -36,6 +36,23 @@ NODEINFO_NS = {
|
||||||
'21': 'http://nodeinfo.diaspora.software/ns/schema/2.1'
|
'21': 'http://nodeinfo.diaspora.software/ns/schema/2.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ACTOR_FORMATS = {
|
||||||
|
'mastodon': 'https://{domain}/actor',
|
||||||
|
'akkoma': 'https://{domain}/relay',
|
||||||
|
'pleroma': 'https://{domain}/relay'
|
||||||
|
}
|
||||||
|
|
||||||
|
SOFTWARE = (
|
||||||
|
'mastodon',
|
||||||
|
'akkoma',
|
||||||
|
'pleroma',
|
||||||
|
'misskey',
|
||||||
|
'friendica',
|
||||||
|
'hubzilla',
|
||||||
|
'firefish',
|
||||||
|
'gotosocial'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def boolean(value: Any) -> bool:
|
def boolean(value: Any) -> bool:
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
|
|
|
@ -7,34 +7,21 @@ from argon2.exceptions import VerifyMismatchError
|
||||||
|
|
||||||
from .base import View, register_route
|
from .base import View, register_route
|
||||||
|
|
||||||
from ..misc import Response
|
from ..misc import ACTOR_FORMATS, Message, Response
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from aiohttp.web import Request
|
from aiohttp.web import Request
|
||||||
|
|
||||||
|
|
||||||
AUTH_ROUTES = {
|
|
||||||
'/admin',
|
|
||||||
'/admin/instances',
|
|
||||||
'/admin/domain_bans',
|
|
||||||
'/admin/software_bans',
|
|
||||||
'/admin/whitelist',
|
|
||||||
'/admin/config',
|
|
||||||
'/logout'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UNAUTH_ROUTES = {
|
UNAUTH_ROUTES = {
|
||||||
'/',
|
'/',
|
||||||
'/login'
|
'/login'
|
||||||
}
|
}
|
||||||
|
|
||||||
ALL_ROUTES = {*AUTH_ROUTES, *UNAUTH_ROUTES}
|
|
||||||
|
|
||||||
|
|
||||||
@web.middleware
|
@web.middleware
|
||||||
async def handle_frontend_path(request: web.Request, handler: Coroutine) -> Response:
|
async def handle_frontend_path(request: web.Request, handler: Coroutine) -> Response:
|
||||||
if request.path in ALL_ROUTES:
|
if request.path in UNAUTH_ROUTES or request.path.startswith('/admin'):
|
||||||
request['token'] = request.cookies.get('user-token')
|
request['token'] = request.cookies.get('user-token')
|
||||||
request['user'] = None
|
request['user'] = None
|
||||||
|
|
||||||
|
@ -57,16 +44,11 @@ async def handle_frontend_path(request: web.Request, handler: Coroutine) -> Resp
|
||||||
class HomeView(View):
|
class HomeView(View):
|
||||||
async def get(self, request: Request) -> Response:
|
async def get(self, request: Request) -> Response:
|
||||||
with self.database.session() as conn:
|
with self.database.session() as conn:
|
||||||
instances = tuple(conn.execute('SELECT * FROM inboxes').all())
|
context = {
|
||||||
|
'instances': tuple(conn.execute('SELECT * FROM inboxes').all())
|
||||||
|
}
|
||||||
|
|
||||||
# text = HOME_TEMPLATE.format(
|
data = self.template.render('page/home.haml', self, **context)
|
||||||
# host = self.config.domain,
|
|
||||||
# note = config['note'],
|
|
||||||
# count = len(inboxes),
|
|
||||||
# targets = '<br>'.join(inbox['domain'] for inbox in inboxes)
|
|
||||||
# )
|
|
||||||
|
|
||||||
data = self.template.render('page/home.haml', self, instances = instances)
|
|
||||||
return Response.new(data, ctype='html')
|
return Response.new(data, ctype='html')
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,11 +119,64 @@ class Admin(View):
|
||||||
|
|
||||||
@register_route('/admin/instances')
|
@register_route('/admin/instances')
|
||||||
class AdminInstances(View):
|
class AdminInstances(View):
|
||||||
async def get(self, request: Request) -> Response:
|
async def get(self,
|
||||||
data = self.template.render('page/admin-instances.haml', self)
|
request: Request,
|
||||||
|
error: str | None = None,
|
||||||
|
message: str | None = None) -> Response:
|
||||||
|
|
||||||
|
with self.database.session() as conn:
|
||||||
|
context = {
|
||||||
|
'instances': tuple(conn.execute('SELECT * FROM inboxes').all())
|
||||||
|
}
|
||||||
|
|
||||||
|
if error:
|
||||||
|
context['error'] = error
|
||||||
|
|
||||||
|
if message:
|
||||||
|
context['message'] = message
|
||||||
|
|
||||||
|
data = self.template.render('page/admin-instances.haml', self, **context)
|
||||||
return Response.new(data, ctype = 'html')
|
return Response.new(data, ctype = 'html')
|
||||||
|
|
||||||
|
|
||||||
|
async def post(self, request: Request) -> Response:
|
||||||
|
data = {key: value for key, value in (await request.post()).items()}
|
||||||
|
|
||||||
|
if not data['actor'] and not data['domain']:
|
||||||
|
return await self.get(request, error = 'Missing actor and/or domain')
|
||||||
|
|
||||||
|
if not data['domain']:
|
||||||
|
data['domain'] = urlparse(data['actor']).netloc
|
||||||
|
|
||||||
|
if not data['software']:
|
||||||
|
nodeinfo = await self.client.fetch_nodeinfo(data['domain'])
|
||||||
|
data['software'] = nodeinfo.sw_name
|
||||||
|
|
||||||
|
if not data['actor'] and data['software'] in ACTOR_FORMATS:
|
||||||
|
data['actor'] = ACTOR_FORMATS[data['software']].format(domain = data['domain'])
|
||||||
|
|
||||||
|
if not data['inbox'] and data['actor']:
|
||||||
|
actor = await self.client.get(data['actor'], sign_headers = True, loads = Message.parse)
|
||||||
|
data['inbox'] = actor.shared_inbox
|
||||||
|
|
||||||
|
with self.database.session(True) as conn:
|
||||||
|
conn.put_inbox(**data)
|
||||||
|
|
||||||
|
return await self.get(request, message = "Added new inbox")
|
||||||
|
|
||||||
|
|
||||||
|
@register_route('/admin/instances/delete/{domain}')
|
||||||
|
class AdminInstancesDelete(View):
|
||||||
|
async def get(self, request: Request, domain: str) -> Response:
|
||||||
|
with self.database.session() as conn:
|
||||||
|
if not (conn.get_inbox(domain)):
|
||||||
|
return await AdminInstances(request).get(request, message = 'Instance not found')
|
||||||
|
|
||||||
|
conn.del_inbox(domain)
|
||||||
|
|
||||||
|
return await AdminInstances(request).get(request, message = 'Removed instance')
|
||||||
|
|
||||||
|
|
||||||
@register_route('/admin/whitelist')
|
@register_route('/admin/whitelist')
|
||||||
class AdminWhitelist(View):
|
class AdminWhitelist(View):
|
||||||
async def get(self, request: Request) -> Response:
|
async def get(self, request: Request) -> Response:
|
||||||
|
|
Loading…
Reference in a new issue