codex 1.6.3__py3-none-any.whl → 1.6.5__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.

Files changed (402) hide show
  1. codex/librarian/importer/importer.py +1 -1
  2. codex/librarian/janitor/cleanup.py +2 -4
  3. codex/librarian/janitor/update.py +10 -9
  4. codex/librarian/search/merge.py +37 -40
  5. codex/librarian/search/remove.py +30 -26
  6. codex/librarian/search/update.py +47 -38
  7. codex/librarian/stats.py +177 -0
  8. codex/librarian/watchdog/events.py +2 -2
  9. codex/serializers/admin/stats.py +77 -65
  10. codex/serializers/fields.py +23 -0
  11. codex/settings/settings.py +3 -3
  12. codex/static_root/assets/{VCheckbox-CXQlndFT.c17c006a62e6.js → VCheckbox-OPrrn8D4.95d8259619aa.js} +1 -1
  13. codex/static_root/assets/VCheckbox-OPrrn8D4.95d8259619aa.js.br +0 -0
  14. codex/static_root/assets/VCheckbox-OPrrn8D4.95d8259619aa.js.gz +0 -0
  15. codex/static_root/assets/{VCheckbox-CXQlndFT.js → VCheckbox-OPrrn8D4.js} +1 -1
  16. codex/static_root/assets/VCheckbox-OPrrn8D4.js.br +0 -0
  17. codex/static_root/assets/VCheckbox-OPrrn8D4.js.gz +0 -0
  18. codex/static_root/assets/{VCheckboxBtn-DB72Bclg.ab414c6ae2b8.js → VCheckboxBtn-BLEc6BrH.e8ae3d2738e2.js} +1 -1
  19. codex/static_root/assets/VCheckboxBtn-BLEc6BrH.e8ae3d2738e2.js.br +0 -0
  20. codex/static_root/assets/VCheckboxBtn-BLEc6BrH.e8ae3d2738e2.js.gz +0 -0
  21. codex/static_root/assets/{VCheckboxBtn-DB72Bclg.js → VCheckboxBtn-BLEc6BrH.js} +1 -1
  22. codex/static_root/assets/VCheckboxBtn-BLEc6BrH.js.br +0 -0
  23. codex/static_root/assets/VCheckboxBtn-BLEc6BrH.js.gz +0 -0
  24. codex/static_root/assets/{VCombobox-BDcFPzYf.0b80447cd638.js → VCombobox-C18LIWGs.2a41fab61075.js} +1 -1
  25. codex/static_root/assets/VCombobox-C18LIWGs.2a41fab61075.js.br +0 -0
  26. codex/static_root/assets/VCombobox-C18LIWGs.2a41fab61075.js.gz +0 -0
  27. codex/static_root/assets/{VCombobox-BDcFPzYf.js → VCombobox-C18LIWGs.js} +1 -1
  28. codex/static_root/assets/VCombobox-C18LIWGs.js.br +0 -0
  29. codex/static_root/assets/VCombobox-C18LIWGs.js.gz +0 -0
  30. codex/static_root/assets/{VDialog-BB4zqrGw.2decc14ea597.js → VDialog-DPlcZ188.9398019bd69c.js} +1 -1
  31. codex/static_root/assets/VDialog-DPlcZ188.9398019bd69c.js.br +0 -0
  32. codex/static_root/assets/VDialog-DPlcZ188.9398019bd69c.js.gz +0 -0
  33. codex/static_root/assets/{VDialog-BB4zqrGw.js → VDialog-DPlcZ188.js} +1 -1
  34. codex/static_root/assets/VDialog-DPlcZ188.js.br +0 -0
  35. codex/static_root/assets/VDialog-DPlcZ188.js.gz +0 -0
  36. codex/static_root/assets/{VExpansionPanels-SZc735F5.19004a0eba16.js → VExpansionPanels-BrAdxiR-.f5e7507958b2.js} +1 -1
  37. codex/static_root/assets/VExpansionPanels-BrAdxiR-.f5e7507958b2.js.br +0 -0
  38. codex/static_root/assets/VExpansionPanels-BrAdxiR-.f5e7507958b2.js.gz +0 -0
  39. codex/static_root/assets/{VExpansionPanels-SZc735F5.js → VExpansionPanels-BrAdxiR-.js} +1 -1
  40. codex/static_root/assets/VExpansionPanels-BrAdxiR-.js.br +0 -0
  41. codex/static_root/assets/VExpansionPanels-BrAdxiR-.js.gz +0 -0
  42. codex/static_root/assets/{VRadioGroup-tFEuhFRq.774e14a4945a.js → VRadioGroup-BWf1qZO1.ee8a1b8d589d.js} +1 -1
  43. codex/static_root/assets/VRadioGroup-BWf1qZO1.ee8a1b8d589d.js.br +0 -0
  44. codex/static_root/assets/VRadioGroup-BWf1qZO1.ee8a1b8d589d.js.gz +0 -0
  45. codex/static_root/assets/{VRadioGroup-tFEuhFRq.js → VRadioGroup-BWf1qZO1.js} +1 -1
  46. codex/static_root/assets/VRadioGroup-BWf1qZO1.js.br +0 -0
  47. codex/static_root/assets/VRadioGroup-BWf1qZO1.js.gz +0 -0
  48. codex/static_root/assets/{VSelect-Dd5Zy8Uy.f225abf824ff.js → VSelect-BEOlJiRW.2d4996f0d6a3.js} +1 -1
  49. codex/static_root/assets/VSelect-BEOlJiRW.2d4996f0d6a3.js.br +0 -0
  50. codex/static_root/assets/VSelect-BEOlJiRW.2d4996f0d6a3.js.gz +0 -0
  51. codex/static_root/assets/{VSelect-Dd5Zy8Uy.js → VSelect-BEOlJiRW.js} +1 -1
  52. codex/static_root/assets/VSelect-BEOlJiRW.js.br +0 -0
  53. codex/static_root/assets/VSelect-BEOlJiRW.js.gz +0 -0
  54. codex/static_root/assets/{VSelectionControl-DImIQPJV.1f14d2113063.js → VSelectionControl-BpvvZpBd.d83b413a38d1.js} +1 -1
  55. codex/static_root/assets/VSelectionControl-BpvvZpBd.d83b413a38d1.js.br +0 -0
  56. codex/static_root/assets/VSelectionControl-BpvvZpBd.d83b413a38d1.js.gz +0 -0
  57. codex/static_root/assets/{VSelectionControl-DImIQPJV.js → VSelectionControl-BpvvZpBd.js} +1 -1
  58. codex/static_root/assets/VSelectionControl-BpvvZpBd.js.br +0 -0
  59. codex/static_root/assets/VSelectionControl-BpvvZpBd.js.gz +0 -0
  60. codex/static_root/assets/{VSlideGroup-CDaAHRAK.783800d70a8a.js → VSlideGroup-Bv0lRnhB.e0b8f680bcbf.js} +1 -1
  61. codex/static_root/assets/VSlideGroup-Bv0lRnhB.e0b8f680bcbf.js.br +0 -0
  62. codex/static_root/assets/VSlideGroup-Bv0lRnhB.e0b8f680bcbf.js.gz +0 -0
  63. codex/static_root/assets/{VSlideGroup-CDaAHRAK.js → VSlideGroup-Bv0lRnhB.js} +1 -1
  64. codex/static_root/assets/VSlideGroup-Bv0lRnhB.js.br +0 -0
  65. codex/static_root/assets/VSlideGroup-Bv0lRnhB.js.gz +0 -0
  66. codex/static_root/assets/{VTable-CkCZonsu.81e34381271f.js → VTable-Dw1ASmYk.4e3817348a64.js} +1 -1
  67. codex/static_root/assets/VTable-Dw1ASmYk.4e3817348a64.js.br +0 -0
  68. codex/static_root/assets/VTable-Dw1ASmYk.4e3817348a64.js.gz +0 -0
  69. codex/static_root/assets/{VTable-CkCZonsu.js → VTable-Dw1ASmYk.js} +1 -1
  70. codex/static_root/assets/VTable-Dw1ASmYk.js.br +0 -0
  71. codex/static_root/assets/VTable-Dw1ASmYk.js.gz +0 -0
  72. codex/static_root/assets/{VTextField-fNAzFu1M.00dec8623f18.js → VTextField-DhIkxARQ.e688815dc516.js} +1 -1
  73. codex/static_root/assets/VTextField-DhIkxARQ.e688815dc516.js.br +0 -0
  74. codex/static_root/assets/VTextField-DhIkxARQ.e688815dc516.js.gz +0 -0
  75. codex/static_root/assets/{VTextField-fNAzFu1M.js → VTextField-DhIkxARQ.js} +1 -1
  76. codex/static_root/assets/VTextField-DhIkxARQ.js.br +0 -0
  77. codex/static_root/assets/VTextField-DhIkxARQ.js.gz +0 -0
  78. codex/static_root/assets/{VWindowItem-_YBMW1SU.0836924f8c12.js → VWindowItem-IDCZgODl.8c4527097642.js} +1 -1
  79. codex/static_root/assets/VWindowItem-IDCZgODl.8c4527097642.js.br +0 -0
  80. codex/static_root/assets/VWindowItem-IDCZgODl.8c4527097642.js.gz +0 -0
  81. codex/static_root/assets/{VWindowItem-_YBMW1SU.js → VWindowItem-IDCZgODl.js} +1 -1
  82. codex/static_root/assets/VWindowItem-IDCZgODl.js.br +0 -0
  83. codex/static_root/assets/VWindowItem-IDCZgODl.js.gz +0 -0
  84. codex/static_root/assets/{admin-DYmGyJVg.262e6032ee86.js → admin-DQMEj7xy.f249ade8981c.js} +1 -1
  85. codex/static_root/assets/admin-DQMEj7xy.f249ade8981c.js.br +0 -0
  86. codex/static_root/assets/admin-DQMEj7xy.f249ade8981c.js.gz +0 -0
  87. codex/static_root/assets/{admin-DYmGyJVg.js → admin-DQMEj7xy.js} +1 -1
  88. codex/static_root/assets/admin-DQMEj7xy.js.br +0 -0
  89. codex/static_root/assets/admin-DQMEj7xy.js.gz +0 -0
  90. codex/static_root/assets/{admin-drawer-panel-c3f3H29x.fa2b12c75b06.js → admin-drawer-panel-Can9sQIk.7021726ce8b9.js} +20 -20
  91. codex/static_root/assets/admin-drawer-panel-Can9sQIk.7021726ce8b9.js.br +0 -0
  92. codex/static_root/assets/admin-drawer-panel-Can9sQIk.7021726ce8b9.js.gz +0 -0
  93. codex/static_root/assets/{admin-drawer-panel-c3f3H29x.js → admin-drawer-panel-Can9sQIk.js} +20 -20
  94. codex/static_root/assets/admin-drawer-panel-Can9sQIk.js.br +0 -0
  95. codex/static_root/assets/admin-drawer-panel-Can9sQIk.js.gz +0 -0
  96. codex/static_root/assets/{browser-Ck3zWCOk.d98c77747e6d.js → browser-BOPyA0wB.b69c491ad88e.js} +1 -1
  97. codex/static_root/assets/browser-BOPyA0wB.b69c491ad88e.js.br +0 -0
  98. codex/static_root/assets/browser-BOPyA0wB.b69c491ad88e.js.gz +0 -0
  99. codex/static_root/assets/{browser-Ck3zWCOk.js → browser-BOPyA0wB.js} +1 -1
  100. codex/static_root/assets/browser-BOPyA0wB.js.br +0 -0
  101. codex/static_root/assets/browser-BOPyA0wB.js.gz +0 -0
  102. codex/static_root/assets/{browser-DgawKPSA.c7cf59dc4b21.css → browser-Cy0OgQJC.css} +1 -1
  103. codex/static_root/assets/browser-Cy0OgQJC.css.br +0 -0
  104. codex/static_root/assets/browser-Cy0OgQJC.css.gz +0 -0
  105. codex/static_root/assets/{browser-DgawKPSA.css → browser-Cy0OgQJC.fabbd1aaffcf.css} +1 -1
  106. codex/static_root/assets/browser-Cy0OgQJC.fabbd1aaffcf.css.br +0 -0
  107. codex/static_root/assets/browser-Cy0OgQJC.fabbd1aaffcf.css.gz +0 -0
  108. codex/static_root/assets/{change-password-dialog-BbIO0YI5.2bb0a5dfb190.js → change-password-dialog-BKyyB0i6.81abe7a243de.js} +1 -1
  109. codex/static_root/assets/change-password-dialog-BKyyB0i6.81abe7a243de.js.br +0 -0
  110. codex/static_root/assets/change-password-dialog-BKyyB0i6.81abe7a243de.js.gz +0 -0
  111. codex/static_root/assets/{change-password-dialog-BbIO0YI5.js → change-password-dialog-BKyyB0i6.js} +1 -1
  112. codex/static_root/assets/change-password-dialog-BKyyB0i6.js.br +0 -0
  113. codex/static_root/assets/change-password-dialog-BKyyB0i6.js.gz +0 -0
  114. codex/static_root/assets/{confirm-dialog-BrzuoYAT.a0a1b6364708.js → confirm-dialog-CbDA0K1C.6fca78c3b9bf.js} +1 -1
  115. codex/static_root/assets/confirm-dialog-CbDA0K1C.6fca78c3b9bf.js.br +0 -0
  116. codex/static_root/assets/confirm-dialog-CbDA0K1C.6fca78c3b9bf.js.gz +0 -0
  117. codex/static_root/assets/{confirm-dialog-BrzuoYAT.js → confirm-dialog-CbDA0K1C.js} +1 -1
  118. codex/static_root/assets/confirm-dialog-CbDA0K1C.js.br +0 -0
  119. codex/static_root/assets/confirm-dialog-CbDA0K1C.js.gz +0 -0
  120. codex/static_root/assets/{datetime-column-D8-UeX_p.e33b1556805b.js → datetime-column-lzxYDDvK.055ffa7f271c.js} +1 -1
  121. codex/static_root/assets/datetime-column-lzxYDDvK.055ffa7f271c.js.br +0 -0
  122. codex/static_root/assets/datetime-column-lzxYDDvK.055ffa7f271c.js.gz +0 -0
  123. codex/static_root/assets/{datetime-column-D8-UeX_p.js → datetime-column-lzxYDDvK.js} +1 -1
  124. codex/static_root/assets/datetime-column-lzxYDDvK.js.br +0 -0
  125. codex/static_root/assets/datetime-column-lzxYDDvK.js.gz +0 -0
  126. codex/static_root/assets/{filter-XMAX5Nmg.c6ed87350f7d.js → filter-SD2wRta_.2db402d82ae5.js} +1 -1
  127. codex/static_root/assets/filter-SD2wRta_.2db402d82ae5.js.br +0 -0
  128. codex/static_root/assets/filter-SD2wRta_.2db402d82ae5.js.gz +0 -0
  129. codex/static_root/assets/{filter-XMAX5Nmg.js → filter-SD2wRta_.js} +1 -1
  130. codex/static_root/assets/filter-SD2wRta_.js.br +0 -0
  131. codex/static_root/assets/filter-SD2wRta_.js.gz +0 -0
  132. codex/static_root/assets/flag-tab-Caak9VvH.643528c944e7.js +1 -0
  133. codex/static_root/assets/flag-tab-Caak9VvH.643528c944e7.js.br +0 -0
  134. codex/static_root/assets/flag-tab-Caak9VvH.643528c944e7.js.gz +0 -0
  135. codex/static_root/assets/flag-tab-Caak9VvH.js +1 -0
  136. codex/static_root/assets/flag-tab-Caak9VvH.js.br +0 -0
  137. codex/static_root/assets/flag-tab-Caak9VvH.js.gz +0 -0
  138. codex/static_root/assets/flag-tab-DBqpLKi7.css +1 -0
  139. codex/static_root/assets/flag-tab-DBqpLKi7.css.br +0 -0
  140. codex/static_root/assets/flag-tab-DBqpLKi7.css.gz +0 -0
  141. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css +1 -0
  142. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.br +0 -0
  143. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.gz +0 -0
  144. codex/static_root/assets/{group-tab-D9n5gZCA.634223001c44.js → group-tab-DI7cBTNB.8042c34ec394.js} +1 -1
  145. codex/static_root/assets/group-tab-DI7cBTNB.8042c34ec394.js.br +0 -0
  146. codex/static_root/assets/group-tab-DI7cBTNB.8042c34ec394.js.gz +0 -0
  147. codex/static_root/assets/{group-tab-D9n5gZCA.js → group-tab-DI7cBTNB.js} +1 -1
  148. codex/static_root/assets/group-tab-DI7cBTNB.js.br +0 -0
  149. codex/static_root/assets/group-tab-DI7cBTNB.js.gz +0 -0
  150. codex/static_root/assets/{http-error-C_EFLi0c.c7e906206b62.js → http-error-BpbtQXBu.5ac5d9dfb219.js} +1 -1
  151. codex/static_root/assets/http-error-BpbtQXBu.5ac5d9dfb219.js.br +0 -0
  152. codex/static_root/assets/http-error-BpbtQXBu.5ac5d9dfb219.js.gz +0 -0
  153. codex/static_root/assets/{http-error-C_EFLi0c.js → http-error-BpbtQXBu.js} +1 -1
  154. codex/static_root/assets/http-error-BpbtQXBu.js.br +0 -0
  155. codex/static_root/assets/http-error-BpbtQXBu.js.gz +0 -0
  156. codex/static_root/assets/{library-tab-fDxuhPBs.285b36d9cec0.js → library-tab-DFEha1Cd.e0c6cde24a27.js} +1 -1
  157. codex/static_root/assets/library-tab-DFEha1Cd.e0c6cde24a27.js.br +0 -0
  158. codex/static_root/assets/library-tab-DFEha1Cd.e0c6cde24a27.js.gz +0 -0
  159. codex/static_root/assets/{library-tab-fDxuhPBs.js → library-tab-DFEha1Cd.js} +1 -1
  160. codex/static_root/assets/library-tab-DFEha1Cd.js.br +0 -0
  161. codex/static_root/assets/library-tab-DFEha1Cd.js.gz +0 -0
  162. codex/static_root/assets/main-hKTXzzX1.6888db202b7a.js +6 -0
  163. codex/static_root/assets/main-hKTXzzX1.6888db202b7a.js.br +0 -0
  164. codex/static_root/assets/main-hKTXzzX1.6888db202b7a.js.gz +0 -0
  165. codex/static_root/assets/main-hKTXzzX1.js +6 -0
  166. codex/static_root/assets/main-hKTXzzX1.js.br +0 -0
  167. codex/static_root/assets/main-hKTXzzX1.js.gz +0 -0
  168. codex/static_root/assets/{pagination-toolbar-BD6nzIKF.f3ca4874c203.js → pagination-toolbar-nUqE7Y6_.573598728e43.js} +1 -1
  169. codex/static_root/assets/pagination-toolbar-nUqE7Y6_.573598728e43.js.br +0 -0
  170. codex/static_root/assets/pagination-toolbar-nUqE7Y6_.573598728e43.js.gz +0 -0
  171. codex/static_root/assets/{pagination-toolbar-BD6nzIKF.js → pagination-toolbar-nUqE7Y6_.js} +1 -1
  172. codex/static_root/assets/pagination-toolbar-nUqE7Y6_.js.br +0 -0
  173. codex/static_root/assets/pagination-toolbar-nUqE7Y6_.js.gz +0 -0
  174. codex/static_root/assets/{pdf-doc-iF15lKRp.de9a9d394438.js → pdf-doc-LW8r9w5L.0fc8e96441a3.js} +1 -1
  175. codex/static_root/assets/pdf-doc-LW8r9w5L.0fc8e96441a3.js.br +0 -0
  176. codex/static_root/assets/pdf-doc-LW8r9w5L.0fc8e96441a3.js.gz +0 -0
  177. codex/static_root/assets/{pdf-doc-iF15lKRp.js → pdf-doc-LW8r9w5L.js} +1 -1
  178. codex/static_root/assets/pdf-doc-LW8r9w5L.js.br +0 -0
  179. codex/static_root/assets/pdf-doc-LW8r9w5L.js.gz +0 -0
  180. codex/static_root/assets/{reader-5Ja_bAaT.2fe33a3891f6.js → reader-DfCdn4RV.e821068881fd.js} +2 -2
  181. codex/static_root/assets/reader-DfCdn4RV.e821068881fd.js.br +0 -0
  182. codex/static_root/assets/reader-DfCdn4RV.e821068881fd.js.gz +0 -0
  183. codex/static_root/assets/{reader-5Ja_bAaT.js → reader-DfCdn4RV.js} +2 -2
  184. codex/static_root/assets/reader-DfCdn4RV.js.br +0 -0
  185. codex/static_root/assets/reader-DfCdn4RV.js.gz +0 -0
  186. codex/static_root/assets/{relation-chips-CUWkvLNo.3d18d0c09d39.js → relation-chips-iwVvmmvT.9e8ef037d134.js} +1 -1
  187. codex/static_root/assets/relation-chips-iwVvmmvT.9e8ef037d134.js.br +0 -0
  188. codex/static_root/assets/relation-chips-iwVvmmvT.9e8ef037d134.js.gz +0 -0
  189. codex/static_root/assets/{relation-chips-CUWkvLNo.js → relation-chips-iwVvmmvT.js} +1 -1
  190. codex/static_root/assets/relation-chips-iwVvmmvT.js.br +0 -0
  191. codex/static_root/assets/relation-chips-iwVvmmvT.js.gz +0 -0
  192. codex/static_root/assets/{settings-drawer-rn3JdMxA.js → settings-drawer-D_S8wFKC.d68db990933d.js} +2 -2
  193. codex/static_root/assets/settings-drawer-D_S8wFKC.d68db990933d.js.br +0 -0
  194. codex/static_root/assets/settings-drawer-D_S8wFKC.d68db990933d.js.gz +0 -0
  195. codex/static_root/assets/{settings-drawer-rn3JdMxA.a9d7b45c2138.js → settings-drawer-D_S8wFKC.js} +2 -2
  196. codex/static_root/assets/settings-drawer-D_S8wFKC.js.br +0 -0
  197. codex/static_root/assets/settings-drawer-D_S8wFKC.js.gz +0 -0
  198. codex/static_root/assets/stats-tab-CI0u-X7Y.2d1b6a0d4139.css +1 -0
  199. codex/static_root/assets/stats-tab-CI0u-X7Y.2d1b6a0d4139.css.br +0 -0
  200. codex/static_root/assets/stats-tab-CI0u-X7Y.2d1b6a0d4139.css.gz +0 -0
  201. codex/static_root/assets/stats-tab-CI0u-X7Y.css +1 -0
  202. codex/static_root/assets/stats-tab-CI0u-X7Y.css.br +0 -0
  203. codex/static_root/assets/stats-tab-CI0u-X7Y.css.gz +0 -0
  204. codex/static_root/assets/stats-tab-DD5sxuw1.29a98d090716.js +1 -0
  205. codex/static_root/assets/stats-tab-DD5sxuw1.29a98d090716.js.br +0 -0
  206. codex/static_root/assets/stats-tab-DD5sxuw1.29a98d090716.js.gz +0 -0
  207. codex/static_root/assets/stats-tab-DD5sxuw1.js +1 -0
  208. codex/static_root/assets/stats-tab-DD5sxuw1.js.br +0 -0
  209. codex/static_root/assets/stats-tab-DD5sxuw1.js.gz +0 -0
  210. codex/static_root/assets/{task-tab-CbzDX0IR.7b43bdf9cf42.js → task-tab-DDrdraG5.ddc487971339.js} +1 -1
  211. codex/static_root/assets/task-tab-DDrdraG5.ddc487971339.js.br +0 -0
  212. codex/static_root/assets/task-tab-DDrdraG5.ddc487971339.js.gz +0 -0
  213. codex/static_root/assets/{task-tab-CbzDX0IR.js → task-tab-DDrdraG5.js} +1 -1
  214. codex/static_root/assets/task-tab-DDrdraG5.js.br +0 -0
  215. codex/static_root/assets/task-tab-DDrdraG5.js.gz +0 -0
  216. codex/static_root/assets/{unauthorized-CllrtnFV.2a18fab3dd41.js → unauthorized-BMsnj48f.512d881936ab.js} +1 -1
  217. codex/static_root/assets/unauthorized-BMsnj48f.512d881936ab.js.br +0 -0
  218. codex/static_root/assets/unauthorized-BMsnj48f.512d881936ab.js.gz +0 -0
  219. codex/static_root/assets/{unauthorized-CllrtnFV.js → unauthorized-BMsnj48f.js} +1 -1
  220. codex/static_root/assets/unauthorized-BMsnj48f.js.br +0 -0
  221. codex/static_root/assets/unauthorized-BMsnj48f.js.gz +0 -0
  222. codex/static_root/assets/{user-tab-FY1xALpi.05a88f51df4f.js → user-tab-DSq5ht4e.5b70e9642a13.js} +1 -1
  223. codex/static_root/assets/user-tab-DSq5ht4e.5b70e9642a13.js.br +0 -0
  224. codex/static_root/assets/user-tab-DSq5ht4e.5b70e9642a13.js.gz +0 -0
  225. codex/static_root/assets/{user-tab-FY1xALpi.js → user-tab-DSq5ht4e.js} +1 -1
  226. codex/static_root/assets/user-tab-DSq5ht4e.js.br +0 -0
  227. codex/static_root/assets/user-tab-DSq5ht4e.js.gz +0 -0
  228. codex/static_root/{manifest.166aa32817b1.json → manifest.342051b44ea0.json} +216 -216
  229. codex/static_root/manifest.342051b44ea0.json.br +0 -0
  230. codex/static_root/manifest.342051b44ea0.json.gz +0 -0
  231. codex/static_root/manifest.json +216 -216
  232. codex/static_root/manifest.json.br +0 -0
  233. codex/static_root/manifest.json.gz +0 -0
  234. codex/static_root/staticfiles.json +1 -1
  235. codex/urls/root.py +12 -2
  236. codex/views/admin/stats.py +38 -186
  237. codex/views/opds/v1/entry/entry.py +14 -18
  238. codex/views/opds/v1/feed.py +5 -1
  239. codex/views/opds/v1/links.py +1 -0
  240. codex/views/reader/arcs.py +5 -4
  241. {codex-1.6.3.dist-info → codex-1.6.5.dist-info}/METADATA +18 -7
  242. {codex-1.6.3.dist-info → codex-1.6.5.dist-info}/RECORD +245 -245
  243. codex/settings/logging.py +0 -20
  244. codex/static_root/assets/VCheckbox-CXQlndFT.c17c006a62e6.js.br +0 -0
  245. codex/static_root/assets/VCheckbox-CXQlndFT.c17c006a62e6.js.gz +0 -0
  246. codex/static_root/assets/VCheckbox-CXQlndFT.js.br +0 -0
  247. codex/static_root/assets/VCheckbox-CXQlndFT.js.gz +0 -0
  248. codex/static_root/assets/VCheckboxBtn-DB72Bclg.ab414c6ae2b8.js.br +0 -0
  249. codex/static_root/assets/VCheckboxBtn-DB72Bclg.ab414c6ae2b8.js.gz +0 -0
  250. codex/static_root/assets/VCheckboxBtn-DB72Bclg.js.br +0 -0
  251. codex/static_root/assets/VCheckboxBtn-DB72Bclg.js.gz +0 -0
  252. codex/static_root/assets/VCombobox-BDcFPzYf.0b80447cd638.js.br +0 -0
  253. codex/static_root/assets/VCombobox-BDcFPzYf.0b80447cd638.js.gz +0 -0
  254. codex/static_root/assets/VCombobox-BDcFPzYf.js.br +0 -0
  255. codex/static_root/assets/VCombobox-BDcFPzYf.js.gz +0 -0
  256. codex/static_root/assets/VDialog-BB4zqrGw.2decc14ea597.js.br +0 -0
  257. codex/static_root/assets/VDialog-BB4zqrGw.2decc14ea597.js.gz +0 -0
  258. codex/static_root/assets/VDialog-BB4zqrGw.js.br +0 -0
  259. codex/static_root/assets/VDialog-BB4zqrGw.js.gz +0 -0
  260. codex/static_root/assets/VExpansionPanels-SZc735F5.19004a0eba16.js.br +0 -0
  261. codex/static_root/assets/VExpansionPanels-SZc735F5.19004a0eba16.js.gz +0 -0
  262. codex/static_root/assets/VExpansionPanels-SZc735F5.js.br +0 -0
  263. codex/static_root/assets/VExpansionPanels-SZc735F5.js.gz +0 -0
  264. codex/static_root/assets/VRadioGroup-tFEuhFRq.774e14a4945a.js.br +0 -0
  265. codex/static_root/assets/VRadioGroup-tFEuhFRq.774e14a4945a.js.gz +0 -0
  266. codex/static_root/assets/VRadioGroup-tFEuhFRq.js.br +0 -0
  267. codex/static_root/assets/VRadioGroup-tFEuhFRq.js.gz +0 -0
  268. codex/static_root/assets/VSelect-Dd5Zy8Uy.f225abf824ff.js.br +0 -0
  269. codex/static_root/assets/VSelect-Dd5Zy8Uy.f225abf824ff.js.gz +0 -0
  270. codex/static_root/assets/VSelect-Dd5Zy8Uy.js.br +0 -0
  271. codex/static_root/assets/VSelect-Dd5Zy8Uy.js.gz +0 -0
  272. codex/static_root/assets/VSelectionControl-DImIQPJV.1f14d2113063.js.br +0 -0
  273. codex/static_root/assets/VSelectionControl-DImIQPJV.1f14d2113063.js.gz +0 -0
  274. codex/static_root/assets/VSelectionControl-DImIQPJV.js.br +0 -0
  275. codex/static_root/assets/VSelectionControl-DImIQPJV.js.gz +0 -0
  276. codex/static_root/assets/VSlideGroup-CDaAHRAK.783800d70a8a.js.br +0 -0
  277. codex/static_root/assets/VSlideGroup-CDaAHRAK.783800d70a8a.js.gz +0 -0
  278. codex/static_root/assets/VSlideGroup-CDaAHRAK.js.br +0 -0
  279. codex/static_root/assets/VSlideGroup-CDaAHRAK.js.gz +0 -0
  280. codex/static_root/assets/VTable-CkCZonsu.81e34381271f.js.br +0 -0
  281. codex/static_root/assets/VTable-CkCZonsu.81e34381271f.js.gz +0 -0
  282. codex/static_root/assets/VTable-CkCZonsu.js.br +0 -0
  283. codex/static_root/assets/VTable-CkCZonsu.js.gz +0 -0
  284. codex/static_root/assets/VTextField-fNAzFu1M.00dec8623f18.js.br +0 -0
  285. codex/static_root/assets/VTextField-fNAzFu1M.00dec8623f18.js.gz +0 -0
  286. codex/static_root/assets/VTextField-fNAzFu1M.js.br +0 -0
  287. codex/static_root/assets/VTextField-fNAzFu1M.js.gz +0 -0
  288. codex/static_root/assets/VWindowItem-_YBMW1SU.0836924f8c12.js.br +0 -0
  289. codex/static_root/assets/VWindowItem-_YBMW1SU.0836924f8c12.js.gz +0 -0
  290. codex/static_root/assets/VWindowItem-_YBMW1SU.js.br +0 -0
  291. codex/static_root/assets/VWindowItem-_YBMW1SU.js.gz +0 -0
  292. codex/static_root/assets/admin-DYmGyJVg.262e6032ee86.js.br +0 -0
  293. codex/static_root/assets/admin-DYmGyJVg.262e6032ee86.js.gz +0 -0
  294. codex/static_root/assets/admin-DYmGyJVg.js.br +0 -0
  295. codex/static_root/assets/admin-DYmGyJVg.js.gz +0 -0
  296. codex/static_root/assets/admin-drawer-panel-c3f3H29x.fa2b12c75b06.js.br +0 -0
  297. codex/static_root/assets/admin-drawer-panel-c3f3H29x.fa2b12c75b06.js.gz +0 -0
  298. codex/static_root/assets/admin-drawer-panel-c3f3H29x.js.br +0 -0
  299. codex/static_root/assets/admin-drawer-panel-c3f3H29x.js.gz +0 -0
  300. codex/static_root/assets/browser-Ck3zWCOk.d98c77747e6d.js.br +0 -0
  301. codex/static_root/assets/browser-Ck3zWCOk.d98c77747e6d.js.gz +0 -0
  302. codex/static_root/assets/browser-Ck3zWCOk.js.br +0 -0
  303. codex/static_root/assets/browser-Ck3zWCOk.js.gz +0 -0
  304. codex/static_root/assets/browser-DgawKPSA.c7cf59dc4b21.css.br +0 -0
  305. codex/static_root/assets/browser-DgawKPSA.c7cf59dc4b21.css.gz +0 -0
  306. codex/static_root/assets/browser-DgawKPSA.css.br +0 -0
  307. codex/static_root/assets/browser-DgawKPSA.css.gz +0 -0
  308. codex/static_root/assets/change-password-dialog-BbIO0YI5.2bb0a5dfb190.js.br +0 -0
  309. codex/static_root/assets/change-password-dialog-BbIO0YI5.2bb0a5dfb190.js.gz +0 -0
  310. codex/static_root/assets/change-password-dialog-BbIO0YI5.js.br +0 -0
  311. codex/static_root/assets/change-password-dialog-BbIO0YI5.js.gz +0 -0
  312. codex/static_root/assets/confirm-dialog-BrzuoYAT.a0a1b6364708.js.br +0 -0
  313. codex/static_root/assets/confirm-dialog-BrzuoYAT.a0a1b6364708.js.gz +0 -0
  314. codex/static_root/assets/confirm-dialog-BrzuoYAT.js.br +0 -0
  315. codex/static_root/assets/confirm-dialog-BrzuoYAT.js.gz +0 -0
  316. codex/static_root/assets/datetime-column-D8-UeX_p.e33b1556805b.js.br +0 -0
  317. codex/static_root/assets/datetime-column-D8-UeX_p.e33b1556805b.js.gz +0 -0
  318. codex/static_root/assets/datetime-column-D8-UeX_p.js.br +0 -0
  319. codex/static_root/assets/datetime-column-D8-UeX_p.js.gz +0 -0
  320. codex/static_root/assets/filter-XMAX5Nmg.c6ed87350f7d.js.br +0 -0
  321. codex/static_root/assets/filter-XMAX5Nmg.c6ed87350f7d.js.gz +0 -0
  322. codex/static_root/assets/filter-XMAX5Nmg.js.br +0 -0
  323. codex/static_root/assets/filter-XMAX5Nmg.js.gz +0 -0
  324. codex/static_root/assets/flag-tab-BLEUVMot.c14936c90346.js +0 -1
  325. codex/static_root/assets/flag-tab-BLEUVMot.c14936c90346.js.br +0 -0
  326. codex/static_root/assets/flag-tab-BLEUVMot.c14936c90346.js.gz +0 -0
  327. codex/static_root/assets/flag-tab-BLEUVMot.js +0 -1
  328. codex/static_root/assets/flag-tab-BLEUVMot.js.br +0 -0
  329. codex/static_root/assets/flag-tab-BLEUVMot.js.gz +0 -0
  330. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css +0 -1
  331. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.br +0 -0
  332. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.gz +0 -0
  333. codex/static_root/assets/flag-tab-BNwbLfrN.css +0 -1
  334. codex/static_root/assets/flag-tab-BNwbLfrN.css.br +0 -0
  335. codex/static_root/assets/flag-tab-BNwbLfrN.css.gz +0 -0
  336. codex/static_root/assets/group-tab-D9n5gZCA.634223001c44.js.br +0 -0
  337. codex/static_root/assets/group-tab-D9n5gZCA.634223001c44.js.gz +0 -0
  338. codex/static_root/assets/group-tab-D9n5gZCA.js.br +0 -0
  339. codex/static_root/assets/group-tab-D9n5gZCA.js.gz +0 -0
  340. codex/static_root/assets/http-error-C_EFLi0c.c7e906206b62.js.br +0 -0
  341. codex/static_root/assets/http-error-C_EFLi0c.c7e906206b62.js.gz +0 -0
  342. codex/static_root/assets/http-error-C_EFLi0c.js.br +0 -0
  343. codex/static_root/assets/http-error-C_EFLi0c.js.gz +0 -0
  344. codex/static_root/assets/library-tab-fDxuhPBs.285b36d9cec0.js.br +0 -0
  345. codex/static_root/assets/library-tab-fDxuhPBs.285b36d9cec0.js.gz +0 -0
  346. codex/static_root/assets/library-tab-fDxuhPBs.js.br +0 -0
  347. codex/static_root/assets/library-tab-fDxuhPBs.js.gz +0 -0
  348. codex/static_root/assets/main-B3MfqYNN.30d1310fc082.js +0 -6
  349. codex/static_root/assets/main-B3MfqYNN.30d1310fc082.js.br +0 -0
  350. codex/static_root/assets/main-B3MfqYNN.30d1310fc082.js.gz +0 -0
  351. codex/static_root/assets/main-B3MfqYNN.js +0 -6
  352. codex/static_root/assets/main-B3MfqYNN.js.br +0 -0
  353. codex/static_root/assets/main-B3MfqYNN.js.gz +0 -0
  354. codex/static_root/assets/pagination-toolbar-BD6nzIKF.f3ca4874c203.js.br +0 -0
  355. codex/static_root/assets/pagination-toolbar-BD6nzIKF.f3ca4874c203.js.gz +0 -0
  356. codex/static_root/assets/pagination-toolbar-BD6nzIKF.js.br +0 -0
  357. codex/static_root/assets/pagination-toolbar-BD6nzIKF.js.gz +0 -0
  358. codex/static_root/assets/pdf-doc-iF15lKRp.de9a9d394438.js.br +0 -0
  359. codex/static_root/assets/pdf-doc-iF15lKRp.de9a9d394438.js.gz +0 -0
  360. codex/static_root/assets/pdf-doc-iF15lKRp.js.br +0 -0
  361. codex/static_root/assets/pdf-doc-iF15lKRp.js.gz +0 -0
  362. codex/static_root/assets/reader-5Ja_bAaT.2fe33a3891f6.js.br +0 -0
  363. codex/static_root/assets/reader-5Ja_bAaT.2fe33a3891f6.js.gz +0 -0
  364. codex/static_root/assets/reader-5Ja_bAaT.js.br +0 -0
  365. codex/static_root/assets/reader-5Ja_bAaT.js.gz +0 -0
  366. codex/static_root/assets/relation-chips-CUWkvLNo.3d18d0c09d39.js.br +0 -0
  367. codex/static_root/assets/relation-chips-CUWkvLNo.3d18d0c09d39.js.gz +0 -0
  368. codex/static_root/assets/relation-chips-CUWkvLNo.js.br +0 -0
  369. codex/static_root/assets/relation-chips-CUWkvLNo.js.gz +0 -0
  370. codex/static_root/assets/settings-drawer-rn3JdMxA.a9d7b45c2138.js.br +0 -0
  371. codex/static_root/assets/settings-drawer-rn3JdMxA.a9d7b45c2138.js.gz +0 -0
  372. codex/static_root/assets/settings-drawer-rn3JdMxA.js.br +0 -0
  373. codex/static_root/assets/settings-drawer-rn3JdMxA.js.gz +0 -0
  374. codex/static_root/assets/stats-tab-B6L-YFRA.1c90593f7b5c.css +0 -1
  375. codex/static_root/assets/stats-tab-B6L-YFRA.1c90593f7b5c.css.br +0 -0
  376. codex/static_root/assets/stats-tab-B6L-YFRA.1c90593f7b5c.css.gz +0 -0
  377. codex/static_root/assets/stats-tab-B6L-YFRA.css +0 -1
  378. codex/static_root/assets/stats-tab-B6L-YFRA.css.br +0 -0
  379. codex/static_root/assets/stats-tab-B6L-YFRA.css.gz +0 -0
  380. codex/static_root/assets/stats-tab-zts2Xsmg.9fb959ccf4da.js +0 -1
  381. codex/static_root/assets/stats-tab-zts2Xsmg.9fb959ccf4da.js.br +0 -0
  382. codex/static_root/assets/stats-tab-zts2Xsmg.9fb959ccf4da.js.gz +0 -0
  383. codex/static_root/assets/stats-tab-zts2Xsmg.js +0 -1
  384. codex/static_root/assets/stats-tab-zts2Xsmg.js.br +0 -0
  385. codex/static_root/assets/stats-tab-zts2Xsmg.js.gz +0 -0
  386. codex/static_root/assets/task-tab-CbzDX0IR.7b43bdf9cf42.js.br +0 -0
  387. codex/static_root/assets/task-tab-CbzDX0IR.7b43bdf9cf42.js.gz +0 -0
  388. codex/static_root/assets/task-tab-CbzDX0IR.js.br +0 -0
  389. codex/static_root/assets/task-tab-CbzDX0IR.js.gz +0 -0
  390. codex/static_root/assets/unauthorized-CllrtnFV.2a18fab3dd41.js.br +0 -0
  391. codex/static_root/assets/unauthorized-CllrtnFV.2a18fab3dd41.js.gz +0 -0
  392. codex/static_root/assets/unauthorized-CllrtnFV.js.br +0 -0
  393. codex/static_root/assets/unauthorized-CllrtnFV.js.gz +0 -0
  394. codex/static_root/assets/user-tab-FY1xALpi.05a88f51df4f.js.br +0 -0
  395. codex/static_root/assets/user-tab-FY1xALpi.05a88f51df4f.js.gz +0 -0
  396. codex/static_root/assets/user-tab-FY1xALpi.js.br +0 -0
  397. codex/static_root/assets/user-tab-FY1xALpi.js.gz +0 -0
  398. codex/static_root/manifest.166aa32817b1.json.br +0 -0
  399. codex/static_root/manifest.166aa32817b1.json.gz +0 -0
  400. {codex-1.6.3.dist-info → codex-1.6.5.dist-info}/LICENSE +0 -0
  401. {codex-1.6.3.dist-info → codex-1.6.5.dist-info}/WHEEL +0 -0
  402. {codex-1.6.3.dist-info → codex-1.6.5.dist-info}/entry_points.txt +0 -0
