add web
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Asset Copier</h1>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<p class="m-0" style="font-size:small;">Do not abuse this tool, allowed assets: ( TShirt, Hat, Shirt, Pants, Head, Face, Gear, Accessories )</p>
|
||||
<p class="m-0 text-danger" style="font-size:small;">WARNING: When cloning accessories please be careful cloning 2016+ assets as some accessories attachments are too new for our client to handle</p>
|
||||
<div class="linebreak"></div>
|
||||
<form method="post" class="d-flex">
|
||||
<input type="text" name="asseturl" class="form-control" placeholder="Asset URL">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-primary ms-3" value="Copy Asset">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,119 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Asset Moderation</h1>
|
||||
<p class="m-0" style="font-size:small;">Do not approve any controversial, NSFW, racist, anti semitism, furry content and aggressive swearing</p>
|
||||
<p class="m-0" style="font-size:small;">For images every second any transparent part of the image will change colors this will help find any hidden content</p>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="linebreak"></div>
|
||||
{% for pendingAsset in PendingAssets: %}
|
||||
<div class="border p-2 mb-1">
|
||||
{% if 'Asset' in pendingAsset %}
|
||||
<h5 class="m-0">{{pendingAsset.Asset.name}}</h5>
|
||||
<div class="d-flex mb-2" style="font-size: small;">
|
||||
<p class="m-0 text-secondary">AssetId: <span class="text-white">{{pendingAsset.Asset.id}}</span></p>
|
||||
<p class="m-0 text-secondary ms-2">Created: <span class="text-white">{{pendingAsset.Asset.created_at}}</span></p>
|
||||
<p class="m-0 text-secondary ms-2">CreatorId: <span class="text-white">{{pendingAsset.Asset.creator_id}}</span></p>
|
||||
<p class="m-0 text-secondary ms-2">Creator Type: <span class="text-white">{% if pendingAsset.Asset.creator_type == 1%}Group{%else%}User{%endif%}</span></p>
|
||||
<p class="m-0 text-secondary ms-2">AssetType: <span class="text-white">{{pendingAsset.Asset.asset_type.name}}</span></p>
|
||||
</div>
|
||||
{%endif%}
|
||||
{% if 'Group' in pendingAsset %}
|
||||
<h5 class="m-0">{{pendingAsset.Group.name}}</h5>
|
||||
<div class="d-flex mb-2" style="font-size: small;">
|
||||
<p class="m-0 text-secondary">GroupId: <span class="text-white">{{pendingAsset.Group.id}}</span></p>
|
||||
<p class="m-0 text-secondary ms-2">Created: <span class="text-white">{{pendingAsset.Icon.created_at}}</span></p>
|
||||
<p class="m-0 text-secondary ms-2">CreatorId: <span class="text-white">{{pendingAsset.Creator.id}}</span></p>
|
||||
</div>
|
||||
{%endif%}
|
||||
{% if pendingAsset.ParentAsset: %}
|
||||
<div class="d-flex border p-1" style="font-size: small;">
|
||||
<p class="m-0 text-secondary">Parent AssetId: <span class="text-white">{{pendingAsset.ParentAsset.id}}</span></p>
|
||||
<p class="m-0 text-secondary ms-2">Parent Name: <span class="text-white">{{pendingAsset.ParentAsset.name}}</span></p>
|
||||
<p class="m-0 text-secondary ms-2">Parent AssetType: <span class="text-white">{{pendingAsset.ParentAsset.asset_type.name}}</span></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'Asset' in pendingAsset %}
|
||||
{% if pendingAsset.Asset.asset_type.value == 1 and not pendingAsset.AssetThumbnail: %}
|
||||
<div class="d-flex justify-content-center">
|
||||
<img width="512" height="512" class="mt-2 content-image" src="https://sussybakaamongus.s3.eu-north-1.amazonaws.com/{{pendingAsset.AssetVersion.content_hash}}">
|
||||
</div>
|
||||
{%endif%}
|
||||
{% if pendingAsset.Asset.asset_type.value == 9: %}
|
||||
{% if pendingAsset.PlaceIcon: %}
|
||||
<div class="d-flex justify-content-center">
|
||||
<img width="512" height="512" class="mt-2 content-image" src="https://sussybakaamongus.s3.eu-north-1.amazonaws.com/{{pendingAsset.AssetVersion.contenthash}}">
|
||||
</div>
|
||||
{%endif%}
|
||||
{%endif%}
|
||||
{% if pendingAsset.Asset.asset_type.value == 3 %}
|
||||
<audio controls class="ms-auto me-auto">
|
||||
<source src="https://sussybakaamongus.s3.eu-north-1.amazonaws.com/{{pendingAsset.AssetVersion.content_hash}}" type="audio/mpeg">
|
||||
</audio>
|
||||
{%endif%}
|
||||
{%endif%}
|
||||
{% if pendingAsset.AssetThumbnail: %}
|
||||
<div class="d-flex justify-content-center">
|
||||
<img class="mt-2 content-image" src="https://sussybakaamongus.s3.eu-north-1.amazonaws.com/{{pendingAsset.AssetVersion.content_hash}}" style="max-width: 512px;height: auto;max-height: 1024px;">
|
||||
</div>
|
||||
{%endif%}
|
||||
{% if 'Group' in pendingAsset %}
|
||||
{% if pendingAsset.Icon: %}
|
||||
<div class="d-flex justify-content-center">
|
||||
<img width="512" height="512" class="mt-2 content-image" src="https://sussybakaamongus.s3.eu-north-1.amazonaws.com/{{pendingAsset.Icon.content_hash}}">
|
||||
</div>
|
||||
{%endif%}
|
||||
{%endif%}
|
||||
{% if 'Asset' in pendingAsset %}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<form method="post" action="/admin/pending-assets/{%if pendingAsset.AssetThumbnail%}{{pendingAsset.AssetVersion.id}}{%else%}{{pendingAsset.Asset.id}}{%endif%}/approve{%if pendingAsset.PlaceIcon%}-icon{%endif%}{%if pendingAsset.AssetThumbnail%}-thumbnail{%endif%}"><button class="btn btn-success w-100 btn-sm mt-2">Approve Content</button></form>
|
||||
</div>
|
||||
<div class="col">
|
||||
<form method="post" action="/admin/pending-assets/{%if pendingAsset.AssetThumbnail%}{{pendingAsset.AssetVersion.id}}{%else%}{{pendingAsset.Asset.id}}{%endif%}/decline{%if pendingAsset.PlaceIcon%}-icon{%endif%}{%if pendingAsset.AssetThumbnail%}-thumbnail{%endif%}"><button type="submit" class="btn btn-danger w-100 btn-sm mt-2">Deny Content</button></form>
|
||||
</div>
|
||||
</div>
|
||||
{%else%}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<form method="post" action="/admin/pending-assets/{{pendingAsset.Icon.content_hash}}/approve-group-icon"><button class="btn btn-success w-100 btn-sm mt-2">Approve Content</button></form>
|
||||
</div>
|
||||
<div class="col">
|
||||
<form method="post" action="/admin/pending-assets/{{pendingAsset.Icon.content_hash}}/deny-group-icon"><button type="submit" class="btn btn-danger w-100 btn-sm mt-2">Deny Content</button></form>
|
||||
</div>
|
||||
</div>
|
||||
{%endif%}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/* Every second get every image with the classname "content-image" and change the background color to a random gradient */
|
||||
setInterval(() => {
|
||||
let images = document.getElementsByClassName("content-image");
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
let image = images[i];
|
||||
let randomColor = Math.floor(Math.random()*16777215).toString(16);
|
||||
let randomColor2 = Math.floor(Math.random()*16777215).toString(16);
|
||||
let randomAngle = Math.floor(Math.random()*360);
|
||||
image.style.background = `linear-gradient(${randomAngle}deg, #${randomColor}, #${randomColor2})`;
|
||||
}
|
||||
}, 500);
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,39 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Bundle Copier</h1>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<p class="m-0" style="font-size:small;">Do not abuse this tool, some extra modifications may be needed when cloning a bundle as it is not always perfect once cloned. Also it might take awhile for it copy all assets, and we recommend to not use it when anyone is in game.</p>
|
||||
<p class="m-0 text-danger" style="font-size:small;">WARNING: PLEASE make sure the bundle you are copying has not already been uploaded</p>
|
||||
<div class="linebreak"></div>
|
||||
<form method="post" class="d-flex">
|
||||
<input type="text" name="bundle-id" class="form-control" placeholder="Bundle Id">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-primary ms-3" value="Copy Bundle">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,59 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Create Asset</h1>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="form-floating mt-2">
|
||||
<input type="text" class="form-control" id="asset-name-input" placeholder="Name" name="asset-name" required>
|
||||
<label for="asset-name-input">Asset Name</label>
|
||||
</div>
|
||||
<div class="form-floating mt-2">
|
||||
<select name="asset-type" class="form-control" required>
|
||||
<option value="8">Hat</option>
|
||||
<option value="17">Head</option>
|
||||
<option value="18">Face</option>
|
||||
<option value="19">Gear</option>
|
||||
<option value="41">Hair Accessory</option>
|
||||
<option value="42">Face Accessory</option>
|
||||
<option value="43">Neck Accessory</option>
|
||||
<option value="44">Shoulder Accessory</option>
|
||||
<option value="45">Front Accessory</option>
|
||||
<option value="46">Back Accessory</option>
|
||||
<option value="47">Waist Accessory</option>
|
||||
<option value="62">Video</option>
|
||||
</select>
|
||||
<label for="floatingNumber">Asset Type</label>
|
||||
</div>
|
||||
|
||||
<input type="file" name="file" id="file" class="form-control mt-2" required/>
|
||||
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-light mt-2 w-100 btn-sm" type="submit">Create Asset</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,67 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Create Giftcard</h1>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post">
|
||||
<div class="form-floating">
|
||||
<select id="floatingSelect" class="form-control" name="giftcard-type">
|
||||
<option value="0">Outrageous Builders Club</option>
|
||||
<option value="1">Turbo Builders Club</option>
|
||||
<option value="2">Robux</option>
|
||||
<option value="3">Tickets</option>
|
||||
<option value="4">Item</option>
|
||||
</select>
|
||||
<label for="floatingSelect">Giftcard Type</label>
|
||||
</div>
|
||||
<div class="form-floating mt-2">
|
||||
<input type="number" class="form-control" id="floatingNumber" placeholder="Value" name="copies" required>
|
||||
<label for="floatingNumber">Copies</label>
|
||||
</div>
|
||||
<div class="form-floating mt-2">
|
||||
<input type="text" class="form-control" id="floatingInput" placeholder="Value" name="value" required>
|
||||
<label for="floatingInput">Value</label>
|
||||
</div>
|
||||
<p class="m-0" style="font-size: 13px;">OBC GC Value = How many months</p>
|
||||
<p class="m-0" style="font-size: 13px;">TBC GC Value = How many weeks</p>
|
||||
<p class="m-0" style="font-size: 13px;">Robux and Tickets GC Value = How much currency</p>
|
||||
<p class="m-0" style="font-size: 13px;">Item GC Value = Asset ID</p>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-primary mt-2 w-100 btn-sm" type="submit">Create Giftcard</button>
|
||||
</form>
|
||||
{% if codes: %}
|
||||
<div class="linebreak"></div>
|
||||
<h2>Giftcard Codes</h2>
|
||||
<div class="border rounded p-2">
|
||||
{% for code in codes: %}
|
||||
<span class="m-0">{{code}}</span>
|
||||
<br>
|
||||
{%endfor%}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,43 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Create User</h1>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" id="floatingInput" placeholder="Username" name="username" required>
|
||||
<label for="floatingInput">Username</label>
|
||||
</div>
|
||||
<div class="form-floating mt-2">
|
||||
<input type="password" class="form-control" id="floatingPassword" placeholder="Password" name="password" required>
|
||||
<label for="floatingPassword">Password</label>
|
||||
</div>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-primary mt-2 w-100 btn-sm" type="submit">Create User</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,41 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(175, 175, 175) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a><a href="/admin/fflags/create" class="btn border-success btn-sm mb-2 ms-2">Create New Group</a>
|
||||
<h1>FFlags Groups</h1>
|
||||
<div class="linebreak"></div>
|
||||
<div class="row">
|
||||
{% for fflaggroup in groups %}
|
||||
<div class="col-12">
|
||||
<a href="/admin/fflags/{{fflaggroup.group_id}}">
|
||||
<div class="rounded border p-2 mb-2">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2 class="m-0">{{fflaggroup.name}}</h2>
|
||||
<p class="m-0 text-secondary">{{fflaggroup.description}}</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="text-secondary m-0">Created: <span class="text-white">{{fflaggroup.created_at}}</span></p>
|
||||
<p class="text-secondary m-0">Last Updated: <span class="text-white">{{fflaggroup.updated_at}}</span></p>
|
||||
<p class="text-secondary m-0">Enabled: <span class="text-white">{{ fflaggroup.enabled }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="linebreak"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,84 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(175, 175, 175) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="overflow-x:scroll;">
|
||||
<a href="/admin/fflags" class="btn border-primary btn-sm mb-2">Back to FFlag Groups</a><a href="/admin/fflags/{{group.id}}/delete" class="btn border-danger btn-sm mb-2 ms-2">Delete Group</a>
|
||||
<h1 class="m-0">{{group.name}}</h1>
|
||||
<p class="m-0 d-flex">{{group.description}}</p>
|
||||
<div class="p-2 border mt-2 mb-2 rounded">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<p class="text-secondary m-0">Created: <span class="text-white">{{group.created_at}}</span></p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="text-secondary m-0">Last Updated: <span class="text-white">{{group.updated_at}}</span></p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="text-secondary m-0">Enabled: <span class="text-white">{{ group.enabled }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="linebreak"></div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<h4 class="m-0">Import from file</h4>
|
||||
<p class="m-0">Note: This will remove all current flags and replace them with the file</p>
|
||||
<form method="post" action="/admin/fflags/{{group.group_id}}/import" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<input class="form-control" type="file" id="file" name="file" required>
|
||||
</div>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Import</button>
|
||||
</form>
|
||||
<div class="linebreak"></div>
|
||||
<h4>Flags ({{flagcount}})</h4>
|
||||
<form method="get" action="/admin/fflags/{{group.group_id}}">
|
||||
<div class="mb-3 d-flex">
|
||||
<input class="form-control rounded-end-0" type="text" id="search" name="search" placeholder="Search" value="{% if search %}{{search}}{%endif%}">
|
||||
<button type="submit" class="btn btn-primary btn-sm rounded-start-0">Search</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-striped-columns">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col-3">Name</th>
|
||||
<th scope="col-2">Type</th>
|
||||
<th scope="col-7">Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for fflag in FFlagsLookupResults %}
|
||||
<tr>
|
||||
<th scope="row">{{fflag.name}}</th>
|
||||
<td>{% if fflag.flag_type == 1: %}boolean{% endif %}{% if fflag.flag_type == 2: %}number{% endif %}{% if fflag.flag_type == 3: %}string{% endif %}</td>
|
||||
<td class="text-wrap w-100">{{ b64decode(fflag.flag_value).decode('utf-8') }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex w-100 mt-2" style="font-size: 14px;">
|
||||
<a class="text-decoration-none ms-auto {% if not FFlagsLookupResults.has_prev: %}text-secondary{%endif%}" {% if FFlagsLookupResults.has_prev: %}href="/admin/fflags/{{group.group_id}}?page={{FFlagsLookupResults.prev_num}}{% if search %}?search={{search}}{%endif%}"{%endif%}>Previous</a>
|
||||
<p class="m-0 ms-2 me-2 text-white">Page {{FFlagsLookupResults.page}} of {{FFlagsLookupResults.pages}}</p>
|
||||
<a class="text-decoration-none me-auto {% if not FFlagsLookupResults.has_next: %}text-secondary{%endif%}" {% if FFlagsLookupResults.has_next: %}href="/admin/fflags/{{group.group_id}}?page={{FFlagsLookupResults.next_num}}{% if search %}?search={{search}}{%endif%}"{%endif%}>Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,64 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(175, 175, 175) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin/gameservers" class="btn border-primary btn-sm mb-2">Back to Game Server Manager</a>
|
||||
<h1>Create Server</h1>
|
||||
<div class="linebreak"></div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post" action="/admin/gameservers/create">
|
||||
<div class="mb-2">
|
||||
<label for="serverNameInput" class="form-label m-0">Server name</label>
|
||||
<input type="text" class="form-control" id="serverNameInput" name="name" placeholder="Name" required>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label for="serverIPinput" class="form-label m-0">Server IP</label>
|
||||
<input type="text" class="form-control" id="serverIPinput" name="serverip" placeholder="1.1.1.1" required>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label for="serverPortInput" class="form-label m-0">Server Port</label>
|
||||
<input type="number" class="form-control" id="serverPortInput" name="serverport" placeholder="80" required>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label for="serverAccessKeyInput" class="form-label m-0">Access Key</label>
|
||||
<input type="password" class="form-control" id="serverAccessKeyInput" name="accesskey" placeholder="Access Key" required>
|
||||
</div>
|
||||
<div class="mb-2 row">
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isThumbnailer" type="checkbox" id="isThumbnailerCheckbox" checked>
|
||||
<label class="form-check-label" for="isThumbnailerCheckbox">
|
||||
<p>Allow Thumbnail Rendering</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isGameHoster" type="checkbox" id="isGameHosterCheckbox" checked>
|
||||
<label class="form-check-label" for="isGameHosterCheckbox">
|
||||
<p>Allow Game server hosting</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
<button type="submit" class="btn btn-primary btn-sm w-100 fw-bold">Create</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,24 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(175, 175, 175) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<h1>Are you sure?</h1>
|
||||
<p class="m-0 d-flex text-secondary">You are deleting {{gameserver.serverName}} ( {{gameserver.serverId}} )</p>
|
||||
<form method="post" class="mt-2">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="hidden" name="serverId" value="{{gameserver.serverId}}">
|
||||
<input type="submit" class="btn btn-danger" value="Delete">
|
||||
<a class="btn border-primary" href="/admin/gameservers/{{gameserver.serverId}}">Back</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,47 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(175, 175, 175) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a><a href="/admin/gameservers/create" class="btn border-success btn-sm mb-2 ms-2">Create server</a>
|
||||
<h1>Game Server Manager</h1>
|
||||
<p class="m-0 d-flex text-secondary">Please be careful when adding and editing gameservers!</p>
|
||||
<div class="linebreak"></div>
|
||||
<div class="row">
|
||||
{% for gameserver in gameservers %}
|
||||
<div class="col-12">
|
||||
<a href="/admin/gameservers/{{gameserver.serverId}}">
|
||||
<div class="gameserver-box rounded border p-2 mb-2 {% if not gameserver.isRCCOnline: %}redborder {% else %} {% if gameserver.heartbeatResponseTime > 0.6 %}yellowborder{% else %}greenborder{% endif %}{% endif %}">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<h2 class="m-0">{{gameserver.serverName}}</h2>
|
||||
<p class="m-0 text-secondary">{{gameserver.serverId}}</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="text-secondary m-0">Last heartbeat: <span class="text-white">{{gameserver.lastHeartbeat}}</span></p>
|
||||
<p class="text-secondary m-0">RCC Memory Usage: <span class="text-white">{{gameserver.RCCmemoryUsage}} MB</span></p>
|
||||
<p class="text-secondary m-0">Response Time: <span class="text-white">{{ round(gameserver.heartbeatResponseTime,3) }} secs</span></p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="text-secondary m-0">Thumbnail Queue Size: <span class="text-white">{{gameserver.thumbnailQueueSize}}</span></p>
|
||||
<p class="text-secondary m-0">isThumbnailer: <span class="text-white">{{gameserver.allowThumbnailGen}}</span></p>
|
||||
<p class="text-secondary m-0">isGameHoster: <span class="text-white">{{ gameserver.allowGameServerHost }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="linebreak"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,24 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(175, 175, 175) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<h1>Are you sure?</h1>
|
||||
<p class="m-0 d-flex text-secondary">Are you sure you want to refresh the AccessKey for {{gameserver.serverName}} ( {{gameserver.serverId}} )</p>
|
||||
<form method="post" class="mt-2">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="hidden" name="serverId" value="{{gameserver.serverId}}">
|
||||
<button type="submit" class="btn btn-light"><i class="bi bi-arrow-clockwise"></i> Refresh Key</button>
|
||||
<a class="btn border-primary" href="/admin/gameservers/{{gameserver.serverId}}">Back</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,84 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(175, 175, 175) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="/admin/gameservers" class="btn border-primary btn-sm mb-2">Back to Game Server Manager</a>
|
||||
<a href="/admin/gameservers/{{gameserver.serverId}}/delete" class="btn border-danger btn-sm mb-2 ms-2">Delete Server</a>
|
||||
<a href="/admin/gameservers/{{gameserver.serverId}}/refresh-accesskey" class="btn border-success btn-sm mb-2 ms-2">Refresh AccessKey</a>
|
||||
</div>
|
||||
<h1 class="m-0">{{gameserver.serverName}}</h1>
|
||||
<p class="m-0 d-flex">{{gameserver.serverId}}</p>
|
||||
<div class="p-2 border mt-2 mb-2 rounded {% if not gameserver.isRCCOnline: %}redborder {% else %} {% if gameserver.heartbeatResponseTime > 0.6 %}yellowborder{% else %}greenborder{% endif %}{% endif %}">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<p class="text-secondary m-0">Last heartbeat: <span class="text-white">{{gameserver.lastHeartbeat}}</span></p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<p class="text-secondary m-0">RCC Memory Usage: <span class="text-white">{{gameserver.RCCmemoryUsage}} MB</span></p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<p class="text-secondary m-0">Response Time: <span class="text-white">{{ round(gameserver.heartbeatResponseTime,3) }} secs</span></p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<p class="text-secondary m-0">Thumbnail Queue Size: <span class="text-white">{{gameserver.thumbnailQueueSize}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post" action="/admin/gameservers/{{gameserver.serverId}}/edit">
|
||||
<div class="mb-2">
|
||||
<label for="serverNameInput" class="form-label m-0">Server name</label>
|
||||
<input type="text" class="form-control" id="serverNameInput" name="name" placeholder="Name" value="{{gameserver.serverName}}" required>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label for="serverIPinput" class="form-label m-0">Server IP</label>
|
||||
<input type="text" class="form-control" id="serverIPinput" name="serverip" placeholder="1.1.1.1" value="{{gameserver.serverIP}}" required>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label for="serverPortInput" class="form-label m-0">Server Port</label>
|
||||
<input type="number" class="form-control" id="serverPortInput" name="serverport" placeholder="80" value="{{gameserver.serverPort}}" required>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label for="serverAccessKeyInput" class="form-label m-0">Access Key</label>
|
||||
<input type="password" class="form-control" id="serverAccessKeyInput" name="accesskey" placeholder="Access Key" value="{{gameserver.accessKey}}" required>
|
||||
</div>
|
||||
<div class="mb-2 row">
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isThumbnailer" type="checkbox" id="isThumbnailerCheckbox" {% if gameserver.allowThumbnailGen: %}checked{% endif %}>
|
||||
<label class="form-check-label" for="isThumbnailerCheckbox">
|
||||
<p>Allow Thumbnail Rendering</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isGameHoster" type="checkbox" id="isGameHosterCheckbox" {% if gameserver.allowGameServerHost: %}checked{% endif %}>
|
||||
<label class="form-check-label" for="isGameHosterCheckbox">
|
||||
<p>Allow Game server hosting</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
<button type="submit" class="btn btn-primary btn-sm w-100 fw-bold">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,48 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Kuromi was here :D-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<div class="d-md-flex align-items-center mb-1">
|
||||
<div class="d-flex align-items-center mb-2 mb-md-0">
|
||||
<img src="/Thumbs/Head.ashx?x=100&y=100&userId={{user.id}}" class="rounded-2" width="90px" height="90px">
|
||||
<div class="ms-2">
|
||||
<h3 class="m-0"><span id="random-greeting"></span>, {{user.username}}!</h3>
|
||||
<p class="m-0" style="font-size: 12px; color: rgb(200,200,200);">Server Time: {{stats.SystemTime}} UTC</b></p>
|
||||
<p class="m-0" style="font-size: 12px; color: rgb(200,200,200);">kuromi was here! :3</b></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center ms-auto p-2 me-2" style="background-color: rgb(27,27,27);box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);">
|
||||
<p class="col-6 col-md-3 m-0">Online: <b class="text-white">{{stats.UsersOnline}}</b></p>
|
||||
<p class="col-6 col-md-3 m-0">In-Game: <b class="text-white">{{stats.UsersPlaying}}</b></p>
|
||||
<p class="col-6 col-md-3 m-0">Active Servers: <b class="text-white">{{stats.PlaceServersCount}}</b></p>
|
||||
<p class="col-6 col-md-3 m-0">Users today: <b class="text-white">{{stats.UsersSignedUpToday}}</b></p>
|
||||
<p class="col-6 col-md-3 m-0">Assets Pending: <b class="text-white">{{stats.PendingAssets}}</b></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row p-2">
|
||||
{% for permission in permissions %}
|
||||
{% if "Hidden" not in permission: %}
|
||||
<div class="col-md-4 mb-1 p-1">
|
||||
<a href="{{permission.route}}">
|
||||
<div class="admin-box p-2">
|
||||
<h2 class="mb-1 text-truncate"><i class="bi {{permission.icon}} me-2"></i>{{permission.Name}}</h2>
|
||||
<p class="m-0 mb-2 text-truncate">{{permission.Description}}</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const greetings = ["Hello", "Bonjour", "Hola", "Ciao", "Hallo", "Olá", "Hej", "Salam", "Namaste", "Konnichiwa"];
|
||||
const randomGreeting = greetings[Math.floor(Math.random() * greetings.length)];
|
||||
document.getElementById("random-greeting").textContent = randomGreeting;
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,101 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin/manage-assets/{{asset.id}}" class="btn border-primary btn-sm mb-2">Back to Asset Manager</a>
|
||||
<h1 class="text-secondary">Insert <span class="text-white">{{asset.name}}</span> into Item Release Pool</h1>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% if asset %}
|
||||
<form method="post">
|
||||
<label for="assetnameinput" class="form-label m-0">Asset Name</label>
|
||||
<input type="text" name="assetname" id="assetnameinput" class="form-control" placeholder="Name" value="{{asset.name}}">
|
||||
<label for="assetdescriptioninput" class="form-label m-0">Asset Description</label>
|
||||
<textarea type="text" name="assetdescription" id="assetdescriptioninput" class="form-control" placeholder="Description">{{asset.description}}</textarea>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label for="assetpricerobuxinput" class="form-label m-0">Robux Price</label>
|
||||
<input type="number" name="assetpricerobux" id="assetpricerobuxinput" class="form-control" placeholder="Robux Price" value="{{asset.price_robux}}">
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="assetpricetixinput" class="form-label m-0">Tickets Price</label>
|
||||
<input type="number" name="assetpricetix" id="assetpricetixinput" class="form-control" placeholder="Tix Price" value="{{asset.price_tix}}">
|
||||
</div>
|
||||
</div>
|
||||
<p class="m-0 text-secondary" style="font-size: small;">note: if you want an item to be free both robux and tix prices have to be set to 0</p>
|
||||
<div class="linebreak"></div>
|
||||
<div class="mt-2">
|
||||
<h5 class="text-center">Offsale After</h5>
|
||||
<div class="row">
|
||||
<div class="col-2 ms-auto">
|
||||
<div class="form-floating">
|
||||
<input type="number" name="offsale-at-hours" id="offsale-at-hours" class="form-control" placeholder="Hours">
|
||||
<label for="offsale-at-hours" class="form-label m-0">Hours</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<div class="form-floating">
|
||||
<input type="number" name="offsale-at-minutes" id="offsale-at-minutes" class="form-control" placeholder="Minutes">
|
||||
<label for="offsale-at-minutes" class="form-label m-0">Minutes</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2 me-auto">
|
||||
<div class="form-floating">
|
||||
<input type="number" name="offsale-at-seconds" id="offsale-at-seconds" class="form-control" placeholder="Seconds">
|
||||
<label for="offsale-at-seconds" class="form-label m-0">Seconds</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-secondary m-0 text-center" style="font-size: 13px;">Amount of time item before the item goes offsale after it releases | Leave empty if you do not want an offsale time</p>
|
||||
</div>
|
||||
<div class="linebreak"></div>
|
||||
<label for="assetserialamount" class="form-label m-0">Serial Amount</label>
|
||||
<input type="number" name="assetserialamount" id="assetserialamount" class="form-control" placeholder="Serial Amount" value="{{asset.serial_count}}">
|
||||
<div class="row mt-3">
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isLimited" type="checkbox" id="isLimitedCheckbox" {% if asset.is_limited: %}checked{% endif %}>
|
||||
<label class="form-check-label" for="isLimitedCheckbox">
|
||||
<p>Limited</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isLimitedUnique" type="checkbox" id="isLimitedUniqueCheckbox" {% if asset.is_limited_unique: %}checked{% endif %}>
|
||||
<label class="form-check-label" for="isLimitedUniqueCheckbox">
|
||||
<p>Limited Unique</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<p clas="m-0 text-secondary">Created: <span class="text-white">{{asset.created_at}}</span></p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p clas="m-0 text-secondary">Updated: <span class="text-white">{{asset.updated_at}}</span></p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p clas="m-0 text-secondary">Original Roblox AssetId: <span class="text-white">{{asset.roblox_asset_id}}</span></p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p clas="m-0 text-secondary">AssetType: <span class="text-white">{{asset.asset_type.name}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-primary mt-1 w-100 btn-sm fw-bold" value="Insert Item">
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,59 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(200,200,200) !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Item Release Pool</h1>
|
||||
<p class="m-0 text-secondary" style="font-size:small;">Next Drop Time: <span class="text-white">{{NextItemDropDatetime}}</span></p>
|
||||
<div class="linebreak"></div>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div>
|
||||
{% for Item in PlannedItems: %}
|
||||
<div class="bg-dark mt-1 mb-1 p-2">
|
||||
<h5 class="m-0 mb-1 text-secondary">Name: <span class="text-white">{{Item.name}}</span></h5>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">Description: <span class="text-white">{{Item.description}}</span></p>
|
||||
<div class="linebreak"></div>
|
||||
<div class="d-flex">
|
||||
<p class="text-secondary m-0 ms-auto me-auto" style="font-size: 14px;">AssetId: <span class="text-white">{{Item.id}}</span></p>
|
||||
<p class="text-secondary m-0 ms-auto me-auto" style="font-size: 14px;">Robux Price: <span class="text-white">{{Item.robux_price}}</span></p>
|
||||
<p class="text-secondary m-0 ms-auto me-auto" style="font-size: 14px;">Tickets Price: <span class="text-white">{{Item.tickets_price}}</span></p>
|
||||
<p class="text-secondary m-0 ms-auto me-auto" style="font-size: 14px;">IsLimited: <span class="text-white">{{Item.is_limited}}</span></p>
|
||||
<p class="text-secondary m-0 ms-auto me-auto" style="font-size: 14px;">IsLimitedUnique: <span class="text-white">{{Item.is_limited_unique}}</span></p>
|
||||
<p class="text-secondary m-0 ms-auto me-auto" style="font-size: 14px;">Serial Count: <span class="text-white">{{Item.serial_count}}</span></p>
|
||||
<p class="text-secondary m-0 ms-auto me-auto" style="font-size: 14px;">Offsale After: <span class="text-white">{{Item.offsale_after}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor%}
|
||||
</div>
|
||||
{% if len(PlannedItems) == 0 %}
|
||||
<p class="m-5 text-secondary text-center">No planned items</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,64 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.bg-dark {
|
||||
background-color: rgb(30,30,30) !important;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75);
|
||||
}
|
||||
.badge {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Lottery</h1>
|
||||
<p class="m-0" style="font-size:small;">Give away limiteds under accounts which is deleted or inactive for more than 31 days. There must be at least 10 users online to give away any limiteds</p>
|
||||
<div class="linebreak"></div>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post">
|
||||
<button type="submit" class="btn btn-primary btn-sm mb-2 w-100">Give Away Selected User Limiteds</button>
|
||||
|
||||
<div style="display: flex;flex-wrap: wrap;gap: 2px;justify-content: flex-start;">
|
||||
{% for User in EligibleUsers: %}
|
||||
<div class="bg-dark p-2 d-flex mb-1 me-1" style="width: calc( 50% - 6px);">
|
||||
<img class="rounded-2 border overflow-hidden me-2" width="48" height="48" src="/Thumbs/Head.ashx?x=48&y=48&userId={{User.id}}">
|
||||
<div>
|
||||
<h5 class="m-0">{{User.username}} {% if User.accountstatus != 1: %}<span class="badge text-bg-danger me-1">Banned</span>{% endif %}{% if User.lastonline < InactiveTime %}<span class="badge text-bg-warning">Inactive</span>{% endif %}</h5>
|
||||
<p class="m-0">Total Limiteds: <span class="text-white">{{ GetTotalLimiteds(User) }}</span></p>
|
||||
</div>
|
||||
<input class="form-check-input h-100 ms-auto" style="aspect-ratio: 1/1;width: auto;" type="radio" value="{{User.id}}" id="user-checkbox-{{User.id}}" name="selected-user">
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
</form>
|
||||
{% if len(EligibleUsers) == 0: %}
|
||||
<p class="m-0 text-secondary mt-5 mb-5 text-center w-100">
|
||||
No eligible users found
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,142 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Asset Manager</h1>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post" class="d-flex" action="/admin/manage-assets">
|
||||
<input type="text" name="assetid" class="form-control" placeholder="AssetId" {% if asset: %}value="{{asset.id}}"{%endif%}>
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-primary ms-3" value="Search">
|
||||
</form>
|
||||
{% if asset %}
|
||||
<div class="linebreak"></div>
|
||||
<form method="post">
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="/catalog/{{asset.id}}/">< View asset on catalog</a>
|
||||
{% if IsItemEligibleForItemReleasePool and CanManageItemReleasePool: %}
|
||||
<a href="/admin/manage-assets/{{asset.id}}/insert-item-pool" class="ms-auto text-primary">Insert Item into Item Release Pool</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<label for="assetnameinput" class="form-label m-0">Asset Name</label>
|
||||
<input type="text" name="assetname" id="assetnameinput" class="form-control" placeholder="Name" value="{{asset.name}}">
|
||||
<label for="assetdescriptioninput" class="form-label m-0">Asset Description</label>
|
||||
<textarea type="text" name="assetdescription" id="assetdescriptioninput" class="form-control" placeholder="Description">{{asset.description}}</textarea>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label for="assetpricerobuxinput" class="form-label m-0">Robux Price</label>
|
||||
<input type="number" name="assetpricerobux" id="assetpricerobuxinput" class="form-control" placeholder="Robux Price" value="{{asset.price_robux}}">
|
||||
</div>
|
||||
<div class="col">
|
||||
<label for="assetpricetixinput" class="form-label m-0">Tickets Price</label>
|
||||
<input type="number" name="assetpricetix" id="assetpricetixinput" class="form-control" placeholder="Tix Price" value="{{asset.price_tix}}">
|
||||
</div>
|
||||
</div>
|
||||
<p class="m-0 text-secondary" style="font-size: small;">note: if you want an item to be free both robux and tix prices have to be set to 0</p>
|
||||
<div class="linebreak"></div>
|
||||
<div class="mt-2">
|
||||
<div class="row">
|
||||
<div class="col-6 ms-auto">
|
||||
<div class="form-floating">
|
||||
<input type="datetime-local" name="offsale-at" id="offsale-at" class="form-control" placeholder="Offsale At">
|
||||
<label for="offsale-at" class="form-label m-0">Offsale At</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2 me-auto">
|
||||
<div class="form-floating">
|
||||
<select name="offsale-timezone" class="form-control">
|
||||
<option value="0">UTC</option>
|
||||
<option value="1">UTC+1</option>
|
||||
<option value="2">UTC+2</option>
|
||||
<option value="3">UTC+3</option>
|
||||
<option value="4">UTC+4</option>
|
||||
<option value="5">UTC+5</option>
|
||||
<option value="6">UTC+6</option>
|
||||
<option value="7">UTC+7</option>
|
||||
<option value="8">UTC+8</option>
|
||||
<option value="9">UTC+9</option>
|
||||
<option value="10">UTC+10</option>
|
||||
<option value="11">UTC+11</option>
|
||||
<option value="12">UTC+12</option>
|
||||
<option value="-1">UTC-1</option>
|
||||
<option value="-2">UTC-2</option>
|
||||
<option value="-3">UTC-3</option>
|
||||
<option value="-4">UTC-4</option>
|
||||
<option value="-5">UTC-5</option>
|
||||
<option value="-6">UTC-6</option>
|
||||
<option value="-7">UTC-7</option>
|
||||
<option value="-8">UTC-8</option>
|
||||
<option value="-9">UTC-9</option>
|
||||
<option value="-10">UTC-10</option>
|
||||
<option value="-11">UTC-11</option>
|
||||
<option value="-12">UTC-12</option>
|
||||
</select>
|
||||
<label for="timezone">Timezone</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-secondary text-center" style="font-size: 13px;">(UTC) Current offsale time: <span class="text-white">{{asset.offsale_at}}</span> | Note: To remove a offsale date you need to set the item offsale manually</p>
|
||||
</div>
|
||||
<div class="linebreak"></div>
|
||||
<label for="assetserialamount" class="form-label m-0">Serial Amount</label>
|
||||
<input type="number" name="assetserialamount" id="assetserialamount" class="form-control" placeholder="Serial Amount" value="{{asset.serial_count}}">
|
||||
<div class="row mt-3">
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isForsale" type="checkbox" id="isForsaleCheckbox" {% if asset.is_for_sale: %}checked{% endif %}>
|
||||
<label class="form-check-label" for="isForsaleCheckbox">
|
||||
<p>For Sale</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isLimited" type="checkbox" id="isLimitedCheckbox" {% if asset.is_limited: %}checked{% endif %}>
|
||||
<label class="form-check-label" for="isLimitedCheckbox">
|
||||
<p>Limited</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input class="form-check-input" name="isLimitedUnique" type="checkbox" id="isLimitedUniqueCheckbox" {% if asset.is_limited_unique: %}checked{% endif %}>
|
||||
<label class="form-check-label" for="isLimitedUniqueCheckbox">
|
||||
<p>Limited Unique</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<p clas="m-0 text-secondary">Created: <span class="text-white">{{asset.created_at}}</span></p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p clas="m-0 text-secondary">Updated: <span class="text-white">{{asset.updated_at}}</span></p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p clas="m-0 text-secondary">Original Roblox AssetId: <a href="https://www.roblox.com/catalog/{{asset.roblox_asset_id}}/--" target="_blank">{{asset.roblox_asset_id}}</a></p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p clas="m-0 text-secondary">AssetType: <span class="text-white">{{asset.asset_type.name}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-primary mt-1 w-100 btn-sm fw-bold" value="Save">
|
||||
</form>
|
||||
<form action="/admin/manage-assets/{{asset.id}}/rerender" method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-success mt-4 w-100 btn-sm fw-bold" value="Rerender Asset">
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,112 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.text-secondary {
|
||||
color: rgb(200,200,200)!important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Asset Moderation</h1>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post" class="d-flex" action="/admin/moderate-asset">
|
||||
<input type="text" name="asset-id" class="form-control" placeholder="Asset ID" required {% if AssetObj %}value="{{AssetObj.id}}"{%endif%}>
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-primary ms-3" value="Search Asset">
|
||||
</form>
|
||||
{% if AssetObj %}
|
||||
<div class="linebreak"></div>
|
||||
<div class="mt-2 p-2">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<img src="/Thumbs/Asset.ashx?assetId={{AssetObj.id}}&x=512&y=512" width="100%" style="aspect-ratio: 1/1;" class="rounded border">
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center">
|
||||
<h3 class="m-0">{{AssetObj.name}}</h3>
|
||||
<a class="btn btn-light btn-sm ms-auto text-black" href="/catalog/{{AssetObj.id}}/">View Asset Page</a>
|
||||
</div>
|
||||
<div class="border p-2 mt-2 rounded">
|
||||
<h5>Description</h5>
|
||||
<p class="m-0 text-secondary mt-2">{{AssetObj.description}}</p>
|
||||
</div>
|
||||
<div class="mt-2 d-flex" style="flex-wrap: wrap;justify-content: flex-start;gap: 9px;">
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">AssetID: <span class="text-white">{{AssetObj.id}}</span></p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">Roblox AssetID: <span class="text-white">{{AssetObj.roblox_asset_id}}</span></p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">Creator: {% if AssetObj.creator_type == 0 %}<a class="text-decoration-none text-primary" href="/admin/manage-users/{{AssetObj.creator_id}}">{{CreatorObj.username}} ( {{CreatorObj.id}} )</a>{%endif%}</p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">CreatorType: <span class="text-white">{% if AssetObj.creator_type == 0 %}User{%else%}Group{%endif%}</span></p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">Created: <span class="text-white">{{AssetObj.created_at}}</span></p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">Last Updated: <span class="text-white">{{AssetObj.updated_at}}</span></p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">AssetType: <span class="text-white">{{AssetObj.asset_type.name}}</span></p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">Moderation Status: <span class="text-white">{% if AssetObj.moderation_status == 0: %}Allowed{%elif AssetObj.moderation_status == 2: %}Deleted{%else%}Pending{%endif%}</span></p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">IsForSale: <span class="text-white">{{AssetObj.is_for_sale}}</span></p>
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">SaleCount: <span class="text-white">{{AssetObj.sale_count}}</span></p>
|
||||
</div>
|
||||
<h4 class="m-0 mt-3">Quick Moderation Actions</h4>
|
||||
<div class="d-flex border rounded p-2 mt-2">
|
||||
{% if AssetObj.moderation_status != 0 %}
|
||||
<form action="/admin/moderate-asset/{{AssetObj.id}}/quick-approve" method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-success" value="Restore Asset to Approved status">
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if AssetObj.moderation_status != 1 %}
|
||||
<form action="/admin/moderate-asset/{{AssetObj.id}}/quick-pending" method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-warning ms-2" value="Set Asset to Pending status">
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if AssetObj.moderation_status != 2 %}
|
||||
<form action="/admin/moderate-asset/{{AssetObj.id}}/quick-delete" method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-danger ms-2" value="Content Delete Asset">
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h4 class="m-0 mt-3">Linked Assets</h4>
|
||||
<div class="border p-2 mt-2 rounded">
|
||||
{% for asset in RelatedAssets: %}
|
||||
<div class="bg-dark p-2 w-100 rounded mt-1 mb-1">
|
||||
<h5 class="m-0">{{asset.name}}</h5>
|
||||
<div class="d-flex align-items-center w-100" style="flex-wrap: wrap;justify-content: flex-start;gap: 9px;">
|
||||
<p class="text-secondary m-0" style="font-size: 14px;">AssetID: <span class="text-white">{{asset.id}}</span></p>
|
||||
<p class="text-secondary m-0 ms-2" style="font-size: 14px;">AssetType: <span class="text-white">{{asset.asset_type.name}}</span></p>
|
||||
<p class="text-secondary m-0 ms-2" style="font-size: 14px;">Creator: {% if asset.creator_type == 0 %}<a class="text-decoration-none text-primary" href="/admin/manage-users/{{asset.creator_id}}">{{asset.creator_id}}</a>{%endif%}</p>
|
||||
<p class="text-secondary m-0 ms-2" style="font-size: 14px;">CreatorType: <span class="text-white">{% if asset.creator_type == 0 %}User{%else%}Group{%endif%}</span></p>
|
||||
<a class="btn btn-primary ms-auto btn-sm" href="/admin/moderate-asset/{{asset.id}}">View Asset</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if len(RelatedAssets) == 0: %}
|
||||
<p class="text-secondary m-0 w-100 text-center mt-2 mb-2">No Linked Assets</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,129 @@
|
||||
PermissionsDefinition = {
|
||||
'GameServerManager' : {
|
||||
'Name' : 'Server Manager',
|
||||
'Description' : 'View gameserver information and manage them',
|
||||
'route': '/admin/gameservers',
|
||||
'icon': 'bi-database'
|
||||
},
|
||||
'UpdateWebsiteMessage' : {
|
||||
'Name' : 'Website Message',
|
||||
'Description' : 'Update website wide message',
|
||||
'route': '/admin/websitemessage',
|
||||
'icon': 'bi-chat-square-text'
|
||||
},
|
||||
'ManageFFlags' : {
|
||||
'Name' : 'Feature Flags',
|
||||
'Description' : 'Manage feature flags for RCC and Clients',
|
||||
'route': '/admin/fflags',
|
||||
'icon': 'bi-flag'
|
||||
},
|
||||
'CopyAssets' : {
|
||||
'Name' : 'Asset Copier',
|
||||
'Description' : 'Copy assets from the Roblox Catalog',
|
||||
'route': '/admin/asset-copier',
|
||||
'icon': 'bi-files'
|
||||
},
|
||||
'ManageAsset' : {
|
||||
'Name' : 'Manage Asset',
|
||||
'Description' : 'Manage assets under the ROBLOX account',
|
||||
'route': '/admin/manage-assets',
|
||||
'icon': 'bi-file-earmark'
|
||||
},
|
||||
'CreateAsset' : {
|
||||
'Name' : 'Create Asset',
|
||||
'Description' : 'Create assets under the ROBLOX account',
|
||||
'route': '/admin/create-asset',
|
||||
'icon': 'bi-file-earmark-plus'
|
||||
},
|
||||
'AssetModeration' : {
|
||||
'Name' : 'Pending Assets',
|
||||
'Description' : 'View and moderate pending assets',
|
||||
'route': '/admin/pending-assets',
|
||||
'icon': 'bi-hourglass-split'
|
||||
},
|
||||
'ManageUsers' : {
|
||||
'Name' : 'Manage Users',
|
||||
'Description' : 'Manage users and their permissions',
|
||||
'route': '/admin/manage-users',
|
||||
'icon': 'bi-people'
|
||||
},
|
||||
'ManageWebsiteFeatures' : {
|
||||
'Name' : 'Website Features',
|
||||
'Description' : 'Toggle certain features on the website',
|
||||
'route': '/admin/manage-website-features',
|
||||
'icon': 'bi-gear'
|
||||
},
|
||||
'CreateUser' : {
|
||||
'Name' : 'Create User',
|
||||
'Description' : 'Create a user on the website',
|
||||
'route': '/admin/create-user',
|
||||
'icon': 'bi-person-plus'
|
||||
},
|
||||
'CreateGiftcard' : {
|
||||
'Name' : 'Create Giftcard',
|
||||
'Description' : 'Create a giftcard on the website',
|
||||
'route': '/admin/create-giftcard',
|
||||
'icon': 'bi-gift'
|
||||
},
|
||||
'UpdateAssetFile' : {
|
||||
'Name' : 'Update RBXM',
|
||||
'Description' : 'Update the RBXM file of an asset',
|
||||
'route': '/admin/update-asset-file',
|
||||
'icon': 'bi-file-earmark-arrow-up'
|
||||
},
|
||||
'CopyBundle' : {
|
||||
'Name' : 'Copy Bundle',
|
||||
'Description' : 'Copy a bundle from the Roblox Catalog',
|
||||
'route': '/admin/copy-bundle',
|
||||
'icon': 'bi-collection'
|
||||
},
|
||||
'ModerateAsset' : {
|
||||
'Name' : 'Moderate Asset',
|
||||
'Description' : 'Change the status of a user generated asset',
|
||||
'route': '/admin/moderate-asset',
|
||||
'icon': 'bi-file-earmark-check'
|
||||
},
|
||||
'Lottery' : {
|
||||
'Name' : 'Lottery',
|
||||
'Description' : 'Give away limiteds under inactive accounts',
|
||||
'route': '/admin/lottery',
|
||||
'icon': 'bi-cash-stack'
|
||||
},
|
||||
'ManageItemReleases' : {
|
||||
'Name' : 'Item Release Pool',
|
||||
'Description' : 'Manage items in the item release pool',
|
||||
'route': '/admin/item-release-pool',
|
||||
'icon': 'bi-shuffle'
|
||||
},
|
||||
|
||||
'BanUser' : {
|
||||
'Name' : 'Ban User',
|
||||
'Description' : 'Ban a user from the website',
|
||||
'Hidden' : True
|
||||
},
|
||||
'ViewUserLoginHistory' : {
|
||||
'Name' : 'View User Login History',
|
||||
'Description' : 'View the login history of a user',
|
||||
'Hidden' : True
|
||||
},
|
||||
'ViewLoginHistoryDetailed' : {
|
||||
'Name' : 'View Sensitive Login History',
|
||||
'Description' : 'Extra permission to viewing sensitive info in login history like hashed IPs and Session Tokens',
|
||||
'Hidden' : True
|
||||
},
|
||||
'ModifyLimitedAssets' : {
|
||||
'Name' : 'Modify Limited Assets',
|
||||
'Description' : 'Modify limited assets',
|
||||
'Hidden' : True
|
||||
},
|
||||
'ViewItemReleasePoolDrop' : {
|
||||
'Name' : 'View Item Release Pool Drop Time',
|
||||
'Description' : 'Able to see the next item release drop',
|
||||
'Hidden' : True
|
||||
},
|
||||
"ManageAdminPermissions" : {
|
||||
'Name' : 'Manage Admin Permissions',
|
||||
'Description' : 'Manage admin permissions',
|
||||
'Hidden' : True
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Update RBXM</h1>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for category, message in messages %}
|
||||
{% if category == 'error': %}
|
||||
<div class="alert border p-2 text-center alert-danger border-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if category == 'success': %}
|
||||
<div class="alert border p-2 text-center alert-success border-success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="form-floating mt-2">
|
||||
<input type="number" class="form-control" id="floatingNumber" placeholder="Value" name="asset-id" required>
|
||||
<label for="floatingNumber">AssetId</label>
|
||||
</div>
|
||||
|
||||
<input type="file" name="file" id="file" class="form-control mt-2" required/>
|
||||
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-primary mt-2 w-100 btn-sm" type="submit">Update RBXM</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,86 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a class="mb-2" href="/admin/manage-users/{{userObj.id}}"> < Return to User Page</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div>
|
||||
<h1 class="m-0 text-secondary">Ban <span class="text-white">{{userObj.username}}</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
{% if LastestUserBanObj != None: %}
|
||||
<div class="alert alert-danger">
|
||||
This user currently has a ongoing ban, please revoke the previous ban before banning again.
|
||||
</div>
|
||||
{% endif %}
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="linebreak"></div>
|
||||
<form method="post">
|
||||
<div class="form-floating">
|
||||
<select name="ban_type" class="form-control" id="ban-type-select">
|
||||
<option value="0" selected>Warning</option>
|
||||
<option value="1">1 Day Ban</option>
|
||||
<option value="2">3 Day Ban</option>
|
||||
<option value="3">7 Day Ban</option>
|
||||
<option value="4">14 Day Ban</option>
|
||||
<option value="5">30 Day Ban</option>
|
||||
<option value="6">Account Deleted</option>
|
||||
</select>
|
||||
<label for="ban-type-select">Ban Type</label>
|
||||
</div>
|
||||
<div class="form-floating mt-2">
|
||||
<input type="text" class="form-control" name="ban_reason" id="ban-reason-input" placeholder="Reason" required>
|
||||
<label for="ban-reason-input">Reason</label>
|
||||
</div>
|
||||
<div class="form-floating mt-2">
|
||||
<input type="text" class="form-control" name="ban_notes" id="ban-notes-input" placeholder="Notes" required>
|
||||
<label for="ban-notes-input">Moderator Note ( Internal )</label>
|
||||
</div>
|
||||
<p class="m-0 text-secondary" style="font-size: 13px;">Please try to include links to evidence that lead to this ban</p>
|
||||
<div class="form-floating mt-2">
|
||||
<input type="password" class="form-control" name="totp_code" id="totp_code-input" placeholder="2FA Code" required>
|
||||
<label for="ban-notes-public-input">2FA Code</label>
|
||||
</div>
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<div class="linebreak"></div>
|
||||
{% if not LastestUserBanObj != None: %}
|
||||
<button type="submit" class="btn btn-danger mt-2 w-100 btn-sm">Ban User</button>
|
||||
{% else%}
|
||||
<button class="btn btn-danger mt-2 w-100 btn-sm" disabled>Ban User</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if LastestUserBanObj != None: %}
|
||||
<form method="post" action="/admin/manage-users/{{userObj.id}}/ban-user/revoke-ban?banid={{LastestUserBanObj.id}}">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<button class="btn btn-warning mt-2 w-100 btn-sm">Unban User</button>
|
||||
</form>
|
||||
{%endif%}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,69 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.bg-dark {
|
||||
background-color: rgb(32, 32, 32) !important;
|
||||
box-shadow: 0px 0px 5px 0px rgb(0,0,0);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a class="mb-2" href="/admin/manage-users/{{userObj.id}}"> < Return to User Page</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div>
|
||||
<h1 class="m-0 {% if userObj.accountstatus == 1 %}text-white{% elif userObj.accountstatus == 2 %}text-warning{% elif userObj.accountstatus == 3%}text-danger{% else %}text-decoration-line-through text-white{%endif%}">{{userObj.username}}<span class="text-secondary"> Ban History</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="p-1">
|
||||
{% for banRecord in BanHistory %}
|
||||
<div class="w-100 bg-dark p-2 mb-2 mt-2">
|
||||
<h4 class="m-0">{{banRecord.ban_type.name}}</h4>
|
||||
<p class="m-0 text-secondary" style="font-size: 14px;">Reason: <span class="text-white">{{banRecord.reason}}</span></p>
|
||||
<p class="m-0 text-secondary" style="font-size: 14px;">Moderator Note: <span class="text-white">{{banRecord.moderator_note}}</span></p>
|
||||
<p class="m-0 text-secondary" style="font-size: 12px;">Ban Author: <a href="/admin/manage-users/{{banRecord.author_userid}}">{{GetBanAuthorName(banRecord)}}</a></p>
|
||||
<div class="linebreak"></div>
|
||||
<div class="d-flex">
|
||||
<p class="m-0 text-secondary me-auto ms-auto" style="font-size: 14px;">Banned At: <span class="text-white">{{banRecord.created_at}}</span></p>
|
||||
<p class="m-0 text-secondary me-auto ms-auto" style="font-size: 14px;">Expires At: <span class="text-white">{{banRecord.expires_at}}</span></p>
|
||||
<p class="m-0 text-secondary me-auto ms-auto" style="font-size: 14px;">Acknowledged: <span class="text-white">{{banRecord.acknowledged}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if len(BanHistory.items) == 0 %}
|
||||
<p class="text-secondary m-5 text-center w-100">No previous bans</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="align-items-center d-flex justify-content-center mt-2 mb-2">
|
||||
<a class="ms-auto m-0 text-decoration-none {% if not BanHistory.has_prev %}text-secondary{%endif%}" {% if BanHistory.has_prev %}href="/admin/manage-users/{{userObj.id}}/ban-history?page={{BanHistory.prev_num}}"{%endif%}>Previous</a>
|
||||
<p class="ms-2 me-2 text-white m-0">Page {{BanHistory.page}} of {{BanHistory.pages}}</p>
|
||||
<a class="me-auto m-0 text-decoration-none {% if not BanHistory.has_next %}text-secondary{%endif%}" {% if BanHistory.has_next %}href="/admin/manage-users/{{userObj.id}}/ban-history?page={{BanHistory.next_num}}"{%endif%}>Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,65 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.bg-dark {
|
||||
background-color: rgb(32, 32, 32) !important;
|
||||
box-shadow: 0px 0px 5px 0px rgb(0,0,0);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 1200px;">
|
||||
<a class="mb-2" href="/admin/manage-users/{{userObj.id}}"> < Return to User Page</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div>
|
||||
<h1 class="m-0 {% if userObj.accountstatus == 1 %}text-white{% elif userObj.accountstatus == 2 %}text-warning{% elif userObj.accountstatus == 3%}text-danger{% else %}text-decoration-line-through text-white{%endif%}">{{userObj.username}}<span class="text-secondary"> Game Sessions</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-dark table-striped">
|
||||
<thead>
|
||||
<tr class="rounded-top">
|
||||
<th scope="col" style="width: 5%;">ID</th>
|
||||
<th scope="col" style="width: 27.5%;">JobId</th>
|
||||
<th scope="col" style="width: 22.5%;">Joined At</th>
|
||||
<th scope="col" style="width: 22.5%;">Left At</th>
|
||||
<th scope="col" style="width: 22.5%;">Place</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-group-divider" style="border-color: rgb(20,20,20);">
|
||||
{% for session in GameSessions: %}
|
||||
<tr>
|
||||
<th scope="row">{{session.id}}</th>
|
||||
<td>{{session.serveruuid}}</td>
|
||||
<td>{{session.joined_at}} UTC</td>
|
||||
<td>{{session.left_at}} UTC</td>
|
||||
<td><a class="text-primary" href="/games/{{session.place_id}}/--">{{get_place_name(session.place_id)}}</a> ({{session.place_id}})</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if len(GameSessions.items) == 0: %}
|
||||
<div class="text-center">
|
||||
<p class="text-secondary">No Game Session Logs Found</p>
|
||||
</div>
|
||||
{%endif%}
|
||||
<div class="align-items-center d-flex justify-content-center mt-2 mb-2">
|
||||
<a class="ms-auto m-0 text-decoration-none {% if not GameSessions.has_prev %}text-secondary{%endif%}" {% if GameSessions.has_prev %}href="/admin/manage-users/{{userObj.id}}/game-sessions?page={{GameSessions.prev_num}}"{%endif%}>Previous</a>
|
||||
<p class="ms-2 me-2 text-white m-0">Page {{GameSessions.page}} of {{GameSessions.pages}}</p>
|
||||
<a class="me-auto m-0 text-decoration-none {% if not GameSessions.has_next %}text-secondary{%endif%}" {% if GameSessions.has_next %}href="/admin/manage-users/{{userObj.id}}/game-sessions?page={{GameSessions.next_num}}"{%endif%}>Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,74 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.bg-dark {
|
||||
background-color: rgb(32, 32, 32) !important;
|
||||
box-shadow: 0px 0px 5px 0px rgb(0,0,0);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 1200px;">
|
||||
<a class="mb-2" href="/admin/manage-users/{{userObj.id}}"> < Return to User Page</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div>
|
||||
<h1 class="m-0 {% if userObj.accountstatus == 1 %}text-white{% elif userObj.accountstatus == 2 %}text-warning{% elif userObj.accountstatus == 3%}text-danger{% else %}text-decoration-line-through text-white{%endif%}">{{userObj.username}}<span class="text-secondary"> Invite Keys</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-dark table-striped">
|
||||
<thead>
|
||||
<tr class="rounded-top">
|
||||
<th scope="col" style="width: 5%;">ID</th>
|
||||
<th scope="col" style="width: 20%;">Key</th>
|
||||
<th scope="col" style="width: 15%;">Created</th>
|
||||
<th scope="col" style="width: 15%;">Used On</th>
|
||||
<th scope="col" style="width: 45%;">Used By</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-group-divider" style="border-color: rgb(20,20,20);">
|
||||
{% for invite in InviteKeys: %}
|
||||
<tr>
|
||||
<th scope="row">{{invite.id}}</th>
|
||||
<td>{{invite.key}}</td>
|
||||
<td>{{invite.created_at}} UTC</td>
|
||||
<td>{% if invite.used_on != None: %}{{invite.used_on}} UTC{%else%}Unused{%endif%}</td>
|
||||
<td>
|
||||
{% if invite.used_by != None: %}
|
||||
<a href="/admin/manage-users/{{invite.used_by}}" class="text-decoration-none text-truncate">
|
||||
<img class="rounded" style="aspect-ratio: 1/1;width: 35px;" src="/Thumbs/Head.ashx?x=48&y=48&userId={{invite.used_by}}">
|
||||
{{invite.user.username}}
|
||||
</a>
|
||||
{% else%}
|
||||
Unused
|
||||
{%endif%}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if len(InviteKeys.items) == 0: %}
|
||||
<div class="text-center">
|
||||
<p class="text-secondary">No Invite Keys found</p>
|
||||
</div>
|
||||
{%endif%}
|
||||
<div class="align-items-center d-flex justify-content-center mt-2 mb-2">
|
||||
<a class="ms-auto m-0 text-decoration-none {% if not InviteKeys.has_prev %}text-secondary{%endif%}" {% if InviteKeys.has_prev %}href="/admin/manage-users/{{userObj.id}}/invite-keys?page={{InviteKeys.prev_num}}"{%endif%}>Previous</a>
|
||||
<p class="ms-2 me-2 text-white m-0">Page {{InviteKeys.page}} of {{InviteKeys.pages}}</p>
|
||||
<a class="me-auto m-0 text-decoration-none {% if not InviteKeys.has_next %}text-secondary{%endif%}" {% if InviteKeys.has_next %}href="/admin/manage-users/{{userObj.id}}/invite-keys?page={{InviteKeys.next_num}}"{%endif%}>Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,105 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.bg-dark {
|
||||
background-color: rgb(32, 32, 32) !important;
|
||||
box-shadow: 0px 0px 5px 0px rgb(0,0,0);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a class="mb-2" href="/admin/manage-users/{{userObj.id}}"> < Return to User Page</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div>
|
||||
<h1 class="m-0 {% if userObj.accountstatus == 1 %}text-white{% elif userObj.accountstatus == 2 %}text-warning{% elif userObj.accountstatus == 3%}text-danger{% else %}text-decoration-line-through text-white{%endif%}">{{userObj.username}}<span class="text-secondary"> Login History</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
{% if len(AlternateAccounts) != 0 %}
|
||||
<div class="border-top border-bottom p-2 ">
|
||||
<h5 class="m-0 mb-1">Possible Alt Accounts ( {{len( AlternateAccounts )}} )</h5>
|
||||
{% for altAccount in AlternateAccounts %}
|
||||
<a class="d-flex align-items-center text-white text-decoration-none" href="/admin/manage-users/{{altAccount.id}}/login-history">
|
||||
<img height="50px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{altAccount.id}}&x=50&y=50">
|
||||
<div>
|
||||
<h5 class="m-0 {% if altAccount.accountstatus == 1 %}text-white{% elif altAccount.accountstatus == 2 %}text-warning{% elif altAccount.accountstatus == 3%}text-danger{% else %}text-decoration-line-through text-white{%endif%}">
|
||||
{{altAccount.username}}
|
||||
{% if altAccount.flags['hwidmatch'] %}
|
||||
<span class="badge rounded-pill text-bg-light ms-1" style="font-size: 12px;font-weight: 400;">HWID</span>
|
||||
{% endif %}
|
||||
{% if altAccount.flags['sessiontokenmatch'] %}
|
||||
<span class="badge rounded-pill text-bg-danger ms-1" style="font-size: 12px;font-weight: 400;">SessionToken</span>
|
||||
{% endif %}
|
||||
{% if altAccount.flags['ipmatch'] %}
|
||||
<span class="badge rounded-pill text-bg-warning ms-1" style="font-size: 12px;font-weight: 400;">IPAddress</span>
|
||||
{% endif %}
|
||||
{% if altAccount.flags['useragentmatch'] %}
|
||||
<span class="badge rounded-pill text-bg-primary ms-1" style="font-size: 12px;font-weight: 400;">UserAgent</span>
|
||||
{% endif %}
|
||||
</h5>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{altAccount.id}}</span></p>
|
||||
</div>
|
||||
</a>
|
||||
{%endfor%}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% if canViewSensitiveInfo %}
|
||||
<div class="p-1">
|
||||
{% for loginRecord in LoginHistory %}
|
||||
<div class="w-100 bg-dark p-2 mb-2 mt-2">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<h5 class="m-0">{{loginRecord.ip}}</h5>
|
||||
<p class="m-0 text-secondary" style="font-size: 13px;">Timestamp: <span class="text-white">{{loginRecord.timestamp}} UTC</span></p>
|
||||
</div>
|
||||
<a data-bs-toggle="collapse" href="#additional-record-data-{{loginRecord.id}}" role="button" class="ms-auto mt-auto mb-auto me-2" style="font-size: 20px;"><i class="bi bi-info-circle"></i></a>
|
||||
</div>
|
||||
<div class="collapse mt-1" id="additional-record-data-{{loginRecord.id}}">
|
||||
<div class="border p-1">
|
||||
<p class="m-0 text-secondary" style="font-size: 13px;">Login Record ID: <span class="text-white">{{loginRecord.id}}</span></p>
|
||||
<div class="border mt-1" style="font-size: 13px;padding: 4px;">
|
||||
<p class="m-0 text-secondary">User Agent</p>
|
||||
<p class="text-white m-0" style="word-break: break-all;white-space: normal;">{{loginRecord.useragent}}</p>
|
||||
</div>
|
||||
<div class="border mt-1" style="font-size: 13px;padding: 4px;">
|
||||
<p class="m-0 text-secondary">Session Token</p>
|
||||
<p class="text-white m-0" style="word-break: break-all;white-space: normal;">{{loginRecord.session_token}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="align-items-center d-flex justify-content-center mt-2 mb-2">
|
||||
<a class="ms-auto m-0 text-decoration-none {% if not LoginHistory.has_prev %}text-secondary{%endif%}" {% if LoginHistory.has_prev %}href="/admin/manage-users/{{userObj.id}}/login-history?page={{LoginHistory.prev_num}}"{%endif%}>Previous</a>
|
||||
<p class="ms-2 me-2 text-white m-0">Page {{LoginHistory.page}} of {{LoginHistory.pages}}</p>
|
||||
<a class="me-auto m-0 text-decoration-none {% if not LoginHistory.has_next %}text-secondary{%endif%}" {% if LoginHistory.has_next %}href="/admin/manage-users/{{userObj.id}}/login-history?page={{LoginHistory.next_num}}"{%endif%}>Next</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,208 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.bg-dark {
|
||||
background-color: rgb(32, 32, 32) !important;
|
||||
box-shadow: 0px 0px 5px 0px rgb(0,0,0);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main" data-csrf-token="{{ csrf_token() }}" data-userid="{{userObj.id}}">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a class="mb-2" href="/admin/manage-users/{{userObj.id}}"> < Return to User Page</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div>
|
||||
<h1 class="m-0 {% if userObj.accountstatus == 1 %}text-white{% elif userObj.accountstatus == 2 %}text-warning{% elif userObj.accountstatus == 3%}text-danger{% else %}text-decoration-line-through text-white{%endif%}">{{userObj.username}}<span class="text-secondary"> Admin Permissions</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border rounded p-2 mt-2 mb-2">
|
||||
<p class="mt-5 mb-5 w-100 text-center text-white" id="status-text" style="display: none;"></p>
|
||||
<div id="data-container">
|
||||
<div class="w-100 bg-dark p-2 mb-2 mt-2 admin-permission-template" style="display: none;">
|
||||
<div class="d-flex align-items-center w-100">
|
||||
<a data-bs-toggle="collapse" href="#admin-permission-info-PermissionName" role="button" class="mt-auto mb-auto me-2 permission-expand-info" style="font-size: 20px;"><i class="bi bi-info-circle"></i></a>
|
||||
<div class="d-flex align-items-center">
|
||||
<h5 class="m-0 permission-name-text">Admin Permission name</h5>
|
||||
<i class="bi ms-2 permission-icon" style="display: none;"></i>
|
||||
</div>
|
||||
<div class="form-check form-switch m-0 me-2 ms-auto">
|
||||
<input class="form-check-input" type="checkbox" role="switch">
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse mt-1 permission-info-container" id="admin-permission-info-PermissionName">
|
||||
<div class="border p-1">
|
||||
<p class="m-0 text-secondary" style="font-size: 13px;">Description: <span class="text-white permission-description-text">Permission Description</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="password" class="form-control mb-2" placeholder="2FA Code" id="2fa-code-input">
|
||||
<input type="submit" class="btn btn-primary w-100 mb-2" value="Save Changes" id="save-changes-button">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", async function () {
|
||||
const ActionCSRFToken = document.getElementById("main").getAttribute("data-csrf-token");
|
||||
const userId = document.getElementById("main").getAttribute("data-userid");
|
||||
const statusText = document.getElementById("status-text");
|
||||
const dataContainer = document.getElementById("data-container");
|
||||
const permissionTemplate = document.getElementsByClassName("admin-permission-template")[0];
|
||||
const saveChangesButton = document.getElementById("save-changes-button");
|
||||
const twoFactorCodeInput = document.getElementById("2fa-code-input");
|
||||
|
||||
var isPermissionsLoaded = false;
|
||||
|
||||
async function setStatusText( new_text ) {
|
||||
if ( new_text ) {
|
||||
statusText.innerText = new_text;
|
||||
statusText.style.display = "block";
|
||||
} else {
|
||||
statusText.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchUserPermissions() {
|
||||
const response = await fetch(`/admin/manage-users/${userId}/manage-admin-permissions/api/fetch-permissions`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-Token": ActionCSRFToken
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
|
||||
async function loadPermission( permission_data ) {
|
||||
const newPermission = permissionTemplate.cloneNode(true);
|
||||
newPermission.style.display = "block";
|
||||
newPermission.classList.remove("admin-permission-template");
|
||||
newPermission.classList.add("admin-permission-container");
|
||||
newPermission.setAttribute("data-permission-internal-name", permission_data.internal_name);
|
||||
|
||||
newPermission.getElementsByClassName("permission-name-text")[0].innerText = permission_data.friendly_name;
|
||||
newPermission.getElementsByClassName("permission-description-text")[0].innerText = permission_data.description;
|
||||
newPermission.getElementsByClassName("form-check-input")[0].checked = permission_data.hasPermission;
|
||||
newPermission.getElementsByClassName("permission-expand-info")[0].setAttribute("href", `#admin-permission-info-${permission_data.internal_name}`);
|
||||
newPermission.getElementsByClassName("permission-info-container")[0].setAttribute("id", `admin-permission-info-${permission_data.internal_name}`);
|
||||
|
||||
if ( permission_data.bi_icon ) {
|
||||
newPermission.getElementsByClassName("permission-icon")[0].style.display = "inline-block";
|
||||
newPermission.getElementsByClassName("permission-icon")[0].classList.add(permission_data.bi_icon);
|
||||
}
|
||||
|
||||
dataContainer.appendChild(newPermission);
|
||||
}
|
||||
|
||||
async function refreshData( new_data ) {
|
||||
dataContainer.innerHTML = "";
|
||||
|
||||
for ( const permission of new_data ) {
|
||||
await loadPermission( permission );
|
||||
}
|
||||
}
|
||||
|
||||
async function attemptFetchAndLoad() {
|
||||
dataContainer.innerHTML = "";
|
||||
isPermissionsLoaded = false;
|
||||
saveChangesButton.disabled = true;
|
||||
twoFactorCodeInput.disabled = true;
|
||||
setStatusText("Fetching Admin Permissions")
|
||||
|
||||
try{
|
||||
const permissionsData = await fetchUserPermissions();
|
||||
await refreshData( permissionsData );
|
||||
setStatusText();
|
||||
isPermissionsLoaded = true;
|
||||
twoFactorCodeInput.disabled = false;
|
||||
} catch (e) {
|
||||
setStatusText("Failed to fetch Admin Permissions");
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
twoFactorCodeInput.addEventListener("input", async function () {
|
||||
if ( !isPermissionsLoaded ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( twoFactorCodeInput.value.length != 6 ) {
|
||||
saveChangesButton.disabled = true;
|
||||
}
|
||||
|
||||
if ( twoFactorCodeInput.value.length == 6 ) {
|
||||
saveChangesButton.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
saveChangesButton.addEventListener("click", async function() {
|
||||
if ( !isPermissionsLoaded ) {
|
||||
return;
|
||||
}
|
||||
if ( twoFactorCodeInput.value.length != 6 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
isPermissionsLoaded = false;
|
||||
saveChangesButton.disabled = true;
|
||||
|
||||
const permissionsData = [];
|
||||
const permissionContainers = document.getElementsByClassName("admin-permission-container");
|
||||
for ( const permissionContainer of permissionContainers ) {
|
||||
if ( permissionContainer.getElementsByClassName("form-check-input")[0].checked ) {
|
||||
permissionsData.push(permissionContainer.getAttribute("data-permission-internal-name"));
|
||||
}
|
||||
}
|
||||
|
||||
setStatusText("Saving Admin Permissions");
|
||||
|
||||
try {
|
||||
const response = await fetch(`/admin/manage-users/${userId}/manage-admin-permissions/api/set-permissions`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-Token": ActionCSRFToken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"permissions": permissionsData,
|
||||
"2fa_code": twoFactorCodeInput.value
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
if ( data.success ) {
|
||||
alert("Successfully saved Admin Permissions");
|
||||
twoFactorCodeInput.value = "";
|
||||
await attemptFetchAndLoad();
|
||||
return;
|
||||
} else {
|
||||
alert(`Failed to save Admin Permissions, reason: ${data.reason}`);
|
||||
}
|
||||
} catch (e) {
|
||||
alert("Failed to save Admin Permissions");
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
isPermissionsLoaded = true;
|
||||
saveChangesButton.disabled = false;
|
||||
twoFactorCodeInput.value = "";
|
||||
twoFactorCodeInput.disabled = false;
|
||||
})
|
||||
|
||||
await attemptFetchAndLoad();
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,94 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Manage User{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/>
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a class="mb-2 d-block" href="/admin/manage-users/{{userObj.id}}">← Return to User Page</a>
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div class="ms-3">
|
||||
<h1 class="m-0 text-secondary">Manage Robux & Builders Club for <span class="text-white">{{userObj.username}}</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert border border-danger p-2 text-center messagealerts">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="linebreak"></div>
|
||||
|
||||
<div class="robux-management">
|
||||
<h3>Robux & Tix Management</h3>
|
||||
<form method="POST" id="robux-form">
|
||||
<div class="form-floating">
|
||||
<select class="form-control" id="action-select" required>
|
||||
<option value="add">Add</option>
|
||||
<option value="subtract">Subtract</option>
|
||||
</select>
|
||||
<label for="action-select">Action</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mt-2">
|
||||
<select class="form-control" name="currency_type" id="currency-type-select" required>
|
||||
<option value="robux">Robux</option>
|
||||
<option value="tix">Tix</option>
|
||||
</select>
|
||||
<label for="currency-type-select">Currency</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mt-2">
|
||||
<input type="number" class="form-control" name="amount" id="amount-input" placeholder="Amount" required>
|
||||
<label for="amount-input">Amount</label>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="linebreak"></div>
|
||||
<button type="submit" class="btn btn-primary mt-2 w-100 btn-sm">Submit Currency Change</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="linebreak"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
const actionSelect = document.getElementById("action-select");
|
||||
const amountInput = document.getElementById("amount-input");
|
||||
const robuxForm = document.getElementById("robux-form");
|
||||
|
||||
robuxForm.addEventListener("submit", function(event) {
|
||||
if (actionSelect.value === "subtract") {
|
||||
amountInput.value = -Math.abs(amountInput.value);
|
||||
} else {
|
||||
amountInput.value = Math.abs(amountInput.value);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,61 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.bg-dark {
|
||||
background-color: rgb(32, 32, 32) !important;
|
||||
box-shadow: 0px 0px 5px 0px rgb(0,0,0);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 800px;">
|
||||
<a class="mb-2" href="/admin/manage-users/{{userObj.id}}"> < Return to User Page</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div>
|
||||
<h1 class="m-0 {% if userObj.accountstatus == 1 %}text-white{% elif userObj.accountstatus == 2 %}text-warning{% elif userObj.accountstatus == 3%}text-danger{% else %}text-decoration-line-through text-white{%endif%}">{{userObj.username}}<span class="text-secondary"> Moderator Notes</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{% for note in UserModeratorNotes.items %}
|
||||
<div class="rounded border bg-dark p-2 mb-1">
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="40px" style="aspect-ratio: 1/1;" class="rounded-2 border" src="/Thumbs/Head.ashx?userId={{note.note_creator_id}}&x=50&y=50">
|
||||
<div class="ms-1">
|
||||
<h5 class="m-0 text-white">{{ GetUserName(note.note_creator_id) }}</h5>
|
||||
<p class="m-0" style="font-size: 12px;color: rgb(200,200,200);">Created at {{note.created_at}} UTC</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-1 border w-100 mt-1">
|
||||
{% for note_line in note.note.split("\n") %}
|
||||
<p class="m-0 text-white">{{note_line}}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if len(UserModeratorNotes.items) == 0 %}
|
||||
<div class="alert alert-danger">
|
||||
This user currently has no moderator notes.
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="align-items-center d-flex justify-content-center mt-2 mb-2">
|
||||
<a class="ms-auto m-0 text-decoration-none {% if not UserModeratorNotes.has_prev %}text-secondary{%endif%}" {% if UserModeratorNotes.has_prev %}href="/admin/manage-users/{{userObj.id}}/moderator-notes?page={{UserModeratorNotes.prev_num}}"{%endif%}>Previous</a>
|
||||
<p class="ms-2 me-2 text-white m-0">Page {{UserModeratorNotes.page}} of {{UserModeratorNotes.pages}}</p>
|
||||
<a class="me-auto m-0 text-decoration-none {% if not UserModeratorNotes.has_next %}text-secondary{%endif%}" {% if UserModeratorNotes.has_next %}href="/admin/manage-users/{{userObj.id}}/moderator-notes?page={{UserModeratorNotes.next_num}}"{%endif%}>Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,82 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="min-width: 1100px;">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>User Manager</h1>
|
||||
<form method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<div class="input-group mb-3">
|
||||
<div class="form-floating" style="width: 52%;">
|
||||
<input type="text" class="form-control" id="user-search-input" name="user-search-input" value="{%if query != None: %}{{query}}{%endif%}" placeholder="ROBLOX">
|
||||
<label for="user-search-input">Search</label>
|
||||
</div>
|
||||
<div class="form-floating" style="min-width: 130px;">
|
||||
<select class="form-select" id="user-search-type" name="user-search-type">
|
||||
<option value="userid">UserID</option>
|
||||
<option value="username" {%if searchType == "username"%}selected{%endif%}>Username</option>
|
||||
<option value="discordid" {%if searchType == "discordid"%}selected{%endif%}>Discord ID</option>
|
||||
</select>
|
||||
<label for="user-search-type">Search With</label>
|
||||
</div>
|
||||
<div class="form-floating" style="min-width: 160px;">
|
||||
<select class="form-select" id="user-order-by" name="user-order-by">
|
||||
<option value="userid">UserID</option>
|
||||
<option value="creation" {%if orderBy == "creation"%}selected{%endif%}>Creation Date</option>
|
||||
<option value="lastonline" {%if orderBy == "lastonline"%}selected{%endif%}>Last Online</option>
|
||||
<option value="robux" {%if orderBy == "robux"%}selected{%endif%}>Robux Balance</option>
|
||||
<option value="tix" {%if orderBy == "tix"%}selected{%endif%}>Tickets Balance</option>
|
||||
</select>
|
||||
<label for="user-order-by">Order By</label>
|
||||
</div>
|
||||
<div class="form-floating" style="min-width: 130px;">
|
||||
<select class="form-select" id="user-order-direction" name="user-order-direction">
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc" {%if orderType == "desc"%}selected{%endif%}>Descending</option>
|
||||
</select>
|
||||
<label for="user-order-direction">Order Direction</label>
|
||||
</div>
|
||||
<input type="submit" class="btn btn-outline-primary fw-bold" value="🔍">
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-dark table-striped">
|
||||
<thead>
|
||||
<tr class="rounded-top">
|
||||
<th scope="col">ID</th>
|
||||
<th scope="col">Username</th>
|
||||
<th scope="col">Created</th>
|
||||
<th scope="col">Last Online</th>
|
||||
<th scope="col">Robux</th>
|
||||
<th scope="col">Tickets</th>
|
||||
<th scope="col">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-group-divider" style="border-color: rgb(20,20,20);">
|
||||
{% for user in returnList: %}
|
||||
<tr>
|
||||
<td>{{user.id}}</td>
|
||||
<td><span class="{% if user.accountstatus == 2%}text-warning{% endif %}{% if user.accountstatus > 2 %}text-danger{%endif%}">{{user.username}}</span></td>
|
||||
<td>{{user.creation}}</td>
|
||||
<td>{{user.lastonline}}</td>
|
||||
<td>{{user.robux}}</td>
|
||||
<td>{{user.tix}}</td>
|
||||
<td><a href="/admin/manage-users/{{user.id}}" class="text-decoration-none btn btn-primary btn-sm w-100">View</a></td>
|
||||
</tr>
|
||||
{%endfor%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if len(returnList) == 0: %}
|
||||
<p class="text-white w-100 text-center">No results found</p>
|
||||
{%endif%}
|
||||
<div class="mt-3 d-flex">
|
||||
<a class="text-decoration-none ms-auto {%if page <= 1: %}disabled text-secondary{%else%}text-primary{%endif%}" {% if page > 1:%}href="/admin/manage-users?searchType={{searchType}}&orderBy={{orderBy}}&page={{page-1}}&orderType={{orderType}}{%if query != None: %}&query={{query}}{%endif%}"{%endif%}>Previous</a>
|
||||
<p class="ms-2 me-2 text-white">Page {{page}}</p>
|
||||
<a class="text-decoration-none me-auto {%if not isThereNextPage: %}disabled text-secondary{%else%}text-primary{%endif%}" {%if isThereNextPage: %}href="/admin/manage-users?searchType={{searchType}}&orderBy={{orderBy}}&page={{page+1}}&orderType={{orderType}}{%if query != None: %}&query={{query}}{%endif%}"{%endif%}>Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,116 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.bg-dark {
|
||||
background-color: rgb(32, 32, 32) !important;
|
||||
box-shadow: 0px 0px 5px 0px rgb(0,0,0);
|
||||
}
|
||||
.text-secondary {
|
||||
color: rgb(199, 199, 199) !important;
|
||||
}
|
||||
.text-tickets {
|
||||
color: rgb(224, 224, 60) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
.text-robux {
|
||||
color: rgb(26, 212, 103) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="max-width: 1000px;">
|
||||
<a class="mb-2" href="/admin/manage-users/{{userObj.id}}"> < Return to User Page</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<img height="100px" style="aspect-ratio: 1/1;" class="rounded-2" src="/Thumbs/Avatar.ashx?userId={{userObj.id}}&x=100&y=100">
|
||||
<div>
|
||||
<h1 class="m-0 {% if userObj.accountstatus == 1 %}text-white{% elif userObj.accountstatus == 2 %}text-warning{% elif userObj.accountstatus == 3%}text-danger{% else %}text-decoration-line-through text-white{%endif%}">{{userObj.username}}<span class="text-secondary"> Transactions</span></h1>
|
||||
<p class="text-secondary m-0" style="font-size: 12px;">UserId: <span class="text-white">{{userObj.id}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-floating mb-2">
|
||||
<select class="form-control" id="change-category-select">
|
||||
<option value="purchase" {%if PageCategory == "purchase"%}selected{%endif%}>Purchases</option>
|
||||
<option value="sale" {%if PageCategory == "sale"%}selected{%endif%}>Sales</option>
|
||||
<option value="group-payout" {%if PageCategory == "group-payout"%}selected{%endif%}>Group Payouts</option>
|
||||
<option value="stipends" {%if PageCategory == "stipends"%}selected{%endif%}>Stipends</option>
|
||||
</select>
|
||||
<label for="change-category-select">Category</label>
|
||||
</div>
|
||||
<table class="table table-dark table-striped">
|
||||
<thead>
|
||||
<tr class="rounded-top">
|
||||
<th scope="col" style="width: 15%;">Date</th>
|
||||
<th scope="col" style="width: 20%;">Source</th>
|
||||
<th scope="col" style="width: 45%;">Description</th>
|
||||
<th scope="col" style="width: 20%;">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-group-divider" style="border-color: rgb(20,20,20);">
|
||||
{% for Transaction in TransactionInfo: %}
|
||||
<tr>
|
||||
<td>{{Transaction.created_at}}</td>
|
||||
<td>
|
||||
{% if Transaction["source"]["type"] == 0: %}
|
||||
<a href="/users/{{Transaction['source']['id']}}/profile" class="text-decoration-none text-white text-truncate">
|
||||
<img class="rounded-5 overflow-hidden me-2" width="38" height="38" src="/Thumbs/Head.ashx?x=48&y=48&userId={{Transaction['source']['id']}}" alt="{{Transaction['source']['name']}}">
|
||||
{{Transaction["source"]["name"]}}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="/groups/{{Transaction['source']['id']}}/--" class="text-decoration-none text-white text-truncate">
|
||||
<img class="rounded-5 overflow-hidden me-2" width="38" height="38" src="/Thumbs/GroupIcon.ashx?x=48&y=48&groupid={{Transaction['source']['id']}}" alt="{{Transaction['source']['name']}}">
|
||||
{{Transaction["source"]["name"]}}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if Transaction['custom_text'] != None %}
|
||||
{{Transaction['custom_text']}}
|
||||
{% else %}
|
||||
{% if Transaction['asset'] != None: %}
|
||||
<a href="/catalog/{{Transaction['asset']['id']}}/--" class="text-decoration-none text-white">
|
||||
<img class="rounded-2 overflow-hidden me-2 border" width="38" height="38" src="/Thumbs/Asset.ashx?x=48&y=48&assetId={{Transaction['asset']['id']}}" alt="{{Transaction['asset']['name']}}">
|
||||
{{Transaction['asset']['name']}}
|
||||
</a>
|
||||
{% else %}
|
||||
Unknown
|
||||
{%endif%}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if Transaction['currency_type'] == 0 %}
|
||||
<span class="text-robux">R$ {{Transaction['currency_amount']}}</span>
|
||||
{% else %}
|
||||
<span class="text-tickets">T$ {{Transaction['currency_amount']}}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if len(TransactionInfo) == 0: %}
|
||||
<div class="text-center">
|
||||
<p class="text-secondary">No transactions found</p>
|
||||
</div>
|
||||
{%endif%}
|
||||
|
||||
<div class="align-items-center d-flex justify-content-center mt-2 mb-2">
|
||||
<a class="ms-auto m-0 text-decoration-none {% if not Pagination.has_prev %}text-secondary{%endif%}" {% if Pagination.has_prev %}href="/admin/manage-users/{{userObj.id}}/transactions?page={{Pagination.prev_num}}&category={{PageCategory}}"{%endif%}>Previous</a>
|
||||
<p class="ms-2 me-2 text-white m-0">Page {{Pagination.page}} of {{Pagination.pages}}</p>
|
||||
<a class="me-auto m-0 text-decoration-none {% if not Pagination.has_next %}text-secondary{%endif%}" {% if Pagination.has_next %}href="/admin/manage-users/{{userObj.id}}/transactions?page={{Pagination.next_num}}&category={{PageCategory}}"{%endif%}>Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>const s = document.getElementById("change-category-select");s.addEventListener("change", function() {var u = new URL(window.location.href);var sb = s.value;u.searchParams.set("category", sb);u.searchParams.set("page", 1);window.location.href = u;});</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,193 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.show-on-hover {
|
||||
filter: blur(4px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.show-on-hover:hover {
|
||||
filter: blur(0px);
|
||||
transition: 0.2s;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container" style="min-width: 1100px;">
|
||||
<div class="d-flex">
|
||||
<a href="/admin/manage-users" class="btn border-success btn-sm mb-2">Back to User Manager</a>
|
||||
<a href="/users/{{userObj.id}}/profile" class="btn border-primary btn-sm mb-2 ms-3">View user profile</a>
|
||||
</div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div>
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-danger p-2 text-center">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="border rounded-2">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0 border-bottom">
|
||||
<div class="d-flex align-items-center">
|
||||
<img width="30px" height="30px" class="rounded me-2" src="/Thumbs/Head.ashx?x=48&y=48&userId={{userObj.id}}" style="aspect-ratio: 1/1;">
|
||||
<h5 class="m-0">{{userObj.username}}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<img width="100%" class="p-2" src="/Thumbs/Avatar.ashx?x=420&y=420&userId={{userObj.id}}" style="aspect-ratio: 1/1;">
|
||||
{% if isAdministrator: %}
|
||||
<div class="border-top" style="background-color: rgba(24, 220, 255,0.5);font-size:12px;padding:3px;">
|
||||
<p class="m-0 fw-bold text-white text-center">Administrator</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if userObj.accountstatus == 2: %}
|
||||
<div class="border-top" style="background-color: rgba(255, 201, 24, 0.5);font-size:12px;padding:3px;">
|
||||
<p class="m-0 fw-bold text-white text-center">This account is temporarily banned</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if userObj.accountstatus == 3: %}
|
||||
<div class="border-top" style="background-color: rgba(255, 24, 24, 0.5);font-size:12px;padding:3px;">
|
||||
<p class="m-0 fw-bold text-white text-center">This account has been deleted</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if userObj.accountstatus == 4: %}
|
||||
<div class="border-top" style="background-color: rgba(255, 24, 243, 0.5);font-size:12px;padding:3px;">
|
||||
<p class="m-0 fw-bold text-white text-center">This account is GDPR deleted</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="bg-dark p-2 rounded-2 rounded-top-0 border-top text-secondary" style="font-size: 13px;">
|
||||
<span>Created: <span class="text-white">{{userObj.created}}</span></span>
|
||||
<br>
|
||||
<span>Last Online: <span class="text-white">{{userObj.lastonline}}</span></span>
|
||||
<br>
|
||||
<span>2FA Enabled: <span class="text-white">{{userObj.TOTPEnabled}}</span></span>
|
||||
<br>
|
||||
<span>Place Visits: <span class="text-white">{{TotalVisits}}</span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border rounded-2 mt-2">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0 border-bottom">
|
||||
<h5 class="m-0">Economy</h5>
|
||||
</div>
|
||||
<div class="text-secondary p-2 pt-1" style="font-size: 13px;">
|
||||
<span>Robux: <span class="text-success fw-bold">R${{UserEconomyObj.robux}}</span></span>
|
||||
<br>
|
||||
<span>Tickets: <span class="text-warning fw-bold">T${{UserEconomyObj.tix}}</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
{% if LastestUserBanObj != None: %}
|
||||
<div class="border rounded-2 mb-2">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0 border-bottom">
|
||||
<h5 class="m-0">Ban Information</h5>
|
||||
</div>
|
||||
<div class="p-2 text-secondary text-truncate" style="font-size: 14px;">
|
||||
<span>Ban Type: <span class="text-white">{{LastestUserBanObj.ban_type.name}}</span></span>
|
||||
<br>
|
||||
<span>Banned On: <span class="text-white">{{LastestUserBanObj.created_at}}</span></span>
|
||||
<br>
|
||||
<span>Expires On: <span class="text-white">{{LastestUserBanObj.expires_at}}</span></span>
|
||||
<br>
|
||||
<span>Reason: <span class="text-white">{{LastestUserBanObj.reason}}</span></span>
|
||||
<br>
|
||||
<span>Moderator Note: <span class="text-white" style="word-break: break-all;white-space: normal;">{{LastestUserBanObj.moderator_note}}</span></span>
|
||||
<br>
|
||||
<span>Banned By: <a class="text-decoration-underline text-primary" href="/admin/manage-users/{{LastestUserBanObj.author_userid}}">{{LastestUserBanObj.author_userid}}</a></span>
|
||||
</div>
|
||||
</div>
|
||||
{%endif%}
|
||||
<div class="border rounded-2" style="min-height: 150px;">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0 border-bottom">
|
||||
<h5 class="m-0">Description</h5>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
{% for line in DescriptionLines %}
|
||||
<p class="text-white m-0">{{line}}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% if LastLogin != None: %}
|
||||
<div class="border rounded-2 mt-2">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0 border-bottom">
|
||||
<h5 class="m-0">Latest Login</h5>
|
||||
</div>
|
||||
<div class="p-2 text-secondary text-truncate" style="font-size: 14px;">
|
||||
<span>User-Agent: <span class="text-white">{{LastLogin.useragent}}</span></span>
|
||||
<br>
|
||||
<span>Login Timestamp: <span class="text-white">{{LastLogin.timestamp}}</span></span>
|
||||
</div>
|
||||
</div>
|
||||
{%endif%}
|
||||
{% if LinkedDiscordObj != None: %}
|
||||
<div class="border rounded-2 mt-2">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0 border-bottom">
|
||||
<h5 class="m-0">Discord Account</h5>
|
||||
</div>
|
||||
<div class="p-2 text-secondary text-truncate" style="font-size: 14px;">
|
||||
<div class="row">
|
||||
<div class="col-10">
|
||||
<span>Discord ID: <span class="text-white">{{DiscordUserInfo.UserId}}</span></span>
|
||||
<br>
|
||||
<span>Username: <span class="text-white">{{DiscordUserInfo.Username}}</span></span>
|
||||
<br>
|
||||
<span>Discriminator: <span class="text-white">{{DiscordUserInfo.Discriminator}}</span></span>
|
||||
<br>
|
||||
<span>Linked On: <span class="text-white">{{LinkedDiscordObj.linked_on}}</span></span>
|
||||
<br>
|
||||
<span>Last Refresh: <span class="text-white">{{LinkedDiscordObj.last_updated}}</span></span>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<img width="100%" style="aspect-ratio: 1/1;" class="border rounded" src="{{DiscordUserInfo.GetAvatarURL()}}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{%endif%}
|
||||
{% if InviteKeyUsed != None: %}
|
||||
<div class="border rounded-2 mt-2">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0 border-bottom">
|
||||
<h5 class="m-0">Invite Key Info</h5>
|
||||
</div>
|
||||
<div class="p-2 text-secondary text-truncate" style="font-size: 14px;">
|
||||
<span>Invite Key: <span class="text-white show-on-hover">{{InviteKeyUsed.key}}</span></span>
|
||||
<br>
|
||||
<span>Creator: {% if InviteKeyUsed.created_by != None: %}<a class="text-decoration-none text-primary" href="/admin/manage-users/{{InviteKeyUsed.created_by}}">{{InviteKeyUsed.creator.username}}</a>{%else%}<span class="text-white">Unknown</span>{%endif%}</span>
|
||||
<br>
|
||||
<span>Created At: <span class="text-white">{{InviteKeyUsed.created_at}}</span></span>
|
||||
</div>
|
||||
</div>
|
||||
{%endif%}
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<div class="border rounded-2">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0">
|
||||
<h5 class="m-0">Actions</h5>
|
||||
</div>
|
||||
<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/ban-user"><i class="bi bi-hammer"></i> Ban User</a>
|
||||
{% if HasAdminPermission("ManageAdminPermissions") %}<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/manage-admin-permissions"><i class="bi bi-shield"></i> Manage Permissions</a>{%endif%}
|
||||
<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/manage-currency"><i class="bi bi-cash-stack"></i> Manage Robux & BC</a>
|
||||
|
||||
</div>
|
||||
<div class="border rounded-2 mt-2">
|
||||
<div class="bg-dark p-2 rounded-2 rounded-bottom-0">
|
||||
<h5 class="m-0">View</h5>
|
||||
</div>
|
||||
<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/moderator-notes"><i class="bi bi-journal-text"></i></i> Moderator Notes</a>
|
||||
<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/login-history"><i class="bi bi-clock-history"></i></i> Login History</a>
|
||||
<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/invite-keys"><i class="bi bi-key"></i></i> Invite Keys</a>
|
||||
<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/game-sessions"><i class="bi bi-controller"></i></i> Game Sessions</a>
|
||||
<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/transactions"><i class="bi bi-bank"></i></i> Transactions</a>
|
||||
<a class="btn border-top rounded-0 w-100 text-decoration-none" href="/admin/manage-users/{{userObj.id}}/ban-history"><i class="bi bi-exclamation-triangle"></i></i> Ban History</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,43 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
<style>
|
||||
.bg-dark {
|
||||
background-color: rgb(30,30,30) !important;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Website Features</h1>
|
||||
<p class="m-0" style="font-size:small;">Only turn off certain features when its an emergency!</p>
|
||||
<div class="row p-2">
|
||||
{% for feature in SitesFeaturesStatus: %}
|
||||
<div class="col-3 p-2">
|
||||
<div class="bg-dark ps-0 pe-0 rounded-top">
|
||||
<div class="{% if feature.enabled: %}bg-success{%else%}bg-danger{%endif%} w-100 rounded-top" style="min-height: 25px;"></div>
|
||||
<div class="p-2 w-100">
|
||||
<h3>{{feature.name}}</h3>
|
||||
{% if feature.enabled: %}
|
||||
<form action="/admin/manage-website-features/{{feature.name}}/disable" method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm w-100">Disable</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="/admin/manage-website-features/{{feature.name}}/enable" method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
<button type="submit" class="btn btn-outline-success btn-sm w-100">Enable</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,83 @@
|
||||
WebsiteFeaturesDefinition = [
|
||||
{
|
||||
"name": "WebSignup"
|
||||
},
|
||||
{
|
||||
"name": "WebLogin"
|
||||
},
|
||||
{
|
||||
"name": "UsernameChange"
|
||||
},
|
||||
{
|
||||
"name": "PasswordChange"
|
||||
},
|
||||
{
|
||||
"name": "DiscordLinking"
|
||||
},
|
||||
{
|
||||
"name": "GameJoinAPI"
|
||||
},
|
||||
{
|
||||
"name": "ThumbnailRendering"
|
||||
},
|
||||
{
|
||||
"name": "GroupJoining"
|
||||
},
|
||||
{
|
||||
"name": "GroupLeaving"
|
||||
},
|
||||
{
|
||||
"name": "GroupWallPosting"
|
||||
},
|
||||
{
|
||||
"name": "GroupCreation"
|
||||
},
|
||||
{
|
||||
"name": "AssetCreation"
|
||||
},
|
||||
{
|
||||
"name": "AssetEditing"
|
||||
},
|
||||
{
|
||||
"name": "AssetValidationService"
|
||||
},
|
||||
{
|
||||
"name": "EconomyPurchase"
|
||||
},
|
||||
{
|
||||
"name": "MessageSending"
|
||||
},
|
||||
{
|
||||
"name": "ItemReselling"
|
||||
},
|
||||
{
|
||||
"name": "ItemTrading"
|
||||
},
|
||||
{
|
||||
"name": "AvatarUpdate"
|
||||
},
|
||||
{
|
||||
"name": "ClothingMigrator"
|
||||
},
|
||||
{
|
||||
"name": "SendFriendRequest"
|
||||
},
|
||||
{
|
||||
"name": "FollowingUsers"
|
||||
},
|
||||
{
|
||||
"name": "GiftcardRedeem"
|
||||
},
|
||||
{
|
||||
"name": "EmailChange"
|
||||
},
|
||||
{
|
||||
"name": "SendResetPassword"
|
||||
},
|
||||
{
|
||||
"name": "AudioMigrator"
|
||||
},
|
||||
{
|
||||
"name": "CurrencyExchange"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
{% extends '__layout__.html' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block head %}
|
||||
<link href="/static/css/admin.css" rel="stylesheet"/> <!-- Its just easier to resuse this-->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<a href="/admin" class="btn border-primary btn-sm mb-2">Back to Admin Panel</a>
|
||||
<h1>Website wide message</h1>
|
||||
<p class="m-0">plz do not put anything useless on here thxxx</p>
|
||||
<div class="linebreak"></div>
|
||||
<form method="post">
|
||||
<input type="text" name="message" class="form-control" value="{{message}}" placeholder="Message">
|
||||
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
||||
<input type="submit" class="btn btn-primary mt-2" value="Save">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user