codex 1.6.0a6__py3-none-any.whl → 1.6.0a8__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 (612) hide show
  1. codex/exceptions.py +1 -0
  2. codex/integrity.py +4 -4
  3. codex/librarian/importer/{aggregate_metadata.py → aggregate.py} +56 -86
  4. codex/librarian/importer/cache.py +180 -0
  5. codex/librarian/importer/const.py +15 -6
  6. codex/librarian/importer/create_comics.py +102 -17
  7. codex/librarian/importer/create_covers.py +98 -0
  8. codex/librarian/importer/create_fks.py +73 -170
  9. codex/librarian/importer/deleted.py +59 -46
  10. codex/librarian/importer/{clean_metadata.py → extract.py} +33 -4
  11. codex/librarian/importer/failed_imports.py +41 -62
  12. codex/librarian/importer/importer.py +96 -0
  13. codex/librarian/importer/importerd.py +71 -395
  14. codex/librarian/importer/init.py +265 -0
  15. codex/librarian/importer/link_comics.py +26 -81
  16. codex/librarian/importer/link_covers.py +73 -0
  17. codex/librarian/importer/moved.py +72 -96
  18. codex/librarian/importer/query_covers.py +52 -0
  19. codex/librarian/importer/query_fks.py +128 -172
  20. codex/librarian/importer/status.py +2 -39
  21. codex/librarian/importer/tasks.py +22 -13
  22. codex/librarian/janitor/cleanup.py +2 -2
  23. codex/librarian/janitor/janitor.py +11 -1
  24. codex/librarian/librariand.py +8 -2
  25. codex/migrations/0027_import_order_and_covers.py +345 -0
  26. codex/models/comic.py +1 -2
  27. codex/models/groups.py +3 -2
  28. codex/models/paths.py +0 -1
  29. codex/permissions.py +1 -1
  30. codex/search/query.py +25 -2
  31. codex/search/writing.py +1 -1
  32. codex/serializers/admin.py +1 -2
  33. codex/serializers/browser/filters.py +8 -101
  34. codex/serializers/browser/mixins.py +2 -3
  35. codex/serializers/browser/page.py +2 -2
  36. codex/serializers/browser/settings.py +4 -3
  37. codex/serializers/choices.py +10 -1
  38. codex/serializers/fields.py +123 -0
  39. codex/serializers/mtime.py +25 -0
  40. codex/serializers/opds/v2.py +7 -11
  41. codex/serializers/opds/v2_unused.py +5 -3
  42. codex/serializers/reader.py +5 -2
  43. codex/serializers/route.py +7 -3
  44. codex/settings/settings.py +2 -2
  45. codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js +1 -0
  46. codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js.br +0 -0
  47. codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js.gz +0 -0
  48. codex/static_root/assets/VCheckbox-DI-DgMb4.js +1 -0
  49. codex/static_root/assets/VCheckbox-DI-DgMb4.js.br +0 -0
  50. codex/static_root/assets/VCheckbox-DI-DgMb4.js.gz +0 -0
  51. codex/static_root/assets/{VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js → VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js} +1 -1
  52. codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js.br +0 -0
  53. codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js.gz +0 -0
  54. codex/static_root/assets/{VCheckboxBtn-m4IbdjEe.js → VCheckboxBtn-B8Z4NA-t.js} +1 -1
  55. codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.js.br +0 -0
  56. codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.js.gz +0 -0
  57. codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js +1 -0
  58. codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js.br +0 -0
  59. codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js.gz +0 -0
  60. codex/static_root/assets/VCombobox-D1_0lCri.js +1 -0
  61. codex/static_root/assets/VCombobox-D1_0lCri.js.br +0 -0
  62. codex/static_root/assets/VCombobox-D1_0lCri.js.gz +0 -0
  63. codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js +1 -0
  64. codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js.br +0 -0
  65. codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js.gz +0 -0
  66. codex/static_root/assets/VDialog-opmV0YZz.js +1 -0
  67. codex/static_root/assets/VDialog-opmV0YZz.js.br +0 -0
  68. codex/static_root/assets/VDialog-opmV0YZz.js.gz +0 -0
  69. codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js +1 -0
  70. codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js.br +0 -0
  71. codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js.gz +0 -0
  72. codex/static_root/assets/VExpansionPanels-DX2dhUf5.js +1 -0
  73. codex/static_root/assets/VExpansionPanels-DX2dhUf5.js.br +0 -0
  74. codex/static_root/assets/VExpansionPanels-DX2dhUf5.js.gz +0 -0
  75. codex/static_root/assets/VRadioGroup-BGa6_q5a.d1a3ad7266bd.js +1 -0
  76. codex/static_root/assets/VRadioGroup-BGa6_q5a.d1a3ad7266bd.js.br +0 -0
  77. codex/static_root/assets/VRadioGroup-BGa6_q5a.d1a3ad7266bd.js.gz +0 -0
  78. codex/static_root/assets/VRadioGroup-BGa6_q5a.js +1 -0
  79. codex/static_root/assets/VRadioGroup-BGa6_q5a.js.br +0 -0
  80. codex/static_root/assets/VRadioGroup-BGa6_q5a.js.gz +0 -0
  81. codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css +1 -0
  82. codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css.br +0 -0
  83. codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css.gz +0 -0
  84. codex/static_root/assets/VSelect-ARDhJiQK.css +1 -0
  85. codex/static_root/assets/VSelect-ARDhJiQK.css.br +0 -0
  86. codex/static_root/assets/VSelect-ARDhJiQK.css.gz +0 -0
  87. codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js +1 -0
  88. codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js.br +0 -0
  89. codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js.gz +0 -0
  90. codex/static_root/assets/VSelect-sIYW_-ud.js +1 -0
  91. codex/static_root/assets/VSelect-sIYW_-ud.js.br +0 -0
  92. codex/static_root/assets/VSelect-sIYW_-ud.js.gz +0 -0
  93. codex/static_root/assets/VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js +1 -0
  94. codex/static_root/assets/VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js.br +0 -0
  95. codex/static_root/assets/VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js.gz +0 -0
  96. codex/static_root/assets/VSelectionControl-C8DP9rgp.js +1 -0
  97. codex/static_root/assets/VSelectionControl-C8DP9rgp.js.br +0 -0
  98. codex/static_root/assets/VSelectionControl-C8DP9rgp.js.gz +0 -0
  99. codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js +1 -0
  100. codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js.br +0 -0
  101. codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js.gz +0 -0
  102. codex/static_root/assets/VSlideGroup-BRYhkLH8.js +1 -0
  103. codex/static_root/assets/VSlideGroup-BRYhkLH8.js.br +0 -0
  104. codex/static_root/assets/VSlideGroup-BRYhkLH8.js.gz +0 -0
  105. codex/static_root/assets/{VTable-C0gAriFq.fa6e4b60d4ef.js → VTable-D1esKtlw.52165930e3b9.js} +1 -1
  106. codex/static_root/assets/VTable-D1esKtlw.52165930e3b9.js.br +0 -0
  107. codex/static_root/assets/VTable-D1esKtlw.52165930e3b9.js.gz +0 -0
  108. codex/static_root/assets/{VTable-C0gAriFq.js → VTable-D1esKtlw.js} +1 -1
  109. codex/static_root/assets/VTable-D1esKtlw.js.br +0 -0
  110. codex/static_root/assets/VTable-D1esKtlw.js.gz +0 -0
  111. codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js +1 -0
  112. codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js.br +0 -0
  113. codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js.gz +0 -0
  114. codex/static_root/assets/VTextField-BnGscKcY.js +1 -0
  115. codex/static_root/assets/VTextField-BnGscKcY.js.br +0 -0
  116. codex/static_root/assets/VTextField-BnGscKcY.js.gz +0 -0
  117. codex/static_root/assets/{VWindowItem-CFhKCj49.b2458002a937.js → VWindowItem-B0KokcAk.ea94224aecb9.js} +1 -1
  118. codex/static_root/assets/VWindowItem-B0KokcAk.ea94224aecb9.js.br +0 -0
  119. codex/static_root/assets/VWindowItem-B0KokcAk.ea94224aecb9.js.gz +0 -0
  120. codex/static_root/assets/{VWindowItem-CFhKCj49.js → VWindowItem-B0KokcAk.js} +1 -1
  121. codex/static_root/assets/VWindowItem-B0KokcAk.js.br +0 -0
  122. codex/static_root/assets/VWindowItem-B0KokcAk.js.gz +0 -0
  123. codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js +1 -0
  124. codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js.br +0 -0
  125. codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js.gz +0 -0
  126. codex/static_root/assets/admin-Y0bL21AB.js +1 -0
  127. codex/static_root/assets/admin-Y0bL21AB.js.br +0 -0
  128. codex/static_root/assets/admin-Y0bL21AB.js.gz +0 -0
  129. codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js +30 -0
  130. codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js.br +0 -0
  131. codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js.gz +0 -0
  132. codex/static_root/assets/admin-drawer-panel-DNngWUEM.js +30 -0
  133. codex/static_root/assets/admin-drawer-panel-DNngWUEM.js.br +0 -0
  134. codex/static_root/assets/admin-drawer-panel-DNngWUEM.js.gz +0 -0
  135. codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css → admin-drawer-panel-o87BwD38.ce39427c8201.css} +1 -1
  136. codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.br +0 -0
  137. codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css.gz → admin-drawer-panel-o87BwD38.ce39427c8201.css.gz} +0 -0
  138. codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.css → admin-drawer-panel-o87BwD38.css} +1 -1
  139. codex/static_root/assets/admin-drawer-panel-o87BwD38.css.br +0 -0
  140. codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.css.gz → admin-drawer-panel-o87BwD38.css.gz} +0 -0
  141. codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css +1 -0
  142. codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css.br +0 -0
  143. codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css.gz +0 -0
  144. codex/static_root/assets/browser-CMAtBCLx.css +1 -0
  145. codex/static_root/assets/browser-CMAtBCLx.css.br +0 -0
  146. codex/static_root/assets/browser-CMAtBCLx.css.gz +0 -0
  147. codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js +1 -0
  148. codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js.br +0 -0
  149. codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js.gz +0 -0
  150. codex/static_root/assets/browser-DoJk8uvb.js +1 -0
  151. codex/static_root/assets/browser-DoJk8uvb.js.br +0 -0
  152. codex/static_root/assets/browser-DoJk8uvb.js.gz +0 -0
  153. codex/static_root/assets/{change-password-dialog-JYM9aAR9.js → change-password-dialog-CH4xbjJa.b749aa6ea07e.js} +1 -1
  154. codex/static_root/assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js.br +0 -0
  155. codex/static_root/assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js.gz +0 -0
  156. codex/static_root/assets/{change-password-dialog-JYM9aAR9.f71d378f4fa6.js → change-password-dialog-CH4xbjJa.js} +1 -1
  157. codex/static_root/assets/change-password-dialog-CH4xbjJa.js.br +0 -0
  158. codex/static_root/assets/change-password-dialog-CH4xbjJa.js.gz +0 -0
  159. codex/static_root/assets/{confirm-dialog-ZAZ6P1Rc.515858dd21e8.js → confirm-dialog-DkU0twE6.a20006aa5ba6.js} +1 -1
  160. codex/static_root/assets/confirm-dialog-DkU0twE6.a20006aa5ba6.js.br +0 -0
  161. codex/static_root/assets/confirm-dialog-DkU0twE6.a20006aa5ba6.js.gz +0 -0
  162. codex/static_root/assets/{confirm-dialog-ZAZ6P1Rc.js → confirm-dialog-DkU0twE6.js} +1 -1
  163. codex/static_root/assets/confirm-dialog-DkU0twE6.js.br +0 -0
  164. codex/static_root/assets/confirm-dialog-DkU0twE6.js.gz +0 -0
  165. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js +1 -0
  166. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js.br +0 -0
  167. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js +1 -0
  168. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js.br +0 -0
  169. codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js +1 -0
  170. codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js.br +0 -0
  171. codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js.gz +0 -0
  172. codex/static_root/assets/datetime-column-BfW_j_3Q.js +1 -0
  173. codex/static_root/assets/datetime-column-BfW_j_3Q.js.br +0 -0
  174. codex/static_root/assets/datetime-column-BfW_j_3Q.js.gz +0 -0
  175. codex/static_root/assets/datetime-column-DeCthByU.1f3bf499e063.css +1 -0
  176. codex/static_root/assets/datetime-column-DeCthByU.css +1 -0
  177. codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js +1 -0
  178. codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js.br +0 -0
  179. codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js.gz +0 -0
  180. codex/static_root/assets/filter-DjxN78cK.js +1 -0
  181. codex/static_root/assets/filter-DjxN78cK.js.br +0 -0
  182. codex/static_root/assets/filter-DjxN78cK.js.gz +0 -0
  183. codex/static_root/assets/{flag-tab-Ci_XcDT0.a5ea640a08d6.js → flag-tab-D4ZNSbMR.e763a9937701.js} +1 -1
  184. codex/static_root/assets/flag-tab-D4ZNSbMR.e763a9937701.js.br +0 -0
  185. codex/static_root/assets/flag-tab-D4ZNSbMR.e763a9937701.js.gz +0 -0
  186. codex/static_root/assets/{flag-tab-Ci_XcDT0.js → flag-tab-D4ZNSbMR.js} +1 -1
  187. codex/static_root/assets/flag-tab-D4ZNSbMR.js.br +0 -0
  188. codex/static_root/assets/flag-tab-D4ZNSbMR.js.gz +0 -0
  189. codex/static_root/assets/{group-tab-DFma2R-E.879c37b15bbd.js → group-tab-DucpNoBs.a6f37ae940c0.js} +1 -1
  190. codex/static_root/assets/group-tab-DucpNoBs.a6f37ae940c0.js.br +0 -0
  191. codex/static_root/assets/group-tab-DucpNoBs.a6f37ae940c0.js.gz +0 -0
  192. codex/static_root/assets/{group-tab-DFma2R-E.js → group-tab-DucpNoBs.js} +1 -1
  193. codex/static_root/assets/group-tab-DucpNoBs.js.br +0 -0
  194. codex/static_root/assets/group-tab-DucpNoBs.js.gz +0 -0
  195. codex/static_root/assets/http-error-Cj0hTq-c.062a88ddd4dc.js +1 -0
  196. codex/static_root/assets/http-error-Cj0hTq-c.062a88ddd4dc.js.br +0 -0
  197. codex/static_root/assets/http-error-Cj0hTq-c.062a88ddd4dc.js.gz +0 -0
  198. codex/static_root/assets/http-error-Cj0hTq-c.js +1 -0
  199. codex/static_root/assets/http-error-Cj0hTq-c.js.br +0 -0
  200. codex/static_root/assets/http-error-Cj0hTq-c.js.gz +0 -0
  201. codex/static_root/assets/{library-tab-V8DUGoHN.js → library-tab-CzksdS3Q.566acdb45dec.js} +1 -1
  202. codex/static_root/assets/library-tab-CzksdS3Q.566acdb45dec.js.br +0 -0
  203. codex/static_root/assets/library-tab-CzksdS3Q.566acdb45dec.js.gz +0 -0
  204. codex/static_root/assets/{library-tab-V8DUGoHN.809c548ff347.js → library-tab-CzksdS3Q.js} +1 -1
  205. codex/static_root/assets/library-tab-CzksdS3Q.js.br +0 -0
  206. codex/static_root/assets/library-tab-CzksdS3Q.js.gz +0 -0
  207. codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js +32 -0
  208. codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js.br +0 -0
  209. codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js.gz +0 -0
  210. codex/static_root/assets/main-DX-k2724.js +32 -0
  211. codex/static_root/assets/main-DX-k2724.js.br +0 -0
  212. codex/static_root/assets/main-DX-k2724.js.gz +0 -0
  213. codex/static_root/assets/{main-sK7HC5h4.css → main-Ztp855PW.css} +1 -1
  214. codex/static_root/assets/main-Ztp855PW.css.br +0 -0
  215. codex/static_root/assets/{main-sK7HC5h4.css.gz → main-Ztp855PW.css.gz} +0 -0
  216. codex/static_root/assets/{main-sK7HC5h4.6f04ddfc5f1a.css → main-Ztp855PW.d46d718fac45.css} +1 -1
  217. codex/static_root/assets/main-Ztp855PW.d46d718fac45.css.br +0 -0
  218. codex/static_root/assets/{main-sK7HC5h4.6f04ddfc5f1a.css.gz → main-Ztp855PW.d46d718fac45.css.gz} +0 -0
  219. codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js +1 -0
  220. codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js.br +0 -0
  221. codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js.gz +0 -0
  222. codex/static_root/assets/pagination-toolbar-CQcR0a3T.js +1 -0
  223. codex/static_root/assets/pagination-toolbar-CQcR0a3T.js.br +0 -0
  224. codex/static_root/assets/pagination-toolbar-CQcR0a3T.js.gz +0 -0
  225. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css +1 -0
  226. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.br +0 -0
  227. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.gz +0 -0
  228. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css +1 -0
  229. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.br +0 -0
  230. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.gz +0 -0
  231. codex/static_root/assets/pdf-doc-GkMk4o5L.ef24c859a7a4.js +305 -0
  232. codex/static_root/assets/pdf-doc-GkMk4o5L.ef24c859a7a4.js.br +0 -0
  233. codex/static_root/assets/pdf-doc-GkMk4o5L.ef24c859a7a4.js.gz +0 -0
  234. codex/static_root/assets/pdf-doc-GkMk4o5L.js +305 -0
  235. codex/static_root/assets/pdf-doc-GkMk4o5L.js.br +0 -0
  236. codex/static_root/assets/pdf-doc-GkMk4o5L.js.gz +0 -0
  237. codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css +1 -0
  238. codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.br +0 -0
  239. codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.gz +0 -0
  240. codex/static_root/assets/reader-CCCfpM3x.css +1 -0
  241. codex/static_root/assets/reader-CCCfpM3x.css.br +0 -0
  242. codex/static_root/assets/reader-CCCfpM3x.css.gz +0 -0
  243. codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js +2 -0
  244. codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js.br +0 -0
  245. codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js.gz +0 -0
  246. codex/static_root/assets/reader-Cl6mmQB_.js +2 -0
  247. codex/static_root/assets/reader-Cl6mmQB_.js.br +0 -0
  248. codex/static_root/assets/reader-Cl6mmQB_.js.gz +0 -0
  249. codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js +1 -0
  250. codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js.br +0 -0
  251. codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js.gz +0 -0
  252. codex/static_root/assets/relation-chips-CZ8VvR4y.js +1 -0
  253. codex/static_root/assets/relation-chips-CZ8VvR4y.js.br +0 -0
  254. codex/static_root/assets/relation-chips-CZ8VvR4y.js.gz +0 -0
  255. codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js +2 -0
  256. codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js.br +0 -0
  257. codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js.gz +0 -0
  258. codex/static_root/assets/settings-drawer-DyS0A2pN.js +2 -0
  259. codex/static_root/assets/settings-drawer-DyS0A2pN.js.br +0 -0
  260. codex/static_root/assets/settings-drawer-DyS0A2pN.js.gz +0 -0
  261. codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js +1 -0
  262. codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js.br +0 -0
  263. codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js.gz +0 -0
  264. codex/static_root/assets/stats-tab-R3Ekobfm.js +1 -0
  265. codex/static_root/assets/stats-tab-R3Ekobfm.js.br +0 -0
  266. codex/static_root/assets/stats-tab-R3Ekobfm.js.gz +0 -0
  267. codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js +1 -0
  268. codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js.br +0 -0
  269. codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js.gz +0 -0
  270. codex/static_root/assets/task-tab-BhLDK_7Q.js +1 -0
  271. codex/static_root/assets/task-tab-BhLDK_7Q.js.br +0 -0
  272. codex/static_root/assets/task-tab-BhLDK_7Q.js.gz +0 -0
  273. codex/static_root/assets/to-case-BR2frjFx.87de5d7a0503.js +1 -0
  274. codex/static_root/assets/to-case-BR2frjFx.js +1 -0
  275. codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js +1 -0
  276. codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js.br +0 -0
  277. codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js.gz +0 -0
  278. codex/static_root/assets/unauthorized-BbXjAe5l.js +1 -0
  279. codex/static_root/assets/unauthorized-BbXjAe5l.js.br +0 -0
  280. codex/static_root/assets/unauthorized-BbXjAe5l.js.gz +0 -0
  281. codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js +1 -0
  282. codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js.br +0 -0
  283. codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js.gz +0 -0
  284. codex/static_root/assets/user-tab-DxITIl2d.js +1 -0
  285. codex/static_root/assets/user-tab-DxITIl2d.js.br +0 -0
  286. codex/static_root/assets/user-tab-DxITIl2d.js.gz +0 -0
  287. codex/static_root/js/choices-admin.d790df01c20a.json +1 -0
  288. codex/static_root/js/choices-admin.d790df01c20a.json.br +0 -0
  289. codex/static_root/js/choices-admin.d790df01c20a.json.gz +0 -0
  290. codex/static_root/js/choices-admin.json +1 -1
  291. codex/static_root/js/choices-admin.json.br +0 -0
  292. codex/static_root/js/choices-admin.json.gz +0 -0
  293. codex/static_root/js/choices.a0aaaa6c7ef7.json +1 -0
  294. codex/static_root/js/choices.a0aaaa6c7ef7.json.br +0 -0
  295. codex/static_root/js/choices.a0aaaa6c7ef7.json.gz +0 -0
  296. codex/static_root/js/choices.json +1 -1
  297. codex/static_root/js/choices.json.br +0 -0
  298. codex/static_root/js/choices.json.gz +0 -0
  299. codex/static_root/manifest.16d52597ef50.json +629 -0
  300. codex/static_root/manifest.16d52597ef50.json.br +0 -0
  301. codex/static_root/manifest.16d52597ef50.json.gz +0 -0
  302. codex/static_root/manifest.json +275 -288
  303. codex/static_root/manifest.json.br +0 -0
  304. codex/static_root/manifest.json.gz +0 -0
  305. codex/static_root/staticfiles.json +1 -1
  306. codex/urls/api/auth.py +2 -1
  307. codex/urls/api/browser.py +13 -4
  308. codex/urls/api/reader.py +3 -9
  309. codex/urls/api/v3.py +2 -0
  310. codex/urls/opds/binary.py +1 -1
  311. codex/util.py +10 -0
  312. codex/views/admin/api_key.py +2 -6
  313. codex/views/admin/auth.py +28 -0
  314. codex/views/admin/flag.py +2 -7
  315. codex/views/admin/group.py +2 -6
  316. codex/views/admin/library.py +7 -20
  317. codex/views/admin/stats.py +7 -66
  318. codex/views/admin/tasks.py +24 -11
  319. codex/views/admin/user.py +3 -9
  320. codex/views/auth.py +30 -53
  321. codex/views/bookmark.py +7 -11
  322. codex/views/browser/{browser_annotations.py → annotations.py} +90 -181
  323. codex/views/browser/base.py +23 -88
  324. codex/views/browser/breadcrumbs.py +202 -0
  325. codex/views/browser/browser.py +64 -342
  326. codex/views/browser/choices.py +22 -54
  327. codex/views/browser/cover.py +177 -0
  328. codex/views/browser/filters/annotations.py +24 -23
  329. codex/views/browser/filters/bookmark.py +9 -13
  330. codex/views/browser/filters/field.py +5 -5
  331. codex/views/browser/filters/group.py +18 -10
  332. codex/views/browser/filters/search.py +30 -18
  333. codex/views/browser/metadata.py +22 -31
  334. codex/views/browser/{browser_order_by.py → order_by.py} +2 -6
  335. codex/views/browser/paginate.py +106 -0
  336. codex/views/browser/{session.py → settings.py} +4 -3
  337. codex/views/browser/title.py +48 -0
  338. codex/views/browser/validate.py +158 -0
  339. codex/views/const.py +109 -0
  340. codex/views/download.py +5 -8
  341. codex/views/frontend.py +4 -2
  342. codex/views/mtime.py +72 -0
  343. codex/views/opds/auth.py +17 -0
  344. codex/views/opds/authentication_v1.py +46 -45
  345. codex/views/opds/binary.py +5 -10
  346. codex/views/opds/const.py +13 -0
  347. codex/views/opds/urls.py +6 -4
  348. codex/views/opds/util.py +4 -12
  349. codex/views/opds/v1/entry/links.py +18 -33
  350. codex/views/opds/v1/facets.py +7 -7
  351. codex/views/opds/v1/feed.py +52 -40
  352. codex/views/opds/v1/links.py +7 -5
  353. codex/views/opds/v1/opensearch_v1.py +2 -6
  354. codex/views/opds/v2/feed.py +22 -23
  355. codex/views/opds/v2/links.py +4 -2
  356. codex/views/opds/v2/publications.py +34 -54
  357. codex/views/opds/v2/top_links.py +2 -2
  358. codex/views/public.py +36 -0
  359. codex/views/reader/arcs.py +101 -0
  360. codex/views/reader/books.py +199 -0
  361. codex/views/reader/page.py +3 -7
  362. codex/views/reader/reader.py +56 -301
  363. codex/views/reader/{session.py → settings.py} +4 -2
  364. codex/views/session.py +77 -103
  365. codex/views/settings.py +34 -0
  366. codex/views/template.py +3 -3
  367. codex/views/util.py +63 -0
  368. codex/views/version.py +2 -2
  369. {codex-1.6.0a6.dist-info → codex-1.6.0a8.dist-info}/METADATA +19 -14
  370. {codex-1.6.0a6.dist-info → codex-1.6.0a8.dist-info}/RECORD +373 -362
  371. codex/librarian/importer/covers.py +0 -47
  372. codex/librarian/importer/update_comics.py +0 -85
  373. codex/migrations/0027_sort_name.py +0 -139
  374. codex/migrations/0028_custom_covers.py +0 -166
  375. codex/migrations/0029_choices_adminflag_and_timestamp.py +0 -44
  376. codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js +0 -1
  377. codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js.br +0 -0
  378. codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js.gz +0 -0
  379. codex/static_root/assets/VCheckbox-BS5fdM4M.js +0 -1
  380. codex/static_root/assets/VCheckbox-BS5fdM4M.js.br +0 -0
  381. codex/static_root/assets/VCheckbox-BS5fdM4M.js.gz +0 -0
  382. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js.br +0 -0
  383. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js.gz +0 -0
  384. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.js.br +0 -0
  385. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.js.gz +0 -0
  386. codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js +0 -1
  387. codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js.br +0 -0
  388. codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js.gz +0 -0
  389. codex/static_root/assets/VCombobox-jg7SI5mn.js +0 -1
  390. codex/static_root/assets/VCombobox-jg7SI5mn.js.br +0 -0
  391. codex/static_root/assets/VCombobox-jg7SI5mn.js.gz +0 -0
  392. codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js +0 -1
  393. codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js.br +0 -0
  394. codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js.gz +0 -0
  395. codex/static_root/assets/VDialog-DiixpkQL.js +0 -1
  396. codex/static_root/assets/VDialog-DiixpkQL.js.br +0 -0
  397. codex/static_root/assets/VDialog-DiixpkQL.js.gz +0 -0
  398. codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js +0 -1
  399. codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js.br +0 -0
  400. codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js.gz +0 -0
  401. codex/static_root/assets/VExpansionPanels-Db5mPFue.js +0 -1
  402. codex/static_root/assets/VExpansionPanels-Db5mPFue.js.br +0 -0
  403. codex/static_root/assets/VExpansionPanels-Db5mPFue.js.gz +0 -0
  404. codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js +0 -1
  405. codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js.br +0 -0
  406. codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js.gz +0 -0
  407. codex/static_root/assets/VRadioGroup-DULWiMSI.js +0 -1
  408. codex/static_root/assets/VRadioGroup-DULWiMSI.js.br +0 -0
  409. codex/static_root/assets/VRadioGroup-DULWiMSI.js.gz +0 -0
  410. codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js +0 -1
  411. codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js.br +0 -0
  412. codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js.gz +0 -0
  413. codex/static_root/assets/VSelect-BnoCfCLY.js +0 -1
  414. codex/static_root/assets/VSelect-BnoCfCLY.js.br +0 -0
  415. codex/static_root/assets/VSelect-BnoCfCLY.js.gz +0 -0
  416. codex/static_root/assets/VSelect-MGVSeLgr.7cabd30bc5e4.css +0 -1
  417. codex/static_root/assets/VSelect-MGVSeLgr.7cabd30bc5e4.css.br +0 -0
  418. codex/static_root/assets/VSelect-MGVSeLgr.7cabd30bc5e4.css.gz +0 -0
  419. codex/static_root/assets/VSelect-MGVSeLgr.css +0 -1
  420. codex/static_root/assets/VSelect-MGVSeLgr.css.br +0 -0
  421. codex/static_root/assets/VSelect-MGVSeLgr.css.gz +0 -0
  422. codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js +0 -1
  423. codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js.br +0 -0
  424. codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js.gz +0 -0
  425. codex/static_root/assets/VSelectionControl-BSL0qeL9.js +0 -1
  426. codex/static_root/assets/VSelectionControl-BSL0qeL9.js.br +0 -0
  427. codex/static_root/assets/VSelectionControl-BSL0qeL9.js.gz +0 -0
  428. codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js +0 -1
  429. codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js.br +0 -0
  430. codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js.gz +0 -0
  431. codex/static_root/assets/VSlideGroup-BQtz8h9p.js +0 -1
  432. codex/static_root/assets/VSlideGroup-BQtz8h9p.js.br +0 -0
  433. codex/static_root/assets/VSlideGroup-BQtz8h9p.js.gz +0 -0
  434. codex/static_root/assets/VTable-C0gAriFq.fa6e4b60d4ef.js.br +0 -0
  435. codex/static_root/assets/VTable-C0gAriFq.fa6e4b60d4ef.js.gz +0 -0
  436. codex/static_root/assets/VTable-C0gAriFq.js.br +0 -0
  437. codex/static_root/assets/VTable-C0gAriFq.js.gz +0 -0
  438. codex/static_root/assets/VTextField-Da_Hs7ls.c295f24c251e.js +0 -1
  439. codex/static_root/assets/VTextField-Da_Hs7ls.c295f24c251e.js.br +0 -0
  440. codex/static_root/assets/VTextField-Da_Hs7ls.c295f24c251e.js.gz +0 -0
  441. codex/static_root/assets/VTextField-Da_Hs7ls.js +0 -1
  442. codex/static_root/assets/VTextField-Da_Hs7ls.js.br +0 -0
  443. codex/static_root/assets/VTextField-Da_Hs7ls.js.gz +0 -0
  444. codex/static_root/assets/VWindowItem-CFhKCj49.b2458002a937.js.br +0 -0
  445. codex/static_root/assets/VWindowItem-CFhKCj49.b2458002a937.js.gz +0 -0
  446. codex/static_root/assets/VWindowItem-CFhKCj49.js.br +0 -0
  447. codex/static_root/assets/VWindowItem-CFhKCj49.js.gz +0 -0
  448. codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js +0 -1
  449. codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js.br +0 -0
  450. codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js.gz +0 -0
  451. codex/static_root/assets/admin-BpGFsvOH.js +0 -1
  452. codex/static_root/assets/admin-BpGFsvOH.js.br +0 -0
  453. codex/static_root/assets/admin-BpGFsvOH.js.gz +0 -0
  454. codex/static_root/assets/admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css.br +0 -0
  455. codex/static_root/assets/admin-drawer-panel-BHdNPwzF.css.br +0 -0
  456. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js +0 -30
  457. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js.br +0 -0
  458. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js.gz +0 -0
  459. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js +0 -30
  460. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js.br +0 -0
  461. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js.gz +0 -0
  462. codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js +0 -1
  463. codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js.br +0 -0
  464. codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js.gz +0 -0
  465. codex/static_root/assets/browser-CRPvEdqv.js +0 -1
  466. codex/static_root/assets/browser-CRPvEdqv.js.br +0 -0
  467. codex/static_root/assets/browser-CRPvEdqv.js.gz +0 -0
  468. codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css +0 -1
  469. codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css.br +0 -0
  470. codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css.gz +0 -0
  471. codex/static_root/assets/browser-Zqc9cR6T.css +0 -1
  472. codex/static_root/assets/browser-Zqc9cR6T.css.br +0 -0
  473. codex/static_root/assets/browser-Zqc9cR6T.css.gz +0 -0
  474. codex/static_root/assets/change-password-dialog-JYM9aAR9.f71d378f4fa6.js.br +0 -0
  475. codex/static_root/assets/change-password-dialog-JYM9aAR9.f71d378f4fa6.js.gz +0 -0
  476. codex/static_root/assets/change-password-dialog-JYM9aAR9.js.br +0 -0
  477. codex/static_root/assets/change-password-dialog-JYM9aAR9.js.gz +0 -0
  478. codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.515858dd21e8.js.br +0 -0
  479. codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.515858dd21e8.js.gz +0 -0
  480. codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.js.br +0 -0
  481. codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.js.gz +0 -0
  482. codex/static_root/assets/datetime-column-BT1MSP82.9617f6b94ebf.js +0 -1
  483. codex/static_root/assets/datetime-column-BT1MSP82.9617f6b94ebf.js.br +0 -0
  484. codex/static_root/assets/datetime-column-BT1MSP82.9617f6b94ebf.js.gz +0 -0
  485. codex/static_root/assets/datetime-column-BT1MSP82.js +0 -1
  486. codex/static_root/assets/datetime-column-BT1MSP82.js.br +0 -0
  487. codex/static_root/assets/datetime-column-BT1MSP82.js.gz +0 -0
  488. codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css +0 -1
  489. codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css.br +0 -0
  490. codex/static_root/assets/datetime-column-Dg_RxTVM.css +0 -1
  491. codex/static_root/assets/datetime-column-Dg_RxTVM.css.br +0 -0
  492. codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js +0 -1
  493. codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js.br +0 -0
  494. codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js.gz +0 -0
  495. codex/static_root/assets/filter-frSNsexx.js +0 -1
  496. codex/static_root/assets/filter-frSNsexx.js.br +0 -0
  497. codex/static_root/assets/filter-frSNsexx.js.gz +0 -0
  498. codex/static_root/assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js.br +0 -0
  499. codex/static_root/assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js.gz +0 -0
  500. codex/static_root/assets/flag-tab-Ci_XcDT0.js.br +0 -0
  501. codex/static_root/assets/flag-tab-Ci_XcDT0.js.gz +0 -0
  502. codex/static_root/assets/group-tab-DFma2R-E.879c37b15bbd.js.br +0 -0
  503. codex/static_root/assets/group-tab-DFma2R-E.879c37b15bbd.js.gz +0 -0
  504. codex/static_root/assets/group-tab-DFma2R-E.js.br +0 -0
  505. codex/static_root/assets/group-tab-DFma2R-E.js.gz +0 -0
  506. codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js +0 -1
  507. codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js.br +0 -0
  508. codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js.gz +0 -0
  509. codex/static_root/assets/http-error-B3fQGxpt.js +0 -1
  510. codex/static_root/assets/http-error-B3fQGxpt.js.br +0 -0
  511. codex/static_root/assets/http-error-B3fQGxpt.js.gz +0 -0
  512. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js +0 -1
  513. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.br +0 -0
  514. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.gz +0 -0
  515. codex/static_root/assets/index-DUjeNg4x.js +0 -1
  516. codex/static_root/assets/index-DUjeNg4x.js.br +0 -0
  517. codex/static_root/assets/index-DUjeNg4x.js.gz +0 -0
  518. codex/static_root/assets/library-tab-V8DUGoHN.809c548ff347.js.br +0 -0
  519. codex/static_root/assets/library-tab-V8DUGoHN.809c548ff347.js.gz +0 -0
  520. codex/static_root/assets/library-tab-V8DUGoHN.js.br +0 -0
  521. codex/static_root/assets/library-tab-V8DUGoHN.js.gz +0 -0
  522. codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js +0 -32
  523. codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js.br +0 -0
  524. codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js.gz +0 -0
  525. codex/static_root/assets/main-Cavvqkyp.js +0 -32
  526. codex/static_root/assets/main-Cavvqkyp.js.br +0 -0
  527. codex/static_root/assets/main-Cavvqkyp.js.gz +0 -0
  528. codex/static_root/assets/main-sK7HC5h4.6f04ddfc5f1a.css.br +0 -0
  529. codex/static_root/assets/main-sK7HC5h4.css.br +0 -0
  530. codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css +0 -1
  531. codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css.br +0 -0
  532. codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css.gz +0 -0
  533. codex/static_root/assets/pagination-toolbar-ClZui9Zf.css +0 -1
  534. codex/static_root/assets/pagination-toolbar-ClZui9Zf.css.br +0 -0
  535. codex/static_root/assets/pagination-toolbar-ClZui9Zf.css.gz +0 -0
  536. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js +0 -1
  537. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js.br +0 -0
  538. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js.gz +0 -0
  539. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js +0 -1
  540. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js.br +0 -0
  541. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js.gz +0 -0
  542. codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js +0 -35
  543. codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js.br +0 -0
  544. codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js.gz +0 -0
  545. codex/static_root/assets/pdf-doc-4PKLN-Z3.js +0 -35
  546. codex/static_root/assets/pdf-doc-4PKLN-Z3.js.br +0 -0
  547. codex/static_root/assets/pdf-doc-4PKLN-Z3.js.gz +0 -0
  548. codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js +0 -2
  549. codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js.br +0 -0
  550. codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js.gz +0 -0
  551. codex/static_root/assets/reader-C39uGGxn.js +0 -2
  552. codex/static_root/assets/reader-C39uGGxn.js.br +0 -0
  553. codex/static_root/assets/reader-C39uGGxn.js.gz +0 -0
  554. codex/static_root/assets/reader-N2Ei_y2K.8c0cdc0d513f.css +0 -1
  555. codex/static_root/assets/reader-N2Ei_y2K.8c0cdc0d513f.css.br +0 -0
  556. codex/static_root/assets/reader-N2Ei_y2K.8c0cdc0d513f.css.gz +0 -0
  557. codex/static_root/assets/reader-N2Ei_y2K.css +0 -1
  558. codex/static_root/assets/reader-N2Ei_y2K.css.br +0 -0
  559. codex/static_root/assets/reader-N2Ei_y2K.css.gz +0 -0
  560. codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js +0 -1
  561. codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js.br +0 -0
  562. codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js.gz +0 -0
  563. codex/static_root/assets/relation-chips-CAC5ytqH.js +0 -1
  564. codex/static_root/assets/relation-chips-CAC5ytqH.js.br +0 -0
  565. codex/static_root/assets/relation-chips-CAC5ytqH.js.gz +0 -0
  566. codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js +0 -2
  567. codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js.br +0 -0
  568. codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js.gz +0 -0
  569. codex/static_root/assets/settings-drawer-CT73ieiV.js +0 -2
  570. codex/static_root/assets/settings-drawer-CT73ieiV.js.br +0 -0
  571. codex/static_root/assets/settings-drawer-CT73ieiV.js.gz +0 -0
  572. codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js +0 -1
  573. codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js.br +0 -0
  574. codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js.gz +0 -0
  575. codex/static_root/assets/stats-tab-C6qAnV6-.js +0 -1
  576. codex/static_root/assets/stats-tab-C6qAnV6-.js.br +0 -0
  577. codex/static_root/assets/stats-tab-C6qAnV6-.js.gz +0 -0
  578. codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js +0 -1
  579. codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js.br +0 -0
  580. codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js.gz +0 -0
  581. codex/static_root/assets/task-tab-JcG2vvgt.js +0 -1
  582. codex/static_root/assets/task-tab-JcG2vvgt.js.br +0 -0
  583. codex/static_root/assets/task-tab-JcG2vvgt.js.gz +0 -0
  584. codex/static_root/assets/to-case-kUm8NPpW.5b3369f511b8.js +0 -1
  585. codex/static_root/assets/to-case-kUm8NPpW.js +0 -1
  586. codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js +0 -1
  587. codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js.br +0 -0
  588. codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js.gz +0 -0
  589. codex/static_root/assets/unauthorized-28bmiwAU.js +0 -1
  590. codex/static_root/assets/unauthorized-28bmiwAU.js.br +0 -0
  591. codex/static_root/assets/unauthorized-28bmiwAU.js.gz +0 -0
  592. codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js +0 -1
  593. codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js.br +0 -0
  594. codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js.gz +0 -0
  595. codex/static_root/assets/user-tab-BOq4BMMc.js +0 -1
  596. codex/static_root/assets/user-tab-BOq4BMMc.js.br +0 -0
  597. codex/static_root/assets/user-tab-BOq4BMMc.js.gz +0 -0
  598. codex/static_root/js/choices-admin.ef1ff3a8b9da.json +0 -1
  599. codex/static_root/js/choices-admin.ef1ff3a8b9da.json.br +0 -0
  600. codex/static_root/js/choices-admin.ef1ff3a8b9da.json.gz +0 -0
  601. codex/static_root/js/choices.23fedac2b9ba.json +0 -1
  602. codex/static_root/js/choices.23fedac2b9ba.json.br +0 -0
  603. codex/static_root/js/choices.23fedac2b9ba.json.gz +0 -0
  604. codex/static_root/manifest.ad9da9714e46.json +0 -642
  605. codex/static_root/manifest.ad9da9714e46.json.br +0 -0
  606. codex/static_root/manifest.ad9da9714e46.json.gz +0 -0
  607. codex/views/browser/browser_breadcrumbs.py +0 -175
  608. codex/views/browser/const.py +0 -3
  609. codex/views/cover.py +0 -78
  610. {codex-1.6.0a6.dist-info → codex-1.6.0a8.dist-info}/LICENSE +0 -0
  611. {codex-1.6.0a6.dist-info → codex-1.6.0a8.dist-info}/WHEEL +0 -0
  612. {codex-1.6.0a6.dist-info → codex-1.6.0a8.dist-info}/entry_points.txt +0 -0
