diff --git a/config.json b/config.json index 8b76522..48e6c6f 100755 --- a/config.json +++ b/config.json @@ -1 +1 @@ -{"TITLE": "pyShelf E-Book Server", "VERSION": "0.6.0", "BOOKPATH": "", "DB_HOST": "localhost", "DB_PORT": "5432", "DATABASE": "pyshelf", "USER": "pyshelf", "PASSWORD": "pyshelf", "BOOKSHELF": "data/shelf.json", "ALLOWED_HOSTS": "*", "hostname": "localhost", "webport": "8000", "wsgiport": "8001"} \ No newline at end of file +{"TITLE": "pyShelf E-Book Server", "VERSION": "0.6.0", "BOOKPATH": "/home/raelon/Books", "DB_HOST": "localhost", "DB_PORT": "5432", "DATABASE": "pyshelf", "USER": "pyshelf", "PASSWORD": "pyshelf", "BOOKSHELF": "data/shelf.json", "ALLOWED_HOSTS": "*", "hostname": "localhost", "webport": "8000", "wsgiport": "8001"} diff --git a/src/backend/lib/library.py b/src/backend/lib/library.py index a6873ca..5016513 100755 --- a/src/backend/lib/library.py +++ b/src/backend/lib/library.py @@ -28,6 +28,7 @@ class Catalogue: self.html_regx = re.compile(r"\.html") self.title_sanitization_regx = re.compile(r"^(Book )+[0-9]*") self.title_sanitization_lvl2_regx = re.compile(r"^(Book )+[0-9]*\W+(-)") + self.title_sanitization_dirs_regx = re.compile(r"/") self.root_dir = config.root self.book_folder = config.book_path self.books = None diff --git a/src/backend/lib/storage.py b/src/backend/lib/storage.py index 06b6b6f..0969707 100755 --- a/src/backend/lib/storage.py +++ b/src/backend/lib/storage.py @@ -1,6 +1,6 @@ #!/usr/bin/python import re - +import datetime import psycopg2 @@ -53,7 +53,7 @@ class Storage: Insert book in database :returns: True if succeeds False if not """ - q = "INSERT INTO books (title, author, cover, progress, file_name, pages, description, identifier, publisher, rights, tags) values (%s, %s, %s, 0, %s, 0, %s, %s, %s, %s, %s);" + q = "INSERT INTO books (title, author, cover, progress, file_name, pages, description, identifier, publisher, date, rights, tags) values (%s, %s, %s, 0, %s, 0, %s, %s, %s, %s, %s, %s);" try: try: cover_image = book[2].data @@ -71,7 +71,7 @@ class Storage: book[4], # descr book[5], # ident book[6], # publisher - # book[7], # date # TODO: set import time + datetime.datetime.now(), book[8], # rights book[9], # tags ), @@ -114,6 +114,7 @@ class Storage: return True def make_collections(self): + breakpoint() _title_regx = re.compile(r"^[0-9][0-9]*|-|\ \B") _q = "SELECT id,file_name FROM books" self.cursor.execute(_q) diff --git a/src/frontend/urls.py b/src/frontend/urls.py index 2c58bb6..379ece7 100755 --- a/src/frontend/urls.py +++ b/src/frontend/urls.py @@ -23,6 +23,7 @@ urlpatterns = [ path("", views.index, name="index"), path("home", views.home, name="index"), path("sort/<_order>", views.index, name="index"), + path("flip_sort/<_order>", views.flip_sort, name="index"), path("download/", views.download, name="download"), path("favorite/", views.favorite, name="favorite"), path("share/", views.share, name="share"), diff --git a/src/interface/migrations/0001_initial.py b/src/interface/migrations/0001_initial.py old mode 100755 new mode 100644 index ab512f0..be3fcdb --- a/src/interface/migrations/0001_initial.py +++ b/src/interface/migrations/0001_initial.py @@ -1,35 +1,90 @@ -# Generated by Django 2.2.7 on 2019-11-28 19:24 +# Generated by Django 3.0.7 on 2020-07-05 23:21 from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): initial = True - dependencies = [] + dependencies = [ + ] operations = [ migrations.CreateModel( - name="Books", + name='Books', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("title", models.CharField(max_length=255)), - ("author", models.CharField(max_length=255, null=True)), - ("categories", models.CharField(max_length=255, null=True)), - ("cover", models.BinaryField(editable=True, null=True)), - ("pages", models.IntegerField(null=True)), - ("progress", models.IntegerField(null=True)), - ("file_name", models.CharField(max_length=255)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.TextField()), + ('author', models.CharField(max_length=255, null=True)), + ('categories', models.TextField(null=True)), + ('cover', models.BinaryField(editable=True, null=True)), + ('pages', models.IntegerField(null=True)), + ('progress', models.IntegerField(null=True)), + ('file_name', models.TextField()), + ('description', models.TextField(null=True)), + ('identifier', models.CharField(max_length=255, null=True)), + ('publisher', models.TextField(null=True)), + ('date', models.DateField(null=True)), + ('rights', models.CharField(max_length=255, null=True)), + ('tags', models.TextField(null=True)), ], - options={"db_table": "books",}, + options={ + 'db_table': 'books', + }, + ), + migrations.CreateModel( + name='Navigation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('link', models.CharField(max_length=255, null=True)), + ('category', models.CharField(max_length=255, null=True)), + ('parent_id', models.IntegerField(null=True)), + ('alt', models.CharField(max_length=255, null=True)), + ('type', models.IntegerField(null=True)), + ('socket', models.CharField(max_length=255)), + ], + options={ + 'db_table': 'navigation', + }, + ), + migrations.CreateModel( + name='Users', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uname', models.CharField(max_length=255)), + ('fname', models.CharField(max_length=255, null=True)), + ('lname', models.CharField(max_length=255, null=True)), + ('email', models.CharField(max_length=255, null=True)), + ('password', models.CharField(max_length=255, null=True)), + ('ulvl', models.IntegerField(null=True)), + ], + options={ + 'db_table': 'users', + }, + ), + migrations.CreateModel( + name='Favorites', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('favorite', models.ManyToManyField(to='interface.Books')), + ('uname', models.ManyToManyField(to='interface.Users')), + ], + options={ + 'db_table': 'favorites', + }, + ), + migrations.CreateModel( + name='Collections', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('collection', models.CharField(max_length=255)), + ('book_id', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='interface.Books')), + ], + options={ + 'db_table': 'collections', + }, ), ] diff --git a/src/interface/migrations/0002_auto_20200101_0445.py b/src/interface/migrations/0002_auto_20200101_0445.py deleted file mode 100755 index d0f105d..0000000 --- a/src/interface/migrations/0002_auto_20200101_0445.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 2.2.7 on 2020-01-01 04:45 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("interface", "0001_initial"), - ] - - operations = [ - migrations.AlterModelOptions(name="books", options={"managed": False},), - ] diff --git a/src/interface/migrations/0003_auto_20200101_0447.py b/src/interface/migrations/0003_auto_20200101_0447.py deleted file mode 100755 index 22d0ea0..0000000 --- a/src/interface/migrations/0003_auto_20200101_0447.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 2.2.7 on 2020-01-01 04:47 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("interface", "0002_auto_20200101_0445"), - ] - - operations = [ - migrations.AlterModelOptions(name="books", options={},), - ] diff --git a/src/interface/migrations/0004_collections.py b/src/interface/migrations/0004_collections.py deleted file mode 100755 index 35f7c37..0000000 --- a/src/interface/migrations/0004_collections.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 3.0.2 on 2020-02-04 20:22 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("interface", "0003_auto_20200101_0447"), - ] - - operations = [ - migrations.CreateModel( - name="Collections", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("collection", models.CharField(max_length=255)), - ( - "book_id", - models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - to="interface.Books", - ), - ), - ], - options={"db_table": "collections",}, - ), - ] diff --git a/src/interface/migrations/0005_navigation.py b/src/interface/migrations/0005_navigation.py deleted file mode 100644 index fcae6e3..0000000 --- a/src/interface/migrations/0005_navigation.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 3.0.4 on 2020-06-10 05:07 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("interface", "0004_collections"), - ] - - operations = [ - migrations.CreateModel( - name="Navigation", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("title", models.CharField(max_length=255)), - ("link", models.CharField(max_length=255, null=True)), - ("category", models.CharField(max_length=255, null=True)), - ("parent_id", models.IntegerField(null=True)), - ("alt", models.CharField(max_length=255, null=True)), - ("type", models.IntegerField(null=True)), - ("socket", models.CharField(max_length=255)), - ], - options={"db_table": "navigation",}, - ), - ] diff --git a/src/interface/migrations/0006_auto_20200617_2333.py b/src/interface/migrations/0006_auto_20200617_2333.py deleted file mode 100644 index 7ca9e25..0000000 --- a/src/interface/migrations/0006_auto_20200617_2333.py +++ /dev/null @@ -1,69 +0,0 @@ -# Generated by Django 3.0.7 on 2020-06-17 23:33 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interface', '0005_navigation'), - ] - - operations = [ - migrations.CreateModel( - name='Users', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uname', models.CharField(max_length=255)), - ('fname', models.CharField(max_length=255, null=True)), - ('lname', models.CharField(max_length=255, null=True)), - ('email', models.CharField(max_length=255, null=True)), - ('password', models.CharField(max_length=255, null=True)), - ('ulvl', models.IntegerField(null=True)), - ], - options={ - 'db_table': 'users', - }, - ), - migrations.AddField( - model_name='books', - name='date', - field=models.DateField(null=True), - ), - migrations.AddField( - model_name='books', - name='description', - field=models.TextField(null=True), - ), - migrations.AddField( - model_name='books', - name='identifier', - field=models.CharField(max_length=255, null=True), - ), - migrations.AddField( - model_name='books', - name='publisher', - field=models.CharField(max_length=266, null=True), - ), - migrations.AddField( - model_name='books', - name='rights', - field=models.CharField(max_length=255, null=True), - ), - migrations.AddField( - model_name='books', - name='tags', - field=models.CharField(max_length=255, null=True), - ), - migrations.CreateModel( - name='Favorites', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('favorite', models.ManyToManyField(to='interface.Books')), - ('uname', models.ManyToManyField(to='interface.Users')), - ], - options={ - 'db_table': 'favorites', - }, - ), - ] diff --git a/src/interface/migrations/__init__.py b/src/interface/migrations/__init__.py old mode 100755 new mode 100644 diff --git a/src/interface/models.py b/src/interface/models.py index 3874f60..cdcd89b 100755 --- a/src/interface/models.py +++ b/src/interface/models.py @@ -22,19 +22,20 @@ class Books(models.Model): def __str__(self): return self.title - title = models.CharField(max_length=255) + title = models.TextField(max_length=None) author = models.CharField(max_length=255, null=True) - categories = models.CharField(max_length=255, null=True) + categories = models.TextField(max_length=None, null=True) cover = models.BinaryField(null=True, editable=True) pages = models.IntegerField(null=True) progress = models.IntegerField(null=True) - file_name = models.CharField(max_length=255, null=False) + file_name = models.TextField(max_length=None, null=False) + date = models.DateTimeField(auto_now_add=True) description = models.TextField(null=True) identifier = models.CharField(max_length=255, null=True) - publisher = models.CharField(max_length=266, null=True) + publisher = models.TextField(max_length=None, null=True) date = models.DateField(null=True) rights = models.CharField(max_length=255, null=True) - tags = models.CharField(max_length=255, null=True) + tags = models.TextField(max_length=None, null=True) def generic_search(self, query): try: @@ -68,7 +69,6 @@ class Collections(models.Model): raise return results - class Navigation(models.Model): """ pyShelfs Navigation Database class @@ -105,7 +105,6 @@ class Navigation(models.Model): raise return results - class Users(models.Model): """ pyShelfs User Database class @@ -139,7 +138,6 @@ class Users(models.Model): raise return results - class Favorites(models.Model): """ pyShelfs User Database class diff --git a/src/interface/static/css/main.css b/src/interface/static/css/main.css index a7cd5df..1c954a2 100644 --- a/src/interface/static/css/main.css +++ b/src/interface/static/css/main.css @@ -349,6 +349,11 @@ body { /* min-width: 55px; */ } +#flip_sort { + margin: 0px; + display: inline-flex; +} + .ui_icon_notxt { margin: 0px 5px 0px 0px; } diff --git a/src/interface/static/css/main.scss b/src/interface/static/css/main.scss index ebc9b94..053fa94 100755 --- a/src/interface/static/css/main.scss +++ b/src/interface/static/css/main.scss @@ -364,6 +364,10 @@ body { justify-content: center; align-items: center;/* min-width: 55px; */ } +#flip_sort{ + margin: 0px; + display: inline-flex; +} .ui_icon_notxt{ margin: 0px 5px 0px 0px; } diff --git a/src/interface/static/js/pyshelf_ux.js b/src/interface/static/js/pyshelf_ux.js index 347a741..8493489 100755 --- a/src/interface/static/js/pyshelf_ux.js +++ b/src/interface/static/js/pyshelf_ux.js @@ -84,6 +84,9 @@ $(document).ready(function(){ _location = $(this).attr('data-location'); window.location.href=_location; }); + $('#flip_sort').on("click", function(){ + window.location.href="/flip_sort/"+$("#_order").val() + }); $('#search_string').html(" "+$('#_search').val().substr(0,15)+"") resize_search(); $(window).resize(resize_search(win_width)); diff --git a/src/interface/templates/index.html b/src/interface/templates/index.html index 0d6382b..ffdf0c7 100755 --- a/src/interface/templates/index.html +++ b/src/interface/templates/index.html @@ -59,8 +59,10 @@
- - +
+ + +
diff --git a/src/interface/views.py b/src/interface/views.py index a0fbb0b..fde706a 100755 --- a/src/interface/views.py +++ b/src/interface/views.py @@ -60,6 +60,19 @@ def show_collection(request, _collection, _colset): }, ) +def flip_sort(request, bookset=1, query=None, _limit=None, _order='title'): + """ + Goto next page in bookset + """ + try: _set = int(bookset) + except Exception: _set = 1 + _payload = payload(request, query, _set, _limit, _order, flip_sort=True) + return render( + request, + "index.html", + _payload, + ) + def next_page(request, bookset, query=None, _limit=None, _order='title'): """ Goto next page in bookset @@ -94,7 +107,7 @@ def prev_page(request, bookset, query=None, _limit=None, _order='title'): _payload, ) -def book_set(_order, _limit=None, _set=1): +def book_set(_order, _limit=None, _set=1, _flip=False): """ Get books results by set # """ @@ -102,7 +115,10 @@ def book_set(_order, _limit=None, _set=1): _limit = 20 # TODO default from user choice _set_max = int(_set) * _limit _set_min = _set_max - _limit - books = Books.objects.all().order_by(_order)[_set_min:_set_max] + if _flip: + books = Books.objects.all().order_by(_order).reverse()[_set_min:_set_max] + else: + books = Books.objects.all().order_by(_order)[_set_min:_set_max] return books def collection(_collection, _set, _limit=None): @@ -247,7 +263,15 @@ def collections_list(): def payload(request, query, _set, _limit, _order, **kwargs): """ Return formatted data to template + : notes : This is the least pythonic function I have ever written, but its + still beautiful """ + try: request.session['ascending'] + except KeyError: request.session['ascending'] = bool + try: + if kwargs['flip_sort']: + request.session['ascending'] = not request.session['ascending'] + except KeyError: pass try: if kwargs['reset']: request.session['cached_query'] = query @@ -256,7 +280,10 @@ def payload(request, query, _set, _limit, _order, **kwargs): _set_max = int(_set) * _limit _set_min = _set_max - _limit _now_showing = "%s-%s"%(_set_min, _set_max) - _r, _r_len, _search = book_set(_order, _limit, _set), None, None + if request.session['ascending']: + _r = book_set(_order, _limit, _set) + else: _r = book_set(_order, _limit, _set, True) + _r_len, _search = None, None except KeyError: _set = int(_set) if _set < 1: _set = 1 @@ -267,26 +294,34 @@ def payload(request, query, _set, _limit, _order, **kwargs): if query: if query != request.session.get('cached_query'): request.session['cached_query'] = query - _results = Books().generic_search(query) + if request.session['ascending']: + _results = Books().generic_search(query) + else: _results = Books().generic_search(query).reverse() _r, _r_len = \ _results[_set_min:_set_max],\ _results.count() elif query == request.session.get('cached_query'): - _results = Books().generic_search(query) + if request.session['ascending']: + _results = Books().generic_search(query) + else: _results = Books().generic_search(query).reverse() _r, _r_len = \ _results.order_by(_order)[_set_min:_set_max],\ _results.count() - else: try: query = request.session['cached_query'] if query == None: raise KeyError - _results = Books().generic_search(query) + if request.session['ascending']: + _results = Books().generic_search(query) + else: _results = Books().generic_search(query).reverse() _r, _r_len = \ _results.order_by(_order)[_set_min:_set_max],\ _results.count() except KeyError: - _r, _r_len, _search = book_set(_order, _limit, _set), None, None + if request.session['ascending']: + _r = book_set(_order, _limit, _set) + else: _r = book_set(_order, _limit, _set, True) + _r_len, _search = None, None _bookstats, _collectionstats, _collectionobject = \ Books.objects.all().count, Collections.objects.all().count, \