diff --git a/.gitattributes b/.gitattributes index da8b3db..6736cd6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,14 +1,4 @@ -docs/* linguist-documentation -src/backend/* -src/interace/static/css/* linguist-vendored -src/interface/admin.py -src/interface/apps.py -src/interface/forms.py -src/interface/models.py -src/interface/tests.py -src/interfaec/views.py -src/interface/templates/* -src/interface/templatetags/* -src/interace/static/js/pyshelf_ux.js -src/frontend/urs.py -src/frontend/settings.py +* linguist-vendored +*.py linguist-vendored=false +*.js linguist-vendored=false +*.html linguist-vendored=false diff --git a/README.md b/README.md index 7a8ded3..2922976 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# pyShelf 0.6.1 +# pyShelf 0.7.0

Terminal based ebook server. Open source & Lightweight.

Having used Calibre for hosting my eBook collection in the past, I found myself frustrated having to install X on my server, or manage my library externally, Thus I have decided to spin up my own.

@@ -14,6 +14,12 @@ Follow or influence development @

Discord

+## 0.7.0 Patch Notes. + +# New Features + +* Administration System +* PDF Support ## Current Features @@ -43,49 +49,6 @@ Follow or influence development @

* mobi * pdf -## 0.6.1 Patch Notes. - -# New Features - -* PDF Format - * Image & Description acquisition needs work. - - -## 0.6.0 Patch Notes. - -# New Features - -* Automated Collections - * A work in progress, the collections are based on your folder structure. -* User System -* Per User Favorites -* Expanded book information view -* Websocket server - * currently only responds to ping, and importBooks, more responders are planned. -* Full Docker integration. -* On Demand Importing -* .mobi Support -* Result set ordering - * You can now choose to order your results: - * Title - * Author - * Categories - * & Tags -* Reworked UI/UX - * More intuitive, less intrusive, & stays out of the way. caveat: I need to rework the placement of the next & previous page controls. While they do remain usable, I intend to have them follow the users - position on the page in future releases. - -![pyShelf 0.6.0 navbar](https://github.com/th3r00t/pyShelf/raw/master/src/interface/static/img/navbar.png) - -* New controls - * Sort - * Ascending / Descending result set - * Display of the result set count, and your current position in the set. - * A pop over layer to hold things like - * [x] User login & Registration - * [x] Control panel - * [x] Book details - ## Installation & Support Information # Installation @@ -133,7 +96,7 @@ The first step is to login, after logging in the button whill show your username - [x] Automated Collections - [ ] Manual Collections -- [ ] Books Removal +- [x] Books Removal - [ ] Access Restrictions - [ ] Metadata Manipulation - [ ] Others? diff --git a/config.json b/config.json index 2dfe7ad..e72eab1 100644 --- 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": "*", "SECRET": "", "BUILD_MODE": "production"} +{"TITLE": "pyShelf E-Book Server", "VERSION": "0.7.0", "BOOKPATH": "", "DB_HOST": "localhost", "DB_PORT": "5432", "DATABASE": "pyshelf", "USER": "pyshelf", "PASSWORD": "pyshelf", "BOOKSHELF": "data/shelf.json", "ALLOWED_HOSTS": "*", "SECRET": "", "BUILD_MODE": "production"} diff --git a/doxygen.conf b/doxygen.conf index f15d382..e846ee0 100755 --- a/doxygen.conf +++ b/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "pyShelf Open Source Ebook Server" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.6.0 +PROJECT_NUMBER = 0.7.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/src/frontend/urls.py b/src/frontend/urls.py index 70c3f1b..54eac9d 100755 --- a/src/frontend/urls.py +++ b/src/frontend/urls.py @@ -22,9 +22,10 @@ from django.urls import include, path, re_path from django.conf.urls.static import static from asgiref.sync import sync_to_async from interface import views +from interface.admin import admin_site urlpatterns = [ - path("admin/", admin.site.urls), + path("admin/", admin_site.urls), path("", views.index, name="index"), path("home", views.home, name="home"), re_path("^live$", views.live, name="live"), diff --git a/src/interface/admin.py b/src/interface/admin.py index 56212ba..8d1effe 100755 --- a/src/interface/admin.py +++ b/src/interface/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin +from django.contrib.admin import AdminSite from django.contrib.auth.admin import UserAdmin from .models import Books, Collections, Favorites, Navigation, User @@ -22,8 +23,27 @@ class CustomUserAdmin(UserAdmin): ) -admin.site.register(Books) -admin.site.register(Collections) -admin.site.register(Favorites) -admin.site.register(Navigation) -admin.site.register(User, CustomUserAdmin) +class pyShelfAdminSite(AdminSite): + site_title = 'pyShelf admin' + site_header = 'pyShelf Administration' + index_title = 'Library' + + +class BookModelSearch(admin.ModelAdmin): + search_fields=('title','author','tags') + + +class CollectionModelSearch(admin.ModelAdmin): + search_fields=('collection',) + + +class FavoritesModelSearch(admin.ModelAdmin): + search_fields=('user_id',) + + +admin_site = pyShelfAdminSite(name='pyadmin') +admin_site.register(Books, BookModelSearch) +admin_site.register(Collections, CollectionModelSearch) +admin_site.register(Favorites, FavoritesModelSearch) +admin_site.register(Navigation) +admin_site.register(User, CustomUserAdmin) diff --git a/src/interface/models.py b/src/interface/models.py index 893ffc4..1ff0259 100755 --- a/src/interface/models.py +++ b/src/interface/models.py @@ -21,6 +21,7 @@ class Books(models.Model): class Meta: db_table = "books" + verbose_name_plural = 'Books' def __str__(self): return self.title @@ -59,6 +60,7 @@ class Books(models.Model): class Collections(models.Model): class Meta: db_table = "collections" + verbose_name_plural = 'Collections' def __str__(self): return self.collection.__str__() @@ -120,6 +122,7 @@ class Navigation(models.Model): class Meta: db_table = "navigation" + verbose_name_plural = "Navigation" def __str__(self): return self.title @@ -162,6 +165,7 @@ class Favorites(models.Model): class Meta: db_table = "favorites" + verbose_name_plural = "Favorites" def __str__(self): return str(self.book) diff --git a/src/interface/static/admin/css/base.css b/src/interface/static/admin/css/base.css index c428519..d03f025 100644 --- a/src/interface/static/admin/css/base.css +++ b/src/interface/static/admin/css/base.css @@ -13,19 +13,19 @@ body { padding: 0; font-size: 14px; font-family: "Roboto","Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif; - color: #333; - background: #fff; + color: #fff; + background: #282828; } /* LINKS */ a:link, a:visited { - color: #447e9b; + color: #fff; text-decoration: none; } a:focus, a:hover { - color: #036; + color: #909090; } a:focus { @@ -64,7 +64,7 @@ h1 { margin: 0 0 20px; font-weight: 300; font-size: 20px; - color: #666; + color: #3f3; } h2 { @@ -234,10 +234,10 @@ th { thead th, tfoot td { - color: #666; + color: #000; padding: 5px 10px; font-size: 11px; - background: #fff; + background: #676767; border: none; border-top: 1px solid #eee; border-bottom: 1px solid #eee; @@ -253,18 +253,18 @@ thead th.required { } tr.alt { - background: #f6f6f6; + background: #797979; } tr:nth-child(odd), .row-form-errors { - background: #fff; + background: #676767; } tr:nth-child(even), tr:nth-child(even) .errorlist, tr:nth-child(odd) + .row-form-errors, tr:nth-child(odd) + .row-form-errors .errorlist { - background: #f9f9f9; + background: #797979; } /* SORTABLE TABLES */ @@ -273,15 +273,15 @@ thead th { padding: 5px 10px; line-height: normal; text-transform: uppercase; - background: #f6f6f6; + background: #797979; } thead th a:link, thead th a:visited { - color: #666; + color: #000; } thead th.sorted { - background: #eee; + background: #797979; } thead th.sorted .text { @@ -300,7 +300,7 @@ table thead th .text a { } table thead th .text a:focus, table thead th .text a:hover { - background: #eee; + background: #797979; } thead th.sorted a.sortremove { @@ -327,7 +327,7 @@ table thead th.sorted .sortpriority { margin-right: 2px; } -table thead th.sorted .sortoptions a { +table thead th.sort79797e.sortoptions a { position: relative; width: 14px; height: 14px; @@ -424,7 +424,7 @@ select[multiple] { /* FORM BUTTONS */ .button, input[type=submit], input[type=button], .submit-row input, a.button { - background: #79aec8; + background: #888; padding: 10px 15px; border: none; border-radius: 4px; @@ -471,7 +471,7 @@ input[type=button][disabled].default { .module { border: none; margin-bottom: 30px; - background: #fff; + background: #363636; } .module p, .module ul, .module h3, .module h4, .module dl, .module pre { @@ -497,7 +497,7 @@ input[type=button][disabled].default { font-weight: 400; font-size: 13px; text-align: left; - background: #79aec8; + background: #888; color: #fff; } @@ -608,7 +608,7 @@ td ul.errorlist + input, td ul.errorlist + select, td ul.errorlist + textarea { /* BREADCRUMBS */ div.breadcrumbs { - background: #79aec8; + background: #888; padding: 10px 40px; border: none; font-size: 14px; @@ -812,10 +812,12 @@ table#change-history tbody th { display: flex; justify-content: space-between; align-items: center; - padding: 10px 40px; - background: #417690; - color: #ffc; + padding: 10px 10px; + background: #363636; + color: #3f3; overflow: hidden; + border-bottom: #3f3 1px solid; + margin-bottom: 5px; } #header a:link, #header a:visited { @@ -835,11 +837,11 @@ table#change-history tbody th { margin: 0 20px 0 0; font-weight: 300; font-size: 24px; - color: #f5dd5d; + color: #3f3; } #branding h1, #branding h1 a:link, #branding h1 a:visited { - color: #f5dd5d; + color: #3f3; } #branding h2 { @@ -871,14 +873,14 @@ table#change-history tbody th { #user-tools a:focus, #user-tools a:hover { text-decoration: none; - border-bottom-color: #79aec8; - color: #79aec8; + border-bottom-color: #888; + color: #888; } /* SIDEBAR */ #content-related { - background: #f8f8f8; + background: #797979; } #content-related .module { @@ -887,7 +889,7 @@ table#change-history tbody th { #content-related h3 { font-size: 14px; - color: #666; + color: #fff; padding: 0 16px; margin: 0 0 16px; } @@ -918,7 +920,7 @@ table#change-history tbody th { margin-bottom: 16px; border-bottom: 1px solid #eaeaea; font-size: 18px; - color: #333; + color: #f7f7f7; } .delete-confirmation form input[type="submit"] { diff --git a/src/interface/static/admin/css/changelists.css b/src/interface/static/admin/css/changelists.css index f9b171c..9b0f4df 100644 --- a/src/interface/static/admin/css/changelists.css +++ b/src/interface/static/admin/css/changelists.css @@ -34,13 +34,13 @@ } #changelist .toplinks { - border-bottom: 1px solid #ddd; + border-bottom: 1px solid #363636; } #changelist .paginator { color: #666; - border-bottom: 1px solid #eee; - background: #fff; + border-bottom: 1px solid #363636; + background: #191919; overflow: hidden; } @@ -69,10 +69,10 @@ #changelist #toolbar { padding: 8px 10px; - margin-bottom: 15px; - border-top: 1px solid #eee; - border-bottom: 1px solid #eee; - background: #f8f8f8; + margin-bottom: 0px; + border-top: 1px solid #363636; + border-bottom: 1px solid #363636; + background: #000; color: #666; } @@ -127,7 +127,7 @@ right: 0; z-index: 1000; width: 240px; - background: #f8f8f8; + background: #000; border-left: none; margin: 0; } @@ -151,7 +151,7 @@ #changelist-filter ul { margin: 5px 0; padding: 0 15px 15px; - border-bottom: 1px solid #eaeaea; + border-bottom: 1px solid #282828; } #changelist-filter ul:last-child { @@ -172,9 +172,10 @@ } #changelist-filter li.selected { - border-left: 5px solid #eaeaea; + border-left: 5px solid #797979; padding-left: 10px; margin-left: -15px; + background-color: #282828; } #changelist-filter li.selected a { @@ -282,11 +283,11 @@ #changelist .actions { padding: 10px; - background: #fff; + background: #191919; border-top: none; border-bottom: none; line-height: 24px; - color: #999; + color: #fff; } #changelist .actions.selected { @@ -311,8 +312,8 @@ #changelist .actions select { vertical-align: top; height: 24px; - background: none; - color: #000; + background: #363636; + color: #fff; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; @@ -335,14 +336,14 @@ font-size: 13px; border: 1px solid #ccc; border-radius: 4px; - background: #fff; + background: #363636; box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; cursor: pointer; height: 24px; line-height: 1; padding: 4px 8px; margin: 0; - color: #333; + color: #fff; } #changelist .actions .button:focus, #changelist .actions .button:hover { diff --git a/src/interface/static/admin/css/forms.css b/src/interface/static/admin/css/forms.css index 06acd42..fb0c391 100644 --- a/src/interface/static/admin/css/forms.css +++ b/src/interface/static/admin/css/forms.css @@ -30,13 +30,13 @@ form .form-row p { label { font-weight: normal; - color: #666; + color: #fff; font-size: 13px; } .required label, label.required { font-weight: bold; - color: #333; + color: #999; } /* RADIO BUTTONS */ @@ -250,8 +250,8 @@ fieldset.monospace textarea { .submit-row { padding: 12px 14px; margin: 0 0 20px; - background: #f8f8f8; - border: 1px solid #eee; + background: #888888; + border: 1px solid #3f3f3f; border-radius: 4px; text-align: right; overflow: hidden; diff --git a/src/interface/static/admin/css/nav_sidebar.css b/src/interface/static/admin/css/nav_sidebar.css index be03db9..d8ca2e2 100644 --- a/src/interface/static/admin/css/nav_sidebar.css +++ b/src/interface/static/admin/css/nav_sidebar.css @@ -13,21 +13,22 @@ flex: 0 0 23px; width: 23px; border-right: 1px solid #eaeaea; - background-color: #ffffff; + background-color: #262626; cursor: pointer; font-size: 20px; color: #447e9b; padding: 0; + display: none !important; } [dir="rtl"] .toggle-nav-sidebar { - border-left: 1px solid #eaeaea; + border-left: 1px solid #262626; border-right: 0; } .toggle-nav-sidebar:hover, .toggle-nav-sidebar:focus { - background-color: #f6f6f6; + background-color: #000; } #nav-sidebar { @@ -37,7 +38,8 @@ margin-left: -276px; border-top: 1px solid transparent; border-right: 1px solid #eaeaea; - background-color: #ffffff; + border: 0px; + background-color: #282828; overflow: auto; } @@ -59,7 +61,7 @@ } .main.shifted > #nav-sidebar { - left: 24px; + left: 0px; margin-left: 0; } @@ -96,7 +98,7 @@ } #nav-sidebar .current-model { - background: #ffc; + background: #555555; } @media (max-width: 767px) { diff --git a/src/interface/static/css/main.css b/src/interface/static/css/main.css index 8e33bba..b30ccb1 100644 --- a/src/interface/static/css/main.css +++ b/src/interface/static/css/main.css @@ -10768,4 +10768,4 @@ a.nav_link { .progress_container { min-width: 300px !important; -} \ No newline at end of file +} diff --git a/src/interface/static/css/mobile.css b/src/interface/static/css/mobile.css index 841fd9d..b0fbf67 100644 --- a/src/interface/static/css/mobile.css +++ b/src/interface/static/css/mobile.css @@ -12,6 +12,27 @@ font-size: small; } .shelf_item{ + width: fit-content; + } + + #book_shelf { + justify-content: left; + flex-direction: column; + } + + .book_description { + display: none; + } + + .book_details_list { + display: grid; + grid-template-areas: + "book_title" + "book_author" + "book_tags" + "book_controls"; + grid-area: details; + grid-template-rows: .5fr .5fr .15fr 0.25fr; } } @@ -29,7 +50,8 @@ font-size: small; } .shelf_item{ - max-width: min-content; + min-width: 100%; + margin: 0px auto 10px auto; } .nav_search{ /* display: none !important; */ @@ -47,7 +69,6 @@ padding: 0px; margin: 0px 0px; } - .vert-nav-item {} #vert-nav { diff --git a/src/interface/static/js/pyshelf_ux.js b/src/interface/static/js/pyshelf_ux.js index df853ea..f52a811 100755 --- a/src/interface/static/js/pyshelf_ux.js +++ b/src/interface/static/js/pyshelf_ux.js @@ -33,6 +33,7 @@ $(document).ready(function(){ const navlink = $('.nav_link') const inputbox = $('input_box') const loginbtn = $('#btn_login') + const adminbtn = $('.admin-btn') const server = ('ws://127.0.0.1:1337') customlog([cmp_height]); $(".search_submit").click(function(){ @@ -170,6 +171,9 @@ $(document).ready(function(){ '' + '' + '

' + + '' + + '
' + + '
' + '' + '
' ); @@ -181,6 +185,7 @@ $(document).ready(function(){ $('#pop_over_0').dialog("open"); }); $(document).on('click', '.logout-btn', function(){window.location.href = '/logout'}); + $(document).on('click', '.admin-btn', function(){window.location.href = '/admin'}); //Web Socket Call $(document).on('click', '.import-btn', async function(){ diff --git a/src/interface/templates/index.html b/src/interface/templates/index.html index 731e7ab..612aca6 100755 --- a/src/interface/templates/index.html +++ b/src/interface/templates/index.html @@ -41,7 +41,7 @@ - + {% if request.user.is_authenticated %}