codex 1.6.14__py3-none-any.whl → 1.6.16__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/cron/crond.py +13 -10
- codex/librarian/importer/importerd.py +24 -19
- codex/librarian/importer/moved.py +176 -73
- codex/librarian/importer/query_fks.py +17 -11
- codex/librarian/telemeter/telemeter.py +6 -3
- codex/librarian/watchdog/dir_snapshot_diff.py +19 -17
- codex/search/backend.py +9 -2
- codex/settings/settings.py +1 -0
- codex/static_root/assets/{VCheckbox-Bf5gdxZe.7edc318a8f33.js → VCheckbox-B_KxeHW4.83cc6be08a2f.js} +1 -1
- codex/static_root/assets/VCheckbox-B_KxeHW4.83cc6be08a2f.js.br +0 -0
- codex/static_root/assets/VCheckbox-B_KxeHW4.83cc6be08a2f.js.gz +0 -0
- codex/static_root/assets/{VCheckbox-Bf5gdxZe.js → VCheckbox-B_KxeHW4.js} +1 -1
- codex/static_root/assets/VCheckbox-B_KxeHW4.js.br +0 -0
- codex/static_root/assets/VCheckbox-B_KxeHW4.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-8Kva6jyD.9e8989b09eeb.js → VCheckboxBtn-D_7rfm4C.f732e47b6674.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-D_7rfm4C.f732e47b6674.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-D_7rfm4C.f732e47b6674.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-8Kva6jyD.js → VCheckboxBtn-D_7rfm4C.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-D_7rfm4C.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-D_7rfm4C.js.gz +0 -0
- codex/static_root/assets/{VCombobox-C_LpolHU.26ce6fff76c1.js → VCombobox-EtQ72JMr.dc75b79417ff.js} +1 -1
- codex/static_root/assets/VCombobox-EtQ72JMr.dc75b79417ff.js.br +0 -0
- codex/static_root/assets/VCombobox-EtQ72JMr.dc75b79417ff.js.gz +0 -0
- codex/static_root/assets/{VCombobox-C_LpolHU.js → VCombobox-EtQ72JMr.js} +1 -1
- codex/static_root/assets/VCombobox-EtQ72JMr.js.br +0 -0
- codex/static_root/assets/VCombobox-EtQ72JMr.js.gz +0 -0
- codex/static_root/assets/VCombobox-bwEYrXCg.9f25a34994e2.css +1 -0
- codex/static_root/assets/VCombobox-bwEYrXCg.9f25a34994e2.css.br +0 -0
- codex/static_root/assets/VCombobox-bwEYrXCg.9f25a34994e2.css.gz +0 -0
- codex/static_root/assets/VCombobox-bwEYrXCg.css +1 -0
- codex/static_root/assets/VCombobox-bwEYrXCg.css.br +0 -0
- codex/static_root/assets/VCombobox-bwEYrXCg.css.gz +0 -0
- codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css +1 -0
- codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.br +0 -0
- codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.gz +0 -0
- codex/static_root/assets/VDialog-38np3TSA.css +1 -0
- codex/static_root/assets/VDialog-38np3TSA.css.br +0 -0
- codex/static_root/assets/VDialog-38np3TSA.css.gz +0 -0
- codex/static_root/assets/{VDialog-CHWtsyYh.7c566f4cb130.js → VDialog-DLAqK7mg.48b2d71bbff3.js} +1 -1
- codex/static_root/assets/VDialog-DLAqK7mg.48b2d71bbff3.js.br +0 -0
- codex/static_root/assets/VDialog-DLAqK7mg.48b2d71bbff3.js.gz +0 -0
- codex/static_root/assets/{VDialog-CHWtsyYh.js → VDialog-DLAqK7mg.js} +1 -1
- codex/static_root/assets/VDialog-DLAqK7mg.js.br +0 -0
- codex/static_root/assets/VDialog-DLAqK7mg.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-6G1AUajL.5b17872981df.css +1 -0
- codex/static_root/assets/VExpansionPanels-6G1AUajL.5b17872981df.css.br +0 -0
- codex/static_root/assets/VExpansionPanels-6G1AUajL.5b17872981df.css.gz +0 -0
- codex/static_root/assets/VExpansionPanels-6G1AUajL.css +1 -0
- codex/static_root/assets/VExpansionPanels-6G1AUajL.css.br +0 -0
- codex/static_root/assets/VExpansionPanels-6G1AUajL.css.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-BB_WowGg.464235562bbb.js → VExpansionPanels-CQ-32h2P.c9e5ed81edb6.js} +1 -1
- codex/static_root/assets/VExpansionPanels-CQ-32h2P.c9e5ed81edb6.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CQ-32h2P.c9e5ed81edb6.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-BB_WowGg.js → VExpansionPanels-CQ-32h2P.js} +1 -1
- codex/static_root/assets/VExpansionPanels-CQ-32h2P.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CQ-32h2P.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-B9rQQnvl.752f43b11884.js → VRadioGroup-B-Q8axWs.76c929c318fc.js} +1 -1
- codex/static_root/assets/VRadioGroup-B-Q8axWs.76c929c318fc.js.br +0 -0
- codex/static_root/assets/VRadioGroup-B-Q8axWs.76c929c318fc.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-B9rQQnvl.js → VRadioGroup-B-Q8axWs.js} +1 -1
- codex/static_root/assets/VRadioGroup-B-Q8axWs.js.br +0 -0
- codex/static_root/assets/VRadioGroup-B-Q8axWs.js.gz +0 -0
- codex/static_root/assets/VSelect-B1_LeX22.892619637f5a.js +1 -0
- codex/static_root/assets/VSelect-B1_LeX22.892619637f5a.js.br +0 -0
- codex/static_root/assets/VSelect-B1_LeX22.892619637f5a.js.gz +0 -0
- codex/static_root/assets/VSelect-B1_LeX22.js +1 -0
- codex/static_root/assets/VSelect-B1_LeX22.js.br +0 -0
- codex/static_root/assets/VSelect-B1_LeX22.js.gz +0 -0
- codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css +1 -0
- codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.br +0 -0
- codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.gz +0 -0
- codex/static_root/assets/VSelect-Ca2bIOso.css +1 -0
- codex/static_root/assets/VSelect-Ca2bIOso.css.br +0 -0
- codex/static_root/assets/VSelect-Ca2bIOso.css.gz +0 -0
- codex/static_root/assets/{VSelectionControl-DKw4TKuO.ab4dea45204e.js → VSelectionControl-B7a_kuaA.72b1a6e1feb8.js} +1 -1
- codex/static_root/assets/VSelectionControl-B7a_kuaA.72b1a6e1feb8.js.br +0 -0
- codex/static_root/assets/VSelectionControl-B7a_kuaA.72b1a6e1feb8.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-DKw4TKuO.js → VSelectionControl-B7a_kuaA.js} +1 -1
- codex/static_root/assets/VSelectionControl-B7a_kuaA.js.br +0 -0
- codex/static_root/assets/VSelectionControl-B7a_kuaA.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-BFq--28I.9687c77461fc.css → VSelectionControl-CiViEYoC.c77bb19a4a06.css} +1 -1
- codex/static_root/assets/VSelectionControl-CiViEYoC.c77bb19a4a06.css.br +0 -0
- codex/static_root/assets/VSelectionControl-CiViEYoC.c77bb19a4a06.css.gz +0 -0
- codex/static_root/assets/{VSelectionControl-BFq--28I.css → VSelectionControl-CiViEYoC.css} +1 -1
- codex/static_root/assets/VSelectionControl-CiViEYoC.css.br +0 -0
- codex/static_root/assets/VSelectionControl-CiViEYoC.css.gz +0 -0
- codex/static_root/assets/{VSlideGroup-B5C2lA7c.70fffff2f577.js → VSlideGroup-BRl45QHs.c4b739d1f83b.js} +1 -1
- codex/static_root/assets/VSlideGroup-BRl45QHs.c4b739d1f83b.js.br +0 -0
- codex/static_root/assets/VSlideGroup-BRl45QHs.c4b739d1f83b.js.gz +0 -0
- codex/static_root/assets/{VSlideGroup-B5C2lA7c.js → VSlideGroup-BRl45QHs.js} +1 -1
- codex/static_root/assets/VSlideGroup-BRl45QHs.js.br +0 -0
- codex/static_root/assets/VSlideGroup-BRl45QHs.js.gz +0 -0
- codex/static_root/assets/{VTable-Lfc0i15y.8bab1b7ae36e.js → VTable-DISTvhO_.bc6f64a341dc.js} +1 -1
- codex/static_root/assets/VTable-DISTvhO_.bc6f64a341dc.js.br +0 -0
- codex/static_root/assets/VTable-DISTvhO_.bc6f64a341dc.js.gz +0 -0
- codex/static_root/assets/{VTable-Lfc0i15y.js → VTable-DISTvhO_.js} +1 -1
- codex/static_root/assets/VTable-DISTvhO_.js.br +0 -0
- codex/static_root/assets/VTable-DISTvhO_.js.gz +0 -0
- codex/static_root/assets/VTable-Y5Sc3hJd.c36f0a6a30cf.css +1 -0
- codex/static_root/assets/VTable-Y5Sc3hJd.c36f0a6a30cf.css.br +0 -0
- codex/static_root/assets/VTable-Y5Sc3hJd.c36f0a6a30cf.css.gz +0 -0
- codex/static_root/assets/VTable-Y5Sc3hJd.css +1 -0
- codex/static_root/assets/VTable-Y5Sc3hJd.css.br +0 -0
- codex/static_root/assets/VTable-Y5Sc3hJd.css.gz +0 -0
- codex/static_root/assets/{VTextField-B4VKy44x.76e6b5eba07d.js → VTextField-C0DUSXBX.fe57b718cbb1.js} +1 -1
- codex/static_root/assets/VTextField-C0DUSXBX.fe57b718cbb1.js.br +0 -0
- codex/static_root/assets/VTextField-C0DUSXBX.fe57b718cbb1.js.gz +0 -0
- codex/static_root/assets/{VTextField-B4VKy44x.js → VTextField-C0DUSXBX.js} +1 -1
- codex/static_root/assets/VTextField-C0DUSXBX.js.br +0 -0
- codex/static_root/assets/VTextField-C0DUSXBX.js.gz +0 -0
- codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css +1 -0
- codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.br +0 -0
- codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.gz +0 -0
- codex/static_root/assets/VTextField-Crc3gdNh.css +1 -0
- codex/static_root/assets/VTextField-Crc3gdNh.css.br +0 -0
- codex/static_root/assets/VTextField-Crc3gdNh.css.gz +0 -0
- codex/static_root/assets/{VWindowItem-KLjTqrqt.ce6d5d378d1e.js → VWindowItem-DXOy9qYi.8e1cd08df101.js} +1 -1
- codex/static_root/assets/VWindowItem-DXOy9qYi.8e1cd08df101.js.br +0 -0
- codex/static_root/assets/VWindowItem-DXOy9qYi.8e1cd08df101.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-KLjTqrqt.js → VWindowItem-DXOy9qYi.js} +1 -1
- codex/static_root/assets/VWindowItem-DXOy9qYi.js.br +0 -0
- codex/static_root/assets/VWindowItem-DXOy9qYi.js.gz +0 -0
- codex/static_root/assets/{admin-CWkrgUZ0.a441d70b810c.js → admin-DgLzn7q2.5d4dc6ca61f9.js} +1 -1
- codex/static_root/assets/admin-DgLzn7q2.5d4dc6ca61f9.js.br +0 -0
- codex/static_root/assets/admin-DgLzn7q2.5d4dc6ca61f9.js.gz +0 -0
- codex/static_root/assets/{admin-CWkrgUZ0.js → admin-DgLzn7q2.js} +1 -1
- codex/static_root/assets/admin-DgLzn7q2.js.br +0 -0
- codex/static_root/assets/admin-DgLzn7q2.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-COV3Ru1J.b0cd2b71000c.css +1 -0
- codex/static_root/assets/admin-drawer-panel-COV3Ru1J.b0cd2b71000c.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-COV3Ru1J.b0cd2b71000c.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-COV3Ru1J.css +1 -0
- codex/static_root/assets/admin-drawer-panel-COV3Ru1J.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-COV3Ru1J.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-CoRl2h5W.1101513b2b68.js +30 -0
- codex/static_root/assets/admin-drawer-panel-CoRl2h5W.1101513b2b68.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-CoRl2h5W.1101513b2b68.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-CoRl2h5W.js +30 -0
- codex/static_root/assets/admin-drawer-panel-CoRl2h5W.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-CoRl2h5W.js.gz +0 -0
- codex/static_root/assets/browser-BSwNpa5t.35d2f6a3dea4.js +1 -0
- codex/static_root/assets/browser-BSwNpa5t.35d2f6a3dea4.js.br +0 -0
- codex/static_root/assets/browser-BSwNpa5t.35d2f6a3dea4.js.gz +0 -0
- codex/static_root/assets/browser-BSwNpa5t.js +1 -0
- codex/static_root/assets/browser-BSwNpa5t.js.br +0 -0
- codex/static_root/assets/browser-BSwNpa5t.js.gz +0 -0
- codex/static_root/assets/{browser-BMYALshd.26be271bbdb1.css → browser-DWoo5pGT.29bee2bbd49b.css} +1 -1
- codex/static_root/assets/browser-DWoo5pGT.29bee2bbd49b.css.br +0 -0
- codex/static_root/assets/browser-DWoo5pGT.29bee2bbd49b.css.gz +0 -0
- codex/static_root/assets/{browser-BMYALshd.css → browser-DWoo5pGT.css} +1 -1
- codex/static_root/assets/browser-DWoo5pGT.css.br +0 -0
- codex/static_root/assets/browser-DWoo5pGT.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-Bosys_6j.036c0eea895d.css +1 -0
- codex/static_root/assets/change-password-dialog-Bosys_6j.036c0eea895d.css.br +0 -0
- codex/static_root/assets/change-password-dialog-Bosys_6j.036c0eea895d.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-Bosys_6j.css +1 -0
- codex/static_root/assets/change-password-dialog-Bosys_6j.css.br +0 -0
- codex/static_root/assets/change-password-dialog-Bosys_6j.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-ColNjAlK.4a425e3a6c8d.js +1 -0
- codex/static_root/assets/change-password-dialog-ColNjAlK.4a425e3a6c8d.js.br +0 -0
- codex/static_root/assets/change-password-dialog-ColNjAlK.4a425e3a6c8d.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-ColNjAlK.js +1 -0
- codex/static_root/assets/change-password-dialog-ColNjAlK.js.br +0 -0
- codex/static_root/assets/change-password-dialog-ColNjAlK.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-CxwshFZG.271c62f45f93.js → confirm-dialog-DPtJ2Fu2.83d1c027b3bc.js} +1 -1
- codex/static_root/assets/confirm-dialog-DPtJ2Fu2.83d1c027b3bc.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DPtJ2Fu2.83d1c027b3bc.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-CxwshFZG.js → confirm-dialog-DPtJ2Fu2.js} +1 -1
- codex/static_root/assets/confirm-dialog-DPtJ2Fu2.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DPtJ2Fu2.js.gz +0 -0
- codex/static_root/assets/{datetime-column-BlrfINye.91b57f3abe97.js → datetime-column-DnOqpZLy.7b8519c1da50.js} +1 -1
- codex/static_root/assets/datetime-column-DnOqpZLy.7b8519c1da50.js.br +0 -0
- codex/static_root/assets/datetime-column-DnOqpZLy.7b8519c1da50.js.gz +0 -0
- codex/static_root/assets/{datetime-column-BlrfINye.js → datetime-column-DnOqpZLy.js} +1 -1
- codex/static_root/assets/datetime-column-DnOqpZLy.js.br +0 -0
- codex/static_root/assets/datetime-column-DnOqpZLy.js.gz +0 -0
- codex/static_root/assets/{filter-Ds3JJmu2.fd08b28c7278.js → filter-BoSLQk91.3ea0dcc99c0e.js} +1 -1
- codex/static_root/assets/filter-BoSLQk91.3ea0dcc99c0e.js.br +0 -0
- codex/static_root/assets/filter-BoSLQk91.3ea0dcc99c0e.js.gz +0 -0
- codex/static_root/assets/{filter-Ds3JJmu2.js → filter-BoSLQk91.js} +1 -1
- codex/static_root/assets/filter-BoSLQk91.js.br +0 -0
- codex/static_root/assets/filter-BoSLQk91.js.gz +0 -0
- codex/static_root/assets/{flag-tab-BQjZsiTg.082622270a94.js → flag-tab-DNh2mpPr.b1645ec1e536.js} +1 -1
- codex/static_root/assets/flag-tab-DNh2mpPr.b1645ec1e536.js.br +0 -0
- codex/static_root/assets/flag-tab-DNh2mpPr.b1645ec1e536.js.gz +0 -0
- codex/static_root/assets/{flag-tab-BQjZsiTg.js → flag-tab-DNh2mpPr.js} +1 -1
- codex/static_root/assets/flag-tab-DNh2mpPr.js.br +0 -0
- codex/static_root/assets/flag-tab-DNh2mpPr.js.gz +0 -0
- codex/static_root/assets/{group-tab-2t5x5GYZ.c75187a4632a.js → group-tab-B6QT9bUe.0458f4530691.js} +1 -1
- codex/static_root/assets/group-tab-B6QT9bUe.0458f4530691.js.br +0 -0
- codex/static_root/assets/group-tab-B6QT9bUe.0458f4530691.js.gz +0 -0
- codex/static_root/assets/{group-tab-2t5x5GYZ.js → group-tab-B6QT9bUe.js} +1 -1
- codex/static_root/assets/group-tab-B6QT9bUe.js.br +0 -0
- codex/static_root/assets/group-tab-B6QT9bUe.js.gz +0 -0
- codex/static_root/assets/{http-error-RDzOjrxR.960c6c4b0146.js → http-error-DUb0F4qg.4567436c85f0.js} +1 -1
- codex/static_root/assets/http-error-DUb0F4qg.4567436c85f0.js.br +0 -0
- codex/static_root/assets/http-error-DUb0F4qg.4567436c85f0.js.gz +0 -0
- codex/static_root/assets/{http-error-RDzOjrxR.js → http-error-DUb0F4qg.js} +1 -1
- codex/static_root/assets/http-error-DUb0F4qg.js.br +0 -0
- codex/static_root/assets/http-error-DUb0F4qg.js.gz +0 -0
- codex/static_root/assets/library-tab-C_6VqUnE.513fe55019e7.css +1 -0
- codex/static_root/assets/library-tab-C_6VqUnE.513fe55019e7.css.br +0 -0
- codex/static_root/assets/library-tab-C_6VqUnE.513fe55019e7.css.gz +0 -0
- codex/static_root/assets/library-tab-C_6VqUnE.css +1 -0
- codex/static_root/assets/library-tab-C_6VqUnE.css.br +0 -0
- codex/static_root/assets/library-tab-C_6VqUnE.css.gz +0 -0
- codex/static_root/assets/library-tab-DPUHpOfq.3e1b6ec73274.js +1 -0
- codex/static_root/assets/library-tab-DPUHpOfq.3e1b6ec73274.js.br +0 -0
- codex/static_root/assets/library-tab-DPUHpOfq.3e1b6ec73274.js.gz +0 -0
- codex/static_root/assets/library-tab-DPUHpOfq.js +1 -0
- codex/static_root/assets/library-tab-DPUHpOfq.js.br +0 -0
- codex/static_root/assets/library-tab-DPUHpOfq.js.gz +0 -0
- codex/static_root/assets/{main-Ztp855PW.css → main-BZ73p_WW.css} +1 -1
- codex/static_root/assets/main-BZ73p_WW.css.br +0 -0
- codex/static_root/assets/{main-Ztp855PW.css.gz → main-BZ73p_WW.css.gz} +0 -0
- codex/static_root/assets/{main-Ztp855PW.d46d718fac45.css → main-BZ73p_WW.d529e8b3f52a.css} +1 -1
- codex/static_root/assets/main-BZ73p_WW.d529e8b3f52a.css.br +0 -0
- codex/static_root/assets/{main-Ztp855PW.d46d718fac45.css.gz → main-BZ73p_WW.d529e8b3f52a.css.gz} +0 -0
- codex/static_root/assets/main-DyDcAKfE.59ea08f0fb1b.js +6 -0
- codex/static_root/assets/main-DyDcAKfE.59ea08f0fb1b.js.br +0 -0
- codex/static_root/assets/main-DyDcAKfE.59ea08f0fb1b.js.gz +0 -0
- codex/static_root/assets/main-DyDcAKfE.js +6 -0
- codex/static_root/assets/main-DyDcAKfE.js.br +0 -0
- codex/static_root/assets/main-DyDcAKfE.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-C9SzPo7k.947a0cd8dcc3.js +1 -0
- codex/static_root/assets/pagination-toolbar-C9SzPo7k.947a0cd8dcc3.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-C9SzPo7k.947a0cd8dcc3.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-C9SzPo7k.js +1 -0
- codex/static_root/assets/pagination-toolbar-C9SzPo7k.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-C9SzPo7k.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-fV7Lb1Xa.50b90ccb5d08.css → pagination-toolbar-D6v3_jVe.4f0e62bbb1e5.css} +1 -1
- codex/static_root/assets/pagination-toolbar-D6v3_jVe.4f0e62bbb1e5.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-D6v3_jVe.4f0e62bbb1e5.css.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-fV7Lb1Xa.css → pagination-toolbar-D6v3_jVe.css} +1 -1
- codex/static_root/assets/pagination-toolbar-D6v3_jVe.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-D6v3_jVe.css.gz +0 -0
- codex/static_root/assets/pdf-doc-BeSm40lQ.29f26de72c2d.js +305 -0
- codex/static_root/assets/pdf-doc-BeSm40lQ.29f26de72c2d.js.br +0 -0
- codex/static_root/assets/pdf-doc-BeSm40lQ.29f26de72c2d.js.gz +0 -0
- codex/static_root/assets/pdf-doc-BeSm40lQ.js +305 -0
- codex/static_root/assets/pdf-doc-BeSm40lQ.js.br +0 -0
- codex/static_root/assets/pdf-doc-BeSm40lQ.js.gz +0 -0
- codex/static_root/assets/{reader-Do0jgF5k.aae2010130b4.css → reader-BORfYc0l.css} +1 -1
- codex/static_root/assets/reader-BORfYc0l.css.br +0 -0
- codex/static_root/assets/{reader-Do0jgF5k.aae2010130b4.css.gz → reader-BORfYc0l.css.gz} +0 -0
- codex/static_root/assets/{reader-Do0jgF5k.css → reader-BORfYc0l.e66ce0ded0b6.css} +1 -1
- codex/static_root/assets/reader-BORfYc0l.e66ce0ded0b6.css.br +0 -0
- codex/static_root/assets/{reader-Do0jgF5k.css.gz → reader-BORfYc0l.e66ce0ded0b6.css.gz} +0 -0
- codex/static_root/assets/{reader-Dqp40SW1.js → reader-BuiJ4J_R.b8f859a3106d.js} +2 -2
- codex/static_root/assets/reader-BuiJ4J_R.b8f859a3106d.js.br +0 -0
- codex/static_root/assets/reader-BuiJ4J_R.b8f859a3106d.js.gz +0 -0
- codex/static_root/assets/{reader-Dqp40SW1.278f67931ddc.js → reader-BuiJ4J_R.js} +2 -2
- codex/static_root/assets/reader-BuiJ4J_R.js.br +0 -0
- codex/static_root/assets/reader-BuiJ4J_R.js.gz +0 -0
- codex/static_root/assets/{relation-chips-lu2nFvjg.e7ab76db0936.js → relation-chips-BWrtvPrs.d304eb1bd4b9.js} +1 -1
- codex/static_root/assets/relation-chips-BWrtvPrs.d304eb1bd4b9.js.br +0 -0
- codex/static_root/assets/relation-chips-BWrtvPrs.d304eb1bd4b9.js.gz +0 -0
- codex/static_root/assets/{relation-chips-lu2nFvjg.js → relation-chips-BWrtvPrs.js} +1 -1
- codex/static_root/assets/relation-chips-BWrtvPrs.js.br +0 -0
- codex/static_root/assets/relation-chips-BWrtvPrs.js.gz +0 -0
- codex/static_root/assets/settings-drawer-BUeCNt4i.96bf8b11d9c0.js +2 -0
- codex/static_root/assets/settings-drawer-BUeCNt4i.96bf8b11d9c0.js.br +0 -0
- codex/static_root/assets/settings-drawer-BUeCNt4i.96bf8b11d9c0.js.gz +0 -0
- codex/static_root/assets/settings-drawer-BUeCNt4i.js +2 -0
- codex/static_root/assets/settings-drawer-BUeCNt4i.js.br +0 -0
- codex/static_root/assets/settings-drawer-BUeCNt4i.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css +1 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css.br +0 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css.gz +0 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.css +1 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.css.br +0 -0
- codex/static_root/assets/settings-drawer-DKncO_vX.css.gz +0 -0
- codex/static_root/assets/{stats-tab-C1O6FCIj.02cbc306f36f.js → stats-tab-D3VbyUqi.dd958058cc1e.js} +1 -1
- codex/static_root/assets/stats-tab-D3VbyUqi.dd958058cc1e.js.br +0 -0
- codex/static_root/assets/stats-tab-D3VbyUqi.dd958058cc1e.js.gz +0 -0
- codex/static_root/assets/{stats-tab-C1O6FCIj.js → stats-tab-D3VbyUqi.js} +1 -1
- codex/static_root/assets/stats-tab-D3VbyUqi.js.br +0 -0
- codex/static_root/assets/stats-tab-D3VbyUqi.js.gz +0 -0
- codex/static_root/assets/{task-tab-CqeHSVhx.4167eaffddd4.js → task-tab-Bosh0alC.852a8529f506.js} +1 -1
- codex/static_root/assets/task-tab-Bosh0alC.852a8529f506.js.br +0 -0
- codex/static_root/assets/task-tab-Bosh0alC.852a8529f506.js.gz +0 -0
- codex/static_root/assets/{task-tab-CqeHSVhx.js → task-tab-Bosh0alC.js} +1 -1
- codex/static_root/assets/task-tab-Bosh0alC.js.br +0 -0
- codex/static_root/assets/task-tab-Bosh0alC.js.gz +0 -0
- codex/static_root/assets/{unauthorized-D87B0TXf.85c5665072a2.css → unauthorized-CQL7W5pA.75124be66863.css} +1 -1
- codex/static_root/assets/unauthorized-CQL7W5pA.75124be66863.css.br +0 -0
- codex/static_root/assets/unauthorized-CQL7W5pA.75124be66863.css.gz +0 -0
- codex/static_root/assets/{unauthorized-D87B0TXf.css → unauthorized-CQL7W5pA.css} +1 -1
- codex/static_root/assets/unauthorized-CQL7W5pA.css.br +0 -0
- codex/static_root/assets/unauthorized-CQL7W5pA.css.gz +0 -0
- codex/static_root/assets/{unauthorized-BdPK_Sdi.785f127a927a.js → unauthorized-Dnq8D35W.4f560e203c18.js} +1 -1
- codex/static_root/assets/unauthorized-Dnq8D35W.4f560e203c18.js.br +0 -0
- codex/static_root/assets/unauthorized-Dnq8D35W.4f560e203c18.js.gz +0 -0
- codex/static_root/assets/{unauthorized-BdPK_Sdi.js → unauthorized-Dnq8D35W.js} +1 -1
- codex/static_root/assets/unauthorized-Dnq8D35W.js.br +0 -0
- codex/static_root/assets/unauthorized-Dnq8D35W.js.gz +0 -0
- codex/static_root/assets/{user-tab-Bp1GOJbE.f7935f7db1fa.js → user-tab-BGlLLXhI.8771bc00ef3a.js} +1 -1
- codex/static_root/assets/user-tab-BGlLLXhI.8771bc00ef3a.js.br +0 -0
- codex/static_root/assets/user-tab-BGlLLXhI.8771bc00ef3a.js.gz +0 -0
- codex/static_root/assets/{user-tab-Bp1GOJbE.js → user-tab-BGlLLXhI.js} +1 -1
- codex/static_root/assets/user-tab-BGlLLXhI.js.br +0 -0
- codex/static_root/assets/user-tab-BGlLLXhI.js.gz +0 -0
- codex/static_root/manifest.aa902634f4fd.json +611 -0
- codex/static_root/manifest.aa902634f4fd.json.br +0 -0
- codex/static_root/manifest.aa902634f4fd.json.gz +0 -0
- codex/static_root/manifest.json +241 -241
- 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/browser/filters/annotations.py +5 -4
- codex/views/browser/validate.py +4 -7
- {codex-1.6.14.dist-info → codex-1.6.16.dist-info}/METADATA +2 -2
- {codex-1.6.14.dist-info → codex-1.6.16.dist-info}/RECORD +316 -316
- codex/static_root/assets/VCheckbox-Bf5gdxZe.7edc318a8f33.js.br +0 -0
- codex/static_root/assets/VCheckbox-Bf5gdxZe.7edc318a8f33.js.gz +0 -0
- codex/static_root/assets/VCheckbox-Bf5gdxZe.js.br +0 -0
- codex/static_root/assets/VCheckbox-Bf5gdxZe.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-8Kva6jyD.9e8989b09eeb.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-8Kva6jyD.9e8989b09eeb.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-8Kva6jyD.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-8Kva6jyD.js.gz +0 -0
- codex/static_root/assets/VCombobox-BksEr4D_.73429bb75f42.css +0 -1
- codex/static_root/assets/VCombobox-BksEr4D_.73429bb75f42.css.br +0 -0
- codex/static_root/assets/VCombobox-BksEr4D_.73429bb75f42.css.gz +0 -0
- codex/static_root/assets/VCombobox-BksEr4D_.css +0 -1
- codex/static_root/assets/VCombobox-BksEr4D_.css.br +0 -0
- codex/static_root/assets/VCombobox-BksEr4D_.css.gz +0 -0
- codex/static_root/assets/VCombobox-C_LpolHU.26ce6fff76c1.js.br +0 -0
- codex/static_root/assets/VCombobox-C_LpolHU.26ce6fff76c1.js.gz +0 -0
- codex/static_root/assets/VCombobox-C_LpolHU.js.br +0 -0
- codex/static_root/assets/VCombobox-C_LpolHU.js.gz +0 -0
- codex/static_root/assets/VDialog-CHWtsyYh.7c566f4cb130.js.br +0 -0
- codex/static_root/assets/VDialog-CHWtsyYh.7c566f4cb130.js.gz +0 -0
- codex/static_root/assets/VDialog-CHWtsyYh.js.br +0 -0
- codex/static_root/assets/VDialog-CHWtsyYh.js.gz +0 -0
- codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css +0 -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-lQ13FnRR.css +0 -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-BB_WowGg.464235562bbb.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BB_WowGg.464235562bbb.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-BB_WowGg.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BB_WowGg.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DsEXVcCv.20b475255e66.css +0 -1
- codex/static_root/assets/VExpansionPanels-DsEXVcCv.20b475255e66.css.br +0 -0
- codex/static_root/assets/VExpansionPanels-DsEXVcCv.20b475255e66.css.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DsEXVcCv.css +0 -1
- codex/static_root/assets/VExpansionPanels-DsEXVcCv.css.br +0 -0
- codex/static_root/assets/VExpansionPanels-DsEXVcCv.css.gz +0 -0
- codex/static_root/assets/VRadioGroup-B9rQQnvl.752f43b11884.js.br +0 -0
- codex/static_root/assets/VRadioGroup-B9rQQnvl.752f43b11884.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-B9rQQnvl.js.br +0 -0
- codex/static_root/assets/VRadioGroup-B9rQQnvl.js.gz +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css +0 -1
- codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css.br +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css.gz +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.css +0 -1
- codex/static_root/assets/VSelect-ARDhJiQK.css.br +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.css.gz +0 -0
- codex/static_root/assets/VSelect-Z04T1ZKO.4747404989f3.js +0 -1
- codex/static_root/assets/VSelect-Z04T1ZKO.4747404989f3.js.br +0 -0
- codex/static_root/assets/VSelect-Z04T1ZKO.4747404989f3.js.gz +0 -0
- codex/static_root/assets/VSelect-Z04T1ZKO.js +0 -1
- codex/static_root/assets/VSelect-Z04T1ZKO.js.br +0 -0
- codex/static_root/assets/VSelect-Z04T1ZKO.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-BFq--28I.9687c77461fc.css.br +0 -0
- codex/static_root/assets/VSelectionControl-BFq--28I.9687c77461fc.css.gz +0 -0
- codex/static_root/assets/VSelectionControl-BFq--28I.css.br +0 -0
- codex/static_root/assets/VSelectionControl-BFq--28I.css.gz +0 -0
- codex/static_root/assets/VSelectionControl-DKw4TKuO.ab4dea45204e.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DKw4TKuO.ab4dea45204e.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-DKw4TKuO.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DKw4TKuO.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-B5C2lA7c.70fffff2f577.js.br +0 -0
- codex/static_root/assets/VSlideGroup-B5C2lA7c.70fffff2f577.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-B5C2lA7c.js.br +0 -0
- codex/static_root/assets/VSlideGroup-B5C2lA7c.js.gz +0 -0
- codex/static_root/assets/VTable-DflzroDq.160504d82195.css +0 -1
- codex/static_root/assets/VTable-DflzroDq.160504d82195.css.br +0 -0
- codex/static_root/assets/VTable-DflzroDq.160504d82195.css.gz +0 -0
- codex/static_root/assets/VTable-DflzroDq.css +0 -1
- codex/static_root/assets/VTable-DflzroDq.css.br +0 -0
- codex/static_root/assets/VTable-DflzroDq.css.gz +0 -0
- codex/static_root/assets/VTable-Lfc0i15y.8bab1b7ae36e.js.br +0 -0
- codex/static_root/assets/VTable-Lfc0i15y.8bab1b7ae36e.js.gz +0 -0
- codex/static_root/assets/VTable-Lfc0i15y.js.br +0 -0
- codex/static_root/assets/VTable-Lfc0i15y.js.gz +0 -0
- codex/static_root/assets/VTextField-B4VKy44x.76e6b5eba07d.js.br +0 -0
- codex/static_root/assets/VTextField-B4VKy44x.76e6b5eba07d.js.gz +0 -0
- codex/static_root/assets/VTextField-B4VKy44x.js.br +0 -0
- codex/static_root/assets/VTextField-B4VKy44x.js.gz +0 -0
- codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css +0 -1
- codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.br +0 -0
- codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.gz +0 -0
- codex/static_root/assets/VTextField-BssVoDhB.css +0 -1
- codex/static_root/assets/VTextField-BssVoDhB.css.br +0 -0
- codex/static_root/assets/VTextField-BssVoDhB.css.gz +0 -0
- codex/static_root/assets/VWindowItem-KLjTqrqt.ce6d5d378d1e.js.br +0 -0
- codex/static_root/assets/VWindowItem-KLjTqrqt.ce6d5d378d1e.js.gz +0 -0
- codex/static_root/assets/VWindowItem-KLjTqrqt.js.br +0 -0
- codex/static_root/assets/VWindowItem-KLjTqrqt.js.gz +0 -0
- codex/static_root/assets/admin-CWkrgUZ0.a441d70b810c.js.br +0 -0
- codex/static_root/assets/admin-CWkrgUZ0.a441d70b810c.js.gz +0 -0
- codex/static_root/assets/admin-CWkrgUZ0.js.br +0 -0
- codex/static_root/assets/admin-CWkrgUZ0.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-DOrhl9Nb.3a7af8ec4462.css +0 -1
- codex/static_root/assets/admin-drawer-panel-DOrhl9Nb.3a7af8ec4462.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-DOrhl9Nb.3a7af8ec4462.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-DOrhl9Nb.css +0 -1
- codex/static_root/assets/admin-drawer-panel-DOrhl9Nb.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-DOrhl9Nb.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-THbQH8zq.01c7471d731a.js +0 -30
- codex/static_root/assets/admin-drawer-panel-THbQH8zq.01c7471d731a.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-THbQH8zq.01c7471d731a.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-THbQH8zq.js +0 -30
- codex/static_root/assets/admin-drawer-panel-THbQH8zq.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-THbQH8zq.js.gz +0 -0
- codex/static_root/assets/browser-BMYALshd.26be271bbdb1.css.br +0 -0
- codex/static_root/assets/browser-BMYALshd.26be271bbdb1.css.gz +0 -0
- codex/static_root/assets/browser-BMYALshd.css.br +0 -0
- codex/static_root/assets/browser-BMYALshd.css.gz +0 -0
- codex/static_root/assets/browser-BRvf19XG.8be4fcbab4f0.js +0 -1
- codex/static_root/assets/browser-BRvf19XG.8be4fcbab4f0.js.br +0 -0
- codex/static_root/assets/browser-BRvf19XG.8be4fcbab4f0.js.gz +0 -0
- codex/static_root/assets/browser-BRvf19XG.js +0 -1
- codex/static_root/assets/browser-BRvf19XG.js.br +0 -0
- codex/static_root/assets/browser-BRvf19XG.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +0 -1
- 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 +0 -1
- 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-DmP85-rP.999791e58d4a.js +0 -1
- codex/static_root/assets/change-password-dialog-DmP85-rP.999791e58d4a.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DmP85-rP.999791e58d4a.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DmP85-rP.js +0 -1
- codex/static_root/assets/change-password-dialog-DmP85-rP.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DmP85-rP.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-CxwshFZG.271c62f45f93.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CxwshFZG.271c62f45f93.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-CxwshFZG.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CxwshFZG.js.gz +0 -0
- codex/static_root/assets/datetime-column-BlrfINye.91b57f3abe97.js.br +0 -0
- codex/static_root/assets/datetime-column-BlrfINye.91b57f3abe97.js.gz +0 -0
- codex/static_root/assets/datetime-column-BlrfINye.js.br +0 -0
- codex/static_root/assets/datetime-column-BlrfINye.js.gz +0 -0
- codex/static_root/assets/filter-Ds3JJmu2.fd08b28c7278.js.br +0 -0
- codex/static_root/assets/filter-Ds3JJmu2.fd08b28c7278.js.gz +0 -0
- codex/static_root/assets/filter-Ds3JJmu2.js.br +0 -0
- codex/static_root/assets/filter-Ds3JJmu2.js.gz +0 -0
- codex/static_root/assets/flag-tab-BQjZsiTg.082622270a94.js.br +0 -0
- codex/static_root/assets/flag-tab-BQjZsiTg.082622270a94.js.gz +0 -0
- codex/static_root/assets/flag-tab-BQjZsiTg.js.br +0 -0
- codex/static_root/assets/flag-tab-BQjZsiTg.js.gz +0 -0
- codex/static_root/assets/group-tab-2t5x5GYZ.c75187a4632a.js.br +0 -0
- codex/static_root/assets/group-tab-2t5x5GYZ.c75187a4632a.js.gz +0 -0
- codex/static_root/assets/group-tab-2t5x5GYZ.js.br +0 -0
- codex/static_root/assets/group-tab-2t5x5GYZ.js.gz +0 -0
- codex/static_root/assets/http-error-RDzOjrxR.960c6c4b0146.js.br +0 -0
- codex/static_root/assets/http-error-RDzOjrxR.960c6c4b0146.js.gz +0 -0
- codex/static_root/assets/http-error-RDzOjrxR.js.br +0 -0
- codex/static_root/assets/http-error-RDzOjrxR.js.gz +0 -0
- codex/static_root/assets/library-tab-DV2jzlXz.be7b5857d1b7.js +0 -1
- codex/static_root/assets/library-tab-DV2jzlXz.be7b5857d1b7.js.br +0 -0
- codex/static_root/assets/library-tab-DV2jzlXz.be7b5857d1b7.js.gz +0 -0
- codex/static_root/assets/library-tab-DV2jzlXz.js +0 -1
- codex/static_root/assets/library-tab-DV2jzlXz.js.br +0 -0
- codex/static_root/assets/library-tab-DV2jzlXz.js.gz +0 -0
- codex/static_root/assets/library-tab-DzRBc0IE.a963111e1349.css +0 -1
- codex/static_root/assets/library-tab-DzRBc0IE.a963111e1349.css.br +0 -3
- codex/static_root/assets/library-tab-DzRBc0IE.a963111e1349.css.gz +0 -0
- codex/static_root/assets/library-tab-DzRBc0IE.css +0 -1
- codex/static_root/assets/library-tab-DzRBc0IE.css.br +0 -3
- codex/static_root/assets/library-tab-DzRBc0IE.css.gz +0 -0
- codex/static_root/assets/main-Dch6DDCJ.bf70fffbe064.js +0 -6
- codex/static_root/assets/main-Dch6DDCJ.bf70fffbe064.js.br +0 -0
- codex/static_root/assets/main-Dch6DDCJ.bf70fffbe064.js.gz +0 -0
- codex/static_root/assets/main-Dch6DDCJ.js +0 -6
- codex/static_root/assets/main-Dch6DDCJ.js.br +0 -0
- codex/static_root/assets/main-Dch6DDCJ.js.gz +0 -0
- codex/static_root/assets/main-Ztp855PW.css.br +0 -0
- codex/static_root/assets/main-Ztp855PW.d46d718fac45.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DXg1CvH6.d255272f3d97.js +0 -1
- codex/static_root/assets/pagination-toolbar-DXg1CvH6.d255272f3d97.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DXg1CvH6.d255272f3d97.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DXg1CvH6.js +0 -1
- codex/static_root/assets/pagination-toolbar-DXg1CvH6.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DXg1CvH6.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-fV7Lb1Xa.50b90ccb5d08.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-fV7Lb1Xa.50b90ccb5d08.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-fV7Lb1Xa.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-fV7Lb1Xa.css.gz +0 -0
- codex/static_root/assets/pdf-doc-CVviRuB6.0c6b12289d5f.js +0 -305
- codex/static_root/assets/pdf-doc-CVviRuB6.0c6b12289d5f.js.br +0 -0
- codex/static_root/assets/pdf-doc-CVviRuB6.0c6b12289d5f.js.gz +0 -0
- codex/static_root/assets/pdf-doc-CVviRuB6.js +0 -305
- codex/static_root/assets/pdf-doc-CVviRuB6.js.br +0 -0
- codex/static_root/assets/pdf-doc-CVviRuB6.js.gz +0 -0
- codex/static_root/assets/reader-Do0jgF5k.aae2010130b4.css.br +0 -0
- codex/static_root/assets/reader-Do0jgF5k.css.br +0 -0
- codex/static_root/assets/reader-Dqp40SW1.278f67931ddc.js.br +0 -0
- codex/static_root/assets/reader-Dqp40SW1.278f67931ddc.js.gz +0 -0
- codex/static_root/assets/reader-Dqp40SW1.js.br +0 -0
- codex/static_root/assets/reader-Dqp40SW1.js.gz +0 -0
- codex/static_root/assets/relation-chips-lu2nFvjg.e7ab76db0936.js.br +0 -0
- codex/static_root/assets/relation-chips-lu2nFvjg.e7ab76db0936.js.gz +0 -0
- codex/static_root/assets/relation-chips-lu2nFvjg.js.br +0 -0
- codex/static_root/assets/relation-chips-lu2nFvjg.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CQ_uhEuE.c6d1a2453b8f.js +0 -2
- codex/static_root/assets/settings-drawer-CQ_uhEuE.c6d1a2453b8f.js.br +0 -0
- codex/static_root/assets/settings-drawer-CQ_uhEuE.c6d1a2453b8f.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CQ_uhEuE.js +0 -2
- codex/static_root/assets/settings-drawer-CQ_uhEuE.js.br +0 -0
- codex/static_root/assets/settings-drawer-CQ_uhEuE.js.gz +0 -0
- codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css +0 -1
- codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.br +0 -0
- codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.gz +0 -0
- codex/static_root/assets/settings-drawer-nZ9HvKSZ.css +0 -1
- codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.br +0 -0
- codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.gz +0 -0
- codex/static_root/assets/stats-tab-C1O6FCIj.02cbc306f36f.js.br +0 -0
- codex/static_root/assets/stats-tab-C1O6FCIj.02cbc306f36f.js.gz +0 -0
- codex/static_root/assets/stats-tab-C1O6FCIj.js.br +0 -0
- codex/static_root/assets/stats-tab-C1O6FCIj.js.gz +0 -0
- codex/static_root/assets/task-tab-CqeHSVhx.4167eaffddd4.js.br +0 -0
- codex/static_root/assets/task-tab-CqeHSVhx.4167eaffddd4.js.gz +0 -0
- codex/static_root/assets/task-tab-CqeHSVhx.js.br +0 -0
- codex/static_root/assets/task-tab-CqeHSVhx.js.gz +0 -0
- codex/static_root/assets/unauthorized-BdPK_Sdi.785f127a927a.js.br +0 -0
- codex/static_root/assets/unauthorized-BdPK_Sdi.785f127a927a.js.gz +0 -0
- codex/static_root/assets/unauthorized-BdPK_Sdi.js.br +0 -0
- codex/static_root/assets/unauthorized-BdPK_Sdi.js.gz +0 -0
- codex/static_root/assets/unauthorized-D87B0TXf.85c5665072a2.css.br +0 -0
- codex/static_root/assets/unauthorized-D87B0TXf.85c5665072a2.css.gz +0 -0
- codex/static_root/assets/unauthorized-D87B0TXf.css.br +0 -0
- codex/static_root/assets/unauthorized-D87B0TXf.css.gz +0 -0
- codex/static_root/assets/user-tab-Bp1GOJbE.f7935f7db1fa.js.br +0 -0
- codex/static_root/assets/user-tab-Bp1GOJbE.f7935f7db1fa.js.gz +0 -0
- codex/static_root/assets/user-tab-Bp1GOJbE.js.br +0 -0
- codex/static_root/assets/user-tab-Bp1GOJbE.js.gz +0 -0
- codex/static_root/manifest.8c459e3a8114.json +0 -611
- codex/static_root/manifest.8c459e3a8114.json.br +0 -0
- codex/static_root/manifest.8c459e3a8114.json.gz +0 -0
- {codex-1.6.14.dist-info → codex-1.6.16.dist-info}/LICENSE +0 -0
- {codex-1.6.14.dist-info → codex-1.6.16.dist-info}/WHEEL +0 -0
- {codex-1.6.14.dist-info → codex-1.6.16.dist-info}/entry_points.txt +0 -0
codex/librarian/cron/crond.py
CHANGED
|
@@ -30,21 +30,23 @@ class CronThread(NamedThread):
|
|
|
30
30
|
self._task_times = ()
|
|
31
31
|
super().__init__(*args, name=self.__class__.__name__, daemon=True, **kwargs)
|
|
32
32
|
|
|
33
|
-
def
|
|
33
|
+
def _create_task_times(self):
|
|
34
34
|
task_times = {}
|
|
35
35
|
for task_class, func in _TASK_TIME_FUNCTION_MAP.items():
|
|
36
36
|
if dttm := func(self.log):
|
|
37
37
|
task_times[dttm] = task_class
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# There's always at least the janitor job
|
|
42
|
-
self._next_time = task_tuple[0][0]
|
|
43
|
-
self._task_times = task_tuple
|
|
39
|
+
self._task_times = tuple(sorted(task_times.items()))
|
|
44
40
|
|
|
45
41
|
def _get_timeout(self):
|
|
42
|
+
if not self._task_times or not self._task_times[0]:
|
|
43
|
+
self.log.warning("No scheduled jobs found. Not normal! Waiting a minute.")
|
|
44
|
+
return 60
|
|
45
|
+
|
|
46
|
+
next_time = self._task_times[0][0]
|
|
46
47
|
now = django_timezone.now()
|
|
47
|
-
delta =
|
|
48
|
+
delta = next_time - now
|
|
49
|
+
self.log.debug(f"Next scheduled job at {next_time} in {delta}.")
|
|
48
50
|
return max(0, int(delta.total_seconds()))
|
|
49
51
|
|
|
50
52
|
def _run_expired_jobs(self):
|
|
@@ -53,6 +55,7 @@ class CronThread(NamedThread):
|
|
|
53
55
|
if dttm < now:
|
|
54
56
|
self.librarian_queue.put(task_class())
|
|
55
57
|
else:
|
|
58
|
+
# Times are always ordered so stop checking at the first future job.
|
|
56
59
|
break
|
|
57
60
|
|
|
58
61
|
def run(self):
|
|
@@ -62,13 +65,13 @@ class CronThread(NamedThread):
|
|
|
62
65
|
with self._cond:
|
|
63
66
|
while not self._stop_event.is_set():
|
|
64
67
|
self._run_expired_jobs()
|
|
65
|
-
self.
|
|
68
|
+
self._create_task_times()
|
|
69
|
+
sleep(2) # try to fix double jobs
|
|
66
70
|
timeout = self._get_timeout()
|
|
67
|
-
self.log.debug(f"Next scheduled job at {self._next_time}.")
|
|
68
71
|
self._cond.wait(timeout=timeout)
|
|
69
72
|
if self._stop_event.is_set():
|
|
70
73
|
break
|
|
71
|
-
sleep(2) #
|
|
74
|
+
sleep(2) # fix time rounding problems
|
|
72
75
|
except Exception:
|
|
73
76
|
self.log.exception(f"In {self.__class__.__name__}")
|
|
74
77
|
self.log.debug(f"Stopped {self.__class__.__name__}.")
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Bulk import and move comics and folders."""
|
|
2
2
|
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
3
5
|
from django.utils import timezone
|
|
4
6
|
|
|
5
7
|
from codex.librarian.importer.importer import ComicImporter
|
|
@@ -46,6 +48,15 @@ class ComicImporterThread(QueuedThread):
|
|
|
46
48
|
)
|
|
47
49
|
self._import(task)
|
|
48
50
|
|
|
51
|
+
def _update_groups(self, task):
|
|
52
|
+
pks = Library.objects.filter(covers_only=False).values_list("pk", flat=True)
|
|
53
|
+
start_time = task.start_time if task.start_time else timezone.now()
|
|
54
|
+
for pk in pks:
|
|
55
|
+
task = ImportDBDiffTask(library_id=pk)
|
|
56
|
+
importer = self._create_importer(task)
|
|
57
|
+
importer.update_all_groups({}, start_time)
|
|
58
|
+
self.librarian_queue.put(LIBRARY_CHANGED_TASK)
|
|
59
|
+
|
|
49
60
|
def _adopt_orphan_folders_for_library(self, library):
|
|
50
61
|
"""Adopt orphan folders for one library."""
|
|
51
62
|
orphan_folder_paths = (
|
|
@@ -53,17 +64,20 @@ class ComicImporterThread(QueuedThread):
|
|
|
53
64
|
.exclude(path=library.path)
|
|
54
65
|
.values_list("path", flat=True)
|
|
55
66
|
)
|
|
56
|
-
|
|
67
|
+
# Move in place
|
|
68
|
+
# Exclude deleted folders
|
|
69
|
+
folders_moved = {
|
|
70
|
+
path: path for path in orphan_folder_paths if Path(path).is_dir()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if folders_moved:
|
|
74
|
+
self.log.debug(
|
|
75
|
+
f"{len(folders_moved)} orphan folders found in {library.path}"
|
|
76
|
+
)
|
|
77
|
+
else:
|
|
57
78
|
self.log.debug(f"No orphan folders in {library.path}")
|
|
58
79
|
return False
|
|
59
80
|
|
|
60
|
-
self.log.debug(
|
|
61
|
-
f"{len(orphan_folder_paths)} orphan folders found in {library.path}"
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
# Move in place
|
|
65
|
-
folders_moved = {path: path for path in orphan_folder_paths}
|
|
66
|
-
|
|
67
81
|
# An abridged import task.
|
|
68
82
|
task = ImportDBDiffTask(
|
|
69
83
|
library_id=library.pk,
|
|
@@ -89,15 +103,6 @@ class ComicImporterThread(QueuedThread):
|
|
|
89
103
|
|
|
90
104
|
self.status_controller.finish_many((moved_status, status))
|
|
91
105
|
|
|
92
|
-
def _update_groups(self, task):
|
|
93
|
-
pks = Library.objects.filter(covers_only=False).values_list("pk", flat=True)
|
|
94
|
-
start_time = task.start_time if task.start_time else timezone.now()
|
|
95
|
-
for pk in pks:
|
|
96
|
-
task = ImportDBDiffTask(library_id=pk)
|
|
97
|
-
importer = self._create_importer(task)
|
|
98
|
-
importer.update_all_groups({}, start_time)
|
|
99
|
-
self.librarian_queue.put(LIBRARY_CHANGED_TASK)
|
|
100
|
-
|
|
101
106
|
def process_item(self, item):
|
|
102
107
|
"""Run the updater."""
|
|
103
108
|
task = item
|
|
@@ -105,9 +110,9 @@ class ComicImporterThread(QueuedThread):
|
|
|
105
110
|
self._import(task)
|
|
106
111
|
elif isinstance(task, LazyImportComicsTask):
|
|
107
112
|
self._lazy_import_metadata(task)
|
|
108
|
-
elif isinstance(task, AdoptOrphanFoldersTask):
|
|
109
|
-
self._adopt_orphan_folders()
|
|
110
113
|
elif isinstance(task, UpdateGroupsTask):
|
|
111
114
|
self._update_groups(task)
|
|
115
|
+
elif isinstance(task, AdoptOrphanFoldersTask):
|
|
116
|
+
self._adopt_orphan_folders()
|
|
112
117
|
else:
|
|
113
118
|
self.log.warning(f"Bad task sent to library updater {task}")
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
+
from bidict import bidict
|
|
5
6
|
from django.db.models.functions import Now
|
|
6
7
|
|
|
7
8
|
from codex.librarian.importer.aggregate import AggregateMetadataImporter
|
|
@@ -23,20 +24,42 @@ from codex.status import Status
|
|
|
23
24
|
class MovedImporter(AggregateMetadataImporter):
|
|
24
25
|
"""Methods for moving comics and folders."""
|
|
25
26
|
|
|
26
|
-
def
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
if not
|
|
27
|
+
def _bulk_comics_moved_ensure_folders(self):
|
|
28
|
+
"""Ensure folders we're moving to exist."""
|
|
29
|
+
dest_comic_paths = self.task.files_moved.values()
|
|
30
|
+
if not dest_comic_paths:
|
|
30
31
|
return
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
self.
|
|
32
|
+
# Not sending statues to the controller for now.
|
|
33
|
+
status = Status(ImportStatusTypes.QUERY_MISSING_FKS)
|
|
34
|
+
create_folder_paths = self.query_missing_folder_paths(dest_comic_paths, status)
|
|
35
|
+
if not create_folder_paths:
|
|
36
|
+
return
|
|
37
|
+
status = Status(ImportStatusTypes.CREATE_FKS, 0, len(create_folder_paths))
|
|
38
|
+
self.log.debug(
|
|
39
|
+
"Creating {len(create_folder_paths)} folders for {len(dest_comic_paths)} moved comics."
|
|
40
|
+
)
|
|
41
|
+
self.bulk_folders_create(create_folder_paths, status)
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
def _prepare_moved_comic(self, comic, folder_m2m_links, updated_comics):
|
|
44
|
+
"""Prepare one comic for bulk update."""
|
|
45
|
+
try:
|
|
46
|
+
new_path = self.task.files_moved[comic.path]
|
|
47
|
+
comic.path = new_path
|
|
48
|
+
new_path = Path(new_path)
|
|
49
|
+
comic.parent_folder = Folder.objects.get( # type: ignore
|
|
50
|
+
path=new_path.parent
|
|
51
|
+
)
|
|
52
|
+
comic.updated_at = Now()
|
|
53
|
+
comic.presave()
|
|
54
|
+
folder_m2m_links[comic.pk] = Folder.objects.filter(
|
|
55
|
+
path__in=new_path.parents
|
|
56
|
+
).values_list("pk", flat=True)
|
|
57
|
+
updated_comics.append(comic)
|
|
58
|
+
except Exception:
|
|
59
|
+
self.log.exception(f"moving {comic.path}")
|
|
60
|
+
|
|
61
|
+
def _bulk_comics_move_prepare(self):
|
|
62
|
+
"""Prepare Update Comics."""
|
|
40
63
|
comics = Comic.objects.filter(
|
|
41
64
|
library=self.library, path__in=self.task.files_moved.keys()
|
|
42
65
|
).only("pk", "path", PARENT_FOLDER, FOLDERS_FIELD)
|
|
@@ -44,29 +67,29 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
44
67
|
folder_m2m_links = {}
|
|
45
68
|
updated_comics = []
|
|
46
69
|
for comic in comics.iterator():
|
|
47
|
-
|
|
48
|
-
new_path = self.task.files_moved[comic.path]
|
|
49
|
-
comic.path = new_path
|
|
50
|
-
new_path = Path(new_path)
|
|
51
|
-
comic.parent_folder = Folder.objects.get( # type: ignore
|
|
52
|
-
path=new_path.parent
|
|
53
|
-
)
|
|
54
|
-
comic.updated_at = Now()
|
|
55
|
-
comic.presave()
|
|
56
|
-
folder_m2m_links[comic.pk] = Folder.objects.filter(
|
|
57
|
-
path__in=new_path.parents
|
|
58
|
-
).values_list("pk", flat=True)
|
|
59
|
-
updated_comics.append(comic)
|
|
60
|
-
except Exception:
|
|
61
|
-
self.log.exception(f"moving {comic.path}")
|
|
70
|
+
self._prepare_moved_comic(comic, folder_m2m_links, updated_comics)
|
|
62
71
|
self.task.files_moved = {}
|
|
72
|
+
self.log.debug(f"Prepared {len(updated_comics)} for move...")
|
|
73
|
+
return updated_comics, folder_m2m_links
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
def _bulk_comics_moved(self):
|
|
76
|
+
"""Move comcis."""
|
|
77
|
+
num_files_moved = len(self.task.files_moved)
|
|
78
|
+
if not num_files_moved:
|
|
79
|
+
return
|
|
80
|
+
status = Status(ImportStatusTypes.FILES_MOVED, 0, num_files_moved)
|
|
81
|
+
self.status_controller.start(status)
|
|
65
82
|
|
|
66
|
-
#
|
|
83
|
+
# Prepare
|
|
84
|
+
self._bulk_comics_moved_ensure_folders()
|
|
85
|
+
updated_comics, folder_m2m_links = self._bulk_comics_move_prepare()
|
|
86
|
+
|
|
87
|
+
# Update comics
|
|
88
|
+
Comic.objects.bulk_update(updated_comics, MOVED_BULK_COMIC_UPDATE_FIELDS)
|
|
67
89
|
if folder_m2m_links:
|
|
68
90
|
self.bulk_fix_comic_m2m_field(FOLDERS_FIELD, folder_m2m_links, status)
|
|
69
|
-
|
|
91
|
+
|
|
92
|
+
count = len(updated_comics)
|
|
70
93
|
if count:
|
|
71
94
|
self.log.info(f"Moved {count} comics.")
|
|
72
95
|
|
|
@@ -140,60 +163,32 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
140
163
|
self.changed += count
|
|
141
164
|
self.status_controller.finish(status)
|
|
142
165
|
|
|
143
|
-
def
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
# Create only intermediate subfolders.
|
|
153
|
-
existing_folder_paths = Folder.objects.filter(
|
|
154
|
-
library=self.library, path__in=dest_parent_folder_paths
|
|
155
|
-
).values_list("path", flat=True)
|
|
156
|
-
create_folder_paths = frozenset(
|
|
157
|
-
dest_parent_folder_paths - frozenset(existing_folder_paths)
|
|
166
|
+
def _bulk_move_folders(
|
|
167
|
+
self, src_folder_paths, dest_parent_folders_map, dirs_moved: bidict, status
|
|
168
|
+
):
|
|
169
|
+
"""Bulk move folders."""
|
|
170
|
+
folders_to_move = (
|
|
171
|
+
Folder.objects.filter(library=self.library, path__in=src_folder_paths)
|
|
172
|
+
.only(*MOVED_BULK_FOLDER_UPDATE_FIELDS)
|
|
173
|
+
.order_by("path")
|
|
158
174
|
)
|
|
159
|
-
self.bulk_folders_create(create_folder_paths, status)
|
|
160
175
|
|
|
161
|
-
#
|
|
162
|
-
dest_parent_folders_objs = Folder.objects.filter(
|
|
163
|
-
path__in=dest_parent_folder_paths
|
|
164
|
-
).only("path", "pk")
|
|
165
|
-
dest_parent_folders = {}
|
|
166
|
-
for folder in dest_parent_folders_objs.iterator():
|
|
167
|
-
dest_parent_folders[folder.path] = folder
|
|
168
|
-
return dest_parent_folders
|
|
169
|
-
|
|
170
|
-
def bulk_folders_moved(self):
|
|
171
|
-
"""Move folders in the database instead of recreating them."""
|
|
172
|
-
num_dirs_moved = len(self.task.dirs_moved)
|
|
173
|
-
if not num_dirs_moved:
|
|
174
|
-
return
|
|
175
|
-
status = Status(ImportStatusTypes.DIRS_MOVED, None, num_dirs_moved)
|
|
176
|
-
self.status_controller.start(status)
|
|
177
|
-
|
|
178
|
-
dest_folder_paths = frozenset(self.task.dirs_moved.values())
|
|
179
|
-
dest_parent_folders = self._get_parent_folders(dest_folder_paths, status)
|
|
180
|
-
|
|
181
|
-
src_folder_paths = frozenset(self.task.dirs_moved.keys())
|
|
182
|
-
folders_to_move = Folder.objects.filter(
|
|
183
|
-
library=self.library, path__in=src_folder_paths
|
|
184
|
-
).order_by("path")
|
|
176
|
+
# TODO what if a folder with that path already exists in the db?
|
|
185
177
|
|
|
178
|
+
new_paths = set()
|
|
186
179
|
update_folders = []
|
|
187
180
|
for folder in folders_to_move.iterator():
|
|
188
|
-
new_path =
|
|
181
|
+
new_path = dirs_moved[folder.path]
|
|
182
|
+
new_paths.add(new_path)
|
|
189
183
|
folder.name = Path(new_path).name
|
|
190
184
|
folder.path = new_path
|
|
191
185
|
parent_path_str = str(Path(new_path).parent)
|
|
192
|
-
folder.parent_folder =
|
|
186
|
+
folder.parent_folder = dest_parent_folders_map.get(parent_path_str)
|
|
193
187
|
folder.presave()
|
|
194
188
|
folder.updated_at = Now()
|
|
195
189
|
update_folders.append(folder)
|
|
196
|
-
|
|
190
|
+
|
|
191
|
+
# delete_folders = Folder.objects.filter(library=self.library, path__in=new_paths)
|
|
197
192
|
|
|
198
193
|
update_folders = sorted(update_folders, key=lambda x: len(Path(x.path).parts))
|
|
199
194
|
|
|
@@ -202,6 +197,112 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
202
197
|
if count:
|
|
203
198
|
self.log.info(f"Moved {count} folders.")
|
|
204
199
|
self.changed += count
|
|
200
|
+
status.add_complete(count)
|
|
201
|
+
self.status_controller.update(status, notify=False)
|
|
202
|
+
|
|
203
|
+
def _bulk_move_folders_under_existing_parents(
|
|
204
|
+
self, dest_parent_folder_paths_map, dirs_moved, status
|
|
205
|
+
):
|
|
206
|
+
"""Move folders under existing folders."""
|
|
207
|
+
while True:
|
|
208
|
+
# Get existing parent folders
|
|
209
|
+
# dest_parent_paths = tuple(str(path) for path in dest_parent_folder_paths_map)
|
|
210
|
+
dest_parent_paths = tuple(dest_parent_folder_paths_map.keys())
|
|
211
|
+
extant_parent_folders = Folder.objects.filter(
|
|
212
|
+
library=self.library, path__in=dest_parent_paths
|
|
213
|
+
).only("path")
|
|
214
|
+
|
|
215
|
+
# Create a list of folders than can be moved under existing folders.
|
|
216
|
+
dest_parent_folders_map = {}
|
|
217
|
+
src_folder_paths = []
|
|
218
|
+
for extant_parent_folder in extant_parent_folders:
|
|
219
|
+
dest_parent_folders_map[extant_parent_folder.path] = (
|
|
220
|
+
extant_parent_folder
|
|
221
|
+
)
|
|
222
|
+
if dest_folder_paths := dest_parent_folder_paths_map.pop(
|
|
223
|
+
extant_parent_folder.path
|
|
224
|
+
):
|
|
225
|
+
for dest_folder_path in dest_folder_paths:
|
|
226
|
+
src_path = dirs_moved.inverse[dest_folder_path]
|
|
227
|
+
src_folder_paths.append(src_path)
|
|
228
|
+
|
|
229
|
+
if not src_folder_paths:
|
|
230
|
+
return
|
|
231
|
+
src_folder_paths = sorted(src_folder_paths)
|
|
232
|
+
self.log.debug(f"Moving folders under existing parents: {src_folder_paths}")
|
|
233
|
+
|
|
234
|
+
self._bulk_move_folders(
|
|
235
|
+
src_folder_paths, dest_parent_folders_map, dirs_moved, status
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
def _get_move_create_folders_one_layer(self, dest_parent_folder_paths_map):
|
|
239
|
+
"""Find the next layer of folder paths to create."""
|
|
240
|
+
create_folder_paths_one_layer = set()
|
|
241
|
+
library_parts_len = len(Path(self.library.path).parts)
|
|
242
|
+
for parent_path_str in sorted(dest_parent_folder_paths_map.keys()):
|
|
243
|
+
parts = Path(parent_path_str).parts
|
|
244
|
+
# Get one layer of folders from existing layers.
|
|
245
|
+
possible_create_folder_path = ""
|
|
246
|
+
for index in range(library_parts_len, len(parts) + 1):
|
|
247
|
+
layer_parts = parts[:index]
|
|
248
|
+
possible_create_folder_path = str(Path(*layer_parts))
|
|
249
|
+
if (
|
|
250
|
+
possible_create_folder_path in create_folder_paths_one_layer
|
|
251
|
+
or not Folder.objects.filter(
|
|
252
|
+
library=self.library, path=possible_create_folder_path
|
|
253
|
+
).exists()
|
|
254
|
+
):
|
|
255
|
+
break
|
|
256
|
+
else:
|
|
257
|
+
possible_create_folder_path = ""
|
|
258
|
+
if possible_create_folder_path:
|
|
259
|
+
create_folder_paths_one_layer.add(possible_create_folder_path)
|
|
260
|
+
|
|
261
|
+
return frozenset(create_folder_paths_one_layer)
|
|
262
|
+
|
|
263
|
+
def _bulk_move_folders_and_create_parents(self, status):
|
|
264
|
+
"""Find folders that can be moved without creating parents."""
|
|
265
|
+
dirs_moved = bidict(self.task.dirs_moved)
|
|
266
|
+
|
|
267
|
+
dest_parent_folder_paths_map = {}
|
|
268
|
+
for dest_path in sorted(set(dirs_moved.values())):
|
|
269
|
+
parent = str(Path(dest_path).parent)
|
|
270
|
+
if parent not in dest_parent_folder_paths_map:
|
|
271
|
+
dest_parent_folder_paths_map[parent] = set()
|
|
272
|
+
dest_parent_folder_paths_map[parent].add(dest_path)
|
|
273
|
+
|
|
274
|
+
create_status = Status(ImportStatusTypes.CREATE_FKS)
|
|
275
|
+
layer = 1
|
|
276
|
+
while True:
|
|
277
|
+
self._bulk_move_folders_under_existing_parents(
|
|
278
|
+
dest_parent_folder_paths_map, dirs_moved, status
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# All folders movable without creation have moved.
|
|
282
|
+
if not dest_parent_folder_paths_map:
|
|
283
|
+
break
|
|
284
|
+
self.log.debug(
|
|
285
|
+
f"Creating intermediate folder layer {layer} to move folders."
|
|
286
|
+
)
|
|
287
|
+
create_folder_paths_one_layer = self._get_move_create_folders_one_layer(
|
|
288
|
+
dest_parent_folder_paths_map
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Create one layer of folders
|
|
292
|
+
self.bulk_folders_create(create_folder_paths_one_layer, create_status)
|
|
293
|
+
layer += 1
|
|
294
|
+
|
|
295
|
+
def bulk_folders_moved(self):
|
|
296
|
+
"""Move folders in the database instead of recreating them."""
|
|
297
|
+
num_dirs_moved = len(self.task.dirs_moved)
|
|
298
|
+
if not num_dirs_moved:
|
|
299
|
+
return
|
|
300
|
+
status = Status(ImportStatusTypes.DIRS_MOVED, None, num_dirs_moved)
|
|
301
|
+
self.status_controller.start(status)
|
|
302
|
+
|
|
303
|
+
self._bulk_move_folders_and_create_parents(status)
|
|
304
|
+
self.task.dirs_moved = {}
|
|
305
|
+
|
|
205
306
|
self.status_controller.finish(status)
|
|
206
307
|
|
|
207
308
|
def _bulk_folders_modified(self):
|
|
@@ -233,6 +334,8 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
233
334
|
|
|
234
335
|
def move_and_modify_dirs(self):
|
|
235
336
|
"""Move files and dirs and modify dirs."""
|
|
337
|
+
# It would be nice to move folders instead of recreating them but it would require
|
|
338
|
+
# an inode map from the snapshots to do correctly.
|
|
236
339
|
self.bulk_folders_moved()
|
|
237
340
|
self._bulk_comics_moved()
|
|
238
341
|
self._bulk_covers_moved()
|
|
@@ -544,19 +544,22 @@ class QueryForeignKeysImporter(QueryCustomCoversImporter):
|
|
|
544
544
|
base_cls = Comic
|
|
545
545
|
fk_data = self.metadata[FK_CREATE][FKC_CREATE_FKS], base_cls, fk_field, "name"
|
|
546
546
|
names = self.metadata[FKS].pop(fk_field)
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
status,
|
|
552
|
-
)
|
|
547
|
+
count = self._query_missing_simple_models(
|
|
548
|
+
names,
|
|
549
|
+
fk_data,
|
|
550
|
+
status,
|
|
553
551
|
)
|
|
552
|
+
status.add_complete(count)
|
|
554
553
|
self.status_controller.update(status, notify=False)
|
|
555
554
|
|
|
556
555
|
###########
|
|
557
556
|
# FOLDERS #
|
|
558
557
|
###########
|
|
559
|
-
def query_missing_folder_paths(
|
|
558
|
+
def query_missing_folder_paths(
|
|
559
|
+
self,
|
|
560
|
+
comic_paths,
|
|
561
|
+
status,
|
|
562
|
+
):
|
|
560
563
|
"""Find missing folder paths."""
|
|
561
564
|
# Get the proposed folder_paths
|
|
562
565
|
library_path = Path(self.library.path)
|
|
@@ -575,15 +578,18 @@ class QueryForeignKeysImporter(QueryCustomCoversImporter):
|
|
|
575
578
|
status,
|
|
576
579
|
)
|
|
577
580
|
create_folder_paths = create_folder_paths_dict.get(Folder, set())
|
|
581
|
+
return frozenset(create_folder_paths)
|
|
582
|
+
|
|
583
|
+
def _add_missing_folder_paths(self, comic_paths, status):
|
|
584
|
+
create_folder_paths = self.query_missing_folder_paths(comic_paths, status)
|
|
585
|
+
"""Add missing folder_paths to create fks."""
|
|
578
586
|
if FK_CREATE not in self.metadata:
|
|
579
587
|
self.metadata[FK_CREATE] = {}
|
|
580
588
|
if FKC_FOLDER_PATHS not in self.metadata[FK_CREATE]:
|
|
581
589
|
self.metadata[FK_CREATE][FKC_FOLDER_PATHS] = set()
|
|
582
590
|
self.metadata[FK_CREATE][FKC_FOLDER_PATHS] |= create_folder_paths
|
|
583
|
-
count
|
|
584
|
-
if count:
|
|
591
|
+
if count := len(create_folder_paths):
|
|
585
592
|
self.log.info(f"Prepared {count} new Folders.")
|
|
586
|
-
return count
|
|
587
593
|
|
|
588
594
|
def _get_create_fks_totals(self):
|
|
589
595
|
fkc = self.metadata[FK_CREATE]
|
|
@@ -634,7 +640,7 @@ class QueryForeignKeysImporter(QueryCustomCoversImporter):
|
|
|
634
640
|
status,
|
|
635
641
|
)
|
|
636
642
|
|
|
637
|
-
self.
|
|
643
|
+
self._add_missing_folder_paths(
|
|
638
644
|
self.metadata[FKS].pop(COMIC_PATHS, ()), status
|
|
639
645
|
)
|
|
640
646
|
|
|
@@ -6,7 +6,7 @@ from logging import getLogger
|
|
|
6
6
|
from lzma import compress
|
|
7
7
|
from uuid import uuid4
|
|
8
8
|
|
|
9
|
-
from requests import
|
|
9
|
+
from requests import Session
|
|
10
10
|
|
|
11
11
|
from codex.librarian.telemeter.stats import CodexStats
|
|
12
12
|
from codex.models.admin import AdminFlag, Timestamp
|
|
@@ -52,8 +52,11 @@ def _post_stats(log, data):
|
|
|
52
52
|
msg = f"{_POST} {len(compressed_data)}, {_HEADERS}, {_TIMEOUT}"
|
|
53
53
|
log.debug(msg)
|
|
54
54
|
else:
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
with Session() as session:
|
|
56
|
+
response = session.post(
|
|
57
|
+
_POST, data=compressed_data, headers=_HEADERS, timeout=_TIMEOUT
|
|
58
|
+
)
|
|
59
|
+
response.raise_for_status()
|
|
57
60
|
|
|
58
61
|
|
|
59
62
|
def _send_telemetry(log):
|
|
@@ -21,9 +21,9 @@ class SnapshotDiffData:
|
|
|
21
21
|
class CodexDirectorySnapshotDiff(DirectorySnapshotDiff):
|
|
22
22
|
"""Custom Diff allows inode only changes to be 'modified'."""
|
|
23
23
|
|
|
24
|
-
def _get_inode(self,
|
|
24
|
+
def _get_inode(self, snapshot, full_path):
|
|
25
25
|
"""Get inode optionally ignoring device stats."""
|
|
26
|
-
result =
|
|
26
|
+
result = snapshot.inode(full_path)
|
|
27
27
|
if self._ignore_device:
|
|
28
28
|
result = result[0]
|
|
29
29
|
return result
|
|
@@ -33,7 +33,7 @@ class CodexDirectorySnapshotDiff(DirectorySnapshotDiff):
|
|
|
33
33
|
return self._get_inode(data.ref, path) == self._get_inode(data.snapshot, path)
|
|
34
34
|
|
|
35
35
|
def _is_stats_equal(self, data, old_path, new_path):
|
|
36
|
-
"""Return if the
|
|
36
|
+
"""Return if the mtime and size are equal.
|
|
37
37
|
|
|
38
38
|
For old paths in the ref and new paths in the snapshot.
|
|
39
39
|
"""
|
|
@@ -48,25 +48,27 @@ class CodexDirectorySnapshotDiff(DirectorySnapshotDiff):
|
|
|
48
48
|
if self._inode_only_modified:
|
|
49
49
|
data.modified.add(path)
|
|
50
50
|
else:
|
|
51
|
+
# Add these to created and deleted. But...
|
|
52
|
+
# The _find_moved_paths() inode tracker should
|
|
53
|
+
# sort them out.
|
|
54
|
+
# This is the same as in upstream dirsnapshot.py
|
|
51
55
|
data.created.add(path)
|
|
52
56
|
data.deleted.add(path)
|
|
53
57
|
|
|
54
58
|
def _find_moved_paths(self, data):
|
|
55
|
-
"""Find moved paths."""
|
|
56
|
-
for
|
|
57
|
-
inode = data.ref
|
|
58
|
-
new_path
|
|
59
|
-
if new_path:
|
|
59
|
+
"""Find moved paths in deleted and created."""
|
|
60
|
+
for old_path in tuple(data.deleted):
|
|
61
|
+
inode = self._get_inode(data.ref, old_path)
|
|
62
|
+
if new_path := data.snapshot.path(inode):
|
|
60
63
|
# file is not deleted but moved
|
|
61
|
-
data.deleted.remove(
|
|
62
|
-
data.moved.add((
|
|
64
|
+
data.deleted.remove(old_path)
|
|
65
|
+
data.moved.add((old_path, new_path))
|
|
63
66
|
|
|
64
|
-
for
|
|
65
|
-
inode = data.snapshot
|
|
66
|
-
old_path
|
|
67
|
-
|
|
68
|
-
data.
|
|
69
|
-
data.moved.add((old_path, path))
|
|
67
|
+
for new_path in tuple(data.created):
|
|
68
|
+
inode = self._get_inode(data.snapshot, new_path)
|
|
69
|
+
if old_path := data.ref.path(inode):
|
|
70
|
+
data.created.remove(new_path)
|
|
71
|
+
data.moved.add((old_path, new_path))
|
|
70
72
|
|
|
71
73
|
def _find_modified_paths(self, data):
|
|
72
74
|
"""Find modified paths."""
|
|
@@ -80,7 +82,7 @@ class CodexDirectorySnapshotDiff(DirectorySnapshotDiff):
|
|
|
80
82
|
# Check moved paths for modificiations.
|
|
81
83
|
for old_path, new_path in data.moved:
|
|
82
84
|
if not self._is_stats_equal(data, old_path, new_path):
|
|
83
|
-
data.modified.add(
|
|
85
|
+
data.modified.add(new_path)
|
|
84
86
|
|
|
85
87
|
def __init__( # C901, PLR0912
|
|
86
88
|
self, ref, snapshot, ignore_device=False, inode_only_modified=False
|
codex/search/backend.py
CHANGED
|
@@ -122,7 +122,10 @@ class CodexSearchBackend(CodexBackendSearchMixin, WhooshSearchBackend, WorkerBas
|
|
|
122
122
|
"created_at": ("created",),
|
|
123
123
|
"critical_rating": gen_multipart_field_aliases("critical_rating"),
|
|
124
124
|
"genres": ("genre",),
|
|
125
|
-
"file_type": (
|
|
125
|
+
"file_type": (
|
|
126
|
+
"filetype",
|
|
127
|
+
"type",
|
|
128
|
+
),
|
|
126
129
|
"identifier": ("id", "nss"),
|
|
127
130
|
"identifier_type": ("idtype", "id_type", "nid"),
|
|
128
131
|
"issue_number": ("number",),
|
|
@@ -132,7 +135,11 @@ class CodexSearchBackend(CodexBackendSearchMixin, WhooshSearchBackend, WorkerBas
|
|
|
132
135
|
"original_format": ("format",),
|
|
133
136
|
"page_count": ("pages",),
|
|
134
137
|
"reading_direction": ("direction",),
|
|
135
|
-
"search_path": (
|
|
138
|
+
"search_path": (
|
|
139
|
+
"path",
|
|
140
|
+
"filename",
|
|
141
|
+
*gen_multipart_field_aliases("folders"),
|
|
142
|
+
),
|
|
136
143
|
"series_groups": gen_multipart_field_aliases("series_groups"),
|
|
137
144
|
"scan_info": ("scan",),
|
|
138
145
|
"stories": ("story",),
|
codex/settings/settings.py
CHANGED
codex/static_root/assets/{VCheckbox-Bf5gdxZe.7edc318a8f33.js → VCheckbox-B_KxeHW4.83cc6be08a2f.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as g,V as t}from"./VCheckboxBtn-
|
|
1
|
+
import{m as g,V as t}from"./VCheckboxBtn-D_7rfm4C.js";import{a as A,u as I,V as l}from"./VSelectionControl-B7a_kuaA.js";import{F as B,am as U,P as D,au as R,G as q,h as G,S as M,cD as N,T as u,aq as r}from"./admin-drawer-panel-CoRl2h5W.js";const S=B({...A(),...U(g(),["inline"])},"VCheckbox"),w=D()({name:"VCheckbox",inheritAttrs:!1,props:S(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(e,c){let{attrs:d,slots:a}=c;const s=R(e,"modelValue"),{isFocused:n,focus:i,blur:m}=I(e),V=q(),p=G(()=>e.id||`checkbox-${V}`);return M(()=>{const[b,f]=N(d),v=l.filterProps(e),k=t.filterProps(e);return u(l,r({class:["v-checkbox",e.class]},b,v,{modelValue:s.value,"onUpdate:modelValue":o=>s.value=o,id:p.value,focused:n.value,style:e.style}),{...a,default:o=>{let{id:h,messagesId:x,isDisabled:P,isReadonly:C,isValid:y}=o;return u(t,r(k,{id:h.value,"aria-describedby":x.value,disabled:P.value,readonly:C.value},f,{error:y.value===!1,modelValue:s.value,"onUpdate:modelValue":F=>s.value=F,onFocus:i,onBlur:m}),a)}})}),{}}});export{w as V};
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as g,V as t}from"./VCheckboxBtn-
|
|
1
|
+
import{m as g,V as t}from"./VCheckboxBtn-D_7rfm4C.js";import{a as A,u as I,V as l}from"./VSelectionControl-B7a_kuaA.js";import{F as B,am as U,P as D,au as R,G as q,h as G,S as M,cD as N,T as u,aq as r}from"./admin-drawer-panel-CoRl2h5W.js";const S=B({...A(),...U(g(),["inline"])},"VCheckbox"),w=D()({name:"VCheckbox",inheritAttrs:!1,props:S(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(e,c){let{attrs:d,slots:a}=c;const s=R(e,"modelValue"),{isFocused:n,focus:i,blur:m}=I(e),V=q(),p=G(()=>e.id||`checkbox-${V}`);return M(()=>{const[b,f]=N(d),v=l.filterProps(e),k=t.filterProps(e);return u(l,r({class:["v-checkbox",e.class]},b,v,{modelValue:s.value,"onUpdate:modelValue":o=>s.value=o,id:p.value,focused:n.value,style:e.style}),{...a,default:o=>{let{id:h,messagesId:x,isDisabled:P,isReadonly:C,isValid:y}=o;return u(t,r(k,{id:h.value,"aria-describedby":x.value,disabled:P.value,readonly:C.value},f,{error:y.value===!1,modelValue:s.value,"onUpdate:modelValue":F=>s.value=F,onFocus:i,onBlur:m}),a)}})}),{}}});export{w as V};
|
|
Binary file
|
|
Binary file
|