Binary file
Binary file
@@ -1 +1 @@
1
- {"paths": {"rest_framework/docs/js/api.js": "rest_framework/docs/js/api.18a5ba8a1bd8.js", "rest_framework/docs/js/jquery.json-view.min.js": "rest_framework/docs/js/jquery.json-view.min.b7c2d6981377.js", "rest_framework/docs/js/highlight.pack.js": "rest_framework/docs/js/highlight.pack.479b5f21dcba.js", "rest_framework/docs/img/favicon.ico": "rest_framework/docs/img/favicon.5195b4d0f3eb.ico", "rest_framework/docs/img/grid.png": "rest_framework/docs/img/grid.a4b938cf382b.png", "rest_framework/docs/css/jquery.json-view.min.css": "rest_framework/docs/css/jquery.json-view.min.a2e6beeb6710.css", "rest_framework/docs/css/highlight.css": "rest_framework/docs/css/highlight.e0e4d973c6d7.css", "rest_framework/docs/css/base.css": "rest_framework/docs/css/base.e630f8f4990e.css", "rest_framework/js/ajax-form.js": "rest_framework/js/ajax-form.4e1cdcb7acab.js", "rest_framework/js/csrf.js": "rest_framework/js/csrf.455080a7b2ce.js", "rest_framework/js/prettify-min.js": "rest_framework/js/prettify-min.709bfcc456c6.js", "rest_framework/js/jquery-3.7.1.min.js": "rest_framework/js/jquery-3.7.1.min.2c872dbe60f4.js", "rest_framework/js/default.js": "rest_framework/js/default.5b08897dbdc3.js", "rest_framework/js/bootstrap.min.js": "rest_framework/js/bootstrap.min.2f34b630ffe3.js", "rest_framework/js/coreapi-0.1.1.js": "rest_framework/js/coreapi-0.1.1.8851fb9336c9.js", "rest_framework/js/load-ajax-form.js": "rest_framework/js/load-ajax-form.8cdb3a9f3466.js", "rest_framework/fonts/fontawesome-webfont.woff": "rest_framework/fonts/fontawesome-webfont.3293616ec0c6.woff", "rest_framework/fonts/glyphicons-halflings-regular.eot": "rest_framework/fonts/glyphicons-halflings-regular.f4769f9bdb74.eot", "rest_framework/fonts/glyphicons-halflings-regular.ttf": "rest_framework/fonts/glyphicons-halflings-regular.e18bbf611f2a.ttf", "rest_framework/fonts/fontawesome-webfont.ttf": "rest_framework/fonts/fontawesome-webfont.dcb26c7239d8.ttf", "rest_framework/fonts/glyphicons-halflings-regular.woff2": "rest_framework/fonts/glyphicons-halflings-regular.448c34a56d69.woff2", "rest_framework/fonts/fontawesome-webfont.svg": "rest_framework/fonts/fontawesome-webfont.83e37a11f9d7.svg", "rest_framework/fonts/glyphicons-halflings-regular.woff": "rest_framework/fonts/glyphicons-halflings-regular.fa2772327f55.woff", "rest_framework/fonts/glyphicons-halflings-regular.svg": "rest_framework/fonts/glyphicons-halflings-regular.08eda92397ae.svg", "rest_framework/fonts/fontawesome-webfont.eot": "rest_framework/fonts/fontawesome-webfont.8b27bc96115c.eot", "rest_framework/img/glyphicons-halflings-white.png": "rest_framework/img/glyphicons-halflings-white.9bbc6e960299.png", "rest_framework/img/glyphicons-halflings.png": "rest_framework/img/glyphicons-halflings.90233c9067e9.png", "rest_framework/img/grid.png": "rest_framework/img/grid.a4b938cf382b.png", "rest_framework/css/bootstrap.min.css.map": "rest_framework/css/bootstrap.min.css.cafbda9c0e9e.map", "rest_framework/css/default.css": "rest_framework/css/default.789dfb5732d7.css", "rest_framework/css/bootstrap.min.css": "rest_framework/css/bootstrap.min.f17d4516b026.css", "rest_framework/css/prettify.css": "rest_framework/css/prettify.a987f72342ee.css", "rest_framework/css/bootstrap-theme.min.css": "rest_framework/css/bootstrap-theme.min.1d4b05b397c3.css", "rest_framework/css/bootstrap-tweaks.css": "rest_framework/css/bootstrap-tweaks.ee4ee6acf9eb.css", "rest_framework/css/font-awesome-4.0.3.css": "rest_framework/css/font-awesome-4.0.3.c1e1ea213abf.css", "rest_framework/css/bootstrap-theme.min.css.map": "rest_framework/css/bootstrap-theme.min.css.51806092cc05.map", "img/publisher.svg": "img/publisher.82d378fcd601.svg", "img/logo-32.webp": "img/logo-32.5688944495bf.webp", "img/logo.svg": "img/logo.0f5344a028ca.svg", "img/story-arc.svg": "img/story-arc.ca10014355ef.svg", "img/missing-cover-165.webp": "img/missing-cover-165.0743171f2148.webp", "img/series.svg": "img/series.ec8a889b8f95.svg", "img/logo-maskable-180.webp": "img/logo-maskable-180.c58d966aa64e.webp", "img/missing-cover.svg": "img/missing-cover.ddb038cc2c56.svg", "img/folder.svg": "img/folder.f28936a3701d.svg", "img/volume.svg": "img/volume.814e4c79461a.svg", "img/logo-maskable.svg": "img/logo-maskable.8f7de7f1c6a8.svg", "img/imprint.svg": "img/imprint.7c2adebb76d6.svg", "pwa/offline.html": "pwa/offline.7bfaf9f94bf9.html", "js/choices.json": "js/choices.2f6b0359e1ef.json", "js/choices-admin.json": "js/choices-admin.3521e2a863df.json", "assets/group-tab-CBKuS3Iv.css": "assets/group-tab-CBKuS3Iv.7e4746634782.css", "assets/http-error-DKulXuTl.css": "assets/http-error-DKulXuTl.95e42988d5d5.css", "assets/VSelect-ARDhJiQK.css": "assets/VSelect-ARDhJiQK.372c098fb475.css", "assets/flag-tab-BNwbLfrN.css": "assets/flag-tab-BNwbLfrN.b755a99fff7e.css", "assets/VTable-CkCZonsu.js": "assets/VTable-CkCZonsu.81e34381271f.js", "assets/VSelectionControl-BFq--28I.css": "assets/VSelectionControl-BFq--28I.9687c77461fc.css", "assets/filter-XMAX5Nmg.js": "assets/filter-XMAX5Nmg.c6ed87350f7d.js", "assets/VWindowItem-_YBMW1SU.js": "assets/VWindowItem-_YBMW1SU.0836924f8c12.js", "assets/pdf-doc-CMzaSV_K.css": "assets/pdf-doc-CMzaSV_K.8cd4b3e65f9a.css", "assets/settings-drawer-rn3JdMxA.js": "assets/settings-drawer-rn3JdMxA.a9d7b45c2138.js", "assets/library-tab-fDxuhPBs.js": "assets/library-tab-fDxuhPBs.285b36d9cec0.js", "assets/VTextField-fNAzFu1M.js": "assets/VTextField-fNAzFu1M.00dec8623f18.js", "assets/admin-drawer-panel-c3f3H29x.js": "assets/admin-drawer-panel-c3f3H29x.fa2b12c75b06.js", "assets/VSelectionControl-DImIQPJV.js": "assets/VSelectionControl-DImIQPJV.1f14d2113063.js", "assets/VRadioGroup-tFEuhFRq.js": "assets/VRadioGroup-tFEuhFRq.774e14a4945a.js", "assets/materialdesignicons-webfont-PXm3-2wK.woff": "assets/materialdesignicons-webfont-PXm3-2wK.026b7ac9c43c.woff", "assets/VSlideGroup-Dk_1upHt.css": "assets/VSlideGroup-Dk_1upHt.2c836070ec75.css", "assets/relation-chips-CUWkvLNo.js": "assets/relation-chips-CUWkvLNo.3d18d0c09d39.js", "assets/admin-drawer-panel-mne3FIj6.css": "assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css", "assets/VTable-DflzroDq.css": "assets/VTable-DflzroDq.160504d82195.css", "assets/settings-drawer-nZ9HvKSZ.css": "assets/settings-drawer-nZ9HvKSZ.01744e131806.css", "assets/VDialog-lQ13FnRR.css": "assets/VDialog-lQ13FnRR.1c801ad756b2.css", "assets/relation-chips-BGitp3yx.css": "assets/relation-chips-BGitp3yx.b3e7d178a615.css", "assets/VCombobox-BDcFPzYf.js": "assets/VCombobox-BDcFPzYf.0b80447cd638.js", "assets/main-Ztp855PW.css": "assets/main-Ztp855PW.d46d718fac45.css", "assets/change-password-dialog-BbIO0YI5.js": "assets/change-password-dialog-BbIO0YI5.2bb0a5dfb190.js", "assets/VRadioGroup-i2qP9Wu9.css": "assets/VRadioGroup-i2qP9Wu9.8e3741381961.css", "assets/admin-D4sw3N4T.css": "assets/admin-D4sw3N4T.b590f88a62cf.css", "assets/unauthorized-CllrtnFV.js": "assets/unauthorized-CllrtnFV.2a18fab3dd41.js", "assets/reader-YbzUiD0T.css": "assets/reader-YbzUiD0T.efb15835b39d.css", "assets/change-password-dialog-0u6IJA87.css": "assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css", "assets/copy-to-clipboard-DoUvDJVx.js": "assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js", "assets/main-B3MfqYNN.js": "assets/main-B3MfqYNN.30d1310fc082.js", "assets/pagination-toolbar-BD6nzIKF.js": "assets/pagination-toolbar-BD6nzIKF.f3ca4874c203.js", "assets/VWindowItem-ByIod57Y.css": "assets/VWindowItem-ByIod57Y.f7fb19752bf3.css", "assets/VDialog-BB4zqrGw.js": "assets/VDialog-BB4zqrGw.2decc14ea597.js", "assets/pagination-toolbar-BA9ifTed.css": "assets/pagination-toolbar-BA9ifTed.b4865334ee08.css", "assets/library-tab-BygwYPnO.css": "assets/library-tab-BygwYPnO.94e92aa60bf2.css", "assets/reader-5Ja_bAaT.js": "assets/reader-5Ja_bAaT.2fe33a3891f6.js", "assets/stats-tab-B6L-YFRA.css": "assets/stats-tab-B6L-YFRA.1c90593f7b5c.css", "assets/user-tab-FY1xALpi.js": "assets/user-tab-FY1xALpi.05a88f51df4f.js", "assets/stats-tab-zts2Xsmg.js": "assets/stats-tab-zts2Xsmg.9fb959ccf4da.js", "assets/confirm-dialog-BmhedLCx.css": "assets/confirm-dialog-BmhedLCx.7c2103d319d4.css", "assets/datetime-column-D8-UeX_p.js": "assets/datetime-column-D8-UeX_p.e33b1556805b.js", "assets/materialdesignicons-webfont-B7mPwVP_.ttf": "assets/materialdesignicons-webfont-B7mPwVP_.6e435534bd35.ttf", "assets/VCombobox-BksEr4D_.css": "assets/VCombobox-BksEr4D_.73429bb75f42.css", "assets/confirm-dialog-BrzuoYAT.js": "assets/confirm-dialog-BrzuoYAT.a0a1b6364708.js", "assets/browser-DgawKPSA.css": "assets/browser-DgawKPSA.c7cf59dc4b21.css", "assets/VCheckbox-CXQlndFT.js": "assets/VCheckbox-CXQlndFT.c17c006a62e6.js", "assets/task-tab-1XiWn9xP.css": "assets/task-tab-1XiWn9xP.06cb8e1b794d.css", "assets/VExpansionPanels-SZc735F5.js": "assets/VExpansionPanels-SZc735F5.19004a0eba16.js", "assets/pdf-doc-iF15lKRp.js": "assets/pdf-doc-iF15lKRp.de9a9d394438.js", "assets/task-tab-CbzDX0IR.js": "assets/task-tab-CbzDX0IR.7b43bdf9cf42.js", "assets/datetime-column-DeCthByU.css": "assets/datetime-column-DeCthByU.1f3bf499e063.css", "assets/materialdesignicons-webfont-CSr8KVlo.eot": "assets/materialdesignicons-webfont-CSr8KVlo.8ced95a05e3c.eot", "assets/admin-DYmGyJVg.js": "assets/admin-DYmGyJVg.262e6032ee86.js", "assets/flag-tab-BLEUVMot.js": "assets/flag-tab-BLEUVMot.c14936c90346.js", "assets/unauthorized-DWDO1s6-.css": "assets/unauthorized-DWDO1s6-.d34daac27dcf.css", "assets/VSlideGroup-CDaAHRAK.js": "assets/VSlideGroup-CDaAHRAK.783800d70a8a.js", "assets/VSelect-Dd5Zy8Uy.js": "assets/VSelect-Dd5Zy8Uy.f225abf824ff.js", "assets/http-error-C_EFLi0c.js": "assets/http-error-C_EFLi0c.c7e906206b62.js", "assets/group-tab-D9n5gZCA.js": "assets/group-tab-D9n5gZCA.634223001c44.js", "assets/VExpansionPanels-DsEXVcCv.css": "assets/VExpansionPanels-DsEXVcCv.20b475255e66.css", "assets/VCheckboxBtn-DB72Bclg.js": "assets/VCheckboxBtn-DB72Bclg.ab414c6ae2b8.js", "assets/VCheckbox-CMKdyl0R.css": "assets/VCheckbox-CMKdyl0R.016ed8d222c4.css", "assets/VTextField-BssVoDhB.css": "assets/VTextField-BssVoDhB.4cc388b4aa3c.css", "assets/materialdesignicons-webfont-Dp5v-WZN.woff2": "assets/materialdesignicons-webfont-Dp5v-WZN.1d7bcee1b302.woff2", "assets/browser-Ck3zWCOk.js": "assets/browser-Ck3zWCOk.d98c77747e6d.js", "robots.txt": "robots.b6216d61c03e.txt", "manifest.json": "manifest.166aa32817b1.json"}, "version": "1.1", "hash": "704d3fcae5ee"}
1
+ {"paths": {"rest_framework/docs/js/api.js": "rest_framework/docs/js/api.18a5ba8a1bd8.js", "rest_framework/docs/js/jquery.json-view.min.js": "rest_framework/docs/js/jquery.json-view.min.b7c2d6981377.js", "rest_framework/docs/js/highlight.pack.js": "rest_framework/docs/js/highlight.pack.479b5f21dcba.js", "rest_framework/docs/img/favicon.ico": "rest_framework/docs/img/favicon.5195b4d0f3eb.ico", "rest_framework/docs/img/grid.png": "rest_framework/docs/img/grid.a4b938cf382b.png", "rest_framework/docs/css/jquery.json-view.min.css": "rest_framework/docs/css/jquery.json-view.min.a2e6beeb6710.css", "rest_framework/docs/css/highlight.css": "rest_framework/docs/css/highlight.e0e4d973c6d7.css", "rest_framework/docs/css/base.css": "rest_framework/docs/css/base.e630f8f4990e.css", "rest_framework/js/ajax-form.js": "rest_framework/js/ajax-form.4e1cdcb7acab.js", "rest_framework/js/csrf.js": "rest_framework/js/csrf.455080a7b2ce.js", "rest_framework/js/prettify-min.js": "rest_framework/js/prettify-min.709bfcc456c6.js", "rest_framework/js/jquery-3.7.1.min.js": "rest_framework/js/jquery-3.7.1.min.2c872dbe60f4.js", "rest_framework/js/default.js": "rest_framework/js/default.5b08897dbdc3.js", "rest_framework/js/bootstrap.min.js": "rest_framework/js/bootstrap.min.2f34b630ffe3.js", "rest_framework/js/coreapi-0.1.1.js": "rest_framework/js/coreapi-0.1.1.8851fb9336c9.js", "rest_framework/js/load-ajax-form.js": "rest_framework/js/load-ajax-form.8cdb3a9f3466.js", "rest_framework/fonts/fontawesome-webfont.woff": "rest_framework/fonts/fontawesome-webfont.3293616ec0c6.woff", "rest_framework/fonts/glyphicons-halflings-regular.eot": "rest_framework/fonts/glyphicons-halflings-regular.f4769f9bdb74.eot", "rest_framework/fonts/glyphicons-halflings-regular.ttf": "rest_framework/fonts/glyphicons-halflings-regular.e18bbf611f2a.ttf", "rest_framework/fonts/fontawesome-webfont.ttf": "rest_framework/fonts/fontawesome-webfont.dcb26c7239d8.ttf", "rest_framework/fonts/glyphicons-halflings-regular.woff2": "rest_framework/fonts/glyphicons-halflings-regular.448c34a56d69.woff2", "rest_framework/fonts/fontawesome-webfont.svg": "rest_framework/fonts/fontawesome-webfont.83e37a11f9d7.svg", "rest_framework/fonts/glyphicons-halflings-regular.woff": "rest_framework/fonts/glyphicons-halflings-regular.fa2772327f55.woff", "rest_framework/fonts/glyphicons-halflings-regular.svg": "rest_framework/fonts/glyphicons-halflings-regular.08eda92397ae.svg", "rest_framework/fonts/fontawesome-webfont.eot": "rest_framework/fonts/fontawesome-webfont.8b27bc96115c.eot", "rest_framework/img/glyphicons-halflings-white.png": "rest_framework/img/glyphicons-halflings-white.9bbc6e960299.png", "rest_framework/img/glyphicons-halflings.png": "rest_framework/img/glyphicons-halflings.90233c9067e9.png", "rest_framework/img/grid.png": "rest_framework/img/grid.a4b938cf382b.png", "rest_framework/css/bootstrap.min.css.map": "rest_framework/css/bootstrap.min.css.cafbda9c0e9e.map", "rest_framework/css/default.css": "rest_framework/css/default.789dfb5732d7.css", "rest_framework/css/bootstrap.min.css": "rest_framework/css/bootstrap.min.f17d4516b026.css", "rest_framework/css/prettify.css": "rest_framework/css/prettify.a987f72342ee.css", "rest_framework/css/bootstrap-theme.min.css": "rest_framework/css/bootstrap-theme.min.1d4b05b397c3.css", "rest_framework/css/bootstrap-tweaks.css": "rest_framework/css/bootstrap-tweaks.ee4ee6acf9eb.css", "rest_framework/css/font-awesome-4.0.3.css": "rest_framework/css/font-awesome-4.0.3.c1e1ea213abf.css", "rest_framework/css/bootstrap-theme.min.css.map": "rest_framework/css/bootstrap-theme.min.css.51806092cc05.map", "img/publisher.svg": "img/publisher.82d378fcd601.svg", "img/logo-32.webp": "img/logo-32.5688944495bf.webp", "img/logo.svg": "img/logo.0f5344a028ca.svg", "img/story-arc.svg": "img/story-arc.ca10014355ef.svg", "img/missing-cover-165.webp": "img/missing-cover-165.0743171f2148.webp", "img/series.svg": "img/series.ec8a889b8f95.svg", "img/logo-maskable-180.webp": "img/logo-maskable-180.c58d966aa64e.webp", "img/missing-cover.svg": "img/missing-cover.ddb038cc2c56.svg", "img/folder.svg": "img/folder.f28936a3701d.svg", "img/volume.svg": "img/volume.814e4c79461a.svg", "img/logo-maskable.svg": "img/logo-maskable.8f7de7f1c6a8.svg", "img/imprint.svg": "img/imprint.7c2adebb76d6.svg", "pwa/offline.html": "pwa/offline.7bfaf9f94bf9.html", "js/choices.json": "js/choices.2f6b0359e1ef.json", "js/choices-admin.json": "js/choices-admin.3521e2a863df.json", "assets/group-tab-CBKuS3Iv.css": "assets/group-tab-CBKuS3Iv.7e4746634782.css", "assets/http-error-DKulXuTl.css": "assets/http-error-DKulXuTl.95e42988d5d5.css", "assets/VSelect-ARDhJiQK.css": "assets/VSelect-ARDhJiQK.372c098fb475.css", "assets/filter-SD2wRta_.js": "assets/filter-SD2wRta_.2db402d82ae5.js", "assets/VSelectionControl-BFq--28I.css": "assets/VSelectionControl-BFq--28I.9687c77461fc.css", "assets/settings-drawer-D_S8wFKC.js": "assets/settings-drawer-D_S8wFKC.d68db990933d.js", "assets/VCheckboxBtn-BLEc6BrH.js": "assets/VCheckboxBtn-BLEc6BrH.e8ae3d2738e2.js", "assets/VCombobox-C18LIWGs.js": "assets/VCombobox-C18LIWGs.2a41fab61075.js", "assets/pdf-doc-CMzaSV_K.css": "assets/pdf-doc-CMzaSV_K.8cd4b3e65f9a.css", "assets/materialdesignicons-webfont-PXm3-2wK.woff": "assets/materialdesignicons-webfont-PXm3-2wK.026b7ac9c43c.woff", "assets/VSlideGroup-Dk_1upHt.css": "assets/VSlideGroup-Dk_1upHt.2c836070ec75.css", "assets/admin-drawer-panel-mne3FIj6.css": "assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css", "assets/VTable-DflzroDq.css": "assets/VTable-DflzroDq.160504d82195.css", "assets/settings-drawer-nZ9HvKSZ.css": "assets/settings-drawer-nZ9HvKSZ.01744e131806.css", "assets/VDialog-lQ13FnRR.css": "assets/VDialog-lQ13FnRR.1c801ad756b2.css", "assets/VWindowItem-IDCZgODl.js": "assets/VWindowItem-IDCZgODl.8c4527097642.js", "assets/user-tab-DSq5ht4e.js": "assets/user-tab-DSq5ht4e.5b70e9642a13.js", "assets/relation-chips-BGitp3yx.css": "assets/relation-chips-BGitp3yx.b3e7d178a615.css", "assets/main-Ztp855PW.css": "assets/main-Ztp855PW.d46d718fac45.css", "assets/VRadioGroup-i2qP9Wu9.css": "assets/VRadioGroup-i2qP9Wu9.8e3741381961.css", "assets/admin-drawer-panel-Can9sQIk.js": "assets/admin-drawer-panel-Can9sQIk.7021726ce8b9.js", "assets/VTextField-DhIkxARQ.js": "assets/VTextField-DhIkxARQ.e688815dc516.js", "assets/admin-D4sw3N4T.css": "assets/admin-D4sw3N4T.b590f88a62cf.css", "assets/stats-tab-DD5sxuw1.js": "assets/stats-tab-DD5sxuw1.29a98d090716.js", "assets/group-tab-DI7cBTNB.js": "assets/group-tab-DI7cBTNB.8042c34ec394.js", "assets/VSelectionControl-BpvvZpBd.js": "assets/VSelectionControl-BpvvZpBd.d83b413a38d1.js", "assets/flag-tab-Caak9VvH.js": "assets/flag-tab-Caak9VvH.643528c944e7.js", "assets/admin-DQMEj7xy.js": "assets/admin-DQMEj7xy.f249ade8981c.js", "assets/http-error-BpbtQXBu.js": "assets/http-error-BpbtQXBu.5ac5d9dfb219.js", "assets/datetime-column-lzxYDDvK.js": "assets/datetime-column-lzxYDDvK.055ffa7f271c.js", "assets/reader-YbzUiD0T.css": "assets/reader-YbzUiD0T.efb15835b39d.css", "assets/change-password-dialog-0u6IJA87.css": "assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css", "assets/unauthorized-BMsnj48f.js": "assets/unauthorized-BMsnj48f.512d881936ab.js", "assets/copy-to-clipboard-DoUvDJVx.js": "assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js", "assets/VWindowItem-ByIod57Y.css": "assets/VWindowItem-ByIod57Y.f7fb19752bf3.css", "assets/VTable-Dw1ASmYk.js": "assets/VTable-Dw1ASmYk.4e3817348a64.js", "assets/relation-chips-iwVvmmvT.js": "assets/relation-chips-iwVvmmvT.9e8ef037d134.js", "assets/pagination-toolbar-BA9ifTed.css": "assets/pagination-toolbar-BA9ifTed.b4865334ee08.css", "assets/library-tab-BygwYPnO.css": "assets/library-tab-BygwYPnO.94e92aa60bf2.css", "assets/reader-DfCdn4RV.js": "assets/reader-DfCdn4RV.e821068881fd.js", "assets/VCheckbox-OPrrn8D4.js": "assets/VCheckbox-OPrrn8D4.95d8259619aa.js", "assets/VSelect-BEOlJiRW.js": "assets/VSelect-BEOlJiRW.2d4996f0d6a3.js", "assets/confirm-dialog-CbDA0K1C.js": "assets/confirm-dialog-CbDA0K1C.6fca78c3b9bf.js", "assets/library-tab-DFEha1Cd.js": "assets/library-tab-DFEha1Cd.e0c6cde24a27.js", "assets/browser-Cy0OgQJC.css": "assets/browser-Cy0OgQJC.fabbd1aaffcf.css", "assets/confirm-dialog-BmhedLCx.css": "assets/confirm-dialog-BmhedLCx.7c2103d319d4.css", "assets/materialdesignicons-webfont-B7mPwVP_.ttf": "assets/materialdesignicons-webfont-B7mPwVP_.6e435534bd35.ttf", "assets/VCombobox-BksEr4D_.css": "assets/VCombobox-BksEr4D_.73429bb75f42.css", "assets/flag-tab-DBqpLKi7.css": "assets/flag-tab-DBqpLKi7.dcfef39f541e.css", "assets/VExpansionPanels-BrAdxiR-.js": "assets/VExpansionPanels-BrAdxiR-.f5e7507958b2.js", "assets/main-hKTXzzX1.js": "assets/main-hKTXzzX1.6888db202b7a.js", "assets/pagination-toolbar-nUqE7Y6_.js": "assets/pagination-toolbar-nUqE7Y6_.573598728e43.js", "assets/task-tab-1XiWn9xP.css": "assets/task-tab-1XiWn9xP.06cb8e1b794d.css", "assets/task-tab-DDrdraG5.js": "assets/task-tab-DDrdraG5.ddc487971339.js", "assets/change-password-dialog-BKyyB0i6.js": "assets/change-password-dialog-BKyyB0i6.81abe7a243de.js", "assets/VSlideGroup-Bv0lRnhB.js": "assets/VSlideGroup-Bv0lRnhB.e0b8f680bcbf.js", "assets/datetime-column-DeCthByU.css": "assets/datetime-column-DeCthByU.1f3bf499e063.css", "assets/materialdesignicons-webfont-CSr8KVlo.eot": "assets/materialdesignicons-webfont-CSr8KVlo.8ced95a05e3c.eot", "assets/unauthorized-DWDO1s6-.css": "assets/unauthorized-DWDO1s6-.d34daac27dcf.css", "assets/VRadioGroup-BWf1qZO1.js": "assets/VRadioGroup-BWf1qZO1.ee8a1b8d589d.js", "assets/stats-tab-CI0u-X7Y.css": "assets/stats-tab-CI0u-X7Y.2d1b6a0d4139.css", "assets/VDialog-DPlcZ188.js": "assets/VDialog-DPlcZ188.9398019bd69c.js", "assets/pdf-doc-LW8r9w5L.js": "assets/pdf-doc-LW8r9w5L.0fc8e96441a3.js", "assets/VExpansionPanels-DsEXVcCv.css": "assets/VExpansionPanels-DsEXVcCv.20b475255e66.css", "assets/browser-BOPyA0wB.js": "assets/browser-BOPyA0wB.b69c491ad88e.js", "assets/VCheckbox-CMKdyl0R.css": "assets/VCheckbox-CMKdyl0R.016ed8d222c4.css", "assets/VTextField-BssVoDhB.css": "assets/VTextField-BssVoDhB.4cc388b4aa3c.css", "assets/materialdesignicons-webfont-Dp5v-WZN.woff2": "assets/materialdesignicons-webfont-Dp5v-WZN.1d7bcee1b302.woff2", "robots.txt": "robots.b6216d61c03e.txt", "manifest.json": "manifest.342051b44ea0.json"}, "version": "1.1", "hash": "83a705fd3113"}
codex/urls/root.py CHANGED
@@ -7,7 +7,7 @@ from django.contrib.staticfiles.storage import staticfiles_storage
7
7
  from django.urls import include, path, register_converter, set_script_prefix
