main
parent
15f824e2b7
commit
eb7729c4d4
2
TODO
2
TODO
|
@ -1,7 +1,7 @@
|
||||||
[x] Attēlot lapu ar pamatinformāciju par izvēlēto spēli. [5]
|
[x] Attēlot lapu ar pamatinformāciju par izvēlēto spēli. [5]
|
||||||
[x] Izveidotajā projektā jābūt direktorijam, kurā ir teksta faili ar spēļu atjauninājumu vēsturi (to varat izdomāt). Vienā no lapām ir jāparāda virsraksti, kas atbilst failu nosaukumiem, un saites uz attiecīgajiem rakstiem (teksta faila saturs). Katram rakstam ir jāatrodas savā lapā ar unikālu URL. Gan rakstu URL adreses, gan rakstu saraksts ir jāģenerē automātiski atbilstoši iepriekš minētā direktorija saturam. [30]
|
[x] Izveidotajā projektā jābūt direktorijam, kurā ir teksta faili ar spēļu atjauninājumu vēsturi (to varat izdomāt). Vienā no lapām ir jāparāda virsraksti, kas atbilst failu nosaukumiem, un saites uz attiecīgajiem rakstiem (teksta faila saturs). Katram rakstam ir jāatrodas savā lapā ar unikālu URL. Gan rakstu URL adreses, gan rakstu saraksts ir jāģenerē automātiski atbilstoši iepriekš minētā direktorija saturam. [30]
|
||||||
[ ] Jāpievieno iespēja lietotājam lejupielādēt .pdf failu, kurā aprakstītas problēmas, ar kurām viņi saskārās jūsu spēlē. Lejupielādētais fails ir jāsaglabā īpaši norādītā direktorijā. [15]
|
[ ] Jāpievieno iespēja lietotājam lejupielādēt .pdf failu, kurā aprakstītas problēmas, ar kurām viņi saskārās jūsu spēlē. Lejupielādētais fails ir jāsaglabā īpaši norādītā direktorijā. [15]
|
||||||
[ ] Jāizveido lapa, no kuras varat lejupielādēt jaunāko spēles versiju. [15]
|
[x] Jāizveido lapa, no kuras varat lejupielādēt jaunāko spēles versiju. [15]
|
||||||
[ ] Piešķirot vērtējumu, tiks ņemts vērā arī tīmekļa aplikācijas vizuālais noformējums. Bootstrap bibliotēkas izmantošana ne tikai vienkāršos procesu, bet arī sniegs priekšrocības, ja tā tiks pareizi integrēta lietojumprogrammā. [20]
|
[ ] Piešķirot vērtējumu, tiks ņemts vērā arī tīmekļa aplikācijas vizuālais noformējums. Bootstrap bibliotēkas izmantošana ne tikai vienkāršos procesu, bet arī sniegs priekšrocības, ja tā tiks pareizi integrēta lietojumprogrammā. [20]
|
||||||
[ ] Ir nepieciešams izveidot prezentāciju, demonstrēt visu paveikto darbu un demonstrēt izveidoto aplikāciju. [15]
|
[ ] Ir nepieciešams izveidot prezentāciju, demonstrēt visu paveikto darbu un demonstrēt izveidoto aplikāciju. [15]
|
||||||
[ ] Visas pievienotās papildu funkcijas, kas uzlabo lietojumprogrammas lietošanas pieredzi un palielina tās tehnisko sarežģītību, var iegūt papildu punktus atkarībā no ieviešanas sarežģītības. [?]
|
[ ] Visas pievienotās papildu funkcijas, kas uzlabo lietojumprogrammas lietošanas pieredzi un palielina tās tehnisko sarežģītību, var iegūt papildu punktus atkarībā no ieviešanas sarežģītības. [?]
|
Binary file not shown.
190
main.py
190
main.py
|
@ -1,4 +1,4 @@
|
||||||
from flask import Flask, render_template, redirect, request, session, url_for
|
from flask import Flask, render_template, redirect, request, session, url_for, g
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_admin import Admin, AdminIndexView, expose, BaseView
|
from flask_admin import Admin, AdminIndexView, expose, BaseView
|
||||||
from flask_admin.contrib.sqla import ModelView
|
from flask_admin.contrib.sqla import ModelView
|
||||||
|
@ -23,6 +23,30 @@ class Post(db.Model):
|
||||||
alias = db.Column(db.String(100), unique=True, nullable=False)
|
alias = db.Column(db.String(100), unique=True, nullable=False)
|
||||||
title = db.Column(db.String(100), nullable=False)
|
title = db.Column(db.String(100), nullable=False)
|
||||||
image = db.Column(db.String(100), nullable=False)
|
image = db.Column(db.String(100), nullable=False)
|
||||||
|
|
||||||
|
class ForumCategory(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
category_name = db.Column(db.String(100), nullable=False)
|
||||||
|
description = db.Column(db.String(200))
|
||||||
|
|
||||||
|
class ForumPost(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
category_id = db.Column(db.Integer, db.ForeignKey('forum_category.id'), nullable=False)
|
||||||
|
post_name = db.Column(db.String(100), nullable=False)
|
||||||
|
created_by = db.Column(db.String(100), nullable=False)
|
||||||
|
creation_date = db.Column(db.DateTime, nullable=False)
|
||||||
|
media = db.Column(db.String(100))
|
||||||
|
text = db.Column(db.Text, nullable=False)
|
||||||
|
edited = db.Column(db.Boolean, default=False)
|
||||||
|
|
||||||
|
class ForumComment(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
post_id = db.Column(db.Integer, db.ForeignKey('forum_post.id'), nullable=False)
|
||||||
|
created_by = db.Column(db.String(100), nullable=False)
|
||||||
|
creation_date = db.Column(db.DateTime, nullable=False)
|
||||||
|
media = db.Column(db.String(100))
|
||||||
|
text = db.Column(db.Text, nullable=False)
|
||||||
|
edited = db.Column(db.Boolean, default=False)
|
||||||
|
|
||||||
def admin_login_required(view_func):
|
def admin_login_required(view_func):
|
||||||
@wraps(view_func)
|
@wraps(view_func)
|
||||||
|
@ -41,12 +65,10 @@ class MyAdminIndexView(AdminIndexView):
|
||||||
class UserAdminView(ModelView):
|
class UserAdminView(ModelView):
|
||||||
column_exclude_list = ['password']
|
column_exclude_list = ['password']
|
||||||
form_excluded_columns = ['password']
|
form_excluded_columns = ['password']
|
||||||
|
can_export = True
|
||||||
|
export_types = ['csv']
|
||||||
|
|
||||||
class PostAdminView(ModelView):
|
class PostAdminView(ModelView):
|
||||||
can_edit = True
|
|
||||||
can_delete = True
|
|
||||||
create_modal = True
|
|
||||||
edit_modal = True
|
|
||||||
can_export = True
|
can_export = True
|
||||||
export_types = ['csv']
|
export_types = ['csv']
|
||||||
|
|
||||||
|
@ -70,6 +92,13 @@ def check_admin_login():
|
||||||
ADMIN_USERNAME = 'user'
|
ADMIN_USERNAME = 'user'
|
||||||
ADMIN_PASSWORD = '1234321'
|
ADMIN_PASSWORD = '1234321'
|
||||||
|
|
||||||
|
@app.before_request
|
||||||
|
def before_request():
|
||||||
|
g.user = None
|
||||||
|
if 'username' in session:
|
||||||
|
user = User.query.filter_by(username=session['username']).first()
|
||||||
|
g.user = user
|
||||||
|
|
||||||
@app.route("/admin/login", methods=["GET", "POST"])
|
@app.route("/admin/login", methods=["GET", "POST"])
|
||||||
def admin_login():
|
def admin_login():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -87,44 +116,6 @@ def admin_logout():
|
||||||
session.pop("admin_logged_in", None)
|
session.pop("admin_logged_in", None)
|
||||||
return redirect(url_for("admin_login"))
|
return redirect(url_for("admin_login"))
|
||||||
|
|
||||||
@app.route("/")
|
|
||||||
def index():
|
|
||||||
latest_posts = Post.query.all()
|
|
||||||
return render_template("index.html", latest_posts=latest_posts)
|
|
||||||
|
|
||||||
@app.route("/posts")
|
|
||||||
def all_posts():
|
|
||||||
all_posts = Post.query.all()
|
|
||||||
return render_template("posts.html", posts=all_posts)
|
|
||||||
|
|
||||||
@app.route("/about")
|
|
||||||
def about():
|
|
||||||
return render_template("about.html")
|
|
||||||
|
|
||||||
@app.route("/posts/<alias>")
|
|
||||||
def post(alias):
|
|
||||||
post_info = Post.query.filter_by(alias=alias).first()
|
|
||||||
if post_info:
|
|
||||||
return render_template(f"{alias}.html", post_info=post_info)
|
|
||||||
else:
|
|
||||||
return "Post not found", 404
|
|
||||||
|
|
||||||
@app.route("/login", methods=["GET", "POST"])
|
|
||||||
def login():
|
|
||||||
if request.method == "POST":
|
|
||||||
username = request.form["username"]
|
|
||||||
password = request.form["password"]
|
|
||||||
user = User.query.filter_by(username=username, password=password).first()
|
|
||||||
if user:
|
|
||||||
session["username"] = username
|
|
||||||
return redirect(url_for("index"))
|
|
||||||
return render_template("auth/login.html")
|
|
||||||
|
|
||||||
@app.route("/logout")
|
|
||||||
def logout():
|
|
||||||
session.pop("username", None)
|
|
||||||
return redirect(url_for("index"))
|
|
||||||
|
|
||||||
@app.route("/register", methods=["GET", "POST"])
|
@app.route("/register", methods=["GET", "POST"])
|
||||||
def register():
|
def register():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -142,12 +133,123 @@ def register():
|
||||||
error_msg = "Username already exists"
|
error_msg = "Username already exists"
|
||||||
return render_template("auth/register.html", error_msg=error_msg)
|
return render_template("auth/register.html", error_msg=error_msg)
|
||||||
|
|
||||||
new_user = User(username=username, email=email, password=password)
|
new_user = User(username=username, email=email, password=password) # type: ignore
|
||||||
db.session.add(new_user)
|
db.session.add(new_user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return redirect(url_for("login"))
|
return redirect(url_for("login"))
|
||||||
|
|
||||||
return render_template("auth/register.html")
|
return render_template("auth/register.html")
|
||||||
|
|
||||||
|
@app.route("/login", methods=["GET", "POST"])
|
||||||
|
def login():
|
||||||
|
if request.method == "POST":
|
||||||
|
username = request.form["username"]
|
||||||
|
password = request.form["password"]
|
||||||
|
user = User.query.filter_by(username=username, password=password).first()
|
||||||
|
if user:
|
||||||
|
session["username"] = username
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
return render_template("auth/login.html")
|
||||||
|
|
||||||
|
@app.route("/logout")
|
||||||
|
def logout():
|
||||||
|
session.pop("username", None)
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
latest_posts = Post.query.all()[::-1]
|
||||||
|
return render_template("index.html", latest_posts=latest_posts)
|
||||||
|
|
||||||
|
@app.route("/posts")
|
||||||
|
def all_posts():
|
||||||
|
all_posts = Post.query.all()[::-1]
|
||||||
|
return render_template("posts.html", posts=all_posts)
|
||||||
|
|
||||||
|
@app.route("/posts/<alias>")
|
||||||
|
def post(alias):
|
||||||
|
post_info = Post.query.filter_by(alias=alias).first()
|
||||||
|
if post_info:
|
||||||
|
return render_template(f"{alias}.html", post_info=post_info)
|
||||||
|
else:
|
||||||
|
return "Post not found", 404
|
||||||
|
|
||||||
|
@app.route('/forums')
|
||||||
|
def forums():
|
||||||
|
categories = ForumCategory.query.all()
|
||||||
|
posts = ForumPost.query.all()
|
||||||
|
comments = ForumComment.query.all()
|
||||||
|
return render_template('forums.html', categories=categories, posts=posts, comments=comments)
|
||||||
|
|
||||||
|
@app.route('/forums/<int:category_id>')
|
||||||
|
def category(category_id):
|
||||||
|
category = ForumCategory.query.get_or_404(category_id)
|
||||||
|
posts = ForumPost.query.filter_by(category_id=category_id).all()
|
||||||
|
return render_template('category.html', category=category, posts=posts)
|
||||||
|
|
||||||
|
@app.route('/forums/<int:post_id>')
|
||||||
|
def new_post(post_id):
|
||||||
|
post = ForumPost.query.get_or_404(post_id)
|
||||||
|
comments = ForumComment.query.filter_by(post_id=post_id).all()
|
||||||
|
return render_template('post.html', post=post, comments=comments)
|
||||||
|
|
||||||
|
@app.route('/forums/create_post', methods=['GET', 'POST'])
|
||||||
|
def create_post():
|
||||||
|
if request.method == 'POST':
|
||||||
|
category_id = request.form['category_id']
|
||||||
|
post_name = request.form['post_name']
|
||||||
|
created_by = request.form['created_by']
|
||||||
|
text = request.form['text']
|
||||||
|
new_post = ForumPost(category_id=category_id, post_name=post_name, created_by=created_by, text=text) # type: ignore
|
||||||
|
db.session.add(new_post)
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('forums'))
|
||||||
|
else:
|
||||||
|
categories = ForumCategory.query.all()
|
||||||
|
return render_template('create_post.html', categories=categories)
|
||||||
|
|
||||||
|
@app.route('/forums/create_comment', methods=['POST']) # type: ignore
|
||||||
|
def create_comment():
|
||||||
|
if request.method == 'POST':
|
||||||
|
post_id = request.form['post_id']
|
||||||
|
created_by = request.form['created_by']
|
||||||
|
text = request.form['text']
|
||||||
|
new_comment = ForumComment(post_id=post_id, created_by=created_by, text=text) # type: ignore
|
||||||
|
db.session.add(new_comment)
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('post', post_id=post_id))
|
||||||
|
|
||||||
|
@app.route('/forums/upvote_post/<int:post_id>')
|
||||||
|
def upvote_post(post_id):
|
||||||
|
post = ForumPost.query.get_or_404(post_id)
|
||||||
|
post.upvotes += 1
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('post', post_id=post_id))
|
||||||
|
|
||||||
|
@app.route('/forums/downvote_post/<int:post_id>')
|
||||||
|
def downvote_post(post_id):
|
||||||
|
post = ForumPost.query.get_or_404(post_id)
|
||||||
|
post.downvotes += 1
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('post', post_id=post_id))
|
||||||
|
|
||||||
|
@app.route('/forums/upvote_comment/<int:comment_id>')
|
||||||
|
def upvote_comment(comment_id):
|
||||||
|
comment = ForumComment.query.get_or_404(comment_id)
|
||||||
|
comment.upvotes += 1
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('post', post_id=comment.post_id))
|
||||||
|
|
||||||
|
@app.route('/forums/downvote_comment/<int:comment_id>')
|
||||||
|
def downvote_comment(comment_id):
|
||||||
|
comment = ForumComment.query.get_or_404(comment_id)
|
||||||
|
comment.downvotes += 1
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('post', post_id=comment.post_id))
|
||||||
|
|
||||||
|
@app.route("/about")
|
||||||
|
def about():
|
||||||
|
return render_template("about.html")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=True)
|
app.run(debug=True)
|
|
@ -434,6 +434,56 @@ i.far.fa-comment {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forums */
|
||||||
|
|
||||||
|
.forum-card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forum-media {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upvote-btn,
|
||||||
|
.downvote-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upvote-btn:hover,
|
||||||
|
.downvote-btn:hover {
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-count {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-section {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-media {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-text {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-details {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mobile-specific */
|
/* Mobile-specific */
|
||||||
@media only screen and (max-width: 767px) {
|
@media only screen and (max-width: 767px) {
|
||||||
/* Navbar */
|
/* Navbar */
|
||||||
|
|
|
@ -37,7 +37,13 @@
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown pull-left">
|
<li class="dropdown pull-left">
|
||||||
<a href="#" class="dropbtn">Account</a>
|
<a href="#" class="dropbtn">
|
||||||
|
{% if g.user %}
|
||||||
|
{{ g.user.username }}
|
||||||
|
{% else %}
|
||||||
|
Account
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
{% if g.user %}
|
{% if g.user %}
|
||||||
<a href="{{ url_for('logout') }}">Log Out</a>
|
<a href="{{ url_for('logout') }}">Log Out</a>
|
||||||
|
@ -63,4 +69,4 @@
|
||||||
</footer>
|
</footer>
|
||||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}{{ category.category_name }} Category{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h1>{{ category.category_name }}</h1>
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="list-group">
|
||||||
|
{% for post in posts %}
|
||||||
|
<a href="{{ url_for('new_post', post_id=post.id) }}" class="list-group-item list-group-item-action">
|
||||||
|
<h5 class="mb-1">{{ post.post_name }}</h5>
|
||||||
|
<p class="mb-1">{{ post.text }}</p>
|
||||||
|
<small>Created by {{ post.created_by }} - {{ post.creation_date }}</small>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,31 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Forums{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h1>Welcome to the Forums!</h1>
|
||||||
|
{% for category in categories %}
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header">{{ category.category_name }}</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="list-group">
|
||||||
|
{% for post in posts %}
|
||||||
|
{% if post.category_id == category.id %}
|
||||||
|
<a href="{{ url_for('new_post', post_id=post.id) }}" class="list-group-item list-group-item-action">
|
||||||
|
<h5 class="mb-1">{{ post.post_name }}</h5>
|
||||||
|
<p class="mb-1">{{ post.text }}</p>
|
||||||
|
<small>Created by {{ post.created_by }} - {{ post.creation_date }}</small>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="simple-text">
|
<section class="simple-text">
|
||||||
<p>Welcome to 'Picture Puzzle remake' website! Here you can see all game updates, articles, and more. If you want to download the latest version of game, just ask that bird on top :)</p></br>
|
<p>Welcome to 'Picture Puzzle remake' website! Here you can see all game updates, articles, and more. If you want to download the latest version of game, just click on that bird on top <i class="fa-solid fa-feather"></i></p></br>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="featured-posts">
|
<section class="featured-posts">
|
||||||
|
|
Loading…
Reference in New Issue