basic view of all books

This commit is contained in:
Kostiantyn Stoliarskyi 2023-04-24 11:31:54 +03:00
parent ca5e3c8fd7
commit 59c1bed020
9 changed files with 103 additions and 55 deletions

View File

@ -18,6 +18,7 @@
"pytest",
"sqlalchemy",
"tailwindcss",
"viewonly",
"werkzeug",
"wrongpassword",
"wsgi",

View File

@ -21,7 +21,7 @@ def create_app(environment="development"):
main_blueprint,
auth_blueprint,
user_blueprint,
books_blueprint,
book_blueprint,
home_blueprint,
)
from app.models import (
@ -48,7 +48,7 @@ def create_app(environment="development"):
app.register_blueprint(auth_blueprint)
app.register_blueprint(main_blueprint)
app.register_blueprint(user_blueprint)
app.register_blueprint(books_blueprint)
app.register_blueprint(book_blueprint)
app.register_blueprint(home_blueprint)
# Set up flask login.

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,30 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block content %}
<div class="relative overflow-x-auto shadow-md sm:rounded-lg mt-5"></div>
<div class="relative overflow-x-auto shadow-md sm:rounded-lg mt-5">
<!-- prettier-ignore -->
<div class="flex border-b-2 border-gray-200 border-solid dark:border-gray-700 text-gray-900 dark:text-white dark:divide-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-8 h-8"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" /> </svg>
<h1 class="text-2xl font-extrabold dark:text-white ml-4">My books</h1>
</div>
{% for book in books %}
<!-- prettier-ignore -->
<dl class="max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
<a class="flex flex-col pb-2" href="{{url_for('book.view',book_id=book.id)}}">
<dt class="mb-2"> {{book.owner.username}}/{{book.label}} </dt>
<dd class=" flex text-lg font-semibold text-gray-500 md:text-lg dark:text-gray-400">Last updated on {{book.versions[-1].updated_at.strftime('%B %d, %Y')}}
<div class="flex ml-auto w-1/4 align-center justify-center">
<span class="mr-3"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22" stroke-width="1" stroke="currentColor" class="w-4 h-4 inline-flex mr-1"> <path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" /></svg>{{ book.stars|length }}</span>
<span class="mr-3"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22" stroke-width="1" stroke="currentColor" class="w-4 h-4 inline-flex mr-1"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" /> </svg> 55</span>
<span class="mr-3"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22" stroke-width="1" stroke="currentColor" class="w-4 h-4 inline-flex mr-1"> <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /> </svg> 55</span>
</div>
</dd>
</a>
</dl>
{% endfor %}
</div>
{% include 'user/add.html' %}
<!-- prettier-ignore -->
{% endblock %}

View File

@ -0,0 +1,13 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block content %}
<div class="relative overflow-x-auto shadow-md sm:rounded-lg mt-5">
<!-- prettier-ignore -->
<span>{{book}}</span>
</div>
{% include 'user/add.html' %}
<!-- prettier-ignore -->
{% endblock %}
<!-- prettier-ignore -->
{% block scripts %}
{% endblock %}

View File

@ -15,7 +15,7 @@
</li>
<li>
<a
href="{{ url_for('books.get_all') }}"
href="{{ url_for('book.get_all') }}"
class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700">
<!-- prettier-ignore -->
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" /> </svg>

View File

@ -2,5 +2,5 @@
from .auth import auth_blueprint
from .main import main_blueprint
from .user import bp as user_blueprint
from .books import bp as books_blueprint
from .book import bp as book_blueprint
from .home import bp as home_blueprint

59
app/views/book.py Normal file
View File

@ -0,0 +1,59 @@
from flask import (
Blueprint,
render_template,
flash,
redirect,
url_for,
request,
)
from flask_login import login_required
from app import models as m
from app import forms as f
from app.logger import log
from app.controllers import create_pagination
bp = Blueprint("book", __name__, url_prefix="/book")
@bp.route("/", methods=["GET"])
def get_all():
q = request.args.get("q", type=str, default=None)
books = m.Book.query.order_by(m.Book.id)
if q:
books = books.filter(m.Book.label.like(f"{q}"))
pagination = create_pagination(total=books.count())
return render_template(
"books/index.html",
books=books.paginate(page=pagination.page, per_page=pagination.per_page),
page=pagination,
search_query=q,
)
@bp.route("/create", methods=["POST"])
@login_required
def create():
form = f.NewBookForm()
if form.validate_on_submit():
book = m.Book(
label=form.label.data,
)
log(log.INFO, "Form submitted. User: [%s]", book)
flash("Book added!", "success")
book.save()
return redirect(url_for("book.get_all"))
@bp.route("/<int:book_id>", methods=["GET"])
@login_required
def view(book_id):
b = m.Book.query.filter_by(id=book_id).first()
if not b:
log(log.CRITICAL, "Book with id [%s] not found", book_id)
flash("Book not found", "danger")
return redirect(url_for("book.get_all"))
else:
return render_template("books/view.html", book=b)

View File

@ -1,48 +0,0 @@
from flask import (
Blueprint,
render_template,
flash,
redirect,
url_for,
)
from flask_login import login_required
from app import models as m
from app import forms as f
from app.logger import log
bp = Blueprint("books", __name__, url_prefix="/books")
@bp.route("/", methods=["GET"])
def get_all():
# q = request.args.get("q", type=str, default=None)
# books = m.Book.query.order_by(m.Book.id)
# if q:
# books = books.filter(m.Book.label.like(f"{q}"))
# pagination = create_pagination(total=books.count())
# return render_template(
# "books/index.html",
# books=books.paginate(page=pagination.page, per_page=pagination.per_page),
# page=pagination,
# search_query=q,
# )
return render_template(
"books/index.html",
)
@bp.route("/create", methods=["POST"])
@login_required
def create():
form = f.NewBookForm()
if form.validate_on_submit():
book = m.Book(
label=form.label.data,
)
log(log.INFO, "Form submitted. User: [%s]", book)
flash("Book added!", "success")
book.save()
return redirect(url_for("books.get_all"))