Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add pre-commit and update readme #100

Merged
merged 1 commit into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,4 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
19 changes: 19 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-json
- id: check-yaml
- id: debug-statements
- id: detect-private-key
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
hooks:
# Run the linter.
- id: ruff
types_or: [ python, pyi ]
args: [ --fix ]
# Run the formatter.
- id: ruff-format
types_or: [ python, pyi ]
niltonpimentel02 marked this conversation as resolved.
Show resolved Hide resolved
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,28 @@ Our simple yet effective reading tracking app: [PyBites Books](https://pybitesbo

## Setup

![](https://img.shields.io/badge/Python-3.9.0-blue.svg)
![](https://img.shields.io/badge/Django-4.1.13-blue.svg)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)

1. Create a [virtual env](https://pybit.es/the-beauty-of-virtualenv.html) and activate it (`source venv/bin/activate`)
2. Install the dependencies: `pip install -r requirements.txt`
3. Create a database, e.g. `pybites_books` and define the full DB URL for the next step, e.g. `DATABASE_URL=postgres://postgres:[email protected]:5432/pybites_books`.
4. Set this env variable together with `SECRET_KEY` in a file called `.env` in the root of the project: `cp .env-template .env && vi .env`. That's the bare minimum. If you want to have email working create a [Sendgrid](https://sendgrid.com/) account obtaining an API key. Same for Slack integration, this requires a `SLACK_VERIFICATION_TOKEN`. The other variables have sensible defaults.
5. Sync the DB: `python manage.py migrate`.
6. And finally run the app server: `python manage.py runserver`.

## Run pre-commit

Install the git hook scripts
```bash
pre-commit install
```
Run against all the files:
```bash
pre-commit run --all-files
```

## Local Via docker-compose

You can use docker / docker compose to run both the postgresql database as well as the app itself. This makes local testing a lot easier, and allows you to worry less about environmental details.
Expand Down
2 changes: 1 addition & 1 deletion api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@


class ApiConfig(AppConfig):
name = 'api'
name = "api"
16 changes: 8 additions & 8 deletions api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

from . import views

app_name = 'api'
app_name = "api"
urlpatterns = [
path('users', views.user_books, name='user_books'),
path('users/<str:username>', views.user_books, name='user_books'),
path('random', views.random_book, name='random_book'),
path('random/<str:grep>', views.random_book, name='random_book'),
path('books/<str:bookid>', views.get_bookid, name='get_bookid'),
path('lists/<str:name>', views.get_book_list, name='get_book_list'),
path('stats/<str:username>', views.get_book_stats, name='get_book_stats'),
path("users", views.user_books, name="user_books"),
path("users/<str:username>", views.user_books, name="user_books"),
path("random", views.random_book, name="random_book"),
path("random/<str:grep>", views.random_book, name="random_book"),
path("books/<str:bookid>", views.get_bookid, name="get_bookid"),
path("lists/<str:name>", views.get_book_list, name="get_book_list"),
path("stats/<str:username>", views.get_book_stats, name="get_book_stats"),
]
147 changes: 77 additions & 70 deletions api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

def get_users():
user_books = defaultdict(list)
books = UserBook.objects.select_related('user').all()
books = UserBook.objects.select_related("user").all()
for book in books:
user_books[book.user.username].append(book)
return user_books
Expand All @@ -20,60 +20,63 @@ def get_users():
def get_user_last_book(username):
user = get_object_or_404(User, username=username)

books = UserBook.objects.select_related('book')
books = books.filter(user=user).order_by('-inserted')
books = UserBook.objects.select_related("book")
books = books.filter(user=user).order_by("-inserted")
if not books:
raise Http404

book = books[0]
data = dict(bookid=book.book.bookid,
title=book.book.title,
url=book.book.url,
authors=book.book.authors,
published=book.book.published,
isbn=book.book.isbn,
pages=book.book.pages,
language=book.book.language,
description=book.book.description,
imagesize=book.book.imagesize)
data = dict(
bookid=book.book.bookid,
title=book.book.title,
url=book.book.url,
authors=book.book.authors,
published=book.book.published,
isbn=book.book.isbn,
pages=book.book.pages,
language=book.book.language,
description=book.book.description,
imagesize=book.book.imagesize,
)
return data


def get_user_books(username):
data = defaultdict(list)
user = get_object_or_404(User, username=username)
books = UserBook.objects.select_related('book').filter(user=user)
books = UserBook.objects.select_related("book").filter(user=user)

for book in books:
row = dict(bookid=book.book.bookid,
title=book.book.title,
url=book.book.url,
authors=book.book.authors,
favorite=book.favorite,
published=book.book.published,
isbn=book.book.isbn,
pages=book.book.pages,
language=book.book.language,
description=book.book.description,
imagesize=book.book.imagesize)
row = dict(
bookid=book.book.bookid,
title=book.book.title,
url=book.book.url,
authors=book.book.authors,
favorite=book.favorite,
published=book.book.published,
isbn=book.book.isbn,
pages=book.book.pages,
language=book.book.language,
description=book.book.description,
imagesize=book.book.imagesize,
)
data[book.status].append(row)
return data


def user_books(request, username=None):

if username is None:
data = get_users()
else:
data = get_user_books(username)

json_data = json.dumps(data, indent=4, default=str, sort_keys=False)

return HttpResponse(json_data, content_type='application/json')
return HttpResponse(json_data, content_type="application/json")


def get_random_book(grep=None):
books = UserBook.objects.select_related('book').all()
books = UserBook.objects.select_related("book").all()

if grep is not None:
books = books.filter(book__title__icontains=grep.lower())
Expand All @@ -84,16 +87,18 @@ def get_random_book(grep=None):
count = books.count()
book = books[randint(0, count - 1)]

data = dict(bookid=book.book.bookid,
title=book.book.title,
url=book.book.url,
authors=book.book.authors,
published=book.book.published,
isbn=book.book.isbn,
pages=book.book.pages,
language=book.book.language,
description=book.book.description,
imagesize=book.book.imagesize)
data = dict(
bookid=book.book.bookid,
title=book.book.title,
url=book.book.url,
authors=book.book.authors,
published=book.book.published,
isbn=book.book.isbn,
pages=book.book.pages,
language=book.book.language,
description=book.book.description,
imagesize=book.book.imagesize,
)

return data

Expand All @@ -104,7 +109,7 @@ def random_book(request, grep=None):

json_data = json.dumps(data, indent=4, default=str, sort_keys=False)

return HttpResponse(json_data, content_type='application/json')
return HttpResponse(json_data, content_type="application/json")


def get_bookid(request, bookid):
Expand All @@ -113,29 +118,31 @@ def get_bookid(request, bookid):
raise Http404

book = books[0]
data = dict(bookid=book.bookid,
title=book.title,
url=book.url,
authors=book.authors,
publisher=book.publisher,
published=book.published,
isbn=book.isbn,
pages=book.pages,
language=book.language,
description=book.description,
imagesize=book.imagesize)
data = dict(
bookid=book.bookid,
title=book.title,
url=book.url,
authors=book.authors,
publisher=book.publisher,
published=book.published,
isbn=book.isbn,
pages=book.pages,
language=book.language,
description=book.description,
imagesize=book.imagesize,
)

json_data = json.dumps(data, indent=4, default=str, sort_keys=False)

return HttpResponse(json_data, content_type='application/json')
return HttpResponse(json_data, content_type="application/json")


def get_book_list(request, name):
books = UserBook.objects.select_related(
"book"
).filter(
booklists__name=name
).order_by("book__title")
books = (
UserBook.objects.select_related("book")
.filter(booklists__name=name)
.order_by("book__title")
)

if not books:
raise Http404
Expand All @@ -148,30 +155,30 @@ def get_book_list(request, name):
url=book.book.url,
authors=book.book.authors,
pages=book.book.pages,
description=book.book.description)
description=book.book.description,
)
data.append(book_obj)

return HttpResponse(
json.dumps(
data, indent=4, default=str, sort_keys=False),
content_type='application/json'
json.dumps(data, indent=4, default=str, sort_keys=False),
content_type="application/json",
)


def get_book_stats(request, username):
user_books = UserBook.objects.select_related(
'book'
).filter(user__username=username)
user_books = UserBook.objects.select_related("book").filter(user__username=username)

data = []
for user_book in user_books:
row = dict(bookid=user_book.book.bookid,
title=user_book.book.title,
url=user_book.book.url,
status=user_book.status,
favorite=user_book.favorite,
completed=user_book.completed)
row = dict(
bookid=user_book.book.bookid,
title=user_book.book.title,
url=user_book.book.url,
status=user_book.status,
favorite=user_book.favorite,
completed=user_book.completed,
)
data.append(row)

json_data = json.dumps(data, indent=4, default=str, sort_keys=False)
return HttpResponse(json_data, content_type='application/json')
return HttpResponse(json_data, content_type="application/json")
35 changes: 27 additions & 8 deletions books/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@
from django.contrib import admin
from django.utils.safestring import mark_safe

from .models import (Category, Book, Search, UserBook,
BookNote, Badge, BookConversion,
ImportedBook)
from .models import (
Category,
Book,
Search,
UserBook,
BookNote,
Badge,
BookConversion,
ImportedBook,
)


class CategoryAdmin(admin.ModelAdmin):
Expand All @@ -23,7 +30,11 @@ class SearchAdmin(admin.ModelAdmin):

class UserBookAdmin(admin.ModelAdmin):
list_display = ("user", "book", "status", "favorite", "completed", "inserted")
search_fields = ("user__username", "book__title", "book__bookid",)
search_fields = (
"user__username",
"book__title",
"book__bookid",
)
list_filter = ("status", "favorite")


Expand All @@ -39,7 +50,8 @@ def short_desc(self, obj):
return f"{obj.description[:limit]} ..."
else:
return obj.description
short_desc.short_description = 'short description'

short_desc.short_description = "short description"


class BadgeAdmin(admin.ModelAdmin):
Expand All @@ -55,12 +67,19 @@ def book_link(self, obj):
f"<a href='{settings.DOMAIN}/books/{obj.googlebooks_id}' "
f"target='_blank'>{obj.googlebooks_id}</a>"
)
book_link.short_description = 'Google / PyBites book link'

book_link.short_description = "Google / PyBites book link"


class ImportedBookAdmin(admin.ModelAdmin):
list_display = ("title", "book", "reading_status", "date_completed",
"book_status", "user")
list_display = (
"title",
"book",
"reading_status",
"date_completed",
"book_status",
"user",
)
search_fields = ("title",)


Expand Down
2 changes: 1 addition & 1 deletion books/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@


class BooksConfig(AppConfig):
name = 'books'
name = "books"
Loading
Loading