Binary file
Binary file
@@ -1 +1 @@
1
- {"paths": {"rest_framework/docs/js/highlight.pack.js": "rest_framework/docs/js/highlight.pack.479b5f21dcba.js", "rest_framework/docs/js/jquery.json-view.min.js": "rest_framework/docs/js/jquery.json-view.min.b7c2d6981377.js", "rest_framework/docs/js/api.js": "rest_framework/docs/js/api.18a5ba8a1bd8.js", "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/docs/img/grid.png": "rest_framework/docs/img/grid.a4b938cf382b.png", "rest_framework/docs/img/favicon.ico": "rest_framework/docs/img/favicon.5195b4d0f3eb.ico", "rest_framework/js/ajax-form.js": "rest_framework/js/ajax-form.4e1cdcb7acab.js", "rest_framework/js/load-ajax-form.js": "rest_framework/js/load-ajax-form.8cdb3a9f3466.js", "rest_framework/js/prettify-min.js": "rest_framework/js/prettify-min.709bfcc456c6.js", "rest_framework/js/default.js": "rest_framework/js/default.5b08897dbdc3.js", "rest_framework/js/coreapi-0.1.1.js": "rest_framework/js/coreapi-0.1.1.8851fb9336c9.js", "rest_framework/js/csrf.js": "rest_framework/js/csrf.455080a7b2ce.js", "rest_framework/js/jquery-3.7.1.min.js": "rest_framework/js/jquery-3.7.1.min.2c872dbe60f4.js", "rest_framework/js/bootstrap.min.js": "rest_framework/js/bootstrap.min.2f34b630ffe3.js", "rest_framework/fonts/glyphicons-halflings-regular.woff": "rest_framework/fonts/glyphicons-halflings-regular.fa2772327f55.woff", "rest_framework/fonts/fontawesome-webfont.woff": "rest_framework/fonts/fontawesome-webfont.3293616ec0c6.woff", "rest_framework/fonts/glyphicons-halflings-regular.svg": "rest_framework/fonts/glyphicons-halflings-regular.08eda92397ae.svg", "rest_framework/fonts/fontawesome-webfont.svg": "rest_framework/fonts/fontawesome-webfont.83e37a11f9d7.svg", "rest_framework/fonts/glyphicons-halflings-regular.eot": "rest_framework/fonts/glyphicons-halflings-regular.f4769f9bdb74.eot", "rest_framework/fonts/glyphicons-halflings-regular.woff2": "rest_framework/fonts/glyphicons-halflings-regular.448c34a56d69.woff2", "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/fontawesome-webfont.eot": "rest_framework/fonts/fontawesome-webfont.8b27bc96115c.eot", "rest_framework/css/bootstrap.min.css": "rest_framework/css/bootstrap.min.f17d4516b026.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/bootstrap-theme.min.css.map": "rest_framework/css/bootstrap-theme.min.css.51806092cc05.map", "rest_framework/css/default.css": "rest_framework/css/default.789dfb5732d7.css", "rest_framework/css/font-awesome-4.0.3.css": "rest_framework/css/font-awesome-4.0.3.c1e1ea213abf.css", "rest_framework/css/prettify.css": "rest_framework/css/prettify.a987f72342ee.css", "rest_framework/css/bootstrap.min.css.map": "rest_framework/css/bootstrap.min.css.cafbda9c0e9e.map", "rest_framework/img/grid.png": "rest_framework/img/grid.a4b938cf382b.png", "rest_framework/img/glyphicons-halflings.png": "rest_framework/img/glyphicons-halflings.90233c9067e9.png", "rest_framework/img/glyphicons-halflings-white.png": "rest_framework/img/glyphicons-halflings-white.9bbc6e960299.png", "img/story-arc.svg": "img/story-arc.ca10014355ef.svg", "img/volume.svg": "img/volume.814e4c79461a.svg", "img/publisher.svg": "img/publisher.82d378fcd601.svg", "img/logo-maskable.svg": "img/logo-maskable.8f7de7f1c6a8.svg", "img/series.svg": "img/series.ec8a889b8f95.svg", "img/missing-cover-165.webp": "img/missing-cover-165.0743171f2148.webp", "img/missing-cover.svg": "img/missing-cover.ddb038cc2c56.svg", "img/folder.svg": "img/folder.f28936a3701d.svg", "img/logo.svg": "img/logo.0f5344a028ca.svg", "img/logo-maskable-180.webp": "img/logo-maskable-180.c58d966aa64e.webp", "img/imprint.svg": "img/imprint.7c2adebb76d6.svg", "img/logo-32.webp": "img/logo-32.5688944495bf.webp", "pwa/offline.html": "pwa/offline.7bfaf9f94bf9.html", "js/choices-admin.json": "js/choices-admin.ef1ff3a8b9da.json", "js/choices.json": "js/choices.23fedac2b9ba.json", "assets/VDialog-DiixpkQL.js": "assets/VDialog-DiixpkQL.f84fd1fd1f84.js", "assets/confirm-dialog-ZAZ6P1Rc.js": "assets/confirm-dialog-ZAZ6P1Rc.515858dd21e8.js", "assets/materialdesignicons-webfont-PXm3-2wK.woff": "assets/materialdesignicons-webfont-PXm3-2wK.026b7ac9c43c.woff", "assets/VDialog-C5Nxd_zP.css": "assets/VDialog-C5Nxd_zP.d327f505ef0e.css", "assets/VExpansionPanels-Db5mPFue.js": "assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js", "assets/VTable-DflzroDq.css": "assets/VTable-DflzroDq.160504d82195.css", "assets/datetime-column-BT1MSP82.js": "assets/datetime-column-BT1MSP82.9617f6b94ebf.js", "assets/VExpansionPanels-DsEXVcCv.css": "assets/VExpansionPanels-DsEXVcCv.20b475255e66.css", "assets/unauthorized-28bmiwAU.js": "assets/unauthorized-28bmiwAU.c74825b5c16f.js", "assets/VSelect-BnoCfCLY.js": "assets/VSelect-BnoCfCLY.4d50fd11c77c.js", "assets/settings-drawer-CT73ieiV.js": "assets/settings-drawer-CT73ieiV.fac6f69e86ff.js", "assets/materialdesignicons-webfont-B7mPwVP_.ttf": "assets/materialdesignicons-webfont-B7mPwVP_.6e435534bd35.ttf", "assets/VWindowItem-CFhKCj49.js": "assets/VWindowItem-CFhKCj49.b2458002a937.js", "assets/relation-chips-Bsc-gUxE.css": "assets/relation-chips-Bsc-gUxE.98e65384c3c9.css", "assets/task-tab-JcG2vvgt.js": "assets/task-tab-JcG2vvgt.eed6e03db487.js", "assets/VSelectionControl-BFq--28I.css": "assets/VSelectionControl-BFq--28I.9687c77461fc.css", "assets/VSelectionControl-BSL0qeL9.js": "assets/VSelectionControl-BSL0qeL9.5b5835d286df.js", "assets/group-tab-DFma2R-E.js": "assets/group-tab-DFma2R-E.879c37b15bbd.js", "assets/VSlideGroup-Dk_1upHt.css": "assets/VSlideGroup-Dk_1upHt.2c836070ec75.css", "assets/user-tab-BOq4BMMc.js": "assets/user-tab-BOq4BMMc.b64ac15dd772.js", "assets/VWindowItem-ByIod57Y.css": "assets/VWindowItem-ByIod57Y.f7fb19752bf3.css", "assets/flag-tab-BNwbLfrN.css": "assets/flag-tab-BNwbLfrN.b755a99fff7e.css", "assets/main-Cavvqkyp.js": "assets/main-Cavvqkyp.a9c4df906406.js", "assets/VRadioGroup-i2qP9Wu9.css": "assets/VRadioGroup-i2qP9Wu9.8e3741381961.css", "assets/flag-tab-Ci_XcDT0.js": "assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js", "assets/admin-drawer-panel-C34Ze3-5.js": "assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js", "assets/filter-frSNsexx.js": "assets/filter-frSNsexx.eab1570bd32d.js", "assets/relation-chips-CAC5ytqH.js": "assets/relation-chips-CAC5ytqH.f205d920ffea.js", "assets/VSlideGroup-BQtz8h9p.js": "assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js", "assets/admin-BpGFsvOH.js": "assets/admin-BpGFsvOH.d7193c78d0dd.js", "assets/VTable-C0gAriFq.js": "assets/VTable-C0gAriFq.fa6e4b60d4ef.js", "assets/library-tab-BN0SfPcH.css": "assets/library-tab-BN0SfPcH.913e236f625e.css", "assets/VCombobox-BksEr4D_.css": "assets/VCombobox-BksEr4D_.73429bb75f42.css", "assets/unauthorized-DHV6Q1n-.css": "assets/unauthorized-DHV6Q1n-.b7847b2872a1.css", "assets/http-error-B3fQGxpt.js": "assets/http-error-B3fQGxpt.9efc29496e30.js", "assets/library-tab-V8DUGoHN.js": "assets/library-tab-V8DUGoHN.809c548ff347.js", "assets/change-password-dialog-HvIvmmIE.css": "assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css", "assets/VCheckboxBtn-m4IbdjEe.js": "assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js", "assets/browser-CRPvEdqv.js": "assets/browser-CRPvEdqv.f355a71f4380.js", "assets/materialdesignicons-webfont-CSr8KVlo.eot": "assets/materialdesignicons-webfont-CSr8KVlo.8ced95a05e3c.eot", "assets/index-DUjeNg4x.js": "assets/index-DUjeNg4x.36d50c91b2c1.js", "assets/materialdesignicons-webfont-Dp5v-WZN.woff2": "assets/materialdesignicons-webfont-Dp5v-WZN.1d7bcee1b302.woff2", "assets/confirm-dialog-BmhedLCx.css": "assets/confirm-dialog-BmhedLCx.7c2103d319d4.css", "assets/datetime-column-Dg_RxTVM.css": "assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css", "assets/reader-C39uGGxn.js": "assets/reader-C39uGGxn.67b0f324cd5e.js", "assets/VCheckbox-BS5fdM4M.js": "assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js", "assets/VCheckbox-CMKdyl0R.css": "assets/VCheckbox-CMKdyl0R.016ed8d222c4.css", "assets/pagination-toolbar-Dg9tH1Ju.js": "assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js", "assets/to-case-kUm8NPpW.js": "assets/to-case-kUm8NPpW.5b3369f511b8.js", "assets/stats-tab-TsyG3wH_.css": "assets/stats-tab-TsyG3wH_.b93c080356fc.css", "assets/VCombobox-jg7SI5mn.js": "assets/VCombobox-jg7SI5mn.af66f18b4c54.js", "assets/group-tab-CBKuS3Iv.css": "assets/group-tab-CBKuS3Iv.7e4746634782.css", "assets/VTextField-Da_Hs7ls.js": "assets/VTextField-Da_Hs7ls.c295f24c251e.js", "assets/main-sK7HC5h4.css": "assets/main-sK7HC5h4.6f04ddfc5f1a.css", "assets/pdf-doc-4PKLN-Z3.js": "assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js", "assets/stats-tab-C6qAnV6-.js": "assets/stats-tab-C6qAnV6-.f08c46b5f141.js", "assets/VRadioGroup-DULWiMSI.js": "assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js", "assets/admin-B8Bp2Uih.css": "assets/admin-B8Bp2Uih.82c98714bcf1.css", "assets/pagination-toolbar-ClZui9Zf.css": "assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css", "assets/settings-drawer-nZ9HvKSZ.css": "assets/settings-drawer-nZ9HvKSZ.01744e131806.css", "assets/admin-drawer-panel-BHdNPwzF.css": "assets/admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css", "assets/VSelect-MGVSeLgr.css": "assets/VSelect-MGVSeLgr.7cabd30bc5e4.css", "assets/browser-Zqc9cR6T.css": "assets/browser-Zqc9cR6T.b7d6ddeff130.css", "assets/pdf-doc-CMzaSV_K.css": "assets/pdf-doc-CMzaSV_K.8cd4b3e65f9a.css", "assets/http-error-DKulXuTl.css": "assets/http-error-DKulXuTl.95e42988d5d5.css", "assets/reader-N2Ei_y2K.css": "assets/reader-N2Ei_y2K.8c0cdc0d513f.css", "assets/change-password-dialog-JYM9aAR9.js": "assets/change-password-dialog-JYM9aAR9.f71d378f4fa6.js", "assets/task-tab-1XiWn9xP.css": "assets/task-tab-1XiWn9xP.06cb8e1b794d.css", "assets/VTextField-BssVoDhB.css": "assets/VTextField-BssVoDhB.4cc388b4aa3c.css", "robots.txt": "robots.b6216d61c03e.txt", "manifest.json": "manifest.ad9da9714e46.json"}, "version": "1.1", "hash": "8e018bd6e7e4"}
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.a0aaaa6c7ef7.json", "js/choices-admin.json": "js/choices-admin.d790df01c20a.json", "assets/relation-chips-Bsc-gUxE.css": "assets/relation-chips-Bsc-gUxE.98e65384c3c9.css", "assets/to-case-BR2frjFx.js": "assets/to-case-BR2frjFx.87de5d7a0503.js", "assets/http-error-Cj0hTq-c.js": "assets/http-error-Cj0hTq-c.062a88ddd4dc.js", "assets/group-tab-CBKuS3Iv.css": "assets/group-tab-CBKuS3Iv.7e4746634782.css", "assets/http-error-DKulXuTl.css": "assets/http-error-DKulXuTl.95e42988d5d5.css", "assets/library-tab-CzksdS3Q.js": "assets/library-tab-CzksdS3Q.566acdb45dec.js", "assets/VSelect-ARDhJiQK.css": "assets/VSelect-ARDhJiQK.372c098fb475.css", "assets/flag-tab-BNwbLfrN.css": "assets/flag-tab-BNwbLfrN.b755a99fff7e.css", "assets/VWindowItem-B0KokcAk.js": "assets/VWindowItem-B0KokcAk.ea94224aecb9.js", "assets/VSelectionControl-BFq--28I.css": "assets/VSelectionControl-BFq--28I.9687c77461fc.css", "assets/pdf-doc-CMzaSV_K.css": "assets/pdf-doc-CMzaSV_K.8cd4b3e65f9a.css", "assets/unauthorized-DHV6Q1n-.css": "assets/unauthorized-DHV6Q1n-.b7847b2872a1.css", "assets/VCheckbox-DI-DgMb4.js": "assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js", "assets/group-tab-DucpNoBs.js": "assets/group-tab-DucpNoBs.a6f37ae940c0.js", "assets/materialdesignicons-webfont-PXm3-2wK.woff": "assets/materialdesignicons-webfont-PXm3-2wK.026b7ac9c43c.woff", "assets/stats-tab-R3Ekobfm.js": "assets/stats-tab-R3Ekobfm.70fa09a67518.js", "assets/VSlideGroup-Dk_1upHt.css": "assets/VSlideGroup-Dk_1upHt.2c836070ec75.css", "assets/pagination-toolbar-CQcR0a3T.js": "assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js", "assets/change-password-dialog-CH4xbjJa.js": "assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js", "assets/VTable-DflzroDq.css": "assets/VTable-DflzroDq.160504d82195.css", "assets/settings-drawer-nZ9HvKSZ.css": "assets/settings-drawer-nZ9HvKSZ.01744e131806.css", "assets/VSelect-sIYW_-ud.js": "assets/VSelect-sIYW_-ud.7d40da0ec3ff.js", "assets/main-Ztp855PW.css": "assets/main-Ztp855PW.d46d718fac45.css", "assets/VSlideGroup-BRYhkLH8.js": "assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js", "assets/VRadioGroup-i2qP9Wu9.css": "assets/VRadioGroup-i2qP9Wu9.8e3741381961.css", "assets/task-tab-BhLDK_7Q.js": "assets/task-tab-BhLDK_7Q.28ff51b3ed01.js", "assets/change-password-dialog-HvIvmmIE.css": "assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css", "assets/browser-CMAtBCLx.css": "assets/browser-CMAtBCLx.17a277ce43a9.css", "assets/copy-to-clipboard-DoUvDJVx.js": "assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js", "assets/browser-DoJk8uvb.js": "assets/browser-DoJk8uvb.2c97a3858932.js", "assets/VWindowItem-ByIod57Y.css": "assets/VWindowItem-ByIod57Y.f7fb19752bf3.css", "assets/user-tab-DxITIl2d.js": "assets/user-tab-DxITIl2d.d79d7f062930.js", "assets/stats-tab-TsyG3wH_.css": "assets/stats-tab-TsyG3wH_.b93c080356fc.css", "assets/flag-tab-D4ZNSbMR.js": "assets/flag-tab-D4ZNSbMR.e763a9937701.js", "assets/VTable-D1esKtlw.js": "assets/VTable-D1esKtlw.52165930e3b9.js", "assets/library-tab-BN0SfPcH.css": "assets/library-tab-BN0SfPcH.913e236f625e.css", "assets/VCombobox-D1_0lCri.js": "assets/VCombobox-D1_0lCri.6ef85a29c2dc.js", "assets/confirm-dialog-BmhedLCx.css": "assets/confirm-dialog-BmhedLCx.7c2103d319d4.css", "assets/pdf-doc-GkMk4o5L.js": "assets/pdf-doc-GkMk4o5L.ef24c859a7a4.js", "assets/materialdesignicons-webfont-B7mPwVP_.ttf": "assets/materialdesignicons-webfont-B7mPwVP_.6e435534bd35.ttf", "assets/reader-CCCfpM3x.css": "assets/reader-CCCfpM3x.1553e45bd775.css", "assets/VCombobox-BksEr4D_.css": "assets/VCombobox-BksEr4D_.73429bb75f42.css", "assets/admin-Y0bL21AB.js": "assets/admin-Y0bL21AB.42d4f0d68163.js", "assets/admin-drawer-panel-o87BwD38.css": "assets/admin-drawer-panel-o87BwD38.ce39427c8201.css", "assets/settings-drawer-DyS0A2pN.js": "assets/settings-drawer-DyS0A2pN.17a98928589f.js", "assets/pagination-toolbar-DWdp_kmz.css": "assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css", "assets/reader-Cl6mmQB_.js": "assets/reader-Cl6mmQB_.7b9e7591954f.js", "assets/VRadioGroup-BGa6_q5a.js": "assets/VRadioGroup-BGa6_q5a.d1a3ad7266bd.js", "assets/main-DX-k2724.js": "assets/main-DX-k2724.f73d08e9ad64.js", "assets/admin-B8Bp2Uih.css": "assets/admin-B8Bp2Uih.82c98714bcf1.css", "assets/VSelectionControl-C8DP9rgp.js": "assets/VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js", "assets/confirm-dialog-DkU0twE6.js": "assets/confirm-dialog-DkU0twE6.a20006aa5ba6.js", "assets/task-tab-1XiWn9xP.css": "assets/task-tab-1XiWn9xP.06cb8e1b794d.css", "assets/VTextField-BnGscKcY.js": "assets/VTextField-BnGscKcY.54032adf3a4b.js", "assets/VCheckboxBtn-B8Z4NA-t.js": "assets/VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js", "assets/datetime-column-DeCthByU.css": "assets/datetime-column-DeCthByU.1f3bf499e063.css", "assets/materialdesignicons-webfont-CSr8KVlo.eot": "assets/materialdesignicons-webfont-CSr8KVlo.8ced95a05e3c.eot", "assets/datetime-column-BfW_j_3Q.js": "assets/datetime-column-BfW_j_3Q.6a614321a435.js", "assets/filter-DjxN78cK.js": "assets/filter-DjxN78cK.35673f6e49b1.js", "assets/relation-chips-CZ8VvR4y.js": "assets/relation-chips-CZ8VvR4y.d4232f3c2518.js", "assets/VExpansionPanels-DX2dhUf5.js": "assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js", "assets/VExpansionPanels-DsEXVcCv.css": "assets/VExpansionPanels-DsEXVcCv.20b475255e66.css", "assets/VDialog-C5Nxd_zP.css": "assets/VDialog-C5Nxd_zP.d327f505ef0e.css", "assets/VCheckbox-CMKdyl0R.css": "assets/VCheckbox-CMKdyl0R.016ed8d222c4.css", "assets/VTextField-BssVoDhB.css": "assets/VTextField-BssVoDhB.4cc388b4aa3c.css", "assets/VDialog-opmV0YZz.js": "assets/VDialog-opmV0YZz.d77216e97599.js", "assets/materialdesignicons-webfont-Dp5v-WZN.woff2": "assets/materialdesignicons-webfont-Dp5v-WZN.1d7bcee1b302.woff2", "assets/unauthorized-BbXjAe5l.js": "assets/unauthorized-BbXjAe5l.d48912d34a68.js", "assets/admin-drawer-panel-DNngWUEM.js": "assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js", "robots.txt": "robots.b6216d61c03e.txt", "manifest.json": "manifest.16d52597ef50.json"}, "version": "1.1", "hash": "1cdc90da430d"}
codex/urls/api/auth.py CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  from django.urls import include, path
4
4
 
