codex 1.7.1__py3-none-any.whl → 1.7.3__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.py +10 -21
- codex/choices_to_json.py +8 -8
- codex/db.py +2 -2
- codex/exceptions.py +5 -6
- codex/librarian/bookmark/bookmarkd.py +9 -6
- codex/librarian/bookmark/tasks.py +1 -1
- codex/librarian/bookmark/update.py +17 -31
- codex/librarian/covers/create.py +10 -8
- codex/librarian/covers/path.py +6 -5
- codex/librarian/covers/purge.py +2 -2
- codex/librarian/cron/crond.py +1 -1
- 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 +2 -2
- codex/librarian/importer/failed_imports.py +1 -1
- codex/librarian/importer/importer.py +3 -1
- 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 +3 -6
- codex/librarian/importer/tasks.py +1 -1
- codex/librarian/janitor/integrity.py +27 -20
- codex/librarian/janitor/janitor.py +5 -2
- codex/librarian/janitor/latest_version.py +1 -1
- codex/librarian/janitor/update.py +2 -2
- codex/librarian/janitor/vacuum.py +1 -1
- codex/librarian/librariand.py +16 -15
- codex/librarian/notifier/notifierd.py +2 -1
- codex/librarian/search/optimize.py +1 -1
- codex/librarian/search/remove.py +1 -1
- codex/librarian/search/update.py +11 -7
- 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/loggerd.py +40 -17
- 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/migrations/0031_adminflag_banner.py +50 -0
- codex/models/admin.py +4 -3
- 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/flags.py +1 -1
- codex/serializers/admin/libraries.py +1 -3
- codex/serializers/auth.py +1 -0
- codex/serializers/browser/choices.py +9 -11
- codex/serializers/browser/metadata.py +1 -1
- codex/serializers/browser/mixins.py +5 -1
- codex/serializers/browser/settings.py +2 -2
- codex/serializers/fields.py +7 -7
- codex/serializers/models/base.py +1 -1
- codex/serializers/models/comic.py +2 -2
- codex/serializers/models/groups.py +0 -2
- codex/serializers/opds/authentication.py +2 -1
- codex/serializers/opds/v2/__init__.py +1 -0
- codex/serializers/opds/v2/facet.py +13 -0
- codex/serializers/opds/v2/feed.py +36 -0
- codex/serializers/opds/v2/links.py +75 -0
- codex/serializers/opds/v2/metadata.py +23 -0
- codex/serializers/opds/v2/progression.py +65 -0
- codex/serializers/opds/v2/publication.py +81 -0
- codex/serializers/opds/{v2_unused.py → v2/unused.py} +16 -9
- codex/serializers/route.py +2 -2
- codex/settings/settings.py +4 -3
- codex/signals/django_signals.py +1 -1
- codex/static_root/assets/VCheckbox-Dv6fwaDb.56abbfb00c8a.js +1 -0
- codex/static_root/assets/VCheckbox-Dv6fwaDb.56abbfb00c8a.js.br +0 -0
- codex/static_root/assets/VCheckbox-Dv6fwaDb.56abbfb00c8a.js.gz +0 -0
- codex/static_root/assets/VCheckbox-Dv6fwaDb.js +1 -0
- codex/static_root/assets/VCheckbox-Dv6fwaDb.js.br +0 -0
- codex/static_root/assets/VCheckbox-Dv6fwaDb.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CNMFahfF.4ee9778a562e.js +1 -0
- codex/static_root/assets/VCheckboxBtn-CNMFahfF.4ee9778a562e.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CNMFahfF.4ee9778a562e.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CNMFahfF.js +1 -0
- codex/static_root/assets/VCheckboxBtn-CNMFahfF.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CNMFahfF.js.gz +0 -0
- codex/static_root/assets/VCombobox-DqBFki-9.2806f95c938d.js +1 -0
- codex/static_root/assets/VCombobox-DqBFki-9.2806f95c938d.js.br +0 -0
- codex/static_root/assets/VCombobox-DqBFki-9.2806f95c938d.js.gz +0 -0
- codex/static_root/assets/VCombobox-DqBFki-9.js +1 -0
- codex/static_root/assets/VCombobox-DqBFki-9.js.br +0 -0
- codex/static_root/assets/VCombobox-DqBFki-9.js.gz +0 -0
- codex/static_root/assets/VDialog-CQXjBvDZ.1a576c5e472f.js +1 -0
- codex/static_root/assets/VDialog-CQXjBvDZ.1a576c5e472f.js.br +0 -0
- codex/static_root/assets/VDialog-CQXjBvDZ.1a576c5e472f.js.gz +0 -0
- codex/static_root/assets/VDialog-CQXjBvDZ.js +1 -0
- codex/static_root/assets/VDialog-CQXjBvDZ.js.br +0 -0
- codex/static_root/assets/VDialog-CQXjBvDZ.js.gz +0 -0
- codex/static_root/assets/VDialog-DWos4S54.b07aca713774.css +1 -0
- codex/static_root/assets/VDialog-DWos4S54.b07aca713774.css.br +0 -0
- codex/static_root/assets/VDialog-DWos4S54.b07aca713774.css.gz +0 -0
- codex/static_root/assets/VDialog-DWos4S54.css +1 -0
- codex/static_root/assets/VDialog-DWos4S54.css.br +0 -0
- codex/static_root/assets/VDialog-DWos4S54.css.gz +0 -0
- codex/static_root/assets/VDivider-DU47sRrT.3d2e17799e5c.css +1 -0
- codex/static_root/assets/VDivider-DU47sRrT.3d2e17799e5c.css.br +0 -0
- codex/static_root/assets/VDivider-DU47sRrT.3d2e17799e5c.css.gz +0 -0
- codex/static_root/assets/VDivider-DU47sRrT.css +1 -0
- codex/static_root/assets/VDivider-DU47sRrT.css.br +0 -0
- codex/static_root/assets/VDivider-DU47sRrT.css.gz +0 -0
- codex/static_root/assets/VDivider-DUxQu-IZ.73d92ae2a07e.js +1 -0
- codex/static_root/assets/VDivider-DUxQu-IZ.73d92ae2a07e.js.br +0 -0
- codex/static_root/assets/VDivider-DUxQu-IZ.73d92ae2a07e.js.gz +0 -0
- codex/static_root/assets/VDivider-DUxQu-IZ.js +1 -0
- codex/static_root/assets/VDivider-DUxQu-IZ.js.br +0 -0
- codex/static_root/assets/VDivider-DUxQu-IZ.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-BaYzHUJp.5346826103eb.js +1 -0
- codex/static_root/assets/VExpansionPanels-BaYzHUJp.5346826103eb.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BaYzHUJp.5346826103eb.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-BaYzHUJp.js +1 -0
- codex/static_root/assets/VExpansionPanels-BaYzHUJp.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BaYzHUJp.js.gz +0 -0
- codex/static_root/assets/VForm-DxBt30-N.138c0b89b6fc.css +1 -0
- codex/static_root/assets/VForm-DxBt30-N.138c0b89b6fc.css.br +0 -0
- codex/static_root/assets/VForm-DxBt30-N.138c0b89b6fc.css.gz +0 -0
- codex/static_root/assets/VForm-DxBt30-N.css +1 -0
- codex/static_root/assets/VForm-DxBt30-N.css.br +0 -0
- codex/static_root/assets/VForm-DxBt30-N.css.gz +0 -0
- codex/static_root/assets/VForm-hB4C5jVd.a2b90ddcd8ee.js +1 -0
- codex/static_root/assets/VForm-hB4C5jVd.a2b90ddcd8ee.js.br +0 -0
- codex/static_root/assets/VForm-hB4C5jVd.a2b90ddcd8ee.js.gz +0 -0
- codex/static_root/assets/VForm-hB4C5jVd.js +1 -0
- codex/static_root/assets/VForm-hB4C5jVd.js.br +0 -0
- codex/static_root/assets/VForm-hB4C5jVd.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-DOjw38qB.cbf2922d05af.js +1 -0
- codex/static_root/assets/VRadioGroup-DOjw38qB.cbf2922d05af.js.br +0 -0
- codex/static_root/assets/VRadioGroup-DOjw38qB.cbf2922d05af.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-DOjw38qB.js +1 -0
- codex/static_root/assets/VRadioGroup-DOjw38qB.js.br +0 -0
- codex/static_root/assets/VRadioGroup-DOjw38qB.js.gz +0 -0
- codex/static_root/assets/VSelect-CP_CVb8s.6309f7bf17bb.css +1 -0
- codex/static_root/assets/VSelect-CP_CVb8s.6309f7bf17bb.css.br +0 -0
- codex/static_root/assets/VSelect-CP_CVb8s.6309f7bf17bb.css.gz +0 -0
- codex/static_root/assets/VSelect-CP_CVb8s.css +1 -0
- codex/static_root/assets/VSelect-CP_CVb8s.css.br +0 -0
- codex/static_root/assets/VSelect-CP_CVb8s.css.gz +0 -0
- codex/static_root/assets/VSelect-L4v_m3ag.db9fb8348617.js +1 -0
- codex/static_root/assets/VSelect-L4v_m3ag.db9fb8348617.js.br +0 -0
- codex/static_root/assets/VSelect-L4v_m3ag.db9fb8348617.js.gz +0 -0
- codex/static_root/assets/VSelect-L4v_m3ag.js +1 -0
- codex/static_root/assets/VSelect-L4v_m3ag.js.br +0 -0
- codex/static_root/assets/VSelect-L4v_m3ag.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-BqB1JeKa.2fb68a673402.js +1 -0
- codex/static_root/assets/VSelectionControl-BqB1JeKa.2fb68a673402.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BqB1JeKa.2fb68a673402.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-BqB1JeKa.js +1 -0
- codex/static_root/assets/VSelectionControl-BqB1JeKa.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BqB1JeKa.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-DPpfgCW2.cc18de4e83f6.css +1 -0
- codex/static_root/assets/VSelectionControl-DPpfgCW2.cc18de4e83f6.css.br +0 -0
- codex/static_root/assets/VSelectionControl-DPpfgCW2.cc18de4e83f6.css.gz +0 -0
- codex/static_root/assets/VSelectionControl-DPpfgCW2.css +1 -0
- codex/static_root/assets/VSelectionControl-DPpfgCW2.css.br +0 -0
- codex/static_root/assets/VSelectionControl-DPpfgCW2.css.gz +0 -0
- codex/static_root/assets/VTable-CtorAbOx.bbda450cbd73.js +1 -0
- codex/static_root/assets/VTable-CtorAbOx.bbda450cbd73.js.br +0 -0
- codex/static_root/assets/VTable-CtorAbOx.bbda450cbd73.js.gz +0 -0
- codex/static_root/assets/VTable-CtorAbOx.js +1 -0
- codex/static_root/assets/VTable-CtorAbOx.js.br +0 -0
- codex/static_root/assets/VTable-CtorAbOx.js.gz +0 -0
- codex/static_root/assets/VWindowItem-Bl-fa3ss.334e6b813775.js +1 -0
- codex/static_root/assets/VWindowItem-Bl-fa3ss.334e6b813775.js.br +0 -0
- codex/static_root/assets/VWindowItem-Bl-fa3ss.334e6b813775.js.gz +0 -0
- codex/static_root/assets/VWindowItem-Bl-fa3ss.js +1 -0
- codex/static_root/assets/VWindowItem-Bl-fa3ss.js.br +0 -0
- codex/static_root/assets/VWindowItem-Bl-fa3ss.js.gz +0 -0
- codex/static_root/assets/admin-BAVKNREt.23c0966bd683.js +1 -0
- codex/static_root/assets/admin-BAVKNREt.23c0966bd683.js.br +0 -0
- codex/static_root/assets/admin-BAVKNREt.23c0966bd683.js.gz +0 -0
- codex/static_root/assets/admin-BAVKNREt.js +1 -0
- codex/static_root/assets/admin-BAVKNREt.js.br +0 -0
- codex/static_root/assets/admin-BAVKNREt.js.gz +0 -0
- codex/static_root/assets/admin-C3iCIUnm.06cb213f624d.css +1 -0
- codex/static_root/assets/admin-C3iCIUnm.06cb213f624d.css.br +0 -0
- codex/static_root/assets/admin-C3iCIUnm.06cb213f624d.css.gz +0 -0
- codex/static_root/assets/admin-C3iCIUnm.css +1 -0
- codex/static_root/assets/admin-C3iCIUnm.css.br +0 -0
- codex/static_root/assets/admin-C3iCIUnm.css.gz +0 -0
- codex/static_root/assets/admin-CHuFhx_t.a54700f97fc8.js +1 -0
- codex/static_root/assets/admin-CHuFhx_t.a54700f97fc8.js.br +0 -0
- codex/static_root/assets/admin-CHuFhx_t.a54700f97fc8.js.gz +0 -0
- codex/static_root/assets/admin-CHuFhx_t.js +1 -0
- codex/static_root/assets/admin-CHuFhx_t.js.br +0 -0
- codex/static_root/assets/admin-CHuFhx_t.js.gz +0 -0
- codex/static_root/assets/admin-menu-T8WJ_x0C.4f011540bb4c.js +1 -0
- codex/static_root/assets/admin-menu-T8WJ_x0C.4f011540bb4c.js.br +0 -0
- codex/static_root/assets/admin-menu-T8WJ_x0C.4f011540bb4c.js.gz +0 -0
- codex/static_root/assets/admin-menu-T8WJ_x0C.js +1 -0
- codex/static_root/assets/admin-menu-T8WJ_x0C.js.br +0 -0
- codex/static_root/assets/admin-menu-T8WJ_x0C.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.7b36216f68b5.js +1 -0
- codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.7b36216f68b5.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.7b36216f68b5.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.js +1 -0
- codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.js.gz +0 -0
- codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css +1 -0
- 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-DNzQvgkY.css +1 -0
- codex/static_root/assets/browser-DNzQvgkY.css.br +0 -0
- codex/static_root/assets/browser-DNzQvgkY.css.gz +0 -0
- codex/static_root/assets/browser-DdLCtUlr.380b79bea4a7.js +1 -0
- codex/static_root/assets/browser-DdLCtUlr.380b79bea4a7.js.br +0 -0
- codex/static_root/assets/browser-DdLCtUlr.380b79bea4a7.js.gz +0 -0
- codex/static_root/assets/browser-DdLCtUlr.js +1 -0
- codex/static_root/assets/browser-DdLCtUlr.js.br +0 -0
- codex/static_root/assets/browser-DdLCtUlr.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-Cy1tU-tj.416ef5bdfd46.js +1 -0
- codex/static_root/assets/change-password-dialog-Cy1tU-tj.416ef5bdfd46.js.br +0 -0
- codex/static_root/assets/change-password-dialog-Cy1tU-tj.416ef5bdfd46.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-Cy1tU-tj.js +1 -0
- codex/static_root/assets/change-password-dialog-Cy1tU-tj.js.br +0 -0
- codex/static_root/assets/change-password-dialog-Cy1tU-tj.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-D0ymWcl_.a30e68c6e303.css +1 -0
- codex/static_root/assets/change-password-dialog-D0ymWcl_.a30e68c6e303.css.br +0 -0
- codex/static_root/assets/change-password-dialog-D0ymWcl_.a30e68c6e303.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-D0ymWcl_.css +1 -0
- codex/static_root/assets/change-password-dialog-D0ymWcl_.css.br +0 -0
- codex/static_root/assets/change-password-dialog-D0ymWcl_.css.gz +0 -0
- codex/static_root/assets/confirm-dialog-B1ABbGMU.9b5915b112c0.css +1 -0
- codex/static_root/assets/confirm-dialog-B1ABbGMU.9b5915b112c0.css.br +0 -0
- codex/static_root/assets/confirm-dialog-B1ABbGMU.css +1 -0
- codex/static_root/assets/confirm-dialog-B1ABbGMU.css.br +0 -0
- codex/static_root/assets/confirm-dialog-B_Y3KKiL.1070d18f6b2d.js +1 -0
- codex/static_root/assets/confirm-dialog-B_Y3KKiL.1070d18f6b2d.js.br +0 -0
- codex/static_root/assets/confirm-dialog-B_Y3KKiL.1070d18f6b2d.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-B_Y3KKiL.js +1 -0
- codex/static_root/assets/confirm-dialog-B_Y3KKiL.js.br +0 -0
- codex/static_root/assets/confirm-dialog-B_Y3KKiL.js.gz +0 -0
- codex/static_root/assets/datetime-column-DVC0YqHC.03bb52c198e9.js +1 -0
- codex/static_root/assets/datetime-column-DVC0YqHC.03bb52c198e9.js.br +0 -0
- codex/static_root/assets/datetime-column-DVC0YqHC.03bb52c198e9.js.gz +0 -0
- codex/static_root/assets/datetime-column-DVC0YqHC.js +1 -0
- codex/static_root/assets/datetime-column-DVC0YqHC.js.br +0 -0
- codex/static_root/assets/datetime-column-DVC0YqHC.js.gz +0 -0
- codex/static_root/assets/{filter-CnO_WiBE.4044b9091aae.js → filter-xcEcgcIx.be1bb4725c89.js} +1 -1
- codex/static_root/assets/filter-xcEcgcIx.be1bb4725c89.js.br +0 -0
- codex/static_root/assets/filter-xcEcgcIx.be1bb4725c89.js.gz +0 -0
- codex/static_root/assets/{filter-CnO_WiBE.js → filter-xcEcgcIx.js} +1 -1
- codex/static_root/assets/filter-xcEcgcIx.js.br +0 -0
- codex/static_root/assets/filter-xcEcgcIx.js.gz +0 -0
- codex/static_root/assets/flag-tab-BOyQb0kr.842fca93f19c.js +1 -0
- codex/static_root/assets/flag-tab-BOyQb0kr.842fca93f19c.js.br +0 -0
- codex/static_root/assets/flag-tab-BOyQb0kr.842fca93f19c.js.gz +0 -0
- codex/static_root/assets/flag-tab-BOyQb0kr.js +1 -0
- codex/static_root/assets/flag-tab-BOyQb0kr.js.br +0 -0
- codex/static_root/assets/flag-tab-BOyQb0kr.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/{VDialog-CSvrKKb2.css → forwardRefs-CFNX6kJ2.9b56b4459240.css} +1 -1
- codex/static_root/assets/forwardRefs-CFNX6kJ2.9b56b4459240.css.br +0 -0
- codex/static_root/assets/forwardRefs-CFNX6kJ2.9b56b4459240.css.gz +0 -0
- codex/static_root/assets/{VDialog-CSvrKKb2.fd4d50904b17.css → forwardRefs-CFNX6kJ2.css} +1 -1
- codex/static_root/assets/forwardRefs-CFNX6kJ2.css.br +0 -0
- codex/static_root/assets/forwardRefs-CFNX6kJ2.css.gz +0 -0
- codex/static_root/assets/forwardRefs-D1ZDjzWx.96fccf773093.js +1 -0
- codex/static_root/assets/forwardRefs-D1ZDjzWx.96fccf773093.js.br +0 -0
- codex/static_root/assets/forwardRefs-D1ZDjzWx.96fccf773093.js.gz +0 -0
- codex/static_root/assets/forwardRefs-D1ZDjzWx.js +1 -0
- codex/static_root/assets/forwardRefs-D1ZDjzWx.js.br +0 -0
- codex/static_root/assets/forwardRefs-D1ZDjzWx.js.gz +0 -0
- codex/static_root/assets/group-tab-DkAIGL8z.527cad03c21d.js +1 -0
- codex/static_root/assets/group-tab-DkAIGL8z.527cad03c21d.js.br +0 -0
- codex/static_root/assets/group-tab-DkAIGL8z.527cad03c21d.js.gz +0 -0
- codex/static_root/assets/group-tab-DkAIGL8z.js +1 -0
- codex/static_root/assets/group-tab-DkAIGL8z.js.br +0 -0
- codex/static_root/assets/group-tab-DkAIGL8z.js.gz +0 -0
- codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css +1 -0
- codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.br +0 -0
- codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.gz +0 -0
- codex/static_root/assets/http-error-CODU7jcH.css +1 -0
- codex/static_root/assets/http-error-CODU7jcH.css.br +0 -0
- codex/static_root/assets/http-error-CODU7jcH.css.gz +0 -0
- codex/static_root/assets/http-error-CjSb8orc.ad6fc5733ed8.js +1 -0
- codex/static_root/assets/http-error-CjSb8orc.ad6fc5733ed8.js.br +0 -0
- codex/static_root/assets/http-error-CjSb8orc.ad6fc5733ed8.js.gz +0 -0
- codex/static_root/assets/http-error-CjSb8orc.js +1 -0
- codex/static_root/assets/http-error-CjSb8orc.js.br +0 -0
- codex/static_root/assets/http-error-CjSb8orc.js.gz +0 -0
- codex/static_root/assets/index-CoFXW6I0.27f397e1425e.js +1 -0
- codex/static_root/assets/index-CoFXW6I0.27f397e1425e.js.br +0 -0
- codex/static_root/assets/index-CoFXW6I0.27f397e1425e.js.gz +0 -0
- codex/static_root/assets/index-CoFXW6I0.js +1 -0
- codex/static_root/assets/index-CoFXW6I0.js.br +0 -0
- codex/static_root/assets/index-CoFXW6I0.js.gz +0 -0
- codex/static_root/assets/library-tab-CgsXOX_r.75baedb7e976.css +1 -0
- codex/static_root/assets/library-tab-CgsXOX_r.75baedb7e976.css.br +0 -0
- codex/static_root/assets/library-tab-CgsXOX_r.75baedb7e976.css.gz +0 -0
- codex/static_root/assets/library-tab-CgsXOX_r.css +1 -0
- codex/static_root/assets/library-tab-CgsXOX_r.css.br +0 -0
- codex/static_root/assets/library-tab-CgsXOX_r.css.gz +0 -0
- codex/static_root/assets/library-tab-hkMMBz1x.02270491d822.js +1 -0
- codex/static_root/assets/library-tab-hkMMBz1x.02270491d822.js.br +0 -0
- codex/static_root/assets/library-tab-hkMMBz1x.02270491d822.js.gz +0 -0
- codex/static_root/assets/library-tab-hkMMBz1x.js +1 -0
- codex/static_root/assets/library-tab-hkMMBz1x.js.br +0 -0
- codex/static_root/assets/library-tab-hkMMBz1x.js.gz +0 -0
- codex/static_root/assets/main-DCaPxp2h.076707ddd123.js +35 -0
- codex/static_root/assets/main-DCaPxp2h.076707ddd123.js.br +0 -0
- codex/static_root/assets/main-DCaPxp2h.076707ddd123.js.gz +0 -0
- codex/static_root/assets/main-DCaPxp2h.js +35 -0
- codex/static_root/assets/main-DCaPxp2h.js.br +0 -0
- codex/static_root/assets/main-DCaPxp2h.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-CwmA9y3l.e7dfdd2a6937.js +1 -0
- codex/static_root/assets/pager-full-pdf-CwmA9y3l.e7dfdd2a6937.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-CwmA9y3l.e7dfdd2a6937.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-CwmA9y3l.js +1 -0
- codex/static_root/assets/pager-full-pdf-CwmA9y3l.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-CwmA9y3l.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-D5VQREy5.css +1 -0
- codex/static_root/assets/pagination-toolbar-D5VQREy5.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-D5VQREy5.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-D5VQREy5.dcb0eba65827.css +1 -0
- codex/static_root/assets/pagination-toolbar-D5VQREy5.dcb0eba65827.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-D5VQREy5.dcb0eba65827.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DoqxSygU.f985bc705fe5.js +1 -0
- codex/static_root/assets/pagination-toolbar-DoqxSygU.f985bc705fe5.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DoqxSygU.f985bc705fe5.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DoqxSygU.js +1 -0
- codex/static_root/assets/pagination-toolbar-DoqxSygU.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DoqxSygU.js.gz +0 -0
- codex/static_root/assets/pdf-doc-BwxvAx1z.96cbc39c321d.js +348 -0
- codex/static_root/assets/pdf-doc-BwxvAx1z.96cbc39c321d.js.br +0 -0
- codex/static_root/assets/pdf-doc-BwxvAx1z.96cbc39c321d.js.gz +0 -0
- codex/static_root/assets/pdf-doc-BwxvAx1z.js +348 -0
- codex/static_root/assets/pdf-doc-BwxvAx1z.js.br +0 -0
- codex/static_root/assets/pdf-doc-BwxvAx1z.js.gz +0 -0
- codex/static_root/assets/reader-D_3ruSqa.2ed32f08e906.css +1 -0
- codex/static_root/assets/reader-D_3ruSqa.2ed32f08e906.css.br +0 -0
- codex/static_root/assets/reader-D_3ruSqa.2ed32f08e906.css.gz +0 -0
- codex/static_root/assets/reader-D_3ruSqa.css +1 -0
- codex/static_root/assets/reader-D_3ruSqa.css.br +0 -0
- codex/static_root/assets/reader-D_3ruSqa.css.gz +0 -0
- codex/static_root/assets/reader-hHIonVbA.4c12219242a9.js +2 -0
- codex/static_root/assets/reader-hHIonVbA.4c12219242a9.js.br +0 -0
- codex/static_root/assets/reader-hHIonVbA.4c12219242a9.js.gz +0 -0
- codex/static_root/assets/reader-hHIonVbA.js +2 -0
- codex/static_root/assets/reader-hHIonVbA.js.br +0 -0
- codex/static_root/assets/reader-hHIonVbA.js.gz +0 -0
- codex/static_root/assets/relation-chips-D7-5kPem.4443b085aca2.js +1 -0
- codex/static_root/assets/relation-chips-D7-5kPem.4443b085aca2.js.br +0 -0
- codex/static_root/assets/relation-chips-D7-5kPem.4443b085aca2.js.gz +0 -0
- codex/static_root/assets/relation-chips-D7-5kPem.js +1 -0
- codex/static_root/assets/relation-chips-D7-5kPem.js.br +0 -0
- codex/static_root/assets/relation-chips-D7-5kPem.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CdFmOhnd.f7dcd12b3ebc.js +2 -0
- codex/static_root/assets/settings-drawer-CdFmOhnd.f7dcd12b3ebc.js.br +0 -0
- codex/static_root/assets/settings-drawer-CdFmOhnd.f7dcd12b3ebc.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CdFmOhnd.js +2 -0
- codex/static_root/assets/settings-drawer-CdFmOhnd.js.br +0 -0
- codex/static_root/assets/settings-drawer-CdFmOhnd.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DMSsWF8c.75a6ea969e71.css +1 -0
- codex/static_root/assets/settings-drawer-DMSsWF8c.75a6ea969e71.css.br +0 -0
- codex/static_root/assets/settings-drawer-DMSsWF8c.75a6ea969e71.css.gz +0 -0
- codex/static_root/assets/settings-drawer-DMSsWF8c.css +1 -0
- codex/static_root/assets/settings-drawer-DMSsWF8c.css.br +0 -0
- codex/static_root/assets/settings-drawer-DMSsWF8c.css.gz +0 -0
- codex/static_root/assets/stats-tab-BzaipD0m.b6bf627ea860.js +1 -0
- codex/static_root/assets/stats-tab-BzaipD0m.b6bf627ea860.js.br +0 -0
- codex/static_root/assets/stats-tab-BzaipD0m.b6bf627ea860.js.gz +0 -0
- codex/static_root/assets/stats-tab-BzaipD0m.js +1 -0
- codex/static_root/assets/stats-tab-BzaipD0m.js.br +0 -0
- codex/static_root/assets/stats-tab-BzaipD0m.js.gz +0 -0
- codex/static_root/assets/{stats-tab-BAYTqQNg.5f715428c394.css → stats-tab-WvF2acoZ.9fdb0106124d.css} +1 -1
- codex/static_root/assets/stats-tab-WvF2acoZ.9fdb0106124d.css.br +0 -0
- codex/static_root/assets/stats-tab-WvF2acoZ.9fdb0106124d.css.gz +0 -0
- codex/static_root/assets/{stats-tab-BAYTqQNg.css → stats-tab-WvF2acoZ.css} +1 -1
- codex/static_root/assets/stats-tab-WvF2acoZ.css.br +0 -0
- codex/static_root/assets/stats-tab-WvF2acoZ.css.gz +0 -0
- codex/static_root/assets/task-tab-DCnS1sM9.44d8435b4989.js +1 -0
- codex/static_root/assets/task-tab-DCnS1sM9.44d8435b4989.js.br +0 -0
- codex/static_root/assets/task-tab-DCnS1sM9.44d8435b4989.js.gz +0 -0
- codex/static_root/assets/task-tab-DCnS1sM9.js +1 -0
- codex/static_root/assets/task-tab-DCnS1sM9.js.br +0 -0
- codex/static_root/assets/task-tab-DCnS1sM9.js.gz +0 -0
- codex/static_root/assets/task-tab-DfdUY9Rc.478e74041f80.css +1 -0
- codex/static_root/assets/{task-tab--cXi48kg.5dfd6890a1c2.css.br → task-tab-DfdUY9Rc.478e74041f80.css.br} +1 -1
- codex/static_root/assets/task-tab-DfdUY9Rc.478e74041f80.css.gz +0 -0
- codex/static_root/assets/task-tab-DfdUY9Rc.css +1 -0
- codex/static_root/assets/{task-tab--cXi48kg.css.br → task-tab-DfdUY9Rc.css.br} +1 -1
- codex/static_root/assets/task-tab-DfdUY9Rc.css.gz +0 -0
- codex/static_root/assets/unauthorized-CsSak07X.c5536d9dae75.css +1 -0
- codex/static_root/assets/unauthorized-CsSak07X.c5536d9dae75.css.br +0 -0
- codex/static_root/assets/unauthorized-CsSak07X.c5536d9dae75.css.gz +0 -0
- codex/static_root/assets/unauthorized-CsSak07X.css +1 -0
- codex/static_root/assets/unauthorized-CsSak07X.css.br +0 -0
- codex/static_root/assets/unauthorized-CsSak07X.css.gz +0 -0
- codex/static_root/assets/unauthorized-DJSr03Dw.7555cbcf1064.js +1 -0
- codex/static_root/assets/unauthorized-DJSr03Dw.7555cbcf1064.js.br +0 -0
- codex/static_root/assets/unauthorized-DJSr03Dw.7555cbcf1064.js.gz +0 -0
- codex/static_root/assets/unauthorized-DJSr03Dw.js +1 -0
- codex/static_root/assets/unauthorized-DJSr03Dw.js.br +0 -0
- codex/static_root/assets/unauthorized-DJSr03Dw.js.gz +0 -0
- codex/static_root/assets/user-tab-DAK_Deoh.1832877d449a.js +1 -0
- codex/static_root/assets/user-tab-DAK_Deoh.1832877d449a.js.br +0 -0
- codex/static_root/assets/user-tab-DAK_Deoh.1832877d449a.js.gz +0 -0
- codex/static_root/assets/user-tab-DAK_Deoh.js +1 -0
- codex/static_root/assets/user-tab-DAK_Deoh.js.br +0 -0
- codex/static_root/assets/user-tab-DAK_Deoh.js.gz +0 -0
- codex/static_root/manifest.cbc39bca88fc.json +735 -0
- codex/static_root/manifest.cbc39bca88fc.json.br +0 -0
- codex/static_root/manifest.cbc39bca88fc.json.gz +0 -0
- codex/static_root/manifest.json +389 -366
- 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 +9 -12
- codex/templates/index.html +1 -1
- codex/threads.py +3 -3
- codex/urls/api/admin.py +4 -3
- codex/urls/api/browser.py +10 -1
- codex/urls/api/reader.py +8 -4
- codex/urls/opds/v2.py +6 -0
- codex/urls/root.py +4 -3
- codex/util.py +11 -0
- codex/views/admin/api_key.py +1 -4
- codex/views/admin/flag.py +5 -1
- codex/views/admin/library.py +4 -4
- codex/views/admin/stats.py +10 -10
- codex/views/admin/tasks.py +9 -9
- codex/views/auth.py +3 -8
- codex/views/bookmark.py +53 -41
- codex/views/browser/annotate/bookmark.py +6 -4
- codex/views/browser/annotate/card.py +4 -21
- codex/views/browser/annotate/order.py +51 -25
- codex/views/browser/bookmark.py +53 -0
- codex/views/browser/breadcrumbs.py +6 -5
- codex/views/browser/browser.py +2 -2
- codex/views/browser/choices.py +6 -5
- codex/views/browser/cover.py +6 -3
- codex/views/browser/download.py +67 -0
- codex/views/browser/filters/bookmark.py +5 -33
- codex/views/browser/filters/field.py +1 -1
- codex/views/browser/filters/filter.py +6 -8
- codex/views/browser/filters/group.py +7 -4
- 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 +3 -3
- codex/views/browser/metadata/annotate.py +1 -1
- codex/views/browser/metadata/copy_intersections.py +1 -1
- codex/views/browser/metadata/metadata.py +2 -2
- codex/views/browser/mtime.py +1 -1
- codex/views/browser/order_by.py +9 -6
- codex/views/browser/params.py +1 -1
- codex/views/browser/settings.py +1 -1
- codex/views/browser/validate.py +14 -7
- codex/views/const.py +0 -3
- codex/views/download.py +5 -5
- codex/views/frontend.py +20 -5
- codex/views/mixins.py +19 -30
- codex/views/opds/authentication_v1.py +1 -1
- codex/views/opds/const.py +6 -4
- codex/views/opds/util.py +5 -5
- codex/views/opds/v1/entry/entry.py +4 -2
- codex/views/opds/v1/entry/links.py +5 -7
- 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 +6 -5
- codex/views/opds/v2/href.py +60 -0
- codex/views/opds/v2/links.py +13 -47
- codex/views/opds/v2/progression.py +136 -0
- codex/views/opds/v2/publications.py +31 -21
- codex/views/opds/v2/top_links.py +2 -1
- codex/views/public.py +12 -5
- codex/views/reader/books.py +22 -10
- codex/views/reader/page.py +19 -14
- codex/views/reader/params.py +3 -3
- 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.1.dist-info → codex-1.7.3.dist-info}/METADATA +23 -27
- codex-1.7.3.dist-info/RECORD +1031 -0
- {codex-1.7.1.dist-info → codex-1.7.3.dist-info}/WHEEL +1 -1
- codex/serializers/opds/v2.py +0 -178
- codex/static_root/assets/VCheckbox-Cf74Jfrq.2fbb5106ef5a.js +0 -1
- codex/static_root/assets/VCheckbox-Cf74Jfrq.2fbb5106ef5a.js.br +0 -0
- codex/static_root/assets/VCheckbox-Cf74Jfrq.2fbb5106ef5a.js.gz +0 -0
- codex/static_root/assets/VCheckbox-Cf74Jfrq.js +0 -1
- codex/static_root/assets/VCheckbox-Cf74Jfrq.js.br +0 -0
- codex/static_root/assets/VCheckbox-Cf74Jfrq.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-D5jbIiqO.921713d268ba.js +0 -1
- codex/static_root/assets/VCheckboxBtn-D5jbIiqO.921713d268ba.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-D5jbIiqO.921713d268ba.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-D5jbIiqO.js +0 -1
- codex/static_root/assets/VCheckboxBtn-D5jbIiqO.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-D5jbIiqO.js.gz +0 -0
- codex/static_root/assets/VCombobox-Dq3Y5j2w.8f4884677e5a.js +0 -1
- codex/static_root/assets/VCombobox-Dq3Y5j2w.8f4884677e5a.js.br +0 -0
- codex/static_root/assets/VCombobox-Dq3Y5j2w.8f4884677e5a.js.gz +0 -0
- codex/static_root/assets/VCombobox-Dq3Y5j2w.js +0 -1
- codex/static_root/assets/VCombobox-Dq3Y5j2w.js.br +0 -0
- codex/static_root/assets/VCombobox-Dq3Y5j2w.js.gz +0 -0
- codex/static_root/assets/VDialog-BVHV10WD.993b98f2be7f.js +0 -1
- codex/static_root/assets/VDialog-BVHV10WD.993b98f2be7f.js.br +0 -0
- codex/static_root/assets/VDialog-BVHV10WD.993b98f2be7f.js.gz +0 -0
- codex/static_root/assets/VDialog-BVHV10WD.js +0 -1
- codex/static_root/assets/VDialog-BVHV10WD.js.br +0 -0
- codex/static_root/assets/VDialog-BVHV10WD.js.gz +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.css.br +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.css.gz +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.br +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.gz +0 -0
- codex/static_root/assets/VExpansionPanels-BLAGU-dj.e244f3902cf9.js +0 -1
- codex/static_root/assets/VExpansionPanels-BLAGU-dj.e244f3902cf9.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BLAGU-dj.e244f3902cf9.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-BLAGU-dj.js +0 -1
- codex/static_root/assets/VExpansionPanels-BLAGU-dj.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BLAGU-dj.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-Bnt5BbmK.826e1c2d9134.js +0 -1
- codex/static_root/assets/VRadioGroup-Bnt5BbmK.826e1c2d9134.js.br +0 -0
- codex/static_root/assets/VRadioGroup-Bnt5BbmK.826e1c2d9134.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-Bnt5BbmK.js +0 -1
- codex/static_root/assets/VRadioGroup-Bnt5BbmK.js.br +0 -0
- codex/static_root/assets/VRadioGroup-Bnt5BbmK.js.gz +0 -0
- codex/static_root/assets/VSelect-BTo1ZM8U.ea4a7a7bbce9.js +0 -1
- codex/static_root/assets/VSelect-BTo1ZM8U.ea4a7a7bbce9.js.br +0 -0
- codex/static_root/assets/VSelect-BTo1ZM8U.ea4a7a7bbce9.js.gz +0 -0
- codex/static_root/assets/VSelect-BTo1ZM8U.js +0 -1
- codex/static_root/assets/VSelect-BTo1ZM8U.js.br +0 -0
- codex/static_root/assets/VSelect-BTo1ZM8U.js.gz +0 -0
- codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css +0 -1
- codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.br +0 -0
- codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.gz +0 -0
- codex/static_root/assets/VSelect-DLu8bpcs.css +0 -1
- codex/static_root/assets/VSelect-DLu8bpcs.css.br +0 -0
- codex/static_root/assets/VSelect-DLu8bpcs.css.gz +0 -0
- codex/static_root/assets/VSelectionControl-CiViEYoC.c77bb19a4a06.css +0 -1
- codex/static_root/assets/VSelectionControl-CiViEYoC.c77bb19a4a06.css.br +0 -0
- codex/static_root/assets/VSelectionControl-CiViEYoC.c77bb19a4a06.css.gz +0 -0
- codex/static_root/assets/VSelectionControl-CiViEYoC.css +0 -1
- codex/static_root/assets/VSelectionControl-CiViEYoC.css.br +0 -0
- codex/static_root/assets/VSelectionControl-CiViEYoC.css.gz +0 -0
- codex/static_root/assets/VSelectionControl-CrzLF2bD.965af5336c62.js +0 -1
- codex/static_root/assets/VSelectionControl-CrzLF2bD.965af5336c62.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CrzLF2bD.965af5336c62.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CrzLF2bD.js +0 -1
- codex/static_root/assets/VSelectionControl-CrzLF2bD.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CrzLF2bD.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css +0 -1
- codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.br +0 -0
- codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.gz +0 -0
- codex/static_root/assets/VSlideGroup-BtXPhMOT.css +0 -1
- codex/static_root/assets/VSlideGroup-BtXPhMOT.css.br +0 -0
- codex/static_root/assets/VSlideGroup-BtXPhMOT.css.gz +0 -0
- codex/static_root/assets/VSlideGroup-ZRALPG67.9807cdc6b330.js +0 -1
- codex/static_root/assets/VSlideGroup-ZRALPG67.9807cdc6b330.js.br +0 -0
- codex/static_root/assets/VSlideGroup-ZRALPG67.9807cdc6b330.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-ZRALPG67.js +0 -1
- codex/static_root/assets/VSlideGroup-ZRALPG67.js.br +0 -0
- codex/static_root/assets/VSlideGroup-ZRALPG67.js.gz +0 -0
- codex/static_root/assets/VTable-Ci8_04Au.1382ab272e40.js +0 -1
- codex/static_root/assets/VTable-Ci8_04Au.1382ab272e40.js.br +0 -0
- codex/static_root/assets/VTable-Ci8_04Au.1382ab272e40.js.gz +0 -0
- codex/static_root/assets/VTable-Ci8_04Au.js +0 -1
- codex/static_root/assets/VTable-Ci8_04Au.js.br +0 -0
- codex/static_root/assets/VTable-Ci8_04Au.js.gz +0 -0
- codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css +0 -1
- codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.br +0 -0
- codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.gz +0 -0
- codex/static_root/assets/VTextField-BnCEPZIq.css +0 -1
- codex/static_root/assets/VTextField-BnCEPZIq.css.br +0 -0
- codex/static_root/assets/VTextField-BnCEPZIq.css.gz +0 -0
- codex/static_root/assets/VTextField-D7pt5iJ3.c020691495b7.js +0 -1
- codex/static_root/assets/VTextField-D7pt5iJ3.c020691495b7.js.br +0 -0
- codex/static_root/assets/VTextField-D7pt5iJ3.c020691495b7.js.gz +0 -0
- codex/static_root/assets/VTextField-D7pt5iJ3.js +0 -1
- codex/static_root/assets/VTextField-D7pt5iJ3.js.br +0 -0
- codex/static_root/assets/VTextField-D7pt5iJ3.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CGBsUHpV.7c57d79cf74a.js +0 -1
- codex/static_root/assets/VWindowItem-CGBsUHpV.7c57d79cf74a.js.br +0 -0
- codex/static_root/assets/VWindowItem-CGBsUHpV.7c57d79cf74a.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CGBsUHpV.js +0 -1
- codex/static_root/assets/VWindowItem-CGBsUHpV.js.br +0 -0
- codex/static_root/assets/VWindowItem-CGBsUHpV.js.gz +0 -0
- codex/static_root/assets/admin-BTXUbxw5.23e0d3602f29.js +0 -1
- codex/static_root/assets/admin-BTXUbxw5.23e0d3602f29.js.br +0 -0
- codex/static_root/assets/admin-BTXUbxw5.23e0d3602f29.js.gz +0 -0
- codex/static_root/assets/admin-BTXUbxw5.js +0 -1
- codex/static_root/assets/admin-BTXUbxw5.js.br +0 -0
- codex/static_root/assets/admin-BTXUbxw5.js.gz +0 -0
- codex/static_root/assets/admin-DJ7pIXDQ.css +0 -1
- codex/static_root/assets/admin-DJ7pIXDQ.css.br +0 -0
- codex/static_root/assets/admin-DJ7pIXDQ.css.gz +0 -0
- codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css +0 -1
- codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.br +0 -0
- codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.gz +0 -0
- codex/static_root/assets/admin-menu-Dbt1Rajw.043fb778ba6c.js +0 -1
- codex/static_root/assets/admin-menu-Dbt1Rajw.043fb778ba6c.js.br +0 -0
- codex/static_root/assets/admin-menu-Dbt1Rajw.043fb778ba6c.js.gz +0 -0
- codex/static_root/assets/admin-menu-Dbt1Rajw.js +0 -1
- codex/static_root/assets/admin-menu-Dbt1Rajw.js.br +0 -0
- codex/static_root/assets/admin-menu-Dbt1Rajw.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.fad596375b9b.js +0 -1
- codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.fad596375b9b.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.fad596375b9b.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.js +0 -1
- codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.js.gz +0 -0
- codex/static_root/assets/browser-3Sm5qvA_.188da1350ec3.css +0 -1
- codex/static_root/assets/browser-3Sm5qvA_.188da1350ec3.css.br +0 -0
- codex/static_root/assets/browser-3Sm5qvA_.188da1350ec3.css.gz +0 -0
- codex/static_root/assets/browser-3Sm5qvA_.css +0 -1
- codex/static_root/assets/browser-3Sm5qvA_.css.br +0 -0
- codex/static_root/assets/browser-3Sm5qvA_.css.gz +0 -0
- codex/static_root/assets/browser-Dq-fQLJF.2e88354a9574.js +0 -1
- codex/static_root/assets/browser-Dq-fQLJF.2e88354a9574.js.br +0 -0
- codex/static_root/assets/browser-Dq-fQLJF.2e88354a9574.js.gz +0 -0
- codex/static_root/assets/browser-Dq-fQLJF.js +0 -1
- codex/static_root/assets/browser-Dq-fQLJF.js.br +0 -0
- codex/static_root/assets/browser-Dq-fQLJF.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-BaGA_bnX.af8ea11b1579.js +0 -1
- codex/static_root/assets/change-password-dialog-BaGA_bnX.af8ea11b1579.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BaGA_bnX.af8ea11b1579.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-BaGA_bnX.js +0 -1
- codex/static_root/assets/change-password-dialog-BaGA_bnX.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BaGA_bnX.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css +0 -1
- codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.br +0 -0
- codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-DrIXdKUC.css +0 -1
- codex/static_root/assets/change-password-dialog-DrIXdKUC.css.br +0 -0
- codex/static_root/assets/change-password-dialog-DrIXdKUC.css.gz +0 -0
- codex/static_root/assets/confirm-dialog-B7w6z2rf.472011c06253.css +0 -1
- codex/static_root/assets/confirm-dialog-B7w6z2rf.css +0 -1
- codex/static_root/assets/confirm-dialog-X14gSw1w.21504f7c1db4.js +0 -1
- codex/static_root/assets/confirm-dialog-X14gSw1w.21504f7c1db4.js.br +0 -0
- codex/static_root/assets/confirm-dialog-X14gSw1w.21504f7c1db4.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-X14gSw1w.js +0 -1
- codex/static_root/assets/confirm-dialog-X14gSw1w.js.br +0 -0
- codex/static_root/assets/confirm-dialog-X14gSw1w.js.gz +0 -0
- codex/static_root/assets/datetime-column-BN2Ulei5.a31061d3729c.js +0 -1
- codex/static_root/assets/datetime-column-BN2Ulei5.a31061d3729c.js.br +0 -0
- codex/static_root/assets/datetime-column-BN2Ulei5.a31061d3729c.js.gz +0 -0
- codex/static_root/assets/datetime-column-BN2Ulei5.js +0 -1
- codex/static_root/assets/datetime-column-BN2Ulei5.js.br +0 -0
- codex/static_root/assets/datetime-column-BN2Ulei5.js.gz +0 -0
- codex/static_root/assets/filter-CnO_WiBE.4044b9091aae.js.br +0 -0
- codex/static_root/assets/filter-CnO_WiBE.4044b9091aae.js.gz +0 -0
- codex/static_root/assets/filter-CnO_WiBE.js.br +0 -0
- codex/static_root/assets/filter-CnO_WiBE.js.gz +0 -0
- codex/static_root/assets/flag-tab-C5NP3j6O.1c692a00884d.js +0 -1
- codex/static_root/assets/flag-tab-C5NP3j6O.1c692a00884d.js.br +0 -0
- codex/static_root/assets/flag-tab-C5NP3j6O.1c692a00884d.js.gz +0 -0
- codex/static_root/assets/flag-tab-C5NP3j6O.js +0 -1
- codex/static_root/assets/flag-tab-C5NP3j6O.js.br +0 -0
- codex/static_root/assets/flag-tab-C5NP3j6O.js.gz +0 -0
- codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css +0 -1
- codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.br +0 -0
- codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.gz +0 -0
- codex/static_root/assets/flag-tab-CqWovuBu.css +0 -1
- codex/static_root/assets/flag-tab-CqWovuBu.css.br +0 -0
- codex/static_root/assets/flag-tab-CqWovuBu.css.gz +0 -0
- codex/static_root/assets/group-tab-Cq4QjmHS.a9d15dac0289.js +0 -1
- codex/static_root/assets/group-tab-Cq4QjmHS.a9d15dac0289.js.br +0 -0
- codex/static_root/assets/group-tab-Cq4QjmHS.a9d15dac0289.js.gz +0 -0
- codex/static_root/assets/group-tab-Cq4QjmHS.js +0 -1
- codex/static_root/assets/group-tab-Cq4QjmHS.js.br +0 -0
- codex/static_root/assets/group-tab-Cq4QjmHS.js.gz +0 -0
- codex/static_root/assets/http-error-DGFbgQC5.da17e7b6d980.js +0 -1
- codex/static_root/assets/http-error-DGFbgQC5.da17e7b6d980.js.br +0 -0
- codex/static_root/assets/http-error-DGFbgQC5.da17e7b6d980.js.gz +0 -0
- codex/static_root/assets/http-error-DGFbgQC5.js +0 -1
- codex/static_root/assets/http-error-DGFbgQC5.js.br +0 -0
- codex/static_root/assets/http-error-DGFbgQC5.js.gz +0 -0
- codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css +0 -1
- codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.br +0 -0
- codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.gz +0 -0
- codex/static_root/assets/http-error-DKulXuTl.css +0 -1
- codex/static_root/assets/http-error-DKulXuTl.css.br +0 -0
- codex/static_root/assets/http-error-DKulXuTl.css.gz +0 -0
- codex/static_root/assets/index-BI-1EK3Q.51e5dd220639.js +0 -1
- codex/static_root/assets/index-BI-1EK3Q.51e5dd220639.js.br +0 -0
- codex/static_root/assets/index-BI-1EK3Q.51e5dd220639.js.gz +0 -0
- codex/static_root/assets/index-BI-1EK3Q.js +0 -1
- codex/static_root/assets/index-BI-1EK3Q.js.br +0 -0
- codex/static_root/assets/index-BI-1EK3Q.js.gz +0 -0
- codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css +0 -1
- codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.br +0 -0
- codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.gz +0 -0
- codex/static_root/assets/library-tab-Wew8YOLv.css +0 -1
- codex/static_root/assets/library-tab-Wew8YOLv.css.br +0 -0
- codex/static_root/assets/library-tab-Wew8YOLv.css.gz +0 -0
- codex/static_root/assets/library-tab-woA1HyfN.acfc4f327913.js +0 -1
- codex/static_root/assets/library-tab-woA1HyfN.acfc4f327913.js.br +0 -0
- codex/static_root/assets/library-tab-woA1HyfN.acfc4f327913.js.gz +0 -0
- codex/static_root/assets/library-tab-woA1HyfN.js +0 -1
- codex/static_root/assets/library-tab-woA1HyfN.js.br +0 -0
- codex/static_root/assets/library-tab-woA1HyfN.js.gz +0 -0
- codex/static_root/assets/main-Ed96tESk.7777498eb960.js +0 -35
- codex/static_root/assets/main-Ed96tESk.7777498eb960.js.br +0 -0
- codex/static_root/assets/main-Ed96tESk.7777498eb960.js.gz +0 -0
- codex/static_root/assets/main-Ed96tESk.js +0 -35
- codex/static_root/assets/main-Ed96tESk.js.br +0 -0
- codex/static_root/assets/main-Ed96tESk.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-DpxPZAZR.ec23b0e50b95.js +0 -1
- codex/static_root/assets/pager-full-pdf-DpxPZAZR.ec23b0e50b95.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-DpxPZAZR.ec23b0e50b95.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-DpxPZAZR.js +0 -1
- codex/static_root/assets/pager-full-pdf-DpxPZAZR.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-DpxPZAZR.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Bz5nEUwa.d01b9cf3ab5e.js +0 -1
- codex/static_root/assets/pagination-toolbar-Bz5nEUwa.d01b9cf3ab5e.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Bz5nEUwa.d01b9cf3ab5e.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Bz5nEUwa.js +0 -1
- codex/static_root/assets/pagination-toolbar-Bz5nEUwa.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Bz5nEUwa.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.css +0 -1
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css +0 -1
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.gz +0 -0
- codex/static_root/assets/pdf-doc-6j4uJzw7.59963079f1ec.js +0 -305
- codex/static_root/assets/pdf-doc-6j4uJzw7.59963079f1ec.js.br +0 -0
- codex/static_root/assets/pdf-doc-6j4uJzw7.59963079f1ec.js.gz +0 -0
- codex/static_root/assets/pdf-doc-6j4uJzw7.js +0 -305
- codex/static_root/assets/pdf-doc-6j4uJzw7.js.br +0 -0
- codex/static_root/assets/pdf-doc-6j4uJzw7.js.gz +0 -0
- codex/static_root/assets/reader-DAyPkkSs.0f54806aed4b.js +0 -2
- codex/static_root/assets/reader-DAyPkkSs.0f54806aed4b.js.br +0 -0
- codex/static_root/assets/reader-DAyPkkSs.0f54806aed4b.js.gz +0 -0
- codex/static_root/assets/reader-DAyPkkSs.js +0 -2
- codex/static_root/assets/reader-DAyPkkSs.js.br +0 -0
- codex/static_root/assets/reader-DAyPkkSs.js.gz +0 -0
- codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css +0 -1
- codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css.br +0 -0
- codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css.gz +0 -0
- codex/static_root/assets/reader-nD70BeEz.css +0 -1
- codex/static_root/assets/reader-nD70BeEz.css.br +0 -0
- codex/static_root/assets/reader-nD70BeEz.css.gz +0 -0
- codex/static_root/assets/relation-chips-DUOduJmS.8b39d35f8503.js +0 -1
- codex/static_root/assets/relation-chips-DUOduJmS.8b39d35f8503.js.br +0 -0
- codex/static_root/assets/relation-chips-DUOduJmS.8b39d35f8503.js.gz +0 -0
- codex/static_root/assets/relation-chips-DUOduJmS.js +0 -1
- codex/static_root/assets/relation-chips-DUOduJmS.js.br +0 -0
- codex/static_root/assets/relation-chips-DUOduJmS.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css +0 -1
- codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css.br +0 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css.gz +0 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.css +0 -1
- codex/static_root/assets/settings-drawer-DKncO_vX.css.br +0 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.css.gz +0 -0
- codex/static_root/assets/settings-drawer-lRimDTyf.054f1f057cee.js +0 -2
- codex/static_root/assets/settings-drawer-lRimDTyf.054f1f057cee.js.br +0 -0
- codex/static_root/assets/settings-drawer-lRimDTyf.054f1f057cee.js.gz +0 -0
- codex/static_root/assets/settings-drawer-lRimDTyf.js +0 -2
- codex/static_root/assets/settings-drawer-lRimDTyf.js.br +0 -0
- codex/static_root/assets/settings-drawer-lRimDTyf.js.gz +0 -0
- codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.br +0 -0
- codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.gz +0 -0
- codex/static_root/assets/stats-tab-BAYTqQNg.css.br +0 -0
- codex/static_root/assets/stats-tab-BAYTqQNg.css.gz +0 -0
- codex/static_root/assets/stats-tab-Cyli0TxY.f9af7d3387d9.js +0 -1
- codex/static_root/assets/stats-tab-Cyli0TxY.f9af7d3387d9.js.br +0 -0
- codex/static_root/assets/stats-tab-Cyli0TxY.f9af7d3387d9.js.gz +0 -0
- codex/static_root/assets/stats-tab-Cyli0TxY.js +0 -1
- codex/static_root/assets/stats-tab-Cyli0TxY.js.br +0 -0
- codex/static_root/assets/stats-tab-Cyli0TxY.js.gz +0 -0
- codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css +0 -1
- codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css.gz +0 -0
- codex/static_root/assets/task-tab--cXi48kg.css +0 -1
- codex/static_root/assets/task-tab--cXi48kg.css.gz +0 -0
- codex/static_root/assets/task-tab-CrRRKMNo.52cc73a5889d.js +0 -1
- codex/static_root/assets/task-tab-CrRRKMNo.52cc73a5889d.js.br +0 -0
- codex/static_root/assets/task-tab-CrRRKMNo.52cc73a5889d.js.gz +0 -0
- codex/static_root/assets/task-tab-CrRRKMNo.js +0 -1
- codex/static_root/assets/task-tab-CrRRKMNo.js.br +0 -0
- codex/static_root/assets/task-tab-CrRRKMNo.js.gz +0 -0
- codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css +0 -1
- codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.br +0 -4
- codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.gz +0 -0
- codex/static_root/assets/transition-5LRFTPo5.css +0 -1
- codex/static_root/assets/transition-5LRFTPo5.css.br +0 -4
- codex/static_root/assets/transition-5LRFTPo5.css.gz +0 -0
- codex/static_root/assets/transition-CyIqQdeu.7496bae455dc.js +0 -1
- codex/static_root/assets/transition-CyIqQdeu.7496bae455dc.js.br +0 -0
- codex/static_root/assets/transition-CyIqQdeu.7496bae455dc.js.gz +0 -0
- codex/static_root/assets/transition-CyIqQdeu.js +0 -1
- codex/static_root/assets/transition-CyIqQdeu.js.br +0 -0
- codex/static_root/assets/transition-CyIqQdeu.js.gz +0 -0
- codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css +0 -1
- codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.br +0 -0
- codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.gz +0 -0
- codex/static_root/assets/unauthorized-BjhIc97q.css +0 -1
- codex/static_root/assets/unauthorized-BjhIc97q.css.br +0 -0
- codex/static_root/assets/unauthorized-BjhIc97q.css.gz +0 -0
- codex/static_root/assets/unauthorized-IWC3QdqX.1d5d2dafa046.js +0 -1
- codex/static_root/assets/unauthorized-IWC3QdqX.1d5d2dafa046.js.br +0 -0
- codex/static_root/assets/unauthorized-IWC3QdqX.1d5d2dafa046.js.gz +0 -0
- codex/static_root/assets/unauthorized-IWC3QdqX.js +0 -1
- codex/static_root/assets/unauthorized-IWC3QdqX.js.br +0 -0
- codex/static_root/assets/unauthorized-IWC3QdqX.js.gz +0 -0
- codex/static_root/assets/user-tab-Bt7BG8Ih.8f797a19b7ae.js +0 -1
- codex/static_root/assets/user-tab-Bt7BG8Ih.8f797a19b7ae.js.br +0 -0
- codex/static_root/assets/user-tab-Bt7BG8Ih.8f797a19b7ae.js.gz +0 -0
- codex/static_root/assets/user-tab-Bt7BG8Ih.js +0 -1
- codex/static_root/assets/user-tab-Bt7BG8Ih.js.br +0 -0
- codex/static_root/assets/user-tab-Bt7BG8Ih.js.gz +0 -0
- codex/static_root/manifest.dbf5ed7a4b40.json +0 -712
- codex/static_root/manifest.dbf5ed7a4b40.json.br +0 -0
- codex/static_root/manifest.dbf5ed7a4b40.json.gz +0 -0
- codex-1.7.1.dist-info/RECORD +0 -1012
- /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css → VCheckbox-CvH8ekHL.016ed8d222c4.css} +0 -0
- /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css.br → VCheckbox-CvH8ekHL.016ed8d222c4.css.br} +0 -0
- /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css.gz → VCheckbox-CvH8ekHL.016ed8d222c4.css.gz} +0 -0
- /codex/static_root/assets/{VCheckbox-CMKdyl0R.css → VCheckbox-CvH8ekHL.css} +0 -0
- /codex/static_root/assets/{VCheckbox-CMKdyl0R.css.br → VCheckbox-CvH8ekHL.css.br} +0 -0
- /codex/static_root/assets/{VCheckbox-CMKdyl0R.css.gz → VCheckbox-CvH8ekHL.css.gz} +0 -0
- /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css → VCombobox-BQHELb_o.9f25a34994e2.css} +0 -0
- /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css.br → VCombobox-BQHELb_o.9f25a34994e2.css.br} +0 -0
- /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css.gz → VCombobox-BQHELb_o.9f25a34994e2.css.gz} +0 -0
- /codex/static_root/assets/{VCombobox-bwEYrXCg.css → VCombobox-BQHELb_o.css} +0 -0
- /codex/static_root/assets/{VCombobox-bwEYrXCg.css.br → VCombobox-BQHELb_o.css.br} +0 -0
- /codex/static_root/assets/{VCombobox-bwEYrXCg.css.gz → VCombobox-BQHELb_o.css.gz} +0 -0
- /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css → VExpansionPanels-RsCANmDP.5b17872981df.css} +0 -0
- /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css.br → VExpansionPanels-RsCANmDP.5b17872981df.css.br} +0 -0
- /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css.gz → VExpansionPanels-RsCANmDP.5b17872981df.css.gz} +0 -0
- /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css → VExpansionPanels-RsCANmDP.css} +0 -0
- /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css.br → VExpansionPanels-RsCANmDP.css.br} +0 -0
- /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css.gz → VExpansionPanels-RsCANmDP.css.gz} +0 -0
- /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css → VRadioGroup-Cp9mZ7cb.8e3741381961.css} +0 -0
- /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css.br → VRadioGroup-Cp9mZ7cb.8e3741381961.css.br} +0 -0
- /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css.gz → VRadioGroup-Cp9mZ7cb.8e3741381961.css.gz} +0 -0
- /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css → VRadioGroup-Cp9mZ7cb.css} +0 -0
- /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css.br → VRadioGroup-Cp9mZ7cb.css.br} +0 -0
- /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css.gz → VRadioGroup-Cp9mZ7cb.css.gz} +0 -0
- /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css → VTable-BnxSZ_W5.c36f0a6a30cf.css} +0 -0
- /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css.br → VTable-BnxSZ_W5.c36f0a6a30cf.css.br} +0 -0
- /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css.gz → VTable-BnxSZ_W5.c36f0a6a30cf.css.gz} +0 -0
- /codex/static_root/assets/{VTable-Y5Sc3hJd.css → VTable-BnxSZ_W5.css} +0 -0
- /codex/static_root/assets/{VTable-Y5Sc3hJd.css.br → VTable-BnxSZ_W5.css.br} +0 -0
- /codex/static_root/assets/{VTable-Y5Sc3hJd.css.gz → VTable-BnxSZ_W5.css.gz} +0 -0
- /codex/static_root/assets/{VWindowItem-ByIod57Y.css → VWindowItem-CWBhiE_Y.css} +0 -0
- /codex/static_root/assets/{VWindowItem-ByIod57Y.css.br → VWindowItem-CWBhiE_Y.css.br} +0 -0
- /codex/static_root/assets/{VWindowItem-ByIod57Y.css.gz → VWindowItem-CWBhiE_Y.css.gz} +0 -0
- /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css → VWindowItem-CWBhiE_Y.f7fb19752bf3.css} +0 -0
- /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css.br → VWindowItem-CWBhiE_Y.f7fb19752bf3.css.br} +0 -0
- /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css.gz → VWindowItem-CWBhiE_Y.f7fb19752bf3.css.gz} +0 -0
- /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css → admin-menu-B3iXsOyy.c13b7df2ff57.css} +0 -0
- /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css.br → admin-menu-B3iXsOyy.c13b7df2ff57.css.br} +0 -0
- /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css.gz → admin-menu-B3iXsOyy.c13b7df2ff57.css.gz} +0 -0
- /codex/static_root/assets/{admin-menu-B9bzD6hV.css → admin-menu-B3iXsOyy.css} +0 -0
- /codex/static_root/assets/{admin-menu-B9bzD6hV.css.br → admin-menu-B3iXsOyy.css.br} +0 -0
- /codex/static_root/assets/{admin-menu-B9bzD6hV.css.gz → admin-menu-B3iXsOyy.css.gz} +0 -0
- /codex/static_root/assets/{admin-settings-button-progress-DUUQfVsZ.2548c49a853e.css → admin-settings-button-progress-BGB22oTD.2548c49a853e.css} +0 -0
- /codex/static_root/assets/{admin-settings-button-progress-DUUQfVsZ.css → admin-settings-button-progress-BGB22oTD.css} +0 -0
- /codex/static_root/assets/{datetime-column-DeCthByU.1f3bf499e063.css → datetime-column-BavtvLnf.1f3bf499e063.css} +0 -0
- /codex/static_root/assets/{datetime-column-DeCthByU.css → datetime-column-BavtvLnf.css} +0 -0
- /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css → group-tab-_vKWzoyd.948e907b1e6b.css} +0 -0
- /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css.br → group-tab-_vKWzoyd.948e907b1e6b.css.br} +0 -0
- /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css.gz → group-tab-_vKWzoyd.948e907b1e6b.css.gz} +0 -0
- /codex/static_root/assets/{group-tab-DkIN1Heu.css → group-tab-_vKWzoyd.css} +0 -0
- /codex/static_root/assets/{group-tab-DkIN1Heu.css.br → group-tab-_vKWzoyd.css.br} +0 -0
- /codex/static_root/assets/{group-tab-DkIN1Heu.css.gz → group-tab-_vKWzoyd.css.gz} +0 -0
- /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css → index-BHXJTQ4V.523d7b3d350f.css} +0 -0
- /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css.br → index-BHXJTQ4V.523d7b3d350f.css.br} +0 -0
- /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css.gz → index-BHXJTQ4V.523d7b3d350f.css.gz} +0 -0
- /codex/static_root/assets/{index-CL_6g4tJ.css → index-BHXJTQ4V.css} +0 -0
- /codex/static_root/assets/{index-CL_6g4tJ.css.br → index-BHXJTQ4V.css.br} +0 -0
- /codex/static_root/assets/{index-CL_6g4tJ.css.gz → index-BHXJTQ4V.css.gz} +0 -0
- /codex/static_root/assets/{main-BZ73p_WW.css → main-K8cER0IH.css} +0 -0
- /codex/static_root/assets/{main-BZ73p_WW.css.br → main-K8cER0IH.css.br} +0 -0
- /codex/static_root/assets/{main-BZ73p_WW.css.gz → main-K8cER0IH.css.gz} +0 -0
- /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css → main-K8cER0IH.d529e8b3f52a.css} +0 -0
- /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css.br → main-K8cER0IH.d529e8b3f52a.css.br} +0 -0
- /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css.gz → main-K8cER0IH.d529e8b3f52a.css.gz} +0 -0
- /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css → pdf-doc-B4cGW_Hl.b94aac7e3313.css} +0 -0
- /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css.br → pdf-doc-B4cGW_Hl.b94aac7e3313.css.br} +0 -0
- /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css.gz → pdf-doc-B4cGW_Hl.b94aac7e3313.css.gz} +0 -0
- /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css → pdf-doc-B4cGW_Hl.css} +0 -0
- /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css.br → pdf-doc-B4cGW_Hl.css.br} +0 -0
- /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css.gz → pdf-doc-B4cGW_Hl.css.gz} +0 -0
- /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css → relation-chips-DpbzrZxT.01269a188e01.css} +0 -0
- /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css.br → relation-chips-DpbzrZxT.01269a188e01.css.br} +0 -0
- /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css.gz → relation-chips-DpbzrZxT.01269a188e01.css.gz} +0 -0
- /codex/static_root/assets/{relation-chips-ByfWwuQc.css → relation-chips-DpbzrZxT.css} +0 -0
- /codex/static_root/assets/{relation-chips-ByfWwuQc.css.br → relation-chips-DpbzrZxT.css.br} +0 -0
- /codex/static_root/assets/{relation-chips-ByfWwuQc.css.gz → relation-chips-DpbzrZxT.css.gz} +0 -0
- {codex-1.7.1.dist-info → codex-1.7.3.dist-info}/LICENSE +0 -0
- {codex-1.7.1.dist-info → codex-1.7.3.dist-info}/entry_points.txt +0 -0
|
@@ -6,7 +6,6 @@ from django.db.models import (
|
|
|
6
6
|
F,
|
|
7
7
|
Value,
|
|
8
8
|
)
|
|
9
|
-
from django.db.models.aggregates import Count
|
|
10
9
|
from django.db.models.fields import CharField
|
|
11
10
|
|
|
12
11
|
from codex.logger.logging import get_logger
|
|
@@ -14,7 +13,6 @@ from codex.models.comic import Comic
|
|
|
14
13
|
from codex.models.functions import JsonGroupArray
|
|
15
14
|
from codex.models.groups import BrowserGroupModel, Imprint, Publisher, Series, Volume
|
|
16
15
|
from codex.views.browser.annotate.bookmark import BrowserAnnotateBookmarkView
|
|
17
|
-
from codex.views.const import FOLDER_GROUP
|
|
18
16
|
|
|
19
17
|
_GROUP_BY: MappingProxyType[type[BrowserGroupModel], str] = MappingProxyType(
|
|
20
18
|
{Publisher: "sort_name", Imprint: "sort_name", Series: "sort_name", Volume: "name"}
|
|
@@ -27,33 +25,18 @@ class BrowserAnnotateCardView(BrowserAnnotateBookmarkView):
|
|
|
27
25
|
|
|
28
26
|
def add_group_by(self, qs):
|
|
29
27
|
"""Get the group by for the model."""
|
|
30
|
-
if group_by := _GROUP_BY.get(qs.model):
|
|
28
|
+
if group_by := _GROUP_BY.get(qs.model):
|
|
31
29
|
qs = qs.group_by(group_by)
|
|
32
30
|
return qs
|
|
33
31
|
|
|
34
|
-
def _annotate_child_count(self, qs):
|
|
35
|
-
"""Annotate child chount for card."""
|
|
36
|
-
if qs.model is Comic:
|
|
37
|
-
return qs
|
|
38
|
-
rel = self.rel_prefix + "pk"
|
|
39
|
-
count_func = Count(rel, distinct=True)
|
|
40
|
-
ann = {"child_count": count_func}
|
|
41
|
-
if self.TARGET == "opds2":
|
|
42
|
-
if qs.model is not Comic:
|
|
43
|
-
qs = qs.alias(**ann)
|
|
44
|
-
else:
|
|
45
|
-
qs = qs.annotate(**ann)
|
|
46
|
-
return qs
|
|
47
|
-
|
|
48
32
|
def _annotate_group(self, qs):
|
|
49
33
|
"""Annotate Group."""
|
|
50
|
-
value = "c" if qs.model is Comic else self.model_group
|
|
34
|
+
value = "c" if qs.model is Comic else self.model_group
|
|
51
35
|
return qs.annotate(group=Value(value, CharField(max_length=1)))
|
|
52
36
|
|
|
53
37
|
def _annotate_file_name(self, qs):
|
|
54
38
|
"""Annotate the file name for folder view."""
|
|
55
|
-
|
|
56
|
-
if group != FOLDER_GROUP or qs.model is not Comic:
|
|
39
|
+
if qs.model is not Comic:
|
|
57
40
|
return qs
|
|
58
41
|
if self.order_key == "filename":
|
|
59
42
|
file_name = F("filename")
|
|
@@ -69,7 +52,7 @@ class BrowserAnnotateCardView(BrowserAnnotateBookmarkView):
|
|
|
69
52
|
qs = self._annotate_group(qs)
|
|
70
53
|
qs = self.annotate_group_names(qs)
|
|
71
54
|
qs = self._annotate_file_name(qs)
|
|
72
|
-
qs = self.
|
|
55
|
+
qs = self.annotate_child_count(qs)
|
|
73
56
|
qs = self.annotate_bookmarks(qs)
|
|
74
57
|
qs = self.annotate_progress(qs)
|
|
75
58
|
return qs.annotate(updated_ats=JsonGroupArray("updated_at", distinct=True))
|
|
@@ -9,7 +9,7 @@ from django.db.models import (
|
|
|
9
9
|
Q,
|
|
10
10
|
Value,
|
|
11
11
|
)
|
|
12
|
-
from django.db.models.aggregates import Avg, Max, Min, Sum
|
|
12
|
+
from django.db.models.aggregates import Avg, Count, Max, Min, Sum
|
|
13
13
|
from django.db.models.fields import CharField
|
|
14
14
|
from django.db.models.functions import Reverse, Right, StrIndex
|
|
15
15
|
|
|
@@ -33,6 +33,7 @@ _ORDER_AGGREGATE_FUNCS = MappingProxyType(
|
|
|
33
33
|
# These are annotated to order_value because they're simple relations
|
|
34
34
|
{
|
|
35
35
|
"age_rating": Avg,
|
|
36
|
+
"child_count": Min,
|
|
36
37
|
"community_rating": Avg,
|
|
37
38
|
"created_at": Min,
|
|
38
39
|
"critical_rating": Avg,
|
|
@@ -45,10 +46,11 @@ _ORDER_AGGREGATE_FUNCS = MappingProxyType(
|
|
|
45
46
|
_ANNOTATED_ORDER_FIELDS = frozenset(
|
|
46
47
|
# These are annotated with their own functions
|
|
47
48
|
{
|
|
49
|
+
"bookmark_updated_at",
|
|
50
|
+
"child_count",
|
|
48
51
|
"filename",
|
|
49
|
-
"sort_name",
|
|
50
52
|
"search_score",
|
|
51
|
-
"
|
|
53
|
+
"sort_name",
|
|
52
54
|
"story_arc_number",
|
|
53
55
|
}
|
|
54
56
|
)
|
|
@@ -71,6 +73,7 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
|
|
|
71
73
|
self._is_opds_acquisition: bool | None = None
|
|
72
74
|
self._opds_acquisition_groups: frozenset[str] | None = None
|
|
73
75
|
self.bmua_is_max = False
|
|
76
|
+
self._child_count_annotated = False
|
|
74
77
|
|
|
75
78
|
@property
|
|
76
79
|
def opds_acquisition_groups(self):
|
|
@@ -109,13 +112,11 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
|
|
|
109
112
|
qs.model is StoryArc and self.order_key == "story_arc_number"
|
|
110
113
|
):
|
|
111
114
|
return qs
|
|
115
|
+
group = self.kwargs.get("group")
|
|
112
116
|
pks = self.kwargs.get("pks")
|
|
113
|
-
show = MappingProxyType(self.params["show"])
|
|
114
|
-
# TODO too many annotations for order?
|
|
115
|
-
# Move other annotations to card.
|
|
116
|
-
# eager publisher for imprint of course
|
|
117
|
+
show = MappingProxyType(self.params["show"])
|
|
117
118
|
sort_name_annotations = self.get_sort_name_annotations(
|
|
118
|
-
qs.model,
|
|
119
|
+
qs.model, group, pks, show
|
|
119
120
|
)
|
|
120
121
|
if sort_name_annotations:
|
|
121
122
|
qs = qs.alias(**sort_name_annotations)
|
|
@@ -130,7 +131,11 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
|
|
|
130
131
|
|
|
131
132
|
return Right(
|
|
132
133
|
path_rel,
|
|
133
|
-
StrIndex(
|
|
134
|
+
StrIndex(
|
|
135
|
+
Reverse(F(path_rel)), # type: ignore[reportArgumentType]
|
|
136
|
+
Value(sep),
|
|
137
|
+
)
|
|
138
|
+
- 1,
|
|
134
139
|
output_field=CharField(),
|
|
135
140
|
)
|
|
136
141
|
|
|
@@ -155,9 +160,7 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
|
|
|
155
160
|
if group == STORY_ARC_GROUP and pks:
|
|
156
161
|
story_arc_pks = pks
|
|
157
162
|
else:
|
|
158
|
-
story_arc_pks = self.params.get("filters", {}).get(
|
|
159
|
-
"story_arcs", ()
|
|
160
|
-
)
|
|
163
|
+
story_arc_pks = self.params.get("filters", {}).get("story_arcs", ())
|
|
161
164
|
|
|
162
165
|
# If we have one annotate it.
|
|
163
166
|
if story_arc_pks:
|
|
@@ -202,6 +205,35 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
|
|
|
202
205
|
# This is used by the serializer to compute mtime
|
|
203
206
|
return qs.annotate(bmua_is_max=Value(self.bmua_is_max))
|
|
204
207
|
|
|
208
|
+
def _annotate_search_scores(self, qs):
|
|
209
|
+
"""Annotate Search Scores."""
|
|
210
|
+
if (
|
|
211
|
+
self.TARGET not in self._COVER_AND_CARD_TARGETS
|
|
212
|
+
or self.order_key != "search_score"
|
|
213
|
+
):
|
|
214
|
+
return qs
|
|
215
|
+
|
|
216
|
+
# Rank is always the max of the relations, cannot aggregate?
|
|
217
|
+
# group by here fixes duplicates with story_arc, probably because it's a long relation
|
|
218
|
+
return qs.annotate(search_score=ComicFTSRank()).group_by("id")
|
|
219
|
+
|
|
220
|
+
def annotate_child_count(self, qs):
|
|
221
|
+
"""Annotate child count."""
|
|
222
|
+
if qs.model is Comic or self._child_count_annotated:
|
|
223
|
+
return qs
|
|
224
|
+
rel = self.rel_prefix + "pk"
|
|
225
|
+
count_func = Count(rel, distinct=True)
|
|
226
|
+
ann = {"child_count": count_func}
|
|
227
|
+
qs = qs.alias(**ann) if self.TARGET == "opds2" else qs.annotate(**ann)
|
|
228
|
+
self._child_count_annotated = True
|
|
229
|
+
return qs
|
|
230
|
+
|
|
231
|
+
def _annotate_order_child_count(self, qs):
|
|
232
|
+
"""Annotate child count for order."""
|
|
233
|
+
if self.order_key != "child_count":
|
|
234
|
+
return qs
|
|
235
|
+
return self.annotate_child_count(qs)
|
|
236
|
+
|
|
205
237
|
def annotate_order_value(self, qs):
|
|
206
238
|
"""Annotate a main key for sorting and browser card display."""
|
|
207
239
|
# Determine order func
|
|
@@ -209,7 +241,12 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
|
|
|
209
241
|
return qs
|
|
210
242
|
if qs.model is Folder and self.order_key == "filename":
|
|
211
243
|
order_value = F("name")
|
|
212
|
-
elif qs.model is Comic
|
|
244
|
+
elif qs.model is Comic:
|
|
245
|
+
order_key = (
|
|
246
|
+
"sort_name" if self.order_key == "child_count" else self.order_key
|
|
247
|
+
)
|
|
248
|
+
order_value = F(order_key)
|
|
249
|
+
elif self.order_key in _ANNOTATED_ORDER_FIELDS:
|
|
213
250
|
# These are annotated in browser_annotaions
|
|
214
251
|
order_value = F(self.order_key)
|
|
215
252
|
else:
|
|
@@ -224,18 +261,6 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
|
|
|
224
261
|
qs = qs.alias(order_value=order_value)
|
|
225
262
|
return qs
|
|
226
263
|
|
|
227
|
-
def _annotate_search_scores(self, qs):
|
|
228
|
-
"""Annotate Search Scores."""
|
|
229
|
-
if (
|
|
230
|
-
self.TARGET not in self._COVER_AND_CARD_TARGETS
|
|
231
|
-
or self.order_key != "search_score"
|
|
232
|
-
):
|
|
233
|
-
return qs
|
|
234
|
-
|
|
235
|
-
# Rank is always the max of the relations, cannot aggregate?
|
|
236
|
-
# group by here fixes duplicates with story_arc, probably because it's a long relation
|
|
237
|
-
return qs.annotate(search_score=ComicFTSRank()).group_by("id")
|
|
238
|
-
|
|
239
264
|
def annotate_order_aggregates(self, qs):
|
|
240
265
|
"""Annotate common aggregates between browser and metadata."""
|
|
241
266
|
qs = qs.annotate(ids=JsonGroupArray("id", distinct=True))
|
|
@@ -245,6 +270,7 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
|
|
|
245
270
|
qs = self._alias_story_arc_number(qs)
|
|
246
271
|
qs = self._annotate_page_count(qs)
|
|
247
272
|
qs = self._annotate_bookmark_updated_at(qs)
|
|
273
|
+
qs = self._annotate_order_child_count(qs)
|
|
248
274
|
if qs.model is not Comic:
|
|
249
275
|
# comic orders on indexed fields when it can
|
|
250
276
|
qs = self.annotate_order_value(qs)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Bookmark view."""
|
|
2
|
+
|
|
3
|
+
from drf_spectacular.utils import extend_schema
|
|
4
|
+
from rest_framework.response import Response
|
|
5
|
+
|
|
6
|
+
from codex.librarian.bookmark.update import BookmarkUpdate
|
|
7
|
+
from codex.logger.logging import get_logger
|
|
8
|
+
from codex.models.comic import Comic
|
|
9
|
+
from codex.serializers.models.bookmark import (
|
|
10
|
+
BookmarkFinishedSerializer,
|
|
11
|
+
BookmarkSerializer,
|
|
12
|
+
)
|
|
13
|
+
from codex.views.bookmark import BookmarkAuthMixin
|
|
14
|
+
from codex.views.browser.filters.filter import BrowserFilterView
|
|
15
|
+
|
|
16
|
+
LOG = get_logger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BookmarkView(BookmarkUpdate, BookmarkAuthMixin, BrowserFilterView):
|
|
20
|
+
"""User Bookmark View."""
|
|
21
|
+
|
|
22
|
+
serializer_class = BookmarkSerializer
|
|
23
|
+
|
|
24
|
+
def _parse_params(self):
|
|
25
|
+
"""Validate and translate the submitted data."""
|
|
26
|
+
group = self.kwargs.get("group")
|
|
27
|
+
# If the target is recursive, strip everything but finished state data.
|
|
28
|
+
serializer_class = None if group == "c" else BookmarkFinishedSerializer
|
|
29
|
+
|
|
30
|
+
data = self.request.data
|
|
31
|
+
if serializer_class:
|
|
32
|
+
serializer = serializer_class(data=data, partial=True)
|
|
33
|
+
else:
|
|
34
|
+
serializer = self.get_serializer(data=data, partial=True)
|
|
35
|
+
serializer.is_valid(raise_exception=True)
|
|
36
|
+
return serializer.validated_data
|
|
37
|
+
|
|
38
|
+
def _get_comic_query(self):
|
|
39
|
+
"""Get comic pks for group."""
|
|
40
|
+
group = self.kwargs.get("group")
|
|
41
|
+
pks = self.kwargs.get("pks")
|
|
42
|
+
return self.get_filtered_queryset(Comic, group=group, pks=pks).only("pk")
|
|
43
|
+
|
|
44
|
+
@extend_schema(request=serializer_class, responses=None)
|
|
45
|
+
def patch(self, *_args, **_kwargs):
|
|
46
|
+
"""Update bookmarks recursively."""
|
|
47
|
+
updates = self._parse_params()
|
|
48
|
+
|
|
49
|
+
auth_filter = self.get_bookmark_auth_filter()
|
|
50
|
+
comic_qs = self._get_comic_query()
|
|
51
|
+
|
|
52
|
+
self.update_bookmarks(auth_filter, comic_qs, updates, LOG)
|
|
53
|
+
return Response()
|
|
@@ -87,8 +87,9 @@ class BrowserBreadcrumbsView(BrowserPaginateView):
|
|
|
87
87
|
if not model:
|
|
88
88
|
model = Publisher
|
|
89
89
|
group_query = model.objects.none()
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
group_instance: BrowserGroupModel | None = group_query.first()
|
|
91
|
+
self._group_instance = group_instance
|
|
92
|
+
return self._group_instance # type: ignore[reportReturnType]
|
|
92
93
|
|
|
93
94
|
def _init_breadcrumbs(self, valid_groups):
|
|
94
95
|
"""Load breadcrumbs and determine if they should be searched for a graft."""
|
|
@@ -103,7 +104,7 @@ class BrowserBreadcrumbsView(BrowserPaginateView):
|
|
|
103
104
|
"""Save the breadcrumbs to params."""
|
|
104
105
|
params = dict(self.params)
|
|
105
106
|
params["breadcrumbs"] = tuple(crumb.dict() for crumb in breadcrumbs)
|
|
106
|
-
#
|
|
107
|
+
# The only place I rewrite params
|
|
107
108
|
self._params = MappingProxyType(params)
|
|
108
109
|
|
|
109
110
|
def _breadcrumbs_graft_or_create_story_arc(self) -> tuple[tuple[Route, ...], bool]:
|
|
@@ -146,7 +147,7 @@ class BrowserBreadcrumbsView(BrowserPaginateView):
|
|
|
146
147
|
|
|
147
148
|
pks = self.kwargs["pks"]
|
|
148
149
|
page = self.kwargs["page"]
|
|
149
|
-
folder: Folder | None = self.group_instance # type: ignore
|
|
150
|
+
folder: Folder | None = self.group_instance # type: ignore[reportAssignmentType]
|
|
150
151
|
name = folder.name if folder and pks else ""
|
|
151
152
|
group_crumb = Route(FOLDER_GROUP, pks, page, name)
|
|
152
153
|
new_breadcrumbs = []
|
|
@@ -230,7 +231,7 @@ class BrowserBreadcrumbsView(BrowserPaginateView):
|
|
|
230
231
|
"""Graft or create browse group breadcrumbs."""
|
|
231
232
|
old_breadcrumbs, changed = self._init_breadcrumbs(GROUP_ORDER)
|
|
232
233
|
|
|
233
|
-
vng = self.valid_nav_groups
|
|
234
|
+
vng = self.valid_nav_groups
|
|
234
235
|
test_groups = tuple(reversed(vng[:-1]))
|
|
235
236
|
new_breadcrumbs = []
|
|
236
237
|
level = done = False
|
codex/views/browser/browser.py
CHANGED
|
@@ -173,13 +173,13 @@ class BrowserView(BrowserTitleView):
|
|
|
173
173
|
else:
|
|
174
174
|
zero_pad = 1
|
|
175
175
|
|
|
176
|
-
# self._debug_queries(page_group_count, page_book_count, group_qs, book_qs)
|
|
176
|
+
# self._debug_queries(page_group_count, page_book_count, group_qs, book_qs) # noqa: ERA001
|
|
177
177
|
|
|
178
178
|
total_page_count = page_group_count + page_book_count
|
|
179
179
|
mtime = self._get_page_mtime()
|
|
180
180
|
return group_qs, book_qs, num_pages, total_page_count, zero_pad, mtime
|
|
181
181
|
|
|
182
|
-
def get_object(self):
|
|
182
|
+
def get_object(self):
|
|
183
183
|
"""Validate settings and get the querysets."""
|
|
184
184
|
group_qs, book_qs, num_pages, total_count, zero_pad, mtime = (
|
|
185
185
|
self._get_group_and_books()
|
codex/views/browser/choices.py
CHANGED
|
@@ -98,7 +98,7 @@ class BrowserChoicesViewBase(BrowserFilterView):
|
|
|
98
98
|
|
|
99
99
|
return rel, model
|
|
100
100
|
|
|
101
|
-
def get_object(self) -> QuerySet:
|
|
101
|
+
def get_object(self) -> QuerySet:
|
|
102
102
|
"""Get the comic subquery use for the choices."""
|
|
103
103
|
return self.get_filtered_queryset(Comic)
|
|
104
104
|
|
|
@@ -136,12 +136,13 @@ class BrowserChoicesAvailableView(BrowserChoicesViewBase):
|
|
|
136
136
|
|
|
137
137
|
return count
|
|
138
138
|
|
|
139
|
-
def get_object(self) -> dict[str, Any]: # type: ignore
|
|
139
|
+
def get_object(self) -> dict[str, Any]: # type: ignore[reportIncompatibleMethodOverride]
|
|
140
140
|
"""Get choice counts."""
|
|
141
141
|
qs = super().get_object()
|
|
142
142
|
filters = self.params.get("filters", {})
|
|
143
143
|
data = {}
|
|
144
|
-
|
|
144
|
+
serializer: BrowserFilterChoicesSerializer = self.serializer_class() # type: ignore[reportOptionalCall, reportAssignmentType]
|
|
145
|
+
for field_name in serializer.get_fields():
|
|
145
146
|
if field_name == "story_arcs" and qs.model is StoryArc:
|
|
146
147
|
# don't allow filtering on story arc in story arc view.
|
|
147
148
|
continue
|
|
@@ -154,7 +155,7 @@ class BrowserChoicesAvailableView(BrowserChoicesViewBase):
|
|
|
154
155
|
|
|
155
156
|
try:
|
|
156
157
|
is_filter_set = bool(filters.get(field_name))
|
|
157
|
-
flag = is_filter_set or count > 1
|
|
158
|
+
flag = is_filter_set or count > 1
|
|
158
159
|
except TypeError:
|
|
159
160
|
flag = False
|
|
160
161
|
data[field_name] = flag
|
|
@@ -185,7 +186,7 @@ class BrowserChoicesView(BrowserChoicesViewBase):
|
|
|
185
186
|
field_name = self.kwargs.get("field_name", "")
|
|
186
187
|
return snakecase(field_name)
|
|
187
188
|
|
|
188
|
-
def get_object(self) -> dict[str, Any]: # type: ignore
|
|
189
|
+
def get_object(self) -> dict[str, Any]: # type: ignore[reportIncompatibleMethodOverride]
|
|
189
190
|
"""Return choices with more than one choice."""
|
|
190
191
|
qs = super().get_object()
|
|
191
192
|
field_name = self._get_field_name()
|
codex/views/browser/cover.py
CHANGED
|
@@ -52,7 +52,7 @@ class CoverView(BrowserAnnotateOrderView):
|
|
|
52
52
|
BrowserAnnotateOrderView.REPARSE_JSON_FIELDS | {"parent"}
|
|
53
53
|
)
|
|
54
54
|
|
|
55
|
-
def get_group_filter(self, group=None, pks=None, page_mtime=False):
|
|
55
|
+
def get_group_filter(self, group=None, pks=None, page_mtime=False): # noqa: FBT002
|
|
56
56
|
"""Get group filter for First Cover View."""
|
|
57
57
|
if self.params.get("dynamic_covers") or self.model in (Volume, Folder):
|
|
58
58
|
return super().get_group_filter(group=group, pks=pks, page_mtime=page_mtime)
|
|
@@ -60,7 +60,10 @@ class CoverView(BrowserAnnotateOrderView):
|
|
|
60
60
|
# First cover group filter relies on sort names to look outside the browser supplied pks
|
|
61
61
|
# For multi_groups not in the browser query.
|
|
62
62
|
pks = self.kwargs["pks"]
|
|
63
|
-
|
|
63
|
+
if not self.model:
|
|
64
|
+
qs = Comic.objects.none()
|
|
65
|
+
else:
|
|
66
|
+
qs = self.model.objects.filter(pk__in=pks)
|
|
64
67
|
sort_names = qs.values_list("sort_name", flat=True).distinct()
|
|
65
68
|
model_rel = GROUP_RELATION[self.model_group]
|
|
66
69
|
group_filter = {f"{model_rel}__sort_name__in": sort_names}
|
|
@@ -142,7 +145,7 @@ class CoverView(BrowserAnnotateOrderView):
|
|
|
142
145
|
parameters=[BrowserAnnotateOrderView.input_serializer_class],
|
|
143
146
|
responses={(200, content_type): OpenApiTypes.BINARY},
|
|
144
147
|
)
|
|
145
|
-
def get(self, *args, **kwargs):
|
|
148
|
+
def get(self, *args, **kwargs):
|
|
146
149
|
"""Get comic cover."""
|
|
147
150
|
try:
|
|
148
151
|
try:
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Download a group of comics in a zipfile."""
|
|
2
|
+
|
|
3
|
+
from django.http import HttpResponseBadRequest
|
|
4
|
+
from django.http.response import FileResponse, Http404
|
|
5
|
+
from drf_spectacular.types import OpenApiTypes
|
|
6
|
+
from drf_spectacular.utils import extend_schema
|
|
7
|
+
from zipstream import ZipStream
|
|
8
|
+
|
|
9
|
+
from codex.logger.logging import get_logger
|
|
10
|
+
from codex.views.browser.filters.filter import BrowserFilterView
|
|
11
|
+
|
|
12
|
+
LOG = get_logger()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class GroupDownloadView(BrowserFilterView):
|
|
16
|
+
"""Return a group of comic archives as a streaming zipfile."""
|
|
17
|
+
|
|
18
|
+
content_type = "application/zip"
|
|
19
|
+
AS_ATTACHMENT = True
|
|
20
|
+
TARGET = "download"
|
|
21
|
+
|
|
22
|
+
def get_object(self):
|
|
23
|
+
"""Get comic paths for a browse group."""
|
|
24
|
+
group = self.kwargs.get("group")
|
|
25
|
+
pks = self.kwargs.get("pks")
|
|
26
|
+
if not self.model:
|
|
27
|
+
reason = f"Could not find model for group {group}"
|
|
28
|
+
return HttpResponseBadRequest(reason)
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
qs = self.get_filtered_queryset(self.model, group=group, pks=pks)
|
|
32
|
+
path_rel = self.rel_prefix + "path"
|
|
33
|
+
paths = qs.values_list(path_rel, flat=True)
|
|
34
|
+
except Exception as exc:
|
|
35
|
+
LOG.warning(f"Error with download query for {group}:{pks} {exc}")
|
|
36
|
+
raise
|
|
37
|
+
|
|
38
|
+
if not paths:
|
|
39
|
+
reason = f"Comics from {group}:{pks} not not found."
|
|
40
|
+
raise Http404(reason)
|
|
41
|
+
|
|
42
|
+
return sorted(set(paths))
|
|
43
|
+
|
|
44
|
+
@extend_schema(responses={(200, content_type): OpenApiTypes.BINARY})
|
|
45
|
+
def get(self, *_args, **kwargs):
|
|
46
|
+
"""Stream a zip archive of many comics."""
|
|
47
|
+
paths = self.get_object()
|
|
48
|
+
|
|
49
|
+
zs = ZipStream(sized=True)
|
|
50
|
+
for path in paths:
|
|
51
|
+
zs.add_path(path)
|
|
52
|
+
download_file = zs
|
|
53
|
+
|
|
54
|
+
filename = kwargs.get("filename")
|
|
55
|
+
if not filename:
|
|
56
|
+
pks = self.kwargs.get("pks")
|
|
57
|
+
name = self.model.__name__ if self.model else "No Model"
|
|
58
|
+
filename = f"{name} {pks} Comics.zip"
|
|
59
|
+
|
|
60
|
+
headers = {"Content-Length": len(zs), "Last-Modified": zs.last_modified}
|
|
61
|
+
return FileResponse(
|
|
62
|
+
download_file,
|
|
63
|
+
as_attachment=self.AS_ATTACHMENT,
|
|
64
|
+
content_type=self.content_type,
|
|
65
|
+
filename=filename,
|
|
66
|
+
headers=headers,
|
|
67
|
+
)
|
|
@@ -1,48 +1,20 @@
|
|
|
1
1
|
"""Bookmark filter view methods."""
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
3
|
from django.db.models import Q
|
|
6
4
|
|
|
5
|
+
from codex.views.bookmark import BookmarkFilterMixin
|
|
7
6
|
from codex.views.browser.validate import BrowserValidateView
|
|
8
7
|
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from codex.models import BrowserGroupModel
|
|
11
|
-
|
|
12
8
|
|
|
13
|
-
class BrowserFilterBookmarkView(BrowserValidateView):
|
|
9
|
+
class BrowserFilterBookmarkView(BookmarkFilterMixin, BrowserValidateView):
|
|
14
10
|
"""BookmarkFilter view methods."""
|
|
15
11
|
|
|
16
|
-
def __init__(self, *args, **kwargs):
|
|
17
|
-
"""Initialize the bm_annotation_data."""
|
|
18
|
-
super().__init__(*args, **kwargs)
|
|
19
|
-
self._bm_rels: dict[BrowserGroupModel, str] = {}
|
|
20
|
-
self._bm_filters: dict[BrowserGroupModel, Q] = {}
|
|
21
|
-
|
|
22
|
-
def _get_bm_rel(self, model):
|
|
23
|
-
"""Create bookmark relation."""
|
|
24
|
-
if model not in self._bm_rels:
|
|
25
|
-
rel_prefix = self.get_rel_prefix(model) # type: ignore
|
|
26
|
-
self._bm_rels[model] = rel_prefix + "bookmark"
|
|
27
|
-
return self._bm_rels[model]
|
|
28
|
-
|
|
29
|
-
def _get_my_bookmark_filter(self, bm_rel):
|
|
30
|
-
"""Get a filter for my session or user defined bookmarks."""
|
|
31
|
-
if self.request.user and self.request.user.is_authenticated:
|
|
32
|
-
key = f"{bm_rel}__user"
|
|
33
|
-
value = self.request.user
|
|
34
|
-
else:
|
|
35
|
-
key = f"{bm_rel}__session__session_key"
|
|
36
|
-
value = self.request.session.session_key
|
|
37
|
-
my_bookmarks_kwargs = {key: value}
|
|
38
|
-
return Q(**my_bookmarks_kwargs)
|
|
39
|
-
|
|
40
12
|
def get_bookmark_filter(self, model):
|
|
41
13
|
"""Build bookmark query."""
|
|
42
|
-
choice: str = self.params.get("filters", {}).get("bookmark", "")
|
|
14
|
+
choice: str = self.params.get("filters", {}).get("bookmark", "")
|
|
43
15
|
if choice:
|
|
44
|
-
bm_rel = self.
|
|
45
|
-
my_bookmark_filter = self.
|
|
16
|
+
bm_rel = self.get_bm_rel(model)
|
|
17
|
+
my_bookmark_filter = self.get_my_bookmark_filter(bm_rel)
|
|
46
18
|
if choice == "READ":
|
|
47
19
|
bookmark_filter = my_bookmark_filter & Q(
|
|
48
20
|
**{f"{bm_rel}__finished": True}
|
|
@@ -55,5 +55,5 @@ class ComicFieldFilterView(GroupFilterView):
|
|
|
55
55
|
def get_comic_field_filter(self, model):
|
|
56
56
|
"""Filter the comics based on the form filters."""
|
|
57
57
|
rel_prefix = self.get_rel_prefix(model)
|
|
58
|
-
filters = self.params["filters"]
|
|
58
|
+
filters = self.params["filters"]
|
|
59
59
|
return self.get_all_comic_field_filters(rel_prefix, filters)
|
|
@@ -13,8 +13,6 @@ LOG = get_logger(__name__)
|
|
|
13
13
|
class BrowserFilterView(BrowserFilterBookmarkView):
|
|
14
14
|
"""Browser Filters."""
|
|
15
15
|
|
|
16
|
-
TARGET = ""
|
|
17
|
-
|
|
18
16
|
def force_inner_joins(self, qs):
|
|
19
17
|
"""Force INNER JOINS to filter empty groups."""
|
|
20
18
|
demote_tables = {"codex_library"}
|
|
@@ -28,10 +26,10 @@ class BrowserFilterView(BrowserFilterBookmarkView):
|
|
|
28
26
|
def _get_query_filters(
|
|
29
27
|
self,
|
|
30
28
|
model,
|
|
29
|
+
page_mtime,
|
|
30
|
+
bookmark_filter,
|
|
31
31
|
group=None,
|
|
32
32
|
pks=None,
|
|
33
|
-
page_mtime=False,
|
|
34
|
-
bookmark_filter=True,
|
|
35
33
|
) -> Q:
|
|
36
34
|
"""Return all the filters except the group filter."""
|
|
37
35
|
big_include_filter = Q()
|
|
@@ -54,16 +52,16 @@ class BrowserFilterView(BrowserFilterBookmarkView):
|
|
|
54
52
|
model,
|
|
55
53
|
group=None,
|
|
56
54
|
pks=None,
|
|
57
|
-
page_mtime=False,
|
|
58
|
-
bookmark_filter=True,
|
|
55
|
+
page_mtime=False, # noqa: FBT002
|
|
56
|
+
bookmark_filter=True, # noqa: FBT002
|
|
59
57
|
) -> QuerySet:
|
|
60
58
|
"""Get a filtered queryset for the model."""
|
|
61
59
|
query_filters = self._get_query_filters(
|
|
62
60
|
model,
|
|
63
|
-
group=group,
|
|
64
|
-
pks=pks,
|
|
65
61
|
page_mtime=page_mtime,
|
|
66
62
|
bookmark_filter=bookmark_filter,
|
|
63
|
+
group=group,
|
|
64
|
+
pks=pks,
|
|
67
65
|
)
|
|
68
66
|
# Distinct necissary for folder view with search
|
|
69
67
|
return model.objects.filter(query_filters).distinct()
|
|
@@ -18,15 +18,18 @@ class GroupFilterView(BrowserParamsView):
|
|
|
18
18
|
|
|
19
19
|
SESSION_KEY = BrowserParamsView.BROWSER_SESSION_KEY
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
TARGET = ""
|
|
22
|
+
|
|
23
|
+
def _get_rel_for_pks(self, group, page_mtime: bool):
|
|
22
24
|
"""Get the relation from the model to the pks."""
|
|
23
|
-
|
|
24
|
-
target: str = self.TARGET # type: ignore
|
|
25
|
+
target: str = self.TARGET
|
|
25
26
|
if target in _GROUP_REL_TARGETS:
|
|
26
27
|
rel = FILTER_ONLY_GROUP_RELATION[group]
|
|
27
28
|
elif target in _PK_REL_TARGETS or page_mtime:
|
|
28
29
|
# metadata, mtime, browser.page_mtime
|
|
29
30
|
rel = "pk"
|
|
31
|
+
elif target == "download":
|
|
32
|
+
rel = "comic__folders" if group == "f" else "pk"
|
|
30
33
|
else:
|
|
31
34
|
# browser.group, opds
|
|
32
35
|
rel = GROUP_RELATION[group]
|
|
@@ -34,7 +37,7 @@ class GroupFilterView(BrowserParamsView):
|
|
|
34
37
|
rel += "__in"
|
|
35
38
|
return rel
|
|
36
39
|
|
|
37
|
-
def get_group_filter(self, group=None, pks=None, page_mtime=False):
|
|
40
|
+
def get_group_filter(self, group=None, pks=None, page_mtime=False): # noqa: FBT002
|
|
38
41
|
"""Get filter for the displayed group."""
|
|
39
42
|
if group is None:
|
|
40
43
|
group = self.kwargs["group"]
|
|
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
|
|
|
22
22
|
from pyparsing.helpers import InfixNotationOperatorSpec
|
|
23
23
|
|
|
24
24
|
_QUOTES_REXP = r"(?:\".*?\")"
|
|
25
|
-
_OPERATORS_REXP = "
|
|
25
|
+
_OPERATORS_REXP = "and not|or not|and|or"
|
|
26
26
|
_BEGIN_NOT_REXP = r"^\s*\(?\s*(?P<not>not)"
|
|
27
27
|
_IMPLICIT_AND_REXP = (
|
|
28
28
|
rf"{_QUOTES_REXP}|\ (?P<ok>{_OPERATORS_REXP})\ |(?P<bare>(?:\ not)?\ )\S"
|
|
@@ -183,5 +183,5 @@ def get_field_query(rel, rel_class, exp, model, many_to_many):
|
|
|
183
183
|
bool_expr = _create_context_expression(context)
|
|
184
184
|
|
|
185
185
|
parsed_result = bool_expr.parse_string(exp)
|
|
186
|
-
root_bool_operand: BoolOperand = parsed_result[0] # type:ignore
|
|
186
|
+
root_bool_operand: BoolOperand = parsed_result[0] # type:ignore[reportAssignmentType]
|
|
187
187
|
return root_bool_operand.to_query()
|