codex 1.6.0a6__py3-none-any.whl → 1.6.0a7__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/exceptions.py +1 -0
- codex/librarian/importer/aggregate_metadata.py +2 -10
- codex/librarian/importer/{covers.py → cache.py} +2 -2
- codex/librarian/importer/importerd.py +5 -3
- codex/librarian/janitor/janitor.py +1 -1
- codex/librarian/librariand.py +1 -1
- codex/permissions.py +1 -1
- codex/serializers/admin.py +1 -2
- codex/serializers/browser/filters.py +8 -101
- codex/serializers/browser/mixins.py +20 -3
- codex/serializers/browser/page.py +2 -2
- codex/serializers/browser/settings.py +2 -0
- codex/serializers/fields.py +123 -0
- codex/serializers/mtime.py +25 -0
- codex/serializers/opds/v2.py +7 -11
- codex/serializers/opds/v2_unused.py +5 -3
- codex/serializers/reader.py +5 -2
- codex/serializers/route.py +7 -3
- codex/static_root/assets/VCheckbox-BOUtyxuo.c690f0cdbe48.js +1 -0
- codex/static_root/assets/VCheckbox-BOUtyxuo.c690f0cdbe48.js.br +0 -0
- codex/static_root/assets/VCheckbox-BOUtyxuo.c690f0cdbe48.js.gz +0 -0
- codex/static_root/assets/VCheckbox-BOUtyxuo.js +1 -0
- codex/static_root/assets/VCheckbox-BOUtyxuo.js.br +0 -0
- codex/static_root/assets/VCheckbox-BOUtyxuo.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js +1 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.js +1 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.js.gz +0 -0
- codex/static_root/assets/VCombobox-DjkDXe33.22617ea193b1.js +1 -0
- codex/static_root/assets/VCombobox-DjkDXe33.22617ea193b1.js.br +0 -0
- codex/static_root/assets/VCombobox-DjkDXe33.22617ea193b1.js.gz +0 -0
- codex/static_root/assets/VCombobox-DjkDXe33.js +1 -0
- codex/static_root/assets/VCombobox-DjkDXe33.js.br +0 -0
- codex/static_root/assets/VCombobox-DjkDXe33.js.gz +0 -0
- codex/static_root/assets/VDialog-X0zn9AGX.0d89c749b9a6.js +1 -0
- codex/static_root/assets/VDialog-X0zn9AGX.0d89c749b9a6.js.br +0 -0
- codex/static_root/assets/VDialog-X0zn9AGX.0d89c749b9a6.js.gz +0 -0
- codex/static_root/assets/VDialog-X0zn9AGX.js +1 -0
- codex/static_root/assets/VDialog-X0zn9AGX.js.br +0 -0
- codex/static_root/assets/VDialog-X0zn9AGX.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.43d65c777c58.js +1 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.43d65c777c58.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.43d65c777c58.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.js +1 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.2b4dfb984a8c.js +1 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.2b4dfb984a8c.js.br +0 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.2b4dfb984a8c.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.js +1 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.js.br +0 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.js.gz +0 -0
- codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js +1 -0
- codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js.br +0 -0
- codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js.gz +0 -0
- codex/static_root/assets/VSelect-DgfIKRnC.js +1 -0
- codex/static_root/assets/VSelect-DgfIKRnC.js.br +0 -0
- codex/static_root/assets/VSelect-DgfIKRnC.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.3030b7a270d6.js +1 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.3030b7a270d6.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.3030b7a270d6.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.js +1 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.71a7101cdddd.js +1 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.71a7101cdddd.js.br +0 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.71a7101cdddd.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.js +1 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.js.br +0 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.js.gz +0 -0
- codex/static_root/assets/{VTable-C0gAriFq.fa6e4b60d4ef.js → VTable-C7pKI7gU.087912f706f5.js} +1 -1
- codex/static_root/assets/VTable-C7pKI7gU.087912f706f5.js.br +0 -0
- codex/static_root/assets/VTable-C7pKI7gU.087912f706f5.js.gz +0 -0
- codex/static_root/assets/{VTable-C0gAriFq.js → VTable-C7pKI7gU.js} +1 -1
- codex/static_root/assets/VTable-C7pKI7gU.js.br +0 -0
- codex/static_root/assets/VTable-C7pKI7gU.js.gz +0 -0
- codex/static_root/assets/{VTextField-Da_Hs7ls.c295f24c251e.js → VTextField-Bs8oq9mk.7999fef12a03.js} +1 -1
- codex/static_root/assets/VTextField-Bs8oq9mk.7999fef12a03.js.br +0 -0
- codex/static_root/assets/VTextField-Bs8oq9mk.7999fef12a03.js.gz +0 -0
- codex/static_root/assets/{VTextField-Da_Hs7ls.js → VTextField-Bs8oq9mk.js} +1 -1
- codex/static_root/assets/VTextField-Bs8oq9mk.js.br +0 -0
- codex/static_root/assets/VTextField-Bs8oq9mk.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-CFhKCj49.b2458002a937.js → VWindowItem-iyZ1XOkP.409f7d292253.js} +1 -1
- codex/static_root/assets/VWindowItem-iyZ1XOkP.409f7d292253.js.br +0 -0
- codex/static_root/assets/VWindowItem-iyZ1XOkP.409f7d292253.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-CFhKCj49.js → VWindowItem-iyZ1XOkP.js} +1 -1
- codex/static_root/assets/VWindowItem-iyZ1XOkP.js.br +0 -0
- codex/static_root/assets/VWindowItem-iyZ1XOkP.js.gz +0 -0
- codex/static_root/assets/admin-B0pCBjma.2407da79bd20.js +1 -0
- codex/static_root/assets/admin-B0pCBjma.2407da79bd20.js.br +0 -0
- codex/static_root/assets/admin-B0pCBjma.2407da79bd20.js.gz +0 -0
- codex/static_root/assets/admin-B0pCBjma.js +1 -0
- codex/static_root/assets/admin-B0pCBjma.js.br +0 -0
- codex/static_root/assets/admin-B0pCBjma.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js +30 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.js +30 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.js.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css → admin-drawer-panel-o87BwD38.ce39427c8201.css} +1 -1
- codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.br +0 -0
- codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css.gz → admin-drawer-panel-o87BwD38.ce39427c8201.css.gz} +0 -0
- codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.css → admin-drawer-panel-o87BwD38.css} +1 -1
- codex/static_root/assets/admin-drawer-panel-o87BwD38.css.br +0 -0
- codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.css.gz → admin-drawer-panel-o87BwD38.css.gz} +0 -0
- codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js +1 -0
- codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js.br +0 -0
- codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js.gz +0 -0
- codex/static_root/assets/browser-DbyAjCNh.js +1 -0
- codex/static_root/assets/browser-DbyAjCNh.js.br +0 -0
- codex/static_root/assets/browser-DbyAjCNh.js.gz +0 -0
- codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css +1 -0
- codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css.br +0 -0
- codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css.gz +0 -0
- codex/static_root/assets/browser-VnzNj1t3.css +1 -0
- codex/static_root/assets/browser-VnzNj1t3.css.br +0 -0
- codex/static_root/assets/browser-VnzNj1t3.css.gz +0 -0
- codex/static_root/assets/{change-password-dialog-JYM9aAR9.f71d378f4fa6.js → change-password-dialog-DZ9dP8_F.930f4cae3cb0.js} +1 -1
- codex/static_root/assets/change-password-dialog-DZ9dP8_F.930f4cae3cb0.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DZ9dP8_F.930f4cae3cb0.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-JYM9aAR9.js → change-password-dialog-DZ9dP8_F.js} +1 -1
- codex/static_root/assets/change-password-dialog-DZ9dP8_F.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DZ9dP8_F.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-ZAZ6P1Rc.515858dd21e8.js → confirm-dialog-RP7JNStF.a752a7c1e697.js} +1 -1
- codex/static_root/assets/confirm-dialog-RP7JNStF.a752a7c1e697.js.br +0 -0
- codex/static_root/assets/confirm-dialog-RP7JNStF.a752a7c1e697.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-ZAZ6P1Rc.js → confirm-dialog-RP7JNStF.js} +1 -1
- codex/static_root/assets/confirm-dialog-RP7JNStF.js.br +0 -0
- codex/static_root/assets/confirm-dialog-RP7JNStF.js.gz +0 -0
- codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js +1 -0
- codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js.br +0 -0
- codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js +1 -0
- codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js.br +0 -0
- codex/static_root/assets/{datetime-column-BT1MSP82.9617f6b94ebf.js → datetime-column-Cu3WYyPj.54b4c3817b74.js} +1 -1
- codex/static_root/assets/datetime-column-Cu3WYyPj.54b4c3817b74.js.br +0 -0
- codex/static_root/assets/datetime-column-Cu3WYyPj.54b4c3817b74.js.gz +0 -0
- codex/static_root/assets/{datetime-column-BT1MSP82.js → datetime-column-Cu3WYyPj.js} +1 -1
- codex/static_root/assets/datetime-column-Cu3WYyPj.js.br +0 -0
- codex/static_root/assets/datetime-column-Cu3WYyPj.js.gz +0 -0
- codex/static_root/assets/filter-DAdGUt-1.3261cbcd50b5.js +1 -0
- codex/static_root/assets/filter-DAdGUt-1.3261cbcd50b5.js.br +0 -0
- codex/static_root/assets/filter-DAdGUt-1.3261cbcd50b5.js.gz +0 -0
- codex/static_root/assets/filter-DAdGUt-1.js +1 -0
- codex/static_root/assets/filter-DAdGUt-1.js.br +0 -0
- codex/static_root/assets/filter-DAdGUt-1.js.gz +0 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js +1 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js.br +0 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js.gz +0 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.js +1 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.js.br +0 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.js.gz +0 -0
- codex/static_root/assets/{group-tab-DFma2R-E.879c37b15bbd.js → group-tab-DEwh4jfB.a95097b5e320.js} +1 -1
- codex/static_root/assets/group-tab-DEwh4jfB.a95097b5e320.js.br +0 -0
- codex/static_root/assets/group-tab-DEwh4jfB.a95097b5e320.js.gz +0 -0
- codex/static_root/assets/{group-tab-DFma2R-E.js → group-tab-DEwh4jfB.js} +1 -1
- codex/static_root/assets/group-tab-DEwh4jfB.js.br +0 -0
- codex/static_root/assets/group-tab-DEwh4jfB.js.gz +0 -0
- codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js +1 -0
- codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js.br +0 -0
- codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js.gz +0 -0
- codex/static_root/assets/http-error-xs3mIL8U.js +1 -0
- codex/static_root/assets/http-error-xs3mIL8U.js.br +0 -0
- codex/static_root/assets/http-error-xs3mIL8U.js.gz +0 -0
- codex/static_root/assets/{library-tab-V8DUGoHN.809c548ff347.js → library-tab-DrXvD9B2.f765f9d3bae4.js} +1 -1
- codex/static_root/assets/library-tab-DrXvD9B2.f765f9d3bae4.js.br +0 -0
- codex/static_root/assets/library-tab-DrXvD9B2.f765f9d3bae4.js.gz +0 -0
- codex/static_root/assets/{library-tab-V8DUGoHN.js → library-tab-DrXvD9B2.js} +1 -1
- codex/static_root/assets/library-tab-DrXvD9B2.js.br +0 -0
- codex/static_root/assets/library-tab-DrXvD9B2.js.gz +0 -0
- codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js +32 -0
- codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js.br +0 -0
- codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js.gz +0 -0
- codex/static_root/assets/main-Dy9Uqpmh.js +32 -0
- codex/static_root/assets/main-Dy9Uqpmh.js.br +0 -0
- codex/static_root/assets/main-Dy9Uqpmh.js.gz +0 -0
- codex/static_root/assets/{main-sK7HC5h4.css → main-Ztp855PW.css} +1 -1
- codex/static_root/assets/main-Ztp855PW.css.br +0 -0
- codex/static_root/assets/{main-sK7HC5h4.css.gz → main-Ztp855PW.css.gz} +0 -0
- codex/static_root/assets/{main-sK7HC5h4.6f04ddfc5f1a.css → main-Ztp855PW.d46d718fac45.css} +1 -1
- codex/static_root/assets/main-Ztp855PW.d46d718fac45.css.br +0 -0
- codex/static_root/assets/{main-sK7HC5h4.6f04ddfc5f1a.css.gz → main-Ztp855PW.d46d718fac45.css.gz} +0 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js +1 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.js +1 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-ClZui9Zf.697d7ae11c21.css → pagination-toolbar-r6nbtWxg.4088ab042c0c.css} +1 -1
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.4088ab042c0c.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.4088ab042c0c.css.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-ClZui9Zf.css → pagination-toolbar-r6nbtWxg.css} +1 -1
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.css.gz +0 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.ec9bd13a5786.js +305 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.ec9bd13a5786.js.br +0 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.ec9bd13a5786.js.gz +0 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.js +305 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.js.br +0 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.js.gz +0 -0
- codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js +2 -0
- codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js.br +0 -0
- codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js.gz +0 -0
- codex/static_root/assets/reader-BXKUaUeC.js +2 -0
- codex/static_root/assets/reader-BXKUaUeC.js.br +0 -0
- codex/static_root/assets/reader-BXKUaUeC.js.gz +0 -0
- codex/static_root/assets/{reader-N2Ei_y2K.8c0cdc0d513f.css → reader-OXJ1KVaW.a463b19d0508.css} +1 -1
- codex/static_root/assets/reader-OXJ1KVaW.a463b19d0508.css.br +0 -0
- codex/static_root/assets/reader-OXJ1KVaW.a463b19d0508.css.gz +0 -0
- codex/static_root/assets/{reader-N2Ei_y2K.css → reader-OXJ1KVaW.css} +1 -1
- codex/static_root/assets/reader-OXJ1KVaW.css.br +0 -0
- codex/static_root/assets/reader-OXJ1KVaW.css.gz +0 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.1d7426dab654.js +1 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.1d7426dab654.js.br +0 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.1d7426dab654.js.gz +0 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.js +1 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.js.br +0 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.js.gz +0 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.337eecf2fdbb.js +2 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.337eecf2fdbb.js.br +0 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.337eecf2fdbb.js.gz +0 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.js +2 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.js.br +0 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.js.gz +0 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.544bf50ffb22.js +1 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.544bf50ffb22.js.br +0 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.544bf50ffb22.js.gz +0 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.js +1 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.js.br +0 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.js.gz +0 -0
- codex/static_root/assets/task-tab-C60TLP6e.63aa929a4ed6.js +1 -0
- codex/static_root/assets/task-tab-C60TLP6e.63aa929a4ed6.js.br +0 -0
- codex/static_root/assets/task-tab-C60TLP6e.63aa929a4ed6.js.gz +0 -0
- codex/static_root/assets/task-tab-C60TLP6e.js +1 -0
- codex/static_root/assets/task-tab-C60TLP6e.js.br +0 -0
- codex/static_root/assets/task-tab-C60TLP6e.js.gz +0 -0
- codex/static_root/assets/to-case-CR9beRR0.21bb805fdab4.js +1 -0
- codex/static_root/assets/to-case-CR9beRR0.js +1 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.c55650fac055.js +1 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.c55650fac055.js.br +0 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.c55650fac055.js.gz +0 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.js +1 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.js.br +0 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.js.gz +0 -0
- codex/static_root/assets/user-tab-ChuH7Atm.7e80cf1fb78e.js +1 -0
- codex/static_root/assets/user-tab-ChuH7Atm.7e80cf1fb78e.js.br +0 -0
- codex/static_root/assets/user-tab-ChuH7Atm.7e80cf1fb78e.js.gz +0 -0
- codex/static_root/assets/user-tab-ChuH7Atm.js +1 -0
- codex/static_root/assets/user-tab-ChuH7Atm.js.br +0 -0
- codex/static_root/assets/user-tab-ChuH7Atm.js.gz +0 -0
- codex/static_root/js/choices.079a01e0be1a.json +1 -0
- codex/static_root/js/choices.079a01e0be1a.json.br +0 -0
- codex/static_root/js/choices.079a01e0be1a.json.gz +0 -0
- codex/static_root/js/choices.json +1 -1
- codex/static_root/js/choices.json.br +0 -0
- codex/static_root/js/choices.json.gz +0 -0
- codex/static_root/manifest.dad79c8475ae.json +629 -0
- codex/static_root/manifest.dad79c8475ae.json.br +0 -0
- codex/static_root/manifest.dad79c8475ae.json.gz +0 -0
- codex/static_root/manifest.json +263 -276
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/urls/api/auth.py +2 -1
- codex/urls/api/browser.py +2 -2
- codex/urls/api/reader.py +2 -2
- codex/urls/api/v3.py +2 -0
- codex/util.py +10 -0
- codex/views/admin/api_key.py +2 -6
- codex/views/admin/auth.py +30 -0
- codex/views/admin/flag.py +2 -7
- codex/views/admin/group.py +2 -6
- codex/views/admin/library.py +7 -20
- codex/views/admin/stats.py +7 -66
- codex/views/admin/tasks.py +12 -11
- codex/views/admin/user.py +3 -9
- codex/views/auth.py +31 -52
- codex/views/bookmark.py +7 -11
- codex/views/browser/{browser_annotations.py → annotations.py} +91 -61
- codex/views/browser/base.py +23 -71
- codex/views/browser/breadcrumbs.py +200 -0
- codex/views/browser/browser.py +64 -337
- codex/views/browser/choices.py +25 -33
- codex/views/browser/filters/annotations.py +2 -2
- codex/views/browser/filters/bookmark.py +9 -13
- codex/views/browser/filters/field.py +6 -5
- codex/views/browser/filters/group.py +8 -5
- codex/views/browser/filters/search.py +11 -8
- codex/views/browser/metadata.py +3 -7
- codex/views/browser/{browser_order_by.py → order_by.py} +2 -6
- codex/views/browser/paginate.py +106 -0
- codex/views/browser/{session.py → settings.py} +4 -3
- codex/views/browser/title.py +48 -0
- codex/views/browser/validate.py +158 -0
- codex/views/const.py +97 -0
- codex/views/cover.py +4 -6
- codex/views/download.py +5 -8
- codex/views/frontend.py +4 -2
- codex/views/mtime.py +70 -0
- codex/views/opds/auth.py +17 -0
- codex/views/opds/authentication_v1.py +46 -45
- codex/views/opds/binary.py +4 -9
- codex/views/opds/const.py +13 -0
- codex/views/opds/urls.py +5 -4
- codex/views/opds/util.py +2 -8
- codex/views/opds/v1/facets.py +6 -7
- codex/views/opds/v1/feed.py +10 -17
- codex/views/opds/v1/links.py +6 -5
- codex/views/opds/v1/opensearch_v1.py +2 -6
- codex/views/opds/v2/feed.py +12 -15
- codex/views/opds/v2/links.py +3 -2
- codex/views/opds/v2/publications.py +21 -20
- codex/views/opds/v2/top_links.py +2 -2
- codex/views/public.py +38 -0
- codex/views/reader/arcs.py +101 -0
- codex/views/reader/books.py +199 -0
- codex/views/reader/page.py +3 -7
- codex/views/reader/reader.py +53 -298
- codex/views/reader/{session.py → settings.py} +4 -2
- codex/views/session.py +74 -102
- codex/views/settings.py +34 -0
- codex/views/template.py +3 -3
- codex/views/util.py +31 -0
- codex/views/utils.py +26 -0
- codex/views/version.py +2 -2
- {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/METADATA +12 -8
- {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/RECORD +332 -320
- codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js +0 -1
- codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js.br +0 -0
- codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js.gz +0 -0
- codex/static_root/assets/VCheckbox-BS5fdM4M.js +0 -1
- codex/static_root/assets/VCheckbox-BS5fdM4M.js.br +0 -0
- codex/static_root/assets/VCheckbox-BS5fdM4M.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js +0 -1
- codex/static_root/assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-m4IbdjEe.js +0 -1
- codex/static_root/assets/VCheckboxBtn-m4IbdjEe.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-m4IbdjEe.js.gz +0 -0
- codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js +0 -1
- codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js.br +0 -0
- codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js.gz +0 -0
- codex/static_root/assets/VCombobox-jg7SI5mn.js +0 -1
- codex/static_root/assets/VCombobox-jg7SI5mn.js.br +0 -0
- codex/static_root/assets/VCombobox-jg7SI5mn.js.gz +0 -0
- codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js +0 -1
- codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js.br +0 -0
- codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js.gz +0 -0
- codex/static_root/assets/VDialog-DiixpkQL.js +0 -1
- codex/static_root/assets/VDialog-DiixpkQL.js.br +0 -0
- codex/static_root/assets/VDialog-DiixpkQL.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js +0 -1
- codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-Db5mPFue.js +0 -1
- codex/static_root/assets/VExpansionPanels-Db5mPFue.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-Db5mPFue.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js +0 -1
- codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js.br +0 -0
- codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-DULWiMSI.js +0 -1
- codex/static_root/assets/VRadioGroup-DULWiMSI.js.br +0 -0
- codex/static_root/assets/VRadioGroup-DULWiMSI.js.gz +0 -0
- codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js +0 -1
- codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js.br +0 -0
- codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js.gz +0 -0
- codex/static_root/assets/VSelect-BnoCfCLY.js +0 -1
- codex/static_root/assets/VSelect-BnoCfCLY.js.br +0 -0
- codex/static_root/assets/VSelect-BnoCfCLY.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js +0 -1
- codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-BSL0qeL9.js +0 -1
- codex/static_root/assets/VSelectionControl-BSL0qeL9.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BSL0qeL9.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js +0 -1
- codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js.br +0 -0
- codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-BQtz8h9p.js +0 -1
- codex/static_root/assets/VSlideGroup-BQtz8h9p.js.br +0 -0
- codex/static_root/assets/VSlideGroup-BQtz8h9p.js.gz +0 -0
- codex/static_root/assets/VTable-C0gAriFq.fa6e4b60d4ef.js.br +0 -0
- codex/static_root/assets/VTable-C0gAriFq.fa6e4b60d4ef.js.gz +0 -0
- codex/static_root/assets/VTable-C0gAriFq.js.br +0 -0
- codex/static_root/assets/VTable-C0gAriFq.js.gz +0 -0
- codex/static_root/assets/VTextField-Da_Hs7ls.c295f24c251e.js.br +0 -0
- codex/static_root/assets/VTextField-Da_Hs7ls.c295f24c251e.js.gz +0 -0
- codex/static_root/assets/VTextField-Da_Hs7ls.js.br +0 -0
- codex/static_root/assets/VTextField-Da_Hs7ls.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CFhKCj49.b2458002a937.js.br +0 -0
- codex/static_root/assets/VWindowItem-CFhKCj49.b2458002a937.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CFhKCj49.js.br +0 -0
- codex/static_root/assets/VWindowItem-CFhKCj49.js.gz +0 -0
- codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js +0 -1
- codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js.br +0 -0
- codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js.gz +0 -0
- codex/static_root/assets/admin-BpGFsvOH.js +0 -1
- codex/static_root/assets/admin-BpGFsvOH.js.br +0 -0
- codex/static_root/assets/admin-BpGFsvOH.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BHdNPwzF.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js +0 -30
- codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js +0 -30
- codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js.gz +0 -0
- codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js +0 -1
- codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js.br +0 -0
- codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js.gz +0 -0
- codex/static_root/assets/browser-CRPvEdqv.js +0 -1
- codex/static_root/assets/browser-CRPvEdqv.js.br +0 -0
- codex/static_root/assets/browser-CRPvEdqv.js.gz +0 -0
- codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css +0 -1
- codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css.br +0 -0
- codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css.gz +0 -0
- codex/static_root/assets/browser-Zqc9cR6T.css +0 -1
- codex/static_root/assets/browser-Zqc9cR6T.css.br +0 -0
- codex/static_root/assets/browser-Zqc9cR6T.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-JYM9aAR9.f71d378f4fa6.js.br +0 -0
- codex/static_root/assets/change-password-dialog-JYM9aAR9.f71d378f4fa6.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-JYM9aAR9.js.br +0 -0
- codex/static_root/assets/change-password-dialog-JYM9aAR9.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.515858dd21e8.js.br +0 -0
- codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.515858dd21e8.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.js.br +0 -0
- codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.js.gz +0 -0
- codex/static_root/assets/datetime-column-BT1MSP82.9617f6b94ebf.js.br +0 -0
- codex/static_root/assets/datetime-column-BT1MSP82.9617f6b94ebf.js.gz +0 -0
- codex/static_root/assets/datetime-column-BT1MSP82.js.br +0 -0
- codex/static_root/assets/datetime-column-BT1MSP82.js.gz +0 -0
- codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js +0 -1
- codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js.br +0 -0
- codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js.gz +0 -0
- codex/static_root/assets/filter-frSNsexx.js +0 -1
- codex/static_root/assets/filter-frSNsexx.js.br +0 -0
- codex/static_root/assets/filter-frSNsexx.js.gz +0 -0
- codex/static_root/assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js +0 -1
- codex/static_root/assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js.br +0 -0
- codex/static_root/assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js.gz +0 -0
- codex/static_root/assets/flag-tab-Ci_XcDT0.js +0 -1
- codex/static_root/assets/flag-tab-Ci_XcDT0.js.br +0 -0
- codex/static_root/assets/flag-tab-Ci_XcDT0.js.gz +0 -0
- codex/static_root/assets/group-tab-DFma2R-E.879c37b15bbd.js.br +0 -0
- codex/static_root/assets/group-tab-DFma2R-E.879c37b15bbd.js.gz +0 -0
- codex/static_root/assets/group-tab-DFma2R-E.js.br +0 -0
- codex/static_root/assets/group-tab-DFma2R-E.js.gz +0 -0
- codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js +0 -1
- codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js.br +0 -0
- codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js.gz +0 -0
- codex/static_root/assets/http-error-B3fQGxpt.js +0 -1
- codex/static_root/assets/http-error-B3fQGxpt.js.br +0 -0
- codex/static_root/assets/http-error-B3fQGxpt.js.gz +0 -0
- codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js +0 -1
- codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.br +0 -0
- codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.gz +0 -0
- codex/static_root/assets/index-DUjeNg4x.js +0 -1
- codex/static_root/assets/index-DUjeNg4x.js.br +0 -0
- codex/static_root/assets/index-DUjeNg4x.js.gz +0 -0
- codex/static_root/assets/library-tab-V8DUGoHN.809c548ff347.js.br +0 -0
- codex/static_root/assets/library-tab-V8DUGoHN.809c548ff347.js.gz +0 -0
- codex/static_root/assets/library-tab-V8DUGoHN.js.br +0 -0
- codex/static_root/assets/library-tab-V8DUGoHN.js.gz +0 -0
- codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js +0 -32
- codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js.br +0 -0
- codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js.gz +0 -0
- codex/static_root/assets/main-Cavvqkyp.js +0 -32
- codex/static_root/assets/main-Cavvqkyp.js.br +0 -0
- codex/static_root/assets/main-Cavvqkyp.js.gz +0 -0
- codex/static_root/assets/main-sK7HC5h4.6f04ddfc5f1a.css.br +0 -0
- codex/static_root/assets/main-sK7HC5h4.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-ClZui9Zf.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-ClZui9Zf.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js +0 -1
- codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js +0 -1
- codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js.gz +0 -0
- codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js +0 -35
- codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js.br +0 -0
- codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js.gz +0 -0
- codex/static_root/assets/pdf-doc-4PKLN-Z3.js +0 -35
- codex/static_root/assets/pdf-doc-4PKLN-Z3.js.br +0 -0
- codex/static_root/assets/pdf-doc-4PKLN-Z3.js.gz +0 -0
- codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js +0 -2
- codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js.br +0 -0
- codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js.gz +0 -0
- codex/static_root/assets/reader-C39uGGxn.js +0 -2
- codex/static_root/assets/reader-C39uGGxn.js.br +0 -0
- codex/static_root/assets/reader-C39uGGxn.js.gz +0 -0
- codex/static_root/assets/reader-N2Ei_y2K.8c0cdc0d513f.css.br +0 -0
- codex/static_root/assets/reader-N2Ei_y2K.8c0cdc0d513f.css.gz +0 -0
- codex/static_root/assets/reader-N2Ei_y2K.css.br +0 -0
- codex/static_root/assets/reader-N2Ei_y2K.css.gz +0 -0
- codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js +0 -1
- codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js.br +0 -0
- codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js.gz +0 -0
- codex/static_root/assets/relation-chips-CAC5ytqH.js +0 -1
- codex/static_root/assets/relation-chips-CAC5ytqH.js.br +0 -0
- codex/static_root/assets/relation-chips-CAC5ytqH.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js +0 -2
- codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js.br +0 -0
- codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CT73ieiV.js +0 -2
- codex/static_root/assets/settings-drawer-CT73ieiV.js.br +0 -0
- codex/static_root/assets/settings-drawer-CT73ieiV.js.gz +0 -0
- codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js +0 -1
- codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js.br +0 -0
- codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js.gz +0 -0
- codex/static_root/assets/stats-tab-C6qAnV6-.js +0 -1
- codex/static_root/assets/stats-tab-C6qAnV6-.js.br +0 -0
- codex/static_root/assets/stats-tab-C6qAnV6-.js.gz +0 -0
- codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js +0 -1
- codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js.br +0 -0
- codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js.gz +0 -0
- codex/static_root/assets/task-tab-JcG2vvgt.js +0 -1
- codex/static_root/assets/task-tab-JcG2vvgt.js.br +0 -0
- codex/static_root/assets/task-tab-JcG2vvgt.js.gz +0 -0
- codex/static_root/assets/to-case-kUm8NPpW.5b3369f511b8.js +0 -1
- codex/static_root/assets/to-case-kUm8NPpW.js +0 -1
- codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js +0 -1
- codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js.br +0 -0
- codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js.gz +0 -0
- codex/static_root/assets/unauthorized-28bmiwAU.js +0 -1
- codex/static_root/assets/unauthorized-28bmiwAU.js.br +0 -0
- codex/static_root/assets/unauthorized-28bmiwAU.js.gz +0 -0
- codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js +0 -1
- codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js.br +0 -0
- codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js.gz +0 -0
- codex/static_root/assets/user-tab-BOq4BMMc.js +0 -1
- codex/static_root/assets/user-tab-BOq4BMMc.js.br +0 -0
- codex/static_root/assets/user-tab-BOq4BMMc.js.gz +0 -0
- codex/static_root/js/choices.23fedac2b9ba.json +0 -1
- codex/static_root/js/choices.23fedac2b9ba.json.br +0 -0
- codex/static_root/js/choices.23fedac2b9ba.json.gz +0 -0
- codex/static_root/manifest.ad9da9714e46.json +0 -642
- codex/static_root/manifest.ad9da9714e46.json.br +0 -0
- codex/static_root/manifest.ad9da9714e46.json.gz +0 -0
- codex/views/browser/browser_breadcrumbs.py +0 -175
- codex/views/browser/const.py +0 -3
- {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/LICENSE +0 -0
- {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/WHEEL +0 -0
- {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/entry_points.txt +0 -0
codex/exceptions.py
CHANGED
|
@@ -30,6 +30,7 @@ class SeeOtherRedirectError(APIException):
|
|
|
30
30
|
route: dict = detail.get("route", {}) # type: ignore
|
|
31
31
|
params: dict = route.get("params", DEFAULTS["breadcrumbs"][0])
|
|
32
32
|
# Save route in server format for redirect reverse
|
|
33
|
+
params.pop("name", None)
|
|
33
34
|
self.route_kwargs = params
|
|
34
35
|
# Serialize route for detail
|
|
35
36
|
serializer = RouteSerializer(params)
|
|
@@ -28,6 +28,7 @@ from codex.librarian.importer.status import ImportStatusTypes, status_notify
|
|
|
28
28
|
from codex.models import Imprint, Publisher, Series, Volume
|
|
29
29
|
from codex.models.admin import AdminFlag
|
|
30
30
|
from codex.status import Status
|
|
31
|
+
from codex.util import max_none
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class AggregateMetadataMixin(CleanMetadataMixin):
|
|
@@ -182,22 +183,13 @@ class AggregateMetadataMixin(CleanMetadataMixin):
|
|
|
182
183
|
all_fks[field] = set()
|
|
183
184
|
all_fks[field].add(name)
|
|
184
185
|
|
|
185
|
-
@staticmethod
|
|
186
|
-
def _none_max(a, b):
|
|
187
|
-
"""None aware math.max."""
|
|
188
|
-
if a is not None and b is not None:
|
|
189
|
-
return max(a, b)
|
|
190
|
-
if a is None:
|
|
191
|
-
return b
|
|
192
|
-
return a
|
|
193
|
-
|
|
194
186
|
@classmethod
|
|
195
187
|
def _set_max_group_count(cls, common_args, group_class, index, count_key):
|
|
196
188
|
"""Assign the maximum group count number."""
|
|
197
189
|
all_fks, group_tree, group_md = common_args
|
|
198
190
|
group_name = group_tree[0:index]
|
|
199
191
|
try:
|
|
200
|
-
count =
|
|
192
|
+
count = max_none(
|
|
201
193
|
all_fks[GROUP_TREES][Series].get(group_name),
|
|
202
194
|
group_md.get(count_key),
|
|
203
195
|
)
|
|
@@ -6,10 +6,10 @@ from django.db.models.query import Q
|
|
|
6
6
|
from codex.models import StoryArc
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class CacheMixin:
|
|
10
10
|
"""Update Groups timestamp for cover cache busting."""
|
|
11
11
|
|
|
12
|
-
def
|
|
12
|
+
def update_groups_with_changed_comics(self, start_time, deleted_comic_groups):
|
|
13
13
|
"""Update timestamps for each group for cover cache busting."""
|
|
14
14
|
total_count = 0
|
|
15
15
|
now = Now()
|
|
@@ -9,8 +9,8 @@ from django.utils.timezone import now
|
|
|
9
9
|
from humanize import naturaldelta
|
|
10
10
|
|
|
11
11
|
from codex.librarian.importer.aggregate_metadata import AggregateMetadataMixin
|
|
12
|
+
from codex.librarian.importer.cache import CacheMixin
|
|
12
13
|
from codex.librarian.importer.const import FIS, FKS, M2M_MDS, MDS
|
|
13
|
-
from codex.librarian.importer.covers import CoversMixin
|
|
14
14
|
from codex.librarian.importer.deleted import DeletedMixin
|
|
15
15
|
from codex.librarian.importer.failed_imports import FailedImportsMixin
|
|
16
16
|
from codex.librarian.importer.moved import MovedMixin
|
|
@@ -37,7 +37,7 @@ class ComicImporterThread(
|
|
|
37
37
|
UpdateComicsMixin,
|
|
38
38
|
FailedImportsMixin,
|
|
39
39
|
MovedMixin,
|
|
40
|
-
|
|
40
|
+
CacheMixin,
|
|
41
41
|
):
|
|
42
42
|
"""A worker to handle all bulk database updates."""
|
|
43
43
|
|
|
@@ -386,7 +386,9 @@ class ComicImporterThread(
|
|
|
386
386
|
deleted_comic_groups = {}
|
|
387
387
|
changed += self.delete(library, task, deleted_comic_groups)
|
|
388
388
|
|
|
389
|
-
self.
|
|
389
|
+
self.update_groups_with_changed_comics(
|
|
390
|
+
import_start_time, deleted_comic_groups
|
|
391
|
+
)
|
|
390
392
|
|
|
391
393
|
if changed:
|
|
392
394
|
cache.clear()
|
|
@@ -76,7 +76,7 @@ class Janitor(CleanupMixin, UpdateMixin, VacuumMixin, UpdateFailedImportsMixin):
|
|
|
76
76
|
except Exception:
|
|
77
77
|
self.log.exception(f"In {self.__class__.__name__}")
|
|
78
78
|
|
|
79
|
-
def run(self, task):
|
|
79
|
+
def run(self, task): # noqa: PLR0912,C901
|
|
80
80
|
"""Run Janitor tasks as the librarian process directly."""
|
|
81
81
|
try:
|
|
82
82
|
match task:
|
codex/librarian/librariand.py
CHANGED
|
@@ -77,7 +77,7 @@ class LibrarianDaemon(Process, LoggerBaseMixin):
|
|
|
77
77
|
self.queue.put(task)
|
|
78
78
|
self.search_indexer_abort_event = Manager().Event()
|
|
79
79
|
|
|
80
|
-
def _process_task(self, task):
|
|
80
|
+
def _process_task(self, task): # noqa: PLR0912,C901
|
|
81
81
|
"""Process an individual task popped off the queue."""
|
|
82
82
|
match task:
|
|
83
83
|
case CoverTask():
|
codex/permissions.py
CHANGED
|
@@ -8,7 +8,7 @@ from codex.models import Timestamp
|
|
|
8
8
|
class HasAPIKeyOrIsAdminUser(BasePermission):
|
|
9
9
|
"""Does the request have the current api key."""
|
|
10
10
|
|
|
11
|
-
def has_permission(self, request, view):
|
|
11
|
+
def has_permission(self, request, view): # type: ignore
|
|
12
12
|
"""Test the request api key against the database."""
|
|
13
13
|
data = request.GET if request.method == "GET" else request.POST
|
|
14
14
|
api_key = data.get("apiKey")
|
codex/serializers/admin.py
CHANGED
|
@@ -173,8 +173,7 @@ class AdminFolderSerializer(Serializer):
|
|
|
173
173
|
def validate_show_hidden(self, show_hidden):
|
|
174
174
|
"""Snakecase the showHidden field."""
|
|
175
175
|
return (
|
|
176
|
-
show_hidden == "true"
|
|
177
|
-
or self.initial_data.get("showHidden", False) == "true"
|
|
176
|
+
show_hidden == "true" or self.initial_data.get("showHidden") == "true" # type: ignore
|
|
178
177
|
)
|
|
179
178
|
|
|
180
179
|
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
"""Browser Settings Filter Serializers."""
|
|
2
2
|
|
|
3
|
-
from abc import ABC
|
|
4
|
-
|
|
5
|
-
from django.core.exceptions import ValidationError
|
|
6
|
-
from django.utils.translation import gettext_lazy as _
|
|
7
|
-
from rest_framework.fields import Field
|
|
8
3
|
from rest_framework.serializers import (
|
|
9
4
|
BooleanField,
|
|
10
|
-
CharField,
|
|
11
5
|
ChoiceField,
|
|
12
|
-
FloatField,
|
|
13
|
-
IntegerField,
|
|
14
|
-
ListField,
|
|
15
6
|
Serializer,
|
|
16
7
|
)
|
|
17
8
|
|
|
18
|
-
from codex.serializers.choices import CHOICES
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
from codex.serializers.choices import CHOICES
|
|
10
|
+
from codex.serializers.fields import (
|
|
11
|
+
BooleanListField,
|
|
12
|
+
CharListField,
|
|
13
|
+
DecadeListField,
|
|
14
|
+
FloatListField,
|
|
15
|
+
IntListField,
|
|
16
|
+
)
|
|
21
17
|
|
|
22
18
|
|
|
23
19
|
class BrowserFilterChoicesSerializer(Serializer):
|
|
@@ -47,95 +43,6 @@ class BrowserFilterChoicesSerializer(Serializer):
|
|
|
47
43
|
year = BooleanField(read_only=True)
|
|
48
44
|
|
|
49
45
|
|
|
50
|
-
def validate_decades(decades):
|
|
51
|
-
"""Validate decades."""
|
|
52
|
-
if not decades:
|
|
53
|
-
return
|
|
54
|
-
# * We don't need a whole db call just to be perfectly accurate
|
|
55
|
-
# * -1s are decoded back into None before validation
|
|
56
|
-
exists = False
|
|
57
|
-
for decade in decades:
|
|
58
|
-
if decade is None or decade % 10 == 0:
|
|
59
|
-
exists = True
|
|
60
|
-
break
|
|
61
|
-
if not exists:
|
|
62
|
-
raise ValidationError(_(f"Invalid decade in: {decades}"))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def validate_int_null(values):
|
|
66
|
-
"""Use a special code for null.
|
|
67
|
-
|
|
68
|
-
Because if a vuetify component has a null key it changes it to the
|
|
69
|
-
array index.
|
|
70
|
-
"""
|
|
71
|
-
for index, value in enumerate(values):
|
|
72
|
-
if value == VUETIFY_NULL_CODE:
|
|
73
|
-
values[index] = None
|
|
74
|
-
return values
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def validate_str_null(values):
|
|
78
|
-
"""Use a special code for null.
|
|
79
|
-
|
|
80
|
-
Because if a vuetify component has a null key it changes it to the
|
|
81
|
-
array index. This is the version for CharFields.
|
|
82
|
-
"""
|
|
83
|
-
for index, value in enumerate(values):
|
|
84
|
-
if value == VUETIFY_NULL_CODE_STR:
|
|
85
|
-
values[index] = None
|
|
86
|
-
return values
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
class FilterListField(ListField, ABC):
|
|
90
|
-
"""Filter List field with custom arguments."""
|
|
91
|
-
|
|
92
|
-
CHILD_CLASS = Field
|
|
93
|
-
VALIDATORS = ()
|
|
94
|
-
|
|
95
|
-
def __init__(self, *args, **kwargs):
|
|
96
|
-
"""Apply the subclass's arguments."""
|
|
97
|
-
super().__init__(
|
|
98
|
-
*args,
|
|
99
|
-
child=self.CHILD_CLASS(allow_null=True, **kwargs),
|
|
100
|
-
required=False,
|
|
101
|
-
validators=self.VALIDATORS,
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
class FloatListField(FilterListField):
|
|
106
|
-
"""Decimal List Field with validation."""
|
|
107
|
-
|
|
108
|
-
CHILD_CLASS = FloatField # type: ignore
|
|
109
|
-
VALIDATORS = (validate_int_null,)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
class IntListField(FilterListField):
|
|
113
|
-
"""Integer List Field with validation."""
|
|
114
|
-
|
|
115
|
-
CHILD_CLASS = IntegerField # type: ignore
|
|
116
|
-
VALIDATORS = (validate_int_null,)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
class DecadeListField(IntListField):
|
|
120
|
-
"""Integer List Field with validation for decades."""
|
|
121
|
-
|
|
122
|
-
VALIDATORS = (validate_int_null, validate_decades)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class CharListField(FilterListField):
|
|
126
|
-
"""Char List Field with validation."""
|
|
127
|
-
|
|
128
|
-
CHILD_CLASS = CharField # type: ignore
|
|
129
|
-
VALIDATORS = (validate_str_null,)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
class BooleanListField(FilterListField):
|
|
133
|
-
"""Bool List Field with validation."""
|
|
134
|
-
|
|
135
|
-
CHILD_CLASS = BooleanField # type: ignore
|
|
136
|
-
VALIDATORS = (validate_int_null,)
|
|
137
|
-
|
|
138
|
-
|
|
139
46
|
class BrowserSettingsFilterSerializer(Serializer):
|
|
140
47
|
"""Filter values for settings."""
|
|
141
48
|
|
|
@@ -10,6 +10,15 @@ from rest_framework.serializers import (
|
|
|
10
10
|
)
|
|
11
11
|
|
|
12
12
|
from codex.serializers.browser.filters import IntListField
|
|
13
|
+
from codex.serializers.fields import TimestampField
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BrowserCover(Serializer):
|
|
17
|
+
"""Browser Cover."""
|
|
18
|
+
|
|
19
|
+
custom = BooleanField(read_only=True, default=False)
|
|
20
|
+
pk = IntegerField(read_only=True, default=0)
|
|
21
|
+
mtime = TimestampField(read_only=True, default=0)
|
|
13
22
|
|
|
14
23
|
|
|
15
24
|
class BrowserAggregateSerializerMixin(Serializer):
|
|
@@ -20,9 +29,8 @@ class BrowserAggregateSerializerMixin(Serializer):
|
|
|
20
29
|
|
|
21
30
|
# Aggregate Annotations
|
|
22
31
|
child_count = IntegerField(read_only=True)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
cover_custom = BooleanField(read_only=True)
|
|
32
|
+
mtime = TimestampField(read_only=True)
|
|
33
|
+
cover = BrowserCover(read_only=True)
|
|
26
34
|
|
|
27
35
|
# Bookmark annotations
|
|
28
36
|
page = IntegerField(read_only=True)
|
|
@@ -31,3 +39,12 @@ class BrowserAggregateSerializerMixin(Serializer):
|
|
|
31
39
|
progress = DecimalField(
|
|
32
40
|
max_digits=5, decimal_places=2, read_only=True, coerce_to_string=False
|
|
33
41
|
)
|
|
42
|
+
|
|
43
|
+
def to_representation(self, instance):
|
|
44
|
+
"""Nest Cover Object."""
|
|
45
|
+
instance.cover = {
|
|
46
|
+
"custom": instance.cover_custom,
|
|
47
|
+
"pk": instance.cover_pk,
|
|
48
|
+
"mtime": instance.cover_mtime,
|
|
49
|
+
}
|
|
50
|
+
return super().to_representation(instance)
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from rest_framework.serializers import (
|
|
4
4
|
BooleanField,
|
|
5
5
|
CharField,
|
|
6
|
-
DateTimeField,
|
|
7
6
|
DecimalField,
|
|
8
7
|
IntegerField,
|
|
9
8
|
ListSerializer,
|
|
@@ -13,6 +12,7 @@ from rest_framework.serializers import (
|
|
|
13
12
|
from codex.serializers.browser.mixins import (
|
|
14
13
|
BrowserAggregateSerializerMixin,
|
|
15
14
|
)
|
|
15
|
+
from codex.serializers.fields import TimestampField
|
|
16
16
|
from codex.serializers.route import RouteSerializer
|
|
17
17
|
|
|
18
18
|
|
|
@@ -34,7 +34,6 @@ class BrowserCardSerializer(BrowserAggregateSerializerMixin):
|
|
|
34
34
|
order_value = CharField(read_only=True)
|
|
35
35
|
page_count = IntegerField(read_only=True)
|
|
36
36
|
reading_direction = CharField(read_only=True)
|
|
37
|
-
mtime = DateTimeField(format="%s", read_only=True)
|
|
38
37
|
|
|
39
38
|
|
|
40
39
|
class BrowserAdminFlagsSerializer(Serializer):
|
|
@@ -63,3 +62,4 @@ class BrowserPageSerializer(Serializer):
|
|
|
63
62
|
num_pages = IntegerField(read_only=True)
|
|
64
63
|
groups = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
|
|
65
64
|
books = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
|
|
65
|
+
mtime = TimestampField(read_only=True)
|
|
@@ -10,6 +10,7 @@ from rest_framework.serializers import (
|
|
|
10
10
|
|
|
11
11
|
from codex.serializers.browser.filters import BrowserSettingsFilterSerializer
|
|
12
12
|
from codex.serializers.choices import CHOICES, VUETIFY_NULL_CODE
|
|
13
|
+
from codex.serializers.fields import TimestampField
|
|
13
14
|
|
|
14
15
|
VUETIFY_NULL_CODE_STR = str(VUETIFY_NULL_CODE)
|
|
15
16
|
|
|
@@ -44,3 +45,4 @@ class BrowserSettingsSerializer(Serializer):
|
|
|
44
45
|
top_group = ChoiceField(choices=tuple(CHOICES["topGroup"].keys()), required=False)
|
|
45
46
|
opds_metadata = BooleanField(required=False)
|
|
46
47
|
limit = IntegerField(required=False)
|
|
48
|
+
mtime = TimestampField(read_only=True)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Custom fields."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from math import floor
|
|
6
|
+
|
|
7
|
+
from django.core.exceptions import ValidationError
|
|
8
|
+
from django.utils.translation import gettext_lazy as _
|
|
9
|
+
from rest_framework.fields import Field
|
|
10
|
+
from rest_framework.serializers import (
|
|
11
|
+
BooleanField,
|
|
12
|
+
CharField,
|
|
13
|
+
FloatField,
|
|
14
|
+
IntegerField,
|
|
15
|
+
ListField,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from codex.serializers.choices import VUETIFY_NULL_CODE
|
|
19
|
+
|
|
20
|
+
VUETIFY_NULL_CODE_STR = str(VUETIFY_NULL_CODE)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TimestampField(IntegerField):
|
|
24
|
+
"""IntegerTimestampField."""
|
|
25
|
+
|
|
26
|
+
def to_representation(self, value):
|
|
27
|
+
"""Convert to int from datetime, or castable."""
|
|
28
|
+
if isinstance(value, datetime):
|
|
29
|
+
value = floor(value.timestamp())
|
|
30
|
+
return int(value)
|
|
31
|
+
|
|
32
|
+
def to_internal_value(self, data):
|
|
33
|
+
"""Convert from castable, likely string."""
|
|
34
|
+
return int(data)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def validate_decades(decades):
|
|
38
|
+
"""Validate decades."""
|
|
39
|
+
if not decades:
|
|
40
|
+
return
|
|
41
|
+
# * We don't need a whole db call just to be perfectly accurate
|
|
42
|
+
# * -1s are decoded back into None before validation
|
|
43
|
+
exists = False
|
|
44
|
+
for decade in decades:
|
|
45
|
+
if decade is None or decade % 10 == 0:
|
|
46
|
+
exists = True
|
|
47
|
+
break
|
|
48
|
+
if not exists:
|
|
49
|
+
raise ValidationError(_(f"Invalid decade in: {decades}"))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def validate_int_null(values):
|
|
53
|
+
"""Use a special code for null.
|
|
54
|
+
|
|
55
|
+
Because if a vuetify component has a null key it changes it to the
|
|
56
|
+
array index.
|
|
57
|
+
"""
|
|
58
|
+
for index, value in enumerate(values):
|
|
59
|
+
if value == VUETIFY_NULL_CODE:
|
|
60
|
+
values[index] = None
|
|
61
|
+
return values
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def validate_str_null(values):
|
|
65
|
+
"""Use a special code for null.
|
|
66
|
+
|
|
67
|
+
Because if a vuetify component has a null key it changes it to the
|
|
68
|
+
array index. This is the version for CharFields.
|
|
69
|
+
"""
|
|
70
|
+
for index, value in enumerate(values):
|
|
71
|
+
if value == VUETIFY_NULL_CODE_STR:
|
|
72
|
+
values[index] = None
|
|
73
|
+
return values
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class FilterListField(ListField, ABC):
|
|
77
|
+
"""Filter List field with custom arguments."""
|
|
78
|
+
|
|
79
|
+
CHILD_CLASS = Field
|
|
80
|
+
VALIDATORS = ()
|
|
81
|
+
|
|
82
|
+
def __init__(self, *args, **kwargs):
|
|
83
|
+
"""Apply the subclass's arguments."""
|
|
84
|
+
super().__init__(
|
|
85
|
+
*args,
|
|
86
|
+
child=self.CHILD_CLASS(allow_null=True, **kwargs),
|
|
87
|
+
required=False,
|
|
88
|
+
validators=self.VALIDATORS,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class FloatListField(FilterListField):
|
|
93
|
+
"""Decimal List Field with validation."""
|
|
94
|
+
|
|
95
|
+
CHILD_CLASS = FloatField # type: ignore
|
|
96
|
+
VALIDATORS = (validate_int_null,)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class IntListField(FilterListField):
|
|
100
|
+
"""Integer List Field with validation."""
|
|
101
|
+
|
|
102
|
+
CHILD_CLASS = IntegerField # type: ignore
|
|
103
|
+
VALIDATORS = (validate_int_null,)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class DecadeListField(IntListField):
|
|
107
|
+
"""Integer List Field with validation for decades."""
|
|
108
|
+
|
|
109
|
+
VALIDATORS = (validate_int_null, validate_decades)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class CharListField(FilterListField):
|
|
113
|
+
"""Char List Field with validation."""
|
|
114
|
+
|
|
115
|
+
CHILD_CLASS = CharField # type: ignore
|
|
116
|
+
VALIDATORS = (validate_str_null,)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class BooleanListField(FilterListField):
|
|
120
|
+
"""Bool List Field with validation."""
|
|
121
|
+
|
|
122
|
+
CHILD_CLASS = BooleanField # type: ignore
|
|
123
|
+
VALIDATORS = (validate_int_null,)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Group Mtimes."""
|
|
2
|
+
|
|
3
|
+
from rest_framework.serializers import BooleanField, Serializer
|
|
4
|
+
|
|
5
|
+
from codex.serializers.fields import IntListField, TimestampField
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class GroupMtimeSerializer(Serializer):
|
|
9
|
+
"""Group Mtimes."""
|
|
10
|
+
|
|
11
|
+
pks = IntListField(read_only=True)
|
|
12
|
+
mtime = TimestampField(read_only=True)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class GroupsMtimeSerializer(Serializer):
|
|
16
|
+
"""Groups Mtimes."""
|
|
17
|
+
|
|
18
|
+
groups = GroupMtimeSerializer(many=True)
|
|
19
|
+
use_bookmark_filter = BooleanField(read_only=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MtimeSerializer(Serializer):
|
|
23
|
+
"""Max mtime for all submitted groups."""
|
|
24
|
+
|
|
25
|
+
max_mtime = TimestampField(read_only=True)
|
codex/serializers/opds/v2.py
CHANGED
|
@@ -11,11 +11,7 @@ from rest_framework.fields import (
|
|
|
11
11
|
)
|
|
12
12
|
from rest_framework.serializers import Serializer
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
class CharListField(ListField):
|
|
16
|
-
"""List of CharFields."""
|
|
17
|
-
|
|
18
|
-
child = CharField()
|
|
14
|
+
from codex.serializers.fields import CharListField
|
|
19
15
|
|
|
20
16
|
|
|
21
17
|
class OPDS2LinkPropertiesSerializer(Serializer):
|
|
@@ -69,7 +65,7 @@ class OPDS2LinkSerializer(Serializer):
|
|
|
69
65
|
return obj.get("rel")
|
|
70
66
|
|
|
71
67
|
|
|
72
|
-
class
|
|
68
|
+
class OPDS2LinkListField(ListField):
|
|
73
69
|
"""Link List."""
|
|
74
70
|
|
|
75
71
|
child = OPDS2LinkSerializer()
|
|
@@ -148,7 +144,7 @@ class OPDS2FacetSerializer(Serializer):
|
|
|
148
144
|
"""Facets."""
|
|
149
145
|
|
|
150
146
|
metadata = OPDS2MetadataSerializer(read_only=True)
|
|
151
|
-
links =
|
|
147
|
+
links = OPDS2LinkListField(read_only=True)
|
|
152
148
|
|
|
153
149
|
|
|
154
150
|
class OPDS2PublicationSerializer(OPDS2FacetSerializer):
|
|
@@ -158,19 +154,19 @@ class OPDS2PublicationSerializer(OPDS2FacetSerializer):
|
|
|
158
154
|
"""
|
|
159
155
|
|
|
160
156
|
metadata = OPDS2PublicationMetadataSerializer(read_only=True)
|
|
161
|
-
links =
|
|
162
|
-
images =
|
|
157
|
+
links = OPDS2LinkListField(read_only=True)
|
|
158
|
+
images = OPDS2LinkListField(read_only=True, required=False)
|
|
163
159
|
|
|
164
160
|
|
|
165
161
|
class OPDS2GroupSerializer(Serializer):
|
|
166
162
|
"""Group."""
|
|
167
163
|
|
|
168
164
|
metadata = OPDS2MetadataSerializer(read_only=True)
|
|
169
|
-
links =
|
|
165
|
+
links = OPDS2LinkListField(read_only=True, required=False)
|
|
170
166
|
publications = ListField(
|
|
171
167
|
child=OPDS2PublicationSerializer(), read_only=True, required=False
|
|
172
168
|
)
|
|
173
|
-
navigation =
|
|
169
|
+
navigation = OPDS2LinkListField(read_only=True, required=False)
|
|
174
170
|
|
|
175
171
|
|
|
176
172
|
class OPDS2FeedSerializer(OPDS2GroupSerializer):
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from rest_framework.fields import CharField, DateTimeField, DecimalField, IntegerField
|
|
4
4
|
from rest_framework.serializers import ChoiceField, Serializer
|
|
5
5
|
|
|
6
|
-
from codex.serializers.opds.v2 import
|
|
6
|
+
from codex.serializers.opds.v2 import OPDS2LinkListField
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class RecursiveField(Serializer):
|
|
@@ -15,7 +15,9 @@ class RecursiveField(Serializer):
|
|
|
15
15
|
|
|
16
16
|
def to_representation(self, instance):
|
|
17
17
|
"""Represent with own class."""
|
|
18
|
-
|
|
18
|
+
parent = self.parent
|
|
19
|
+
# Should not be ignored but is currently unused
|
|
20
|
+
serializer = parent.parent.__class__(instance, context=self.context) # type: ignore
|
|
19
21
|
return serializer.data
|
|
20
22
|
|
|
21
23
|
|
|
@@ -68,7 +70,7 @@ class OPDS2ProfileSerializer(Serializer):
|
|
|
68
70
|
|
|
69
71
|
name = CharField(read_only=True)
|
|
70
72
|
email = CharField(read_only=True)
|
|
71
|
-
links =
|
|
73
|
+
links = OPDS2LinkListField(read_only=True, required=False)
|
|
72
74
|
loans = OPDS2CopiesSerializer(read_only=True)
|
|
73
75
|
holds = OPDS2HoldsSerializer(read_only=True)
|
|
74
76
|
|
codex/serializers/reader.py
CHANGED
|
@@ -4,13 +4,13 @@ from rest_framework.serializers import (
|
|
|
4
4
|
BooleanField,
|
|
5
5
|
CharField,
|
|
6
6
|
ChoiceField,
|
|
7
|
-
DateTimeField,
|
|
8
7
|
DecimalField,
|
|
9
8
|
IntegerField,
|
|
10
9
|
Serializer,
|
|
11
10
|
)
|
|
12
11
|
|
|
13
12
|
from codex.models import Bookmark
|
|
13
|
+
from codex.serializers.fields import TimestampField
|
|
14
14
|
from codex.serializers.route import RouteSerializer
|
|
15
15
|
|
|
16
16
|
|
|
@@ -25,6 +25,7 @@ class ReaderSettingsSerializer(Serializer):
|
|
|
25
25
|
two_pages = BooleanField(allow_null=True, required=False)
|
|
26
26
|
reading_direction = CharField(allow_null=True, required=False)
|
|
27
27
|
read_rtl_in_reverse = BooleanField(allow_null=True, required=False)
|
|
28
|
+
mtime = TimestampField(read_only=True)
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class ReaderComicSerializer(Serializer):
|
|
@@ -34,7 +35,7 @@ class ReaderComicSerializer(Serializer):
|
|
|
34
35
|
settings = ReaderSettingsSerializer(read_only=True)
|
|
35
36
|
max_page = IntegerField(read_only=True)
|
|
36
37
|
reading_direction = CharField(read_only=True)
|
|
37
|
-
mtime =
|
|
38
|
+
mtime = TimestampField(read_only=True)
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
class ReaderArcSerializer(RouteSerializer):
|
|
@@ -43,6 +44,7 @@ class ReaderArcSerializer(RouteSerializer):
|
|
|
43
44
|
page = None
|
|
44
45
|
index = IntegerField(read_only=True, required=False)
|
|
45
46
|
count = IntegerField(read_only=True, required=False)
|
|
47
|
+
mtime = TimestampField(read_only=True)
|
|
46
48
|
|
|
47
49
|
|
|
48
50
|
class ReaderCurrentComicSerializer(ReaderComicSerializer):
|
|
@@ -84,3 +86,4 @@ class ReaderComicsSerializer(Serializer):
|
|
|
84
86
|
arcs = ReaderArcSerializer(many=True, read_only=True)
|
|
85
87
|
arc = ReaderArcSerializer(read_only=True)
|
|
86
88
|
close_route = RouteSerializer(read_only=True)
|
|
89
|
+
mtime = TimestampField(read_only=True)
|
codex/serializers/route.py
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
from rest_framework.fields import CharField, IntegerField
|
|
4
4
|
from rest_framework.serializers import Serializer
|
|
5
5
|
|
|
6
|
+
from codex.views.util import Route
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
class RouteSerializer(Serializer):
|
|
8
10
|
"""A vue route for the browser."""
|
|
@@ -14,7 +16,9 @@ class RouteSerializer(Serializer):
|
|
|
14
16
|
|
|
15
17
|
def to_representation(self, instance):
|
|
16
18
|
"""Allow submission of sequences instead of strings for pks."""
|
|
17
|
-
|
|
19
|
+
if isinstance(instance, Route):
|
|
20
|
+
instance = instance.dict()
|
|
21
|
+
pks = instance["pks"]
|
|
18
22
|
if not pks:
|
|
19
23
|
instance["pks"] = "0"
|
|
20
24
|
elif not isinstance(pks, str):
|
|
@@ -28,9 +32,9 @@ class RouteSerializer(Serializer):
|
|
|
28
32
|
pks = instance.get("pks")
|
|
29
33
|
if isinstance(pks, str):
|
|
30
34
|
pks = tuple(sorted(int(pk) for pk in pks.split(",")))
|
|
31
|
-
if 0 in pks:
|
|
35
|
+
if 0 in pks: # type: ignore
|
|
32
36
|
pks = ()
|
|
33
|
-
instance["pks"] = tuple(pks)
|
|
37
|
+
instance["pks"] = tuple(pks) # type: ignore
|
|
34
38
|
except ValueError:
|
|
35
39
|
instance["pks"] = ()
|
|
36
40
|
return instance
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{m as g,V as t}from"./VCheckboxBtn-B1-m5pEh.js";import{a as A,u as I,V as l}from"./VSelectionControl-CGu0oz0K.js";import{E as B,as as R,O as U,az as w,F as z,h as D,R as E,ct as M,S as u,aw as r}from"./admin-drawer-panel-BxoNUHQr.js";const N=B({...A(),...R(g(),["inline"])},"VCheckbox"),j=U()({name:"VCheckbox",inheritAttrs:!1,props:N(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(e,c){let{attrs:d,slots:a}=c;const s=w(e,"modelValue"),{isFocused:n,focus:i,blur:m}=I(e),V=z(),p=D(()=>e.id||`checkbox-${V}`);return E(()=>{const[b,f]=M(d),v=l.filterProps(e),k=t.filterProps(e);return u(l,r({class:["v-checkbox",e.class]},b,v,{modelValue:s.value,"onUpdate:modelValue":o=>s.value=o,id:p.value,focused:n.value,style:e.style}),{...a,default:o=>{let{id:h,messagesId:x,isDisabled:P,isReadonly:C,isValid:y}=o;return u(t,r(k,{id:h.value,"aria-describedby":x.value,disabled:P.value,readonly:C.value},f,{error:y.value===!1,modelValue:s.value,"onUpdate:modelValue":F=>s.value=F,onFocus:i,onBlur:m}),a)}})}),{}}});export{j as V};
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{m as g,V as t}from"./VCheckboxBtn-B1-m5pEh.js";import{a as A,u as I,V as l}from"./VSelectionControl-CGu0oz0K.js";import{E as B,as as R,O as U,az as w,F as z,h as D,R as E,ct as M,S as u,aw as r}from"./admin-drawer-panel-BxoNUHQr.js";const N=B({...A(),...R(g(),["inline"])},"VCheckbox"),j=U()({name:"VCheckbox",inheritAttrs:!1,props:N(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(e,c){let{attrs:d,slots:a}=c;const s=w(e,"modelValue"),{isFocused:n,focus:i,blur:m}=I(e),V=z(),p=D(()=>e.id||`checkbox-${V}`);return E(()=>{const[b,f]=M(d),v=l.filterProps(e),k=t.filterProps(e);return u(l,r({class:["v-checkbox",e.class]},b,v,{modelValue:s.value,"onUpdate:modelValue":o=>s.value=o,id:p.value,focused:n.value,style:e.style}),{...a,default:o=>{let{id:h,messagesId:x,isDisabled:P,isReadonly:C,isValid:y}=o;return u(t,r(k,{id:h.value,"aria-describedby":x.value,disabled:P.value,readonly:C.value},f,{error:y.value===!1,modelValue:s.value,"onUpdate:modelValue":F=>s.value=F,onFocus:i,onBlur:m}),a)}})}),{}}});export{j as V};
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as f,d as o}from"./VSelectionControl-CGu0oz0K.js";import{E as V,bh as h,O as v,az as c,h as l,R as I,as as k,S as x,aw as b}from"./admin-drawer-panel-BxoNUHQr.js";const C=V({indeterminate:Boolean,indeterminateIcon:{type:h,default:"$checkboxIndeterminate"},...f({falseIcon:"$checkboxOff",trueIcon:"$checkboxOn"})},"VCheckboxBtn"),B=v()({name:"VCheckboxBtn",props:C(),emits:{"update:modelValue":e=>!0,"update:indeterminate":e=>!0},setup(e,r){let{slots:s}=r;const t=c(e,"indeterminate"),n=c(e,"modelValue");function u(a){t.value&&(t.value=!1)}const i=l(()=>t.value?e.indeterminateIcon:e.falseIcon),d=l(()=>t.value?e.indeterminateIcon:e.trueIcon);return I(()=>{const a=k(o.filterProps(e),["modelValue"]);return x(o,b(a,{modelValue:n.value,"onUpdate:modelValue":[m=>n.value=m,u],class:["v-checkbox-btn",e.class],style:e.style,type:"checkbox",falseIcon:i.value,trueIcon:d.value,"aria-checked":t.value?"mixed":void 0}),s)}),{}}});export{B as V,C as m};
|
|
Binary file
|
|
Binary file
|