5
- from codex.views.auth import AdminFlagsView, TimezoneView
5
+ from codex.views.auth import TimezoneView
6
+ from codex.views.public import AdminFlagsView
6
7
 
7
8
  app_name = "auth"
8
9
  urlpatterns = [
codex/urls/api/browser.py CHANGED
@@ -1,14 +1,15 @@
1
1
  """codex:api:v3:browser URL Configuration."""
2
2
 
3
3
  from django.urls import path
4
- from django.views.decorators.cache import cache_page, never_cache
4
+ from django.views.decorators.cache import cache_control, cache_page, never_cache
5
5
 
6
- from codex.urls.const import BROWSER_TIMEOUT, PAGE_MAX_AGE
6
+ from codex.urls.const import BROWSER_TIMEOUT, COVER_MAX_AGE, PAGE_MAX_AGE
7
7
  from codex.views.bookmark import BookmarkView
8
8
  from codex.views.browser.browser import BrowserView
9
9
  from codex.views.browser.choices import BrowserChoicesAvailableView, BrowserChoicesView
10
+ from codex.views.browser.cover import CoverView
10
11
  from codex.views.browser.metadata import MetadataView
11
- from codex.views.browser.session import BrowserSessionView
12
+ from codex.views.browser.settings import BrowserSettingsView
12
13
 
13
14
  METADATA_TIMEOUT = PAGE_MAX_AGE
14
15
 
@@ -45,5 +46,13 @@ urlpatterns = [
45
46
  BookmarkView.as_view(),
46
47
  name="bookmark",
47
48
  ),
48
- path("settings", never_cache(BrowserSessionView.as_view()), name="settings"),
49
+ path("settings", never_cache(BrowserSettingsView.as_view()), name="settings"),
50
+ #
51
+ #
52
+ # Cover
53
+ path(
54
+ "<int_list:pks>/cover.webp",
55
+ cache_control(max_age=COVER_MAX_AGE, public=True)(CoverView.as_view()),
56
+ name="cover",
57
+ ),
49
58
  ]