8
8
  from django.views.generic.base import RedirectView
9
9
 
10
- from codex.settings.settings import ROOT_PATH
10
+ from codex.settings.settings import DEBUG, ROOT_PATH
11
11
  from codex.urls.converters import GroupConverter, IntListConverter
12
12
 
13
13
  register_converter(GroupConverter, "group")
@@ -17,7 +17,17 @@ if ROOT_PATH:
17
17
  # Django 5 bug https://code.djangoproject.com/ticket/35169#comment:11
18
18
  set_script_prefix(ROOT_PATH)
19
19
 
20
- urlpatterns = [
20
+
21
+ urlpatterns = []
22
+ if DEBUG:
23
+ # Pyright doesn't follow logic so will try to find these types.
24
+ from schema_graph.views import Schema # type: ignore
25
+
26
+ urlpatterns += [
27
+ path("schema/", Schema.as_view()), # type: ignore
28
+ ]
29
+
30
+ urlpatterns += [
21
31
  path(
22
32
  "favicon.ico",
23
33
  RedirectView.as_view(url=staticfiles_storage.url("img/logo-32.webp")),
@@ -1,218 +1,70 @@
1
- """Admin Flag View."""
1
+ """Admin Stats View."""
2
2
 
3
- from multiprocessing import cpu_count
4
- from pathlib import Path
5
- from platform import machine, python_version, release, system
6
- from types import MappingProxyType
7
3
  from typing import ClassVar
8
4
 
9
- from caseconverter import snakecase
10
- from django.contrib.sessions.models import Session
11
- from django.db.models import Count
12
5
  from drf_spectacular.utils import extend_schema
13
6
  from rest_framework.response import Response
7
+ from rest_framework.serializers import empty
14
8
 
9
+ from codex.librarian.stats import CodexStats
15
10
  from codex.logger.logging import get_logger
16
- from codex.models import (
17
- Comic,
18
- Library,
19
- Timestamp,
20
- )
11
+ from codex.models.admin import Timestamp
21
12
  from codex.permissions import HasAPIKeyOrIsAdminUser
22
13
  from codex.serializers.admin.stats import (
23
14
  AdminStatsRequestSerializer,
24
- AdminStatsSerializer,
15
+ StatsSerializer,
25
16
  )
26
- from codex.version import VERSION
27
17
  from codex.views.admin.auth import AdminGenericAPIView
28
- from codex.views.const import CONFIG_MODELS, METADATA_MODELS, STATS_GROUP_MODELS
29
- from codex.views.session import SessionView
30
18
 
31
19
  LOG = get_logger(__name__)
32
- _KEY_MODELS_MAP = MappingProxyType(
33
- {
34
- "config": CONFIG_MODELS,
35
- "groups": STATS_GROUP_MODELS,
36
- "metadata": METADATA_MODELS,
37
- }
38
- )
39
- _DOCKERENV_PATH = Path("/.dockerenv")
40
- _CGROUP_PATH = Path("/proc/self/cgroup")
41
- _USER_STATS = MappingProxyType(
42
- {
43
- SessionView.BROWSER_SESSION_KEY: ("top_group", "order_by", "dynamic_covers"),
44
- SessionView.READER_SESSION_KEY: (
45
- "finish_on_last_page",
46
- "fit_to",
47
- "reading_direction",
48
- ),
49
- }
50
- )
51
20
 
52
21
 
53
22
  class AdminStatsView(AdminGenericAPIView):
54
23
  """Admin Flag Viewset."""
55
24
 
56
25
  permission_classes: ClassVar[list] = [HasAPIKeyOrIsAdminUser] # type: ignore
57
- serializer_class = AdminStatsSerializer
26
+ serializer_class = StatsSerializer
58
27
  input_serializer_class = AdminStatsRequestSerializer
59
28
 
60
- @classmethod
61
- def _is_docker(cls):
62
- """Test if we're in a docker container."""
63
- try:
64
- return _DOCKERENV_PATH.is_file() or "docker" in _CGROUP_PATH.read_text()
65
- except Exception:
66
- return False
67
-
68
- def _get_request_counts(self, key):
69
- """Get lowercase names of requested fields."""
70
- request_count_list = self.request.GET.get(key, "")
71
- request_counts = set()
72
- for name in request_count_list.split(","):
73
- if name:
74
- request_counts.add(name.lower())
75
- return request_counts
76
-
77
- def _get_models(self, key):
78
- """Get models from request params."""
79
- request_model_list = self.request.GET.get(key)
80
- all_models = _KEY_MODELS_MAP[key]
81
- if request_model_list:
82
- models = []
83
- for model_name in request_model_list.split(","):
84
- for model in all_models:
85
- if model.__name__.lower() == model_name.lower():
86
- models.append(model)
87
- else:
88
- models = all_models
89
- return models
90
-
91
- def _get_model_counts(self, key):
92
- """Get database counts of each model group."""
93
- models = self._get_models(key)
94
- obj = {}
95
- for model in models:
96
- vnp = model._meta.verbose_name_plural
97
- if vnp:
98
- title = vnp.title()
99
- else:
100
- LOG.warning(f"No verbose plural name for {model.__name__}")
101
- title = model.__name__
102
-
103
- vnp_name = snakecase(title)
104
- vnp_name += "_count"
105
- qs = model.objects
106
- if model == Library:
107
- qs = qs.filter(covers_only=False)
108
- obj[vnp_name] = qs.count()
109
- return obj
110
-
111
- @staticmethod
112
- def _aggregate_session_key(session, session_key, session_subkeys, user_stats):
113
- session_dict = session.get(session_key, {})
114
- for key in session_subkeys:
115
- value = session_dict.get(key)
116
- if value is None:
117
- continue
118
- if key not in user_stats:
119
- user_stats[key] = {}
120
- if value not in user_stats[key]:
121
- user_stats[key][value] = 0
122
- user_stats[key][value] += 1
123
-
124
- @classmethod
125
- def _get_session_stats(cls):
126
- """Return the number of anonymous sessions."""
127
- sessions = Session.objects.all()
128
- anon_session_count = 0
129
- user_stats = {}
130
- for encoded_session in sessions:
131
- session = encoded_session.get_decoded()
132
- if not session.get("_auth_user_id"):
133
- anon_session_count += 1
134
- for session_key, subkeys in _USER_STATS.items():
135
- cls._aggregate_session_key(session, session_key, subkeys, user_stats)
136
-
137
- return user_stats, anon_session_count
138
-
139
- def _get_platform(self, obj):
140
- """Add dict of platform information to object."""
141
- platform = {
142
- "docker": self._is_docker(),
143
- "machine": machine(),
144
- "cores": cpu_count(),
145
- "system": system(),
146
- "system_release": release(),
147
- "python": python_version(),
148
- "codex": VERSION,
149
- }
150
- obj["platform"] = platform
151
-
152
- def _get_config(self, obj):
153
- """Add dict of config informaation to object."""
154
- config = self._get_model_counts("config")
155
- request_counts = self._get_request_counts("config")
156
- sessions, config["anonymous_users_count"] = self._get_session_stats()
157
- if not request_counts or "apikey" in request_counts:
158
- config["api_key"] = Timestamp.objects.get(
159
- key=Timestamp.TimestampChoices.API_KEY.value
160
- ).version
161
- config["registered_users_count"] = config.pop("users_count", 0)
162
- config["user_groups_count"] = config.pop("groups_count", 0)
163
- obj["config"] = config
164
- obj["sessions"] = sessions
165
-
166
- def _get_file_types(self):
167
- """Query for file types."""
168
- file_types = {}
169
- qs = (
170
- Comic.objects.values("file_type")
171
- .annotate(count=Count("file_type"))
172
- .order_by()
173
- )
174
- for query_group in qs:
175
- value = query_group["file_type"]
176
- name = value.lower() if value else "unknown"
177
- field = f"{name}_count"
178
- file_types[field] = query_group["count"]
179
- return file_types
180
-
181
- def _get_groups(self, obj):
182
- """Add dict of groups information to object."""
183
- if not self.params or "groups" in self.params:
184
- groups = self._get_model_counts("groups")
185
- obj["groups"] = groups
186
-
187
- if not self.params or "fileTypes" in self.params:
188
- file_types = self._get_file_types()
189
- obj["file_types"] = file_types
190
-
191
- def _get_metadata(self, obj):
192
- """Add dict of metadata counts to object."""
193
- metadata = self._get_model_counts("metadata")
194
- obj["metadata"] = metadata
29
+ def _parse_params(self):
30
+ """Parse and input params."""
31
+ data = self.request.GET
32
+
33
+ input_serializer = self.input_serializer_class(data=data)
34
+ input_serializer.is_valid(raise_exception=True)
35
+ params = {}
36
+ if input_serializer.validated_data and not isinstance(
37
+ input_serializer.validated_data, empty
38
+ ):
39
+ for key, value in input_serializer.validated_data.items():
40
+ if value:
41
+ params[key] = value
42
+ return params
43
+
44
+ def _add_api_key(self, obj):
45
+ """Add the api key to the config object if specified."""
46
+ request_counts = self.params.get("config", {})
47
+ if request_counts and ("apikey" not in request_counts):
48
+ return
49
+ api_key = Timestamp.objects.get(
50
+ key=Timestamp.TimestampChoices.API_KEY.value
51
+ ).version
52
+ if "config" not in obj:
53
+ obj["config"] = {}
54
+ obj["config"]["api_key"] = api_key
195
55
 
196
56
  def get_object(self):
197
- """Construct the stats object."""
198
- obj = {}
199
- if not self.params or "platform" in self.params:
200
- self._get_platform(obj)
201
- if not self.params or "config" in self.params:
202
- self._get_config(obj)
203
- if not self.params or "groups" in self.params:
204
- self._get_groups(obj)
205
- if not self.params or "metadata" in self.params:
206
- self._get_metadata(obj)
57
+ """Get the stats object with an api key."""
58
+ getter = CodexStats(self.params)
59
+ obj = getter.get()
60
+ self._add_api_key(obj)
207
61
  return obj
208
62
 
209
63
  @extend_schema(parameters=[input_serializer_class])
210
64
  def get(self, *_args, **_kwargs):
211
65
  """Get the stats object and serialize it."""
212
- input_serializer = self.input_serializer_class(data=self.request.GET)
213
- input_serializer.is_valid()
214
- self.params = frozenset(input_serializer.validated_data.get("params", {})) # type: ignore
215
-
66
+ self.params = self._parse_params()
216
67
  obj = self.get_object()
68
+
217
69
  serializer = self.get_serializer(obj)
218
70
  return Response(serializer.data)
@@ -1,9 +1,11 @@
1
1
  """OPDS v1 Entry."""
2
2
 
3
3
  import json
4
+ from contextlib import suppress
4
5
  from datetime import datetime, timezone
5
6
  from urllib.parse import urlencode
6
7
 
8
+ from dateutil import parser
7
9
  from django.urls import reverse
8
10
 
9
11
  from codex.logger.logging import get_logger
@@ -24,11 +26,6 @@ LOG = get_logger(__name__)
24
26
  class OPDS1Entry(OPDS1EntryLinksMixin):
25
27
  """An OPDS entry object."""
26
28
 
27
- _DATE_FORMAT_BASE = "%Y-%m-%dT%H:%M:%S"
28
- _DATE_FORMAT_MS = _DATE_FORMAT_BASE + ".%f%z"
29
- _DATE_FORMAT = _DATE_FORMAT_BASE + "%z"
30
- _DATE_FORMATS = (_DATE_FORMAT_MS, _DATE_FORMAT)
31
-
32
29
  @property
33
30
  def id_tag(self):
34
31
  """GUID is a nav url."""
@@ -69,9 +66,12 @@ class OPDS1Entry(OPDS1EntryLinksMixin):
69
66
  @property
70
67
  def issued(self):
71
68
  """Return the published date."""
69
+ date = ""
72
70
  if self.obj.group == "c":
73
- return self.obj.date
74
- return None
71
+ with suppress(Exception):
72
+ date = self.obj.date.isoformat()
73
+
74
+ return date
75
75
 
76
76
  @property
77
77
  def publisher(self):
@@ -81,17 +81,13 @@ class OPDS1Entry(OPDS1EntryLinksMixin):
81
81
  def _get_datefield(self, key):
82
82
  result = None
83
83
  if not self.fake and (value := getattr(self.obj, key, None)):
84
- for date_format in self._DATE_FORMATS:
85
- try:
86
- if isinstance(value, str):
87
- result = datetime.strptime(value, date_format).astimezone(
88
- timezone.utc
89
- )
90
- if isinstance(value, datetime):
91
- result = value.astimezone(timezone.utc).strftime(date_format)
92
- break
93
- except ValueError:
94
- pass
84
+ try:
85
+ if isinstance(value, str):
86
+ result = parser.parse(value)
87
+ if isinstance(value, datetime):
88
+ result = value.astimezone(timezone.utc).isoformat()
89
+ except ValueError:
90
+ pass
95
91
  return result
96
92
 
97
93
  @property
@@ -96,10 +96,14 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView):
96
96
  @property
97
97
  def updated(self):
98
98
  """Use mtime for updated."""
99
+ datestr = ""
99
100
  try:
100
- return self.obj.get("mtime", "")
101
+ mtime = self.obj.get("mtime")
102
+ if mtime:
103
+ datestr = mtime.isoformat() # type: ignore
101
104
  except Exception:
102
105
  LOG.exception("Getting OPDS v1 updated")
106
+ return datestr
103
107
 
104
108
  @property
105
109
  def items_per_page(self):
@@ -168,6 +168,7 @@ class OPDS1LinksView(OPDS1FacetsView):
168
168
  reverse("opds:authentication:v1"),
169
169
  MimeType.AUTHENTICATION,
170
170
  ),
171
+ OPDS1Link(Rel.START, reverse("opds:v1:start"), MimeType.NAV),
171
172
  OPDS1Link(
172
173
  "search", reverse("opds:v1:opensearch_v1"), MimeType.OPENSEARCH
173
174
  ),
@@ -22,10 +22,10 @@ class ReaderArcsView(ReaderBooksView):
22
22
  def _get_group_arc(self, book, attr, browser_arc_group, arcs, max_mtime): # noqa: PLR0913
23
23
  """Append the volume arc."""
24
24
  if browser_arc_group == attr[0]:
25
- return None, max_mtime
25
+ return max_mtime
26
26
  group = getattr(book, attr, None)
27
27
  if not group:
28
- return None, max_mtime
28
+ return max_mtime
29
29
 
30
30
  _, arc_pks = self.get_group_pks_from_breadcrumbs([group])
31
31
  if group.pk not in arc_pks:
@@ -48,7 +48,7 @@ class ReaderArcsView(ReaderBooksView):
48
48
  .on
49
49
  )
