bug fixes, CSS update, admin dashboard functions, extended UI, update README.md
This commit is contained in:
parent
40cb71715b
commit
ff34dc024a
7 changed files with 322 additions and 48 deletions
15
README.md
15
README.md
|
|
@ -7,6 +7,14 @@ imageboard written in python(flask)
|
||||||
wirechan is an anonymous(optional registration) imageboard written in Flask framework using MongoDB as a database. It's designed to be used
|
wirechan is an anonymous(optional registration) imageboard written in Flask framework using MongoDB as a database. It's designed to be used
|
||||||
as a way of communication for various topics without the fear of being recogniszed, if the user wishes to remain unknown.
|
as a way of communication for various topics without the fear of being recogniszed, if the user wishes to remain unknown.
|
||||||
|
|
||||||
|
# features
|
||||||
|
|
||||||
|
>Both logged-in and anonymous posting
|
||||||
|
>Admin dashboard for moderation
|
||||||
|
>No Javascript whatsoever
|
||||||
|
>Minimal dependencies
|
||||||
|
>Minimalistic design
|
||||||
|
|
||||||
# installation
|
# installation
|
||||||
|
|
||||||
1. Clone the repository:
|
1. Clone the repository:
|
||||||
|
|
@ -26,5 +34,10 @@ python3 -m pip install -r requirements.txt
|
||||||
|
|
||||||
4. Initialize the MongoDB server:
|
4. Initialize the MongoDB server:
|
||||||
```
|
```
|
||||||
mongo
|
mongo #or systemctl enable mongod && systemctl start mongod
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Start the server
|
||||||
|
```
|
||||||
|
python3 app.py
|
||||||
```
|
```
|
||||||
54
app.py
54
app.py
|
|
@ -12,6 +12,7 @@ client = MongoClient('localhost', 27017)
|
||||||
db = client.flask_db
|
db = client.flask_db
|
||||||
posts_collection = db.posts_collection
|
posts_collection = db.posts_collection
|
||||||
users_collection = db.users_collection
|
users_collection = db.users_collection
|
||||||
|
nuke_counter = db.nuke_counter
|
||||||
|
|
||||||
#app routes
|
#app routes
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
|
|
@ -34,13 +35,21 @@ def board(board_name):
|
||||||
|
|
||||||
posts = posts_collection.find({'board_name': board_name}).sort('timestamp', -1)
|
posts = posts_collection.find({'board_name': board_name}).sort('timestamp', -1)
|
||||||
display_name = next((link['display_name'] for link in links if link['name'] == board_name), board_name)
|
display_name = next((link['display_name'] for link in links if link['name'] == board_name), board_name)
|
||||||
return render_template('board.html', title=board_name, header=display_name, links=links, posts=posts)
|
admin_user = users_collection.find_one({'username': 'admin'})
|
||||||
|
if admin_user and session.get('user_id') == str(admin_user['_id']):
|
||||||
|
return render_template('board.html', title=board_name, header=display_name, links=links, posts=posts, admin=True)
|
||||||
|
else:
|
||||||
|
admin=False
|
||||||
|
return render_template('board.html', title=board_name, header=display_name, links=links, posts=posts, admin=admin)
|
||||||
|
|
||||||
@app.route('/post', methods=['POST'])
|
@app.route('/post', methods=['POST'])
|
||||||
def post():
|
def post():
|
||||||
board_name = request.form['board_name']
|
board_name = request.form['board_name']
|
||||||
content = request.form['content']
|
content = request.form['content']
|
||||||
image = request.files['image']
|
if 'image' in request.files:
|
||||||
|
image = request.files['image']
|
||||||
|
else:
|
||||||
|
image = None
|
||||||
timestamp = datetime.now()
|
timestamp = datetime.now()
|
||||||
if 'user_id' not in session:
|
if 'user_id' not in session:
|
||||||
username = 'Anonymous'
|
username = 'Anonymous'
|
||||||
|
|
@ -55,7 +64,7 @@ def post():
|
||||||
'username' : username
|
'username' : username
|
||||||
}
|
}
|
||||||
|
|
||||||
if image:
|
if image != None:
|
||||||
post_data['image'] = image.read()
|
post_data['image'] = image.read()
|
||||||
|
|
||||||
posts_collection.insert_one(post_data)
|
posts_collection.insert_one(post_data)
|
||||||
|
|
@ -118,9 +127,15 @@ def register_post():
|
||||||
@app.route('/admin', methods=['GET'])
|
@app.route('/admin', methods=['GET'])
|
||||||
def admin():
|
def admin():
|
||||||
admin_user = users_collection.find_one({'username': 'admin'})
|
admin_user = users_collection.find_one({'username': 'admin'})
|
||||||
success = request.args.get('success', '')
|
users = users_collection.find({})
|
||||||
|
success1 = request.args.get('success1', '')
|
||||||
|
success2 = request.args.get('success2', '')
|
||||||
|
success3 = request.args.get('success3', '')
|
||||||
|
total_users = users_collection.count_documents({})
|
||||||
|
total_posts = posts_collection.count_documents({})
|
||||||
|
nuke_count = nuke_counter.count_documents({})
|
||||||
if admin_user or session['user_id'] != str(admin_user['_id']):
|
if admin_user or session['user_id'] != str(admin_user['_id']):
|
||||||
return render_template('admin.html', success=success)
|
return render_template('admin.html', success1=success1, success2=success2, success3=success3, total_users=total_users, total_posts=total_posts, nuke_count=nuke_count, users=users)
|
||||||
else:
|
else:
|
||||||
return url_for('index')
|
return url_for('index')
|
||||||
|
|
||||||
|
|
@ -133,13 +148,38 @@ def deletepost():
|
||||||
post_id = request.form['post_id']
|
post_id = request.form['post_id']
|
||||||
posts_collection.delete_one({'_id': ObjectId(post_id)})
|
posts_collection.delete_one({'_id': ObjectId(post_id)})
|
||||||
success = 'post deleted!'
|
success = 'post deleted!'
|
||||||
return redirect(url_for('admin', success=success))
|
return redirect(url_for('admin', success1=success))
|
||||||
|
|
||||||
|
@app.route('/deleteuser', methods=['POST'])
|
||||||
|
def deleteuser():
|
||||||
|
admin_user = users_collection.find_one({'username': 'admin'})
|
||||||
|
if not admin_user or session['user_id'] != str(admin_user['_id']):
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
else:
|
||||||
|
user_id = request.form['user_id']
|
||||||
|
users_collection.delete_one({'_id': ObjectId(user_id)})
|
||||||
|
success = 'user deleted!'
|
||||||
|
return redirect(url_for('admin', success2=success))
|
||||||
|
|
||||||
|
@app.route('/nukeboard', methods=['POST'])
|
||||||
|
def nukeboard():
|
||||||
|
admin_user = users_collection.find_one({'username': 'admin'})
|
||||||
|
if not admin_user or session['user_id'] != str(admin_user['_id']):
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
else:
|
||||||
|
board_name = request.form['board_name']
|
||||||
|
posts_collection.delete_many({'board_name': board_name})
|
||||||
|
success = 'board nuked!'
|
||||||
|
nuke_counter.insert_one({'board_name': board_name}, {'date': datetime.now()})
|
||||||
|
return redirect(url_for('admin', success3=success))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/logout')
|
@app.route('/logout')
|
||||||
def logout():
|
def logout():
|
||||||
session.pop('user_id', None)
|
session.pop('user_id', None)
|
||||||
|
session.pop('username', None)
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=True)
|
app.run(debug=True, host='100.64.0.18', port=5000)
|
||||||
172
static/css/styles.css
Normal file → Executable file
172
static/css/styles.css
Normal file → Executable file
|
|
@ -7,11 +7,13 @@ body {
|
||||||
.link-container {
|
.link-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom {
|
.bottom {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 2vw;
|
bottom: 2vw;
|
||||||
|
margin: 2vw;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,6 +32,12 @@ a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 1vw;
|
||||||
|
color: #00FF00;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
color: #00FF00;
|
color: #00FF00;
|
||||||
|
|
@ -75,26 +83,166 @@ h4 {
|
||||||
color: #00FF00;
|
color: #00FF00;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
.post_form {
|
||||||
width: 20vw;
|
display: grid;
|
||||||
|
grid-template-columns: min-content;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
text-align: center;
|
||||||
|
align-self: center;
|
||||||
height: auto;
|
height: auto;
|
||||||
margin: 2vw;
|
width: 20vw auto;
|
||||||
|
max-width: fit-content;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: rgb(42, 42, 42);
|
||||||
|
border: 1px solid #00FF00;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_input {
|
||||||
|
grid-column: 1 / span 1;
|
||||||
|
grid-row: 1 / span 1;
|
||||||
|
text-align: center;
|
||||||
|
height: 10vw auto;
|
||||||
|
width: 20vw;
|
||||||
|
max-width: fit-content;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_file_input {
|
||||||
|
grid-column: 1 / span 1;
|
||||||
|
grid-row: 2 / span 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.5vw;
|
||||||
|
height: auto;
|
||||||
|
width: 20vw auto;
|
||||||
|
max-width: fit-content;
|
||||||
|
border: none;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_submit {
|
||||||
|
grid-column: 1 / span 1;
|
||||||
|
grid-row: 2 / span 1;
|
||||||
|
text-align: center;
|
||||||
|
height: auto;
|
||||||
|
width: 20vw;
|
||||||
|
max-width: fit-content;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0.5vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post {
|
.post {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: row;
|
grid-template-columns: auto auto;
|
||||||
justify-content: flex-start;
|
grid-template-rows: auto auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
height: 50% auto;
|
height: auto;
|
||||||
width: 50% auto;
|
width: auto;
|
||||||
|
max-width: fit-content;
|
||||||
|
overflow: auto;
|
||||||
background-color: rgb(42, 42, 42);
|
background-color: rgb(42, 42, 42);
|
||||||
border: 1px solid #00FF00;
|
border: 1px solid #00FF00;
|
||||||
padding: 10px;
|
padding: 0.5vw;
|
||||||
margin: 2vw;
|
margin: 0.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_header {
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
grid-row: 1 / span 1;
|
||||||
|
text-align: left;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
max-width: fit-content;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_content {
|
||||||
|
grid-row: 2 / span 1;
|
||||||
|
text-align: left;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
max-width: fit-content;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
grid-row: 2 / span 1;
|
||||||
|
grid-column: 1 / span 1;
|
||||||
|
width: 10vw;
|
||||||
|
height: auto;
|
||||||
|
margin: 1vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
img:hover {
|
||||||
|
width: 20vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post:hover {
|
.post:hover {
|
||||||
background-color: #00FF00;
|
background-color: rgb(42, 42, 42);
|
||||||
color: black;
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgb(42, 42, 42);
|
||||||
|
color: #00FF00;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin_actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
background-color: black;
|
||||||
|
color: #00FF00;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin_action {
|
||||||
|
background-color: black;
|
||||||
|
color: #00FF00;
|
||||||
|
border: 1px solid #00FF00;
|
||||||
|
max-width: fit-content;
|
||||||
|
height: 20vw;
|
||||||
|
padding: 1vw;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
grid-gap: 1vw;
|
||||||
|
text-align: left;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
max-width: fit-content;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.5vw;
|
||||||
|
margin: 0.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_list a {
|
||||||
|
font-size: 2vw;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats {
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
@ -7,14 +7,60 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
<h2>admin panel</h2>
|
<div class="navbar">
|
||||||
<div>
|
{% if session.username != Anonymous %}
|
||||||
<h4>delete post</h4>
|
<a>logged in as: <span style="color: yellow;">{{ session.username }}</span></a>
|
||||||
<h4 style="color: yellow;">{{ success }}</h4>
|
{% endif %}
|
||||||
<form action="{{ url_for('deletepost') }}" method="post">
|
<a href="{{ url_for('index') }}">home</a>
|
||||||
<input type="text" name="post_id" placeholder="post id">
|
<a href="{{ url_for('login') }}">login</a>
|
||||||
<button type="submit">delete</button>
|
<a href="{{ url_for('logout') }}">logout</a>
|
||||||
</form>
|
<a href="{{ url_for('board', board_name='b') }}">/b/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='g') }}">/g/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='a') }}">/a/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='v') }}">/v/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='w') }}">/w/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='x') }}">/x/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='t') }}">/t/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='s') }}">/s/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='pol') }}">/pol/</a>
|
||||||
|
</div>
|
||||||
|
<h1>admin panel</h1>
|
||||||
|
<div class="stats">
|
||||||
|
<h4>stats</h4>
|
||||||
|
<p>total posts: <span style="color: yellow;">{{ total_posts }}</span></p>
|
||||||
|
<p>total users: <span style="color: yellow;">{{ total_users }}</span></p>
|
||||||
|
<p>nuke count: <span style="color: yellow;">{{ nuke_count }}</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="admin_actions">
|
||||||
|
<div class="admin_action">
|
||||||
|
<h4>delete post</h4>
|
||||||
|
<h4 style="color: yellow;">{{ success1 }}</h4>
|
||||||
|
<form action="{{ url_for('deletepost') }}" method="post">
|
||||||
|
<input type="text" name="post_id" placeholder="post id">
|
||||||
|
<button type="submit">delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="admin_action">
|
||||||
|
<h4>delete user</h4>
|
||||||
|
<h4 style="color: yellow;">{{ success2 }}</h4>
|
||||||
|
{% for user in users %}
|
||||||
|
{% if user.username != 'admin' %}
|
||||||
|
<form action="{{ url_for('deleteuser') }}" method="post" class="user_list">
|
||||||
|
<a>{{ user.username }}</a>
|
||||||
|
<input type="hidden" name="user_id" value="{{ user._id }}">
|
||||||
|
<button type="submit">delete</button>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="admin_action">
|
||||||
|
<h4>nuke board</h4>
|
||||||
|
<h4 style="color: yellow;">{{ success3 }}</h4>
|
||||||
|
<form action="{{ url_for('nukeboard') }}" method="post">
|
||||||
|
<input type="text" name="board_name" placeholder="board">
|
||||||
|
<button type="submit">nuke</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -8,28 +8,44 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="navbar">
|
<div class="navbar">
|
||||||
<a>logged in as {{ session.username }}</a>
|
{% if session.username != Anonymous %}
|
||||||
|
<a>logged in as: <span style="color: yellow;">{{ session.username }}</span></a>
|
||||||
|
{% endif %}
|
||||||
<a href="{{ url_for('index') }}">home</a>
|
<a href="{{ url_for('index') }}">home</a>
|
||||||
|
<a href="{{ url_for('login') }}">login</a>
|
||||||
<a href="{{ url_for('logout') }}">logout</a>
|
<a href="{{ url_for('logout') }}">logout</a>
|
||||||
|
{% if admin %}
|
||||||
<a href="{{ url_for('admin') }}">admin</a>
|
<a href="{{ url_for('admin') }}">admin</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ url_for('board', board_name='b') }}">/b/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='g') }}">/g/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='a') }}">/a/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='v') }}">/v/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='w') }}">/w/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='x') }}">/x/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='t') }}">/t/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='s') }}">/s/</a>
|
||||||
|
<a href="{{ url_for('board', board_name='pol') }}">/pol/</a>
|
||||||
</div>
|
</div>
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="link-container">
|
<div class="link-container">
|
||||||
<h2>{{ header }}</h2>
|
<h1>{{ header }}</h1>
|
||||||
<form action="{{ url_for('post') }}" method="post" enctype="multipart/form-data">
|
<div class="post_form">
|
||||||
<input type="hidden" name="board_name" value="{{ title }}">
|
<form action="{{ url_for('post') }}" method="post" enctype="multipart/form-data">
|
||||||
<textarea name="content" rows="4" cols="50" placeholder="Write your post here..."></textarea>
|
<textarea class="post_input" name="content" rows="4" cols="50" placeholder="write your post here..." required></textarea>
|
||||||
<input type="file" name="image">
|
<input class="post_file_input" name="image" type="file">
|
||||||
<button type="submit">Post</button>
|
<button class="post_submit" type="submit">post!</button>
|
||||||
</form>
|
<input type="hidden" name="board_name" value="{{ title }}">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
<div class="posts">
|
<div class="posts">
|
||||||
{% for post in posts %}
|
{% for post in posts %}
|
||||||
<div class="post">
|
<div class="post">
|
||||||
|
<p class="post_header">{{ post.username }} {{ post.timestamp }} <span style="color: violet;">{{ post._id }}</span></p>
|
||||||
{% if post.image %}
|
{% if post.image %}
|
||||||
<img src="{{ url_for('image', post_id=post._id) }}" alt="Post Image">
|
<img src="{{ url_for('image', post_id=post._id) }}" alt="Post Image">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>{{ post.content }}</p>
|
<p class="post_content">{{ post.content }}</p>
|
||||||
<small>{{ post.username }} {{ post.timestamp }} {{ post._id }}</small>
|
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,17 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="link-container">
|
<div class="link-container">
|
||||||
<h4>registration is optional</h4>
|
<h4>registration is optional</h4>
|
||||||
|
{% if session.username == Anonymous %}
|
||||||
<a href="{{ url_for('login') }}">login</a>
|
<a href="{{ url_for('login') }}">login</a>
|
||||||
<a href="{{ url_for('register') }}">register</a>
|
<a href="{{ url_for('register') }}">register</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if session.username != Anonymous %}
|
||||||
|
<a>hello, {{ session.username }}</a>
|
||||||
|
<a href="{{ url_for('logout') }}">logout</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if session.username == 'admin' %}
|
||||||
|
<a href="{{ url_for('admin') }}">admin</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<a>lainlounge.xyz - copyleft all wrongs released</a>
|
<a>lainlounge.xyz - copyleft all wrongs released</a>
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,17 @@
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>login</h1>
|
<div class="link-container">
|
||||||
<form action="{{ url_for('login_post') }}" method="post">
|
<h1>login</h1>
|
||||||
<label for="username">username:</label>
|
<form action="{{ url_for('login_post') }}" method="post">
|
||||||
<input type="text" id="username" name="username" required>
|
<label for="username">username:</label>
|
||||||
<br>
|
<input type="text" id="username" name="username" required>
|
||||||
<label for="password">password:</label>
|
<br>
|
||||||
<input type="password" id="password" name="password" required>
|
<label for="password">password:</label>
|
||||||
<br>
|
<input type="password" id="password" name="password" required>
|
||||||
<button type="submit">login</button>
|
<br>
|
||||||
</form>
|
<button type="submit">login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Add table
Reference in a new issue