forked from chainsaw_mcginny/RoosterReWrite
12 changed files with 235 additions and 1 deletions
After Width: | Height: | Size: 128 KiB |
After Width: | Height: | Size: 49 KiB |
File diff suppressed because one or more lines are too long
@ -0,0 +1,41 @@ |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
|||
<title>Rooster Web UI</title> |
|||
<link rel="shortcut icon" href="/assets/favicon.ico" type="image/x-icon"> |
|||
<link rel="stylesheet" href="/assets/style.css"> |
|||
</head> |
|||
<body> |
|||
|
|||
<nav class="navbar navbar-expand-lg navbar-light p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm"> |
|||
<a class="navbar-brand" href="{{ url_for('index') }}"> |
|||
<img src="/assets/fweddit.png" width="30" height="30" class="d-inline-block align-top" alt=""> |
|||
Rooster Web UI |
|||
</a> |
|||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" |
|||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> |
|||
<span class="navbar-toggler-icon"></span> |
|||
</button> |
|||
<div class="collapse navbar-collapse" id="navbarSupportedContent"> |
|||
<ul class="navbar-nav mr-auto"> |
|||
{% if current_user.is_authenticated %} |
|||
<li class="nav-item"> |
|||
<a class="nav-link" href="{{ url_for('logs') }}">Logs</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" href="{{ url_for('killstream') }}">Killstream</a> |
|||
</li> |
|||
{% endif %} |
|||
</ul> |
|||
{% if current_user.is_authenticated %} |
|||
<a class="my-2 my-lg-0 btn btn-outline-danger" href="{{ url_for('logout') }}">Logout</a> |
|||
{% endif %} |
|||
</div> |
|||
</nav> |
|||
<div class="container"> |
|||
{% block content %}{% endblock %} |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,47 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block content %} |
|||
<p>Rooster is currently in <span class="badge">{{ guilds|length }}</span> guilds and is serving |
|||
<span class="badge">{{ users|length }}</span> users.</p> |
|||
|
|||
<table class="table table-bordered table-striped"> |
|||
<thead> |
|||
<tr> |
|||
<th scope="col">Id</th> |
|||
<th scope="col">Name</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for user in users %} |
|||
<tr> |
|||
<td>{{ user.id }}</td> |
|||
<td> |
|||
<img src="{{ user.avatar_url }}" width="32" height="32" alt="Avatar"> {{ user.name }} |
|||
{% if user.bot %}<span class="badge badge-info">BOT</span>{% endif %} |
|||
</td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
|
|||
<table class="table table-bordered table-striped"> |
|||
<thead> |
|||
<tr> |
|||
<th scope="col">Id</th> |
|||
<th scope="col">Name</th> |
|||
<th scope="col">Members</th> |
|||
<th scope="col">Channels</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for guild in guilds %} |
|||
<tr> |
|||
<td>{{ guild.id }}</td> |
|||
<td><img src="{{ guild.icon_url }}" width="32" height="32" alt="Icon"> {{ guild.name }}</td> |
|||
<td>{{ guild.members|length }}</td> |
|||
<td>{{ guild.channels|length }}</td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
{% endblock %} |
@ -0,0 +1,29 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block content %} |
|||
<p>We have <span class="badge">{{ killwatches|length }}</span> killwatches. |
|||
|
|||
<table class="table table-bordered table-striped"> |
|||
<thead> |
|||
<tr> |
|||
<th scope="col">Channel</th> |
|||
<th scope="col">Entity Name</th> |
|||
<th scope="col">Entity Id</th> |
|||
<th scope="col">Value</th> |
|||
<th scope="col">Scope</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for killwatch in killwatches %} |
|||
<tr> |
|||
<td>{{ killwatches[killwatch].channel }}</td> |
|||
<td>{{ killwatches[killwatch].name }}</td> |
|||
<td>{{ killwatches[killwatch].id }}</td> |
|||
<td>{{ killwatches[killwatch].value }}</td> |
|||
<td>{{ killwatches[killwatch].scope }}</td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
|
|||
{% endblock %} |
@ -0,0 +1,12 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block content %} |
|||
<p>You need to login to access this page.</p> |
|||
<form class="form" action="{{ url_for('login') }}" method="post"> |
|||
<div class="form-group"> |
|||
<label for="access_key">Access key</label> |
|||
<input type="password" class="form-control" id="access_key" name="access_key" required> |
|||
</div> |
|||
<button type="submit" class="btn btn-primary">Submit</button> |
|||
</form> |
|||
{% endblock %} |
@ -0,0 +1,14 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
{% block content %} |
|||
<table class="table table-bordered table-striped"> |
|||
<tbody> |
|||
{% for log in logs %} |
|||
<tr> |
|||
<td>{{ log }}</td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
|
|||
{% endblock %} |
@ -0,0 +1,76 @@ |
|||
import json |
|||
import logging |
|||
import config |
|||
from discord.ext import commands, tasks |
|||
from quart import Quart, render_template, ResponseReturnValue, redirect, url_for, request |
|||
from quart.exceptions import Unauthorized |
|||
from quart_auth import AuthManager, AuthUser, login_required, login_user, logout_user |
|||
|
|||
log = logging.getLogger(__name__) |
|||
app = Quart(__name__, static_url_path='/assets/', static_folder='web/assets', template_folder='web/templates') |
|||
app.secret_key = config.web_secret_key |
|||
AuthManager(app) |
|||
|
|||
|
|||
class Webserver(commands.Cog): |
|||
def __init__(self, bot): |
|||
self.bot = bot |
|||
self.web_server.start() |
|||
|
|||
@app.route('/') |
|||
@login_required |
|||
async def index(): |
|||
return await render_template('index.html', guilds=self.bot.guilds, users=self.bot.users) |
|||
|
|||
@app.route('/logs') |
|||
@login_required |
|||
async def logs(): |
|||
with open('Rooster.log') as f: |
|||
content = f.readlines() |
|||
return await render_template('logs.html', logs=reversed([x.strip() for x in content])) |
|||
|
|||
@app.route('/killstream/') |
|||
@login_required |
|||
async def killstream(): |
|||
killwatches = await self.bot.redis.execute("get", "killwatch_criteria") |
|||
return await render_template('killstream.html', killwatches=json.loads(killwatches.decode("utf-8"))) |
|||
|
|||
@app.route('/send-message/<channel_id>') |
|||
@login_required |
|||
async def test_message(channel_id): |
|||
channel = self.bot.get_channel(int(channel_id)) |
|||
await channel.send('web ui test') |
|||
return 'Done!' |
|||
|
|||
@app.errorhandler(Unauthorized) |
|||
async def redirect_to_login(*_: Exception) -> ResponseReturnValue: |
|||
return redirect(url_for("login")) |
|||
|
|||
@app.route("/login", methods=['GET', 'POST']) |
|||
async def login(): |
|||
if request.method == 'POST': |
|||
access_key = (await request.form)["access_key"] |
|||
if access_key == config.web_access_key: |
|||
login_user(AuthUser(access_key)) |
|||
return redirect(url_for('index')) |
|||
else: |
|||
return redirect(url_for('login')) |
|||
else: |
|||
return await render_template('login.html') |
|||
|
|||
@app.route("/logout") |
|||
async def logout(): |
|||
logout_user() |
|||
return redirect(url_for('index')) |
|||
|
|||
@tasks.loop() |
|||
async def web_server(self): |
|||
await app.run_task(host=config.web_host, port=config.web_port, use_reloader=False) |
|||
|
|||
@web_server.before_loop |
|||
async def web_server_before_loop(self): |
|||
await self.bot.wait_until_ready() |
|||
|
|||
|
|||
def setup(bot): |
|||
bot.add_cog(Webserver(bot)) |
Loading…
Reference in new issue