50
50
  if not efv_flag or browser_arc_group == FOLDER_GROUP:
51
- return None, max_mtime
51
+ return max_mtime
52
52
 
53
53
  folder = book.parent_folder
54
54
  arcs.append(
@@ -88,7 +88,8 @@ class ReaderArcsView(ReaderBooksView):
88
88
 
89
89
  if browser_arc := self.params.get("browser_arc", {}):
90
90
  arcs.append(browser_arc)
91
- max_mtime = max_none(max_mtime, browser_arc.get("mtime", max_mtime))
91
+ browser_arc_mtime = browser_arc.get("mtime")
92
+ max_mtime = max_none(max_mtime, browser_arc_mtime)
92
93
 
93
94
  browser_arc_group = browser_arc.get("group", "")
94
95
  max_mtime = self._get_group_arc(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codex
3
- Version: 1.6.3
3
+ Version: 1.6.5
4
4
  Summary: A comic archive web server.
5
5
  Home-page: https://github.com/ajslater/codex
6
6
  License: GPL-3.0-only
@@ -29,7 +29,7 @@ Requires-Dist: ansicolors (>=1.1,<2.0)
29
29
  Requires-Dist: bidict (>=0.23.1,<0.24.0)
30
30
  Requires-Dist: case-converter (>=1.1.0,<2.0.0)
31
31
  Requires-Dist: channels (>=4.0.0,<5.0.0)
32
- Requires-Dist: comicbox[pdf] (>=1.1.8,<2.0.0)
32
+ Requires-Dist: comicbox[pdf] (>=1.1.10,<2.0.0)
33
33
  Requires-Dist: django (>=5.0.6,<6.0.0)
34
34
  Requires-Dist: django-cachalot (>=2.6.2,<3.0.0)
35
35
  Requires-Dist: django-cors-headers (>=4.0,<5.0)
@@ -42,7 +42,7 @@ Requires-Dist: fnvhash (>=0.1,<0.2)
42
42
  Requires-Dist: humanfriendly (>=10.0,<11.0)
43
43
  Requires-Dist: humanize (>=4.0.0,<5.0.0)
44
44
  Requires-Dist: hypercorn[h3] (>=0.17.3,<0.18.0)
45
- Requires-Dist: psutil (>=5.9.4,<6.0.0)
45
+ Requires-Dist: psutil (>=6.0.0,<7.0.0)
46
46
  Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
47
47
  Requires-Dist: requests (>=2.24,<3.0)
48
48
  Requires-Dist: setuptools (>=70.0.0,<71.0.0)
@@ -71,6 +71,7 @@ border-radius: 128px;
71
71
  ## <a name="features">✨ Features</a>
72
72
 
73
73
  - Codex is a web server.
74
+ - GPLv3 Licenced.
74
75
  - Full text search of metadata and bookmarks.
75
76
  - Filter and sort on all comic metadata and unread status per user.
76
77
  - Browse a tree of Publishers, Imprints, Series, Volumes, or your own folder
@@ -95,8 +96,8 @@ border-radius: 128px;
95
96
 
96
97
  ## <a name="demonstration">👀 Demonstration</a>
97
98
 
98
- You may browse a [live demo server](https://codex.sl8r.net/) to get a feel for
99
- Codex.
99
+ You may browse a [live demo server](https://demo.codex-reader.app/) to get a
100
+ feel for Codex.
100
101
 
101
102
  ## <a name="news">📜 News</a>
102
103
 
@@ -134,12 +135,22 @@ brew install jpeg libffi libyaml libzip openssl python unrar webp
134
135
 
135
136
  ###### <a href="#debian">Debian</a>
136
137
 
137
- ...and Ubuntu, Mint, MX and others.
138
+ ...and Ubuntu, Mint, MX and others (and WSL).
138
139
 
139
140
  <!-- eslint-skip -->
140
141
 
141
142
  ```sh
142
- apt install build-essential libimagequant0 libjpeg62-turbo libopenjp2-7 libssl3 libyaml-0-2 libtiff6 libwebp7 python3-dev python3-pip mupdf unrar zlib1g
143
+ apt install build-essential libimagequant0 libjpeg-turbo8 libopenjp2-7 libssl libyaml-0-2 libtiff6 libwebp7 python3-dev python3-pip mupdf unrar zlib1g
144
+ ```
145
+
146
+ Versions of packages like libjpeg, libssl, libtiff may differ between flavors
147
+ and versions of Debian. If the version above is not available, try searching for
148
+ one that is with apt-cache or aptitude.
149
+
150
+ <!-- eslint-skip -->
151
+
152
+ ```sh
153
+ apt-cache search libjpeg-turbo
143
154
  ```
144
155
 
145
156
  ###### Alpine