part 1
This commit is contained in:
parent
a927e542c4
commit
f93c384c2c
39
template/admin_dashboard.html
Normal file
39
template/admin_dashboard.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Admin Dashboard{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Admin Dashboard</h1>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
Admin Toolbox
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Database Management</h5>
|
||||||
|
<form action="{{ url_for('reset_db') }}" method="POST" class="mb-3" onsubmit="return confirm('Are you sure you want to reset the database? This action cannot be undone.');">
|
||||||
|
<button type="submit" class="btn btn-danger">fucking nuke the db</button>
|
||||||
|
</form>
|
||||||
|
<a href="{{ url_for('backup_db') }}" class="btn btn-primary mb-3">bekáp the db</a>
|
||||||
|
|
||||||
|
<h5 class="card-title">File Management</h5>
|
||||||
|
<form action="{{ url_for('clear_uploads') }}" method="POST" class="mb-3" onsubmit="return confirm('Are you sure you want to clear all uploaded files? This action cannot be undone.');">
|
||||||
|
<button type="submit" class="btn btn-warning">Clear Upload Folder</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>All Posts</h2>
|
||||||
|
{% for post in posts %}
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">{{ post.author.username if post.author else 'Anonymous' }}</h5>
|
||||||
|
<p class="card-text">{{ post.content }}</p>
|
||||||
|
<p class="card-text"><small class="text-muted">{{ post.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}</small></p>
|
||||||
|
<form action="{{ url_for('delete_post', post_id=post.id) }}" method="POST" onsubmit="return confirm('Are you sure you want to delete this post?');">
|
||||||
|
<button type="submit" class="btn btn-danger btn-sm">Delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
14
template/admin_login.html
Normal file
14
template/admin_login.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Admin Login{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Admin Login</h1>
|
||||||
|
<form method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Password</label>
|
||||||
|
<input type="password" class="form-control" id="password" name="password" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Login</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
155
template/base.html
Normal file
155
template/base.html
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" data-bs-theme="dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>TechTalks - {% block title %}{% endblock %}</title>
|
||||||
|
{% block head %}
|
||||||
|
{% if metadata %}
|
||||||
|
{% for key, value in metadata.items() %}
|
||||||
|
<meta property="og:{{ key }}" content="{{ value }}">
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
padding-bottom: 70px;
|
||||||
|
}
|
||||||
|
.navbar-nav {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
.navbar-nav .nav-item {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.navbar-nav .nav-link {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.navbar-nav .nav-link i {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
body {
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
.navbar {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
.navbar-nav .nav-link {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.navbar-nav .nav-link i {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.navbar-nav .nav-link span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
padding-bottom: 60px;
|
||||||
|
}
|
||||||
|
.card-footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% block styles %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-4">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="navbar fixed-bottom navbar-expand navbar-dark bg-primary">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('home') }}">
|
||||||
|
<i class="bi bi-house-door-fill"></i>
|
||||||
|
<span>Home</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('post') }}">
|
||||||
|
<i class="bi bi-plus-circle-fill"></i>
|
||||||
|
<span>Post</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('profile', username=current_user.username) }}">
|
||||||
|
<i class="bi bi-person-fill"></i>
|
||||||
|
<span>Profile</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('logout') }}">
|
||||||
|
<i class="bi bi-box-arrow-right"></i>
|
||||||
|
<span>Logout</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('login') }}">
|
||||||
|
<i class="bi bi-box-arrow-in-right"></i>
|
||||||
|
<span>Login</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('register') }}">
|
||||||
|
<i class="bi bi-person-plus-fill"></i>
|
||||||
|
<span>Register</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#" data-bs-toggle="modal" data-bs-target="#infoModal">
|
||||||
|
<i class="bi bi-info-circle-fill"></i>
|
||||||
|
<span>Info</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('groups') }}">
|
||||||
|
<i class="bi bi-people-fill"></i>
|
||||||
|
<span>Groups</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Info Modal -->
|
||||||
|
<div class="modal fade" id="infoModal" tabindex="-1" aria-labelledby="infoModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="infoModalLabel">About TechTalks</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>This is basically Twitter but for techtokers built by spitkov (<a href="https://spitkov.hu" target="_blank">https://spitkov.hu</a>) for anyone who will dig into on how this app works its completely garbage code it has a bunch of flaws and its really unoptimized but it works on my machine :D so have fun using it. Also this project will be avaiable on my git soon i'll post it here and other news will be shown here too</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
{% block scripts %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
13
template/comment.html
Normal file
13
template/comment.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<li id="comment-{{ comment.id }}">
|
||||||
|
<strong>
|
||||||
|
{% if comment.author %}
|
||||||
|
<a href="{{ url_for('profile', username=comment.author.username) }}">{{ comment.author.username }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-white">Anonymous</span>
|
||||||
|
{% endif %}
|
||||||
|
</strong>:
|
||||||
|
{{ comment.content }}
|
||||||
|
<button class="btn btn-sm btn-outline-primary like-comment-btn" data-comment-id="{{ comment.id }}">
|
||||||
|
<i class="bi bi-heart-fill"></i> (<span class="comment-like-count">{{ comment.likes|length }}</span>)
|
||||||
|
</button>
|
||||||
|
</li>
|
94
template/create_group.html
Normal file
94
template/create_group.html
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Create Group{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="mb-4">Create a New Group</h1>
|
||||||
|
<form method="POST" enctype="multipart/form-data" id="createGroupForm">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">Group Name</label>
|
||||||
|
<input type="text" class="form-control" id="name" name="name" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="description" class="form-label">Description</label>
|
||||||
|
<textarea class="form-control" id="description" name="description" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="vanity_url" class="form-label">Vanity URL</label>
|
||||||
|
<input type="text" class="form-control" id="vanity_url" name="vanity_url" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="visibility" class="form-label">Visibility</label>
|
||||||
|
<select class="form-select" id="visibility" name="visibility" required>
|
||||||
|
<option value="public">Public</option>
|
||||||
|
<option value="registered_only">Registered Only</option>
|
||||||
|
<option value="invite_only">Invite Only</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 form-check" id="allow_requests_div" style="display: none;">
|
||||||
|
<input type="checkbox" class="form-check-input" id="allow_requests" name="allow_requests">
|
||||||
|
<label class="form-check-label" for="allow_requests">Allow Join Requests</label>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="image" class="form-label">Group Image</label>
|
||||||
|
<input type="file" class="form-control" id="image" name="image" accept="image/*">
|
||||||
|
</div>
|
||||||
|
<div id="cropperContainer" style="display: none;">
|
||||||
|
<img id="cropperImage" src="" alt="Group Image">
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="croppedData" name="cropped_data">
|
||||||
|
<button type="submit" class="btn btn-primary">Create Group</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
{{ super() }}
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.css">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{{ super() }}
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const imageInput = document.getElementById('image');
|
||||||
|
const cropperContainer = document.getElementById('cropperContainer');
|
||||||
|
const cropperImage = document.getElementById('cropperImage');
|
||||||
|
const croppedDataInput = document.getElementById('croppedData');
|
||||||
|
let cropper;
|
||||||
|
|
||||||
|
imageInput.addEventListener('change', function(e) {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = function(event) {
|
||||||
|
cropperImage.src = event.target.result;
|
||||||
|
cropperContainer.style.display = 'block';
|
||||||
|
|
||||||
|
if (cropper) {
|
||||||
|
cropper.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
cropper = new Cropper(cropperImage, {
|
||||||
|
aspectRatio: 1,
|
||||||
|
viewMode: 1,
|
||||||
|
minCropBoxWidth: 200,
|
||||||
|
minCropBoxHeight: 200,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('createGroupForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (cropper) {
|
||||||
|
croppedDataInput.value = cropper.getCroppedCanvas().toDataURL();
|
||||||
|
}
|
||||||
|
this.submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user