codex 1.6.0a6__py3-none-any.whl → 1.6.0a7__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 (548) hide show
  1. codex/exceptions.py +1 -0
  2. codex/librarian/importer/aggregate_metadata.py +2 -10
  3. codex/librarian/importer/{covers.py → cache.py} +2 -2
  4. codex/librarian/importer/importerd.py +5 -3
  5. codex/librarian/janitor/janitor.py +1 -1
  6. codex/librarian/librariand.py +1 -1
  7. codex/permissions.py +1 -1
  8. codex/serializers/admin.py +1 -2
  9. codex/serializers/browser/filters.py +8 -101
  10. codex/serializers/browser/mixins.py +20 -3
  11. codex/serializers/browser/page.py +2 -2
  12. codex/serializers/browser/settings.py +2 -0
  13. codex/serializers/fields.py +123 -0
  14. codex/serializers/mtime.py +25 -0
  15. codex/serializers/opds/v2.py +7 -11
  16. codex/serializers/opds/v2_unused.py +5 -3
  17. codex/serializers/reader.py +5 -2
  18. codex/serializers/route.py +7 -3
  19. codex/static_root/assets/VCheckbox-BOUtyxuo.c690f0cdbe48.js +1 -0
  20. codex/static_root/assets/VCheckbox-BOUtyxuo.c690f0cdbe48.js.br +0 -0
  21. codex/static_root/assets/VCheckbox-BOUtyxuo.c690f0cdbe48.js.gz +0 -0
  22. codex/static_root/assets/VCheckbox-BOUtyxuo.js +1 -0
  23. codex/static_root/assets/VCheckbox-BOUtyxuo.js.br +0 -0
  24. codex/static_root/assets/VCheckbox-BOUtyxuo.js.gz +0 -0
  25. codex/static_root/assets/VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js +1 -0
  26. codex/static_root/assets/VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js.br +0 -0
  27. codex/static_root/assets/VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js.gz +0 -0
  28. codex/static_root/assets/VCheckboxBtn-B1-m5pEh.js +1 -0
  29. codex/static_root/assets/VCheckboxBtn-B1-m5pEh.js.br +0 -0
  30. codex/static_root/assets/VCheckboxBtn-B1-m5pEh.js.gz +0 -0
  31. codex/static_root/assets/VCombobox-DjkDXe33.22617ea193b1.js +1 -0
  32. codex/static_root/assets/VCombobox-DjkDXe33.22617ea193b1.js.br +0 -0
  33. codex/static_root/assets/VCombobox-DjkDXe33.22617ea193b1.js.gz +0 -0
  34. codex/static_root/assets/VCombobox-DjkDXe33.js +1 -0
  35. codex/static_root/assets/VCombobox-DjkDXe33.js.br +0 -0
  36. codex/static_root/assets/VCombobox-DjkDXe33.js.gz +0 -0
  37. codex/static_root/assets/VDialog-X0zn9AGX.0d89c749b9a6.js +1 -0
  38. codex/static_root/assets/VDialog-X0zn9AGX.0d89c749b9a6.js.br +0 -0
  39. codex/static_root/assets/VDialog-X0zn9AGX.0d89c749b9a6.js.gz +0 -0
  40. codex/static_root/assets/VDialog-X0zn9AGX.js +1 -0
  41. codex/static_root/assets/VDialog-X0zn9AGX.js.br +0 -0
  42. codex/static_root/assets/VDialog-X0zn9AGX.js.gz +0 -0
  43. codex/static_root/assets/VExpansionPanels-CRevojaF.43d65c777c58.js +1 -0
  44. codex/static_root/assets/VExpansionPanels-CRevojaF.43d65c777c58.js.br +0 -0
  45. codex/static_root/assets/VExpansionPanels-CRevojaF.43d65c777c58.js.gz +0 -0
  46. codex/static_root/assets/VExpansionPanels-CRevojaF.js +1 -0
  47. codex/static_root/assets/VExpansionPanels-CRevojaF.js.br +0 -0
  48. codex/static_root/assets/VExpansionPanels-CRevojaF.js.gz +0 -0
  49. codex/static_root/assets/VRadioGroup-8nrrxjDv.2b4dfb984a8c.js +1 -0
  50. codex/static_root/assets/VRadioGroup-8nrrxjDv.2b4dfb984a8c.js.br +0 -0
  51. codex/static_root/assets/VRadioGroup-8nrrxjDv.2b4dfb984a8c.js.gz +0 -0
  52. codex/static_root/assets/VRadioGroup-8nrrxjDv.js +1 -0
  53. codex/static_root/assets/VRadioGroup-8nrrxjDv.js.br +0 -0
  54. codex/static_root/assets/VRadioGroup-8nrrxjDv.js.gz +0 -0
  55. codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js +1 -0
  56. codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js.br +0 -0
  57. codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js.gz +0 -0
  58. codex/static_root/assets/VSelect-DgfIKRnC.js +1 -0
  59. codex/static_root/assets/VSelect-DgfIKRnC.js.br +0 -0
  60. codex/static_root/assets/VSelect-DgfIKRnC.js.gz +0 -0
  61. codex/static_root/assets/VSelectionControl-CGu0oz0K.3030b7a270d6.js +1 -0
  62. codex/static_root/assets/VSelectionControl-CGu0oz0K.3030b7a270d6.js.br +0 -0
  63. codex/static_root/assets/VSelectionControl-CGu0oz0K.3030b7a270d6.js.gz +0 -0
  64. codex/static_root/assets/VSelectionControl-CGu0oz0K.js +1 -0
  65. codex/static_root/assets/VSelectionControl-CGu0oz0K.js.br +0 -0
  66. codex/static_root/assets/VSelectionControl-CGu0oz0K.js.gz +0 -0
  67. codex/static_root/assets/VSlideGroup-D_oNvCOd.71a7101cdddd.js +1 -0
  68. codex/static_root/assets/VSlideGroup-D_oNvCOd.71a7101cdddd.js.br +0 -0
  69. codex/static_root/assets/VSlideGroup-D_oNvCOd.71a7101cdddd.js.gz +0 -0
  70. codex/static_root/assets/VSlideGroup-D_oNvCOd.js +1 -0
  71. codex/static_root/assets/VSlideGroup-D_oNvCOd.js.br +0 -0
  72. codex/static_root/assets/VSlideGroup-D_oNvCOd.js.gz +0 -0
  73. codex/static_root/assets/{VTable-C0gAriFq.fa6e4b60d4ef.js → VTable-C7pKI7gU.087912f706f5.js} +1 -1
  74. codex/static_root/assets/VTable-C7pKI7gU.087912f706f5.js.br +0 -0
  75. codex/static_root/assets/VTable-C7pKI7gU.087912f706f5.js.gz +0 -0
  76. codex/static_root/assets/{VTable-C0gAriFq.js → VTable-C7pKI7gU.js} +1 -1
  77. codex/static_root/assets/VTable-C7pKI7gU.js.br +0 -0
  78. codex/static_root/assets/VTable-C7pKI7gU.js.gz +0 -0
  79. codex/static_root/assets/{VTextField-Da_Hs7ls.c295f24c251e.js → VTextField-Bs8oq9mk.7999fef12a03.js} +1 -1
  80. codex/static_root/assets/VTextField-Bs8oq9mk.7999fef12a03.js.br +0 -0
  81. codex/static_root/assets/VTextField-Bs8oq9mk.7999fef12a03.js.gz +0 -0
  82. codex/static_root/assets/{VTextField-Da_Hs7ls.js → VTextField-Bs8oq9mk.js} +1 -1
  83. codex/static_root/assets/VTextField-Bs8oq9mk.js.br +0 -0
  84. codex/static_root/assets/VTextField-Bs8oq9mk.js.gz +0 -0
  85. codex/static_root/assets/{VWindowItem-CFhKCj49.b2458002a937.js → VWindowItem-iyZ1XOkP.409f7d292253.js} +1 -1
  86. codex/static_root/assets/VWindowItem-iyZ1XOkP.409f7d292253.js.br +0 -0
  87. codex/static_root/assets/VWindowItem-iyZ1XOkP.409f7d292253.js.gz +0 -0
  88. codex/static_root/assets/{VWindowItem-CFhKCj49.js → VWindowItem-iyZ1XOkP.js} +1 -1
  89. codex/static_root/assets/VWindowItem-iyZ1XOkP.js.br +0 -0
  90. codex/static_root/assets/VWindowItem-iyZ1XOkP.js.gz +0 -0
  91. codex/static_root/assets/admin-B0pCBjma.2407da79bd20.js +1 -0
  92. codex/static_root/assets/admin-B0pCBjma.2407da79bd20.js.br +0 -0
  93. codex/static_root/assets/admin-B0pCBjma.2407da79bd20.js.gz +0 -0
  94. codex/static_root/assets/admin-B0pCBjma.js +1 -0
  95. codex/static_root/assets/admin-B0pCBjma.js.br +0 -0
  96. codex/static_root/assets/admin-B0pCBjma.js.gz +0 -0
  97. codex/static_root/assets/admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js +30 -0
  98. codex/static_root/assets/admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js.br +0 -0
  99. codex/static_root/assets/admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js.gz +0 -0
  100. codex/static_root/assets/admin-drawer-panel-BxoNUHQr.js +30 -0
  101. codex/static_root/assets/admin-drawer-panel-BxoNUHQr.js.br +0 -0
  102. codex/static_root/assets/admin-drawer-panel-BxoNUHQr.js.gz +0 -0
  103. codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css → admin-drawer-panel-o87BwD38.ce39427c8201.css} +1 -1
  104. codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.br +0 -0
  105. codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css.gz → admin-drawer-panel-o87BwD38.ce39427c8201.css.gz} +0 -0
  106. codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.css → admin-drawer-panel-o87BwD38.css} +1 -1
  107. codex/static_root/assets/admin-drawer-panel-o87BwD38.css.br +0 -0
  108. codex/static_root/assets/{admin-drawer-panel-BHdNPwzF.css.gz → admin-drawer-panel-o87BwD38.css.gz} +0 -0
  109. codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js +1 -0
  110. codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js.br +0 -0
  111. codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js.gz +0 -0
  112. codex/static_root/assets/browser-DbyAjCNh.js +1 -0
  113. codex/static_root/assets/browser-DbyAjCNh.js.br +0 -0
  114. codex/static_root/assets/browser-DbyAjCNh.js.gz +0 -0
  115. codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css +1 -0
  116. codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css.br +0 -0
  117. codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css.gz +0 -0
  118. codex/static_root/assets/browser-VnzNj1t3.css +1 -0
  119. codex/static_root/assets/browser-VnzNj1t3.css.br +0 -0
  120. codex/static_root/assets/browser-VnzNj1t3.css.gz +0 -0
  121. codex/static_root/assets/{change-password-dialog-JYM9aAR9.f71d378f4fa6.js → change-password-dialog-DZ9dP8_F.930f4cae3cb0.js} +1 -1
  122. codex/static_root/assets/change-password-dialog-DZ9dP8_F.930f4cae3cb0.js.br +0 -0
  123. codex/static_root/assets/change-password-dialog-DZ9dP8_F.930f4cae3cb0.js.gz +0 -0
  124. codex/static_root/assets/{change-password-dialog-JYM9aAR9.js → change-password-dialog-DZ9dP8_F.js} +1 -1
  125. codex/static_root/assets/change-password-dialog-DZ9dP8_F.js.br +0 -0
  126. codex/static_root/assets/change-password-dialog-DZ9dP8_F.js.gz +0 -0
  127. codex/static_root/assets/{confirm-dialog-ZAZ6P1Rc.515858dd21e8.js → confirm-dialog-RP7JNStF.a752a7c1e697.js} +1 -1
  128. codex/static_root/assets/confirm-dialog-RP7JNStF.a752a7c1e697.js.br +0 -0
  129. codex/static_root/assets/confirm-dialog-RP7JNStF.a752a7c1e697.js.gz +0 -0
  130. codex/static_root/assets/{confirm-dialog-ZAZ6P1Rc.js → confirm-dialog-RP7JNStF.js} +1 -1
  131. codex/static_root/assets/confirm-dialog-RP7JNStF.js.br +0 -0
  132. codex/static_root/assets/confirm-dialog-RP7JNStF.js.gz +0 -0
  133. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js +1 -0
  134. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js.br +0 -0
  135. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js +1 -0
  136. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js.br +0 -0
  137. codex/static_root/assets/{datetime-column-BT1MSP82.9617f6b94ebf.js → datetime-column-Cu3WYyPj.54b4c3817b74.js} +1 -1
  138. codex/static_root/assets/datetime-column-Cu3WYyPj.54b4c3817b74.js.br +0 -0
  139. codex/static_root/assets/datetime-column-Cu3WYyPj.54b4c3817b74.js.gz +0 -0
  140. codex/static_root/assets/{datetime-column-BT1MSP82.js → datetime-column-Cu3WYyPj.js} +1 -1
  141. codex/static_root/assets/datetime-column-Cu3WYyPj.js.br +0 -0
  142. codex/static_root/assets/datetime-column-Cu3WYyPj.js.gz +0 -0
  143. codex/static_root/assets/filter-DAdGUt-1.3261cbcd50b5.js +1 -0
  144. codex/static_root/assets/filter-DAdGUt-1.3261cbcd50b5.js.br +0 -0
  145. codex/static_root/assets/filter-DAdGUt-1.3261cbcd50b5.js.gz +0 -0
  146. codex/static_root/assets/filter-DAdGUt-1.js +1 -0
  147. codex/static_root/assets/filter-DAdGUt-1.js.br +0 -0
  148. codex/static_root/assets/filter-DAdGUt-1.js.gz +0 -0
  149. codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js +1 -0
  150. codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js.br +0 -0
  151. codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js.gz +0 -0
  152. codex/static_root/assets/flag-tab-BP7Zs7iQ.js +1 -0
  153. codex/static_root/assets/flag-tab-BP7Zs7iQ.js.br +0 -0
  154. codex/static_root/assets/flag-tab-BP7Zs7iQ.js.gz +0 -0
  155. codex/static_root/assets/{group-tab-DFma2R-E.879c37b15bbd.js → group-tab-DEwh4jfB.a95097b5e320.js} +1 -1
  156. codex/static_root/assets/group-tab-DEwh4jfB.a95097b5e320.js.br +0 -0
  157. codex/static_root/assets/group-tab-DEwh4jfB.a95097b5e320.js.gz +0 -0
  158. codex/static_root/assets/{group-tab-DFma2R-E.js → group-tab-DEwh4jfB.js} +1 -1
  159. codex/static_root/assets/group-tab-DEwh4jfB.js.br +0 -0
  160. codex/static_root/assets/group-tab-DEwh4jfB.js.gz +0 -0
  161. codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js +1 -0
  162. codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js.br +0 -0
  163. codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js.gz +0 -0
  164. codex/static_root/assets/http-error-xs3mIL8U.js +1 -0
  165. codex/static_root/assets/http-error-xs3mIL8U.js.br +0 -0
  166. codex/static_root/assets/http-error-xs3mIL8U.js.gz +0 -0
  167. codex/static_root/assets/{library-tab-V8DUGoHN.809c548ff347.js → library-tab-DrXvD9B2.f765f9d3bae4.js} +1 -1
  168. codex/static_root/assets/library-tab-DrXvD9B2.f765f9d3bae4.js.br +0 -0
  169. codex/static_root/assets/library-tab-DrXvD9B2.f765f9d3bae4.js.gz +0 -0
  170. codex/static_root/assets/{library-tab-V8DUGoHN.js → library-tab-DrXvD9B2.js} +1 -1
  171. codex/static_root/assets/library-tab-DrXvD9B2.js.br +0 -0
  172. codex/static_root/assets/library-tab-DrXvD9B2.js.gz +0 -0
  173. codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js +32 -0
  174. codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js.br +0 -0
  175. codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js.gz +0 -0
  176. codex/static_root/assets/main-Dy9Uqpmh.js +32 -0
  177. codex/static_root/assets/main-Dy9Uqpmh.js.br +0 -0
  178. codex/static_root/assets/main-Dy9Uqpmh.js.gz +0 -0
  179. codex/static_root/assets/{main-sK7HC5h4.css → main-Ztp855PW.css} +1 -1
  180. codex/static_root/assets/main-Ztp855PW.css.br +0 -0
  181. codex/static_root/assets/{main-sK7HC5h4.css.gz → main-Ztp855PW.css.gz} +0 -0
  182. codex/static_root/assets/{main-sK7HC5h4.6f04ddfc5f1a.css → main-Ztp855PW.d46d718fac45.css} +1 -1
  183. codex/static_root/assets/main-Ztp855PW.d46d718fac45.css.br +0 -0
  184. codex/static_root/assets/{main-sK7HC5h4.6f04ddfc5f1a.css.gz → main-Ztp855PW.d46d718fac45.css.gz} +0 -0
  185. codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js +1 -0
  186. codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js.br +0 -0
  187. codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js.gz +0 -0
  188. codex/static_root/assets/pagination-toolbar-DbS_HOT1.js +1 -0
  189. codex/static_root/assets/pagination-toolbar-DbS_HOT1.js.br +0 -0
  190. codex/static_root/assets/pagination-toolbar-DbS_HOT1.js.gz +0 -0
  191. codex/static_root/assets/{pagination-toolbar-ClZui9Zf.697d7ae11c21.css → pagination-toolbar-r6nbtWxg.4088ab042c0c.css} +1 -1
  192. codex/static_root/assets/pagination-toolbar-r6nbtWxg.4088ab042c0c.css.br +0 -0
  193. codex/static_root/assets/pagination-toolbar-r6nbtWxg.4088ab042c0c.css.gz +0 -0
  194. codex/static_root/assets/{pagination-toolbar-ClZui9Zf.css → pagination-toolbar-r6nbtWxg.css} +1 -1
  195. codex/static_root/assets/pagination-toolbar-r6nbtWxg.css.br +0 -0
  196. codex/static_root/assets/pagination-toolbar-r6nbtWxg.css.gz +0 -0
  197. codex/static_root/assets/pdf-doc-obrBwxa6.ec9bd13a5786.js +305 -0
  198. codex/static_root/assets/pdf-doc-obrBwxa6.ec9bd13a5786.js.br +0 -0
  199. codex/static_root/assets/pdf-doc-obrBwxa6.ec9bd13a5786.js.gz +0 -0
  200. codex/static_root/assets/pdf-doc-obrBwxa6.js +305 -0
  201. codex/static_root/assets/pdf-doc-obrBwxa6.js.br +0 -0
  202. codex/static_root/assets/pdf-doc-obrBwxa6.js.gz +0 -0
  203. codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js +2 -0
  204. codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js.br +0 -0
  205. codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js.gz +0 -0
  206. codex/static_root/assets/reader-BXKUaUeC.js +2 -0
  207. codex/static_root/assets/reader-BXKUaUeC.js.br +0 -0
  208. codex/static_root/assets/reader-BXKUaUeC.js.gz +0 -0
  209. codex/static_root/assets/{reader-N2Ei_y2K.8c0cdc0d513f.css → reader-OXJ1KVaW.a463b19d0508.css} +1 -1
  210. codex/static_root/assets/reader-OXJ1KVaW.a463b19d0508.css.br +0 -0
  211. codex/static_root/assets/reader-OXJ1KVaW.a463b19d0508.css.gz +0 -0
  212. codex/static_root/assets/{reader-N2Ei_y2K.css → reader-OXJ1KVaW.css} +1 -1
  213. codex/static_root/assets/reader-OXJ1KVaW.css.br +0 -0
  214. codex/static_root/assets/reader-OXJ1KVaW.css.gz +0 -0
  215. codex/static_root/assets/relation-chips-CZJcLjc8.1d7426dab654.js +1 -0
  216. codex/static_root/assets/relation-chips-CZJcLjc8.1d7426dab654.js.br +0 -0
  217. codex/static_root/assets/relation-chips-CZJcLjc8.1d7426dab654.js.gz +0 -0
  218. codex/static_root/assets/relation-chips-CZJcLjc8.js +1 -0
  219. codex/static_root/assets/relation-chips-CZJcLjc8.js.br +0 -0
  220. codex/static_root/assets/relation-chips-CZJcLjc8.js.gz +0 -0
  221. codex/static_root/assets/settings-drawer-7iTnAdjf.337eecf2fdbb.js +2 -0
  222. codex/static_root/assets/settings-drawer-7iTnAdjf.337eecf2fdbb.js.br +0 -0
  223. codex/static_root/assets/settings-drawer-7iTnAdjf.337eecf2fdbb.js.gz +0 -0
  224. codex/static_root/assets/settings-drawer-7iTnAdjf.js +2 -0
  225. codex/static_root/assets/settings-drawer-7iTnAdjf.js.br +0 -0
  226. codex/static_root/assets/settings-drawer-7iTnAdjf.js.gz +0 -0
  227. codex/static_root/assets/stats-tab-CQsK1n8O.544bf50ffb22.js +1 -0
  228. codex/static_root/assets/stats-tab-CQsK1n8O.544bf50ffb22.js.br +0 -0
  229. codex/static_root/assets/stats-tab-CQsK1n8O.544bf50ffb22.js.gz +0 -0
  230. codex/static_root/assets/stats-tab-CQsK1n8O.js +1 -0
  231. codex/static_root/assets/stats-tab-CQsK1n8O.js.br +0 -0
  232. codex/static_root/assets/stats-tab-CQsK1n8O.js.gz +0 -0
  233. codex/static_root/assets/task-tab-C60TLP6e.63aa929a4ed6.js +1 -0
  234. codex/static_root/assets/task-tab-C60TLP6e.63aa929a4ed6.js.br +0 -0
  235. codex/static_root/assets/task-tab-C60TLP6e.63aa929a4ed6.js.gz +0 -0
  236. codex/static_root/assets/task-tab-C60TLP6e.js +1 -0
  237. codex/static_root/assets/task-tab-C60TLP6e.js.br +0 -0
  238. codex/static_root/assets/task-tab-C60TLP6e.js.gz +0 -0
  239. codex/static_root/assets/to-case-CR9beRR0.21bb805fdab4.js +1 -0
  240. codex/static_root/assets/to-case-CR9beRR0.js +1 -0
  241. codex/static_root/assets/unauthorized-Bs7NSqea.c55650fac055.js +1 -0
  242. codex/static_root/assets/unauthorized-Bs7NSqea.c55650fac055.js.br +0 -0
  243. codex/static_root/assets/unauthorized-Bs7NSqea.c55650fac055.js.gz +0 -0
  244. codex/static_root/assets/unauthorized-Bs7NSqea.js +1 -0
  245. codex/static_root/assets/unauthorized-Bs7NSqea.js.br +0 -0
  246. codex/static_root/assets/unauthorized-Bs7NSqea.js.gz +0 -0
  247. codex/static_root/assets/user-tab-ChuH7Atm.7e80cf1fb78e.js +1 -0
  248. codex/static_root/assets/user-tab-ChuH7Atm.7e80cf1fb78e.js.br +0 -0
  249. codex/static_root/assets/user-tab-ChuH7Atm.7e80cf1fb78e.js.gz +0 -0
  250. codex/static_root/assets/user-tab-ChuH7Atm.js +1 -0
  251. codex/static_root/assets/user-tab-ChuH7Atm.js.br +0 -0
  252. codex/static_root/assets/user-tab-ChuH7Atm.js.gz +0 -0
  253. codex/static_root/js/choices.079a01e0be1a.json +1 -0
  254. codex/static_root/js/choices.079a01e0be1a.json.br +0 -0
  255. codex/static_root/js/choices.079a01e0be1a.json.gz +0 -0
  256. codex/static_root/js/choices.json +1 -1
  257. codex/static_root/js/choices.json.br +0 -0
  258. codex/static_root/js/choices.json.gz +0 -0
  259. codex/static_root/manifest.dad79c8475ae.json +629 -0
  260. codex/static_root/manifest.dad79c8475ae.json.br +0 -0
  261. codex/static_root/manifest.dad79c8475ae.json.gz +0 -0
  262. codex/static_root/manifest.json +263 -276
  263. codex/static_root/manifest.json.br +0 -0
  264. codex/static_root/manifest.json.gz +0 -0
  265. codex/static_root/staticfiles.json +1 -1
  266. codex/urls/api/auth.py +2 -1
  267. codex/urls/api/browser.py +2 -2
  268. codex/urls/api/reader.py +2 -2
  269. codex/urls/api/v3.py +2 -0
  270. codex/util.py +10 -0
  271. codex/views/admin/api_key.py +2 -6
  272. codex/views/admin/auth.py +30 -0
  273. codex/views/admin/flag.py +2 -7
  274. codex/views/admin/group.py +2 -6
  275. codex/views/admin/library.py +7 -20
  276. codex/views/admin/stats.py +7 -66
  277. codex/views/admin/tasks.py +12 -11
  278. codex/views/admin/user.py +3 -9
  279. codex/views/auth.py +31 -52
  280. codex/views/bookmark.py +7 -11
  281. codex/views/browser/{browser_annotations.py → annotations.py} +91 -61
  282. codex/views/browser/base.py +23 -71
  283. codex/views/browser/breadcrumbs.py +200 -0
  284. codex/views/browser/browser.py +64 -337
  285. codex/views/browser/choices.py +25 -33
  286. codex/views/browser/filters/annotations.py +2 -2
  287. codex/views/browser/filters/bookmark.py +9 -13
  288. codex/views/browser/filters/field.py +6 -5
  289. codex/views/browser/filters/group.py +8 -5
  290. codex/views/browser/filters/search.py +11 -8
  291. codex/views/browser/metadata.py +3 -7
  292. codex/views/browser/{browser_order_by.py → order_by.py} +2 -6
  293. codex/views/browser/paginate.py +106 -0
  294. codex/views/browser/{session.py → settings.py} +4 -3
  295. codex/views/browser/title.py +48 -0
  296. codex/views/browser/validate.py +158 -0
  297. codex/views/const.py +97 -0
  298. codex/views/cover.py +4 -6
  299. codex/views/download.py +5 -8
  300. codex/views/frontend.py +4 -2
  301. codex/views/mtime.py +70 -0
  302. codex/views/opds/auth.py +17 -0
  303. codex/views/opds/authentication_v1.py +46 -45
  304. codex/views/opds/binary.py +4 -9
  305. codex/views/opds/const.py +13 -0
  306. codex/views/opds/urls.py +5 -4
  307. codex/views/opds/util.py +2 -8
  308. codex/views/opds/v1/facets.py +6 -7
  309. codex/views/opds/v1/feed.py +10 -17
  310. codex/views/opds/v1/links.py +6 -5
  311. codex/views/opds/v1/opensearch_v1.py +2 -6
  312. codex/views/opds/v2/feed.py +12 -15
  313. codex/views/opds/v2/links.py +3 -2
  314. codex/views/opds/v2/publications.py +21 -20
  315. codex/views/opds/v2/top_links.py +2 -2
  316. codex/views/public.py +38 -0
  317. codex/views/reader/arcs.py +101 -0
  318. codex/views/reader/books.py +199 -0
  319. codex/views/reader/page.py +3 -7
  320. codex/views/reader/reader.py +53 -298
  321. codex/views/reader/{session.py → settings.py} +4 -2
  322. codex/views/session.py +74 -102
  323. codex/views/settings.py +34 -0
  324. codex/views/template.py +3 -3
  325. codex/views/util.py +31 -0
  326. codex/views/utils.py +26 -0
  327. codex/views/version.py +2 -2
  328. {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/METADATA +12 -8
  329. {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/RECORD +332 -320
  330. codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js +0 -1
  331. codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js.br +0 -0
  332. codex/static_root/assets/VCheckbox-BS5fdM4M.a5d446e4aeb3.js.gz +0 -0
  333. codex/static_root/assets/VCheckbox-BS5fdM4M.js +0 -1
  334. codex/static_root/assets/VCheckbox-BS5fdM4M.js.br +0 -0
  335. codex/static_root/assets/VCheckbox-BS5fdM4M.js.gz +0 -0
  336. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js +0 -1
  337. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js.br +0 -0
  338. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.f0c4a814ded8.js.gz +0 -0
  339. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.js +0 -1
  340. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.js.br +0 -0
  341. codex/static_root/assets/VCheckboxBtn-m4IbdjEe.js.gz +0 -0
  342. codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js +0 -1
  343. codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js.br +0 -0
  344. codex/static_root/assets/VCombobox-jg7SI5mn.af66f18b4c54.js.gz +0 -0
  345. codex/static_root/assets/VCombobox-jg7SI5mn.js +0 -1
  346. codex/static_root/assets/VCombobox-jg7SI5mn.js.br +0 -0
  347. codex/static_root/assets/VCombobox-jg7SI5mn.js.gz +0 -0
  348. codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js +0 -1
  349. codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js.br +0 -0
  350. codex/static_root/assets/VDialog-DiixpkQL.f84fd1fd1f84.js.gz +0 -0
  351. codex/static_root/assets/VDialog-DiixpkQL.js +0 -1
  352. codex/static_root/assets/VDialog-DiixpkQL.js.br +0 -0
  353. codex/static_root/assets/VDialog-DiixpkQL.js.gz +0 -0
  354. codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js +0 -1
  355. codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js.br +0 -0
  356. codex/static_root/assets/VExpansionPanels-Db5mPFue.56d0ad094a62.js.gz +0 -0
  357. codex/static_root/assets/VExpansionPanels-Db5mPFue.js +0 -1
  358. codex/static_root/assets/VExpansionPanels-Db5mPFue.js.br +0 -0
  359. codex/static_root/assets/VExpansionPanels-Db5mPFue.js.gz +0 -0
  360. codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js +0 -1
  361. codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js.br +0 -0
  362. codex/static_root/assets/VRadioGroup-DULWiMSI.4ae535e01d2b.js.gz +0 -0
  363. codex/static_root/assets/VRadioGroup-DULWiMSI.js +0 -1
  364. codex/static_root/assets/VRadioGroup-DULWiMSI.js.br +0 -0
  365. codex/static_root/assets/VRadioGroup-DULWiMSI.js.gz +0 -0
  366. codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js +0 -1
  367. codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js.br +0 -0
  368. codex/static_root/assets/VSelect-BnoCfCLY.4d50fd11c77c.js.gz +0 -0
  369. codex/static_root/assets/VSelect-BnoCfCLY.js +0 -1
  370. codex/static_root/assets/VSelect-BnoCfCLY.js.br +0 -0
  371. codex/static_root/assets/VSelect-BnoCfCLY.js.gz +0 -0
  372. codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js +0 -1
  373. codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js.br +0 -0
  374. codex/static_root/assets/VSelectionControl-BSL0qeL9.5b5835d286df.js.gz +0 -0
  375. codex/static_root/assets/VSelectionControl-BSL0qeL9.js +0 -1
  376. codex/static_root/assets/VSelectionControl-BSL0qeL9.js.br +0 -0
  377. codex/static_root/assets/VSelectionControl-BSL0qeL9.js.gz +0 -0
  378. codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js +0 -1
  379. codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js.br +0 -0
  380. codex/static_root/assets/VSlideGroup-BQtz8h9p.ff97dbf209e1.js.gz +0 -0
  381. codex/static_root/assets/VSlideGroup-BQtz8h9p.js +0 -1
  382. codex/static_root/assets/VSlideGroup-BQtz8h9p.js.br +0 -0
  383. codex/static_root/assets/VSlideGroup-BQtz8h9p.js.gz +0 -0
  384. codex/static_root/assets/VTable-C0gAriFq.fa6e4b60d4ef.js.br +0 -0
  385. codex/static_root/assets/VTable-C0gAriFq.fa6e4b60d4ef.js.gz +0 -0
  386. codex/static_root/assets/VTable-C0gAriFq.js.br +0 -0
  387. codex/static_root/assets/VTable-C0gAriFq.js.gz +0 -0
  388. codex/static_root/assets/VTextField-Da_Hs7ls.c295f24c251e.js.br +0 -0
  389. codex/static_root/assets/VTextField-Da_Hs7ls.c295f24c251e.js.gz +0 -0
  390. codex/static_root/assets/VTextField-Da_Hs7ls.js.br +0 -0
  391. codex/static_root/assets/VTextField-Da_Hs7ls.js.gz +0 -0
  392. codex/static_root/assets/VWindowItem-CFhKCj49.b2458002a937.js.br +0 -0
  393. codex/static_root/assets/VWindowItem-CFhKCj49.b2458002a937.js.gz +0 -0
  394. codex/static_root/assets/VWindowItem-CFhKCj49.js.br +0 -0
  395. codex/static_root/assets/VWindowItem-CFhKCj49.js.gz +0 -0
  396. codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js +0 -1
  397. codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js.br +0 -0
  398. codex/static_root/assets/admin-BpGFsvOH.d7193c78d0dd.js.gz +0 -0
  399. codex/static_root/assets/admin-BpGFsvOH.js +0 -1
  400. codex/static_root/assets/admin-BpGFsvOH.js.br +0 -0
  401. codex/static_root/assets/admin-BpGFsvOH.js.gz +0 -0
  402. codex/static_root/assets/admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css.br +0 -0
  403. codex/static_root/assets/admin-drawer-panel-BHdNPwzF.css.br +0 -0
  404. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js +0 -30
  405. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js.br +0 -0
  406. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.113c50cdf2cc.js.gz +0 -0
  407. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js +0 -30
  408. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js.br +0 -0
  409. codex/static_root/assets/admin-drawer-panel-C34Ze3-5.js.gz +0 -0
  410. codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js +0 -1
  411. codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js.br +0 -0
  412. codex/static_root/assets/browser-CRPvEdqv.f355a71f4380.js.gz +0 -0
  413. codex/static_root/assets/browser-CRPvEdqv.js +0 -1
  414. codex/static_root/assets/browser-CRPvEdqv.js.br +0 -0
  415. codex/static_root/assets/browser-CRPvEdqv.js.gz +0 -0
  416. codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css +0 -1
  417. codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css.br +0 -0
  418. codex/static_root/assets/browser-Zqc9cR6T.b7d6ddeff130.css.gz +0 -0
  419. codex/static_root/assets/browser-Zqc9cR6T.css +0 -1
  420. codex/static_root/assets/browser-Zqc9cR6T.css.br +0 -0
  421. codex/static_root/assets/browser-Zqc9cR6T.css.gz +0 -0
  422. codex/static_root/assets/change-password-dialog-JYM9aAR9.f71d378f4fa6.js.br +0 -0
  423. codex/static_root/assets/change-password-dialog-JYM9aAR9.f71d378f4fa6.js.gz +0 -0
  424. codex/static_root/assets/change-password-dialog-JYM9aAR9.js.br +0 -0
  425. codex/static_root/assets/change-password-dialog-JYM9aAR9.js.gz +0 -0
  426. codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.515858dd21e8.js.br +0 -0
  427. codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.515858dd21e8.js.gz +0 -0
  428. codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.js.br +0 -0
  429. codex/static_root/assets/confirm-dialog-ZAZ6P1Rc.js.gz +0 -0
  430. codex/static_root/assets/datetime-column-BT1MSP82.9617f6b94ebf.js.br +0 -0
  431. codex/static_root/assets/datetime-column-BT1MSP82.9617f6b94ebf.js.gz +0 -0
  432. codex/static_root/assets/datetime-column-BT1MSP82.js.br +0 -0
  433. codex/static_root/assets/datetime-column-BT1MSP82.js.gz +0 -0
  434. codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js +0 -1
  435. codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js.br +0 -0
  436. codex/static_root/assets/filter-frSNsexx.eab1570bd32d.js.gz +0 -0
  437. codex/static_root/assets/filter-frSNsexx.js +0 -1
  438. codex/static_root/assets/filter-frSNsexx.js.br +0 -0
  439. codex/static_root/assets/filter-frSNsexx.js.gz +0 -0
  440. codex/static_root/assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js +0 -1
  441. codex/static_root/assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js.br +0 -0
  442. codex/static_root/assets/flag-tab-Ci_XcDT0.a5ea640a08d6.js.gz +0 -0
  443. codex/static_root/assets/flag-tab-Ci_XcDT0.js +0 -1
  444. codex/static_root/assets/flag-tab-Ci_XcDT0.js.br +0 -0
  445. codex/static_root/assets/flag-tab-Ci_XcDT0.js.gz +0 -0
  446. codex/static_root/assets/group-tab-DFma2R-E.879c37b15bbd.js.br +0 -0
  447. codex/static_root/assets/group-tab-DFma2R-E.879c37b15bbd.js.gz +0 -0
  448. codex/static_root/assets/group-tab-DFma2R-E.js.br +0 -0
  449. codex/static_root/assets/group-tab-DFma2R-E.js.gz +0 -0
  450. codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js +0 -1
  451. codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js.br +0 -0
  452. codex/static_root/assets/http-error-B3fQGxpt.9efc29496e30.js.gz +0 -0
  453. codex/static_root/assets/http-error-B3fQGxpt.js +0 -1
  454. codex/static_root/assets/http-error-B3fQGxpt.js.br +0 -0
  455. codex/static_root/assets/http-error-B3fQGxpt.js.gz +0 -0
  456. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js +0 -1
  457. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.br +0 -0
  458. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.gz +0 -0
  459. codex/static_root/assets/index-DUjeNg4x.js +0 -1
  460. codex/static_root/assets/index-DUjeNg4x.js.br +0 -0
  461. codex/static_root/assets/index-DUjeNg4x.js.gz +0 -0
  462. codex/static_root/assets/library-tab-V8DUGoHN.809c548ff347.js.br +0 -0
  463. codex/static_root/assets/library-tab-V8DUGoHN.809c548ff347.js.gz +0 -0
  464. codex/static_root/assets/library-tab-V8DUGoHN.js.br +0 -0
  465. codex/static_root/assets/library-tab-V8DUGoHN.js.gz +0 -0
  466. codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js +0 -32
  467. codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js.br +0 -0
  468. codex/static_root/assets/main-Cavvqkyp.a9c4df906406.js.gz +0 -0
  469. codex/static_root/assets/main-Cavvqkyp.js +0 -32
  470. codex/static_root/assets/main-Cavvqkyp.js.br +0 -0
  471. codex/static_root/assets/main-Cavvqkyp.js.gz +0 -0
  472. codex/static_root/assets/main-sK7HC5h4.6f04ddfc5f1a.css.br +0 -0
  473. codex/static_root/assets/main-sK7HC5h4.css.br +0 -0
  474. codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css.br +0 -0
  475. codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css.gz +0 -0
  476. codex/static_root/assets/pagination-toolbar-ClZui9Zf.css.br +0 -0
  477. codex/static_root/assets/pagination-toolbar-ClZui9Zf.css.gz +0 -0
  478. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js +0 -1
  479. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js.br +0 -0
  480. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.b2eb1e0c6985.js.gz +0 -0
  481. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js +0 -1
  482. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js.br +0 -0
  483. codex/static_root/assets/pagination-toolbar-Dg9tH1Ju.js.gz +0 -0
  484. codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js +0 -35
  485. codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js.br +0 -0
  486. codex/static_root/assets/pdf-doc-4PKLN-Z3.62d8de4d1fd8.js.gz +0 -0
  487. codex/static_root/assets/pdf-doc-4PKLN-Z3.js +0 -35
  488. codex/static_root/assets/pdf-doc-4PKLN-Z3.js.br +0 -0
  489. codex/static_root/assets/pdf-doc-4PKLN-Z3.js.gz +0 -0
  490. codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js +0 -2
  491. codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js.br +0 -0
  492. codex/static_root/assets/reader-C39uGGxn.67b0f324cd5e.js.gz +0 -0
  493. codex/static_root/assets/reader-C39uGGxn.js +0 -2
  494. codex/static_root/assets/reader-C39uGGxn.js.br +0 -0
  495. codex/static_root/assets/reader-C39uGGxn.js.gz +0 -0
  496. codex/static_root/assets/reader-N2Ei_y2K.8c0cdc0d513f.css.br +0 -0
  497. codex/static_root/assets/reader-N2Ei_y2K.8c0cdc0d513f.css.gz +0 -0
  498. codex/static_root/assets/reader-N2Ei_y2K.css.br +0 -0
  499. codex/static_root/assets/reader-N2Ei_y2K.css.gz +0 -0
  500. codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js +0 -1
  501. codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js.br +0 -0
  502. codex/static_root/assets/relation-chips-CAC5ytqH.f205d920ffea.js.gz +0 -0
  503. codex/static_root/assets/relation-chips-CAC5ytqH.js +0 -1
  504. codex/static_root/assets/relation-chips-CAC5ytqH.js.br +0 -0
  505. codex/static_root/assets/relation-chips-CAC5ytqH.js.gz +0 -0
  506. codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js +0 -2
  507. codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js.br +0 -0
  508. codex/static_root/assets/settings-drawer-CT73ieiV.fac6f69e86ff.js.gz +0 -0
  509. codex/static_root/assets/settings-drawer-CT73ieiV.js +0 -2
  510. codex/static_root/assets/settings-drawer-CT73ieiV.js.br +0 -0
  511. codex/static_root/assets/settings-drawer-CT73ieiV.js.gz +0 -0
  512. codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js +0 -1
  513. codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js.br +0 -0
  514. codex/static_root/assets/stats-tab-C6qAnV6-.f08c46b5f141.js.gz +0 -0
  515. codex/static_root/assets/stats-tab-C6qAnV6-.js +0 -1
  516. codex/static_root/assets/stats-tab-C6qAnV6-.js.br +0 -0
  517. codex/static_root/assets/stats-tab-C6qAnV6-.js.gz +0 -0
  518. codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js +0 -1
  519. codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js.br +0 -0
  520. codex/static_root/assets/task-tab-JcG2vvgt.eed6e03db487.js.gz +0 -0
  521. codex/static_root/assets/task-tab-JcG2vvgt.js +0 -1
  522. codex/static_root/assets/task-tab-JcG2vvgt.js.br +0 -0
  523. codex/static_root/assets/task-tab-JcG2vvgt.js.gz +0 -0
  524. codex/static_root/assets/to-case-kUm8NPpW.5b3369f511b8.js +0 -1
  525. codex/static_root/assets/to-case-kUm8NPpW.js +0 -1
  526. codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js +0 -1
  527. codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js.br +0 -0
  528. codex/static_root/assets/unauthorized-28bmiwAU.c74825b5c16f.js.gz +0 -0
  529. codex/static_root/assets/unauthorized-28bmiwAU.js +0 -1
  530. codex/static_root/assets/unauthorized-28bmiwAU.js.br +0 -0
  531. codex/static_root/assets/unauthorized-28bmiwAU.js.gz +0 -0
  532. codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js +0 -1
  533. codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js.br +0 -0
  534. codex/static_root/assets/user-tab-BOq4BMMc.b64ac15dd772.js.gz +0 -0
  535. codex/static_root/assets/user-tab-BOq4BMMc.js +0 -1
  536. codex/static_root/assets/user-tab-BOq4BMMc.js.br +0 -0
  537. codex/static_root/assets/user-tab-BOq4BMMc.js.gz +0 -0
  538. codex/static_root/js/choices.23fedac2b9ba.json +0 -1
  539. codex/static_root/js/choices.23fedac2b9ba.json.br +0 -0
  540. codex/static_root/js/choices.23fedac2b9ba.json.gz +0 -0
  541. codex/static_root/manifest.ad9da9714e46.json +0 -642
  542. codex/static_root/manifest.ad9da9714e46.json.br +0 -0
  543. codex/static_root/manifest.ad9da9714e46.json.gz +0 -0
  544. codex/views/browser/browser_breadcrumbs.py +0 -175
  545. codex/views/browser/const.py +0 -3
  546. {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/LICENSE +0 -0
  547. {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/WHEEL +0 -0
  548. {codex-1.6.0a6.dist-info → codex-1.6.0a7.dist-info}/entry_points.txt +0 -0
codex/exceptions.py CHANGED
@@ -30,6 +30,7 @@ class SeeOtherRedirectError(APIException):
30
30
  route: dict = detail.get("route", {}) # type: ignore
31
31
  params: dict = route.get("params", DEFAULTS["breadcrumbs"][0])
32
32
  # Save route in server format for redirect reverse
33
+ params.pop("name", None)
33
34
  self.route_kwargs = params
34
35
  # Serialize route for detail
35
36
  serializer = RouteSerializer(params)
@@ -28,6 +28,7 @@ from codex.librarian.importer.status import ImportStatusTypes, status_notify
28
28
  from codex.models import Imprint, Publisher, Series, Volume
29
29
  from codex.models.admin import AdminFlag
30
30
  from codex.status import Status
31
+ from codex.util import max_none
31
32
 
32
33
 
33
34
  class AggregateMetadataMixin(CleanMetadataMixin):
@@ -182,22 +183,13 @@ class AggregateMetadataMixin(CleanMetadataMixin):
182
183
  all_fks[field] = set()
183
184
  all_fks[field].add(name)
184
185
 
185
- @staticmethod
186
- def _none_max(a, b):
187
- """None aware math.max."""
188
- if a is not None and b is not None:
189
- return max(a, b)
190
- if a is None:
191
- return b
192
- return a
193
-
194
186
  @classmethod
195
187
  def _set_max_group_count(cls, common_args, group_class, index, count_key):
196
188
  """Assign the maximum group count number."""
197
189
  all_fks, group_tree, group_md = common_args
198
190
  group_name = group_tree[0:index]
199
191
  try:
200
- count = cls._none_max(
192
+ count = max_none(
201
193
  all_fks[GROUP_TREES][Series].get(group_name),
202
194
  group_md.get(count_key),
203
195
  )
@@ -6,10 +6,10 @@ from django.db.models.query import Q
6
6
  from codex.models import StoryArc
7
7
 
8
8
 
9
- class CoversMixin:
9
+ class CacheMixin:
10
10
  """Update Groups timestamp for cover cache busting."""
11
11
 
12
- def update_groups_for_covers(self, start_time, deleted_comic_groups):
12
+ def update_groups_with_changed_comics(self, start_time, deleted_comic_groups):
13
13
  """Update timestamps for each group for cover cache busting."""
14
14
  total_count = 0
15
15
  now = Now()
@@ -9,8 +9,8 @@ from django.utils.timezone import now
9
9
  from humanize import naturaldelta
10
10
 
11
11
  from codex.librarian.importer.aggregate_metadata import AggregateMetadataMixin
12
+ from codex.librarian.importer.cache import CacheMixin
12
13
  from codex.librarian.importer.const import FIS, FKS, M2M_MDS, MDS
13
- from codex.librarian.importer.covers import CoversMixin
14
14
  from codex.librarian.importer.deleted import DeletedMixin
15
15
  from codex.librarian.importer.failed_imports import FailedImportsMixin
16
16
  from codex.librarian.importer.moved import MovedMixin
@@ -37,7 +37,7 @@ class ComicImporterThread(
37
37
  UpdateComicsMixin,
38
38
  FailedImportsMixin,
39
39
  MovedMixin,
40
- CoversMixin,
40
+ CacheMixin,
41
41
  ):
42
42
  """A worker to handle all bulk database updates."""
43
43
 
@@ -386,7 +386,9 @@ class ComicImporterThread(
386
386
  deleted_comic_groups = {}
387
387
  changed += self.delete(library, task, deleted_comic_groups)
388
388
 
389
- self.update_groups_for_covers(import_start_time, deleted_comic_groups)
389
+ self.update_groups_with_changed_comics(
390
+ import_start_time, deleted_comic_groups
391
+ )
390
392
 
391
393
  if changed:
392
394
  cache.clear()
@@ -76,7 +76,7 @@ class Janitor(CleanupMixin, UpdateMixin, VacuumMixin, UpdateFailedImportsMixin):
76
76
  except Exception:
77
77
  self.log.exception(f"In {self.__class__.__name__}")
78
78
 
79
- def run(self, task):
79
+ def run(self, task): # noqa: PLR0912,C901
80
80
  """Run Janitor tasks as the librarian process directly."""
81
81
  try:
82
82
  match task:
@@ -77,7 +77,7 @@ class LibrarianDaemon(Process, LoggerBaseMixin):
77
77
  self.queue.put(task)
78
78
  self.search_indexer_abort_event = Manager().Event()
79
79
 
80
- def _process_task(self, task):
80
+ def _process_task(self, task): # noqa: PLR0912,C901
81
81
  """Process an individual task popped off the queue."""
82
82
  match task:
83
83
  case CoverTask():
codex/permissions.py CHANGED
@@ -8,7 +8,7 @@ from codex.models import Timestamp
8
8
  class HasAPIKeyOrIsAdminUser(BasePermission):
9
9
  """Does the request have the current api key."""
10
10
 
11
- def has_permission(self, request, view):
11
+ def has_permission(self, request, view): # type: ignore
12
12
  """Test the request api key against the database."""
13
13
  data = request.GET if request.method == "GET" else request.POST
14
14
  api_key = data.get("apiKey")
@@ -173,8 +173,7 @@ class AdminFolderSerializer(Serializer):
173
173
  def validate_show_hidden(self, show_hidden):
174
174
  """Snakecase the showHidden field."""
175
175
  return (
176
- show_hidden == "true"
177
- or self.initial_data.get("showHidden", False) == "true"
176
+ show_hidden == "true" or self.initial_data.get("showHidden") == "true" # type: ignore
178
177
  )
179
178
 
180
179
 
@@ -1,23 +1,19 @@
1
1
  """Browser Settings Filter Serializers."""
2
2
 
3
- from abc import ABC
4
-
5
- from django.core.exceptions import ValidationError
6
- from django.utils.translation import gettext_lazy as _
7
- from rest_framework.fields import Field
8
3
  from rest_framework.serializers import (
9
4
  BooleanField,
10
- CharField,
11
5
  ChoiceField,
12
- FloatField,
13
- IntegerField,
14
- ListField,
15
6
  Serializer,
16
7
  )
17
8
 
18
- from codex.serializers.choices import CHOICES, VUETIFY_NULL_CODE
19
-
20
- VUETIFY_NULL_CODE_STR = str(VUETIFY_NULL_CODE)
9
+ from codex.serializers.choices import CHOICES
10
+ from codex.serializers.fields import (
11
+ BooleanListField,
12
+ CharListField,
13
+ DecadeListField,
14
+ FloatListField,
15
+ IntListField,
16
+ )
21
17
 
22
18
 
23
19
  class BrowserFilterChoicesSerializer(Serializer):
@@ -47,95 +43,6 @@ class BrowserFilterChoicesSerializer(Serializer):
47
43
  year = BooleanField(read_only=True)
48
44
 
49
45
 
50
- def validate_decades(decades):
51
- """Validate decades."""
52
- if not decades:
53
- return
54
- # * We don't need a whole db call just to be perfectly accurate
55
- # * -1s are decoded back into None before validation
56
- exists = False
57
- for decade in decades:
58
- if decade is None or decade % 10 == 0:
59
- exists = True
60
- break
61
- if not exists:
62
- raise ValidationError(_(f"Invalid decade in: {decades}"))
63
-
64
-
65
- def validate_int_null(values):
66
- """Use a special code for null.
67
-
68
- Because if a vuetify component has a null key it changes it to the
69
- array index.
70
- """
71
- for index, value in enumerate(values):
72
- if value == VUETIFY_NULL_CODE:
73
- values[index] = None
74
- return values
75
-
76
-
77
- def validate_str_null(values):
78
- """Use a special code for null.
79
-
80
- Because if a vuetify component has a null key it changes it to the
81
- array index. This is the version for CharFields.
82
- """
83
- for index, value in enumerate(values):
84
- if value == VUETIFY_NULL_CODE_STR:
85
- values[index] = None
86
- return values
87
-
88
-
89
- class FilterListField(ListField, ABC):
90
- """Filter List field with custom arguments."""
91
-
92
- CHILD_CLASS = Field
93
- VALIDATORS = ()
94
-
95
- def __init__(self, *args, **kwargs):
96
- """Apply the subclass's arguments."""
97
- super().__init__(
98
- *args,
99
- child=self.CHILD_CLASS(allow_null=True, **kwargs),
100
- required=False,
101
- validators=self.VALIDATORS,
102
- )
103
-
104
-
105
- class FloatListField(FilterListField):
106
- """Decimal List Field with validation."""
107
-
108
- CHILD_CLASS = FloatField # type: ignore
109
- VALIDATORS = (validate_int_null,)
110
-
111
-
112
- class IntListField(FilterListField):
113
- """Integer List Field with validation."""
114
-
115
- CHILD_CLASS = IntegerField # type: ignore
116
- VALIDATORS = (validate_int_null,)
117
-
118
-
119
- class DecadeListField(IntListField):
120
- """Integer List Field with validation for decades."""
121
-
122
- VALIDATORS = (validate_int_null, validate_decades)
123
-
124
-
125
- class CharListField(FilterListField):
126
- """Char List Field with validation."""
127
-
128
- CHILD_CLASS = CharField # type: ignore
129
- VALIDATORS = (validate_str_null,)
130
-
131
-
132
- class BooleanListField(FilterListField):
133
- """Bool List Field with validation."""
134
-
135
- CHILD_CLASS = BooleanField # type: ignore
136
- VALIDATORS = (validate_int_null,)
137
-
138
-
139
46
  class BrowserSettingsFilterSerializer(Serializer):
140
47
  """Filter values for settings."""
141
48
 
@@ -10,6 +10,15 @@ from rest_framework.serializers import (
10
10
  )
11
11
 
12
12
  from codex.serializers.browser.filters import IntListField
13
+ from codex.serializers.fields import TimestampField
14
+
15
+
16
+ class BrowserCover(Serializer):
17
+ """Browser Cover."""
18
+
19
+ custom = BooleanField(read_only=True, default=False)
20
+ pk = IntegerField(read_only=True, default=0)
21
+ mtime = TimestampField(read_only=True, default=0)
13
22
 
14
23
 
15
24
  class BrowserAggregateSerializerMixin(Serializer):
@@ -20,9 +29,8 @@ class BrowserAggregateSerializerMixin(Serializer):
20
29
 
21
30
  # Aggregate Annotations
22
31
  child_count = IntegerField(read_only=True)
23
- cover_pk = IntegerField(read_only=True)
24
- cover_mtime = DateTimeField(format="%s", read_only=True)
25
- cover_custom = BooleanField(read_only=True)
32
+ mtime = TimestampField(read_only=True)
33
+ cover = BrowserCover(read_only=True)
26
34
 
27
35
  # Bookmark annotations
28
36
  page = IntegerField(read_only=True)
@@ -31,3 +39,12 @@ class BrowserAggregateSerializerMixin(Serializer):
31
39
  progress = DecimalField(
32
40
  max_digits=5, decimal_places=2, read_only=True, coerce_to_string=False
33
41
  )
42
+
43
+ def to_representation(self, instance):
44
+ """Nest Cover Object."""
45
+ instance.cover = {
46
+ "custom": instance.cover_custom,
47
+ "pk": instance.cover_pk,
48
+ "mtime": instance.cover_mtime,
49
+ }
50
+ return super().to_representation(instance)
@@ -3,7 +3,6 @@
3
3
  from rest_framework.serializers import (
4
4
  BooleanField,
5
5
  CharField,
6
- DateTimeField,
7
6
  DecimalField,
8
7
  IntegerField,
9
8
  ListSerializer,
@@ -13,6 +12,7 @@ from rest_framework.serializers import (
13
12
  from codex.serializers.browser.mixins import (
14
13
  BrowserAggregateSerializerMixin,
15
14
  )
15
+ from codex.serializers.fields import TimestampField
16
16
  from codex.serializers.route import RouteSerializer
17
17
 
18
18
 
@@ -34,7 +34,6 @@ class BrowserCardSerializer(BrowserAggregateSerializerMixin):
34
34
  order_value = CharField(read_only=True)
35
35
  page_count = IntegerField(read_only=True)
36
36
  reading_direction = CharField(read_only=True)
37
- mtime = DateTimeField(format="%s", read_only=True)
38
37
 
39
38
 
40
39
  class BrowserAdminFlagsSerializer(Serializer):
@@ -63,3 +62,4 @@ class BrowserPageSerializer(Serializer):
63
62
  num_pages = IntegerField(read_only=True)
64
63
  groups = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
65
64
  books = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
65
+ mtime = TimestampField(read_only=True)
@@ -10,6 +10,7 @@ from rest_framework.serializers import (
10
10
 
11
11
  from codex.serializers.browser.filters import BrowserSettingsFilterSerializer
12
12
  from codex.serializers.choices import CHOICES, VUETIFY_NULL_CODE
13
+ from codex.serializers.fields import TimestampField
13
14
 
14
15
  VUETIFY_NULL_CODE_STR = str(VUETIFY_NULL_CODE)
15
16
 
@@ -44,3 +45,4 @@ class BrowserSettingsSerializer(Serializer):
44
45
  top_group = ChoiceField(choices=tuple(CHOICES["topGroup"].keys()), required=False)
45
46
  opds_metadata = BooleanField(required=False)
46
47
  limit = IntegerField(required=False)
48
+ mtime = TimestampField(read_only=True)
@@ -0,0 +1,123 @@
1
+ """Custom fields."""
2
+
3
+ from abc import ABC
4
+ from datetime import datetime
5
+ from math import floor
6
+
7
+ from django.core.exceptions import ValidationError
8
+ from django.utils.translation import gettext_lazy as _
9
+ from rest_framework.fields import Field
10
+ from rest_framework.serializers import (
11
+ BooleanField,
12
+ CharField,
13
+ FloatField,
14
+ IntegerField,
15
+ ListField,
16
+ )
17
+
18
+ from codex.serializers.choices import VUETIFY_NULL_CODE
19
+
20
+ VUETIFY_NULL_CODE_STR = str(VUETIFY_NULL_CODE)
21
+
22
+
23
+ class TimestampField(IntegerField):
24
+ """IntegerTimestampField."""
25
+
26
+ def to_representation(self, value):
27
+ """Convert to int from datetime, or castable."""
28
+ if isinstance(value, datetime):
29
+ value = floor(value.timestamp())
30
+ return int(value)
31
+
32
+ def to_internal_value(self, data):
33
+ """Convert from castable, likely string."""
34
+ return int(data)
35
+
36
+
37
+ def validate_decades(decades):
38
+ """Validate decades."""
39
+ if not decades:
40
+ return
41
+ # * We don't need a whole db call just to be perfectly accurate
42
+ # * -1s are decoded back into None before validation
43
+ exists = False
44
+ for decade in decades:
45
+ if decade is None or decade % 10 == 0:
46
+ exists = True
47
+ break
48
+ if not exists:
49
+ raise ValidationError(_(f"Invalid decade in: {decades}"))
50
+
51
+
52
+ def validate_int_null(values):
53
+ """Use a special code for null.
54
+
55
+ Because if a vuetify component has a null key it changes it to the
56
+ array index.
57
+ """
58
+ for index, value in enumerate(values):
59
+ if value == VUETIFY_NULL_CODE:
60
+ values[index] = None
61
+ return values
62
+
63
+
64
+ def validate_str_null(values):
65
+ """Use a special code for null.
66
+
67
+ Because if a vuetify component has a null key it changes it to the
68
+ array index. This is the version for CharFields.
69
+ """
70
+ for index, value in enumerate(values):
71
+ if value == VUETIFY_NULL_CODE_STR:
72
+ values[index] = None
73
+ return values
74
+
75
+
76
+ class FilterListField(ListField, ABC):
77
+ """Filter List field with custom arguments."""
78
+
79
+ CHILD_CLASS = Field
80
+ VALIDATORS = ()
81
+
82
+ def __init__(self, *args, **kwargs):
83
+ """Apply the subclass's arguments."""
84
+ super().__init__(
85
+ *args,
86
+ child=self.CHILD_CLASS(allow_null=True, **kwargs),
87
+ required=False,
88
+ validators=self.VALIDATORS,
89
+ )
90
+
91
+
92
+ class FloatListField(FilterListField):
93
+ """Decimal List Field with validation."""
94
+
95
+ CHILD_CLASS = FloatField # type: ignore
96
+ VALIDATORS = (validate_int_null,)
97
+
98
+
99
+ class IntListField(FilterListField):
100
+ """Integer List Field with validation."""
101
+
102
+ CHILD_CLASS = IntegerField # type: ignore
103
+ VALIDATORS = (validate_int_null,)
104
+
105
+
106
+ class DecadeListField(IntListField):
107
+ """Integer List Field with validation for decades."""
108
+
109
+ VALIDATORS = (validate_int_null, validate_decades)
110
+
111
+
112
+ class CharListField(FilterListField):
113
+ """Char List Field with validation."""
114
+
115
+ CHILD_CLASS = CharField # type: ignore
116
+ VALIDATORS = (validate_str_null,)
117
+
118
+
119
+ class BooleanListField(FilterListField):
120
+ """Bool List Field with validation."""
121
+
122
+ CHILD_CLASS = BooleanField # type: ignore
123
+ VALIDATORS = (validate_int_null,)
@@ -0,0 +1,25 @@
1
+ """Group Mtimes."""
2
+
3
+ from rest_framework.serializers import BooleanField, Serializer
4
+
5
+ from codex.serializers.fields import IntListField, TimestampField
6
+
7
+
8
+ class GroupMtimeSerializer(Serializer):
9
+ """Group Mtimes."""
10
+
11
+ pks = IntListField(read_only=True)
12
+ mtime = TimestampField(read_only=True)
13
+
14
+
15
+ class GroupsMtimeSerializer(Serializer):
16
+ """Groups Mtimes."""
17
+
18
+ groups = GroupMtimeSerializer(many=True)
19
+ use_bookmark_filter = BooleanField(read_only=True)
20
+
21
+
22
+ class MtimeSerializer(Serializer):
23
+ """Max mtime for all submitted groups."""
24
+
25
+ max_mtime = TimestampField(read_only=True)
@@ -11,11 +11,7 @@ from rest_framework.fields import (
11
11
  )
12
12
  from rest_framework.serializers import Serializer
13
13
 
14
-
15
- class CharListField(ListField):
16
- """List of CharFields."""
17
-
18
- child = CharField()
14
+ from codex.serializers.fields import CharListField
19
15
 
20
16
 
21
17
  class OPDS2LinkPropertiesSerializer(Serializer):
@@ -69,7 +65,7 @@ class OPDS2LinkSerializer(Serializer):
69
65
  return obj.get("rel")
70
66
 
71
67
 
72
- class LinkListField(ListField):
68
+ class OPDS2LinkListField(ListField):
73
69
  """Link List."""
74
70
 
75
71
  child = OPDS2LinkSerializer()
@@ -148,7 +144,7 @@ class OPDS2FacetSerializer(Serializer):
148
144
  """Facets."""
149
145
 
150
146
  metadata = OPDS2MetadataSerializer(read_only=True)
151
- links = LinkListField(read_only=True)
147
+ links = OPDS2LinkListField(read_only=True)
152
148
 
153
149
 
154
150
  class OPDS2PublicationSerializer(OPDS2FacetSerializer):
@@ -158,19 +154,19 @@ class OPDS2PublicationSerializer(OPDS2FacetSerializer):
158
154
  """
159
155
 
160
156
  metadata = OPDS2PublicationMetadataSerializer(read_only=True)
161
- links = LinkListField(read_only=True)
162
- images = LinkListField(read_only=True, required=False)
157
+ links = OPDS2LinkListField(read_only=True)
158
+ images = OPDS2LinkListField(read_only=True, required=False)
163
159
 
164
160
 
165
161
  class OPDS2GroupSerializer(Serializer):
166
162
  """Group."""
167
163
 
168
164
  metadata = OPDS2MetadataSerializer(read_only=True)
169
- links = LinkListField(read_only=True, required=False)
165
+ links = OPDS2LinkListField(read_only=True, required=False)
170
166
  publications = ListField(
171
167
  child=OPDS2PublicationSerializer(), read_only=True, required=False
172
168
  )
173
- navigation = LinkListField(read_only=True, required=False)
169
+ navigation = OPDS2LinkListField(read_only=True, required=False)
174
170
 
175
171
 
176
172
  class OPDS2FeedSerializer(OPDS2GroupSerializer):
@@ -3,7 +3,7 @@
3
3
  from rest_framework.fields import CharField, DateTimeField, DecimalField, IntegerField
4
4
  from rest_framework.serializers import ChoiceField, Serializer
5
5
 
6
- from codex.serializers.opds.v2 import LinkListField
6
+ from codex.serializers.opds.v2 import OPDS2LinkListField
7
7
 
8
8
 
9
9
  class RecursiveField(Serializer):
@@ -15,7 +15,9 @@ class RecursiveField(Serializer):
15
15
 
16
16
  def to_representation(self, instance):
17
17
  """Represent with own class."""
18
- serializer = self.parent.parent.__class__(instance, context=self.context)
18
+ parent = self.parent
19
+ # Should not be ignored but is currently unused
20
+ serializer = parent.parent.__class__(instance, context=self.context) # type: ignore
19
21
  return serializer.data
20
22
 
21
23
 
@@ -68,7 +70,7 @@ class OPDS2ProfileSerializer(Serializer):
68
70
 
69
71
  name = CharField(read_only=True)
70
72
  email = CharField(read_only=True)
71
- links = LinkListField(read_only=True, required=False)
73
+ links = OPDS2LinkListField(read_only=True, required=False)
72
74
  loans = OPDS2CopiesSerializer(read_only=True)
73
75
  holds = OPDS2HoldsSerializer(read_only=True)
74
76
 
@@ -4,13 +4,13 @@ from rest_framework.serializers import (
4
4
  BooleanField,
5
5
  CharField,
6
6
  ChoiceField,
7
- DateTimeField,
8
7
  DecimalField,
9
8
  IntegerField,
10
9
  Serializer,
11
10
  )
12
11
 
13
12
  from codex.models import Bookmark
13
+ from codex.serializers.fields import TimestampField
14
14
  from codex.serializers.route import RouteSerializer
15
15
 
16
16
 
@@ -25,6 +25,7 @@ class ReaderSettingsSerializer(Serializer):
25
25
  two_pages = BooleanField(allow_null=True, required=False)
26
26
  reading_direction = CharField(allow_null=True, required=False)
27
27
  read_rtl_in_reverse = BooleanField(allow_null=True, required=False)
28
+ mtime = TimestampField(read_only=True)
28
29
 
29
30
 
30
31
  class ReaderComicSerializer(Serializer):
@@ -34,7 +35,7 @@ class ReaderComicSerializer(Serializer):
34
35
  settings = ReaderSettingsSerializer(read_only=True)
35
36
  max_page = IntegerField(read_only=True)
36
37
  reading_direction = CharField(read_only=True)
37
- mtime = DateTimeField(format="%s", read_only=True)
38
+ mtime = TimestampField(read_only=True)
38
39
 
39
40
 
40
41
  class ReaderArcSerializer(RouteSerializer):
@@ -43,6 +44,7 @@ class ReaderArcSerializer(RouteSerializer):
43
44
  page = None
44
45
  index = IntegerField(read_only=True, required=False)
45
46
  count = IntegerField(read_only=True, required=False)
47
+ mtime = TimestampField(read_only=True)
46
48
 
47
49
 
48
50
  class ReaderCurrentComicSerializer(ReaderComicSerializer):
@@ -84,3 +86,4 @@ class ReaderComicsSerializer(Serializer):
84
86
  arcs = ReaderArcSerializer(many=True, read_only=True)
85
87
  arc = ReaderArcSerializer(read_only=True)
86
88
  close_route = RouteSerializer(read_only=True)
89
+ mtime = TimestampField(read_only=True)
@@ -3,6 +3,8 @@
3
3
  from rest_framework.fields import CharField, IntegerField
4
4
  from rest_framework.serializers import Serializer
5
5
 
6
+ from codex.views.util import Route
7
+
6
8
 
7
9
  class RouteSerializer(Serializer):
8
10
  """A vue route for the browser."""
@@ -14,7 +16,9 @@ class RouteSerializer(Serializer):
14
16
 
15
17
  def to_representation(self, instance):
16
18
  """Allow submission of sequences instead of strings for pks."""
17
- pks = instance.get("pks")
19
+ if isinstance(instance, Route):
20
+ instance = instance.dict()
21
+ pks = instance["pks"]
18
22
  if not pks:
19
23
  instance["pks"] = "0"
20
24
  elif not isinstance(pks, str):
@@ -28,9 +32,9 @@ class RouteSerializer(Serializer):
28
32
  pks = instance.get("pks")
29
33
  if isinstance(pks, str):
30
34
  pks = tuple(sorted(int(pk) for pk in pks.split(",")))
31
- if 0 in pks:
35
+ if 0 in pks: # type: ignore
32
36
  pks = ()
33
- instance["pks"] = tuple(pks)
37
+ instance["pks"] = tuple(pks) # type: ignore
34
38
  except ValueError:
35
39
  instance["pks"] = ()
36
40
  return instance
@@ -0,0 +1 @@
1
+ import{m as g,V as t}from"./VCheckboxBtn-B1-m5pEh.js";import{a as A,u as I,V as l}from"./VSelectionControl-CGu0oz0K.js";import{E as B,as as R,O as U,az as w,F as z,h as D,R as E,ct as M,S as u,aw as r}from"./admin-drawer-panel-BxoNUHQr.js";const N=B({...A(),...R(g(),["inline"])},"VCheckbox"),j=U()({name:"VCheckbox",inheritAttrs:!1,props:N(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(e,c){let{attrs:d,slots:a}=c;const s=w(e,"modelValue"),{isFocused:n,focus:i,blur:m}=I(e),V=z(),p=D(()=>e.id||`checkbox-${V}`);return E(()=>{const[b,f]=M(d),v=l.filterProps(e),k=t.filterProps(e);return u(l,r({class:["v-checkbox",e.class]},b,v,{modelValue:s.value,"onUpdate:modelValue":o=>s.value=o,id:p.value,focused:n.value,style:e.style}),{...a,default:o=>{let{id:h,messagesId:x,isDisabled:P,isReadonly:C,isValid:y}=o;return u(t,r(k,{id:h.value,"aria-describedby":x.value,disabled:P.value,readonly:C.value},f,{error:y.value===!1,modelValue:s.value,"onUpdate:modelValue":F=>s.value=F,onFocus:i,onBlur:m}),a)}})}),{}}});export{j as V};
@@ -0,0 +1 @@
1
+ import{m as g,V as t}from"./VCheckboxBtn-B1-m5pEh.js";import{a as A,u as I,V as l}from"./VSelectionControl-CGu0oz0K.js";import{E as B,as as R,O as U,az as w,F as z,h as D,R as E,ct as M,S as u,aw as r}from"./admin-drawer-panel-BxoNUHQr.js";const N=B({...A(),...R(g(),["inline"])},"VCheckbox"),j=U()({name:"VCheckbox",inheritAttrs:!1,props:N(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(e,c){let{attrs:d,slots:a}=c;const s=w(e,"modelValue"),{isFocused:n,focus:i,blur:m}=I(e),V=z(),p=D(()=>e.id||`checkbox-${V}`);return E(()=>{const[b,f]=M(d),v=l.filterProps(e),k=t.filterProps(e);return u(l,r({class:["v-checkbox",e.class]},b,v,{modelValue:s.value,"onUpdate:modelValue":o=>s.value=o,id:p.value,focused:n.value,style:e.style}),{...a,default:o=>{let{id:h,messagesId:x,isDisabled:P,isReadonly:C,isValid:y}=o;return u(t,r(k,{id:h.value,"aria-describedby":x.value,disabled:P.value,readonly:C.value},f,{error:y.value===!1,modelValue:s.value,"onUpdate:modelValue":F=>s.value=F,onFocus:i,onBlur:m}),a)}})}),{}}});export{j as V};
@@ -0,0 +1 @@
1
+ import{c as f,d as o}from"./VSelectionControl-CGu0oz0K.js";import{E as V,bh as h,O as v,az as c,h as l,R as I,as as k,S as x,aw as b}from"./admin-drawer-panel-BxoNUHQr.js";const C=V({indeterminate:Boolean,indeterminateIcon:{type:h,default:"$checkboxIndeterminate"},...f({falseIcon:"$checkboxOff",trueIcon:"$checkboxOn"})},"VCheckboxBtn"),B=v()({name:"VCheckboxBtn",props:C(),emits:{"update:modelValue":e=>!0,"update:indeterminate":e=>!0},setup(e,r){let{slots:s}=r;const t=c(e,"indeterminate"),n=c(e,"modelValue");function u(a){t.value&&(t.value=!1)}const i=l(()=>t.value?e.indeterminateIcon:e.falseIcon),d=l(()=>t.value?e.indeterminateIcon:e.trueIcon);return I(()=>{const a=k(o.filterProps(e),["modelValue"]);return x(o,b(a,{modelValue:n.value,"onUpdate:modelValue":[m=>n.value=m,u],class:["v-checkbox-btn",e.class],style:e.style,type:"checkbox",falseIcon:i.value,trueIcon:d.value,"aria-checked":t.value?"mixed":void 0}),s)}),{}}});export{B as V,C as m};