codex 1.7.3a2__py3-none-any.whl → 1.7.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of codex might be problematic. Click here for more details.
- codex/asgi.py +2 -1
- codex/choices/__init__.py +1 -0
- codex/{choices.py → choices/admin.py} +47 -146
- codex/choices/browser.py +85 -0
- codex/{choices_to_json.py → choices/choices_to_json.py} +25 -19
- codex/choices/notifications.py +16 -0
- codex/choices/reader.py +33 -0
- codex/db.py +2 -2
- codex/exceptions.py +7 -8
- codex/librarian/bookmark/bookmarkd.py +8 -4
- codex/librarian/bookmark/update.py +84 -49
- codex/librarian/covers/create.py +10 -8
- codex/librarian/covers/path.py +6 -5
- codex/librarian/covers/purge.py +4 -4
- codex/librarian/importer/aggregate.py +2 -2
- codex/librarian/importer/cache.py +1 -4
- codex/librarian/importer/create_comics.py +2 -2
- codex/librarian/importer/create_covers.py +1 -1
- codex/librarian/importer/create_fks.py +4 -3
- codex/librarian/importer/deleted.py +3 -3
- codex/librarian/importer/extract.py +56 -37
- codex/librarian/importer/failed_imports.py +1 -1
- codex/librarian/importer/importer.py +8 -3
- codex/librarian/importer/importerd.py +3 -3
- codex/librarian/importer/link_comics.py +2 -1
- codex/librarian/importer/moved.py +2 -7
- codex/librarian/importer/query_fks.py +1 -4
- codex/librarian/importer/tasks.py +1 -1
- codex/librarian/janitor/integrity.py +27 -20
- codex/librarian/janitor/janitor.py +1 -1
- codex/librarian/janitor/latest_version.py +1 -1
- codex/librarian/janitor/update.py +5 -2
- codex/librarian/janitor/vacuum.py +1 -1
- codex/librarian/librariand.py +3 -2
- codex/librarian/notifier/notifierd.py +2 -1
- codex/librarian/notifier/tasks.py +17 -3
- codex/librarian/search/optimize.py +1 -1
- codex/librarian/search/remove.py +1 -1
- codex/librarian/search/update.py +4 -4
- codex/librarian/telemeter/stats.py +7 -6
- codex/librarian/telemeter/telemeter.py +0 -1
- codex/librarian/watchdog/db_snapshot.py +3 -3
- codex/librarian/watchdog/dir_snapshot_diff.py +3 -4
- codex/librarian/watchdog/emitter.py +4 -4
- codex/librarian/watchdog/event_batcherd.py +2 -1
- codex/librarian/watchdog/events.py +1 -2
- codex/librarian/watchdog/observers.py +15 -10
- codex/logger/logging.py +1 -1
- codex/memory.py +3 -2
- codex/migrations/0001_init.py +1 -2
- codex/migrations/0014_pdf_issue_suffix_remove_cover_image_sort_name.py +1 -2
- codex/migrations/0018_rename_userbookmark_bookmark.py +1 -2
- codex/migrations/0028_telemeter.py +1 -5
- codex/models/base.py +3 -1
- codex/models/bookmark.py +4 -7
- codex/models/comic.py +2 -2
- codex/models/functions.py +12 -5
- codex/models/groups.py +1 -1
- codex/models/library.py +1 -1
- codex/models/paths.py +4 -4
- codex/models/query.py +8 -4
- codex/models/util.py +1 -1
- codex/permissions.py +1 -1
- codex/run.py +1 -1
- codex/serializers/admin/libraries.py +1 -3
- codex/serializers/admin/stats.py +4 -4
- codex/serializers/admin/tasks.py +12 -2
- codex/serializers/auth.py +4 -2
- codex/serializers/browser/choices.py +87 -9
- codex/serializers/browser/filters.py +9 -37
- codex/serializers/browser/metadata.py +2 -1
- codex/serializers/browser/mixins.py +7 -3
- codex/serializers/browser/mtime.py +3 -5
- codex/serializers/browser/page.py +5 -4
- codex/serializers/browser/settings.py +8 -6
- codex/serializers/fields/__init__.py +37 -0
- codex/serializers/fields/auth.py +45 -0
- codex/serializers/fields/browser.py +85 -0
- codex/serializers/fields/group.py +13 -0
- codex/serializers/fields/reader.py +22 -0
- codex/serializers/fields/sanitized.py +13 -0
- codex/serializers/fields/session.py +16 -0
- codex/serializers/fields/stats.py +36 -0
- codex/serializers/fields/vuetify.py +62 -0
- codex/serializers/models/base.py +1 -1
- codex/serializers/models/comic.py +2 -2
- codex/serializers/models/groups.py +0 -2
- codex/serializers/models/named.py +1 -1
- codex/serializers/models/pycountry.py +1 -1
- codex/serializers/opds/authentication.py +4 -2
- codex/serializers/opds/urls.py +2 -1
- codex/serializers/opds/v1.py +4 -3
- codex/serializers/opds/v2/feed.py +2 -1
- codex/serializers/opds/v2/links.py +23 -21
- codex/serializers/opds/v2/metadata.py +4 -8
- codex/serializers/opds/v2/progression.py +5 -3
- codex/serializers/opds/v2/publication.py +16 -18
- codex/serializers/opds/v2/unused.py +15 -8
- codex/serializers/reader.py +16 -14
- codex/serializers/redirect.py +2 -1
- codex/serializers/route.py +6 -4
- codex/serializers/settings.py +5 -3
- codex/serializers/versions.py +2 -1
- codex/settings/settings.py +4 -3
- codex/signals/django_signals.py +1 -1
- codex/startup.py +2 -2
- codex/static_root/assets/{VCheckbox-FaT6MGfu.f6732060f734.js → VCheckbox-CWBDr4kF.6da5bf3a4d90.js} +1 -1
- codex/static_root/assets/VCheckbox-CWBDr4kF.6da5bf3a4d90.js.br +0 -0
- codex/static_root/assets/VCheckbox-CWBDr4kF.6da5bf3a4d90.js.gz +0 -0
- codex/static_root/assets/{VCheckbox-FaT6MGfu.js → VCheckbox-CWBDr4kF.js} +1 -1
- codex/static_root/assets/VCheckbox-CWBDr4kF.js.br +0 -0
- codex/static_root/assets/VCheckbox-CWBDr4kF.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-CZ_P-qUM.847452d574cf.js → VCheckboxBtn-COaoh3uF.fc880a386827.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-COaoh3uF.fc880a386827.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-COaoh3uF.fc880a386827.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-CZ_P-qUM.js → VCheckboxBtn-COaoh3uF.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-COaoh3uF.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-COaoh3uF.js.gz +0 -0
- codex/static_root/assets/{VCombobox-C8QLNlSl.6f431e19a453.js → VCombobox-DkOruNH0.f30f163ee632.js} +1 -1
- codex/static_root/assets/VCombobox-DkOruNH0.f30f163ee632.js.br +0 -0
- codex/static_root/assets/VCombobox-DkOruNH0.f30f163ee632.js.gz +0 -0
- codex/static_root/assets/{VCombobox-C8QLNlSl.js → VCombobox-DkOruNH0.js} +1 -1
- codex/static_root/assets/VCombobox-DkOruNH0.js.br +0 -0
- codex/static_root/assets/VCombobox-DkOruNH0.js.gz +0 -0
- codex/static_root/assets/{VDialog-RVLeW7je.c0c7eef71eec.js → VDialog-Dr7SuC2S.b6ec7df390f4.js} +1 -1
- codex/static_root/assets/VDialog-Dr7SuC2S.b6ec7df390f4.js.br +0 -0
- codex/static_root/assets/VDialog-Dr7SuC2S.b6ec7df390f4.js.gz +0 -0
- codex/static_root/assets/{VDialog-RVLeW7je.js → VDialog-Dr7SuC2S.js} +1 -1
- codex/static_root/assets/VDialog-Dr7SuC2S.js.br +0 -0
- codex/static_root/assets/VDialog-Dr7SuC2S.js.gz +0 -0
- codex/static_root/assets/{VDivider-D1Ot4vR2.9dbee744fb3c.js → VDivider-By4u2EsM.fd5ee9cce906.js} +1 -1
- codex/static_root/assets/VDivider-By4u2EsM.fd5ee9cce906.js.br +0 -0
- codex/static_root/assets/VDivider-By4u2EsM.fd5ee9cce906.js.gz +0 -0
- codex/static_root/assets/{VDivider-D1Ot4vR2.js → VDivider-By4u2EsM.js} +1 -1
- codex/static_root/assets/VDivider-By4u2EsM.js.br +0 -0
- codex/static_root/assets/VDivider-By4u2EsM.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-DQilGHZk.43f06d0a45e0.js → VExpansionPanels-BhO9oj0a.e99bea455c78.js} +1 -1
- codex/static_root/assets/VExpansionPanels-BhO9oj0a.e99bea455c78.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BhO9oj0a.e99bea455c78.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-DQilGHZk.js → VExpansionPanels-BhO9oj0a.js} +1 -1
- codex/static_root/assets/VExpansionPanels-BhO9oj0a.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BhO9oj0a.js.gz +0 -0
- codex/static_root/assets/VForm-XhA6T0Lc.70c9c6fcb9e3.js +1 -0
- codex/static_root/assets/VForm-XhA6T0Lc.70c9c6fcb9e3.js.br +0 -0
- codex/static_root/assets/VForm-XhA6T0Lc.70c9c6fcb9e3.js.gz +0 -0
- codex/static_root/assets/VForm-XhA6T0Lc.js +1 -0
- codex/static_root/assets/VForm-XhA6T0Lc.js.br +0 -0
- codex/static_root/assets/VForm-XhA6T0Lc.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-DoayJpcS.fe5e0e74ffee.js → VRadioGroup-C1WCG0rO.6ebc88e4f144.js} +1 -1
- codex/static_root/assets/VRadioGroup-C1WCG0rO.6ebc88e4f144.js.br +3 -0
- codex/static_root/assets/VRadioGroup-C1WCG0rO.6ebc88e4f144.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-DoayJpcS.js → VRadioGroup-C1WCG0rO.js} +1 -1
- codex/static_root/assets/VRadioGroup-C1WCG0rO.js.br +3 -0
- codex/static_root/assets/VRadioGroup-C1WCG0rO.js.gz +0 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.ec45ee26818a.js +1 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.ec45ee26818a.js.br +0 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.ec45ee26818a.js.gz +0 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.js +1 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.js.br +0 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-TaKCeZgb.ad6c96efe57c.js → VSelectionControl-BkZZAsWo.ba6eca944e2e.js} +1 -1
- codex/static_root/assets/VSelectionControl-BkZZAsWo.ba6eca944e2e.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BkZZAsWo.ba6eca944e2e.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-TaKCeZgb.js → VSelectionControl-BkZZAsWo.js} +1 -1
- codex/static_root/assets/VSelectionControl-BkZZAsWo.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BkZZAsWo.js.gz +0 -0
- codex/static_root/assets/{VTable-BfcOiEpa.77ef3973bb54.js → VTable-D7P2eIc2.5e94bf2a515b.js} +1 -1
- codex/static_root/assets/VTable-D7P2eIc2.5e94bf2a515b.js.br +0 -0
- codex/static_root/assets/VTable-D7P2eIc2.5e94bf2a515b.js.gz +0 -0
- codex/static_root/assets/{VTable-BfcOiEpa.js → VTable-D7P2eIc2.js} +1 -1
- codex/static_root/assets/VTable-D7P2eIc2.js.br +0 -0
- codex/static_root/assets/VTable-D7P2eIc2.js.gz +0 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.e77444188aa3.js +1 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.e77444188aa3.js.br +0 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.e77444188aa3.js.gz +0 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.js +1 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.js.br +0 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.js.gz +0 -0
- codex/static_root/assets/{admin-80eqCqtz.d6deb9edb8cb.js → admin-B4z2nA5P.da0c92500311.js} +1 -1
- codex/static_root/assets/admin-B4z2nA5P.da0c92500311.js.br +0 -0
- codex/static_root/assets/admin-B4z2nA5P.da0c92500311.js.gz +0 -0
- codex/static_root/assets/{admin-80eqCqtz.js → admin-B4z2nA5P.js} +1 -1
- codex/static_root/assets/admin-B4z2nA5P.js.br +0 -0
- codex/static_root/assets/admin-B4z2nA5P.js.gz +0 -0
- codex/static_root/assets/admin-BhW3PNO0.e444048e548d.js +1 -0
- codex/static_root/assets/admin-BhW3PNO0.e444048e548d.js.br +0 -0
- codex/static_root/assets/admin-BhW3PNO0.e444048e548d.js.gz +0 -0
- codex/static_root/assets/admin-BhW3PNO0.js +1 -0
- codex/static_root/assets/admin-BhW3PNO0.js.br +0 -0
- codex/static_root/assets/admin-BhW3PNO0.js.gz +0 -0
- codex/static_root/assets/{admin-menu-_aAGknKO.0c08c9bd2e7d.js → admin-menu-CL7S-xqR.92b6d84c4b70.js} +1 -1
- codex/static_root/assets/admin-menu-CL7S-xqR.92b6d84c4b70.js.br +0 -0
- codex/static_root/assets/admin-menu-CL7S-xqR.92b6d84c4b70.js.gz +0 -0
- codex/static_root/assets/{admin-menu-_aAGknKO.js → admin-menu-CL7S-xqR.js} +1 -1
- codex/static_root/assets/admin-menu-CL7S-xqR.js.br +0 -0
- codex/static_root/assets/admin-menu-CL7S-xqR.js.gz +0 -0
- codex/static_root/assets/{admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js → admin-settings-button-progress-BgBgdELw.52d052e38bc1.js} +1 -1
- codex/static_root/assets/admin-settings-button-progress-BgBgdELw.52d052e38bc1.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-BgBgdELw.52d052e38bc1.js.gz +0 -0
- codex/static_root/assets/{admin-settings-button-progress-BqRFyhjf.js → admin-settings-button-progress-BgBgdELw.js} +1 -1
- codex/static_root/assets/admin-settings-button-progress-BgBgdELw.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-BgBgdELw.js.gz +0 -0
- codex/static_root/assets/browser-Bi5ov5k8.a4af87c2a667.js +1 -0
- codex/static_root/assets/browser-Bi5ov5k8.a4af87c2a667.js.br +0 -0
- codex/static_root/assets/browser-Bi5ov5k8.a4af87c2a667.js.gz +0 -0
- codex/static_root/assets/browser-Bi5ov5k8.js +1 -0
- codex/static_root/assets/browser-Bi5ov5k8.js.br +0 -0
- codex/static_root/assets/browser-Bi5ov5k8.js.gz +0 -0
- codex/static_root/assets/{browser-chTZ1CM4.521193ab0710.css → browser-DNzQvgkY.aea8b7d7ca40.css} +1 -1
- codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.br +0 -0
- codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.gz +0 -0
- codex/static_root/assets/{browser-chTZ1CM4.css → browser-DNzQvgkY.css} +1 -1
- codex/static_root/assets/browser-DNzQvgkY.css.br +0 -0
- codex/static_root/assets/browser-DNzQvgkY.css.gz +0 -0
- codex/static_root/assets/{change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js → change-password-dialog-BKar2Bhb.3dbc2feb3c5a.js} +1 -1
- codex/static_root/assets/change-password-dialog-BKar2Bhb.3dbc2feb3c5a.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BKar2Bhb.3dbc2feb3c5a.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-1ZVP_Q2w.js → change-password-dialog-BKar2Bhb.js} +1 -1
- codex/static_root/assets/change-password-dialog-BKar2Bhb.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BKar2Bhb.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-DqCey9Iq.e315d7f8f752.js → confirm-dialog-BoBL4OoS.abef9614fea9.js} +1 -1
- codex/static_root/assets/confirm-dialog-BoBL4OoS.abef9614fea9.js.br +0 -0
- codex/static_root/assets/confirm-dialog-BoBL4OoS.abef9614fea9.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-DqCey9Iq.js → confirm-dialog-BoBL4OoS.js} +1 -1
- codex/static_root/assets/confirm-dialog-BoBL4OoS.js.br +0 -0
- codex/static_root/assets/confirm-dialog-BoBL4OoS.js.gz +0 -0
- codex/static_root/assets/{datetime-column-CBA8bYeO.17a31f189d66.js → datetime-column-BsiYRUKO.cadd764c06f4.js} +1 -1
- codex/static_root/assets/datetime-column-BsiYRUKO.cadd764c06f4.js.br +0 -0
- codex/static_root/assets/datetime-column-BsiYRUKO.cadd764c06f4.js.gz +0 -0
- codex/static_root/assets/{datetime-column-CBA8bYeO.js → datetime-column-BsiYRUKO.js} +1 -1
- codex/static_root/assets/datetime-column-BsiYRUKO.js.br +0 -0
- codex/static_root/assets/datetime-column-BsiYRUKO.js.gz +0 -0
- codex/static_root/assets/{filter-mnO3lLPo.659442401b16.js → filter-HnY0knto.07f807227dcc.js} +1 -1
- codex/static_root/assets/filter-HnY0knto.07f807227dcc.js.br +0 -0
- codex/static_root/assets/filter-HnY0knto.07f807227dcc.js.gz +0 -0
- codex/static_root/assets/{filter-mnO3lLPo.js → filter-HnY0knto.js} +1 -1
- codex/static_root/assets/filter-HnY0knto.js.br +0 -0
- codex/static_root/assets/filter-HnY0knto.js.gz +0 -0
- codex/static_root/assets/{flag-tab-Bc677pNb.1b8a2f7c0dc3.js → flag-tab-CcS5pve2.a1df5d92e222.js} +1 -1
- codex/static_root/assets/flag-tab-CcS5pve2.a1df5d92e222.js.br +0 -0
- codex/static_root/assets/flag-tab-CcS5pve2.a1df5d92e222.js.gz +0 -0
- codex/static_root/assets/{flag-tab-Bc677pNb.js → flag-tab-CcS5pve2.js} +1 -1
- codex/static_root/assets/flag-tab-CcS5pve2.js.br +0 -0
- codex/static_root/assets/flag-tab-CcS5pve2.js.gz +0 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css +1 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.br +0 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.gz +0 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.css +1 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.css.br +0 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.css.gz +0 -0
- codex/static_root/assets/{forwardRefs-DPRKg5wq.6f09e9d22fa6.js → forwardRefs-i80xmxX3.db393aeef392.js} +1 -1
- codex/static_root/assets/forwardRefs-i80xmxX3.db393aeef392.js.br +0 -0
- codex/static_root/assets/forwardRefs-i80xmxX3.db393aeef392.js.gz +0 -0
- codex/static_root/assets/{forwardRefs-DPRKg5wq.js → forwardRefs-i80xmxX3.js} +1 -1
- codex/static_root/assets/forwardRefs-i80xmxX3.js.br +0 -0
- codex/static_root/assets/forwardRefs-i80xmxX3.js.gz +0 -0
- codex/static_root/assets/group-tab-SY0gxmHW.f72e944c0ff1.js +1 -0
- codex/static_root/assets/group-tab-SY0gxmHW.f72e944c0ff1.js.br +0 -0
- codex/static_root/assets/group-tab-SY0gxmHW.f72e944c0ff1.js.gz +0 -0
- codex/static_root/assets/group-tab-SY0gxmHW.js +1 -0
- codex/static_root/assets/group-tab-SY0gxmHW.js.br +0 -0
- codex/static_root/assets/group-tab-SY0gxmHW.js.gz +0 -0
- codex/static_root/assets/http-error-EE8gtq5A.07e291d9d955.js +1 -0
- codex/static_root/assets/http-error-EE8gtq5A.07e291d9d955.js.br +0 -0
- codex/static_root/assets/http-error-EE8gtq5A.07e291d9d955.js.gz +0 -0
- codex/static_root/assets/http-error-EE8gtq5A.js +1 -0
- codex/static_root/assets/http-error-EE8gtq5A.js.br +0 -0
- codex/static_root/assets/http-error-EE8gtq5A.js.gz +0 -0
- codex/static_root/assets/{index-9nBCksDQ.4561d2608773.js → index-gVdawuuE.a940fadbac00.js} +1 -1
- codex/static_root/assets/index-gVdawuuE.a940fadbac00.js.br +0 -0
- codex/static_root/assets/index-gVdawuuE.a940fadbac00.js.gz +0 -0
- codex/static_root/assets/{index-9nBCksDQ.js → index-gVdawuuE.js} +1 -1
- codex/static_root/assets/index-gVdawuuE.js.br +0 -0
- codex/static_root/assets/index-gVdawuuE.js.gz +0 -0
- codex/static_root/assets/library-tab-BkDIAvyS.4b4c606b77d6.js +1 -0
- codex/static_root/assets/library-tab-BkDIAvyS.4b4c606b77d6.js.br +0 -0
- codex/static_root/assets/library-tab-BkDIAvyS.4b4c606b77d6.js.gz +0 -0
- codex/static_root/assets/library-tab-BkDIAvyS.js +1 -0
- codex/static_root/assets/library-tab-BkDIAvyS.js.br +0 -0
- codex/static_root/assets/library-tab-BkDIAvyS.js.gz +0 -0
- codex/static_root/assets/main-B5uflU6E.77f3fcd6873f.js +35 -0
- codex/static_root/assets/main-B5uflU6E.77f3fcd6873f.js.br +0 -0
- codex/static_root/assets/main-B5uflU6E.77f3fcd6873f.js.gz +0 -0
- codex/static_root/assets/main-B5uflU6E.js +35 -0
- codex/static_root/assets/main-B5uflU6E.js.br +0 -0
- codex/static_root/assets/main-B5uflU6E.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.111d9b9d4133.js +1 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.111d9b9d4133.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.111d9b9d4133.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.js +1 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js → pagination-toolbar-D3JQmDiD.8513a4db85f0.js} +1 -1
- codex/static_root/assets/pagination-toolbar-D3JQmDiD.8513a4db85f0.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-D3JQmDiD.8513a4db85f0.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-Dx5JwWG-.js → pagination-toolbar-D3JQmDiD.js} +1 -1
- codex/static_root/assets/pagination-toolbar-D3JQmDiD.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-D3JQmDiD.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-6ZE_HmLT.10d1e16abc78.js → pdf-doc-DRBtl9_2.225a6d89e842.js} +1 -1
- codex/static_root/assets/pdf-doc-DRBtl9_2.225a6d89e842.js.br +0 -0
- codex/static_root/assets/pdf-doc-DRBtl9_2.225a6d89e842.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-6ZE_HmLT.js → pdf-doc-DRBtl9_2.js} +1 -1
- codex/static_root/assets/pdf-doc-DRBtl9_2.js.br +0 -0
- codex/static_root/assets/pdf-doc-DRBtl9_2.js.gz +0 -0
- codex/static_root/assets/reader-DycvjN42.3e2b4f43235e.js +2 -0
- codex/static_root/assets/reader-DycvjN42.3e2b4f43235e.js.br +0 -0
- codex/static_root/assets/reader-DycvjN42.3e2b4f43235e.js.gz +0 -0
- codex/static_root/assets/reader-DycvjN42.js +2 -0
- codex/static_root/assets/reader-DycvjN42.js.br +0 -0
- codex/static_root/assets/reader-DycvjN42.js.gz +0 -0
- codex/static_root/assets/{relation-chips-C96hi5jm.js → relation-chips-CeHIEjvZ.04d302f4fa89.js} +1 -1
- codex/static_root/assets/relation-chips-CeHIEjvZ.04d302f4fa89.js.br +0 -0
- codex/static_root/assets/relation-chips-CeHIEjvZ.04d302f4fa89.js.gz +0 -0
- codex/static_root/assets/{relation-chips-C96hi5jm.9f07c9eb533a.js → relation-chips-CeHIEjvZ.js} +1 -1
- codex/static_root/assets/relation-chips-CeHIEjvZ.js.br +0 -0
- codex/static_root/assets/relation-chips-CeHIEjvZ.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.48dfaafaa00e.js +2 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.48dfaafaa00e.js.br +0 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.48dfaafaa00e.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.js +2 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.js.br +0 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.js.gz +0 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.3b5868abdd61.js +1 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.3b5868abdd61.js.br +0 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.3b5868abdd61.js.gz +0 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.js +1 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.js.br +0 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.js.gz +0 -0
- codex/static_root/assets/{stats-tab-CkT2ZGUQ.b704fa46dc88.js → stats-tab-C1XYGBKj.812896e1d09c.js} +1 -1
- codex/static_root/assets/stats-tab-C1XYGBKj.812896e1d09c.js.br +0 -0
- codex/static_root/assets/stats-tab-C1XYGBKj.812896e1d09c.js.gz +0 -0
- codex/static_root/assets/{stats-tab-CkT2ZGUQ.js → stats-tab-C1XYGBKj.js} +1 -1
- codex/static_root/assets/stats-tab-C1XYGBKj.js.br +0 -0
- codex/static_root/assets/stats-tab-C1XYGBKj.js.gz +0 -0
- codex/static_root/assets/task-tab-CW4DQ3KN.81812f9208e5.css +1 -0
- codex/static_root/assets/{task-tab-DfdUY9Rc.478e74041f80.css.br → task-tab-CW4DQ3KN.81812f9208e5.css.br} +1 -1
- codex/static_root/assets/task-tab-CW4DQ3KN.81812f9208e5.css.gz +0 -0
- codex/static_root/assets/task-tab-CW4DQ3KN.css +1 -0
- codex/static_root/assets/{task-tab-DfdUY9Rc.css.br → task-tab-CW4DQ3KN.css.br} +1 -1
- codex/static_root/assets/task-tab-CW4DQ3KN.css.gz +0 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.6b90f40a1a9f.js +1 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.6b90f40a1a9f.js.br +0 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.6b90f40a1a9f.js.gz +0 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.js +1 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.js.br +0 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.js.gz +0 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.4e675fd9991c.js +1 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.4e675fd9991c.js.br +0 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.4e675fd9991c.js.gz +0 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.js +1 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.js.br +0 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.js.gz +0 -0
- codex/static_root/assets/user-tab-CN9nBOMS.f88d8b1c8afe.js +1 -0
- codex/static_root/assets/user-tab-CN9nBOMS.f88d8b1c8afe.js.br +0 -0
- codex/static_root/assets/user-tab-CN9nBOMS.f88d8b1c8afe.js.gz +0 -0
- codex/static_root/assets/user-tab-CN9nBOMS.js +1 -0
- codex/static_root/assets/user-tab-CN9nBOMS.js.br +0 -0
- codex/static_root/assets/user-tab-CN9nBOMS.js.gz +0 -0
- codex/static_root/{manifest.225989a17f49.json → manifest.66d7229aa07a.json} +297 -277
- codex/static_root/manifest.66d7229aa07a.json.br +0 -0
- codex/static_root/manifest.66d7229aa07a.json.gz +0 -0
- codex/static_root/manifest.json +297 -277
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/status_controller.py +10 -13
- codex/urls/root.py +4 -3
- codex/views/admin/api_key.py +1 -4
- codex/views/admin/flag.py +2 -2
- codex/views/admin/group.py +2 -2
- codex/views/admin/library.py +4 -4
- codex/views/admin/stats.py +10 -10
- codex/views/admin/tasks.py +32 -13
- codex/views/admin/user.py +36 -10
- codex/views/auth.py +3 -8
- codex/views/bookmark.py +3 -3
- codex/views/browser/annotate/card.py +2 -2
- codex/views/browser/annotate/order.py +6 -7
- codex/views/browser/bookmark.py +3 -1
- codex/views/browser/breadcrumbs.py +6 -5
- codex/views/browser/browser.py +2 -2
- codex/views/browser/choices.py +7 -8
- codex/views/browser/cover.py +6 -3
- codex/views/browser/download.py +2 -1
- codex/views/browser/filters/bookmark.py +1 -1
- codex/views/browser/filters/field.py +1 -1
- codex/views/browser/filters/filter.py +6 -8
- codex/views/browser/filters/group.py +8 -8
- codex/views/browser/filters/search/field/expression.py +1 -2
- codex/views/browser/filters/search/field/optimize.py +1 -1
- codex/views/browser/filters/search/field/parse.py +2 -2
- codex/views/browser/filters/search/parse.py +4 -19
- codex/views/browser/group_mtime.py +1 -1
- codex/views/browser/metadata/copy_intersections.py +1 -1
- codex/views/browser/metadata/metadata.py +1 -1
- codex/views/browser/mtime.py +1 -1
- codex/views/browser/order_by.py +3 -5
- codex/views/browser/params.py +1 -1
- codex/views/browser/settings.py +1 -1
- codex/views/browser/validate.py +9 -6
- codex/views/const.py +0 -3
- codex/views/frontend.py +1 -1
- codex/views/mixins.py +3 -2
- codex/views/opds/authentication_v1.py +1 -1
- codex/views/opds/const.py +4 -4
- codex/views/opds/urls.py +1 -1
- codex/views/opds/util.py +4 -4
- codex/views/opds/v1/entry/entry.py +4 -2
- codex/views/opds/v1/entry/links.py +4 -5
- codex/views/opds/v1/facets.py +8 -4
- codex/views/opds/v1/feed.py +5 -5
- codex/views/opds/v1/links.py +11 -6
- codex/views/opds/v2/const.py +5 -2
- codex/views/opds/v2/feed.py +3 -3
- codex/views/opds/v2/links.py +18 -11
- codex/views/opds/v2/progression.py +8 -9
- codex/views/opds/v2/publications.py +10 -20
- codex/views/public.py +2 -2
- codex/views/reader/books.py +3 -2
- codex/views/reader/page.py +3 -3
- codex/views/reader/params.py +2 -2
- codex/views/reader/reader.py +6 -6
- codex/views/reader/settings.py +1 -1
- codex/views/session.py +10 -3
- codex/views/settings.py +2 -2
- codex/views/timezone.py +2 -2
- codex/views/util.py +10 -9
- codex/views/version.py +1 -1
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/METADATA +3 -1
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/RECORD +433 -415
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/WHEEL +1 -1
- codex/serializers/fields.py +0 -183
- codex/static_root/assets/VCheckbox-FaT6MGfu.f6732060f734.js.br +0 -0
- codex/static_root/assets/VCheckbox-FaT6MGfu.f6732060f734.js.gz +0 -0
- codex/static_root/assets/VCheckbox-FaT6MGfu.js.br +0 -0
- codex/static_root/assets/VCheckbox-FaT6MGfu.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.847452d574cf.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.847452d574cf.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.js.gz +0 -0
- codex/static_root/assets/VCombobox-C8QLNlSl.6f431e19a453.js.br +0 -0
- codex/static_root/assets/VCombobox-C8QLNlSl.6f431e19a453.js.gz +0 -0
- codex/static_root/assets/VCombobox-C8QLNlSl.js.br +0 -0
- codex/static_root/assets/VCombobox-C8QLNlSl.js.gz +0 -0
- codex/static_root/assets/VDialog-RVLeW7je.c0c7eef71eec.js.br +0 -0
- codex/static_root/assets/VDialog-RVLeW7je.c0c7eef71eec.js.gz +0 -0
- codex/static_root/assets/VDialog-RVLeW7je.js.br +0 -0
- codex/static_root/assets/VDialog-RVLeW7je.js.gz +0 -0
- codex/static_root/assets/VDivider-D1Ot4vR2.9dbee744fb3c.js.br +0 -0
- codex/static_root/assets/VDivider-D1Ot4vR2.9dbee744fb3c.js.gz +0 -0
- codex/static_root/assets/VDivider-D1Ot4vR2.js.br +0 -0
- codex/static_root/assets/VDivider-D1Ot4vR2.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DQilGHZk.43f06d0a45e0.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DQilGHZk.43f06d0a45e0.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DQilGHZk.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DQilGHZk.js.gz +0 -0
- codex/static_root/assets/VForm-DNmY-qFJ.81f3a5ff7ec3.js +0 -1
- codex/static_root/assets/VForm-DNmY-qFJ.81f3a5ff7ec3.js.br +0 -0
- codex/static_root/assets/VForm-DNmY-qFJ.81f3a5ff7ec3.js.gz +0 -0
- codex/static_root/assets/VForm-DNmY-qFJ.js +0 -1
- codex/static_root/assets/VForm-DNmY-qFJ.js.br +0 -0
- codex/static_root/assets/VForm-DNmY-qFJ.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-DoayJpcS.fe5e0e74ffee.js.br +0 -0
- codex/static_root/assets/VRadioGroup-DoayJpcS.fe5e0e74ffee.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-DoayJpcS.js.br +0 -0
- codex/static_root/assets/VRadioGroup-DoayJpcS.js.gz +0 -0
- codex/static_root/assets/VSelect-BSLmHX_P.9ab865ec0fad.js +0 -1
- codex/static_root/assets/VSelect-BSLmHX_P.9ab865ec0fad.js.br +0 -0
- codex/static_root/assets/VSelect-BSLmHX_P.9ab865ec0fad.js.gz +0 -0
- codex/static_root/assets/VSelect-BSLmHX_P.js +0 -1
- codex/static_root/assets/VSelect-BSLmHX_P.js.br +0 -0
- codex/static_root/assets/VSelect-BSLmHX_P.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-TaKCeZgb.ad6c96efe57c.js.br +0 -0
- codex/static_root/assets/VSelectionControl-TaKCeZgb.ad6c96efe57c.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-TaKCeZgb.js.br +0 -0
- codex/static_root/assets/VSelectionControl-TaKCeZgb.js.gz +0 -0
- codex/static_root/assets/VTable-BfcOiEpa.77ef3973bb54.js.br +0 -0
- codex/static_root/assets/VTable-BfcOiEpa.77ef3973bb54.js.gz +0 -0
- codex/static_root/assets/VTable-BfcOiEpa.js.br +0 -0
- codex/static_root/assets/VTable-BfcOiEpa.js.gz +0 -0
- codex/static_root/assets/VWindowItem-D8lWcbQY.e4c75ad78718.js +0 -1
- codex/static_root/assets/VWindowItem-D8lWcbQY.e4c75ad78718.js.br +0 -0
- codex/static_root/assets/VWindowItem-D8lWcbQY.e4c75ad78718.js.gz +0 -0
- codex/static_root/assets/VWindowItem-D8lWcbQY.js +0 -1
- codex/static_root/assets/VWindowItem-D8lWcbQY.js.br +0 -0
- codex/static_root/assets/VWindowItem-D8lWcbQY.js.gz +0 -0
- codex/static_root/assets/admin-80eqCqtz.d6deb9edb8cb.js.br +0 -0
- codex/static_root/assets/admin-80eqCqtz.d6deb9edb8cb.js.gz +0 -0
- codex/static_root/assets/admin-80eqCqtz.js.br +0 -0
- codex/static_root/assets/admin-80eqCqtz.js.gz +0 -0
- codex/static_root/assets/admin-CBLHOrM9.8c3c2268bc96.js +0 -1
- codex/static_root/assets/admin-CBLHOrM9.8c3c2268bc96.js.br +0 -0
- codex/static_root/assets/admin-CBLHOrM9.8c3c2268bc96.js.gz +0 -0
- codex/static_root/assets/admin-CBLHOrM9.js +0 -1
- codex/static_root/assets/admin-CBLHOrM9.js.br +0 -0
- codex/static_root/assets/admin-CBLHOrM9.js.gz +0 -0
- codex/static_root/assets/admin-menu-_aAGknKO.0c08c9bd2e7d.js.br +0 -0
- codex/static_root/assets/admin-menu-_aAGknKO.0c08c9bd2e7d.js.gz +0 -0
- codex/static_root/assets/admin-menu-_aAGknKO.js.br +0 -0
- codex/static_root/assets/admin-menu-_aAGknKO.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.js.gz +0 -0
- codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js +0 -1
- codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js.br +0 -0
- codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js.gz +0 -0
- codex/static_root/assets/browser-DAprXYuP.js +0 -1
- codex/static_root/assets/browser-DAprXYuP.js.br +0 -0
- codex/static_root/assets/browser-DAprXYuP.js.gz +0 -0
- codex/static_root/assets/browser-chTZ1CM4.521193ab0710.css.br +0 -0
- codex/static_root/assets/browser-chTZ1CM4.521193ab0710.css.gz +0 -0
- codex/static_root/assets/browser-chTZ1CM4.css.br +0 -0
- codex/static_root/assets/browser-chTZ1CM4.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js.br +0 -0
- codex/static_root/assets/change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-1ZVP_Q2w.js.br +0 -0
- codex/static_root/assets/change-password-dialog-1ZVP_Q2w.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-DqCey9Iq.e315d7f8f752.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DqCey9Iq.e315d7f8f752.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-DqCey9Iq.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DqCey9Iq.js.gz +0 -0
- codex/static_root/assets/datetime-column-CBA8bYeO.17a31f189d66.js.br +0 -0
- codex/static_root/assets/datetime-column-CBA8bYeO.17a31f189d66.js.gz +0 -0
- codex/static_root/assets/datetime-column-CBA8bYeO.js.br +0 -0
- codex/static_root/assets/datetime-column-CBA8bYeO.js.gz +0 -0
- codex/static_root/assets/filter-mnO3lLPo.659442401b16.js.br +0 -0
- codex/static_root/assets/filter-mnO3lLPo.659442401b16.js.gz +0 -0
- codex/static_root/assets/filter-mnO3lLPo.js.br +0 -0
- codex/static_root/assets/filter-mnO3lLPo.js.gz +0 -0
- codex/static_root/assets/flag-tab-Bc677pNb.1b8a2f7c0dc3.js.br +0 -0
- codex/static_root/assets/flag-tab-Bc677pNb.1b8a2f7c0dc3.js.gz +0 -0
- codex/static_root/assets/flag-tab-Bc677pNb.js.br +0 -0
- codex/static_root/assets/flag-tab-Bc677pNb.js.gz +0 -0
- codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css +0 -1
- codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css.br +0 -0
- codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css.gz +0 -0
- codex/static_root/assets/flag-tab-glFvEgEl.css +0 -1
- codex/static_root/assets/flag-tab-glFvEgEl.css.br +0 -0
- codex/static_root/assets/flag-tab-glFvEgEl.css.gz +0 -0
- codex/static_root/assets/forwardRefs-DPRKg5wq.6f09e9d22fa6.js.br +0 -0
- codex/static_root/assets/forwardRefs-DPRKg5wq.6f09e9d22fa6.js.gz +0 -0
- codex/static_root/assets/forwardRefs-DPRKg5wq.js.br +0 -0
- codex/static_root/assets/forwardRefs-DPRKg5wq.js.gz +0 -0
- codex/static_root/assets/group-tab-BVlBrMwo.1127b51be6e7.js +0 -1
- codex/static_root/assets/group-tab-BVlBrMwo.1127b51be6e7.js.br +0 -0
- codex/static_root/assets/group-tab-BVlBrMwo.1127b51be6e7.js.gz +0 -0
- codex/static_root/assets/group-tab-BVlBrMwo.js +0 -1
- codex/static_root/assets/group-tab-BVlBrMwo.js.br +0 -0
- codex/static_root/assets/group-tab-BVlBrMwo.js.gz +0 -0
- codex/static_root/assets/http-error-C9-_aEBF.d29b164e80de.js +0 -1
- codex/static_root/assets/http-error-C9-_aEBF.d29b164e80de.js.br +0 -0
- codex/static_root/assets/http-error-C9-_aEBF.d29b164e80de.js.gz +0 -0
- codex/static_root/assets/http-error-C9-_aEBF.js +0 -1
- codex/static_root/assets/http-error-C9-_aEBF.js.br +0 -0
- codex/static_root/assets/http-error-C9-_aEBF.js.gz +0 -0
- codex/static_root/assets/index-9nBCksDQ.4561d2608773.js.br +0 -0
- codex/static_root/assets/index-9nBCksDQ.4561d2608773.js.gz +0 -0
- codex/static_root/assets/index-9nBCksDQ.js.br +0 -0
- codex/static_root/assets/index-9nBCksDQ.js.gz +0 -0
- codex/static_root/assets/library-tab-BMe3dKzy.22b6e123ecfb.js +0 -1
- codex/static_root/assets/library-tab-BMe3dKzy.22b6e123ecfb.js.br +0 -0
- codex/static_root/assets/library-tab-BMe3dKzy.22b6e123ecfb.js.gz +0 -0
- codex/static_root/assets/library-tab-BMe3dKzy.js +0 -1
- codex/static_root/assets/library-tab-BMe3dKzy.js.br +0 -0
- codex/static_root/assets/library-tab-BMe3dKzy.js.gz +0 -0
- codex/static_root/assets/main-BbNUiWEb.565b616eb122.js +0 -35
- codex/static_root/assets/main-BbNUiWEb.565b616eb122.js.br +0 -0
- codex/static_root/assets/main-BbNUiWEb.565b616eb122.js.gz +0 -0
- codex/static_root/assets/main-BbNUiWEb.js +0 -35
- codex/static_root/assets/main-BbNUiWEb.js.br +0 -0
- codex/static_root/assets/main-BbNUiWEb.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js +0 -1
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.js +0 -1
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Dx5JwWG-.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Dx5JwWG-.js.gz +0 -0
- codex/static_root/assets/pdf-doc-6ZE_HmLT.10d1e16abc78.js.br +0 -0
- codex/static_root/assets/pdf-doc-6ZE_HmLT.10d1e16abc78.js.gz +0 -0
- codex/static_root/assets/pdf-doc-6ZE_HmLT.js.br +0 -0
- codex/static_root/assets/pdf-doc-6ZE_HmLT.js.gz +0 -0
- codex/static_root/assets/reader-DdPKDuh5.0c55cef1e98b.js +0 -2
- codex/static_root/assets/reader-DdPKDuh5.0c55cef1e98b.js.br +0 -0
- codex/static_root/assets/reader-DdPKDuh5.0c55cef1e98b.js.gz +0 -0
- codex/static_root/assets/reader-DdPKDuh5.js +0 -2
- codex/static_root/assets/reader-DdPKDuh5.js.br +0 -0
- codex/static_root/assets/reader-DdPKDuh5.js.gz +0 -0
- codex/static_root/assets/relation-chips-C96hi5jm.9f07c9eb533a.js.br +0 -0
- codex/static_root/assets/relation-chips-C96hi5jm.9f07c9eb533a.js.gz +0 -0
- codex/static_root/assets/relation-chips-C96hi5jm.js.br +0 -0
- codex/static_root/assets/relation-chips-C96hi5jm.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CqbT1rid.5639fa00b301.js +0 -2
- codex/static_root/assets/settings-drawer-CqbT1rid.5639fa00b301.js.br +0 -0
- codex/static_root/assets/settings-drawer-CqbT1rid.5639fa00b301.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CqbT1rid.js +0 -2
- codex/static_root/assets/settings-drawer-CqbT1rid.js.br +0 -0
- codex/static_root/assets/settings-drawer-CqbT1rid.js.gz +0 -0
- codex/static_root/assets/stats-tab-CkT2ZGUQ.b704fa46dc88.js.br +0 -0
- codex/static_root/assets/stats-tab-CkT2ZGUQ.b704fa46dc88.js.gz +0 -0
- codex/static_root/assets/stats-tab-CkT2ZGUQ.js.br +0 -0
- codex/static_root/assets/stats-tab-CkT2ZGUQ.js.gz +0 -0
- codex/static_root/assets/task-tab-DfdUY9Rc.478e74041f80.css +0 -1
- codex/static_root/assets/task-tab-DfdUY9Rc.478e74041f80.css.gz +0 -0
- codex/static_root/assets/task-tab-DfdUY9Rc.css +0 -1
- codex/static_root/assets/task-tab-DfdUY9Rc.css.gz +0 -0
- codex/static_root/assets/task-tab-a-DcU3Tj.8c2f7bf3c4c9.js +0 -1
- codex/static_root/assets/task-tab-a-DcU3Tj.8c2f7bf3c4c9.js.br +0 -0
- codex/static_root/assets/task-tab-a-DcU3Tj.8c2f7bf3c4c9.js.gz +0 -0
- codex/static_root/assets/task-tab-a-DcU3Tj.js +0 -1
- codex/static_root/assets/task-tab-a-DcU3Tj.js.br +0 -0
- codex/static_root/assets/task-tab-a-DcU3Tj.js.gz +0 -0
- codex/static_root/assets/unauthorized-BOl5YpL3.f3c4b52718d5.js +0 -1
- codex/static_root/assets/unauthorized-BOl5YpL3.f3c4b52718d5.js.br +0 -0
- codex/static_root/assets/unauthorized-BOl5YpL3.f3c4b52718d5.js.gz +0 -0
- codex/static_root/assets/unauthorized-BOl5YpL3.js +0 -1
- codex/static_root/assets/unauthorized-BOl5YpL3.js.br +0 -0
- codex/static_root/assets/unauthorized-BOl5YpL3.js.gz +0 -0
- codex/static_root/assets/user-tab-BBDZvD8G.aa4263a68b22.js +0 -1
- codex/static_root/assets/user-tab-BBDZvD8G.aa4263a68b22.js.br +0 -0
- codex/static_root/assets/user-tab-BBDZvD8G.aa4263a68b22.js.gz +0 -0
- codex/static_root/assets/user-tab-BBDZvD8G.js +0 -1
- codex/static_root/assets/user-tab-BBDZvD8G.js.br +0 -0
- codex/static_root/assets/user-tab-BBDZvD8G.js.gz +0 -0
- codex/static_root/manifest.225989a17f49.json.br +0 -0
- codex/static_root/manifest.225989a17f49.json.gz +0 -0
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/LICENSE +0 -0
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/entry_points.txt +0 -0
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
"""Generated by Django 5.0.6 on 2024-07-02 21:01."""
|
|
2
2
|
|
|
3
|
-
from typing import ClassVar
|
|
4
|
-
|
|
5
3
|
from django.db import migrations, models
|
|
6
4
|
|
|
7
5
|
|
|
8
6
|
class Migration(migrations.Migration):
|
|
9
7
|
"""Migrate db."""
|
|
10
8
|
|
|
11
|
-
dependencies
|
|
12
|
-
("codex", "0027_import_order_and_covers"),
|
|
13
|
-
]
|
|
9
|
+
dependencies = [("codex", "0027_import_order_and_covers")]
|
|
14
10
|
|
|
15
11
|
operations = [
|
|
16
12
|
migrations.AlterField(
|
codex/models/base.py
CHANGED
|
@@ -27,9 +27,11 @@ class BaseModel(Model):
|
|
|
27
27
|
updated_at = DateTimeField(auto_now=True)
|
|
28
28
|
objects = GroupByManager()
|
|
29
29
|
|
|
30
|
-
class Meta(ModelBase): # type: ignore
|
|
30
|
+
class Meta(ModelBase): # type: ignore[reportIncompatibleVariableOverride]
|
|
31
31
|
"""Without this a real table is created and joined to."""
|
|
32
32
|
|
|
33
|
+
# Model.Meta is not inheritable.
|
|
34
|
+
|
|
33
35
|
abstract = True
|
|
34
36
|
get_latest_by = "updated_at"
|
|
35
37
|
|
codex/models/bookmark.py
CHANGED
|
@@ -23,18 +23,15 @@ def cascade_if_user_null(
|
|
|
23
23
|
sub_objs,
|
|
24
24
|
using, # noqa: ARG001
|
|
25
25
|
):
|
|
26
|
-
"""
|
|
26
|
+
"""
|
|
27
|
+
Cascade only if the user field is null.
|
|
27
28
|
|
|
28
29
|
Do this to keep deleting ephemeral session data from Bookmark table.
|
|
29
30
|
Adapted from:
|
|
30
31
|
https://github.com/django/django/blob/master/django/db/models/deletion.py#L23
|
|
31
32
|
"""
|
|
32
|
-
|
|
33
|
-
for sub_obj in sub_objs
|
|
34
|
-
# only cascade the ones with null user fields.
|
|
35
|
-
if sub_obj.user is None:
|
|
36
|
-
null_user_sub_objs.append(sub_obj)
|
|
37
|
-
|
|
33
|
+
# only cascade the ones with null user fields.
|
|
34
|
+
null_user_sub_objs = [sub_obj for sub_obj in sub_objs if sub_obj.user is None]
|
|
38
35
|
if null_user_sub_objs:
|
|
39
36
|
collector.collect(
|
|
40
37
|
null_user_sub_objs,
|
codex/models/comic.py
CHANGED
|
@@ -263,7 +263,7 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
263
263
|
|
|
264
264
|
@classmethod
|
|
265
265
|
def get_title(
|
|
266
|
-
cls, obj, volume
|
|
266
|
+
cls, obj, volume: bool, name: bool, filename_fallback: bool, zero_pad=None
|
|
267
267
|
):
|
|
268
268
|
"""Create the comic title for display."""
|
|
269
269
|
names = []
|
|
@@ -293,7 +293,7 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
293
293
|
|
|
294
294
|
def __str__(self):
|
|
295
295
|
"""Most common text representation for logging."""
|
|
296
|
-
return self.get_title(self, filename_fallback=True)
|
|
296
|
+
return self.get_title(self, volume=True, name=True, filename_fallback=True)
|
|
297
297
|
|
|
298
298
|
def issue(self) -> str:
|
|
299
299
|
"""Combine issue parts for search."""
|
codex/models/functions.py
CHANGED
|
@@ -14,7 +14,10 @@ class JsonGroupArray(Aggregate):
|
|
|
14
14
|
allow_distinct = True
|
|
15
15
|
function = "JSON_GROUP_ARRAY"
|
|
16
16
|
name = "JsonGroupArray"
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
def __init__(self, *args, **kwargs):
|
|
19
|
+
"""output_field is set in the constructor."""
|
|
20
|
+
super().__init__(*args, output_field=JSONField(), **kwargs)
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
class GroupConcat(Aggregate):
|
|
@@ -25,7 +28,10 @@ class GroupConcat(Aggregate):
|
|
|
25
28
|
allow_distinct = True
|
|
26
29
|
function = "GROUP_CONCAT"
|
|
27
30
|
name = "GroupConcat"
|
|
28
|
-
|
|
31
|
+
|
|
32
|
+
def __init__(self, *args, **kwargs):
|
|
33
|
+
"""output_field is set in the constructor."""
|
|
34
|
+
super().__init__(*args, output_field=CharField(), **kwargs)
|
|
29
35
|
|
|
30
36
|
|
|
31
37
|
@OneToOneField.register_lookup
|
|
@@ -36,8 +42,6 @@ class FTS5Match(Lookup):
|
|
|
36
42
|
|
|
37
43
|
def as_sql(self, compiler, connection):
|
|
38
44
|
"""Generate MATCH sql."""
|
|
39
|
-
# lhs, lhs_params = self.process_lhs(compiler, connection)
|
|
40
|
-
# fts_table = lhs.split(".")[0]
|
|
41
45
|
rhs, rhs_params = self.process_rhs(compiler, connection)
|
|
42
46
|
# MATCH works on the table itself not the one_to_one rel.
|
|
43
47
|
# Force the table name without substitutions by the optimizer
|
|
@@ -67,4 +71,7 @@ class ComicFTSRank(Func):
|
|
|
67
71
|
|
|
68
72
|
function = "rank"
|
|
69
73
|
template = '("codex_comicfts"."rank" * -1)'
|
|
70
|
-
|
|
74
|
+
|
|
75
|
+
def __init__(self, *args, **kwargs):
|
|
76
|
+
"""output_field is set in the constructor."""
|
|
77
|
+
super().__init__(*args, output_field=FloatField(), **kwargs)
|
codex/models/groups.py
CHANGED
|
@@ -136,7 +136,7 @@ class WatchedPathBrowserGroup(BrowserGroupModel, WatchedPath):
|
|
|
136
136
|
super().presave()
|
|
137
137
|
WatchedPath.presave(self)
|
|
138
138
|
|
|
139
|
-
class Meta(WatchedPath.Meta):
|
|
139
|
+
class Meta(BrowserGroupModel.Meta, WatchedPath.Meta):
|
|
140
140
|
"""Use Mixin Meta."""
|
|
141
141
|
|
|
142
142
|
abstract = True
|
codex/models/library.py
CHANGED
|
@@ -23,7 +23,7 @@ __all__ = ("Library", "validate_dir_exists")
|
|
|
23
23
|
def validate_dir_exists(path):
|
|
24
24
|
"""Validate that a library exists."""
|
|
25
25
|
if not Path(path).is_dir():
|
|
26
|
-
raise ValidationError(_(
|
|
26
|
+
raise ValidationError(_("{path} is not a directory"), params={"path": path})
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class Library(BaseModel):
|
codex/models/paths.py
CHANGED
|
@@ -36,11 +36,11 @@ class WatchedPath(BaseModel):
|
|
|
36
36
|
st[0] = st_record.st_mode
|
|
37
37
|
st[1] = st_record.st_ino
|
|
38
38
|
# st[2] = st_record.st_dev is ignored by diff
|
|
39
|
-
# st[3] = st_record.st_nlink
|
|
40
|
-
# st[4] = st_record.st_uid
|
|
41
|
-
# st[5] = st_record.st_gid
|
|
39
|
+
# st[3] = st_record.st_nlink ignored
|
|
40
|
+
# st[4] = st_record.st_uid ignored
|
|
41
|
+
# st[5] = st_record.st_gid ignored
|
|
42
42
|
st[6] = st_record.st_size
|
|
43
|
-
# st[7] = st_record.st_atime
|
|
43
|
+
# st[7] = st_record.st_atime ignored
|
|
44
44
|
st[8] = st_record.st_mtime
|
|
45
45
|
self.stat = st
|
|
46
46
|
|
codex/models/query.py
CHANGED
|
@@ -45,7 +45,7 @@ class GroupByQuery(Query):
|
|
|
45
45
|
self.force_group_by_table = ""
|
|
46
46
|
self.force_group_by_fields = ()
|
|
47
47
|
|
|
48
|
-
def get_compiler(self, using=None, connection=None, elide_empty=True):
|
|
48
|
+
def get_compiler(self, using=None, connection=None, elide_empty=True): # noqa: FBT002
|
|
49
49
|
"""Use the custom compiler instead of SQLCompiler."""
|
|
50
50
|
if self.compiler == "SQLCompiler":
|
|
51
51
|
if using is None and connection is None:
|
|
@@ -59,7 +59,11 @@ class GroupByQuery(Query):
|
|
|
59
59
|
)
|
|
60
60
|
else:
|
|
61
61
|
# Normal super() operation.
|
|
62
|
-
compiler = super().get_compiler(
|
|
62
|
+
compiler = super().get_compiler(
|
|
63
|
+
using=using,
|
|
64
|
+
connection=connection,
|
|
65
|
+
elide_empty=elide_empty, # type: ignore[reportCallIssue]
|
|
66
|
+
)
|
|
63
67
|
|
|
64
68
|
return compiler
|
|
65
69
|
|
|
@@ -82,13 +86,13 @@ class GroupByQuerySet(QuerySet):
|
|
|
82
86
|
|
|
83
87
|
def group_by(self, *fields, model=None):
|
|
84
88
|
"""Force group_by operator."""
|
|
85
|
-
obj = self._chain() # type: ignore
|
|
89
|
+
obj = self._chain() # type: ignore[reportAttributeAccessIssue]
|
|
86
90
|
obj.query.set_force_group_by(fields, model=model)
|
|
87
91
|
return obj
|
|
88
92
|
|
|
89
93
|
def demote_joins(self, tables):
|
|
90
94
|
"""Force INNER JOINS."""
|
|
91
|
-
obj = self._chain() # type: ignore
|
|
95
|
+
obj = self._chain() # type: ignore[reportAttributeAccessIssue]
|
|
92
96
|
obj.query.demote_joins(tables)
|
|
93
97
|
return obj
|
|
94
98
|
|
codex/models/util.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Utilities for models."""
|
|
2
2
|
|
|
3
3
|
_ARTICLES = frozenset(
|
|
4
|
-
("a", "an", "the") # en # noqa RUF005
|
|
4
|
+
("a", "an", "the") # en # noqa: RUF005
|
|
5
5
|
+ ("un", "unos", "unas", "el", "los", "la", "las") # es
|
|
6
6
|
+ ("un", "une", "le", "les", "la", "les", "l'") # fr
|
|
7
7
|
+ ("o", "a", "os") # pt
|
codex/permissions.py
CHANGED
|
@@ -8,7 +8,7 @@ from codex.models import Timestamp
|
|
|
8
8
|
class HasAPIKeyOrIsAdminUser(BasePermission):
|
|
9
9
|
"""Does the request have the current api key."""
|
|
10
10
|
|
|
11
|
-
def has_permission(self, request, view):
|
|
11
|
+
def has_permission(self, request, view):
|
|
12
12
|
"""Test the request api key against the database."""
|
|
13
13
|
data = request.GET if request.method == "GET" else request.POST
|
|
14
14
|
api_key = data.get("apiKey")
|
codex/run.py
CHANGED
|
@@ -85,6 +85,4 @@ class AdminFolderSerializer(Serializer):
|
|
|
85
85
|
|
|
86
86
|
def validate_show_hidden(self, show_hidden):
|
|
87
87
|
"""Snakecase the showHidden field."""
|
|
88
|
-
return (
|
|
89
|
-
show_hidden == "true" or self.initial_data.get("showHidden") == "true" # type: ignore
|
|
90
|
-
)
|
|
88
|
+
return show_hidden == "true" or self.initial_data.get("showHidden") == "true"
|
codex/serializers/admin/stats.py
CHANGED
|
@@ -19,8 +19,8 @@ FILE_TYPES_CHOICES = ("CBZ", "CBR", "CBT", "PDF", "UNKNOWN")
|
|
|
19
19
|
class StatsSystemSerializer(Serializer):
|
|
20
20
|
"""Platform System Information."""
|
|
21
21
|
|
|
22
|
-
name = CharField(
|
|
23
|
-
release = CharField(
|
|
22
|
+
name = CharField(read_only=True, required=False)
|
|
23
|
+
release = CharField(read_only=True, required=False)
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class StatsPlatformSerializer(Serializer):
|
|
@@ -42,7 +42,7 @@ class StatsConfigSerializer(Serializer):
|
|
|
42
42
|
user_registered_count = IntegerField(required=False, read_only=True)
|
|
43
43
|
auth_group_count = IntegerField(required=False, read_only=True)
|
|
44
44
|
# Only for api
|
|
45
|
-
api_key = CharField(
|
|
45
|
+
api_key = CharField(read_only=True, required=False)
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
class StatsSessionsSerializer(Serializer):
|
|
@@ -123,4 +123,4 @@ class AdminStatsRequestSerializer(Serializer):
|
|
|
123
123
|
class APIKeySerializer(Serializer):
|
|
124
124
|
"""API Key."""
|
|
125
125
|
|
|
126
|
-
api_key = CharField(source="name")
|
|
126
|
+
api_key = CharField(source="name", read_only=True)
|
codex/serializers/admin/tasks.py
CHANGED
|
@@ -6,11 +6,21 @@ from rest_framework.serializers import (
|
|
|
6
6
|
Serializer,
|
|
7
7
|
)
|
|
8
8
|
|
|
9
|
-
from codex.choices import
|
|
9
|
+
from codex.choices.admin import ADMIN_TASK_GROUPS
|
|
10
|
+
|
|
11
|
+
_ADMIN_TASK_CHOICES = tuple(
|
|
12
|
+
sorted(
|
|
13
|
+
[
|
|
14
|
+
item["value"]
|
|
15
|
+
for group in ADMIN_TASK_GROUPS["tasks"]
|
|
16
|
+
for item in group["tasks"]
|
|
17
|
+
]
|
|
18
|
+
)
|
|
19
|
+
)
|
|
10
20
|
|
|
11
21
|
|
|
12
22
|
class AdminLibrarianTaskSerializer(Serializer):
|
|
13
23
|
"""Get tasks from front end."""
|
|
14
24
|
|
|
15
|
-
task = ChoiceField(choices=
|
|
25
|
+
task = ChoiceField(choices=_ADMIN_TASK_CHOICES)
|
|
16
26
|
library_id = IntegerField(required=False)
|
codex/serializers/auth.py
CHANGED
|
@@ -8,6 +8,8 @@ from rest_framework.serializers import (
|
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
from codex.models import AdminFlag
|
|
11
|
+
from codex.serializers.fields.auth import TimezoneField
|
|
12
|
+
from codex.serializers.fields.sanitized import SanitizedCharField
|
|
11
13
|
from codex.serializers.models.base import BaseModelSerializer
|
|
12
14
|
|
|
13
15
|
|
|
@@ -49,7 +51,7 @@ class UserSerializer(BaseModelSerializer):
|
|
|
49
51
|
class TimezoneSerializer(Serializer):
|
|
50
52
|
"""Serialize Timezone submission from front end."""
|
|
51
53
|
|
|
52
|
-
timezone =
|
|
54
|
+
timezone = TimezoneField(write_only=True)
|
|
53
55
|
|
|
54
56
|
|
|
55
57
|
class UserCreateSerializer(BaseModelSerializer, TimezoneSerializer):
|
|
@@ -67,7 +69,7 @@ class UserLoginSerializer(UserCreateSerializer):
|
|
|
67
69
|
"""Serialize user login input."""
|
|
68
70
|
|
|
69
71
|
# specify this so it doesn't trigger the username unique constraint.
|
|
70
|
-
username =
|
|
72
|
+
username = SanitizedCharField(min_length=2)
|
|
71
73
|
|
|
72
74
|
class Meta(UserCreateSerializer.Meta):
|
|
73
75
|
"""Explicit meta inheritance required."""
|
|
@@ -2,28 +2,106 @@
|
|
|
2
2
|
|
|
3
3
|
from types import MappingProxyType
|
|
4
4
|
|
|
5
|
-
from rest_framework.fields import
|
|
6
|
-
|
|
5
|
+
from rest_framework.fields import (
|
|
6
|
+
BooleanField,
|
|
7
|
+
CharField,
|
|
8
|
+
ListField,
|
|
9
|
+
SerializerMethodField,
|
|
10
|
+
)
|
|
11
|
+
from rest_framework.serializers import Serializer
|
|
7
12
|
|
|
8
|
-
from codex.serializers.browser.filters import BrowserSettingsFilterSerializer
|
|
9
13
|
from codex.serializers.fields import (
|
|
14
|
+
VuetifyBooleanField,
|
|
10
15
|
VuetifyCharField,
|
|
16
|
+
VuetifyDecadeField,
|
|
17
|
+
VuetifyFloatField,
|
|
11
18
|
VuetifyIntegerField,
|
|
12
19
|
)
|
|
20
|
+
from codex.serializers.fields.browser import BookmarkFilterField
|
|
13
21
|
from codex.serializers.models.pycountry import CountrySerializer, LanguageSerializer
|
|
14
22
|
|
|
15
23
|
|
|
16
|
-
class
|
|
24
|
+
class BrowserFilterChoicesSerializer(Serializer):
|
|
25
|
+
"""All dynamic filters."""
|
|
26
|
+
|
|
27
|
+
age_rating = BooleanField(read_only=True)
|
|
28
|
+
community_rating = BooleanField(read_only=True)
|
|
29
|
+
characters = BooleanField(read_only=True)
|
|
30
|
+
country = BooleanField(read_only=True)
|
|
31
|
+
critical_rating = BooleanField(read_only=True)
|
|
32
|
+
contributors = BooleanField(read_only=True)
|
|
33
|
+
decade = BooleanField(read_only=True)
|
|
34
|
+
genres = BooleanField(read_only=True)
|
|
35
|
+
file_type = BooleanField(read_only=True)
|
|
36
|
+
identifier_type = BooleanField(read_only=True)
|
|
37
|
+
monochrome = BooleanField(read_only=True)
|
|
38
|
+
language = BooleanField(read_only=True)
|
|
39
|
+
locations = BooleanField(read_only=True)
|
|
40
|
+
original_format = BooleanField(read_only=True)
|
|
41
|
+
reading_direction = BooleanField(read_only=True)
|
|
42
|
+
series_groups = BooleanField(read_only=True)
|
|
43
|
+
stories = BooleanField(read_only=True)
|
|
44
|
+
story_arcs = BooleanField(read_only=True)
|
|
45
|
+
tagger = BooleanField(read_only=True)
|
|
46
|
+
tags = BooleanField(read_only=True)
|
|
47
|
+
teams = BooleanField(read_only=True)
|
|
48
|
+
year = BooleanField(read_only=True)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BrowserSettingsFilterSerializer(Serializer):
|
|
52
|
+
"""Filter values for settings."""
|
|
53
|
+
|
|
54
|
+
bookmark = BookmarkFilterField(required=False, read_only=True)
|
|
55
|
+
# Dynamic filters
|
|
56
|
+
age_rating = ListField(child=VuetifyCharField(), required=False, read_only=True)
|
|
57
|
+
characters = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
58
|
+
community_rating = ListField(
|
|
59
|
+
child=VuetifyFloatField(), required=False, read_only=True
|
|
60
|
+
)
|
|
61
|
+
country = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
62
|
+
contributors = ListField(
|
|
63
|
+
child=VuetifyIntegerField(), required=False, read_only=True
|
|
64
|
+
)
|
|
65
|
+
critical_rating = ListField(
|
|
66
|
+
child=VuetifyFloatField(), required=False, read_only=True
|
|
67
|
+
)
|
|
68
|
+
decade = ListField(child=VuetifyDecadeField(), required=False, read_only=True)
|
|
69
|
+
file_type = ListField(child=VuetifyCharField(), required=False, read_only=True)
|
|
70
|
+
genres = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
71
|
+
identifier_type = ListField(
|
|
72
|
+
child=VuetifyCharField(), required=False, read_only=True
|
|
73
|
+
)
|
|
74
|
+
language = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
75
|
+
locations = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
76
|
+
monochrome = ListField(child=VuetifyBooleanField(), required=False, read_only=True)
|
|
77
|
+
original_format = ListField(
|
|
78
|
+
child=VuetifyCharField(), required=False, read_only=True
|
|
79
|
+
)
|
|
80
|
+
reading_direction = ListField(
|
|
81
|
+
child=VuetifyCharField(), required=False, read_only=True
|
|
82
|
+
)
|
|
83
|
+
series_groups = ListField(
|
|
84
|
+
child=VuetifyIntegerField(), required=False, read_only=True
|
|
85
|
+
)
|
|
86
|
+
stories = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
87
|
+
story_arcs = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
88
|
+
tagger = ListField(child=VuetifyCharField(), required=False, read_only=True)
|
|
89
|
+
tags = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
90
|
+
teams = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
91
|
+
year = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class BrowserChoicesIntegerPkSerializer(Serializer):
|
|
17
95
|
"""Named Model Serializer."""
|
|
18
96
|
|
|
19
|
-
pk =
|
|
97
|
+
pk = VuetifyIntegerField(read_only=True)
|
|
20
98
|
name = CharField(read_only=True)
|
|
21
99
|
|
|
22
100
|
|
|
23
|
-
class BrowserChoicesIntegerPkSerializer
|
|
101
|
+
class BrowserChoicesCharPkSerializer(BrowserChoicesIntegerPkSerializer):
|
|
24
102
|
"""Named Model Serailizer with pk = char hack for languages & countries."""
|
|
25
103
|
|
|
26
|
-
pk =
|
|
104
|
+
pk = VuetifyCharField(read_only=True)
|
|
27
105
|
|
|
28
106
|
|
|
29
107
|
_CHOICES_NAME_SERIALIZER_MAP = MappingProxyType(
|
|
@@ -50,9 +128,9 @@ class BrowserChoicesFilterSerializer(Serializer):
|
|
|
50
128
|
if serializer_class:
|
|
51
129
|
value = serializer_class(choices, many=True).data
|
|
52
130
|
elif not serializer_class and field_name in _LIST_FIELDS:
|
|
53
|
-
field: ListField = (
|
|
131
|
+
field: ListField = ( # type: ignore[reportAssignmentType]
|
|
54
132
|
BrowserSettingsFilterSerializer().get_fields().get(field_name)
|
|
55
|
-
)
|
|
133
|
+
)
|
|
56
134
|
value = field.to_representation(choices)
|
|
57
135
|
else:
|
|
58
136
|
value = BrowserChoicesIntegerPkSerializer(choices, many=True).data
|
|
@@ -1,68 +1,40 @@
|
|
|
1
1
|
"""Browser Settings Filter Serializers."""
|
|
2
2
|
|
|
3
|
-
from rest_framework.serializers import
|
|
3
|
+
from rest_framework.serializers import ListField, Serializer
|
|
4
4
|
|
|
5
5
|
from codex.serializers.fields import (
|
|
6
|
-
BookmarkFilterField,
|
|
7
6
|
VuetifyBooleanField,
|
|
8
|
-
VuetifyCharField,
|
|
9
7
|
VuetifyDecadeField,
|
|
10
8
|
VuetifyFloatField,
|
|
11
9
|
VuetifyIntegerField,
|
|
12
10
|
)
|
|
11
|
+
from codex.serializers.fields.browser import BookmarkFilterField
|
|
13
12
|
|
|
14
13
|
|
|
15
|
-
class
|
|
16
|
-
"""All dynamic filters."""
|
|
17
|
-
|
|
18
|
-
age_rating = BooleanField(read_only=True)
|
|
19
|
-
community_rating = BooleanField(read_only=True)
|
|
20
|
-
characters = BooleanField(read_only=True)
|
|
21
|
-
country = BooleanField(read_only=True)
|
|
22
|
-
critical_rating = BooleanField(read_only=True)
|
|
23
|
-
contributors = BooleanField(read_only=True)
|
|
24
|
-
decade = BooleanField(read_only=True)
|
|
25
|
-
genres = BooleanField(read_only=True)
|
|
26
|
-
file_type = BooleanField(read_only=True)
|
|
27
|
-
identifier_type = BooleanField(read_only=True)
|
|
28
|
-
monochrome = BooleanField(read_only=True)
|
|
29
|
-
language = BooleanField(read_only=True)
|
|
30
|
-
locations = BooleanField(read_only=True)
|
|
31
|
-
original_format = BooleanField(read_only=True)
|
|
32
|
-
reading_direction = BooleanField(read_only=True)
|
|
33
|
-
series_groups = BooleanField(read_only=True)
|
|
34
|
-
stories = BooleanField(read_only=True)
|
|
35
|
-
story_arcs = BooleanField(read_only=True)
|
|
36
|
-
tagger = BooleanField(read_only=True)
|
|
37
|
-
tags = BooleanField(read_only=True)
|
|
38
|
-
teams = BooleanField(read_only=True)
|
|
39
|
-
year = BooleanField(read_only=True)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class BrowserSettingsFilterSerializer(Serializer):
|
|
14
|
+
class BrowserSettingsFilterInputSerializer(Serializer):
|
|
43
15
|
"""Filter values for settings."""
|
|
44
16
|
|
|
45
17
|
bookmark = BookmarkFilterField(required=False)
|
|
46
18
|
# Dynamic filters
|
|
47
|
-
age_rating = ListField(child=
|
|
19
|
+
age_rating = ListField(child=VuetifyIntegerField(), required=False)
|
|
48
20
|
characters = ListField(child=VuetifyIntegerField(), required=False)
|
|
49
21
|
community_rating = ListField(child=VuetifyFloatField(), required=False)
|
|
50
22
|
country = ListField(child=VuetifyIntegerField(), required=False)
|
|
51
23
|
contributors = ListField(child=VuetifyIntegerField(), required=False)
|
|
52
24
|
critical_rating = ListField(child=VuetifyFloatField(), required=False)
|
|
53
25
|
decade = ListField(child=VuetifyDecadeField(), required=False)
|
|
54
|
-
file_type = ListField(child=
|
|
26
|
+
file_type = ListField(child=VuetifyIntegerField(), required=False)
|
|
55
27
|
genres = ListField(child=VuetifyIntegerField(), required=False)
|
|
56
|
-
identifier_type = ListField(child=
|
|
28
|
+
identifier_type = ListField(child=VuetifyIntegerField(), required=False)
|
|
57
29
|
language = ListField(child=VuetifyIntegerField(), required=False)
|
|
58
30
|
locations = ListField(child=VuetifyIntegerField(), required=False)
|
|
59
31
|
monochrome = ListField(child=VuetifyBooleanField(), required=False)
|
|
60
|
-
original_format = ListField(child=
|
|
61
|
-
reading_direction = ListField(child=
|
|
32
|
+
original_format = ListField(child=VuetifyIntegerField(), required=False)
|
|
33
|
+
reading_direction = ListField(child=VuetifyIntegerField(), required=False)
|
|
62
34
|
series_groups = ListField(child=VuetifyIntegerField(), required=False)
|
|
63
35
|
stories = ListField(child=VuetifyIntegerField(), required=False)
|
|
64
36
|
story_arcs = ListField(child=VuetifyIntegerField(), required=False)
|
|
65
|
-
tagger = ListField(child=
|
|
37
|
+
tagger = ListField(child=VuetifyIntegerField(), required=False)
|
|
66
38
|
tags = ListField(child=VuetifyIntegerField(), required=False)
|
|
67
39
|
teams = ListField(child=VuetifyIntegerField(), required=False)
|
|
68
40
|
year = ListField(child=VuetifyIntegerField(), required=False)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Codex Serializers for the metadata box."""
|
|
2
2
|
|
|
3
|
-
from rest_framework.
|
|
3
|
+
from rest_framework.fields import CharField
|
|
4
|
+
from rest_framework.serializers import IntegerField, ListField, Serializer
|
|
4
5
|
|
|
5
6
|
from codex.serializers.browser.mixins import BrowserAggregateSerializerMixin
|
|
6
7
|
from codex.serializers.models.comic import ComicSerializer
|
|
@@ -5,7 +5,6 @@ from itertools import chain
|
|
|
5
5
|
|
|
6
6
|
from rest_framework.serializers import (
|
|
7
7
|
BooleanField,
|
|
8
|
-
CharField,
|
|
9
8
|
DecimalField,
|
|
10
9
|
IntegerField,
|
|
11
10
|
ListField,
|
|
@@ -14,6 +13,7 @@ from rest_framework.serializers import (
|
|
|
14
13
|
)
|
|
15
14
|
|
|
16
15
|
from codex.logger.logging import get_logger
|
|
16
|
+
from codex.serializers.fields.browser import TopGroupField
|
|
17
17
|
from codex.util import max_none
|
|
18
18
|
from codex.views.const import EPOCH_START
|
|
19
19
|
|
|
@@ -23,7 +23,7 @@ LOG = get_logger(__name__)
|
|
|
23
23
|
class BrowserAggregateSerializerMixin(Serializer):
|
|
24
24
|
"""Mixin for browser, opds & metadata serializers."""
|
|
25
25
|
|
|
26
|
-
group =
|
|
26
|
+
group = TopGroupField(read_only=True)
|
|
27
27
|
ids = ListField(child=IntegerField(), read_only=True)
|
|
28
28
|
|
|
29
29
|
# Aggregate Annotations
|
|
@@ -64,5 +64,9 @@ class BrowserAggregateSerializerMixin(Serializer):
|
|
|
64
64
|
)
|
|
65
65
|
mtime = self._get_max_updated_at(EPOCH_START, updated_ats)
|
|
66
66
|
if obj.bmua_is_max:
|
|
67
|
-
mtime: datetime = max_none(
|
|
67
|
+
mtime: datetime | None = max_none(
|
|
68
|
+
mtime, obj.bookmark_updated_at, EPOCH_START
|
|
69
|
+
)
|
|
70
|
+
if mtime is None:
|
|
71
|
+
return 0
|
|
68
72
|
return int(mtime.timestamp() * 1000)
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
"""Group Mtimes."""
|
|
2
2
|
|
|
3
|
-
from rest_framework.serializers import
|
|
3
|
+
from rest_framework.serializers import Serializer
|
|
4
4
|
|
|
5
|
-
from codex.serializers.browser.settings import
|
|
5
|
+
from codex.serializers.browser.settings import BrowserFilterChoicesInputSerilalizer
|
|
6
6
|
from codex.serializers.fields import TimestampField
|
|
7
7
|
from codex.serializers.route import SimpleRouteSerializer
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class GroupsMtimeSerializer(
|
|
10
|
+
class GroupsMtimeSerializer(BrowserFilterChoicesInputSerilalizer):
|
|
11
11
|
"""Groups Mtimes."""
|
|
12
12
|
|
|
13
|
-
filters = BrowserSettingsFilterSerializer(required=False)
|
|
14
|
-
q = CharField(allow_blank=True, required=False)
|
|
15
13
|
groups = SimpleRouteSerializer(many=True, required=True)
|
|
16
14
|
|
|
17
15
|
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
"""Browser Page Serializer."""
|
|
2
2
|
|
|
3
|
-
from rest_framework.
|
|
3
|
+
from rest_framework.fields import (
|
|
4
4
|
BooleanField,
|
|
5
5
|
CharField,
|
|
6
6
|
DecimalField,
|
|
7
7
|
IntegerField,
|
|
8
|
-
Serializer,
|
|
9
8
|
)
|
|
9
|
+
from rest_framework.serializers import Serializer
|
|
10
10
|
|
|
11
11
|
from codex.serializers.browser.mixins import (
|
|
12
12
|
BrowserAggregateSerializerMixin,
|
|
13
13
|
)
|
|
14
|
-
from codex.serializers.fields import
|
|
14
|
+
from codex.serializers.fields import TimestampField
|
|
15
|
+
from codex.serializers.fields.browser import BreadcrumbsField, TopGroupField
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class BrowserCardSerializer(BrowserAggregateSerializerMixin):
|
|
@@ -57,7 +58,7 @@ class BrowserPageSerializer(Serializer):
|
|
|
57
58
|
title = BrowserTitleSerializer(read_only=True)
|
|
58
59
|
zero_pad = IntegerField(read_only=True)
|
|
59
60
|
libraries_exist = BooleanField(read_only=True)
|
|
60
|
-
model_group =
|
|
61
|
+
model_group = TopGroupField(read_only=True)
|
|
61
62
|
num_pages = IntegerField(read_only=True)
|
|
62
63
|
groups = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
|
|
63
64
|
books = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
|
|
@@ -8,9 +8,10 @@ from rest_framework.serializers import (
|
|
|
8
8
|
Serializer,
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
from codex.choices import BROWSER_ORDER_BY_CHOICES
|
|
12
|
-
from codex.serializers.browser.filters import
|
|
13
|
-
from codex.serializers.fields import
|
|
11
|
+
from codex.choices.browser import BROWSER_ORDER_BY_CHOICES
|
|
12
|
+
from codex.serializers.browser.filters import BrowserSettingsFilterInputSerializer
|
|
13
|
+
from codex.serializers.fields import TimestampField
|
|
14
|
+
from codex.serializers.fields.browser import BreadcrumbsField, TopGroupField
|
|
14
15
|
from codex.serializers.route import SimpleRouteSerializer
|
|
15
16
|
|
|
16
17
|
|
|
@@ -26,7 +27,8 @@ class BrowserSettingsShowGroupFlagsSerializer(Serializer):
|
|
|
26
27
|
class BrowserFilterChoicesInputSerilalizer(Serializer):
|
|
27
28
|
"""Browser Settings for the filter choices response."""
|
|
28
29
|
|
|
29
|
-
filters =
|
|
30
|
+
filters = BrowserSettingsFilterInputSerializer(required=False)
|
|
31
|
+
# NOT Sanitized because so complex.
|
|
30
32
|
q = CharField(allow_blank=True, required=False)
|
|
31
33
|
|
|
32
34
|
|
|
@@ -51,7 +53,6 @@ class BrowserCoverInputSerializer(BrowserCoverInputSerializerBase):
|
|
|
51
53
|
class BrowserSettingsSerializerBase(BrowserCoverInputSerializerBase):
|
|
52
54
|
"""Base Serializer for Browser & OPDS Settings."""
|
|
53
55
|
|
|
54
|
-
# search_results_limit = IntegerField(required=False)
|
|
55
56
|
top_group = TopGroupField(required=False)
|
|
56
57
|
|
|
57
58
|
|
|
@@ -64,7 +65,8 @@ class OPDSSettingsSerializer(BrowserSettingsSerializerBase):
|
|
|
64
65
|
|
|
65
66
|
|
|
66
67
|
class BrowserSettingsSerializer(BrowserSettingsSerializerBase):
|
|
67
|
-
"""
|
|
68
|
+
"""
|
|
69
|
+
Browser Settings that the user can change.
|
|
68
70
|
|
|
69
71
|
This is the only browse serializer that's submitted.
|
|
70
72
|
"""
|