codex/urls/api/reader.py CHANGED
@@ -3,23 +3,17 @@
3
3
  from django.urls import path
4
4
  from django.views.decorators.cache import cache_control
5
5
 
6
- from codex.urls.const import COVER_MAX_AGE, PAGE_MAX_AGE
7
- from codex.views.cover import CoverView
6
+ from codex.urls.const import PAGE_MAX_AGE
8
7
  from codex.views.download import DownloadView
9
8
  from codex.views.reader.page import ReaderPageView
10
9
  from codex.views.reader.reader import ReaderView
11
- from codex.views.reader.session import ReaderSessionView
10
+ from codex.views.reader.settings import ReaderSettingsView
12
11
 
13
12
  app_name = "issue"
14
13
  urlpatterns = [
15
14
  #
16
15
  #
17
16
  # Comic
18
- path(
19
- "<int:pk>/cover.webp",
20
- cache_control(max_age=COVER_MAX_AGE, public=True)(CoverView.as_view()),
21
- name="cover",
22
- ),
23
17
  path("<int:pk>/download/<str:filename>", DownloadView.as_view(), name="download"),
24
18
  #
25
19
  #
@@ -30,5 +24,5 @@ urlpatterns = [
30
24
  cache_control(max_age=PAGE_MAX_AGE, public=True)(ReaderPageView.as_view()),
31
25
  name="page",
32
26
  ),
33
- path("settings", ReaderSessionView.as_view(), name="settings"),
27
+ path("settings", ReaderSettingsView.as_view(), name="settings"),
34
28
  ]
