codex 1.7.0__py3-none-any.whl → 1.7.0a0__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/db.py +17 -32
- codex/exceptions.py +3 -2
- codex/librarian/covers/coverd.py +4 -3
- codex/librarian/covers/create.py +7 -8
- codex/librarian/covers/path.py +2 -1
- codex/librarian/covers/purge.py +2 -2
- codex/librarian/janitor/integrity.py +10 -12
- codex/librarian/janitor/tasks.py +1 -1
- codex/librarian/librariand.py +0 -5
- codex/librarian/watchdog/emitter.py +19 -21
- codex/librarian/watchdog/event_batcherd.py +1 -0
- codex/migrations/0030_nocase_collation_day_month_indexes_status_types.py +0 -4
- codex/models/admin.py +5 -0
- codex/models/functions.py +5 -6
- codex/models/query.py +0 -6
- codex/run.py +9 -11
- codex/serializers/admin/tasks.py +2 -2
- codex/serializers/browser/mixins.py +14 -18
- codex/serializers/browser/settings.py +4 -4
- codex/serializers/choices.py +196 -0
- codex/serializers/fields.py +5 -9
- codex/startup.py +4 -6
- codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js +1 -0
- codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.br +0 -0
- codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.gz +0 -0
- codex/static_root/assets/VCheckbox-CWiqcZ7a.js +1 -0
- codex/static_root/assets/VCheckbox-CWiqcZ7a.js.br +0 -0
- codex/static_root/assets/VCheckbox-CWiqcZ7a.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js +1 -0
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js +1 -0
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.gz +0 -0
- codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js +1 -0
- codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.br +0 -0
- codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.gz +0 -0
- codex/static_root/assets/VCombobox-D1_KU27A.js +1 -0
- codex/static_root/assets/VCombobox-D1_KU27A.js.br +0 -0
- codex/static_root/assets/VCombobox-D1_KU27A.js.gz +0 -0
- codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css +1 -0
- codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.br +0 -0
- codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.gz +0 -0
- codex/static_root/assets/VDialog-38np3TSA.css +1 -0
- codex/static_root/assets/VDialog-38np3TSA.css.br +0 -0
- codex/static_root/assets/VDialog-38np3TSA.css.gz +0 -0
- codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js +1 -0
- codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.br +0 -0
- codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.gz +0 -0
- codex/static_root/assets/VDialog-GbxvFMMN.js +1 -0
- codex/static_root/assets/VDialog-GbxvFMMN.js.br +0 -0
- codex/static_root/assets/VDialog-GbxvFMMN.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js +1 -0
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.js +1 -0
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js +1 -0
- codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.br +0 -0
- codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-C0etmxpZ.js +1 -0
- codex/static_root/assets/VRadioGroup-C0etmxpZ.js.br +0 -0
- codex/static_root/assets/VRadioGroup-C0etmxpZ.js.gz +0 -0
- codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css +1 -0
- codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.br +0 -0
- codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.gz +0 -0
- codex/static_root/assets/VSelect-Ca2bIOso.css +1 -0
- codex/static_root/assets/VSelect-Ca2bIOso.css.br +0 -0
- codex/static_root/assets/VSelect-Ca2bIOso.css.gz +0 -0
- codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js +1 -0
- codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.br +0 -0
- codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.gz +0 -0
- codex/static_root/assets/VSelect-txrnRiNJ.js +1 -0
- codex/static_root/assets/VSelect-txrnRiNJ.js.br +0 -0
- codex/static_root/assets/VSelect-txrnRiNJ.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js +1 -0
- codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CY6RmcvW.js +1 -0
- codex/static_root/assets/VSelectionControl-CY6RmcvW.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CY6RmcvW.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css +1 -0
- codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.br +0 -0
- codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.gz +0 -0
- codex/static_root/assets/VSlideGroup-Dk_1upHt.css +1 -0
- codex/static_root/assets/VSlideGroup-Dk_1upHt.css.br +0 -0
- codex/static_root/assets/VSlideGroup-Dk_1upHt.css.gz +0 -0
- codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js +1 -0
- codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.br +0 -0
- codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-DtEQMwY1.js +1 -0
- codex/static_root/assets/VSlideGroup-DtEQMwY1.js.br +0 -0
- codex/static_root/assets/VSlideGroup-DtEQMwY1.js.gz +0 -0
- codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js +1 -0
- codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.br +0 -0
- codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.gz +0 -0
- codex/static_root/assets/VTable-2af995xo.js +1 -0
- codex/static_root/assets/VTable-2af995xo.js.br +0 -0
- codex/static_root/assets/VTable-2af995xo.js.gz +0 -0
- codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css +1 -0
- codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.br +0 -0
- codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.gz +0 -0
- codex/static_root/assets/VTextField-Crc3gdNh.css +1 -0
- codex/static_root/assets/VTextField-Crc3gdNh.css.br +0 -0
- codex/static_root/assets/VTextField-Crc3gdNh.css.gz +0 -0
- codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js +1 -0
- codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.br +0 -0
- codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.gz +0 -0
- codex/static_root/assets/VTextField-G6CMj7yO.js +1 -0
- codex/static_root/assets/VTextField-G6CMj7yO.js.br +0 -0
- codex/static_root/assets/VTextField-G6CMj7yO.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js +1 -0
- codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.br +0 -0
- codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CzoGd6Ul.js +1 -0
- codex/static_root/assets/VWindowItem-CzoGd6Ul.js.br +0 -0
- codex/static_root/assets/VWindowItem-CzoGd6Ul.js.gz +0 -0
- codex/static_root/assets/{admin-DJ7pIXDQ.css → admin-CWEjaFr5.7d4523387384.css} +1 -1
- codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.br +0 -0
- codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.gz +0 -0
- codex/static_root/assets/{admin-DJ7pIXDQ.e2a77af73ef2.css → admin-CWEjaFr5.css} +1 -1
- codex/static_root/assets/admin-CWEjaFr5.css.br +0 -0
- codex/static_root/assets/admin-CWEjaFr5.css.gz +0 -0
- codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js +1 -0
- codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.br +0 -0
- codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.gz +0 -0
- codex/static_root/assets/admin-CsPAIQeG.js +1 -0
- codex/static_root/assets/admin-CsPAIQeG.js.br +0 -0
- codex/static_root/assets/admin-CsPAIQeG.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js +30 -0
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.js +30 -0
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css +1 -0
- codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css +1 -0
- codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css.gz +0 -0
- codex/static_root/assets/browser-C18l93yc.923860009ef4.js +1 -0
- codex/static_root/assets/browser-C18l93yc.923860009ef4.js.br +0 -0
- codex/static_root/assets/browser-C18l93yc.923860009ef4.js.gz +0 -0
- codex/static_root/assets/browser-C18l93yc.js +1 -0
- codex/static_root/assets/browser-C18l93yc.js.br +0 -0
- codex/static_root/assets/browser-C18l93yc.js.gz +0 -0
- codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css +1 -0
- codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.br +0 -0
- codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.gz +0 -0
- codex/static_root/assets/browser-DaAqlBYO.css +1 -0
- codex/static_root/assets/browser-DaAqlBYO.css.br +0 -0
- codex/static_root/assets/browser-DaAqlBYO.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js +1 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.js +1 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css +1 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.br +0 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.css +1 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.br +0 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.gz +0 -0
- codex/static_root/assets/confirm-dialog-BmhedLCx.7c2103d319d4.css +1 -0
- codex/static_root/assets/confirm-dialog-BmhedLCx.css +1 -0
- codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js +1 -0
- codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-CbW3hlOp.js +1 -0
- codex/static_root/assets/confirm-dialog-CbW3hlOp.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CbW3hlOp.js.gz +0 -0
- codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js +1 -0
- codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.br +0 -0
- codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.gz +0 -0
- codex/static_root/assets/datetime-column-uSqKZU37.js +1 -0
- codex/static_root/assets/datetime-column-uSqKZU37.js.br +0 -0
- codex/static_root/assets/datetime-column-uSqKZU37.js.gz +0 -0
- codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js +1 -0
- codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.br +0 -0
- codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.gz +0 -0
- codex/static_root/assets/filter-CBl5KEsB.js +1 -0
- codex/static_root/assets/filter-CBl5KEsB.js.br +0 -0
- codex/static_root/assets/filter-CBl5KEsB.js.gz +0 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js +1 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.br +0 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.gz +0 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.js +1 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.js.br +0 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.js.gz +0 -0
- codex/static_root/assets/flag-tab-DBqpLKi7.css +1 -0
- codex/static_root/assets/flag-tab-DBqpLKi7.css.br +0 -0
- codex/static_root/assets/flag-tab-DBqpLKi7.css.gz +0 -0
- codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css +1 -0
- codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.br +0 -0
- codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.gz +0 -0
- codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js +1 -0
- codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.br +0 -0
- codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.gz +0 -0
- codex/static_root/assets/group-tab-BOW9kigw.js +1 -0
- codex/static_root/assets/group-tab-BOW9kigw.js.br +0 -0
- codex/static_root/assets/group-tab-BOW9kigw.js.gz +0 -0
- codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css +1 -0
- codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.br +0 -0
- codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.gz +0 -0
- codex/static_root/assets/group-tab-CBKuS3Iv.css +1 -0
- codex/static_root/assets/group-tab-CBKuS3Iv.css.br +0 -0
- codex/static_root/assets/group-tab-CBKuS3Iv.css.gz +0 -0
- codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js +1 -0
- codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.br +4 -0
- codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.gz +0 -0
- codex/static_root/assets/http-error-C6yuLApo.js +1 -0
- codex/static_root/assets/http-error-C6yuLApo.js.br +4 -0
- codex/static_root/assets/http-error-C6yuLApo.js.gz +0 -0
- codex/static_root/assets/{library-tab-Wew8YOLv.0c1780a6b68e.css → library-tab-Bh7ErAk7.7c44200ee727.css} +1 -1
- codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.br +2 -0
- codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.gz +0 -0
- codex/static_root/assets/{library-tab-Wew8YOLv.css → library-tab-Bh7ErAk7.css} +1 -1
- codex/static_root/assets/library-tab-Bh7ErAk7.css.br +2 -0
- codex/static_root/assets/library-tab-Bh7ErAk7.css.gz +0 -0
- codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js +1 -0
- codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.br +0 -0
- codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.gz +0 -0
- codex/static_root/assets/library-tab-D3WOtpE0.js +1 -0
- codex/static_root/assets/library-tab-D3WOtpE0.js.br +0 -0
- codex/static_root/assets/library-tab-D3WOtpE0.js.gz +0 -0
- codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js +6 -0
- codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.br +0 -0
- codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.gz +0 -0
- codex/static_root/assets/main-CmjU2oTp.js +6 -0
- codex/static_root/assets/main-CmjU2oTp.js.br +0 -0
- codex/static_root/assets/main-CmjU2oTp.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js +1 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.js +1 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js +1 -0
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.js +1 -0
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-ctqZIwOP.7e7b2c815ea4.js → pdf-doc-BcRNpoaW.882f6e967869.js} +3 -3
- codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.br +0 -0
- codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-ctqZIwOP.js → pdf-doc-BcRNpoaW.js} +3 -3
- codex/static_root/assets/pdf-doc-BcRNpoaW.js.br +0 -0
- codex/static_root/assets/pdf-doc-BcRNpoaW.js.gz +0 -0
- codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js +2 -0
- codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.br +0 -0
- codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.gz +0 -0
- codex/static_root/assets/reader-DIPRg2VB.js +2 -0
- codex/static_root/assets/reader-DIPRg2VB.js.br +0 -0
- codex/static_root/assets/reader-DIPRg2VB.js.gz +0 -0
- codex/static_root/assets/{reader-nD70BeEz.06e85e73c391.css → reader-DveZZr9x.7b21b9f8f628.css} +1 -1
- codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.br +0 -0
- codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.gz +0 -0
- codex/static_root/assets/{reader-nD70BeEz.css → reader-DveZZr9x.css} +1 -1
- codex/static_root/assets/reader-DveZZr9x.css.br +0 -0
- codex/static_root/assets/reader-DveZZr9x.css.gz +0 -0
- codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js +1 -0
- codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.br +0 -0
- codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.gz +0 -0
- codex/static_root/assets/relation-chips-3tTlR5QH.js +1 -0
- codex/static_root/assets/relation-chips-3tTlR5QH.js.br +0 -0
- codex/static_root/assets/relation-chips-3tTlR5QH.js.gz +0 -0
- codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js +2 -0
- codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.br +0 -0
- codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.gz +0 -0
- codex/static_root/assets/settings-drawer-BdyFhA_r.js +2 -0
- codex/static_root/assets/settings-drawer-BdyFhA_r.js.br +0 -0
- codex/static_root/assets/settings-drawer-BdyFhA_r.js.gz +0 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js +1 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.br +0 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.gz +0 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.js +1 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.js.br +0 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.js.gz +0 -0
- codex/static_root/assets/{stats-tab-BAYTqQNg.5f715428c394.css → stats-tab-DpfGsVX3.1cb66f2649a9.css} +1 -1
- codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.br +0 -0
- codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.gz +0 -0
- codex/static_root/assets/{stats-tab-BAYTqQNg.css → stats-tab-DpfGsVX3.css} +1 -1
- codex/static_root/assets/stats-tab-DpfGsVX3.css.br +0 -0
- codex/static_root/assets/stats-tab-DpfGsVX3.css.gz +0 -0
- codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css +1 -0
- codex/static_root/assets/{task-tab--cXi48kg.5dfd6890a1c2.css.br → task-tab-1XiWn9xP.06cb8e1b794d.css.br} +1 -1
- codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css.gz +0 -0
- codex/static_root/assets/task-tab-1XiWn9xP.css +1 -0
- codex/static_root/assets/{task-tab--cXi48kg.css.br → task-tab-1XiWn9xP.css.br} +1 -1
- codex/static_root/assets/task-tab-1XiWn9xP.css.gz +0 -0
- codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js +1 -0
- codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.br +0 -0
- codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.gz +0 -0
- codex/static_root/assets/task-tab-C8D0qRP_.js +1 -0
- codex/static_root/assets/task-tab-C8D0qRP_.js.br +0 -0
- codex/static_root/assets/task-tab-C8D0qRP_.js.gz +0 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js +1 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.br +0 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.gz +0 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.js +1 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.js.br +0 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.js.gz +0 -0
- codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js +1 -0
- codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.br +0 -0
- codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.gz +0 -0
- codex/static_root/assets/user-tab-BU31Z92y.js +1 -0
- codex/static_root/assets/user-tab-BU31Z92y.js.br +0 -0
- codex/static_root/assets/user-tab-BU31Z92y.js.gz +0 -0
- codex/static_root/js/choices-admin.8aa64c911203.json +1 -0
- codex/static_root/js/choices-admin.8aa64c911203.json.br +0 -0
- codex/static_root/js/choices-admin.8aa64c911203.json.gz +0 -0
- codex/static_root/js/choices-admin.json +1 -0
- codex/static_root/js/choices-admin.json.br +0 -0
- codex/static_root/js/choices-admin.json.gz +0 -0
- codex/static_root/js/choices.2f6b0359e1ef.json +1 -0
- codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
- codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
- codex/static_root/js/choices.json +1 -0
- codex/static_root/js/choices.json.br +0 -0
- codex/static_root/js/choices.json.gz +0 -0
- codex/static_root/manifest.45cb46e19686.json +635 -0
- codex/static_root/manifest.45cb46e19686.json.br +0 -0
- codex/static_root/manifest.45cb46e19686.json.gz +0 -0
- codex/static_root/manifest.json +300 -377
- 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 +6 -5
- codex/threads.py +1 -1
- codex/urls/api/auth.py +1 -1
- codex/urls/api/browser.py +1 -1
- codex/views/admin/library.py +13 -18
- codex/views/admin/stats.py +16 -23
- codex/views/admin/tasks.py +2 -1
- codex/views/auth.py +77 -42
- codex/views/bookmark.py +153 -16
- codex/views/browser/annotations.py +339 -0
- codex/views/browser/base.py +139 -0
- codex/views/browser/breadcrumbs.py +11 -90
- codex/views/browser/browser.py +110 -44
- codex/views/browser/choices.py +18 -15
- codex/views/browser/cover.py +20 -10
- codex/views/browser/filters/annotations.py +125 -0
- codex/views/browser/filters/bookmark.py +19 -18
- codex/views/browser/filters/field.py +3 -8
- codex/views/browser/filters/group.py +6 -9
- codex/views/browser/filters/search/fts.py +19 -5
- codex/views/browser/filters/search/parse.py +24 -54
- codex/views/browser/metadata.py +332 -0
- codex/views/browser/mtime.py +10 -2
- codex/views/browser/order_by.py +22 -22
- codex/views/browser/page_in_bounds.py +2 -2
- codex/views/browser/paginate.py +15 -9
- codex/views/browser/title.py +6 -1
- codex/views/browser/validate.py +33 -68
- codex/views/download.py +1 -1
- codex/views/mixins.py +15 -27
- codex/views/opds/const.py +3 -2
- codex/views/opds/urls.py +2 -2
- codex/views/opds/util.py +3 -2
- codex/views/opds/v1/entry/links.py +1 -3
- codex/views/opds/v1/facets.py +12 -65
- codex/views/opds/v1/feed.py +64 -5
- codex/views/opds/v1/links.py +4 -5
- codex/views/opds/v2/feed.py +28 -1
- codex/views/opds/v2/links.py +1 -26
- codex/views/opds/v2/publications.py +6 -5
- codex/views/opds/v2/top_links.py +6 -3
- codex/views/public.py +2 -2
- codex/views/reader/arcs.py +3 -0
- codex/views/reader/books.py +41 -57
- codex/views/reader/{params.py → init.py} +31 -37
- codex/views/reader/page.py +4 -10
- codex/views/reader/reader.py +2 -1
- codex/views/session.py +54 -43
- codex/views/version.py +1 -1
- {codex-1.7.0.dist-info → codex-1.7.0a0.dist-info}/METADATA +5 -2
- {codex-1.7.0.dist-info → codex-1.7.0a0.dist-info}/RECORD +385 -419
- codex/choices.py +0 -419
- codex/choices_to_json.py +0 -122
- codex/librarian/bookmark/__init__.py +0 -1
- codex/librarian/bookmark/bookmarkd.py +0 -38
- codex/librarian/bookmark/tasks.py +0 -19
- codex/librarian/bookmark/update.py +0 -154
- codex/static_root/assets/VCheckbox-D_CWEmqR.84f2b49311e8.js +0 -1
- codex/static_root/assets/VCheckbox-D_CWEmqR.84f2b49311e8.js.br +0 -0
- codex/static_root/assets/VCheckbox-D_CWEmqR.84f2b49311e8.js.gz +0 -0
- codex/static_root/assets/VCheckbox-D_CWEmqR.js +0 -1
- codex/static_root/assets/VCheckbox-D_CWEmqR.js.br +0 -0
- codex/static_root/assets/VCheckbox-D_CWEmqR.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-B1BhcFvi.0eaf3c516474.js +0 -1
- codex/static_root/assets/VCheckboxBtn-B1BhcFvi.0eaf3c516474.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-B1BhcFvi.0eaf3c516474.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-B1BhcFvi.js +0 -1
- codex/static_root/assets/VCheckboxBtn-B1BhcFvi.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-B1BhcFvi.js.gz +0 -0
- codex/static_root/assets/VCombobox-CZAW6_3Q.0e2401e819a5.js +0 -1
- codex/static_root/assets/VCombobox-CZAW6_3Q.0e2401e819a5.js.br +0 -0
- codex/static_root/assets/VCombobox-CZAW6_3Q.0e2401e819a5.js.gz +0 -0
- codex/static_root/assets/VCombobox-CZAW6_3Q.js +0 -1
- codex/static_root/assets/VCombobox-CZAW6_3Q.js.br +0 -0
- codex/static_root/assets/VCombobox-CZAW6_3Q.js.gz +0 -0
- codex/static_root/assets/VDialog-CSHgHIlG.a0bcd336cb7b.js +0 -1
- codex/static_root/assets/VDialog-CSHgHIlG.a0bcd336cb7b.js.br +0 -0
- codex/static_root/assets/VDialog-CSHgHIlG.a0bcd336cb7b.js.gz +0 -0
- codex/static_root/assets/VDialog-CSHgHIlG.js +0 -1
- codex/static_root/assets/VDialog-CSHgHIlG.js.br +0 -0
- codex/static_root/assets/VDialog-CSHgHIlG.js.gz +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.css +0 -1
- 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 +0 -1
- 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-CG6MpdMC.e96ae8afad97.js +0 -1
- codex/static_root/assets/VExpansionPanels-CG6MpdMC.e96ae8afad97.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CG6MpdMC.e96ae8afad97.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CG6MpdMC.js +0 -1
- codex/static_root/assets/VExpansionPanels-CG6MpdMC.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CG6MpdMC.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-CAgQxkiU.f26ecb0c3e34.js +0 -1
- codex/static_root/assets/VRadioGroup-CAgQxkiU.f26ecb0c3e34.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CAgQxkiU.f26ecb0c3e34.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-CAgQxkiU.js +0 -1
- codex/static_root/assets/VRadioGroup-CAgQxkiU.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CAgQxkiU.js.gz +0 -0
- codex/static_root/assets/VSelect-C1gez8rl.9b11d2f00faf.js +0 -1
- codex/static_root/assets/VSelect-C1gez8rl.9b11d2f00faf.js.br +0 -0
- codex/static_root/assets/VSelect-C1gez8rl.9b11d2f00faf.js.gz +0 -0
- codex/static_root/assets/VSelect-C1gez8rl.js +0 -1
- codex/static_root/assets/VSelect-C1gez8rl.js.br +0 -0
- codex/static_root/assets/VSelect-C1gez8rl.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-DBqDlKjK.160beaa1b56c.js +0 -1
- codex/static_root/assets/VSelectionControl-DBqDlKjK.160beaa1b56c.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DBqDlKjK.160beaa1b56c.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-DBqDlKjK.js +0 -1
- codex/static_root/assets/VSelectionControl-DBqDlKjK.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DBqDlKjK.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-SqR_NAL1.40ba1d838a6e.js +0 -1
- codex/static_root/assets/VSlideGroup-SqR_NAL1.40ba1d838a6e.js.br +0 -0
- codex/static_root/assets/VSlideGroup-SqR_NAL1.40ba1d838a6e.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-SqR_NAL1.js +0 -1
- codex/static_root/assets/VSlideGroup-SqR_NAL1.js.br +0 -0
- codex/static_root/assets/VSlideGroup-SqR_NAL1.js.gz +0 -0
- codex/static_root/assets/VTable-CYC-wMpk.8f15d66044da.js +0 -1
- codex/static_root/assets/VTable-CYC-wMpk.8f15d66044da.js.br +0 -0
- codex/static_root/assets/VTable-CYC-wMpk.8f15d66044da.js.gz +0 -0
- codex/static_root/assets/VTable-CYC-wMpk.js +0 -1
- codex/static_root/assets/VTable-CYC-wMpk.js.br +0 -0
- codex/static_root/assets/VTable-CYC-wMpk.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-DMRKRbbT.911ac84d8c9d.js +0 -1
- codex/static_root/assets/VTextField-DMRKRbbT.911ac84d8c9d.js.br +0 -0
- codex/static_root/assets/VTextField-DMRKRbbT.911ac84d8c9d.js.gz +0 -0
- codex/static_root/assets/VTextField-DMRKRbbT.js +0 -1
- codex/static_root/assets/VTextField-DMRKRbbT.js.br +0 -0
- codex/static_root/assets/VTextField-DMRKRbbT.js.gz +0 -0
- codex/static_root/assets/VWindowItem-D0P2xNJl.6a10e3f3a153.js +0 -1
- codex/static_root/assets/VWindowItem-D0P2xNJl.6a10e3f3a153.js.br +0 -0
- codex/static_root/assets/VWindowItem-D0P2xNJl.6a10e3f3a153.js.gz +0 -0
- codex/static_root/assets/VWindowItem-D0P2xNJl.js +0 -1
- codex/static_root/assets/VWindowItem-D0P2xNJl.js.br +0 -0
- codex/static_root/assets/VWindowItem-D0P2xNJl.js.gz +0 -0
- codex/static_root/assets/admin-CD90VMen.4c2b6f2a5111.js +0 -1
- codex/static_root/assets/admin-CD90VMen.4c2b6f2a5111.js.br +0 -0
- codex/static_root/assets/admin-CD90VMen.4c2b6f2a5111.js.gz +0 -0
- codex/static_root/assets/admin-CD90VMen.js +0 -1
- codex/static_root/assets/admin-CD90VMen.js.br +0 -0
- codex/static_root/assets/admin-CD90VMen.js.gz +0 -0
- 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.br +0 -0
- codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.gz +0 -0
- codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css +0 -1
- codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css.br +0 -0
- codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css.gz +0 -0
- codex/static_root/assets/admin-menu-B9bzD6hV.css +0 -1
- codex/static_root/assets/admin-menu-B9bzD6hV.css.br +0 -0
- codex/static_root/assets/admin-menu-B9bzD6hV.css.gz +0 -0
- codex/static_root/assets/admin-menu-BpEPGKr_.c9f9178c5a82.js +0 -1
- codex/static_root/assets/admin-menu-BpEPGKr_.c9f9178c5a82.js.br +0 -0
- codex/static_root/assets/admin-menu-BpEPGKr_.c9f9178c5a82.js.gz +0 -0
- codex/static_root/assets/admin-menu-BpEPGKr_.js +0 -1
- codex/static_root/assets/admin-menu-BpEPGKr_.js.br +0 -0
- codex/static_root/assets/admin-menu-BpEPGKr_.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-DDF4rY07.4f1158b650ab.js +0 -1
- codex/static_root/assets/admin-settings-button-progress-DDF4rY07.4f1158b650ab.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-DDF4rY07.4f1158b650ab.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-DDF4rY07.js +0 -1
- codex/static_root/assets/admin-settings-button-progress-DDF4rY07.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-DDF4rY07.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.2548c49a853e.css +0 -1
- codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.css +0 -1
- codex/static_root/assets/browser-C0KS3g2E.0bf1c9c6319c.js +0 -1
- codex/static_root/assets/browser-C0KS3g2E.0bf1c9c6319c.js.br +0 -0
- codex/static_root/assets/browser-C0KS3g2E.0bf1c9c6319c.js.gz +0 -0
- codex/static_root/assets/browser-C0KS3g2E.js +0 -1
- codex/static_root/assets/browser-C0KS3g2E.js.br +0 -0
- codex/static_root/assets/browser-C0KS3g2E.js.gz +0 -0
- codex/static_root/assets/browser-JFL2hLjt.21cb2f7335f7.css +0 -1
- codex/static_root/assets/browser-JFL2hLjt.21cb2f7335f7.css.br +0 -0
- codex/static_root/assets/browser-JFL2hLjt.21cb2f7335f7.css.gz +0 -0
- codex/static_root/assets/browser-JFL2hLjt.css +0 -1
- codex/static_root/assets/browser-JFL2hLjt.css.br +0 -0
- codex/static_root/assets/browser-JFL2hLjt.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-DXJalgW4.a9f34729599d.js +0 -1
- codex/static_root/assets/change-password-dialog-DXJalgW4.a9f34729599d.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DXJalgW4.a9f34729599d.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DXJalgW4.js +0 -1
- codex/static_root/assets/change-password-dialog-DXJalgW4.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DXJalgW4.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-CqDEpU9k.e1811488121d.js +0 -1
- codex/static_root/assets/confirm-dialog-CqDEpU9k.e1811488121d.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CqDEpU9k.e1811488121d.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-CqDEpU9k.js +0 -1
- codex/static_root/assets/confirm-dialog-CqDEpU9k.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CqDEpU9k.js.gz +0 -0
- codex/static_root/assets/datetime-column-UxNaJr8b.c06a11531af3.js +0 -1
- codex/static_root/assets/datetime-column-UxNaJr8b.c06a11531af3.js.br +0 -0
- codex/static_root/assets/datetime-column-UxNaJr8b.c06a11531af3.js.gz +0 -0
- codex/static_root/assets/datetime-column-UxNaJr8b.js +0 -1
- codex/static_root/assets/datetime-column-UxNaJr8b.js.br +0 -0
- codex/static_root/assets/datetime-column-UxNaJr8b.js.gz +0 -0
- codex/static_root/assets/filter-DskcqZHA.e707b5a05b4b.js +0 -1
- codex/static_root/assets/filter-DskcqZHA.e707b5a05b4b.js.br +0 -0
- codex/static_root/assets/filter-DskcqZHA.e707b5a05b4b.js.gz +0 -0
- codex/static_root/assets/filter-DskcqZHA.js +0 -1
- codex/static_root/assets/filter-DskcqZHA.js.br +0 -0
- codex/static_root/assets/filter-DskcqZHA.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/flag-tab-xBeWEQ0w.582e77d9e885.js +0 -1
- codex/static_root/assets/flag-tab-xBeWEQ0w.582e77d9e885.js.br +0 -0
- codex/static_root/assets/flag-tab-xBeWEQ0w.582e77d9e885.js.gz +0 -0
- codex/static_root/assets/flag-tab-xBeWEQ0w.js +0 -1
- codex/static_root/assets/flag-tab-xBeWEQ0w.js.br +0 -0
- codex/static_root/assets/flag-tab-xBeWEQ0w.js.gz +0 -0
- codex/static_root/assets/group-tab-Czt2x61x.56e2886b1bac.js +0 -1
- codex/static_root/assets/group-tab-Czt2x61x.56e2886b1bac.js.br +0 -0
- codex/static_root/assets/group-tab-Czt2x61x.56e2886b1bac.js.gz +0 -0
- codex/static_root/assets/group-tab-Czt2x61x.js +0 -1
- codex/static_root/assets/group-tab-Czt2x61x.js.br +0 -0
- codex/static_root/assets/group-tab-Czt2x61x.js.gz +0 -0
- codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css +0 -1
- codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css.br +0 -0
- codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css.gz +0 -0
- codex/static_root/assets/group-tab-DkIN1Heu.css +0 -1
- codex/static_root/assets/group-tab-DkIN1Heu.css.br +0 -0
- codex/static_root/assets/group-tab-DkIN1Heu.css.gz +0 -0
- codex/static_root/assets/http-error-NHcwE5e_.d49089e40589.js +0 -1
- codex/static_root/assets/http-error-NHcwE5e_.d49089e40589.js.br +0 -0
- codex/static_root/assets/http-error-NHcwE5e_.d49089e40589.js.gz +0 -0
- codex/static_root/assets/http-error-NHcwE5e_.js +0 -1
- codex/static_root/assets/http-error-NHcwE5e_.js.br +0 -0
- codex/static_root/assets/http-error-NHcwE5e_.js.gz +0 -0
- codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css +0 -1
- codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css.br +0 -0
- codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css.gz +0 -0
- codex/static_root/assets/index-CL_6g4tJ.css +0 -1
- codex/static_root/assets/index-CL_6g4tJ.css.br +0 -0
- codex/static_root/assets/index-CL_6g4tJ.css.gz +0 -0
- codex/static_root/assets/index-DYNNO5kn.24a2d270253a.js +0 -1
- codex/static_root/assets/index-DYNNO5kn.24a2d270253a.js.br +0 -0
- codex/static_root/assets/index-DYNNO5kn.24a2d270253a.js.gz +0 -0
- codex/static_root/assets/index-DYNNO5kn.js +0 -1
- codex/static_root/assets/index-DYNNO5kn.js.br +0 -0
- codex/static_root/assets/index-DYNNO5kn.js.gz +0 -0
- codex/static_root/assets/library-tab-CgIqcjvj.60327dfa8ecb.js +0 -1
- codex/static_root/assets/library-tab-CgIqcjvj.60327dfa8ecb.js.br +0 -0
- codex/static_root/assets/library-tab-CgIqcjvj.60327dfa8ecb.js.gz +0 -0
- codex/static_root/assets/library-tab-CgIqcjvj.js +0 -1
- codex/static_root/assets/library-tab-CgIqcjvj.js.br +0 -0
- codex/static_root/assets/library-tab-CgIqcjvj.js.gz +0 -0
- 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.br +0 -0
- codex/static_root/assets/library-tab-Wew8YOLv.css.gz +0 -0
- codex/static_root/assets/main-B3EwXQ3Q.14dfc21e272c.js +0 -35
- codex/static_root/assets/main-B3EwXQ3Q.14dfc21e272c.js.br +0 -0
- codex/static_root/assets/main-B3EwXQ3Q.14dfc21e272c.js.gz +0 -0
- codex/static_root/assets/main-B3EwXQ3Q.js +0 -35
- codex/static_root/assets/main-B3EwXQ3Q.js.br +0 -0
- codex/static_root/assets/main-B3EwXQ3Q.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-YkzUXx0B.f39d84e2380a.js +0 -1
- codex/static_root/assets/pager-full-pdf-YkzUXx0B.f39d84e2380a.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-YkzUXx0B.f39d84e2380a.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-YkzUXx0B.js +0 -1
- codex/static_root/assets/pager-full-pdf-YkzUXx0B.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-YkzUXx0B.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-CrruiVov.3bf9b795350d.js +0 -1
- codex/static_root/assets/pagination-toolbar-CrruiVov.3bf9b795350d.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-CrruiVov.3bf9b795350d.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-CrruiVov.js +0 -1
- codex/static_root/assets/pagination-toolbar-CrruiVov.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-CrruiVov.js.gz +0 -0
- codex/static_root/assets/pdf-doc-ctqZIwOP.7e7b2c815ea4.js.br +0 -0
- codex/static_root/assets/pdf-doc-ctqZIwOP.7e7b2c815ea4.js.gz +0 -0
- codex/static_root/assets/pdf-doc-ctqZIwOP.js.br +0 -0
- codex/static_root/assets/pdf-doc-ctqZIwOP.js.gz +0 -0
- codex/static_root/assets/reader-DPLhdrJD.268417c618c5.js +0 -2
- codex/static_root/assets/reader-DPLhdrJD.268417c618c5.js.br +0 -0
- codex/static_root/assets/reader-DPLhdrJD.268417c618c5.js.gz +0 -0
- codex/static_root/assets/reader-DPLhdrJD.js +0 -2
- codex/static_root/assets/reader-DPLhdrJD.js.br +0 -0
- codex/static_root/assets/reader-DPLhdrJD.js.gz +0 -0
- 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.br +0 -0
- codex/static_root/assets/reader-nD70BeEz.css.gz +0 -0
- codex/static_root/assets/relation-chips-DOALMcWL.5d3b8100ba03.js +0 -1
- codex/static_root/assets/relation-chips-DOALMcWL.5d3b8100ba03.js.br +0 -0
- codex/static_root/assets/relation-chips-DOALMcWL.5d3b8100ba03.js.gz +0 -0
- codex/static_root/assets/relation-chips-DOALMcWL.js +0 -1
- codex/static_root/assets/relation-chips-DOALMcWL.js.br +0 -0
- codex/static_root/assets/relation-chips-DOALMcWL.js.gz +0 -0
- codex/static_root/assets/settings-drawer-BVj1U_LC.c68369e0c2de.js +0 -2
- codex/static_root/assets/settings-drawer-BVj1U_LC.c68369e0c2de.js.br +0 -0
- codex/static_root/assets/settings-drawer-BVj1U_LC.c68369e0c2de.js.gz +0 -0
- codex/static_root/assets/settings-drawer-BVj1U_LC.js +0 -2
- codex/static_root/assets/settings-drawer-BVj1U_LC.js.br +0 -0
- codex/static_root/assets/settings-drawer-BVj1U_LC.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-DDLwwwnP.35305258097b.js +0 -1
- codex/static_root/assets/stats-tab-DDLwwwnP.35305258097b.js.br +0 -0
- codex/static_root/assets/stats-tab-DDLwwwnP.35305258097b.js.gz +0 -0
- codex/static_root/assets/stats-tab-DDLwwwnP.js +0 -1
- codex/static_root/assets/stats-tab-DDLwwwnP.js.br +0 -0
- codex/static_root/assets/stats-tab-DDLwwwnP.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-BpP3n2dO.c853eb565200.js +0 -1
- codex/static_root/assets/task-tab-BpP3n2dO.c853eb565200.js.br +0 -0
- codex/static_root/assets/task-tab-BpP3n2dO.c853eb565200.js.gz +0 -0
- codex/static_root/assets/task-tab-BpP3n2dO.js +0 -1
- codex/static_root/assets/task-tab-BpP3n2dO.js.br +0 -0
- codex/static_root/assets/task-tab-BpP3n2dO.js.gz +0 -0
- codex/static_root/assets/transition-3g2arGgl.c6e6f91b7978.js +0 -1
- codex/static_root/assets/transition-3g2arGgl.c6e6f91b7978.js.br +0 -0
- codex/static_root/assets/transition-3g2arGgl.c6e6f91b7978.js.gz +0 -0
- codex/static_root/assets/transition-3g2arGgl.js +0 -1
- codex/static_root/assets/transition-3g2arGgl.js.br +0 -0
- codex/static_root/assets/transition-3g2arGgl.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/unauthorized-CdumQ1Vf.79d9a61eb572.js +0 -1
- codex/static_root/assets/unauthorized-CdumQ1Vf.79d9a61eb572.js.br +0 -0
- codex/static_root/assets/unauthorized-CdumQ1Vf.79d9a61eb572.js.gz +0 -0
- codex/static_root/assets/unauthorized-CdumQ1Vf.js +0 -1
- codex/static_root/assets/unauthorized-CdumQ1Vf.js.br +0 -0
- codex/static_root/assets/unauthorized-CdumQ1Vf.js.gz +0 -0
- codex/static_root/assets/user-tab-D6oOKZTP.05944b00c700.js +0 -1
- codex/static_root/assets/user-tab-D6oOKZTP.05944b00c700.js.br +0 -0
- codex/static_root/assets/user-tab-D6oOKZTP.05944b00c700.js.gz +0 -0
- codex/static_root/assets/user-tab-D6oOKZTP.js +0 -1
- codex/static_root/assets/user-tab-D6oOKZTP.js.br +0 -0
- codex/static_root/assets/user-tab-D6oOKZTP.js.gz +0 -0
- codex/static_root/manifest.c5f1de88b1ac.json +0 -712
- codex/static_root/manifest.c5f1de88b1ac.json.br +0 -0
- codex/static_root/manifest.c5f1de88b1ac.json.gz +0 -0
- codex/views/browser/annotate/__init__.py +0 -1
- codex/views/browser/annotate/bookmark.py +0 -112
- codex/views/browser/annotate/card.py +0 -61
- codex/views/browser/annotate/order.py +0 -247
- codex/views/browser/filters/filter.py +0 -69
- codex/views/browser/group_mtime.py +0 -83
- codex/views/browser/metadata/__init__.py +0 -1
- codex/views/browser/metadata/annotate.py +0 -109
- codex/views/browser/metadata/copy_intersections.py +0 -90
- codex/views/browser/metadata/metadata.py +0 -83
- codex/views/browser/metadata/query_intersections.py +0 -112
- codex/views/browser/params.py +0 -64
- codex/views/timezone.py +0 -54
- {codex-1.7.0.dist-info → codex-1.7.0a0.dist-info}/LICENSE +0 -0
- {codex-1.7.0.dist-info → codex-1.7.0a0.dist-info}/WHEEL +0 -0
- {codex-1.7.0.dist-info → codex-1.7.0a0.dist-info}/entry_points.txt +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"""Browser Page Bounds Checking."""
|
|
2
2
|
|
|
3
3
|
from codex.logger.logging import get_logger
|
|
4
|
-
from codex.views.browser.
|
|
4
|
+
from codex.views.browser.annotations import BrowserAnnotationsView
|
|
5
5
|
from codex.views.util import Route
|
|
6
6
|
|
|
7
7
|
LOG = get_logger(__name__)
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class BrowserPageInBoundsView(
|
|
10
|
+
class BrowserPageInBoundsView(BrowserAnnotationsView):
|
|
11
11
|
"""Browser Page Bounds Checking."""
|
|
12
12
|
|
|
13
13
|
def _get_back_one_page_route(self, num_pages):
|
codex/views/browser/paginate.py
CHANGED
|
@@ -5,8 +5,14 @@ from math import ceil
|
|
|
5
5
|
from django.core.paginator import EmptyPage, Paginator
|
|
6
6
|
|
|
7
7
|
from codex.logger.logging import get_logger
|
|
8
|
+
from codex.models import (
|
|
9
|
+
Comic,
|
|
10
|
+
Folder,
|
|
11
|
+
)
|
|
8
12
|
from codex.views.browser.page_in_bounds import BrowserPageInBoundsView
|
|
9
|
-
from codex.views.const import
|
|
13
|
+
from codex.views.const import (
|
|
14
|
+
MAX_OBJ_PER_PAGE,
|
|
15
|
+
)
|
|
10
16
|
|
|
11
17
|
LOG = get_logger(__name__)
|
|
12
18
|
|
|
@@ -14,7 +20,7 @@ LOG = get_logger(__name__)
|
|
|
14
20
|
class BrowserPaginateView(BrowserPageInBoundsView):
|
|
15
21
|
"""Paginate Groups and Books."""
|
|
16
22
|
|
|
17
|
-
def _paginate_section(self, qs, page):
|
|
23
|
+
def _paginate_section(self, model, qs, page):
|
|
18
24
|
"""Paginate a group or Comic section."""
|
|
19
25
|
orphans = 0 if self.model_group == "f" or self.params.get("q") else 5
|
|
20
26
|
paginator = Paginator(qs, MAX_OBJ_PER_PAGE, orphans=orphans)
|
|
@@ -22,21 +28,21 @@ class BrowserPaginateView(BrowserPageInBoundsView):
|
|
|
22
28
|
paginator_page = paginator.page(page)
|
|
23
29
|
qs = paginator_page.object_list
|
|
24
30
|
except EmptyPage:
|
|
25
|
-
if
|
|
26
|
-
model_name =
|
|
31
|
+
if model != Folder:
|
|
32
|
+
model_name = self.model.__name__ if self.model else "UnknownGroup"
|
|
27
33
|
LOG.warning(f"No {model_name}s on page {page}")
|
|
28
|
-
qs =
|
|
34
|
+
qs = model.objects.none()
|
|
29
35
|
|
|
30
36
|
return qs
|
|
31
37
|
|
|
32
38
|
def _paginate_groups(self, group_qs):
|
|
33
39
|
"""Paginate the group object list before books."""
|
|
34
40
|
page = self.kwargs.get("page", 1)
|
|
35
|
-
return self._paginate_section(group_qs, page)
|
|
41
|
+
return self._paginate_section(self.model, group_qs, page)
|
|
36
42
|
|
|
37
43
|
def _paginate_books(self, book_qs, total_group_count, page_group_count):
|
|
38
44
|
"""Paginate the book object list based on how many group/folders are showing."""
|
|
39
|
-
group_remainder =
|
|
45
|
+
group_remainder = page_group_count % MAX_OBJ_PER_PAGE
|
|
40
46
|
num_books_on_mixed_page = MAX_OBJ_PER_PAGE - group_remainder
|
|
41
47
|
if page_group_count:
|
|
42
48
|
# There are books after the groups on the same page
|
|
@@ -44,7 +50,7 @@ class BrowserPaginateView(BrowserPageInBoundsView):
|
|
|
44
50
|
page_book_qs = book_qs[:num_books_on_mixed_page]
|
|
45
51
|
else:
|
|
46
52
|
# There are books after the groups on a new page
|
|
47
|
-
book_offset = 0 if
|
|
53
|
+
book_offset = 0 if group_remainder else num_books_on_mixed_page
|
|
48
54
|
page_book_qs = book_qs[book_offset:]
|
|
49
55
|
|
|
50
56
|
# Which book page are we on after groups?
|
|
@@ -52,7 +58,7 @@ class BrowserPaginateView(BrowserPageInBoundsView):
|
|
|
52
58
|
num_group_and_mixed_pages = ceil(total_group_count / MAX_OBJ_PER_PAGE)
|
|
53
59
|
book_only_page = page - num_group_and_mixed_pages
|
|
54
60
|
|
|
55
|
-
page_book_qs = self._paginate_section(page_book_qs, book_only_page)
|
|
61
|
+
page_book_qs = self._paginate_section(Comic, page_book_qs, book_only_page)
|
|
56
62
|
return page_book_qs
|
|
57
63
|
|
|
58
64
|
def paginate(self, group_qs, book_qs, group_count):
|
codex/views/browser/title.py
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
"""Browser title."""
|
|
2
2
|
|
|
3
|
-
from codex.models import Comic, Volume
|
|
3
|
+
from codex.models import BrowserGroupModel, Comic, Volume
|
|
4
4
|
from codex.views.browser.breadcrumbs import BrowserBreadcrumbsView
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class BrowserTitleView(BrowserBreadcrumbsView):
|
|
8
8
|
"""Browser title methods."""
|
|
9
9
|
|
|
10
|
+
def __init__(self, *args, **kwargs):
|
|
11
|
+
"""Set params for the type checker."""
|
|
12
|
+
super().__init__(*args, **kwargs)
|
|
13
|
+
self.group_instance: BrowserGroupModel | None = None
|
|
14
|
+
|
|
10
15
|
def _get_root_group_name(self):
|
|
11
16
|
if not self.model:
|
|
12
17
|
reason = "No model set in browser"
|
codex/views/browser/validate.py
CHANGED
|
@@ -3,17 +3,13 @@
|
|
|
3
3
|
from copy import deepcopy
|
|
4
4
|
from types import MappingProxyType
|
|
5
5
|
|
|
6
|
-
from rest_framework.exceptions import NotFound
|
|
7
|
-
|
|
8
|
-
from codex.choices import DEFAULT_BROWSER_ROUTE, mapping_to_dict
|
|
9
6
|
from codex.exceptions import SeeOtherRedirectError
|
|
10
7
|
from codex.logger.logging import get_logger
|
|
11
|
-
from codex.
|
|
12
|
-
from codex.views.browser.
|
|
8
|
+
from codex.serializers.choices import DEFAULTS
|
|
9
|
+
from codex.views.browser.base import BrowserBaseView
|
|
13
10
|
from codex.views.const import (
|
|
14
11
|
COMIC_GROUP,
|
|
15
12
|
FOLDER_GROUP,
|
|
16
|
-
GROUP_MODEL_MAP,
|
|
17
13
|
ROOT_GROUP,
|
|
18
14
|
STORY_ARC_GROUP,
|
|
19
15
|
)
|
|
@@ -21,55 +17,19 @@ from codex.views.const import (
|
|
|
21
17
|
LOG = get_logger(__name__)
|
|
22
18
|
|
|
23
19
|
|
|
24
|
-
class BrowserValidateView(
|
|
20
|
+
class BrowserValidateView(BrowserBaseView):
|
|
25
21
|
"""Browser Settings and URL Validation."""
|
|
26
22
|
|
|
27
23
|
DEFAULT_ROUTE = MappingProxyType(
|
|
28
|
-
{
|
|
24
|
+
{
|
|
25
|
+
"name": "browser",
|
|
26
|
+
"params": deepcopy(DEFAULTS["breadcrumbs"][0]),
|
|
27
|
+
}
|
|
29
28
|
)
|
|
30
29
|
|
|
31
|
-
def __init__(self, *args, **kwargs):
|
|
32
|
-
"""Initialize properties."""
|
|
33
|
-
super().__init__(*args, **kwargs)
|
|
34
|
-
self._is_admin: bool | None = None
|
|
35
|
-
self._model_group: str = ""
|
|
36
|
-
self._model: type[BrowserGroupModel] | None = None
|
|
37
|
-
self._rel_prefix: str | None = None
|
|
38
|
-
self._valid_nav_groups: tuple[str, ...] | None = None
|
|
39
|
-
|
|
40
|
-
@property
|
|
41
|
-
def model_group(self):
|
|
42
|
-
"""Memoize the model group."""
|
|
43
|
-
if not self._model_group:
|
|
44
|
-
group = self.kwargs["group"]
|
|
45
|
-
if group == ROOT_GROUP:
|
|
46
|
-
group = self.params["top_group"]
|
|
47
|
-
self._model_group = group
|
|
48
|
-
return self._model_group
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def model(self) -> type[BrowserGroupModel] | None:
|
|
52
|
-
"""Memoize the model for the browse list."""
|
|
53
|
-
if not self._model:
|
|
54
|
-
model = GROUP_MODEL_MAP.get(self.model_group)
|
|
55
|
-
if model is None:
|
|
56
|
-
group = self.kwargs["group"]
|
|
57
|
-
detail = f"Cannot browse {group=}"
|
|
58
|
-
LOG.debug(detail)
|
|
59
|
-
raise NotFound(detail=detail)
|
|
60
|
-
self._model = model
|
|
61
|
-
return self._model
|
|
62
|
-
|
|
63
|
-
@property
|
|
64
|
-
def rel_prefix(self):
|
|
65
|
-
"""Memoize model rel prefix."""
|
|
66
|
-
if self._rel_prefix is None:
|
|
67
|
-
self._rel_prefix = self.get_rel_prefix(self.model)
|
|
68
|
-
return self._rel_prefix
|
|
69
|
-
|
|
70
30
|
def raise_redirect(self, reason, route_mask=None, settings_mask=None):
|
|
71
31
|
"""Redirect the client to a valid group url."""
|
|
72
|
-
route =
|
|
32
|
+
route = deepcopy(dict(self.DEFAULT_ROUTE))
|
|
73
33
|
if route_mask:
|
|
74
34
|
route["params"].update(route_mask) # type: ignore
|
|
75
35
|
settings = deepcopy(dict(self.params))
|
|
@@ -113,7 +73,7 @@ class BrowserValidateView(SearchFilterView):
|
|
|
113
73
|
settings_mask = {"top_group": valid_top_group, "breadcrumbs": breadcrumbs}
|
|
114
74
|
self.raise_redirect(reason, route, settings_mask)
|
|
115
75
|
|
|
116
|
-
def
|
|
76
|
+
def set_valid_browse_nav_groups(self, valid_top_groups):
|
|
117
77
|
"""Get valid nav groups for the current settings.
|
|
118
78
|
|
|
119
79
|
Valid nav groups are the top group and below that are also
|
|
@@ -136,7 +96,7 @@ class BrowserValidateView(SearchFilterView):
|
|
|
136
96
|
reason = f"Nav group {nav_group} unavailable, redirect to {ROOT_GROUP}"
|
|
137
97
|
self.raise_redirect(reason)
|
|
138
98
|
|
|
139
|
-
|
|
99
|
+
self.valid_nav_groups = tuple(valid_nav_groups)
|
|
140
100
|
|
|
141
101
|
def _validate_folder_settings(self):
|
|
142
102
|
"""Check that all the view variables for folder mode are set right."""
|
|
@@ -153,7 +113,7 @@ class BrowserValidateView(SearchFilterView):
|
|
|
153
113
|
|
|
154
114
|
valid_top_groups = (FOLDER_GROUP,)
|
|
155
115
|
self._validate_top_group(valid_top_groups)
|
|
156
|
-
|
|
116
|
+
self.valid_nav_groups = valid_top_groups
|
|
157
117
|
|
|
158
118
|
def _validate_browser_group_settings(self):
|
|
159
119
|
"""Check that all the view variables for browser mode are set right."""
|
|
@@ -172,24 +132,29 @@ class BrowserValidateView(SearchFilterView):
|
|
|
172
132
|
|
|
173
133
|
# Validate Browser nav_group
|
|
174
134
|
# Redirect if nav group is wrong
|
|
175
|
-
|
|
135
|
+
self.set_valid_browse_nav_groups(valid_top_groups)
|
|
176
136
|
|
|
177
|
-
def _validate_story_arc_settings(self)
|
|
137
|
+
def _validate_story_arc_settings(self):
|
|
178
138
|
"""Validate story arc settings."""
|
|
179
139
|
valid_top_groups = (STORY_ARC_GROUP,)
|
|
180
140
|
self._validate_top_group(valid_top_groups)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
141
|
+
self.valid_nav_groups = valid_top_groups
|
|
142
|
+
|
|
143
|
+
def validate_settings(self):
|
|
144
|
+
"""Validate group and top group settings."""
|
|
145
|
+
group = self.kwargs["group"]
|
|
146
|
+
if group == FOLDER_GROUP:
|
|
147
|
+
self._validate_folder_settings()
|
|
148
|
+
elif group == STORY_ARC_GROUP:
|
|
149
|
+
self._validate_story_arc_settings()
|
|
150
|
+
else:
|
|
151
|
+
self._validate_browser_group_settings()
|
|
152
|
+
|
|
153
|
+
# Validate order
|
|
154
|
+
if self.order_key == "filename" and not self.admin_flags["folder_view"]:
|
|
155
|
+
pks = self.kwargs["pks"]
|
|
156
|
+
page = self.kwargs["page"]
|
|
157
|
+
route_changes = {"group": group, "pks": pks, "page": page}
|
|
158
|
+
reason = "order by filename not allowed by admin flag."
|
|
159
|
+
settings_mask = {"order_by": "sort_name"}
|
|
160
|
+
self.raise_redirect(reason, route_changes, settings_mask)
|
codex/views/download.py
CHANGED
|
@@ -22,7 +22,7 @@ class DownloadView(AuthFilterAPIView):
|
|
|
22
22
|
"""Download a comic archive."""
|
|
23
23
|
pk = kwargs.get("pk")
|
|
24
24
|
try:
|
|
25
|
-
group_acl_filter = self.get_group_acl_filter(Comic
|
|
25
|
+
group_acl_filter = self.get_group_acl_filter(Comic)
|
|
26
26
|
comic = (
|
|
27
27
|
Comic.objects.filter(group_acl_filter)
|
|
28
28
|
.only("path", "file_type")
|
codex/views/mixins.py
CHANGED
|
@@ -12,7 +12,7 @@ class SharedAnnotationsMixin:
|
|
|
12
12
|
"""Cross view annotation methods."""
|
|
13
13
|
|
|
14
14
|
@staticmethod
|
|
15
|
-
def _get_order_groups(
|
|
15
|
+
def _get_order_groups(pks, model_group):
|
|
16
16
|
"""Annotate sort_name."""
|
|
17
17
|
if not pks or len(pks) > 1:
|
|
18
18
|
order_groups = _SHOW_GROUPS
|
|
@@ -28,11 +28,12 @@ class SharedAnnotationsMixin:
|
|
|
28
28
|
return order_groups
|
|
29
29
|
|
|
30
30
|
@classmethod
|
|
31
|
-
def
|
|
31
|
+
def alias_sort_names(cls, qs, model, pks, model_group, show=None):
|
|
32
32
|
"""Annotate sort names for browser subclasses and reader."""
|
|
33
33
|
sort_name_annotations = {}
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
comic_sort_names = []
|
|
35
|
+
if model == Comic:
|
|
36
|
+
order_groups = cls._get_order_groups(pks, model_group)
|
|
36
37
|
for order_group in order_groups:
|
|
37
38
|
if show and not show.get(order_group):
|
|
38
39
|
continue
|
|
@@ -41,19 +42,23 @@ class SharedAnnotationsMixin:
|
|
|
41
42
|
name_field = "name" if group_name == "volume" else "sort_name"
|
|
42
43
|
sort_name = F(f"{group_name}__{name_field}")
|
|
43
44
|
sort_name_annotations[ann_name] = sort_name
|
|
44
|
-
|
|
45
|
+
comic_sort_names.append(ann_name)
|
|
46
|
+
elif model == Volume:
|
|
45
47
|
sort_name_annotations["sort_name"] = F("name")
|
|
46
|
-
|
|
48
|
+
|
|
49
|
+
if sort_name_annotations:
|
|
50
|
+
qs = qs.alias(**sort_name_annotations)
|
|
51
|
+
return qs, comic_sort_names
|
|
47
52
|
|
|
48
53
|
@classmethod
|
|
49
|
-
def annotate_group_names(cls, qs):
|
|
54
|
+
def annotate_group_names(cls, qs, model):
|
|
50
55
|
"""Annotate name fields by hoisting them up."""
|
|
51
56
|
# Optimized to only lookup what is used on the frontend
|
|
52
57
|
target = cls.TARGET # type: ignore
|
|
53
58
|
if target not in frozenset({"browser", "opds1", "opds2", "reader"}):
|
|
54
59
|
return qs
|
|
55
60
|
group_names = {}
|
|
56
|
-
if
|
|
61
|
+
if model == Comic:
|
|
57
62
|
if target != "reader":
|
|
58
63
|
group_names["publisher_name"] = F("publisher__name")
|
|
59
64
|
if target == "opds2":
|
|
@@ -64,25 +69,8 @@ class SharedAnnotationsMixin:
|
|
|
64
69
|
"volume_name": F("volume__name"),
|
|
65
70
|
}
|
|
66
71
|
)
|
|
67
|
-
elif
|
|
72
|
+
elif model == Volume:
|
|
68
73
|
group_names["series_name"] = F("series__name")
|
|
69
|
-
elif
|
|
74
|
+
elif model == Imprint:
|
|
70
75
|
group_names["publisher_name"] = F("publisher__name")
|
|
71
76
|
return qs.annotate(**group_names)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class BookmarkSearchMixin:
|
|
75
|
-
"""Create Bookmark Search kwargs."""
|
|
76
|
-
|
|
77
|
-
@staticmethod
|
|
78
|
-
def get_bookmark_search_kwargs(auth_filter, comic_filter=None):
|
|
79
|
-
"""Get the search kwargs for a user's authentication state."""
|
|
80
|
-
# search kwargs are relative to the bookmark object.
|
|
81
|
-
search_kwargs = {}
|
|
82
|
-
search_kwargs.update(auth_filter)
|
|
83
|
-
|
|
84
|
-
if comic_filter:
|
|
85
|
-
for key, value in comic_filter.items():
|
|
86
|
-
search_kwargs[f"comic__{key}"] = value
|
|
87
|
-
|
|
88
|
-
return search_kwargs
|
codex/views/opds/const.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""OPDS Common consts."""
|
|
2
2
|
|
|
3
|
+
from collections.abc import Mapping
|
|
3
4
|
from types import MappingProxyType
|
|
4
5
|
|
|
5
6
|
from codex.models import (
|
|
@@ -62,7 +63,7 @@ class MimeType:
|
|
|
62
63
|
HTML = "text/html"
|
|
63
64
|
AUTH_BASIC = "http://opds-spec.org/auth/basic"
|
|
64
65
|
COOKIE = "cookie"
|
|
65
|
-
FILE_TYPE_MAP:
|
|
66
|
+
FILE_TYPE_MAP: Mapping[str, str] = MappingProxyType(
|
|
66
67
|
{
|
|
67
68
|
"CBZ": "application/vnd.comicbook+zip",
|
|
68
69
|
"CBR": "application/vnd.comicbook+rar",
|
|
@@ -70,7 +71,7 @@ class MimeType:
|
|
|
70
71
|
"PDF": "application/pdf",
|
|
71
72
|
}
|
|
72
73
|
)
|
|
73
|
-
SIMPLE_FILE_TYPE_MAP:
|
|
74
|
+
SIMPLE_FILE_TYPE_MAP: Mapping[str, str] = MappingProxyType(
|
|
74
75
|
{
|
|
75
76
|
# PocketBooks needs app/zip
|
|
76
77
|
"CBZ": "application/zip",
|
codex/views/opds/urls.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from django.urls import reverse
|
|
4
4
|
from rest_framework.response import Response
|
|
5
5
|
|
|
6
|
-
from codex.choices import
|
|
6
|
+
from codex.serializers.choices import DEFAULTS
|
|
7
7
|
from codex.serializers.opds.urls import OPDSURLsSerializer
|
|
8
8
|
from codex.views.auth import AuthGenericAPIView
|
|
9
9
|
from codex.views.util import pop_name
|
|
@@ -19,7 +19,7 @@ class OPDSURLsView(AuthGenericAPIView):
|
|
|
19
19
|
def get(self, *args, **kwargs):
|
|
20
20
|
"""Resolve the urls."""
|
|
21
21
|
obj = {}
|
|
22
|
-
route =
|
|
22
|
+
route = DEFAULTS["breadcrumbs"][0]
|
|
23
23
|
route = pop_name(route)
|
|
24
24
|
for version in _OPDS_VERSIONS:
|
|
25
25
|
key = f"v{version}"
|
codex/views/opds/util.py
CHANGED
|
@@ -5,11 +5,11 @@ from django.http.response import HttpResponseRedirect
|
|
|
5
5
|
from django.urls import reverse
|
|
6
6
|
from django.utils.http import urlencode
|
|
7
7
|
|
|
8
|
-
from codex.choices import DEFAULT_BROWSER_ROUTE
|
|
9
8
|
from codex.models import (
|
|
10
9
|
Contributor,
|
|
11
10
|
ContributorPerson,
|
|
12
11
|
)
|
|
12
|
+
from codex.serializers.choices import DEFAULTS
|
|
13
13
|
from codex.views.auth import GroupACLMixin
|
|
14
14
|
from codex.views.opds.const import OPDS_M2M_MODELS
|
|
15
15
|
|
|
@@ -71,7 +71,8 @@ def full_redirect_view(url_name):
|
|
|
71
71
|
|
|
72
72
|
def func(request):
|
|
73
73
|
"""Redirect to view, forwarding query strings and auth."""
|
|
74
|
-
kwargs =
|
|
74
|
+
kwargs = DEFAULTS["breadcrumbs"][0]
|
|
75
|
+
kwargs.pop("name", None)
|
|
75
76
|
url = reverse(url_name, kwargs=kwargs)
|
|
76
77
|
|
|
77
78
|
# Forward the query string.
|
|
@@ -82,9 +82,7 @@ class OPDS1EntryLinksMixin:
|
|
|
82
82
|
else:
|
|
83
83
|
mime_type = MimeType.NAV
|
|
84
84
|
|
|
85
|
-
thr_count =
|
|
86
|
-
0 if self.fake else 1 if self.obj.group == "c" else self.obj.child_count
|
|
87
|
-
)
|
|
85
|
+
thr_count = 0 if self.fake else self.obj.child_count
|
|
88
86
|
rel = Rel.ALTERNATE if metadata else "subsection"
|
|
89
87
|
|
|
90
88
|
return OPDS1Link(rel, href, mime_type, thr_count=thr_count)
|
codex/views/opds/v1/facets.py
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from types import MappingProxyType
|
|
5
|
-
from typing import Any
|
|
6
5
|
|
|
7
6
|
from django.urls import reverse
|
|
8
7
|
|
|
9
8
|
from codex.models import AdminFlag
|
|
10
9
|
from codex.views.browser.browser import BrowserView
|
|
11
|
-
from codex.views.opds.const import MimeType, Rel
|
|
12
|
-
from codex.views.opds.util import
|
|
10
|
+
from codex.views.opds.const import MimeType, Rel
|
|
11
|
+
from codex.views.opds.util import update_href_query_params
|
|
13
12
|
from codex.views.opds.v1.data import OPDS1Link
|
|
14
13
|
from codex.views.opds.v1.entry.data import OPDS1EntryData, OPDS1EntryObject
|
|
15
14
|
from codex.views.opds.v1.entry.entry import OPDS1Entry
|
|
@@ -82,61 +81,13 @@ DEFAULT_FACETS = {
|
|
|
82
81
|
class OPDS1FacetsView(BrowserView):
|
|
83
82
|
"""OPDS 1 Facets methods."""
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@property
|
|
94
|
-
def user_agent_name(self) -> str:
|
|
95
|
-
"""Memoize user agent name."""
|
|
96
|
-
if self._user_agent_name is None:
|
|
97
|
-
self._user_agent_name = get_user_agent_name(self.request)
|
|
98
|
-
return self._user_agent_name
|
|
99
|
-
|
|
100
|
-
@property
|
|
101
|
-
def mime_type_map(self) -> MappingProxyType[str, str]:
|
|
102
|
-
"""Memoize mime type map."""
|
|
103
|
-
if self._mime_type_map is None:
|
|
104
|
-
self._mime_type_map = (
|
|
105
|
-
MimeType.SIMPLE_FILE_TYPE_MAP
|
|
106
|
-
if self.user_agent_name in UserAgentNames.SIMPLE_DOWNLOAD_MIME_TYPES
|
|
107
|
-
else MimeType.FILE_TYPE_MAP
|
|
108
|
-
)
|
|
109
|
-
return self._mime_type_map
|
|
110
|
-
|
|
111
|
-
@property
|
|
112
|
-
def use_facets(self) -> bool:
|
|
113
|
-
"""Memoize use_facets."""
|
|
114
|
-
if self._use_facets is None:
|
|
115
|
-
self._use_facets = self.user_agent_name in UserAgentNames.FACET_SUPPORT
|
|
116
|
-
return self._use_facets
|
|
117
|
-
|
|
118
|
-
@property
|
|
119
|
-
def obj(self) -> MappingProxyType[str, Any]:
|
|
120
|
-
"""Get the browser page and serialize it for this subclass."""
|
|
121
|
-
if self._obj is None:
|
|
122
|
-
group_qs, book_qs, num_pages, total_count, zero_pad, mtime = (
|
|
123
|
-
self._get_group_and_books()
|
|
124
|
-
)
|
|
125
|
-
book_qs = book_qs.select_related("series", "volume", "language")
|
|
126
|
-
|
|
127
|
-
title = self.get_browser_page_title()
|
|
128
|
-
self._obj = MappingProxyType(
|
|
129
|
-
{
|
|
130
|
-
"title": title,
|
|
131
|
-
"groups": group_qs,
|
|
132
|
-
"books": book_qs,
|
|
133
|
-
"zero_pad": zero_pad,
|
|
134
|
-
"num_pages": num_pages,
|
|
135
|
-
"total_count": total_count,
|
|
136
|
-
"mtime": mtime,
|
|
137
|
-
}
|
|
138
|
-
)
|
|
139
|
-
return self._obj
|
|
84
|
+
OPDS = 1
|
|
85
|
+
# Overwritten by get_object()
|
|
86
|
+
use_facets = False
|
|
87
|
+
skip_order_facets = False
|
|
88
|
+
acquisition_groups = frozenset()
|
|
89
|
+
mime_type_map = MimeType.FILE_TYPE_MAP
|
|
90
|
+
obj = MappingProxyType({})
|
|
140
91
|
|
|
141
92
|
def _facet(self, kwargs, facet_group, facet_title, new_query_params):
|
|
142
93
|
kwargs = pop_name(kwargs)
|
|
@@ -169,9 +120,9 @@ class OPDS1FacetsView(BrowserView):
|
|
|
169
120
|
)
|
|
170
121
|
qps = {**self.request.GET}
|
|
171
122
|
qps.update(query_params)
|
|
172
|
-
zero_pad
|
|
123
|
+
zero_pad = self.obj["zero_pad"]
|
|
173
124
|
data = OPDS1EntryData(
|
|
174
|
-
self.
|
|
125
|
+
self.acquisition_groups, zero_pad, False, self.mime_type_map
|
|
175
126
|
)
|
|
176
127
|
return OPDS1Entry(entry_obj, qps, data)
|
|
177
128
|
|
|
@@ -234,11 +185,7 @@ class OPDS1FacetsView(BrowserView):
|
|
|
234
185
|
def facets(self, entries=False, root=True):
|
|
235
186
|
"""Return facets."""
|
|
236
187
|
facets = []
|
|
237
|
-
|
|
238
|
-
add_order_facets = (
|
|
239
|
-
group != "c" and self.user_agent_name not in UserAgentNames.CLIENT_REORDERS
|
|
240
|
-
)
|
|
241
|
-
if not add_order_facets:
|
|
188
|
+
if not self.skip_order_facets:
|
|
242
189
|
facets += self._facet_group(FacetGroups.ORDER_BY, entries)
|
|
243
190
|
facets += self._facet_group(FacetGroups.ORDER_REVERSE, entries)
|
|
244
191
|
if root:
|
codex/views/opds/v1/feed.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""OPDS v1 feed."""
|
|
2
2
|
|
|
3
|
+
from types import MappingProxyType
|
|
3
4
|
from typing import TYPE_CHECKING, Any
|
|
4
5
|
|
|
5
6
|
from drf_spectacular.utils import extend_schema
|
|
@@ -16,7 +17,8 @@ from codex.serializers.opds.v1 import (
|
|
|
16
17
|
from codex.settings.settings import FALSY
|
|
17
18
|
from codex.views.const import MAX_OBJ_PER_PAGE
|
|
18
19
|
from codex.views.opds.auth import OPDSTemplateView
|
|
19
|
-
from codex.views.opds.const import BLANK_TITLE
|
|
20
|
+
from codex.views.opds.const import BLANK_TITLE, MimeType, UserAgentNames
|
|
21
|
+
from codex.views.opds.util import get_user_agent_name
|
|
20
22
|
from codex.views.opds.v1.entry.data import OPDS1EntryData
|
|
21
23
|
from codex.views.opds.v1.entry.entry import OPDS1Entry
|
|
22
24
|
from codex.views.opds.v1.links import (
|
|
@@ -53,14 +55,14 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView):
|
|
|
53
55
|
def opds_ns(self):
|
|
54
56
|
"""Dynamic opds namespace."""
|
|
55
57
|
try:
|
|
56
|
-
return OpdsNs.ACQUISITION if self.
|
|
58
|
+
return OpdsNs.ACQUISITION if self.is_aq_feed else OpdsNs.CATALOG
|
|
57
59
|
except Exception:
|
|
58
60
|
LOG.exception("Getting OPDS v1 namespace")
|
|
59
61
|
|
|
60
62
|
@property
|
|
61
63
|
def is_acquisition(self):
|
|
62
64
|
"""Is acquisition."""
|
|
63
|
-
return self.
|
|
65
|
+
return self.is_aq_feed
|
|
64
66
|
|
|
65
67
|
@property
|
|
66
68
|
def id_tag(self):
|
|
@@ -126,7 +128,7 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView):
|
|
|
126
128
|
if objs := self.obj.get(key):
|
|
127
129
|
zero_pad: int = self.obj["zero_pad"] # type: ignore
|
|
128
130
|
data = OPDS1EntryData(
|
|
129
|
-
self.
|
|
131
|
+
self.acquisition_groups, zero_pad, metadata, self.mime_type_map
|
|
130
132
|
)
|
|
131
133
|
fallback = bool(self.admin_flags.get("folder_view"))
|
|
132
134
|
import_pks = set()
|
|
@@ -164,8 +166,65 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView):
|
|
|
164
166
|
LOG.exception("Getting OPDS v1 entries")
|
|
165
167
|
return entries
|
|
166
168
|
|
|
169
|
+
def get_object(self): # type: ignore
|
|
170
|
+
"""Get the browser page and serialize it for this subclass."""
|
|
171
|
+
group_qs, book_qs, num_pages, total_count, zero_pad, mtime = (
|
|
172
|
+
super()._get_group_and_books()
|
|
173
|
+
)
|
|
174
|
+
book_qs = book_qs.select_related("series", "volume", "language")
|
|
175
|
+
|
|
176
|
+
title = self.get_browser_page_title()
|
|
177
|
+
self.obj = MappingProxyType(
|
|
178
|
+
{
|
|
179
|
+
"title": title,
|
|
180
|
+
"groups": group_qs,
|
|
181
|
+
"books": book_qs,
|
|
182
|
+
"zero_pad": zero_pad,
|
|
183
|
+
"num_pages": num_pages,
|
|
184
|
+
"total_count": total_count,
|
|
185
|
+
"mtime": mtime,
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
self.is_aq_feed = self.model_group in ("c", "f")
|
|
190
|
+
|
|
191
|
+
# Do not return a Mapping despite the type. Return self for the serializer.
|
|
192
|
+
return self
|
|
193
|
+
|
|
194
|
+
def _set_user_agent_variables(self):
|
|
195
|
+
"""Set User Agent variables."""
|
|
196
|
+
user_agent_name = get_user_agent_name(self.request)
|
|
197
|
+
|
|
198
|
+
self.user_facets = user_agent_name in UserAgentNames.FACET_SUPPORT
|
|
199
|
+
self.skip_order_facets = user_agent_name in UserAgentNames.CLIENT_REORDERS
|
|
200
|
+
if user_agent_name in UserAgentNames.SIMPLE_DOWNLOAD_MIME_TYPES:
|
|
201
|
+
self.mime_type_map = MimeType.SIMPLE_FILE_TYPE_MAP
|
|
202
|
+
|
|
203
|
+
def set_opds_request_type(self):
|
|
204
|
+
"""Set the opds request type variables."""
|
|
205
|
+
group = self.kwargs.get("group")
|
|
206
|
+
if group == "a":
|
|
207
|
+
self.acquisition_groups = frozenset({"a", "c"})
|
|
208
|
+
pks = self.kwargs["pks"]
|
|
209
|
+
self.is_opds_1_acquisition = group in self.acquisition_groups and pks
|
|
210
|
+
else:
|
|
211
|
+
self.acquisition_groups = frozenset({*self.valid_nav_groups[-2:]} | {"c"})
|
|
212
|
+
self.is_opds_1_acquisition = group in self.acquisition_groups
|
|
213
|
+
self.is_opds_metadata = (
|
|
214
|
+
self.request.GET.get("opdsMetadata", "").lower() not in FALSY
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
def init_request(self):
|
|
218
|
+
"""Initialize request."""
|
|
219
|
+
super().init_request()
|
|
220
|
+
self.set_opds_request_type()
|
|
221
|
+
self._set_user_agent_variables()
|
|
222
|
+
self.skip_order_facets |= self.kwargs.get("group") == "c"
|
|
223
|
+
|
|
167
224
|
@extend_schema(parameters=[input_serializer_class])
|
|
168
225
|
def get(self, *_args, **_kwargs):
|
|
169
226
|
"""Get the feed."""
|
|
170
|
-
|
|
227
|
+
self.init_request()
|
|
228
|
+
obj = self.get_object()
|
|
229
|
+
serializer = self.get_serializer(obj)
|
|
171
230
|
return Response(serializer.data, content_type=self.content_type)
|