codex 1.6.0a9__py3-none-any.whl → 1.6.0a10__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/librarian/importer/cache.py +46 -133
- codex/librarian/importer/create_fks.py +3 -1
- codex/librarian/importer/importer.py +1 -1
- codex/librarian/importer/importerd.py +5 -5
- codex/librarian/importer/tasks.py +2 -2
- codex/librarian/janitor/janitor.py +0 -3
- codex/librarian/librariand.py +0 -2
- codex/librarian/notifier/notifierd.py +1 -1
- codex/librarian/notifier/tasks.py +4 -4
- codex/middleware.py +1 -2
- codex/migrations/0027_import_order_and_covers.py +1 -66
- codex/models/comic.py +0 -1
- codex/models/groups.py +0 -3
- codex/serializers/admin.py +41 -40
- codex/serializers/browser/choices.py +22 -6
- codex/serializers/browser/metadata.py +45 -1
- codex/serializers/browser/page.py +2 -4
- codex/serializers/browser/settings.py +34 -14
- codex/serializers/fields.py +19 -1
- codex/serializers/reader.py +11 -1
- codex/serializers/route.py +1 -1
- codex/serializers/settings.py +12 -0
- codex/settings/settings.py +10 -1
- codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js +1 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js.br +0 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js.gz +0 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.js +1 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.js.br +0 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-DLzF_WHB.9a47873b8548.js → VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-DLzF_WHB.js → VCheckboxBtn-D2tPTt6P.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-D2tPTt6P.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-D2tPTt6P.js.gz +0 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js +1 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js.br +0 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js.gz +0 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.js +1 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.js.br +0 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.js.gz +0 -0
- codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js +1 -0
- codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js.br +0 -0
- codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js.gz +0 -0
- codex/static_root/assets/VDialog-61pzfUB2.js +1 -0
- codex/static_root/assets/VDialog-61pzfUB2.js.br +0 -0
- codex/static_root/assets/VDialog-61pzfUB2.js.gz +0 -0
- codex/static_root/assets/{VDialog-C5Nxd_zP.css → VDialog-lQ13FnRR.1c801ad756b2.css} +1 -1
- codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.br +0 -0
- codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.gz +0 -0
- codex/static_root/assets/{VDialog-C5Nxd_zP.d327f505ef0e.css → VDialog-lQ13FnRR.css} +1 -1
- codex/static_root/assets/VDialog-lQ13FnRR.css.br +0 -0
- codex/static_root/assets/VDialog-lQ13FnRR.css.gz +0 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js +1 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.js +1 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-B--7K_v5.4a4e9c2d6c42.js → VRadioGroup-QFQbK1qo.750a42b1b814.js} +1 -1
- codex/static_root/assets/VRadioGroup-QFQbK1qo.750a42b1b814.js.br +0 -0
- codex/static_root/assets/VRadioGroup-QFQbK1qo.750a42b1b814.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-B--7K_v5.js → VRadioGroup-QFQbK1qo.js} +1 -1
- codex/static_root/assets/VRadioGroup-QFQbK1qo.js.br +0 -0
- codex/static_root/assets/VRadioGroup-QFQbK1qo.js.gz +0 -0
- codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js +1 -0
- codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js.br +0 -0
- codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js.gz +0 -0
- codex/static_root/assets/VSelect-Dixy6okt.js +1 -0
- codex/static_root/assets/VSelect-Dixy6okt.js.br +0 -0
- codex/static_root/assets/VSelect-Dixy6okt.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-CVQ9wkE2.c02186cceba6.js → VSelectionControl-MNmxKc3J.08055d00917e.js} +1 -1
- codex/static_root/assets/VSelectionControl-MNmxKc3J.08055d00917e.js.br +0 -0
- codex/static_root/assets/VSelectionControl-MNmxKc3J.08055d00917e.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-CVQ9wkE2.js → VSelectionControl-MNmxKc3J.js} +1 -1
- codex/static_root/assets/VSelectionControl-MNmxKc3J.js.br +0 -0
- codex/static_root/assets/VSelectionControl-MNmxKc3J.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js +1 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js.br +0 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.js +1 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.js.br +0 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.js.gz +0 -0
- codex/static_root/assets/{VTable-CrWkhkiP.6d530eea0c09.js → VTable-lcnYg9Ee.d72927b13c2e.js} +1 -1
- codex/static_root/assets/VTable-lcnYg9Ee.d72927b13c2e.js.br +0 -0
- codex/static_root/assets/VTable-lcnYg9Ee.d72927b13c2e.js.gz +0 -0
- codex/static_root/assets/{VTable-CrWkhkiP.js → VTable-lcnYg9Ee.js} +1 -1
- codex/static_root/assets/VTable-lcnYg9Ee.js.br +0 -0
- codex/static_root/assets/VTable-lcnYg9Ee.js.gz +0 -0
- codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js +1 -0
- codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js.br +0 -0
- codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js.gz +0 -0
- codex/static_root/assets/VTextField-BkFrjhdV.js +1 -0
- codex/static_root/assets/VTextField-BkFrjhdV.js.br +0 -0
- codex/static_root/assets/VTextField-BkFrjhdV.js.gz +0 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js +1 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js.br +0 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js.gz +0 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.js +1 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.js.br +0 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.js.gz +0 -0
- codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js +1 -0
- codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js.br +0 -0
- codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js.gz +0 -0
- codex/static_root/assets/admin-CXES2HXe.js +1 -0
- codex/static_root/assets/admin-CXES2HXe.js.br +0 -0
- codex/static_root/assets/admin-CXES2HXe.js.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-o87BwD38.ce39427c8201.css → admin-drawer-panel-mne3FIj6.561b3f75fe65.css} +1 -1
- codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-o87BwD38.css → admin-drawer-panel-mne3FIj6.css} +1 -1
- codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js +30 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js +30 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js.gz +0 -0
- codex/static_root/assets/browser-BuDeXGEe.css +1 -0
- codex/static_root/assets/browser-BuDeXGEe.css.br +0 -0
- codex/static_root/assets/browser-BuDeXGEe.css.gz +0 -0
- codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css +1 -0
- codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css.br +0 -0
- codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css.gz +0 -0
- codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js +1 -0
- codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js.br +0 -0
- codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js.gz +0 -0
- codex/static_root/assets/browser-s6mFzrK9.js +1 -0
- codex/static_root/assets/browser-s6mFzrK9.js.br +0 -0
- codex/static_root/assets/browser-s6mFzrK9.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +1 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.br +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.css +1 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.css.br +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js +1 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js.br +0 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.js +1 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.js.br +0 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-jwL7B98r.1cfd579cbcfe.js → confirm-dialog-CWszioQE.859051c35dd9.js} +1 -1
- codex/static_root/assets/confirm-dialog-CWszioQE.859051c35dd9.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CWszioQE.859051c35dd9.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-jwL7B98r.js → confirm-dialog-CWszioQE.js} +1 -1
- codex/static_root/assets/confirm-dialog-CWszioQE.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CWszioQE.js.gz +0 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js +1 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js.br +0 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js.gz +0 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.js +1 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.js.br +0 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.js.gz +0 -0
- codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js +1 -0
- codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js.br +0 -0
- codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js.gz +0 -0
- codex/static_root/assets/filter-D3gaGf87.js +1 -0
- codex/static_root/assets/filter-D3gaGf87.js.br +0 -0
- codex/static_root/assets/filter-D3gaGf87.js.gz +0 -0
- codex/static_root/assets/{flag-tab-Da2DBNyz.ffbe5ca37e1c.js → flag-tab-8vzpdySX.a982c7f0776a.js} +1 -1
- codex/static_root/assets/flag-tab-8vzpdySX.a982c7f0776a.js.br +0 -0
- codex/static_root/assets/flag-tab-8vzpdySX.a982c7f0776a.js.gz +0 -0
- codex/static_root/assets/{flag-tab-Da2DBNyz.js → flag-tab-8vzpdySX.js} +1 -1
- codex/static_root/assets/flag-tab-8vzpdySX.js.br +0 -0
- codex/static_root/assets/flag-tab-8vzpdySX.js.gz +0 -0
- codex/static_root/assets/{group-tab-BONYWOc1.6ddf321a4a56.js → group-tab-Cz9t_ECi.a9e8aea79254.js} +1 -1
- codex/static_root/assets/group-tab-Cz9t_ECi.a9e8aea79254.js.br +0 -0
- codex/static_root/assets/group-tab-Cz9t_ECi.a9e8aea79254.js.gz +0 -0
- codex/static_root/assets/{group-tab-BONYWOc1.js → group-tab-Cz9t_ECi.js} +1 -1
- codex/static_root/assets/group-tab-Cz9t_ECi.js.br +0 -0
- codex/static_root/assets/group-tab-Cz9t_ECi.js.gz +0 -0
- codex/static_root/assets/{http-error-D2Jnc20C.32846bc3a43d.js → http-error-Cqtszzf1.b31df3d9c29f.js} +1 -1
- codex/static_root/assets/http-error-Cqtszzf1.b31df3d9c29f.js.br +0 -0
- codex/static_root/assets/http-error-Cqtszzf1.b31df3d9c29f.js.gz +0 -0
- codex/static_root/assets/{http-error-D2Jnc20C.js → http-error-Cqtszzf1.js} +1 -1
- codex/static_root/assets/http-error-Cqtszzf1.js.br +0 -0
- codex/static_root/assets/http-error-Cqtszzf1.js.gz +0 -0
- codex/static_root/assets/{library-tab-B419agXA.js → library-tab-DMlnswUU.30f454e84184.js} +1 -1
- codex/static_root/assets/library-tab-DMlnswUU.30f454e84184.js.br +0 -0
- codex/static_root/assets/library-tab-DMlnswUU.30f454e84184.js.gz +0 -0
- codex/static_root/assets/{library-tab-B419agXA.d4b778172aaa.js → library-tab-DMlnswUU.js} +1 -1
- codex/static_root/assets/library-tab-DMlnswUU.js.br +0 -0
- codex/static_root/assets/library-tab-DMlnswUU.js.gz +0 -0
- codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js +32 -0
- codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js.br +0 -0
- codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js.gz +0 -0
- codex/static_root/assets/main-vjXu_QYL.js +32 -0
- codex/static_root/assets/main-vjXu_QYL.js.br +0 -0
- codex/static_root/assets/main-vjXu_QYL.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css +1 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.css +1 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js +1 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.js +1 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-8RVZqILx.2e7166dd26fb.js → pdf-doc-BiamrjRZ.4c9be1ade43c.js} +1 -1
- codex/static_root/assets/pdf-doc-BiamrjRZ.4c9be1ade43c.js.br +0 -0
- codex/static_root/assets/pdf-doc-BiamrjRZ.4c9be1ade43c.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-8RVZqILx.js → pdf-doc-BiamrjRZ.js} +1 -1
- codex/static_root/assets/pdf-doc-BiamrjRZ.js.br +0 -0
- codex/static_root/assets/pdf-doc-BiamrjRZ.js.gz +0 -0
- codex/static_root/assets/{reader-CCCfpM3x.1553e45bd775.css → reader-BpsctRsY.5d72e393911a.css} +1 -1
- codex/static_root/assets/reader-BpsctRsY.5d72e393911a.css.br +0 -0
- codex/static_root/assets/reader-BpsctRsY.5d72e393911a.css.gz +0 -0
- codex/static_root/assets/{reader-CCCfpM3x.css → reader-BpsctRsY.css} +1 -1
- codex/static_root/assets/reader-BpsctRsY.css.br +0 -0
- codex/static_root/assets/reader-BpsctRsY.css.gz +0 -0
- codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js +2 -0
- codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js.br +0 -0
- codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js.gz +0 -0
- codex/static_root/assets/reader-CDk8oZzB.js +2 -0
- codex/static_root/assets/reader-CDk8oZzB.js.br +0 -0
- codex/static_root/assets/reader-CDk8oZzB.js.gz +0 -0
- codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js +1 -0
- codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js.br +0 -0
- codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js.gz +0 -0
- codex/static_root/assets/relation-chips-C5acBjpy.js +1 -0
- codex/static_root/assets/relation-chips-C5acBjpy.js.br +0 -0
- codex/static_root/assets/relation-chips-C5acBjpy.js.gz +0 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js +2 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js.br +0 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js.gz +0 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.js +2 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.js.br +0 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.js.gz +0 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +1 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.css +1 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js +1 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js.br +0 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js.gz +0 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.js +1 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.js.br +0 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.js.gz +0 -0
- codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js +1 -0
- codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js.br +0 -0
- codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js.gz +0 -0
- codex/static_root/assets/task-tab-DF9qa6LO.js +1 -0
- codex/static_root/assets/task-tab-DF9qa6LO.js.br +0 -0
- codex/static_root/assets/task-tab-DF9qa6LO.js.gz +0 -0
- codex/static_root/assets/to-case-CGbULRaE.4c80644f460d.js +1 -0
- codex/static_root/assets/to-case-CGbULRaE.4c80644f460d.js.br +0 -0
- codex/static_root/assets/to-case-CGbULRaE.js +1 -0
- codex/static_root/assets/to-case-CGbULRaE.js.br +0 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js +1 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js.br +0 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js.gz +0 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.js +1 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.js.br +0 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.js.gz +0 -0
- codex/static_root/assets/{unauthorized-DHV6Q1n-.b7847b2872a1.css → unauthorized-CibJYD8o.4c2de98c2b53.css} +1 -1
- codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.br +0 -0
- codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.gz +0 -0
- codex/static_root/assets/{unauthorized-DHV6Q1n-.css → unauthorized-CibJYD8o.css} +1 -1
- codex/static_root/assets/unauthorized-CibJYD8o.css.br +0 -0
- codex/static_root/assets/unauthorized-CibJYD8o.css.gz +0 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js +1 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js.br +0 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js.gz +0 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.js +1 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.js.br +0 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.js.gz +0 -0
- codex/static_root/js/choices-admin.3521e2a863df.json +1 -0
- codex/static_root/js/choices-admin.3521e2a863df.json.br +0 -0
- codex/static_root/js/choices-admin.3521e2a863df.json.gz +0 -0
- codex/static_root/js/choices-admin.json +1 -1
- codex/static_root/js/choices-admin.json.br +0 -0
- codex/static_root/js/choices-admin.json.gz +0 -0
- codex/static_root/manifest.35e46a3ec8fa.json +622 -0
- codex/static_root/manifest.35e46a3ec8fa.json.br +0 -0
- codex/static_root/manifest.35e46a3ec8fa.json.gz +0 -0
- codex/static_root/manifest.json +245 -252
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/views/admin/api_key.py +5 -2
- codex/views/admin/stats.py +13 -20
- codex/views/admin/tasks.py +2 -3
- codex/views/auth.py +1 -1
- codex/views/bookmark.py +30 -16
- codex/views/browser/annotations.py +2 -0
- codex/views/browser/base.py +22 -6
- codex/views/browser/breadcrumbs.py +5 -5
- codex/views/browser/browser.py +14 -22
- codex/views/browser/choices.py +18 -15
- codex/views/browser/cover.py +30 -66
- codex/views/browser/filters/annotations.py +14 -6
- codex/views/browser/filters/group.py +24 -15
- codex/views/browser/filters/search.py +3 -4
- codex/views/browser/metadata.py +86 -47
- codex/views/browser/mtime.py +3 -14
- codex/views/browser/order_by.py +1 -6
- codex/views/browser/settings.py +53 -0
- codex/views/browser/validate.py +3 -0
- codex/views/const.py +24 -1
- codex/views/opds/v1/feed.py +3 -5
- codex/views/opds/v2/feed.py +3 -3
- codex/views/reader/arcs.py +42 -51
- codex/views/reader/books.py +47 -63
- codex/views/reader/init.py +121 -0
- codex/views/reader/reader.py +9 -70
- codex/views/session.py +15 -11
- codex/views/settings.py +23 -10
- codex/views/util.py +2 -1
- codex/websockets/consumers.py +13 -9
- {codex-1.6.0a9.dist-info → codex-1.6.0a10.dist-info}/METADATA +1 -1
- {codex-1.6.0a9.dist-info → codex-1.6.0a10.dist-info}/RECORD +321 -317
- codex/static_root/assets/VCheckbox-eNspVUje.da8282a08876.js +0 -1
- codex/static_root/assets/VCheckbox-eNspVUje.da8282a08876.js.br +0 -0
- codex/static_root/assets/VCheckbox-eNspVUje.da8282a08876.js.gz +0 -0
- codex/static_root/assets/VCheckbox-eNspVUje.js +0 -1
- codex/static_root/assets/VCheckbox-eNspVUje.js.br +0 -0
- codex/static_root/assets/VCheckbox-eNspVUje.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-DLzF_WHB.9a47873b8548.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-DLzF_WHB.9a47873b8548.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-DLzF_WHB.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-DLzF_WHB.js.gz +0 -0
- codex/static_root/assets/VCombobox-BIO7lU_B.d607ada71b06.js +0 -1
- codex/static_root/assets/VCombobox-BIO7lU_B.d607ada71b06.js.br +0 -0
- codex/static_root/assets/VCombobox-BIO7lU_B.d607ada71b06.js.gz +0 -0
- codex/static_root/assets/VCombobox-BIO7lU_B.js +0 -1
- codex/static_root/assets/VCombobox-BIO7lU_B.js.br +0 -0
- codex/static_root/assets/VCombobox-BIO7lU_B.js.gz +0 -0
- codex/static_root/assets/VDialog-87AymJC5.4a46716358c0.js +0 -1
- codex/static_root/assets/VDialog-87AymJC5.4a46716358c0.js.br +0 -0
- codex/static_root/assets/VDialog-87AymJC5.4a46716358c0.js.gz +0 -0
- codex/static_root/assets/VDialog-87AymJC5.js +0 -1
- codex/static_root/assets/VDialog-87AymJC5.js.br +0 -0
- codex/static_root/assets/VDialog-87AymJC5.js.gz +0 -0
- codex/static_root/assets/VDialog-C5Nxd_zP.css.br +0 -0
- codex/static_root/assets/VDialog-C5Nxd_zP.css.gz +0 -0
- codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.br +0 -0
- codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CgA3shsd.9e524c73726a.js +0 -1
- codex/static_root/assets/VExpansionPanels-CgA3shsd.9e524c73726a.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CgA3shsd.9e524c73726a.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CgA3shsd.js +0 -1
- codex/static_root/assets/VExpansionPanels-CgA3shsd.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CgA3shsd.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-B--7K_v5.4a4e9c2d6c42.js.br +0 -0
- codex/static_root/assets/VRadioGroup-B--7K_v5.4a4e9c2d6c42.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-B--7K_v5.js.br +0 -0
- codex/static_root/assets/VRadioGroup-B--7K_v5.js.gz +0 -0
- codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js +0 -1
- codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js.br +0 -0
- codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js.gz +0 -0
- codex/static_root/assets/VSelect-BoJq222l.js +0 -1
- codex/static_root/assets/VSelect-BoJq222l.js.br +0 -0
- codex/static_root/assets/VSelect-BoJq222l.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CVQ9wkE2.c02186cceba6.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CVQ9wkE2.c02186cceba6.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CVQ9wkE2.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CVQ9wkE2.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.85e64443a928.js +0 -1
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.85e64443a928.js.br +0 -0
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.85e64443a928.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.js +0 -1
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.js.br +0 -0
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.js.gz +0 -0
- codex/static_root/assets/VTable-CrWkhkiP.6d530eea0c09.js.br +0 -0
- codex/static_root/assets/VTable-CrWkhkiP.6d530eea0c09.js.gz +0 -0
- codex/static_root/assets/VTable-CrWkhkiP.js.br +0 -0
- codex/static_root/assets/VTable-CrWkhkiP.js.gz +0 -0
- codex/static_root/assets/VTextField-CkWbil3K.2cac13161dfe.js +0 -1
- codex/static_root/assets/VTextField-CkWbil3K.2cac13161dfe.js.br +0 -0
- codex/static_root/assets/VTextField-CkWbil3K.2cac13161dfe.js.gz +0 -0
- codex/static_root/assets/VTextField-CkWbil3K.js +0 -1
- codex/static_root/assets/VTextField-CkWbil3K.js.br +0 -0
- codex/static_root/assets/VTextField-CkWbil3K.js.gz +0 -0
- codex/static_root/assets/VWindowItem-7z55Y4lK.98eb7487e039.js +0 -1
- codex/static_root/assets/VWindowItem-7z55Y4lK.98eb7487e039.js.br +0 -0
- codex/static_root/assets/VWindowItem-7z55Y4lK.98eb7487e039.js.gz +0 -0
- codex/static_root/assets/VWindowItem-7z55Y4lK.js +0 -1
- codex/static_root/assets/VWindowItem-7z55Y4lK.js.br +0 -0
- codex/static_root/assets/VWindowItem-7z55Y4lK.js.gz +0 -0
- codex/static_root/assets/admin-D3OK784R.f69891726ec5.js +0 -1
- codex/static_root/assets/admin-D3OK784R.f69891726ec5.js.br +0 -0
- codex/static_root/assets/admin-D3OK784R.f69891726ec5.js.gz +0 -0
- codex/static_root/assets/admin-D3OK784R.js +0 -1
- codex/static_root/assets/admin-D3OK784R.js.br +0 -0
- codex/static_root/assets/admin-D3OK784R.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.5438f252970e.js +0 -30
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.5438f252970e.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.5438f252970e.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.js +0 -30
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-o87BwD38.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-o87BwD38.css.gz +0 -0
- codex/static_root/assets/browser-BuU2x9y7.css +0 -1
- codex/static_root/assets/browser-BuU2x9y7.css.br +0 -0
- codex/static_root/assets/browser-BuU2x9y7.css.gz +0 -0
- codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css +0 -1
- codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css.br +0 -0
- codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css.gz +0 -0
- codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js +0 -1
- codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js.br +0 -0
- codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js.gz +0 -0
- codex/static_root/assets/browser-CO9EYHIr.js +0 -1
- codex/static_root/assets/browser-CO9EYHIr.js.br +0 -0
- codex/static_root/assets/browser-CO9EYHIr.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-CjZdzaIk.188c765431ab.js +0 -1
- codex/static_root/assets/change-password-dialog-CjZdzaIk.188c765431ab.js.br +0 -0
- codex/static_root/assets/change-password-dialog-CjZdzaIk.188c765431ab.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-CjZdzaIk.js +0 -1
- codex/static_root/assets/change-password-dialog-CjZdzaIk.js.br +0 -0
- codex/static_root/assets/change-password-dialog-CjZdzaIk.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css +0 -1
- codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.br +0 -0
- codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-HvIvmmIE.css +0 -1
- codex/static_root/assets/change-password-dialog-HvIvmmIE.css.br +0 -0
- codex/static_root/assets/change-password-dialog-HvIvmmIE.css.gz +0 -0
- codex/static_root/assets/confirm-dialog-jwL7B98r.1cfd579cbcfe.js.br +0 -0
- codex/static_root/assets/confirm-dialog-jwL7B98r.1cfd579cbcfe.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-jwL7B98r.js.br +0 -0
- codex/static_root/assets/confirm-dialog-jwL7B98r.js.gz +0 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js +0 -1
- codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js.br +0 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js.gz +0 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.js +0 -1
- codex/static_root/assets/datetime-column-9w3GcKvo.js.br +0 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.js.gz +0 -0
- codex/static_root/assets/filter-C-pghOri.eeb7c2ecf398.js +0 -1
- codex/static_root/assets/filter-C-pghOri.eeb7c2ecf398.js.br +0 -0
- codex/static_root/assets/filter-C-pghOri.eeb7c2ecf398.js.gz +0 -0
- codex/static_root/assets/filter-C-pghOri.js +0 -1
- codex/static_root/assets/filter-C-pghOri.js.br +0 -0
- codex/static_root/assets/filter-C-pghOri.js.gz +0 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.ffbe5ca37e1c.js.br +0 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.ffbe5ca37e1c.js.gz +0 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.js.br +0 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.js.gz +0 -0
- codex/static_root/assets/group-tab-BONYWOc1.6ddf321a4a56.js.br +0 -0
- codex/static_root/assets/group-tab-BONYWOc1.6ddf321a4a56.js.gz +0 -0
- codex/static_root/assets/group-tab-BONYWOc1.js.br +0 -0
- codex/static_root/assets/group-tab-BONYWOc1.js.gz +0 -0
- codex/static_root/assets/http-error-D2Jnc20C.32846bc3a43d.js.br +0 -0
- codex/static_root/assets/http-error-D2Jnc20C.32846bc3a43d.js.gz +0 -0
- codex/static_root/assets/http-error-D2Jnc20C.js.br +0 -0
- codex/static_root/assets/http-error-D2Jnc20C.js.gz +0 -0
- codex/static_root/assets/library-tab-B419agXA.d4b778172aaa.js.br +0 -0
- codex/static_root/assets/library-tab-B419agXA.d4b778172aaa.js.gz +0 -0
- codex/static_root/assets/library-tab-B419agXA.js.br +0 -0
- codex/static_root/assets/library-tab-B419agXA.js.gz +0 -0
- codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js +0 -32
- codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js.br +0 -0
- codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js.gz +0 -0
- codex/static_root/assets/main-CMQwJ9aG.js +0 -32
- codex/static_root/assets/main-CMQwJ9aG.js.br +0 -0
- codex/static_root/assets/main-CMQwJ9aG.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css +0 -1
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css +0 -1
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js +0 -1
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.js +0 -1
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.js.gz +0 -0
- codex/static_root/assets/pdf-doc-8RVZqILx.2e7166dd26fb.js.br +0 -0
- codex/static_root/assets/pdf-doc-8RVZqILx.2e7166dd26fb.js.gz +0 -0
- codex/static_root/assets/pdf-doc-8RVZqILx.js.br +0 -0
- codex/static_root/assets/pdf-doc-8RVZqILx.js.gz +0 -0
- codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.br +0 -0
- codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.gz +0 -0
- codex/static_root/assets/reader-CCCfpM3x.css.br +0 -0
- codex/static_root/assets/reader-CCCfpM3x.css.gz +0 -0
- codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js +0 -2
- codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js.br +0 -0
- codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js.gz +0 -0
- codex/static_root/assets/reader-DNnK_Chr.js +0 -2
- codex/static_root/assets/reader-DNnK_Chr.js.br +0 -0
- codex/static_root/assets/reader-DNnK_Chr.js.gz +0 -0
- codex/static_root/assets/relation-chips-PYua7aXv.428ba0b5861e.js +0 -1
- codex/static_root/assets/relation-chips-PYua7aXv.428ba0b5861e.js.br +0 -0
- codex/static_root/assets/relation-chips-PYua7aXv.428ba0b5861e.js.gz +0 -0
- codex/static_root/assets/relation-chips-PYua7aXv.js +0 -1
- codex/static_root/assets/relation-chips-PYua7aXv.js.br +0 -0
- codex/static_root/assets/relation-chips-PYua7aXv.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DbN6ISRH.d14f525d8eee.js +0 -2
- codex/static_root/assets/settings-drawer-DbN6ISRH.d14f525d8eee.js.br +0 -0
- codex/static_root/assets/settings-drawer-DbN6ISRH.d14f525d8eee.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DbN6ISRH.js +0 -2
- codex/static_root/assets/settings-drawer-DbN6ISRH.js.br +0 -0
- codex/static_root/assets/settings-drawer-DbN6ISRH.js.gz +0 -0
- codex/static_root/assets/stats-tab-DImNhH8O.d5026283841a.js +0 -1
- codex/static_root/assets/stats-tab-DImNhH8O.d5026283841a.js.br +0 -0
- codex/static_root/assets/stats-tab-DImNhH8O.d5026283841a.js.gz +0 -0
- codex/static_root/assets/stats-tab-DImNhH8O.js +0 -1
- codex/static_root/assets/stats-tab-DImNhH8O.js.br +0 -0
- codex/static_root/assets/stats-tab-DImNhH8O.js.gz +0 -0
- codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css +0 -1
- codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.br +0 -2
- codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.gz +0 -0
- codex/static_root/assets/stats-tab-TsyG3wH_.css +0 -1
- codex/static_root/assets/stats-tab-TsyG3wH_.css.br +0 -2
- codex/static_root/assets/stats-tab-TsyG3wH_.css.gz +0 -0
- codex/static_root/assets/task-tab-DPD53kjv.e56a35ff1691.js +0 -1
- codex/static_root/assets/task-tab-DPD53kjv.e56a35ff1691.js.br +0 -0
- codex/static_root/assets/task-tab-DPD53kjv.e56a35ff1691.js.gz +0 -0
- codex/static_root/assets/task-tab-DPD53kjv.js +0 -1
- codex/static_root/assets/task-tab-DPD53kjv.js.br +0 -0
- codex/static_root/assets/task-tab-DPD53kjv.js.gz +0 -0
- codex/static_root/assets/to-case-ehC9Ccyj.a7b8e25b391f.js +0 -1
- codex/static_root/assets/to-case-ehC9Ccyj.js +0 -1
- codex/static_root/assets/unauthorized-BOIx7Y18.ee3961abfccb.js +0 -1
- codex/static_root/assets/unauthorized-BOIx7Y18.ee3961abfccb.js.br +0 -0
- codex/static_root/assets/unauthorized-BOIx7Y18.ee3961abfccb.js.gz +0 -0
- codex/static_root/assets/unauthorized-BOIx7Y18.js +0 -1
- codex/static_root/assets/unauthorized-BOIx7Y18.js.br +0 -0
- codex/static_root/assets/unauthorized-BOIx7Y18.js.gz +0 -0
- codex/static_root/assets/unauthorized-DHV6Q1n-.b7847b2872a1.css.br +0 -0
- codex/static_root/assets/unauthorized-DHV6Q1n-.b7847b2872a1.css.gz +0 -0
- codex/static_root/assets/unauthorized-DHV6Q1n-.css.br +0 -0
- codex/static_root/assets/unauthorized-DHV6Q1n-.css.gz +0 -0
- codex/static_root/assets/user-tab-BABwfxLO.37dd0440fbdd.js +0 -1
- codex/static_root/assets/user-tab-BABwfxLO.37dd0440fbdd.js.br +0 -0
- codex/static_root/assets/user-tab-BABwfxLO.37dd0440fbdd.js.gz +0 -0
- codex/static_root/assets/user-tab-BABwfxLO.js +0 -1
- codex/static_root/assets/user-tab-BABwfxLO.js.br +0 -0
- codex/static_root/assets/user-tab-BABwfxLO.js.gz +0 -0
- codex/static_root/js/choices-admin.d790df01c20a.json +0 -1
- codex/static_root/js/choices-admin.d790df01c20a.json.br +0 -0
- codex/static_root/js/choices-admin.d790df01c20a.json.gz +0 -0
- codex/static_root/manifest.cbea5663003a.json +0 -629
- codex/static_root/manifest.cbea5663003a.json.br +0 -0
- codex/static_root/manifest.cbea5663003a.json.gz +0 -0
- {codex-1.6.0a9.dist-info → codex-1.6.0a10.dist-info}/LICENSE +0 -0
- {codex-1.6.0a9.dist-info → codex-1.6.0a10.dist-info}/WHEEL +0 -0
- {codex-1.6.0a9.dist-info → codex-1.6.0a10.dist-info}/entry_points.txt +0 -0
|
@@ -1,171 +1,84 @@
|
|
|
1
1
|
"""Update Groups timestamp for cover cache busting."""
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
3
|
from django.db.models.aggregates import Count
|
|
6
4
|
from django.db.models.functions.datetime import Now
|
|
7
5
|
from django.db.models.query import Q
|
|
8
6
|
|
|
9
7
|
from codex.librarian.importer.init import InitImporter
|
|
10
8
|
from codex.librarian.importer.status import ImportStatusTypes
|
|
11
|
-
from codex.models import
|
|
9
|
+
from codex.models import StoryArc, Volume
|
|
12
10
|
from codex.status import Status
|
|
11
|
+
from codex.views.const import GROUP_MODELS
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
_UPDATE_FIELDS = ("first_comic", "updated_at")
|
|
13
|
+
_UPDATE_FIELDS = ("updated_at",)
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
class CacheUpdateImporter(InitImporter):
|
|
19
17
|
"""Update Groups timestamp for cover cache busting."""
|
|
20
18
|
|
|
21
19
|
@staticmethod
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.select_related("first_comic")
|
|
29
|
-
.only("path", *_UPDATE_FIELDS)
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
# Create a map of each folder by path depth level
|
|
33
|
-
batch_map = {}
|
|
34
|
-
for folder in all_folders:
|
|
35
|
-
depth = folder.path.count(os.sep)
|
|
36
|
-
if depth not in batch_map:
|
|
37
|
-
batch_map[depth] = set()
|
|
38
|
-
batch_map[depth].add(folder)
|
|
39
|
-
|
|
40
|
-
# Order batches by reverse depth level to update bottom up.
|
|
41
|
-
batches = []
|
|
42
|
-
for _, folders in sorted(batch_map.items(), reverse=True):
|
|
43
|
-
batches.append(folders)
|
|
44
|
-
|
|
45
|
-
return tuple(batches)
|
|
20
|
+
def _get_update_filter(model, start_time, force_update_group_map):
|
|
21
|
+
# Get groups with comics updated during this import
|
|
22
|
+
rel = "storyarcnumber__" if model == StoryArc else ""
|
|
23
|
+
updated_at_rel = rel + "comic__updated_at__gt"
|
|
24
|
+
updated_filter = {updated_at_rel: start_time}
|
|
25
|
+
update_filter = Q(**updated_filter)
|
|
46
26
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
qs = qs.order_by("issue_number", "issue_suffix", "sort_name").only("pk")
|
|
51
|
-
obj.first_comic = qs.first()
|
|
27
|
+
# Get groups with custom covers updated during this import
|
|
28
|
+
if model != Volume:
|
|
29
|
+
update_filter |= Q(custom_cover__updated_at__gt=start_time)
|
|
52
30
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
order_by = "name" if model == Volume else "sort_name"
|
|
57
|
-
qs = qs.select_related("first_comic").order_by(order_by).only("first_comic")
|
|
58
|
-
obj.first_comic = qs.first().first_comic
|
|
31
|
+
# Get groups to be force updated (usually those with deleted children)
|
|
32
|
+
if pks := force_update_group_map.get(model):
|
|
33
|
+
update_filter |= Q(pk__in=pks)
|
|
59
34
|
|
|
60
|
-
|
|
61
|
-
def _update_first_cover_story_arc(obj):
|
|
62
|
-
qs = Comic.objects.filter(story_arc_numbers__story_arc=obj)
|
|
63
|
-
qs = qs.order_by("story_arc_numbers__number", "date").only("pk")
|
|
64
|
-
obj.first_comic = qs.first()
|
|
35
|
+
return update_filter
|
|
65
36
|
|
|
66
37
|
@staticmethod
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
first_folder = (
|
|
75
|
-
Folder.objects.filter(parent_folder=obj)
|
|
76
|
-
.select_related("first_comic")
|
|
77
|
-
.order_by("path")
|
|
78
|
-
.only("first_comic", "path")
|
|
79
|
-
.first()
|
|
80
|
-
)
|
|
81
|
-
if first_comic and not first_folder:
|
|
82
|
-
obj.first_comic = first_comic
|
|
83
|
-
elif first_folder and not first_comic:
|
|
84
|
-
obj.first_comic = first_folder.first_comic
|
|
85
|
-
elif first_folder and first_comic:
|
|
86
|
-
if first_comic and first_comic.path < first_folder.path:
|
|
87
|
-
obj.first_comic = first_comic
|
|
88
|
-
else:
|
|
89
|
-
obj.first_comic = first_folder.first_comic
|
|
90
|
-
|
|
91
|
-
@classmethod
|
|
92
|
-
def _update_first_cover(cls, model, obj):
|
|
93
|
-
if model == Volume:
|
|
94
|
-
cls._update_first_cover_volume(obj)
|
|
95
|
-
elif model == Series:
|
|
96
|
-
cls._update_first_cover_group(obj, Volume, "series")
|
|
97
|
-
elif model == Imprint:
|
|
98
|
-
cls._update_first_cover_group(obj, Series, "imprint")
|
|
99
|
-
elif model == Publisher:
|
|
100
|
-
cls._update_first_cover_group(obj, Imprint, "publisher")
|
|
101
|
-
elif model == StoryArc:
|
|
102
|
-
cls._update_first_cover_story_arc(obj)
|
|
103
|
-
elif model == Folder:
|
|
104
|
-
cls._update_first_cover_folder(obj)
|
|
38
|
+
def _add_child_count_filter(qs, model):
|
|
39
|
+
"""Filter out groups with no comics."""
|
|
40
|
+
rel_prefix = "storyarcnumber__" if model == StoryArc else ""
|
|
41
|
+
rel_prefix += "comic"
|
|
42
|
+
qs = qs.alias(child_count=Count(f"{rel_prefix}__pk", distinct=True))
|
|
43
|
+
return qs.filter(child_count__gt=0)
|
|
105
44
|
|
|
106
45
|
@classmethod
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
updated_at_rel = rel + "comic__updated_at__gt"
|
|
112
|
-
updated_filter = {updated_at_rel: start_time}
|
|
113
|
-
filter_query = (
|
|
114
|
-
Q(**updated_filter)
|
|
115
|
-
| Q(first_comic__isnull=True)
|
|
116
|
-
| Q(updated_at__gt=start_time)
|
|
46
|
+
def _update_group_model(cls, force_update_group_map, model, start_time, log_list):
|
|
47
|
+
"""Update a single group model."""
|
|
48
|
+
update_filter = cls._get_update_filter(
|
|
49
|
+
model, start_time, force_update_group_map
|
|
117
50
|
)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
pks = force_update_group_map.get(model)
|
|
121
|
-
if pks:
|
|
122
|
-
filter_query |= Q(pk__in=pks)
|
|
123
|
-
model_qs = model.objects.filter(filter_query)
|
|
51
|
+
qs = model.objects.filter(update_filter)
|
|
52
|
+
qs = cls._add_child_count_filter(qs, model)
|
|
124
53
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
rel_prefix += "comic"
|
|
128
|
-
model_qs = model_qs.alias(child_count=Count(f"{rel_prefix}__pk", distinct=True))
|
|
129
|
-
model_qs = model_qs.filter(child_count__gt=0)
|
|
130
|
-
model_qs = model_qs.distinct()
|
|
131
|
-
if model == Folder:
|
|
132
|
-
batches = cls._get_folder_batches(model_qs)
|
|
133
|
-
else:
|
|
134
|
-
model_qs.select_related("first_comic").only(*_UPDATE_FIELDS)
|
|
135
|
-
batches = (model_qs,)
|
|
54
|
+
qs = qs.distinct()
|
|
55
|
+
qs = qs.only(*_UPDATE_FIELDS)
|
|
136
56
|
|
|
137
|
-
|
|
138
|
-
for
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
count
|
|
146
|
-
|
|
147
|
-
model.objects.bulk_update(updated, _UPDATE_FIELDS)
|
|
148
|
-
total_count += count
|
|
149
|
-
if total_count:
|
|
150
|
-
log_list.append(f"{total_count} {model.__name__}s")
|
|
151
|
-
return total_count
|
|
57
|
+
updated = []
|
|
58
|
+
for obj in qs:
|
|
59
|
+
obj.updated_at = Now()
|
|
60
|
+
updated.append(obj)
|
|
61
|
+
|
|
62
|
+
count = len(updated)
|
|
63
|
+
if count:
|
|
64
|
+
model.objects.bulk_update(updated, _UPDATE_FIELDS)
|
|
65
|
+
log_list.append(f"{count} {model.__name__}s")
|
|
66
|
+
return count
|
|
152
67
|
|
|
153
|
-
def
|
|
68
|
+
def update_all_groups(self, force_update_group_map, start_time):
|
|
154
69
|
"""Update timestamps for each group for cover cache busting."""
|
|
155
70
|
total_count = 0
|
|
156
71
|
status = Status(ImportStatusTypes.GROUP_UPDATE)
|
|
157
72
|
self.status_controller.start(status)
|
|
158
73
|
try:
|
|
159
74
|
log_list = []
|
|
160
|
-
for model in
|
|
161
|
-
# self.log.debug(f"Updating
|
|
162
|
-
count = self.
|
|
75
|
+
for model in GROUP_MODELS:
|
|
76
|
+
# self.log.debug(f"Updating timestamps for {model.__name__}s...")
|
|
77
|
+
count = self._update_group_model(
|
|
163
78
|
force_update_group_map, model, start_time, log_list
|
|
164
79
|
)
|
|
165
80
|
if count:
|
|
166
|
-
self.log.debug(
|
|
167
|
-
f"Updated {count} first covers for {model.__name__}s"
|
|
168
|
-
)
|
|
81
|
+
self.log.debug(f"Updated {count} {model.__name__}s timestamps.")
|
|
169
82
|
status.add_complete(count)
|
|
170
83
|
self.status_controller.update(status, notify=False)
|
|
171
84
|
total_count += count
|
|
@@ -173,7 +86,7 @@ class CacheUpdateImporter(InitImporter):
|
|
|
173
86
|
if total_count:
|
|
174
87
|
groups_log = ", ".join(log_list)
|
|
175
88
|
self.log.info( # type: ignore
|
|
176
|
-
f"Updated
|
|
89
|
+
f"Updated timestamps for {groups_log}."
|
|
177
90
|
)
|
|
178
91
|
self.changed += total_count
|
|
179
92
|
finally:
|
|
@@ -211,8 +211,10 @@ class CreateForeignKeysImporter(CreateCoversImporter):
|
|
|
211
211
|
folder_path_dict[path_length].add(path)
|
|
212
212
|
|
|
213
213
|
# create each depth level first to ensure we can assign parents
|
|
214
|
-
for
|
|
214
|
+
for depth_level in sorted(folder_path_dict):
|
|
215
|
+
paths = sorted(folder_path_dict[depth_level])
|
|
215
216
|
count += self._bulk_folders_create_depth_level(paths, status)
|
|
217
|
+
self.log.debug(f"Created {count} Folders at depth level {depth_level}")
|
|
216
218
|
|
|
217
219
|
if count:
|
|
218
220
|
self.log.info(f"Created {count} Folders.")
|
|
@@ -88,7 +88,7 @@ class ComicImporter(MovedImporter):
|
|
|
88
88
|
|
|
89
89
|
deleted_comic_groups = self.delete()
|
|
90
90
|
|
|
91
|
-
self.
|
|
91
|
+
self.update_all_groups(deleted_comic_groups, self.start_time)
|
|
92
92
|
|
|
93
93
|
finally:
|
|
94
94
|
self._finish_apply_status()
|
|
@@ -8,7 +8,7 @@ from codex.librarian.importer.tasks import (
|
|
|
8
8
|
AdoptOrphanFoldersTask,
|
|
9
9
|
ImportDBDiffTask,
|
|
10
10
|
LazyImportComicsTask,
|
|
11
|
-
|
|
11
|
+
UpdateGroupsTask,
|
|
12
12
|
)
|
|
13
13
|
from codex.librarian.notifier.tasks import LIBRARY_CHANGED_TASK
|
|
14
14
|
from codex.models import Comic, Folder, Library
|
|
@@ -89,13 +89,13 @@ class ComicImporterThread(QueuedThread):
|
|
|
89
89
|
|
|
90
90
|
self.status_controller.finish_many((moved_status, status))
|
|
91
91
|
|
|
92
|
-
def
|
|
92
|
+
def _update_groups(self, task):
|
|
93
93
|
pks = Library.objects.filter(covers_only=False).values_list("pk", flat=True)
|
|
94
94
|
start_time = task.start_time if task.start_time else timezone.now()
|
|
95
95
|
for pk in pks:
|
|
96
96
|
task = ImportDBDiffTask(library_id=pk)
|
|
97
97
|
importer = self._create_importer(task)
|
|
98
|
-
importer.
|
|
98
|
+
importer.update_all_groups({}, start_time)
|
|
99
99
|
self.librarian_queue.put(LIBRARY_CHANGED_TASK)
|
|
100
100
|
|
|
101
101
|
def process_item(self, item):
|
|
@@ -107,7 +107,7 @@ class ComicImporterThread(QueuedThread):
|
|
|
107
107
|
self._lazy_import_metadata(task)
|
|
108
108
|
elif isinstance(task, AdoptOrphanFoldersTask):
|
|
109
109
|
self._adopt_orphan_folders()
|
|
110
|
-
elif isinstance(task,
|
|
111
|
-
self.
|
|
110
|
+
elif isinstance(task, UpdateGroupsTask):
|
|
111
|
+
self._update_groups(task)
|
|
112
112
|
else:
|
|
113
113
|
self.log.warning(f"Bad task sent to library updater {task}")
|
|
@@ -47,7 +47,7 @@ class AdoptOrphanFoldersTask(ImportTask):
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
@dataclass
|
|
50
|
-
class
|
|
51
|
-
"""Force the update of
|
|
50
|
+
class UpdateGroupsTask(ImportTask):
|
|
51
|
+
"""Force the update of group timestamp."""
|
|
52
52
|
|
|
53
53
|
start_time: datetime | None = None
|
|
@@ -5,7 +5,6 @@ from codex.librarian.covers.tasks import CoverRemoveOrphansTask
|
|
|
5
5
|
from codex.librarian.importer.status import ImportStatusTypes
|
|
6
6
|
from codex.librarian.importer.tasks import (
|
|
7
7
|
AdoptOrphanFoldersTask,
|
|
8
|
-
UpdateGroupsFirstComic,
|
|
9
8
|
)
|
|
10
9
|
from codex.librarian.janitor.cleanup import TOTAL_NUM_FK_CLASSES, CleanupMixin
|
|
11
10
|
from codex.librarian.janitor.failed_imports import UpdateFailedImportsMixin
|
|
@@ -41,7 +40,6 @@ _JANITOR_STATII = (
|
|
|
41
40
|
Status(JanitorStatusTypes.DB_OPTIMIZE),
|
|
42
41
|
Status(JanitorStatusTypes.DB_BACKUP),
|
|
43
42
|
Status(JanitorStatusTypes.CODEX_UPDATE),
|
|
44
|
-
Status(ImportStatusTypes.GROUP_UPDATE),
|
|
45
43
|
Status(CoverStatusTypes.FIND_ORPHAN),
|
|
46
44
|
Status(CoverStatusTypes.PURGE_COVERS),
|
|
47
45
|
Status(ImportStatusTypes.ADOPT_FOLDERS),
|
|
@@ -75,7 +73,6 @@ class Janitor(CleanupMixin, UpdateMixin, VacuumMixin, UpdateFailedImportsMixin):
|
|
|
75
73
|
JanitorBackupTask(),
|
|
76
74
|
JanitorUpdateTask(force=False),
|
|
77
75
|
AdoptOrphanFoldersTask(),
|
|
78
|
-
UpdateGroupsFirstComic(),
|
|
79
76
|
CoverRemoveOrphansTask(),
|
|
80
77
|
SearchIndexUpdateTask(False),
|
|
81
78
|
SearchIndexMergeTask(optimize),
|
codex/librarian/librariand.py
CHANGED
|
@@ -14,7 +14,6 @@ from codex.librarian.importer.importerd import ComicImporterThread
|
|
|
14
14
|
from codex.librarian.importer.tasks import (
|
|
15
15
|
AdoptOrphanFoldersTask,
|
|
16
16
|
ImportTask,
|
|
17
|
-
UpdateGroupsFirstComic,
|
|
18
17
|
)
|
|
19
18
|
from codex.librarian.janitor.janitor import Janitor
|
|
20
19
|
from codex.librarian.janitor.janitord import JanitorThread
|
|
@@ -74,7 +73,6 @@ class LibrarianDaemon(Process, LoggerBaseMixin):
|
|
|
74
73
|
self.broadcast_queue = broadcast_queue
|
|
75
74
|
startup_tasks = (
|
|
76
75
|
AdoptOrphanFoldersTask(),
|
|
77
|
-
UpdateGroupsFirstComic(),
|
|
78
76
|
WatchdogSyncTask(),
|
|
79
77
|
SearchIndexRebuildIfDBChangedTask(),
|
|
80
78
|
)
|
|
@@ -10,9 +10,9 @@ class NotifierTask:
|
|
|
10
10
|
"""Handle with the Notifier."""
|
|
11
11
|
|
|
12
12
|
text: str
|
|
13
|
-
group:
|
|
13
|
+
group: str
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
LIBRARY_CHANGED_TASK = NotifierTask("LIBRARY_CHANGED", ChannelGroups.ALL)
|
|
17
|
-
LIBRARIAN_STATUS_TASK = NotifierTask("LIBRARIAN_STATUS", ChannelGroups.ADMIN)
|
|
18
|
-
FAILED_IMPORTS_TASK = NotifierTask("FAILED_IMPORTS", ChannelGroups.ADMIN)
|
|
16
|
+
LIBRARY_CHANGED_TASK = NotifierTask("LIBRARY_CHANGED", ChannelGroups.ALL.name)
|
|
17
|
+
LIBRARIAN_STATUS_TASK = NotifierTask("LIBRARIAN_STATUS", ChannelGroups.ADMIN.name)
|
|
18
|
+
FAILED_IMPORTS_TASK = NotifierTask("FAILED_IMPORTS", ChannelGroups.ADMIN.name)
|
codex/middleware.py
CHANGED
|
@@ -22,8 +22,7 @@ class TimezoneMiddleware:
|
|
|
22
22
|
|
|
23
23
|
def __call__(self, request):
|
|
24
24
|
"""Fix timeszone from the django session."""
|
|
25
|
-
tzname
|
|
26
|
-
if tzname:
|
|
25
|
+
if tzname := request.session.get("django_timezone"):
|
|
27
26
|
timezone.activate(tzname)
|
|
28
27
|
else:
|
|
29
28
|
timezone.deactivate()
|
|
@@ -71,33 +71,11 @@ class Migration(migrations.Migration):
|
|
|
71
71
|
name="sort_name",
|
|
72
72
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
73
73
|
),
|
|
74
|
-
migrations.AddField(
|
|
75
|
-
model_name="folder",
|
|
76
|
-
name="first_comic",
|
|
77
|
-
field=models.ForeignKey(
|
|
78
|
-
default=None,
|
|
79
|
-
null=True,
|
|
80
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
81
|
-
related_name="+",
|
|
82
|
-
to="codex.comic",
|
|
83
|
-
),
|
|
84
|
-
),
|
|
85
74
|
migrations.AddField(
|
|
86
75
|
model_name="folder",
|
|
87
76
|
name="sort_name",
|
|
88
77
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
89
78
|
),
|
|
90
|
-
migrations.AddField(
|
|
91
|
-
model_name="imprint",
|
|
92
|
-
name="first_comic",
|
|
93
|
-
field=models.ForeignKey(
|
|
94
|
-
default=None,
|
|
95
|
-
null=True,
|
|
96
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
97
|
-
related_name="+",
|
|
98
|
-
to="codex.comic",
|
|
99
|
-
),
|
|
100
|
-
),
|
|
101
79
|
migrations.AddField(
|
|
102
80
|
model_name="imprint",
|
|
103
81
|
name="sort_name",
|
|
@@ -108,65 +86,21 @@ class Migration(migrations.Migration):
|
|
|
108
86
|
name="covers_only",
|
|
109
87
|
field=models.BooleanField(db_index=True, default=False),
|
|
110
88
|
),
|
|
111
|
-
migrations.AddField(
|
|
112
|
-
model_name="publisher",
|
|
113
|
-
name="first_comic",
|
|
114
|
-
field=models.ForeignKey(
|
|
115
|
-
default=None,
|
|
116
|
-
null=True,
|
|
117
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
118
|
-
related_name="+",
|
|
119
|
-
to="codex.comic",
|
|
120
|
-
),
|
|
121
|
-
),
|
|
122
89
|
migrations.AddField(
|
|
123
90
|
model_name="publisher",
|
|
124
91
|
name="sort_name",
|
|
125
92
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
126
93
|
),
|
|
127
|
-
migrations.AddField(
|
|
128
|
-
model_name="series",
|
|
129
|
-
name="first_comic",
|
|
130
|
-
field=models.ForeignKey(
|
|
131
|
-
default=None,
|
|
132
|
-
null=True,
|
|
133
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
134
|
-
related_name="+",
|
|
135
|
-
to="codex.comic",
|
|
136
|
-
),
|
|
137
|
-
),
|
|
138
94
|
migrations.AddField(
|
|
139
95
|
model_name="series",
|
|
140
96
|
name="sort_name",
|
|
141
97
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
142
98
|
),
|
|
143
|
-
migrations.AddField(
|
|
144
|
-
model_name="storyarc",
|
|
145
|
-
name="first_comic",
|
|
146
|
-
field=models.ForeignKey(
|
|
147
|
-
default=None,
|
|
148
|
-
null=True,
|
|
149
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
150
|
-
related_name="+",
|
|
151
|
-
to="codex.comic",
|
|
152
|
-
),
|
|
153
|
-
),
|
|
154
99
|
migrations.AddField(
|
|
155
100
|
model_name="storyarc",
|
|
156
101
|
name="sort_name",
|
|
157
102
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
158
103
|
),
|
|
159
|
-
migrations.AddField(
|
|
160
|
-
model_name="volume",
|
|
161
|
-
name="first_comic",
|
|
162
|
-
field=models.ForeignKey(
|
|
163
|
-
default=None,
|
|
164
|
-
null=True,
|
|
165
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
166
|
-
related_name="+",
|
|
167
|
-
to="codex.comic",
|
|
168
|
-
),
|
|
169
|
-
),
|
|
170
104
|
migrations.AlterField(
|
|
171
105
|
model_name="adminflag",
|
|
172
106
|
name="key",
|
|
@@ -211,6 +145,7 @@ class Migration(migrations.Migration):
|
|
|
211
145
|
("ICD", "Covers Deleted"),
|
|
212
146
|
("ICL", "Covers Link"),
|
|
213
147
|
("IGU", "Group Update"),
|
|
148
|
+
("IAF", "Adopt Folders"),
|
|
214
149
|
("JTD", "Cleanup Fk"),
|
|
215
150
|
("JCU", "Codex Update"),
|
|
216
151
|
("JCR", "Codex Restart"),
|
codex/models/comic.py
CHANGED
codex/models/groups.py
CHANGED
|
@@ -25,9 +25,6 @@ class BrowserGroupModel(BaseModel):
|
|
|
25
25
|
custom_cover = ForeignKey(
|
|
26
26
|
CustomCover, on_delete=SET_DEFAULT, null=True, default=None
|
|
27
27
|
)
|
|
28
|
-
first_comic = ForeignKey(
|
|
29
|
-
"Comic", on_delete=SET_DEFAULT, null=True, default=None, related_name="+"
|
|
30
|
-
)
|
|
31
28
|
|
|
32
29
|
def set_sort_name(self):
|
|
33
30
|
"""Create sort_name for model."""
|
codex/serializers/admin.py
CHANGED
|
@@ -181,67 +181,68 @@ class AdminGroupSerializer(Serializer):
|
|
|
181
181
|
"""Group Counts."""
|
|
182
182
|
|
|
183
183
|
publishers_count = IntegerField(required=False, read_only=True)
|
|
184
|
-
imprints_count = IntegerField(required=False)
|
|
185
|
-
series_count = IntegerField(required=False)
|
|
186
|
-
volumes_count = IntegerField(required=False)
|
|
187
|
-
issues_count = IntegerField(required=False)
|
|
188
|
-
folders_count = IntegerField(required=False)
|
|
184
|
+
imprints_count = IntegerField(required=False, read_only=True)
|
|
185
|
+
series_count = IntegerField(required=False, read_only=True)
|
|
186
|
+
volumes_count = IntegerField(required=False, read_only=True)
|
|
187
|
+
issues_count = IntegerField(required=False, read_only=True)
|
|
188
|
+
folders_count = IntegerField(required=False, read_only=True)
|
|
189
|
+
story_arcs_count = IntegerField(required=False, read_only=True)
|
|
189
190
|
|
|
190
191
|
|
|
191
192
|
class AdminFileTypeSerializer(Serializer):
|
|
192
193
|
"""File Type Counts."""
|
|
193
194
|
|
|
194
|
-
pdf_count = IntegerField(required=False)
|
|
195
|
-
cbz_count = IntegerField(required=False)
|
|
196
|
-
cbr_count = IntegerField(required=False)
|
|
197
|
-
cbt_count = IntegerField(required=False)
|
|
198
|
-
unknown_count = IntegerField(required=False)
|
|
195
|
+
pdf_count = IntegerField(required=False, read_only=True)
|
|
196
|
+
cbz_count = IntegerField(required=False, read_only=True)
|
|
197
|
+
cbr_count = IntegerField(required=False, read_only=True)
|
|
198
|
+
cbt_count = IntegerField(required=False, read_only=True)
|
|
199
|
+
unknown_count = IntegerField(required=False, read_only=True)
|
|
199
200
|
|
|
200
201
|
|
|
201
202
|
class AdminComicMetadataSerializer(Serializer):
|
|
202
203
|
"""Metadata Counts."""
|
|
203
204
|
|
|
204
|
-
age_ratings_count = IntegerField(required=False)
|
|
205
|
-
characters_count = IntegerField(required=False)
|
|
206
|
-
contributors_count = IntegerField(required=False)
|
|
207
|
-
contributor_persons_count = IntegerField(required=False)
|
|
208
|
-
contributor_roles_count = IntegerField(required=False)
|
|
209
|
-
countries_count = IntegerField(required=False)
|
|
210
|
-
genres_count = IntegerField(required=False)
|
|
211
|
-
identifiers_count = IntegerField(required=False)
|
|
212
|
-
identifier_types_count = IntegerField(required=False)
|
|
213
|
-
languages_count = IntegerField(required=False)
|
|
214
|
-
locations_count = IntegerField(required=False)
|
|
215
|
-
original_formats_count = IntegerField(required=False)
|
|
216
|
-
series_groups_count = IntegerField(required=False)
|
|
217
|
-
scan_infos_count = IntegerField(required=False)
|
|
205
|
+
age_ratings_count = IntegerField(required=False, read_only=True)
|
|
206
|
+
characters_count = IntegerField(required=False, read_only=True)
|
|
207
|
+
contributors_count = IntegerField(required=False, read_only=True)
|
|
208
|
+
contributor_persons_count = IntegerField(required=False, read_only=True)
|
|
209
|
+
contributor_roles_count = IntegerField(required=False, read_only=True)
|
|
210
|
+
countries_count = IntegerField(required=False, read_only=True)
|
|
211
|
+
genres_count = IntegerField(required=False, read_only=True)
|
|
212
|
+
identifiers_count = IntegerField(required=False, read_only=True)
|
|
213
|
+
identifier_types_count = IntegerField(required=False, read_only=True)
|
|
214
|
+
languages_count = IntegerField(required=False, read_only=True)
|
|
215
|
+
locations_count = IntegerField(required=False, read_only=True)
|
|
216
|
+
original_formats_count = IntegerField(required=False, read_only=True)
|
|
217
|
+
series_groups_count = IntegerField(required=False, read_only=True)
|
|
218
|
+
scan_infos_count = IntegerField(required=False, read_only=True)
|
|
218
219
|
story_arcs_count = IntegerField(required=False)
|
|
219
|
-
story_arc_numbers_count = IntegerField(required=False)
|
|
220
|
-
tags_count = IntegerField(required=False)
|
|
221
|
-
taggers_count = IntegerField(required=False)
|
|
222
|
-
teams_count = IntegerField(required=False)
|
|
220
|
+
story_arc_numbers_count = IntegerField(required=False, read_only=True)
|
|
221
|
+
tags_count = IntegerField(required=False, read_only=True)
|
|
222
|
+
taggers_count = IntegerField(required=False, read_only=True)
|
|
223
|
+
teams_count = IntegerField(required=False, read_only=True)
|
|
223
224
|
|
|
224
225
|
|
|
225
226
|
class AdminConfigSerializer(Serializer):
|
|
226
227
|
"""Config Information."""
|
|
227
228
|
|
|
228
|
-
api_key = CharField(required=False)
|
|
229
|
-
groups_count = IntegerField(required=False)
|
|
230
|
-
libraries_count = IntegerField(required=False)
|
|
231
|
-
sessions_anon_count = IntegerField(required=False)
|
|
232
|
-
sessions_count = IntegerField(required=False)
|
|
233
|
-
users_count = IntegerField(required=False)
|
|
229
|
+
api_key = CharField(required=False, read_only=True)
|
|
230
|
+
groups_count = IntegerField(required=False, read_only=True)
|
|
231
|
+
libraries_count = IntegerField(required=False, read_only=True)
|
|
232
|
+
sessions_anon_count = IntegerField(required=False, read_only=True)
|
|
233
|
+
sessions_count = IntegerField(required=False, read_only=True)
|
|
234
|
+
users_count = IntegerField(required=False, read_only=True)
|
|
234
235
|
|
|
235
236
|
|
|
236
237
|
class AdminPlatformSerializer(Serializer):
|
|
237
238
|
"""Platform Information."""
|
|
238
239
|
|
|
239
|
-
docker = BooleanField()
|
|
240
|
-
machine = CharField()
|
|
241
|
-
system = CharField()
|
|
242
|
-
system_release = CharField()
|
|
243
|
-
python = CharField()
|
|
244
|
-
codex = CharField()
|
|
240
|
+
docker = BooleanField(read_only=True)
|
|
241
|
+
machine = CharField(read_only=True)
|
|
242
|
+
system = CharField(read_only=True)
|
|
243
|
+
system_release = CharField(read_only=True)
|
|
244
|
+
python = CharField(read_only=True)
|
|
245
|
+
codex = CharField(read_only=True)
|
|
245
246
|
|
|
246
247
|
|
|
247
248
|
class AdminStatsSerializer(Serializer):
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from types import MappingProxyType
|
|
4
4
|
|
|
5
|
+
from rest_framework.fields import SerializerMethodField
|
|
5
6
|
from rest_framework.serializers import (
|
|
6
7
|
BooleanField,
|
|
7
8
|
CharField,
|
|
@@ -10,10 +11,11 @@ from rest_framework.serializers import (
|
|
|
10
11
|
IntegerField,
|
|
11
12
|
Serializer,
|
|
12
13
|
)
|
|
14
|
+
from rest_framework.utils.serializer_helpers import ReturnList
|
|
13
15
|
|
|
14
|
-
from codex.serializers.browser.filters import
|
|
16
|
+
from codex.serializers.browser.filters import BrowserSettingsFilterSerializer
|
|
17
|
+
from codex.serializers.fields import (
|
|
15
18
|
BooleanListField,
|
|
16
|
-
BrowserSettingsFilterSerializer,
|
|
17
19
|
CharListField,
|
|
18
20
|
DecadeListField,
|
|
19
21
|
FloatListField,
|
|
@@ -56,11 +58,25 @@ _CHOICES_TYPE_SERIALIZER_MAP = MappingProxyType(
|
|
|
56
58
|
IntListField: BrowserChoicesIntPkSerializer,
|
|
57
59
|
}
|
|
58
60
|
)
|
|
59
|
-
|
|
60
|
-
_BSFS = BrowserSettingsFilterSerializer
|
|
61
|
-
CHOICES_SERIALIZER_CLASS_MAP = MappingProxyType(
|
|
61
|
+
_CHOICES_SERIALIZER_CLASS_MAP = MappingProxyType(
|
|
62
62
|
{
|
|
63
63
|
name: _CHOICES_TYPE_SERIALIZER_MAP[field.__class__]
|
|
64
|
-
for name, field in
|
|
64
|
+
for name, field in BrowserSettingsFilterSerializer().fields.items() # type: ignore
|
|
65
65
|
}
|
|
66
66
|
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class BrowserChoicesFilterSerializer(Serializer):
|
|
70
|
+
"""Dynamic Serializer response by field type."""
|
|
71
|
+
|
|
72
|
+
choices = SerializerMethodField(read_only=True)
|
|
73
|
+
|
|
74
|
+
def get_choices(self, obj) -> ReturnList:
|
|
75
|
+
"""Dynamic Serializer response by field type."""
|
|
76
|
+
key = obj.get("field_name", "")
|
|
77
|
+
choices = obj.get("choices", [])
|
|
78
|
+
serializer_class = _CHOICES_SERIALIZER_CLASS_MAP.get(
|
|
79
|
+
key, BrowserChoicesCharPkSerializer
|
|
80
|
+
)
|
|
81
|
+
serializer = serializer_class(choices, many=True)
|
|
82
|
+
return serializer.data # type: ignore
|