codex 1.7.0a0__py3-none-any.whl → 1.7.0a1__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/choices.py +404 -0
- codex/choices_to_json.py +122 -0
- codex/db.py +31 -15
- codex/exceptions.py +2 -3
- codex/librarian/bookmark/__init__.py +1 -0
- codex/librarian/bookmark/bookmarkd.py +38 -0
- codex/librarian/bookmark/tasks.py +19 -0
- codex/librarian/bookmark/update.py +154 -0
- codex/librarian/covers/coverd.py +3 -4
- codex/librarian/covers/create.py +8 -7
- codex/librarian/covers/path.py +1 -2
- codex/librarian/covers/purge.py +2 -2
- codex/librarian/janitor/integrity.py +1 -0
- codex/librarian/librariand.py +5 -0
- codex/librarian/watchdog/emitter.py +21 -19
- codex/librarian/watchdog/event_batcherd.py +0 -1
- codex/migrations/0030_nocase_collation_day_month_indexes_status_types.py +4 -0
- codex/models/admin.py +0 -5
- codex/models/functions.py +6 -5
- codex/models/query.py +6 -0
- codex/run.py +11 -9
- codex/serializers/admin/tasks.py +2 -2
- codex/serializers/browser/mixins.py +18 -14
- codex/serializers/browser/settings.py +4 -4
- codex/serializers/fields.py +9 -5
- codex/startup.py +6 -4
- codex/static_root/assets/VCheckbox-B38iL9f_.81d9c00753e7.js +1 -0
- codex/static_root/assets/VCheckbox-B38iL9f_.81d9c00753e7.js.br +0 -0
- codex/static_root/assets/VCheckbox-B38iL9f_.81d9c00753e7.js.gz +0 -0
- codex/static_root/assets/VCheckbox-B38iL9f_.js +1 -0
- codex/static_root/assets/VCheckbox-B38iL9f_.js.br +0 -0
- codex/static_root/assets/VCheckbox-B38iL9f_.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-BbNnqvzj.aa7fa886f86a.js +1 -0
- codex/static_root/assets/VCheckboxBtn-BbNnqvzj.aa7fa886f86a.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-BbNnqvzj.aa7fa886f86a.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-BbNnqvzj.js +1 -0
- codex/static_root/assets/VCheckboxBtn-BbNnqvzj.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-BbNnqvzj.js.gz +0 -0
- codex/static_root/assets/VCombobox-BaV3XhIr.bf0c945d80a9.js +1 -0
- codex/static_root/assets/VCombobox-BaV3XhIr.bf0c945d80a9.js.br +0 -0
- codex/static_root/assets/VCombobox-BaV3XhIr.bf0c945d80a9.js.gz +0 -0
- codex/static_root/assets/VCombobox-BaV3XhIr.js +1 -0
- codex/static_root/assets/VCombobox-BaV3XhIr.js.br +0 -0
- codex/static_root/assets/VCombobox-BaV3XhIr.js.gz +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.css +1 -0
- codex/static_root/assets/VDialog-CSvrKKb2.css.br +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.css.gz +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css +1 -0
- codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.br +0 -0
- codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.gz +0 -0
- codex/static_root/assets/VDialog-DJR54d5g.9d6a52f62db3.js +1 -0
- codex/static_root/assets/VDialog-DJR54d5g.9d6a52f62db3.js.br +0 -0
- codex/static_root/assets/VDialog-DJR54d5g.9d6a52f62db3.js.gz +0 -0
- codex/static_root/assets/VDialog-DJR54d5g.js +1 -0
- codex/static_root/assets/VDialog-DJR54d5g.js.br +0 -0
- codex/static_root/assets/VDialog-DJR54d5g.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CJWqDA9d.acf5acdb3a81.js +1 -0
- codex/static_root/assets/VExpansionPanels-CJWqDA9d.acf5acdb3a81.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CJWqDA9d.acf5acdb3a81.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CJWqDA9d.js +1 -0
- codex/static_root/assets/VExpansionPanels-CJWqDA9d.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CJWqDA9d.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-BFLE3yCT.8b78cefe4206.js +1 -0
- codex/static_root/assets/VRadioGroup-BFLE3yCT.8b78cefe4206.js.br +0 -0
- codex/static_root/assets/VRadioGroup-BFLE3yCT.8b78cefe4206.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-BFLE3yCT.js +1 -0
- codex/static_root/assets/VRadioGroup-BFLE3yCT.js.br +0 -0
- codex/static_root/assets/VRadioGroup-BFLE3yCT.js.gz +0 -0
- codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css +1 -0
- 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 +1 -0
- codex/static_root/assets/VSelect-DLu8bpcs.css.br +0 -0
- codex/static_root/assets/VSelect-DLu8bpcs.css.gz +0 -0
- codex/static_root/assets/VSelect-Dvsi19pi.6d38dc99e0a8.js +1 -0
- codex/static_root/assets/VSelect-Dvsi19pi.6d38dc99e0a8.js.br +0 -0
- codex/static_root/assets/VSelect-Dvsi19pi.6d38dc99e0a8.js.gz +0 -0
- codex/static_root/assets/VSelect-Dvsi19pi.js +1 -0
- codex/static_root/assets/VSelect-Dvsi19pi.js.br +0 -0
- codex/static_root/assets/VSelect-Dvsi19pi.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-BioGLzkQ.106c3be4b6d4.js +1 -0
- codex/static_root/assets/VSelectionControl-BioGLzkQ.106c3be4b6d4.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BioGLzkQ.106c3be4b6d4.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-BioGLzkQ.js +1 -0
- codex/static_root/assets/VSelectionControl-BioGLzkQ.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BioGLzkQ.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css +1 -0
- 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 +1 -0
- 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-CFkaPBuS.1d168fc87687.js +1 -0
- codex/static_root/assets/VSlideGroup-CFkaPBuS.1d168fc87687.js.br +0 -0
- codex/static_root/assets/VSlideGroup-CFkaPBuS.1d168fc87687.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-CFkaPBuS.js +1 -0
- codex/static_root/assets/VSlideGroup-CFkaPBuS.js.br +0 -0
- codex/static_root/assets/VSlideGroup-CFkaPBuS.js.gz +0 -0
- codex/static_root/assets/VTable-B7x3Oih2.d0010dab39ce.js +1 -0
- codex/static_root/assets/VTable-B7x3Oih2.d0010dab39ce.js.br +0 -0
- codex/static_root/assets/VTable-B7x3Oih2.d0010dab39ce.js.gz +0 -0
- codex/static_root/assets/VTable-B7x3Oih2.js +1 -0
- codex/static_root/assets/VTable-B7x3Oih2.js.br +0 -0
- codex/static_root/assets/VTable-B7x3Oih2.js.gz +0 -0
- codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css +1 -0
- 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 +1 -0
- 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-rsRdtAxl.488a06f530fe.js +1 -0
- codex/static_root/assets/VTextField-rsRdtAxl.488a06f530fe.js.br +0 -0
- codex/static_root/assets/VTextField-rsRdtAxl.488a06f530fe.js.gz +0 -0
- codex/static_root/assets/VTextField-rsRdtAxl.js +1 -0
- codex/static_root/assets/VTextField-rsRdtAxl.js.br +0 -0
- codex/static_root/assets/VTextField-rsRdtAxl.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CibnlNHs.75a48ded87d5.js +1 -0
- codex/static_root/assets/VWindowItem-CibnlNHs.75a48ded87d5.js.br +0 -0
- codex/static_root/assets/VWindowItem-CibnlNHs.75a48ded87d5.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CibnlNHs.js +1 -0
- codex/static_root/assets/VWindowItem-CibnlNHs.js.br +0 -0
- codex/static_root/assets/VWindowItem-CibnlNHs.js.gz +0 -0
- codex/static_root/assets/admin-CaVmJ-fa.251f5d3cc755.js +1 -0
- codex/static_root/assets/admin-CaVmJ-fa.251f5d3cc755.js.br +0 -0
- codex/static_root/assets/admin-CaVmJ-fa.251f5d3cc755.js.gz +0 -0
- codex/static_root/assets/admin-CaVmJ-fa.js +1 -0
- codex/static_root/assets/admin-CaVmJ-fa.js.br +0 -0
- codex/static_root/assets/admin-CaVmJ-fa.js.gz +0 -0
- codex/static_root/assets/{admin-CWEjaFr5.7d4523387384.css → admin-DJ7pIXDQ.css} +1 -1
- codex/static_root/assets/admin-DJ7pIXDQ.css.br +0 -0
- codex/static_root/assets/admin-DJ7pIXDQ.css.gz +0 -0
- codex/static_root/assets/{admin-CWEjaFr5.css → admin-DJ7pIXDQ.e2a77af73ef2.css} +1 -1
- codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.br +0 -0
- codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.gz +0 -0
- codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css +1 -0
- 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 +1 -0
- 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-Cb7A0Ilo.ddf1e9339257.js +1 -0
- codex/static_root/assets/admin-menu-Cb7A0Ilo.ddf1e9339257.js.br +0 -0
- codex/static_root/assets/admin-menu-Cb7A0Ilo.ddf1e9339257.js.gz +0 -0
- codex/static_root/assets/admin-menu-Cb7A0Ilo.js +1 -0
- codex/static_root/assets/admin-menu-Cb7A0Ilo.js.br +0 -0
- codex/static_root/assets/admin-menu-Cb7A0Ilo.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-DID-drll.979420762aea.js +1 -0
- codex/static_root/assets/admin-settings-button-progress-DID-drll.979420762aea.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-DID-drll.979420762aea.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-DID-drll.js +1 -0
- codex/static_root/assets/admin-settings-button-progress-DID-drll.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-DID-drll.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.2548c49a853e.css +1 -0
- codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.css +1 -0
- codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css +1 -0
- codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css.br +0 -0
- codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css.gz +0 -0
- codex/static_root/assets/browser-Br5CorL4.css +1 -0
- codex/static_root/assets/browser-Br5CorL4.css.br +0 -0
- codex/static_root/assets/browser-Br5CorL4.css.gz +0 -0
- codex/static_root/assets/browser-xxQTUEuu.1686c20dc492.js +1 -0
- codex/static_root/assets/browser-xxQTUEuu.1686c20dc492.js.br +0 -0
- codex/static_root/assets/browser-xxQTUEuu.1686c20dc492.js.gz +0 -0
- codex/static_root/assets/browser-xxQTUEuu.js +1 -0
- codex/static_root/assets/browser-xxQTUEuu.js.br +0 -0
- codex/static_root/assets/browser-xxQTUEuu.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DXY2Xg9k.4a7ca6108810.js +1 -0
- codex/static_root/assets/change-password-dialog-DXY2Xg9k.4a7ca6108810.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DXY2Xg9k.4a7ca6108810.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DXY2Xg9k.js +1 -0
- codex/static_root/assets/change-password-dialog-DXY2Xg9k.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DXY2Xg9k.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css +1 -0
- 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 +1 -0
- 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 +1 -0
- codex/static_root/assets/confirm-dialog-B7w6z2rf.css +1 -0
- codex/static_root/assets/confirm-dialog-BEVEU-kA.281b6e877fb5.js +1 -0
- codex/static_root/assets/confirm-dialog-BEVEU-kA.281b6e877fb5.js.br +0 -0
- codex/static_root/assets/confirm-dialog-BEVEU-kA.281b6e877fb5.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-BEVEU-kA.js +1 -0
- codex/static_root/assets/confirm-dialog-BEVEU-kA.js.br +0 -0
- codex/static_root/assets/confirm-dialog-BEVEU-kA.js.gz +0 -0
- codex/static_root/assets/datetime-column-DhrZEHwa.80e95aef7bdb.js +1 -0
- codex/static_root/assets/datetime-column-DhrZEHwa.80e95aef7bdb.js.br +1 -0
- codex/static_root/assets/datetime-column-DhrZEHwa.80e95aef7bdb.js.gz +0 -0
- codex/static_root/assets/datetime-column-DhrZEHwa.js +1 -0
- codex/static_root/assets/datetime-column-DhrZEHwa.js.br +1 -0
- codex/static_root/assets/datetime-column-DhrZEHwa.js.gz +0 -0
- codex/static_root/assets/filter-BJ7TmFiU.3cefe2d609c7.js +1 -0
- codex/static_root/assets/filter-BJ7TmFiU.3cefe2d609c7.js.br +0 -0
- codex/static_root/assets/filter-BJ7TmFiU.3cefe2d609c7.js.gz +0 -0
- codex/static_root/assets/filter-BJ7TmFiU.js +1 -0
- codex/static_root/assets/filter-BJ7TmFiU.js.br +0 -0
- codex/static_root/assets/filter-BJ7TmFiU.js.gz +0 -0
- codex/static_root/assets/flag-tab-AJj0sesB.2ab1be15d10f.js +1 -0
- codex/static_root/assets/flag-tab-AJj0sesB.2ab1be15d10f.js.br +0 -0
- codex/static_root/assets/flag-tab-AJj0sesB.2ab1be15d10f.js.gz +0 -0
- codex/static_root/assets/flag-tab-AJj0sesB.js +1 -0
- codex/static_root/assets/flag-tab-AJj0sesB.js.br +0 -0
- codex/static_root/assets/flag-tab-AJj0sesB.js.gz +0 -0
- codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css +1 -0
- 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 +1 -0
- codex/static_root/assets/flag-tab-CqWovuBu.css.br +0 -0
- codex/static_root/assets/flag-tab-CqWovuBu.css.gz +0 -0
- codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css +1 -0
- 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 +1 -0
- 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/group-tab-DuxOH4Hn.8ac96cfe7c43.js +1 -0
- codex/static_root/assets/group-tab-DuxOH4Hn.8ac96cfe7c43.js.br +0 -0
- codex/static_root/assets/group-tab-DuxOH4Hn.8ac96cfe7c43.js.gz +0 -0
- codex/static_root/assets/group-tab-DuxOH4Hn.js +1 -0
- codex/static_root/assets/group-tab-DuxOH4Hn.js.br +0 -0
- codex/static_root/assets/group-tab-DuxOH4Hn.js.gz +0 -0
- codex/static_root/assets/http-error-DIeFpbQV.086e1dd09555.js +1 -0
- codex/static_root/assets/http-error-DIeFpbQV.086e1dd09555.js.br +0 -0
- codex/static_root/assets/http-error-DIeFpbQV.086e1dd09555.js.gz +0 -0
- codex/static_root/assets/http-error-DIeFpbQV.js +1 -0
- codex/static_root/assets/http-error-DIeFpbQV.js.br +0 -0
- codex/static_root/assets/http-error-DIeFpbQV.js.gz +0 -0
- codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css +1 -0
- 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 +1 -0
- 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-MN9BB_He.201e30aa00ef.js +1 -0
- codex/static_root/assets/index-MN9BB_He.201e30aa00ef.js.br +0 -0
- codex/static_root/assets/index-MN9BB_He.201e30aa00ef.js.gz +0 -0
- codex/static_root/assets/index-MN9BB_He.js +1 -0
- codex/static_root/assets/index-MN9BB_He.js.br +0 -0
- codex/static_root/assets/index-MN9BB_He.js.gz +0 -0
- codex/static_root/assets/{library-tab-Bh7ErAk7.7c44200ee727.css → library-tab-Wew8YOLv.0c1780a6b68e.css} +1 -1
- codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.br +0 -0
- codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.gz +0 -0
- codex/static_root/assets/{library-tab-Bh7ErAk7.css → library-tab-Wew8YOLv.css} +1 -1
- codex/static_root/assets/library-tab-Wew8YOLv.css.br +0 -0
- codex/static_root/assets/library-tab-Wew8YOLv.css.gz +0 -0
- codex/static_root/assets/library-tab-jpeUUWzV.70dae13f6dab.js +1 -0
- codex/static_root/assets/library-tab-jpeUUWzV.70dae13f6dab.js.br +0 -0
- codex/static_root/assets/library-tab-jpeUUWzV.70dae13f6dab.js.gz +0 -0
- codex/static_root/assets/library-tab-jpeUUWzV.js +1 -0
- codex/static_root/assets/library-tab-jpeUUWzV.js.br +0 -0
- codex/static_root/assets/library-tab-jpeUUWzV.js.gz +0 -0
- codex/static_root/assets/main-Cs7q8tob.86ef2567544d.js +35 -0
- codex/static_root/assets/main-Cs7q8tob.86ef2567544d.js.br +0 -0
- codex/static_root/assets/main-Cs7q8tob.86ef2567544d.js.gz +0 -0
- codex/static_root/assets/main-Cs7q8tob.js +35 -0
- codex/static_root/assets/main-Cs7q8tob.js.br +0 -0
- codex/static_root/assets/main-Cs7q8tob.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-D_ecZhu-.ff93ca6c55e0.js +1 -0
- codex/static_root/assets/pager-full-pdf-D_ecZhu-.ff93ca6c55e0.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-D_ecZhu-.ff93ca6c55e0.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-D_ecZhu-.js +1 -0
- codex/static_root/assets/pager-full-pdf-D_ecZhu-.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-D_ecZhu-.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-yeU7sPiY.ce0751d6009d.js +1 -0
- codex/static_root/assets/pagination-toolbar-yeU7sPiY.ce0751d6009d.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-yeU7sPiY.ce0751d6009d.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-yeU7sPiY.js +1 -0
- codex/static_root/assets/pagination-toolbar-yeU7sPiY.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-yeU7sPiY.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-BcRNpoaW.882f6e967869.js → pdf-doc-Czi9tnhD.4d4b8b7ff5d7.js} +3 -3
- codex/static_root/assets/pdf-doc-Czi9tnhD.4d4b8b7ff5d7.js.br +0 -0
- codex/static_root/assets/pdf-doc-Czi9tnhD.4d4b8b7ff5d7.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-BcRNpoaW.js → pdf-doc-Czi9tnhD.js} +3 -3
- codex/static_root/assets/pdf-doc-Czi9tnhD.js.br +0 -0
- codex/static_root/assets/pdf-doc-Czi9tnhD.js.gz +0 -0
- codex/static_root/assets/reader-DQKMY8MS.d9d3451f2cff.js +2 -0
- codex/static_root/assets/reader-DQKMY8MS.d9d3451f2cff.js.br +0 -0
- codex/static_root/assets/reader-DQKMY8MS.d9d3451f2cff.js.gz +0 -0
- codex/static_root/assets/reader-DQKMY8MS.js +2 -0
- codex/static_root/assets/reader-DQKMY8MS.js.br +0 -0
- codex/static_root/assets/reader-DQKMY8MS.js.gz +0 -0
- codex/static_root/assets/{reader-DveZZr9x.7b21b9f8f628.css → reader-OpKdTZ_B.css} +1 -1
- codex/static_root/assets/reader-OpKdTZ_B.css.br +0 -0
- codex/static_root/assets/reader-OpKdTZ_B.css.gz +0 -0
- codex/static_root/assets/{reader-DveZZr9x.css → reader-OpKdTZ_B.ebd1512b7014.css} +1 -1
- codex/static_root/assets/reader-OpKdTZ_B.ebd1512b7014.css.br +0 -0
- codex/static_root/assets/reader-OpKdTZ_B.ebd1512b7014.css.gz +0 -0
- codex/static_root/assets/relation-chips-CFH0Xf78.62ded2739a22.js +1 -0
- codex/static_root/assets/relation-chips-CFH0Xf78.62ded2739a22.js.br +0 -0
- codex/static_root/assets/relation-chips-CFH0Xf78.62ded2739a22.js.gz +0 -0
- codex/static_root/assets/relation-chips-CFH0Xf78.js +1 -0
- codex/static_root/assets/relation-chips-CFH0Xf78.js.br +0 -0
- codex/static_root/assets/relation-chips-CFH0Xf78.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DbOztp2R.b6f981108782.js +2 -0
- codex/static_root/assets/settings-drawer-DbOztp2R.b6f981108782.js.br +0 -0
- codex/static_root/assets/settings-drawer-DbOztp2R.b6f981108782.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DbOztp2R.js +2 -0
- codex/static_root/assets/settings-drawer-DbOztp2R.js.br +0 -0
- codex/static_root/assets/settings-drawer-DbOztp2R.js.gz +0 -0
- codex/static_root/assets/{stats-tab-DpfGsVX3.1cb66f2649a9.css → stats-tab-BAYTqQNg.5f715428c394.css} +1 -1
- 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-DpfGsVX3.css → stats-tab-BAYTqQNg.css} +1 -1
- 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-DWktIwEj.42666baa0d93.js +1 -0
- codex/static_root/assets/stats-tab-DWktIwEj.42666baa0d93.js.br +0 -0
- codex/static_root/assets/stats-tab-DWktIwEj.42666baa0d93.js.gz +0 -0
- codex/static_root/assets/stats-tab-DWktIwEj.js +1 -0
- codex/static_root/assets/stats-tab-DWktIwEj.js.br +0 -0
- codex/static_root/assets/stats-tab-DWktIwEj.js.gz +0 -0
- codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css +1 -0
- codex/static_root/assets/{task-tab-1XiWn9xP.06cb8e1b794d.css.br → task-tab--cXi48kg.5dfd6890a1c2.css.br} +1 -1
- codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css.gz +0 -0
- codex/static_root/assets/task-tab--cXi48kg.css +1 -0
- codex/static_root/assets/{task-tab-1XiWn9xP.css.br → task-tab--cXi48kg.css.br} +1 -1
- codex/static_root/assets/task-tab--cXi48kg.css.gz +0 -0
- codex/static_root/assets/task-tab-BtTtKJP6.421692e51e82.js +1 -0
- codex/static_root/assets/task-tab-BtTtKJP6.421692e51e82.js.br +0 -0
- codex/static_root/assets/task-tab-BtTtKJP6.421692e51e82.js.gz +0 -0
- codex/static_root/assets/task-tab-BtTtKJP6.js +1 -0
- codex/static_root/assets/task-tab-BtTtKJP6.js.br +0 -0
- codex/static_root/assets/task-tab-BtTtKJP6.js.gz +0 -0
- codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css +1 -0
- codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.br +4 -0
- codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.gz +0 -0
- codex/static_root/assets/transition-5LRFTPo5.css +1 -0
- codex/static_root/assets/transition-5LRFTPo5.css.br +4 -0
- codex/static_root/assets/transition-5LRFTPo5.css.gz +0 -0
- codex/static_root/assets/transition-A__CJ90w.970355913cb9.js +1 -0
- codex/static_root/assets/transition-A__CJ90w.970355913cb9.js.br +0 -0
- codex/static_root/assets/transition-A__CJ90w.970355913cb9.js.gz +0 -0
- codex/static_root/assets/transition-A__CJ90w.js +1 -0
- codex/static_root/assets/transition-A__CJ90w.js.br +0 -0
- codex/static_root/assets/transition-A__CJ90w.js.gz +0 -0
- codex/static_root/assets/unauthorized-FF1nwDKt.b3d6255ddb7f.js +1 -0
- codex/static_root/assets/unauthorized-FF1nwDKt.b3d6255ddb7f.js.br +0 -0
- codex/static_root/assets/unauthorized-FF1nwDKt.b3d6255ddb7f.js.gz +0 -0
- codex/static_root/assets/unauthorized-FF1nwDKt.js +1 -0
- codex/static_root/assets/unauthorized-FF1nwDKt.js.br +0 -0
- codex/static_root/assets/unauthorized-FF1nwDKt.js.gz +0 -0
- codex/static_root/assets/user-tab-RwMqZeSN.d4ed24177855.js +1 -0
- codex/static_root/assets/user-tab-RwMqZeSN.d4ed24177855.js.br +0 -0
- codex/static_root/assets/user-tab-RwMqZeSN.d4ed24177855.js.gz +0 -0
- codex/static_root/assets/user-tab-RwMqZeSN.js +1 -0
- codex/static_root/assets/user-tab-RwMqZeSN.js.br +0 -0
- codex/static_root/assets/user-tab-RwMqZeSN.js.gz +0 -0
- codex/static_root/manifest.8dff5f2fb15e.json +712 -0
- codex/static_root/manifest.8dff5f2fb15e.json.br +0 -0
- codex/static_root/manifest.8dff5f2fb15e.json.gz +0 -0
- codex/static_root/manifest.json +377 -300
- 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 +5 -6
- codex/threads.py +1 -1
- codex/urls/api/auth.py +1 -1
- codex/urls/api/browser.py +1 -1
- codex/views/admin/library.py +18 -13
- codex/views/admin/stats.py +23 -16
- codex/views/auth.py +42 -77
- codex/views/bookmark.py +16 -153
- codex/views/browser/annotate/__init__.py +1 -0
- codex/views/browser/annotate/bookmark.py +112 -0
- codex/views/browser/annotate/card.py +61 -0
- codex/views/browser/annotate/order.py +247 -0
- codex/views/browser/breadcrumbs.py +90 -11
- codex/views/browser/browser.py +44 -110
- codex/views/browser/choices.py +15 -18
- codex/views/browser/cover.py +10 -20
- codex/views/browser/filters/bookmark.py +18 -19
- codex/views/browser/filters/field.py +8 -3
- codex/views/browser/filters/filter.py +69 -0
- codex/views/browser/filters/group.py +9 -6
- codex/views/browser/filters/search/fts.py +5 -19
- codex/views/browser/filters/search/parse.py +54 -24
- codex/views/browser/group_mtime.py +83 -0
- codex/views/browser/metadata/__init__.py +1 -0
- codex/views/browser/metadata/annotate.py +109 -0
- codex/views/browser/metadata/copy_intersections.py +90 -0
- codex/views/browser/metadata/metadata.py +83 -0
- codex/views/browser/metadata/query_intersections.py +114 -0
- codex/views/browser/mtime.py +2 -10
- codex/views/browser/order_by.py +22 -22
- codex/views/browser/page_in_bounds.py +2 -2
- codex/views/browser/paginate.py +9 -15
- codex/views/browser/params.py +64 -0
- codex/views/browser/title.py +1 -6
- codex/views/browser/validate.py +68 -33
- codex/views/download.py +1 -1
- codex/views/mixins.py +27 -15
- codex/views/opds/const.py +2 -3
- codex/views/opds/urls.py +2 -2
- codex/views/opds/util.py +2 -3
- codex/views/opds/v1/entry/links.py +3 -1
- codex/views/opds/v1/facets.py +65 -12
- codex/views/opds/v1/feed.py +5 -64
- codex/views/opds/v1/links.py +5 -4
- codex/views/opds/v2/feed.py +1 -28
- codex/views/opds/v2/links.py +26 -1
- codex/views/opds/v2/publications.py +5 -6
- codex/views/opds/v2/top_links.py +3 -6
- codex/views/public.py +2 -2
- codex/views/reader/arcs.py +0 -3
- codex/views/reader/books.py +57 -41
- codex/views/reader/page.py +10 -4
- codex/views/reader/{init.py → params.py} +37 -31
- codex/views/reader/reader.py +1 -2
- codex/views/session.py +43 -54
- codex/views/timezone.py +54 -0
- codex/views/version.py +1 -1
- {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/METADATA +1 -1
- {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/RECORD +417 -383
- codex/serializers/choices.py +0 -196
- codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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-CWEjaFr5.7d4523387384.css.br +0 -0
- codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.gz +0 -0
- 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 +0 -1
- 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 +0 -1
- 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 +0 -30
- 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 +0 -30
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- codex/static_root/assets/confirm-dialog-BmhedLCx.css +0 -1
- codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.br +0 -4
- codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.gz +0 -0
- codex/static_root/assets/http-error-C6yuLApo.js +0 -1
- codex/static_root/assets/http-error-C6yuLApo.js.br +0 -4
- codex/static_root/assets/http-error-C6yuLApo.js.gz +0 -0
- codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.br +0 -2
- codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.gz +0 -0
- codex/static_root/assets/library-tab-Bh7ErAk7.css.br +0 -2
- codex/static_root/assets/library-tab-Bh7ErAk7.css.gz +0 -0
- codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js +0 -1
- 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 +0 -1
- 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 +0 -6
- 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 +0 -6
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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-BcRNpoaW.882f6e967869.js.br +0 -0
- codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.gz +0 -0
- 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 +0 -2
- 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 +0 -2
- 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-DveZZr9x.7b21b9f8f628.css.br +0 -0
- codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.gz +0 -0
- 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 +0 -1
- 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 +0 -1
- 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 +0 -2
- 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 +0 -2
- 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 +0 -1
- 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 +0 -1
- 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-DpfGsVX3.1cb66f2649a9.css.br +0 -0
- codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.gz +0 -0
- 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 +0 -1
- codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css.gz +0 -0
- codex/static_root/assets/task-tab-1XiWn9xP.css +0 -1
- codex/static_root/assets/task-tab-1XiWn9xP.css.gz +0 -0
- codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- codex/static_root/js/choices.json.br +0 -0
- codex/static_root/js/choices.json.gz +0 -0
- codex/static_root/manifest.45cb46e19686.json +0 -635
- codex/static_root/manifest.45cb46e19686.json.br +0 -0
- codex/static_root/manifest.45cb46e19686.json.gz +0 -0
- codex/views/browser/annotations.py +0 -339
- codex/views/browser/base.py +0 -139
- codex/views/browser/filters/annotations.py +0 -125
- codex/views/browser/metadata.py +0 -332
- {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/LICENSE +0 -0
- {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/WHEEL +0 -0
- {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/entry_points.txt +0 -0
codex/views/browser/browser.py
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from math import ceil, floor, log10
|
|
4
4
|
from types import MappingProxyType
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
5
|
|
|
7
|
-
from django.db.models import Max
|
|
8
|
-
from django.db.models.expressions import OuterRef
|
|
6
|
+
from django.db.models import Max
|
|
9
7
|
from django.db.utils import OperationalError
|
|
10
8
|
from drf_spectacular.utils import extend_schema
|
|
11
9
|
from rest_framework.response import Response
|
|
@@ -13,12 +11,9 @@ from rest_framework.response import Response
|
|
|
13
11
|
from codex.logger.logging import get_logger
|
|
14
12
|
from codex.models import (
|
|
15
13
|
AdminFlag,
|
|
16
|
-
BrowserGroupModel,
|
|
17
14
|
Comic,
|
|
18
15
|
Folder,
|
|
19
|
-
Imprint,
|
|
20
16
|
Library,
|
|
21
|
-
Volume,
|
|
22
17
|
)
|
|
23
18
|
from codex.serializers.browser.page import BrowserPageSerializer
|
|
24
19
|
from codex.views.browser.title import BrowserTitleView
|
|
@@ -26,24 +21,10 @@ from codex.views.const import (
|
|
|
26
21
|
COMIC_GROUP,
|
|
27
22
|
FOLDER_GROUP,
|
|
28
23
|
MAX_OBJ_PER_PAGE,
|
|
29
|
-
NONE_DATETIMEFIELD,
|
|
30
24
|
STORY_ARC_GROUP,
|
|
31
25
|
)
|
|
32
26
|
|
|
33
|
-
if TYPE_CHECKING:
|
|
34
|
-
from django.db.models.query import QuerySet
|
|
35
|
-
|
|
36
|
-
|
|
37
27
|
LOG = get_logger(__name__)
|
|
38
|
-
_GROUP_INSTANCE_SELECT_RELATED: MappingProxyType[
|
|
39
|
-
type[BrowserGroupModel], tuple[str | None, ...]
|
|
40
|
-
] = MappingProxyType(
|
|
41
|
-
{
|
|
42
|
-
Comic: ("series", "volume"),
|
|
43
|
-
Volume: ("series",),
|
|
44
|
-
Imprint: ("publisher",),
|
|
45
|
-
}
|
|
46
|
-
)
|
|
47
28
|
|
|
48
29
|
|
|
49
30
|
class BrowserView(BrowserTitleView):
|
|
@@ -59,61 +40,31 @@ class BrowserView(BrowserTitleView):
|
|
|
59
40
|
)
|
|
60
41
|
TARGET = "browser"
|
|
61
42
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
self.is_opds_2_acquisition = False
|
|
66
|
-
self.group_query: QuerySet = Comic.objects.none()
|
|
67
|
-
self.valid_nav_groups: tuple[str, ...] = ()
|
|
43
|
+
########
|
|
44
|
+
# Init #
|
|
45
|
+
########
|
|
68
46
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
pks = self.kwargs.get("pks")
|
|
72
|
-
if pks and self.group_class:
|
|
73
|
-
try:
|
|
74
|
-
select_related: tuple[str | None, ...] = (
|
|
75
|
-
_GROUP_INSTANCE_SELECT_RELATED.get(self.group_class, (None,))
|
|
76
|
-
)
|
|
77
|
-
self.group_query = self.group_class.objects.select_related(
|
|
78
|
-
*select_related
|
|
79
|
-
).filter(pk__in=pks)
|
|
80
|
-
except self.group_class.DoesNotExist:
|
|
81
|
-
group = self.kwargs.get("group")
|
|
82
|
-
page = self.kwargs.get("page")
|
|
83
|
-
if group == "r" and not pks and page == 1:
|
|
84
|
-
self.group_query = self.group_class.objects.none()
|
|
85
|
-
else:
|
|
86
|
-
reason = f"{group}__in={pks} does not exist!"
|
|
87
|
-
settings_mask = {"breadcrumbs": []}
|
|
88
|
-
self.raise_redirect(
|
|
89
|
-
reason, route_mask={"group": group}, settings_mask=settings_mask
|
|
90
|
-
)
|
|
91
|
-
elif self.group_class:
|
|
92
|
-
self.group_query = self.group_class.objects.none()
|
|
93
|
-
else:
|
|
94
|
-
self.group_query = Comic.objects.none()
|
|
95
|
-
self.group_instance = self.group_query.first()
|
|
96
|
-
|
|
97
|
-
def init_request(self):
|
|
98
|
-
"""Initialize request."""
|
|
99
|
-
super().init_request()
|
|
100
|
-
self._set_group_query_and_instance()
|
|
101
|
-
|
|
102
|
-
def get_model_group(self):
|
|
47
|
+
@property
|
|
48
|
+
def model_group(self):
|
|
103
49
|
"""Get the group of the models to browse."""
|
|
104
50
|
# the model group shown must be:
|
|
105
51
|
# A valid nav group or 'c'
|
|
106
52
|
# the child of the current nav group or 'c'
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
53
|
+
if not self._model_group:
|
|
54
|
+
group = self.kwargs["group"]
|
|
55
|
+
if group == FOLDER_GROUP:
|
|
56
|
+
self._model_group = group
|
|
57
|
+
elif group == STORY_ARC_GROUP:
|
|
58
|
+
pks = self.kwargs.get("pks")
|
|
59
|
+
self._model_group = COMIC_GROUP if pks else group
|
|
60
|
+
elif group == self.valid_nav_groups[-1]:
|
|
61
|
+
# special case for lowest valid group
|
|
62
|
+
self._model_group = COMIC_GROUP
|
|
63
|
+
else:
|
|
64
|
+
self._model_group = self.valid_nav_groups[
|
|
65
|
+
self.valid_nav_groups.index(group) + 1
|
|
66
|
+
]
|
|
67
|
+
return self._model_group
|
|
117
68
|
|
|
118
69
|
################
|
|
119
70
|
# MAIN QUERIES #
|
|
@@ -134,8 +85,8 @@ class BrowserView(BrowserTitleView):
|
|
|
134
85
|
"""Create queryset common to group & books."""
|
|
135
86
|
qs = self.get_filtered_queryset(model)
|
|
136
87
|
limit = self._get_limit()
|
|
137
|
-
count_qs = self.add_group_by(qs, model)
|
|
138
88
|
try:
|
|
89
|
+
count_qs = self.add_group_by(qs)
|
|
139
90
|
if limit:
|
|
140
91
|
count_qs = count_qs[:limit]
|
|
141
92
|
# Get count after filters and before any annotations or orders
|
|
@@ -148,20 +99,19 @@ class BrowserView(BrowserTitleView):
|
|
|
148
99
|
qs = model.objects.none()
|
|
149
100
|
|
|
150
101
|
if count:
|
|
151
|
-
qs = self.annotate_order_aggregates(qs
|
|
152
|
-
qs = self.add_order_by(qs
|
|
102
|
+
qs = self.annotate_order_aggregates(qs)
|
|
103
|
+
qs = self.add_order_by(qs)
|
|
153
104
|
if limit:
|
|
154
105
|
qs = qs[:limit]
|
|
106
|
+
else:
|
|
107
|
+
qs = qs.order_by("pk")
|
|
155
108
|
|
|
156
109
|
return qs, count
|
|
157
110
|
|
|
158
111
|
def _get_group_queryset(self):
|
|
159
112
|
"""Create group queryset."""
|
|
160
|
-
if
|
|
161
|
-
|
|
162
|
-
raise ValueError(reason)
|
|
163
|
-
if self.is_model_comic:
|
|
164
|
-
qs = self.model.objects.none()
|
|
113
|
+
if self.model is Comic:
|
|
114
|
+
qs = self.model.objects.none().order_by("pk")
|
|
165
115
|
count = 0
|
|
166
116
|
else:
|
|
167
117
|
qs, count = self._get_common_queryset(self.model)
|
|
@@ -173,28 +123,10 @@ class BrowserView(BrowserTitleView):
|
|
|
173
123
|
if self.model in (Comic, Folder):
|
|
174
124
|
qs, count = self._get_common_queryset(Comic)
|
|
175
125
|
else:
|
|
176
|
-
qs = Comic.objects.none()
|
|
126
|
+
qs = Comic.objects.none().order_by("pk")
|
|
177
127
|
count = 0
|
|
178
128
|
return qs, count
|
|
179
129
|
|
|
180
|
-
def _requery_max_bookmark_updated_at(self, group_qs):
|
|
181
|
-
"""Get max updated at without bookmark filter and aware of multi-groups."""
|
|
182
|
-
if not self.is_bookmark_filtered:
|
|
183
|
-
return group_qs
|
|
184
|
-
if not self.model:
|
|
185
|
-
reason = "No model to compute max bookmark updated_at"
|
|
186
|
-
raise ValueError(reason)
|
|
187
|
-
|
|
188
|
-
qs = self.model.objects.filter(pk=OuterRef("pk"))
|
|
189
|
-
|
|
190
|
-
bm_rel, bm_filter = self.get_bookmark_rel_and_filter(self.model)
|
|
191
|
-
bm_updated_at_rel = f"{bm_rel}__updated_at"
|
|
192
|
-
max_bmua = Max(bm_updated_at_rel, default=NONE_DATETIMEFIELD, filter=bm_filter)
|
|
193
|
-
|
|
194
|
-
mbua = qs.aggregate(max=max_bmua)["max"]
|
|
195
|
-
|
|
196
|
-
return group_qs.annotate(max_bookmark_updated_at=Subquery(mbua))
|
|
197
|
-
|
|
198
130
|
@staticmethod
|
|
199
131
|
def _get_zero_pad(book_qs):
|
|
200
132
|
"""Get the zero padding for the display."""
|
|
@@ -207,12 +139,16 @@ class BrowserView(BrowserTitleView):
|
|
|
207
139
|
return zero_pad
|
|
208
140
|
|
|
209
141
|
def _get_page_mtime(self):
|
|
210
|
-
|
|
211
|
-
# Nice optimization if we can get get it.
|
|
212
|
-
return self.group_instance.updated_at
|
|
142
|
+
return self.get_group_mtime(self.model, page_mtime=True)
|
|
213
143
|
|
|
214
|
-
|
|
215
|
-
|
|
144
|
+
def _debug_queries(self, group_count, book_count, group_qs, book_qs):
|
|
145
|
+
"""Log query details."""
|
|
146
|
+
if group_count:
|
|
147
|
+
LOG.debug(group_qs.explain())
|
|
148
|
+
LOG.debug(group_qs.query)
|
|
149
|
+
if book_count:
|
|
150
|
+
LOG.debug(book_qs.explain())
|
|
151
|
+
LOG.debug(book_qs.query)
|
|
216
152
|
|
|
217
153
|
def _get_group_and_books(self):
|
|
218
154
|
"""Create the main queries with filters, annotation and pagination."""
|
|
@@ -228,22 +164,22 @@ class BrowserView(BrowserTitleView):
|
|
|
228
164
|
|
|
229
165
|
# Annotate
|
|
230
166
|
if page_group_count:
|
|
231
|
-
group_qs = self.annotate_card_aggregates(group_qs
|
|
232
|
-
group_qs = self.
|
|
167
|
+
group_qs = self.annotate_card_aggregates(group_qs)
|
|
168
|
+
group_qs = self.force_inner_joins(group_qs)
|
|
233
169
|
if page_book_count:
|
|
234
170
|
zero_pad = self._get_zero_pad(book_qs)
|
|
235
|
-
book_qs = self.annotate_card_aggregates(book_qs
|
|
171
|
+
book_qs = self.annotate_card_aggregates(book_qs)
|
|
172
|
+
book_qs = self.force_inner_joins(book_qs)
|
|
236
173
|
else:
|
|
237
174
|
zero_pad = 1
|
|
238
175
|
|
|
239
|
-
#
|
|
240
|
-
# print(book_qs.query)
|
|
176
|
+
# self._debug_queries(page_group_count, page_book_count, group_qs, book_qs)
|
|
241
177
|
|
|
242
178
|
total_page_count = page_group_count + page_book_count
|
|
243
179
|
mtime = self._get_page_mtime()
|
|
244
180
|
return group_qs, book_qs, num_pages, total_page_count, zero_pad, mtime
|
|
245
181
|
|
|
246
|
-
def get_object(self):
|
|
182
|
+
def get_object(self): # type: ignore
|
|
247
183
|
"""Validate settings and get the querysets."""
|
|
248
184
|
group_qs, book_qs, num_pages, total_count, zero_pad, mtime = (
|
|
249
185
|
self._get_group_and_books()
|
|
@@ -255,7 +191,6 @@ class BrowserView(BrowserTitleView):
|
|
|
255
191
|
# needs to happen after pagination
|
|
256
192
|
# runs obj list query twice :/
|
|
257
193
|
libraries_exist = Library.objects.filter(covers_only=False).exists()
|
|
258
|
-
|
|
259
194
|
# construct final data structure
|
|
260
195
|
return MappingProxyType(
|
|
261
196
|
{
|
|
@@ -278,7 +213,6 @@ class BrowserView(BrowserTitleView):
|
|
|
278
213
|
@extend_schema(parameters=[BrowserTitleView.input_serializer_class])
|
|
279
214
|
def get(self, *_args, **_kwargs):
|
|
280
215
|
"""Get browser settings."""
|
|
281
|
-
self.init_request()
|
|
282
216
|
data = self.get_object()
|
|
283
217
|
serializer = self.get_serializer(data)
|
|
284
218
|
return Response(serializer.data)
|
codex/views/browser/choices.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"""View for marking comics read and unread."""
|
|
2
2
|
|
|
3
3
|
from types import MappingProxyType
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
from caseconverter import snakecase
|
|
6
7
|
from django.db.models import QuerySet
|
|
7
8
|
from drf_spectacular.utils import extend_schema
|
|
8
9
|
from rest_framework.response import Response
|
|
9
10
|
|
|
11
|
+
from codex.choices import DUMMY_NULL_NAME, VUETIFY_NULL_CODE
|
|
10
12
|
from codex.logger.logging import get_logger
|
|
11
13
|
from codex.models import (
|
|
12
14
|
Comic,
|
|
@@ -21,24 +23,26 @@ from codex.serializers.browser.filters import (
|
|
|
21
23
|
BrowserFilterChoicesSerializer,
|
|
22
24
|
)
|
|
23
25
|
from codex.serializers.browser.settings import BrowserFilterChoicesInputSerilalizer
|
|
24
|
-
from codex.
|
|
25
|
-
from codex.views.
|
|
26
|
-
|
|
26
|
+
from codex.views.browser.filters.filter import BrowserFilterView
|
|
27
|
+
from codex.views.session import (
|
|
28
|
+
CONTRIBUTOR_PERSON_UI_FIELD,
|
|
29
|
+
IDENTIFIER_TYPE_UI_FIELD,
|
|
30
|
+
STORY_ARC_UI_FIELD,
|
|
27
31
|
)
|
|
28
32
|
|
|
29
33
|
LOG = get_logger(__name__)
|
|
30
34
|
|
|
31
35
|
_FIELD_TO_REL_MODEL_MAP = MappingProxyType(
|
|
32
36
|
{
|
|
33
|
-
|
|
37
|
+
CONTRIBUTOR_PERSON_UI_FIELD: (
|
|
34
38
|
"contributors__person",
|
|
35
39
|
ContributorPerson,
|
|
36
40
|
),
|
|
37
|
-
|
|
41
|
+
STORY_ARC_UI_FIELD: (
|
|
38
42
|
"story_arc_numbers__story_arc",
|
|
39
43
|
StoryArc,
|
|
40
44
|
),
|
|
41
|
-
|
|
45
|
+
IDENTIFIER_TYPE_UI_FIELD: (
|
|
42
46
|
"identifiers__identifier_type",
|
|
43
47
|
IdentifierType,
|
|
44
48
|
),
|
|
@@ -54,18 +58,12 @@ _BACK_REL_MAP = MappingProxyType(
|
|
|
54
58
|
_NULL_NAMED_ROW = MappingProxyType({"pk": VUETIFY_NULL_CODE, "name": DUMMY_NULL_NAME})
|
|
55
59
|
|
|
56
60
|
|
|
57
|
-
class BrowserChoicesViewBase(
|
|
61
|
+
class BrowserChoicesViewBase(BrowserFilterView):
|
|
58
62
|
"""Get choices for filter dialog."""
|
|
59
63
|
|
|
60
64
|
input_serializer_class = BrowserFilterChoicesInputSerilalizer
|
|
61
65
|
TARGET = "choices"
|
|
62
66
|
|
|
63
|
-
def init_request(self):
|
|
64
|
-
"""Initialieze request."""
|
|
65
|
-
self.parse_params()
|
|
66
|
-
self.set_model()
|
|
67
|
-
self.set_rel_prefix()
|
|
68
|
-
|
|
69
67
|
@staticmethod
|
|
70
68
|
def get_field_choices_query(comic_qs, field_name):
|
|
71
69
|
"""Get distinct values for the field."""
|
|
@@ -100,14 +98,13 @@ class BrowserChoicesViewBase(BrowserAnnotationsFilterView):
|
|
|
100
98
|
|
|
101
99
|
return rel, model
|
|
102
100
|
|
|
103
|
-
def get_object(self):
|
|
101
|
+
def get_object(self) -> QuerySet: # type: ignore
|
|
104
102
|
"""Get the comic subquery use for the choices."""
|
|
105
103
|
return self.get_filtered_queryset(Comic)
|
|
106
104
|
|
|
107
105
|
@extend_schema(parameters=[input_serializer_class])
|
|
108
106
|
def get(self, *_args, **_kwargs):
|
|
109
107
|
"""Return choices."""
|
|
110
|
-
self.init_request()
|
|
111
108
|
obj = self.get_object()
|
|
112
109
|
serializer = self.get_serializer(obj)
|
|
113
110
|
return Response(serializer.data)
|
|
@@ -139,13 +136,13 @@ class BrowserChoicesAvailableView(BrowserChoicesViewBase):
|
|
|
139
136
|
|
|
140
137
|
return count
|
|
141
138
|
|
|
142
|
-
def get_object(self):
|
|
139
|
+
def get_object(self) -> dict[str, Any]: # type: ignore
|
|
143
140
|
"""Get choice counts."""
|
|
144
141
|
qs = super().get_object()
|
|
145
142
|
filters = self.params.get("filters", {})
|
|
146
143
|
data = {}
|
|
147
144
|
for field_name in self.serializer_class().get_fields(): # type: ignore
|
|
148
|
-
if field_name == "story_arcs" and
|
|
145
|
+
if field_name == "story_arcs" and qs.model is StoryArc:
|
|
149
146
|
# don't allow filtering on story arc in story arc view.
|
|
150
147
|
continue
|
|
151
148
|
rel, m2m_model = self.get_rel_and_model(field_name)
|
|
@@ -188,7 +185,7 @@ class BrowserChoicesView(BrowserChoicesViewBase):
|
|
|
188
185
|
field_name = self.kwargs.get("field_name", "")
|
|
189
186
|
return snakecase(field_name)
|
|
190
187
|
|
|
191
|
-
def get_object(self):
|
|
188
|
+
def get_object(self) -> dict[str, Any]: # type: ignore
|
|
192
189
|
"""Return choices with more than one choice."""
|
|
193
190
|
qs = super().get_object()
|
|
194
191
|
field_name = self._get_field_name()
|
codex/views/browser/cover.py
CHANGED
|
@@ -7,7 +7,7 @@ from drf_spectacular.types import OpenApiTypes
|
|
|
7
7
|
from drf_spectacular.utils import extend_schema
|
|
8
8
|
from rest_framework.renderers import BaseRenderer
|
|
9
9
|
|
|
10
|
-
from codex.librarian.covers.create import
|
|
10
|
+
from codex.librarian.covers.create import CoverCreateThread
|
|
11
11
|
from codex.librarian.covers.path import CoverPathMixin
|
|
12
12
|
from codex.librarian.mp_queue import LIBRARIAN_QUEUE
|
|
13
13
|
from codex.logger.logging import get_logger
|
|
@@ -15,7 +15,7 @@ from codex.models import Comic, Volume
|
|
|
15
15
|
from codex.models.groups import Folder
|
|
16
16
|
from codex.models.paths import CustomCover
|
|
17
17
|
from codex.serializers.browser.settings import BrowserCoverInputSerializer
|
|
18
|
-
from codex.views.browser.
|
|
18
|
+
from codex.views.browser.annotate.order import BrowserAnnotateOrderView
|
|
19
19
|
from codex.views.const import (
|
|
20
20
|
CUSTOM_COVER_GROUP_RELATION,
|
|
21
21
|
GROUP_RELATION,
|
|
@@ -41,7 +41,7 @@ class WEBPRenderer(BaseRenderer):
|
|
|
41
41
|
return data
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
class CoverView(
|
|
44
|
+
class CoverView(BrowserAnnotateOrderView):
|
|
45
45
|
"""ComicCover View."""
|
|
46
46
|
|
|
47
47
|
input_serializer_class = BrowserCoverInputSerializer
|
|
@@ -49,7 +49,7 @@ class CoverView(BrowserAnnotationsView):
|
|
|
49
49
|
content_type = "image/webp"
|
|
50
50
|
TARGET = "cover"
|
|
51
51
|
REPARSE_JSON_FIELDS = frozenset(
|
|
52
|
-
|
|
52
|
+
BrowserAnnotateOrderView.REPARSE_JSON_FIELDS | {"parent"}
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
def get_group_filter(self, group=None, pks=None, page_mtime=False):
|
|
@@ -71,22 +71,13 @@ class CoverView(BrowserAnnotationsView):
|
|
|
71
71
|
group_filter[f"{parent_rel}__pk__in"] = parent_pks
|
|
72
72
|
return Q(**group_filter)
|
|
73
73
|
|
|
74
|
-
def get_model_group(self):
|
|
75
|
-
"""Return the url group."""
|
|
76
|
-
return self.kwargs["group"]
|
|
77
|
-
|
|
78
|
-
def init_request(self):
|
|
79
|
-
"""Initialize request."""
|
|
80
|
-
self.parse_params()
|
|
81
|
-
self.set_model()
|
|
82
|
-
|
|
83
74
|
def _get_comic_cover(self):
|
|
84
75
|
pks = self.kwargs["pks"]
|
|
85
76
|
return pks[0], False
|
|
86
77
|
|
|
87
78
|
def _get_custom_cover(self):
|
|
88
79
|
"""Get Custom Cover."""
|
|
89
|
-
if self.model
|
|
80
|
+
if self.model is Volume or not self.params.get("custom_covers"):
|
|
90
81
|
return None
|
|
91
82
|
group = self.kwargs["group"]
|
|
92
83
|
group_rel = CUSTOM_COVER_GROUP_RELATION[group]
|
|
@@ -99,8 +90,8 @@ class CoverView(BrowserAnnotationsView):
|
|
|
99
90
|
def _get_dynamic_cover(self):
|
|
100
91
|
"""Get dynamic cover."""
|
|
101
92
|
comic_qs = self.get_filtered_queryset(Comic)
|
|
102
|
-
comic_qs = self.annotate_order_aggregates(comic_qs
|
|
103
|
-
comic_qs = self.add_order_by(comic_qs
|
|
93
|
+
comic_qs = self.annotate_order_aggregates(comic_qs)
|
|
94
|
+
comic_qs = self.add_order_by(comic_qs)
|
|
104
95
|
comic_qs = comic_qs.only("pk")
|
|
105
96
|
comic = comic_qs.first()
|
|
106
97
|
cover_pk = comic.pk if comic else 0
|
|
@@ -108,7 +99,7 @@ class CoverView(BrowserAnnotationsView):
|
|
|
108
99
|
|
|
109
100
|
def _get_cover_pk(self) -> tuple[int, bool]:
|
|
110
101
|
"""Get Cover Pk queryset for comic queryset."""
|
|
111
|
-
if self.model
|
|
102
|
+
if self.model is Comic:
|
|
112
103
|
cover_pk, custom = self._get_comic_cover()
|
|
113
104
|
elif custom_cover := self._get_custom_cover():
|
|
114
105
|
cover_pk = custom_cover.pk
|
|
@@ -136,7 +127,7 @@ class CoverView(BrowserAnnotationsView):
|
|
|
136
127
|
|
|
137
128
|
cover_path = CoverPathMixin.get_cover_path(pk, custom)
|
|
138
129
|
if not cover_path.exists():
|
|
139
|
-
thumb_buffer =
|
|
130
|
+
thumb_buffer = CoverCreateThread.create_cover_from_path(
|
|
140
131
|
pk, cover_path, LOG, LIBRARIAN_QUEUE, custom
|
|
141
132
|
)
|
|
142
133
|
if not thumb_buffer:
|
|
@@ -148,13 +139,12 @@ class CoverView(BrowserAnnotationsView):
|
|
|
148
139
|
return cover_file, content_type
|
|
149
140
|
|
|
150
141
|
@extend_schema(
|
|
151
|
-
parameters=[
|
|
142
|
+
parameters=[BrowserAnnotateOrderView.input_serializer_class],
|
|
152
143
|
responses={(200, content_type): OpenApiTypes.BINARY},
|
|
153
144
|
)
|
|
154
145
|
def get(self, *args, **kwargs): # type: ignore
|
|
155
146
|
"""Get comic cover."""
|
|
156
147
|
try:
|
|
157
|
-
self.init_request()
|
|
158
148
|
try:
|
|
159
149
|
pk, custom = self._get_cover_pk()
|
|
160
150
|
except OperationalError as exc:
|
|
@@ -4,46 +4,45 @@ from typing import TYPE_CHECKING
|
|
|
4
4
|
|
|
5
5
|
from django.db.models import Q
|
|
6
6
|
|
|
7
|
+
from codex.views.browser.validate import BrowserValidateView
|
|
8
|
+
|
|
7
9
|
if TYPE_CHECKING:
|
|
8
10
|
from codex.models import BrowserGroupModel
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
class
|
|
13
|
+
class BrowserFilterBookmarkView(BrowserValidateView):
|
|
12
14
|
"""BookmarkFilter view methods."""
|
|
13
15
|
|
|
14
|
-
def
|
|
16
|
+
def __init__(self, *args, **kwargs):
|
|
15
17
|
"""Initialize the bm_annotation_data."""
|
|
16
|
-
|
|
18
|
+
super().__init__(*args, **kwargs)
|
|
19
|
+
self._bm_rels: dict[BrowserGroupModel, str] = {}
|
|
20
|
+
self._bm_filters: dict[BrowserGroupModel, Q] = {}
|
|
17
21
|
|
|
18
22
|
def _get_bm_rel(self, model):
|
|
19
23
|
"""Create bookmark relation."""
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
if model not in self._bm_rels:
|
|
25
|
+
rel_prefix = self.get_rel_prefix(model) # type: ignore
|
|
26
|
+
self._bm_rels[model] = rel_prefix + "bookmark"
|
|
27
|
+
return self._bm_rels[model]
|
|
22
28
|
|
|
23
29
|
def _get_my_bookmark_filter(self, bm_rel):
|
|
24
30
|
"""Get a filter for my session or user defined bookmarks."""
|
|
25
|
-
if self.request.user.is_authenticated:
|
|
26
|
-
|
|
31
|
+
if self.request.user and self.request.user.is_authenticated:
|
|
32
|
+
key = f"{bm_rel}__user"
|
|
33
|
+
value = self.request.user
|
|
27
34
|
else:
|
|
28
35
|
key = f"{bm_rel}__session__session_key"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
36
|
+
value = self.request.session.session_key
|
|
37
|
+
my_bookmarks_kwargs = {key: value}
|
|
32
38
|
return Q(**my_bookmarks_kwargs)
|
|
33
39
|
|
|
34
|
-
def get_bookmark_rel_and_filter(self, model):
|
|
35
|
-
"""Get the bookmark rel and filter once."""
|
|
36
|
-
if model not in self._bm_annotation_data:
|
|
37
|
-
bm_rel = self._get_bm_rel(model)
|
|
38
|
-
bm_filter = self._get_my_bookmark_filter(bm_rel)
|
|
39
|
-
self._bm_annotation_data[model] = (bm_rel, bm_filter)
|
|
40
|
-
return self._bm_annotation_data[model]
|
|
41
|
-
|
|
42
40
|
def get_bookmark_filter(self, model):
|
|
43
41
|
"""Build bookmark query."""
|
|
44
42
|
choice: str = self.params.get("filters", {}).get("bookmark", "") # type: ignore
|
|
45
43
|
if choice:
|
|
46
|
-
bm_rel
|
|
44
|
+
bm_rel = self._get_bm_rel(model)
|
|
45
|
+
my_bookmark_filter = self._get_my_bookmark_filter(bm_rel)
|
|
47
46
|
if choice == "READ":
|
|
48
47
|
bookmark_filter = my_bookmark_filter & Q(
|
|
49
48
|
**{f"{bm_rel}__finished": True}
|
|
@@ -5,12 +5,17 @@ from types import MappingProxyType
|
|
|
5
5
|
from django.db.models import Q
|
|
6
6
|
|
|
7
7
|
from codex.views.browser.filters.group import GroupFilterView
|
|
8
|
+
from codex.views.session import (
|
|
9
|
+
CONTRIBUTOR_PERSON_UI_FIELD,
|
|
10
|
+
IDENTIFIER_TYPE_UI_FIELD,
|
|
11
|
+
STORY_ARC_UI_FIELD,
|
|
12
|
+
)
|
|
8
13
|
|
|
9
14
|
_FILTER_REL_MAP = MappingProxyType(
|
|
10
15
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
CONTRIBUTOR_PERSON_UI_FIELD: "contributors__person",
|
|
17
|
+
STORY_ARC_UI_FIELD: "story_arc_numbers__story_arc",
|
|
18
|
+
IDENTIFIER_TYPE_UI_FIELD: "identifiers__identifier_type",
|
|
14
19
|
}
|
|
15
20
|
)
|
|
16
21
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Browser Filters."""
|
|
2
|
+
|
|
3
|
+
from django.db.models.query import QuerySet
|
|
4
|
+
from django.db.models.query_utils import Q
|
|
5
|
+
|
|
6
|
+
from codex.logger.logging import get_logger
|
|
7
|
+
from codex.models.comic import Comic
|
|
8
|
+
from codex.views.browser.filters.bookmark import BrowserFilterBookmarkView
|
|
9
|
+
|
|
10
|
+
LOG = get_logger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BrowserFilterView(BrowserFilterBookmarkView):
|
|
14
|
+
"""Browser Filters."""
|
|
15
|
+
|
|
16
|
+
TARGET = ""
|
|
17
|
+
|
|
18
|
+
def force_inner_joins(self, qs):
|
|
19
|
+
"""Force INNER JOINS to filter empty groups."""
|
|
20
|
+
demote_tables = {"codex_library"}
|
|
21
|
+
if qs.model is not Comic:
|
|
22
|
+
demote_tables.add("codex_comic")
|
|
23
|
+
if self.fts_mode:
|
|
24
|
+
# Forcing INNER JOINS required to make fts5 work
|
|
25
|
+
demote_tables.add("codex_comicfts")
|
|
26
|
+
return qs.demote_joins(demote_tables)
|
|
27
|
+
|
|
28
|
+
def _get_query_filters(
|
|
29
|
+
self,
|
|
30
|
+
model,
|
|
31
|
+
group=None,
|
|
32
|
+
pks=None,
|
|
33
|
+
page_mtime=False,
|
|
34
|
+
bookmark_filter=True,
|
|
35
|
+
) -> Q:
|
|
36
|
+
"""Return all the filters except the group filter."""
|
|
37
|
+
big_include_filter = Q()
|
|
38
|
+
big_exclude_filter = Q()
|
|
39
|
+
big_include_filter &= self.get_group_acl_filter(model, self.request.user)
|
|
40
|
+
big_include_filter &= self.get_group_filter(group, pks, page_mtime=page_mtime)
|
|
41
|
+
big_include_filter &= self.get_comic_field_filter(model)
|
|
42
|
+
if bookmark_filter:
|
|
43
|
+
big_include_filter &= self.get_bookmark_filter(model)
|
|
44
|
+
include_search_filter, exclude_search_filter, fts_q = self.get_search_filters(
|
|
45
|
+
model
|
|
46
|
+
)
|
|
47
|
+
big_include_filter &= include_search_filter
|
|
48
|
+
big_exclude_filter &= exclude_search_filter
|
|
49
|
+
|
|
50
|
+
return big_include_filter & ~big_exclude_filter & fts_q
|
|
51
|
+
|
|
52
|
+
def get_filtered_queryset(
|
|
53
|
+
self,
|
|
54
|
+
model,
|
|
55
|
+
group=None,
|
|
56
|
+
pks=None,
|
|
57
|
+
page_mtime=False,
|
|
58
|
+
bookmark_filter=True,
|
|
59
|
+
) -> QuerySet:
|
|
60
|
+
"""Get a filtered queryset for the model."""
|
|
61
|
+
query_filters = self._get_query_filters(
|
|
62
|
+
model,
|
|
63
|
+
group=group,
|
|
64
|
+
pks=pks,
|
|
65
|
+
page_mtime=page_mtime,
|
|
66
|
+
bookmark_filter=bookmark_filter,
|
|
67
|
+
)
|
|
68
|
+
# Distinct necissary for folder view with search
|
|
69
|
+
return model.objects.filter(query_filters).distinct()
|
|
@@ -2,26 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
from django.db.models import Q
|
|
4
4
|
|
|
5
|
+
from codex.views.browser.params import BrowserParamsView
|
|
5
6
|
from codex.views.const import (
|
|
6
7
|
FILTER_ONLY_GROUP_RELATION,
|
|
7
8
|
FOLDER_GROUP,
|
|
8
9
|
GROUP_RELATION,
|
|
9
10
|
)
|
|
10
|
-
from codex.views.session import SessionView
|
|
11
11
|
|
|
12
|
+
_GROUP_REL_TARGETS = frozenset({"cover", "choices"})
|
|
13
|
+
_PK_REL_TARGETS = frozenset({"metadata", "mtime"})
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
|
|
16
|
+
class GroupFilterView(BrowserParamsView):
|
|
14
17
|
"""Group Filters."""
|
|
15
18
|
|
|
16
|
-
SESSION_KEY =
|
|
19
|
+
SESSION_KEY = BrowserParamsView.BROWSER_SESSION_KEY
|
|
17
20
|
|
|
18
21
|
def _get_rel_for_pks(self, group, page_mtime=False):
|
|
19
22
|
"""Get the relation from the model to the pks."""
|
|
20
23
|
# XXX these TARGET refs might be better as subclass get rel methods.
|
|
21
24
|
target: str = self.TARGET # type: ignore
|
|
22
|
-
if target in
|
|
25
|
+
if target in _GROUP_REL_TARGETS:
|
|
23
26
|
rel = FILTER_ONLY_GROUP_RELATION[group]
|
|
24
|
-
elif target in
|
|
27
|
+
elif target in _PK_REL_TARGETS or page_mtime:
|
|
25
28
|
# metadata, mtime, browser.page_mtime
|
|
26
29
|
rel = "pk"
|
|
27
30
|
else:
|
|
@@ -42,8 +45,8 @@ class GroupFilterView(SessionView):
|
|
|
42
45
|
rel = self._get_rel_for_pks(group, page_mtime)
|
|
43
46
|
group_filter_dict = {rel: pks}
|
|
44
47
|
elif group == FOLDER_GROUP:
|
|
48
|
+
# Top folder search
|
|
45
49
|
group_filter_dict = {"parent_folder": None}
|
|
46
50
|
else:
|
|
47
51
|
group_filter_dict = {}
|
|
48
|
-
|
|
49
52
|
return Q(**group_filter_dict)
|