codex/urls/api/v3.py CHANGED
@@ -3,6 +3,7 @@
3
3
  from django.urls import include, path
4
4
  from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
5
5
 
6
+ from codex.views.mtime import MtimeView
6
7
  from codex.views.opds.urls import OPDSURLsView
7
8
  from codex.views.version import VersionView
8
9
 
@@ -12,6 +13,7 @@ urlpatterns = [
12
13
  # reader must come first to occlude browser group
13
14
  path("c/", include("codex.urls.api.reader")),
14
15
  path("<group:group>/", include("codex.urls.api.browser")),
16
+ path("mtime", MtimeView.as_view(), name="mtimes"),
15
17
  path("version", VersionView.as_view(), name="version"),
16
18
  path("admin/", include("codex.urls.api.admin")),
17
19
  path("schema", SpectacularAPIView.as_view(), name="schema"),
codex/urls/opds/binary.py CHANGED
@@ -20,7 +20,7 @@ urlpatterns = [
20
20
  #
21
21
  # utilities
22
22
  path(
23
- "c/<int:pk>/cover.webp",
23
+ "<str:group>/<int_list:pks>/cover.webp",
24
24
  cache_control(max_age=COVER_MAX_AGE, public=True)(OPDSCoverView.as_view()),
25
25
  name="cover",
26
26
  ),
codex/util.py ADDED
@@ -0,0 +1,10 @@
1
+ """Utility functions."""
2
+
3
+
4
+ def max_none(a, b):
5
+ """None aware math.max."""
6
+ if a is not None and b is not None:
7
+ return max(a, b)
8
+ if a is None:
9
+ return b
10
+ return a
@@ -1,20 +1,16 @@
1
1
  """API Key Endpoint."""
2
2
 
3
- from typing import ClassVar
4
-
5
3
  from drf_spectacular.utils import extend_schema
6
- from rest_framework.generics import GenericAPIView
7
- from rest_framework.permissions import IsAdminUser
8
4
  from rest_framework.response import Response
9
5
 
10
6
  from codex.models import Timestamp
11
7
  from codex.serializers.admin import APIKeySerializer
8
+ from codex.views.admin.auth import AdminGenericAPIView
12
9
 
13
10
 
14
- class AdminAPIKey(GenericAPIView):
11
+ class AdminAPIKey(AdminGenericAPIView):
15
12
  """Regenerate API Key."""
16
13
 
17
- permission_classes: ClassVar[list] = [IsAdminUser] # type: ignore
18
14
  serializer_class = APIKeySerializer
19
15
  input_serializer_class = None
20
16
 
@@ -0,0 +1,28 @@
1
+ """Admin Auth."""
2
+
3
+ from rest_framework.generics import GenericAPIView
4
+ from rest_framework.permissions import IsAdminUser
5
+ from rest_framework.views import APIView
6
+ from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
7
+
8
+
9
+ class AdminAuthMixin:
10
+ """Admin Authorization Classes."""
11
+
12
+ permission_classes = (IsAdminUser,)
13
+
14
+
15
+ class AdminAPIView(AdminAuthMixin, APIView):
16
+ """Admin API View."""
17
+
18
+
19
+ class AdminGenericAPIView(AdminAuthMixin, GenericAPIView):
20
+ """Admin Generic API View."""
21
+
22
+
23
+ class AdminModelViewSet(AdminAuthMixin, ModelViewSet):
24
+ """Admin Model View Set."""
25
+
26
+
27
+ class AdminReadOnlyModelViewSet(AdminAuthMixin, ReadOnlyModelViewSet):
28
+ """Admin Read Only Model View Set."""
codex/views/admin/flag.py CHANGED
@@ -1,24 +1,19 @@
1
1
  """Admin Flag View."""
2
2
 
3
- from typing import ClassVar
4
-
5
- from rest_framework.permissions import IsAdminUser
6
- from rest_framework.viewsets import ModelViewSet
7
-
8
3
  from codex.librarian.mp_queue import LIBRARIAN_QUEUE
9
4
  from codex.librarian.notifier.tasks import LIBRARY_CHANGED_TASK
10
5
  from codex.logger.logging import get_logger
11
6
  from codex.models import AdminFlag
12
7
  from codex.registration import patch_registration_setting
13
8
  from codex.serializers.admin import AdminFlagSerializer
9
+ from codex.views.admin.auth import AdminModelViewSet
14
10
 
15
11
  LOG = get_logger(__name__)
16
12
 
17
13
 
18
- class AdminFlagViewSet(ModelViewSet):
14
+ class AdminFlagViewSet(AdminModelViewSet):
19
15
  """Admin Flag Viewset."""
20
16
 
21
- permission_classes: ClassVar[list] = [IsAdminUser] # type: ignore
22
17
  queryset = AdminFlag.objects.all()
23
18
  serializer_class = AdminFlagSerializer
24
19
  lookup_field = "key"
@@ -1,24 +1,20 @@
1
1
  """Group View."""
2
2
 
3
- from typing import ClassVar
4
-
5
3
  from django.contrib.auth.models import Group
6
4
  from django.core.cache import cache
7
- from rest_framework.permissions import IsAdminUser
8
- from rest_framework.viewsets import ModelViewSet
9
5
 
10
6
  from codex.librarian.mp_queue import LIBRARIAN_QUEUE
11
7
  from codex.librarian.notifier.tasks import LIBRARY_CHANGED_TASK
12
8
  from codex.logger.logging import get_logger
13
9
  from codex.serializers.admin import GroupSerializer
10
+ from codex.views.admin.auth import AdminModelViewSet
14
11
 
15
12
  LOG = get_logger(__name__)
16
13
 
17
14
 
18
- class AdminGroupViewSet(ModelViewSet):
15
+ class AdminGroupViewSet(AdminModelViewSet):
19
16
  """Admin Group Viewset."""
20
17
 
21
- permission_classes: ClassVar[list] = [IsAdminUser] # type: ignore
22
18
  queryset = Group.objects.prefetch_related("user_set", "library_set").select_related(
23
19
  "groupauth"
24
20
  )
@@ -2,16 +2,12 @@
2
2
 
3
3
  from pathlib import Path
4
4
  from time import time
5
- from typing import ClassVar
6
5
 
7
6
  from django.core.cache import cache
8
7
  from django.db.utils import NotSupportedError
9
8
  from drf_spectacular.utils import extend_schema
10
9
  from rest_framework.exceptions import ValidationError
11
- from rest_framework.generics import GenericAPIView
12
- from rest_framework.permissions import IsAdminUser
13
10
  from rest_framework.response import Response
14
- from rest_framework.viewsets import ModelViewSet
15
11
 
16
12
  from codex.librarian.mp_queue import LIBRARIAN_QUEUE
17
13
  from codex.librarian.notifier.tasks import LIBRARY_CHANGED_TASK
@@ -28,20 +24,15 @@ from codex.serializers.admin import (
28
24
  FailedImportSerializer,
29
25
  LibrarySerializer,
30
26
  )
27
+ from codex.views.admin.auth import AdminGenericAPIView, AdminModelViewSet
31
28
 
32
29
  LOG = get_logger(__name__)
33
30
 
34
31
 
35
- class AdminModelViewSet(ModelViewSet):
36
- """Admin ModelViewSet."""
37
-
38
- permission_classes: ClassVar[list] = [IsAdminUser] # type: ignore
39
-
40
-
41
32
  class AdminLibraryViewSet(AdminModelViewSet):
42
33
  """Admin Library Viewset."""
43
34
 
44
- WATCHDOG_SYNC_FIELDS = frozenset({"events", "poll", "pollEvery"})
35
+ _WATCHDOG_SYNC_FIELDS = frozenset({"events", "poll", "pollEvery"})
45
36
 
46
37
  queryset = Library.objects.prefetch_related("groups").defer(
47
38
  "update_in_progress", "created_at", "updated_at"
@@ -51,7 +42,7 @@ class AdminLibraryViewSet(AdminModelViewSet):
51
42
  @classmethod
52
43
  def _sync_watchdog(cls, validated_keys=None):
53
44
  if validated_keys is None or validated_keys.intersection(
54
- cls.WATCHDOG_SYNC_FIELDS
45
+ cls._WATCHDOG_SYNC_FIELDS
55
46
  ):
56
47
  task = DelayedTasks(time() + 2, (WatchdogSyncTask(),))
57
48
  LIBRARIAN_QUEUE.put(task)
@@ -68,9 +59,6 @@ class AdminLibraryViewSet(AdminModelViewSet):
68
59
  )
69
60
  folder.save()
70
61
 
71
- def _get_pk(self):
72
- return self.kwargs["pk"]
73
-
74
62
  @staticmethod
75
63
  def _poll(pk, force):
76
64
  task = WatchdogPollLibrariesTask(frozenset({pk}), force)
@@ -117,10 +105,9 @@ class AdminFailedImportViewSet(AdminModelViewSet):
117
105
  serializer_class = FailedImportSerializer
118
106
 
119
107
 
120
- class AdminFolderListView(GenericAPIView):
108
+ class AdminFolderListView(AdminGenericAPIView):
121
109
  """List server directories."""
122
110
 
123
- permission_classes: ClassVar[list] = [IsAdminUser] # type:ignore
124
111
  serializer_class = AdminFolderListSerializer
125
112
  input_serializer_class = AdminFolderSerializer
126
113
 
@@ -128,10 +115,10 @@ class AdminFolderListView(GenericAPIView):
128
115
  def get(self, *_args, **_kwargs):
129
116
  """Get subdirectories for a path."""
130
117
  try:
131
- serializer = self.input_serializer_class(data=self.request.query_params)
118
+ serializer = self.input_serializer_class(data=self.request.GET)
132
119
  serializer.is_valid(raise_exception=True)
133
- path = Path(serializer.validated_data.get("path", "."))
134
- show_hidden = serializer.validated_data.get("show_hidden", False)
120
+ path = Path(serializer.validated_data.get("path", ".")) # type: ignore
121
+ show_hidden = serializer.validated_data.get("show_hidden", False) # type: ignore
135
122
  root_path = path.resolve()
136
123
 
137
124
  dirs = []
@@ -6,97 +6,38 @@ from types import MappingProxyType
6
6
  from typing import ClassVar
7
7
 
8
8
  from caseconverter import snakecase
9
- from django.contrib.auth.models import Group, User
10
9
  from django.contrib.sessions.models import Session
11
10
  from django.db.models import Count
12
11
  from drf_spectacular.utils import extend_schema
13
- from rest_framework.generics import GenericAPIView
14
12
  from rest_framework.response import Response
15
13
 
16
14
  from codex.logger.logging import get_logger
17
15
  from codex.models import (
18
- AgeRating,
19
- Character,
20
16
  Comic,
21
- Contributor,
22
- ContributorPerson,
23
- ContributorRole,
24
- Country,
25
- Folder,
26
- Genre,
27
- Identifier,
28
- IdentifierType,
29
- Imprint,
30
- Language,
31
17
  Library,
32
- Location,
33
- OriginalFormat,
34
- Publisher,
35
- ScanInfo,
36
- Series,
37
- SeriesGroup,
38
- StoryArc,
39
- StoryArcNumber,
40
- Tag,
41
- Tagger,
42
- Team,
43
18
  Timestamp,
44
- Volume,
45
19
  )
46
20
  from codex.permissions import HasAPIKeyOrIsAdminUser
47
21
  from codex.serializers.admin import AdminStatsRequestSerializer, AdminStatsSerializer
48
22
  from codex.version import VERSION
23
+ from codex.views.admin.auth import AdminGenericAPIView
24
+ from codex.views.const import CONFIG_MODELS, GROUP_MODELS, METADATA_MODELS
49
25
 
50
26
  LOG = get_logger(__name__)
51
27
 
52
28
 
53
- class AdminStatsView(GenericAPIView):
29
+ class AdminStatsView(AdminGenericAPIView):
54
30
  """Admin Flag Viewset."""
55
31
 
56
32
  permission_classes: ClassVar[list] = [HasAPIKeyOrIsAdminUser] # type: ignore
57
33
  serializer_class = AdminStatsSerializer
58
34
  input_serializer_class = AdminStatsRequestSerializer
59
35
 
60
- _GROUP_MODELS = (
61
- Publisher,
62
- Imprint,
63
- Series,
64
- Volume,
65
- Comic,
66
- Folder,
67
- )
68
- _METADATA_MODELS = (
69
- AgeRating,
70
- Character,
71
- Country,
72
- Genre,
73
- Identifier,
74
- IdentifierType,
75
- Language,
76
- Location,
77
- OriginalFormat,
78
- SeriesGroup,
79
- ScanInfo,
80
- StoryArc,
81
- StoryArcNumber,
82
- Team,
83
- Tag,
84
- Tagger,
85
- Contributor,
86
- ContributorPerson,
87
- ContributorRole,
88
- )
89
- _CONFIG_MODELS = (
90
- Library,
91
- User,
92
- Group,
93
- Session,
94
- )
95
36
  _KEY_MODELS_MAP = MappingProxyType(
96
37
  {
97
- "config": _CONFIG_MODELS,
98
- "groups": _GROUP_MODELS,
99
- "metadata": _METADATA_MODELS,
38
+ "config": CONFIG_MODELS,
39
+ "groups": GROUP_MODELS,
40
+ "metadata": METADATA_MODELS,
100
41
  }
101
42
  )
102
43
  _DOCKERENV_PATH = Path("/.dockerenv")
@@ -243,7 +184,7 @@ class AdminStatsView(GenericAPIView):
243
184
  """Get the stats object and serialize it."""
244
185
  input_serializer = self.input_serializer_class(data=self.request.GET)
245
186
  input_serializer.is_valid()
246
- self.params = frozenset(input_serializer.validated_data.get("params", {}))
187
+ self.params = frozenset(input_serializer.validated_data.get("params", {})) # type: ignore
247
188
 
248
189
  obj = self.get_object()
249
190
  serializer = self.get_serializer(obj)
@@ -1,19 +1,21 @@
1
1
  """Librarian Status View."""
2
2
 
3
+ from datetime import datetime, timezone
3
4
  from types import MappingProxyType
4
- from typing import ClassVar
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  from drf_spectacular.utils import extend_schema
7
- from rest_framework.permissions import IsAdminUser
8
8
  from rest_framework.response import Response
9
- from rest_framework.views import APIView
10
- from rest_framework.viewsets import ReadOnlyModelViewSet
11
9
 
12
10
  from codex.librarian.covers.tasks import (
13
11
  CoverCreateAllTask,
14
12
  CoverRemoveAllTask,
15
13
  CoverRemoveOrphansTask,
16
14
  )
15
+ from codex.librarian.importer.tasks import (
16
+ AdoptOrphanFoldersTask,
17
+ UpdateGroupsFirstComic,
18
+ )
17
19
  from codex.librarian.janitor.tasks import (
18
20
  ForceUpdateAllFailedImportsTask,
19
21
  JanitorBackupTask,
@@ -46,24 +48,27 @@ from codex.models import LibrarianStatus
46
48
  from codex.serializers.admin import AdminLibrarianTaskSerializer
47
49
  from codex.serializers.mixins import OKSerializer
48
50
  from codex.serializers.models.admin import LibrarianStatusSerializer
51
+ from codex.views.admin.auth import AdminAPIView, AdminReadOnlyModelViewSet
52
+
53
+ if TYPE_CHECKING:
54
+ from collections.abc import Mapping
49
55
 
50
56
  LOG = get_logger(__name__)
57
+ _EPOCH_START = datetime.fromtimestamp(0, tz=timezone.utc)
51
58
 
52
59
 
53
- class AdminLibrarianStatusViewSet(ReadOnlyModelViewSet):
60
+ class AdminLibrarianStatusViewSet(AdminReadOnlyModelViewSet):
54
61
  """Librarian Task Statuses."""
55
62
 
56
- permission_classes: ClassVar[list] = [IsAdminUser] # type: ignore
57
63
  queryset = LibrarianStatus.objects.filter(active__isnull=False).order_by(
58
64
  "active", "pk"
59
65
  )
60
66
  serializer_class = LibrarianStatusSerializer
61
67
 
62
68
 
63
- class AdminLibrarianTaskView(APIView):
69
+ class AdminLibrarianTaskView(AdminAPIView):
64
70
  """Queue Librarian Jobs."""
65
71
 
66
- permission_classes: ClassVar[list] = [IsAdminUser] # type: ignore
67
72
  input_serializer_class = AdminLibrarianTaskSerializer
68
73
  serializer_class = OKSerializer
69
74
 
@@ -98,6 +103,11 @@ class AdminLibrarianTaskView(APIView):
98
103
  "poll": WatchdogPollLibrariesTask(frozenset(), False),
99
104
  "poll_force": WatchdogPollLibrariesTask(frozenset(), True),
100
105
  "janitor_nightly": JanitorNightlyTask(),
106
+ "update_first_covers": UpdateGroupsFirstComic(),
107
+ "force_update_first_covers": UpdateGroupsFirstComic(
108
+ start_time=_EPOCH_START
109
+ ),
110
+ "adopt_folders": AdoptOrphanFoldersTask(),
101
111
  }
102
112
  )
103
113
 
@@ -114,10 +124,13 @@ class AdminLibrarianTaskView(APIView):
114
124
  @extend_schema(request=input_serializer_class)
115
125
  def post(self, *_args, **_kwargs):
116
126
  """Download a comic archive."""
117
- serializer = self.input_serializer_class(data=self.request.data)
127
+ # DRF does not populate POST correctly, only data
128
+ data = self.request.data # type:ignore
129
+ serializer = self.input_serializer_class(data=data)
118
130
  serializer.is_valid(raise_exception=True)
119
- task_name = serializer.validated_data.get("task")
120
- pk = serializer.validated_data.get("library_id")
131
+ validated_data: Mapping = serializer.validated_data # type: ignore
132
+ task_name = validated_data.get("task")
133
+ pk = validated_data.get("library_id")
121
134
  task = self._get_task(task_name, pk)
122
135
  if task:
123
136
  LIBRARIAN_QUEUE.put(task)
codex/views/admin/user.py CHANGED
@@ -1,29 +1,24 @@
1
1
  """Admin User ViewSet."""
2
2
 
3
- from typing import ClassVar
4
-
5
3
  from django.contrib.auth.models import User
6
4
  from django.contrib.auth.password_validation import validate_password
7
5
  from django.core.cache import cache
8
6
  from django.core.exceptions import ValidationError
9
- from rest_framework.generics import GenericAPIView
10
- from rest_framework.permissions import IsAdminUser
11
7
  from rest_framework.response import Response
12
8
  from rest_framework.status import HTTP_202_ACCEPTED, HTTP_400_BAD_REQUEST
13
- from rest_framework.viewsets import ModelViewSet
14
9
 
15
10
  from codex.librarian.mp_queue import LIBRARIAN_QUEUE
16
11
  from codex.librarian.notifier.tasks import LIBRARY_CHANGED_TASK
17
12
  from codex.logger.logging import get_logger
18
13
  from codex.serializers.admin import UserChangePasswordSerializer, UserSerializer
14
+ from codex.views.admin.auth import AdminGenericAPIView, AdminModelViewSet
19
15
 
20
16
  LOG = get_logger(__name__)
21
17
 
22
18
 
23
- class AdminUserViewSet(ModelViewSet):
19
+ class AdminUserViewSet(AdminModelViewSet):
24
20
  """User ViewSet."""
25
21
 
26
- permission_classes: ClassVar[list] = [IsAdminUser] # type: ignore
27
22
  queryset = User.objects.prefetch_related("groups").defer(
28
23
  "first_name", "last_name", "email"
29
24
  )
@@ -55,10 +50,9 @@ class AdminUserViewSet(ModelViewSet):
55
50
  self._on_change()
56
51
 
57
52
 
58
- class AdminUserChangePasswordView(GenericAPIView):
53
+ class AdminUserChangePasswordView(AdminGenericAPIView):
59
54
  """Special View to hash user password."""
60
55
 
61
- permission_classes: ClassVar[list] = [IsAdminUser] # type: ignore
62
56
  serializer_class = UserChangePasswordSerializer
63
57
 
64
58
  def put(self, request, *args, **kwargs):