codex 1.7.0a0__py3-none-any.whl → 1.7.0a2__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 (715) hide show
  1. codex/choices.py +424 -0
  2. codex/choices_to_json.py +122 -0
  3. codex/db.py +31 -15
  4. codex/exceptions.py +2 -3
  5. codex/librarian/bookmark/__init__.py +1 -0
  6. codex/librarian/bookmark/bookmarkd.py +38 -0
  7. codex/librarian/bookmark/tasks.py +19 -0
  8. codex/librarian/bookmark/update.py +154 -0
  9. codex/librarian/covers/coverd.py +3 -4
  10. codex/librarian/covers/create.py +8 -7
  11. codex/librarian/covers/path.py +1 -2
  12. codex/librarian/covers/purge.py +2 -2
  13. codex/librarian/janitor/integrity.py +1 -0
  14. codex/librarian/librariand.py +5 -0
  15. codex/librarian/watchdog/emitter.py +21 -19
  16. codex/librarian/watchdog/event_batcherd.py +0 -1
  17. codex/migrations/0030_nocase_collation_day_month_indexes_status_types.py +4 -0
  18. codex/models/admin.py +0 -5
  19. codex/models/functions.py +6 -5
  20. codex/models/query.py +6 -0
  21. codex/run.py +11 -9
  22. codex/serializers/admin/tasks.py +2 -2
  23. codex/serializers/browser/mixins.py +18 -14
  24. codex/serializers/browser/settings.py +4 -4
  25. codex/serializers/fields.py +9 -5
  26. codex/startup.py +6 -4
  27. codex/static_root/assets/VCheckbox-CCOzQpCw.a65ad95bd21a.js +1 -0
  28. codex/static_root/assets/VCheckbox-CCOzQpCw.a65ad95bd21a.js.br +0 -0
  29. codex/static_root/assets/VCheckbox-CCOzQpCw.a65ad95bd21a.js.gz +0 -0
  30. codex/static_root/assets/VCheckbox-CCOzQpCw.js +1 -0
  31. codex/static_root/assets/VCheckbox-CCOzQpCw.js.br +0 -0
  32. codex/static_root/assets/VCheckbox-CCOzQpCw.js.gz +0 -0
  33. codex/static_root/assets/VCheckboxBtn-DnBH3a96.876fda35b85a.js +1 -0
  34. codex/static_root/assets/VCheckboxBtn-DnBH3a96.876fda35b85a.js.br +0 -0
  35. codex/static_root/assets/VCheckboxBtn-DnBH3a96.876fda35b85a.js.gz +0 -0
  36. codex/static_root/assets/VCheckboxBtn-DnBH3a96.js +1 -0
  37. codex/static_root/assets/VCheckboxBtn-DnBH3a96.js.br +0 -0
  38. codex/static_root/assets/VCheckboxBtn-DnBH3a96.js.gz +0 -0
  39. codex/static_root/assets/VCombobox-DwwoR4yO.e7a4db7ab7f0.js +1 -0
  40. codex/static_root/assets/VCombobox-DwwoR4yO.e7a4db7ab7f0.js.br +0 -0
  41. codex/static_root/assets/VCombobox-DwwoR4yO.e7a4db7ab7f0.js.gz +0 -0
  42. codex/static_root/assets/VCombobox-DwwoR4yO.js +1 -0
  43. codex/static_root/assets/VCombobox-DwwoR4yO.js.br +0 -0
  44. codex/static_root/assets/VCombobox-DwwoR4yO.js.gz +0 -0
  45. codex/static_root/assets/VDialog-CSvrKKb2.css +1 -0
  46. codex/static_root/assets/VDialog-CSvrKKb2.css.br +0 -0
  47. codex/static_root/assets/VDialog-CSvrKKb2.css.gz +0 -0
  48. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css +1 -0
  49. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.br +0 -0
  50. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.gz +0 -0
  51. codex/static_root/assets/VDialog-DbN2FfmF.b2843f79d90f.js +1 -0
  52. codex/static_root/assets/VDialog-DbN2FfmF.b2843f79d90f.js.br +0 -0
  53. codex/static_root/assets/VDialog-DbN2FfmF.b2843f79d90f.js.gz +0 -0
  54. codex/static_root/assets/VDialog-DbN2FfmF.js +1 -0
  55. codex/static_root/assets/VDialog-DbN2FfmF.js.br +0 -0
  56. codex/static_root/assets/VDialog-DbN2FfmF.js.gz +0 -0
  57. codex/static_root/assets/VExpansionPanels-CBPnoy7O.212f4cad7d78.js +1 -0
  58. codex/static_root/assets/VExpansionPanels-CBPnoy7O.212f4cad7d78.js.br +0 -0
  59. codex/static_root/assets/VExpansionPanels-CBPnoy7O.212f4cad7d78.js.gz +0 -0
  60. codex/static_root/assets/VExpansionPanels-CBPnoy7O.js +1 -0
  61. codex/static_root/assets/VExpansionPanels-CBPnoy7O.js.br +0 -0
  62. codex/static_root/assets/VExpansionPanels-CBPnoy7O.js.gz +0 -0
  63. codex/static_root/assets/VRadioGroup-C7Zu_Eup.b42735892aec.js +1 -0
  64. codex/static_root/assets/VRadioGroup-C7Zu_Eup.b42735892aec.js.br +0 -0
  65. codex/static_root/assets/VRadioGroup-C7Zu_Eup.b42735892aec.js.gz +0 -0
  66. codex/static_root/assets/VRadioGroup-C7Zu_Eup.js +1 -0
  67. codex/static_root/assets/VRadioGroup-C7Zu_Eup.js.br +0 -0
  68. codex/static_root/assets/VRadioGroup-C7Zu_Eup.js.gz +0 -0
  69. codex/static_root/assets/VSelect-BTy7SKk0.dee138de5dd0.js +1 -0
  70. codex/static_root/assets/VSelect-BTy7SKk0.dee138de5dd0.js.br +0 -0
  71. codex/static_root/assets/VSelect-BTy7SKk0.dee138de5dd0.js.gz +0 -0
  72. codex/static_root/assets/VSelect-BTy7SKk0.js +1 -0
  73. codex/static_root/assets/VSelect-BTy7SKk0.js.br +0 -0
  74. codex/static_root/assets/VSelect-BTy7SKk0.js.gz +0 -0
  75. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css +1 -0
  76. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.br +0 -0
  77. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.gz +0 -0
  78. codex/static_root/assets/VSelect-DLu8bpcs.css +1 -0
  79. codex/static_root/assets/VSelect-DLu8bpcs.css.br +0 -0
  80. codex/static_root/assets/VSelect-DLu8bpcs.css.gz +0 -0
  81. codex/static_root/assets/VSelectionControl-B42mmzLA.bf64d259ddef.js +1 -0
  82. codex/static_root/assets/VSelectionControl-B42mmzLA.bf64d259ddef.js.br +0 -0
  83. codex/static_root/assets/VSelectionControl-B42mmzLA.bf64d259ddef.js.gz +0 -0
  84. codex/static_root/assets/VSelectionControl-B42mmzLA.js +1 -0
  85. codex/static_root/assets/VSelectionControl-B42mmzLA.js.br +0 -0
  86. codex/static_root/assets/VSelectionControl-B42mmzLA.js.gz +0 -0
  87. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css +1 -0
  88. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.br +0 -0
  89. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.gz +0 -0
  90. codex/static_root/assets/VSlideGroup-BtXPhMOT.css +1 -0
  91. codex/static_root/assets/VSlideGroup-BtXPhMOT.css.br +0 -0
  92. codex/static_root/assets/VSlideGroup-BtXPhMOT.css.gz +0 -0
  93. codex/static_root/assets/VSlideGroup-BtfHoWCn.33e2bd94e34a.js +1 -0
  94. codex/static_root/assets/VSlideGroup-BtfHoWCn.33e2bd94e34a.js.br +0 -0
  95. codex/static_root/assets/VSlideGroup-BtfHoWCn.33e2bd94e34a.js.gz +0 -0
  96. codex/static_root/assets/VSlideGroup-BtfHoWCn.js +1 -0
  97. codex/static_root/assets/VSlideGroup-BtfHoWCn.js.br +0 -0
  98. codex/static_root/assets/VSlideGroup-BtfHoWCn.js.gz +0 -0
  99. codex/static_root/assets/VTable-R3X0iPjV.ee07d9c2ca5f.js +1 -0
  100. codex/static_root/assets/VTable-R3X0iPjV.ee07d9c2ca5f.js.br +0 -0
  101. codex/static_root/assets/VTable-R3X0iPjV.ee07d9c2ca5f.js.gz +0 -0
  102. codex/static_root/assets/VTable-R3X0iPjV.js +1 -0
  103. codex/static_root/assets/VTable-R3X0iPjV.js.br +0 -0
  104. codex/static_root/assets/VTable-R3X0iPjV.js.gz +0 -0
  105. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css +1 -0
  106. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.br +0 -0
  107. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.gz +0 -0
  108. codex/static_root/assets/VTextField-BnCEPZIq.css +1 -0
  109. codex/static_root/assets/VTextField-BnCEPZIq.css.br +0 -0
  110. codex/static_root/assets/VTextField-BnCEPZIq.css.gz +0 -0
  111. codex/static_root/assets/VTextField-D9pqgz_R.47beb9e7e547.js +1 -0
  112. codex/static_root/assets/VTextField-D9pqgz_R.47beb9e7e547.js.br +0 -0
  113. codex/static_root/assets/VTextField-D9pqgz_R.47beb9e7e547.js.gz +0 -0
  114. codex/static_root/assets/VTextField-D9pqgz_R.js +1 -0
  115. codex/static_root/assets/VTextField-D9pqgz_R.js.br +0 -0
  116. codex/static_root/assets/VTextField-D9pqgz_R.js.gz +0 -0
  117. codex/static_root/assets/VWindowItem-DHTDdYfK.f6bf6b893442.js +1 -0
  118. codex/static_root/assets/VWindowItem-DHTDdYfK.f6bf6b893442.js.br +0 -0
  119. codex/static_root/assets/VWindowItem-DHTDdYfK.f6bf6b893442.js.gz +0 -0
  120. codex/static_root/assets/VWindowItem-DHTDdYfK.js +1 -0
  121. codex/static_root/assets/VWindowItem-DHTDdYfK.js.br +0 -0
  122. codex/static_root/assets/VWindowItem-DHTDdYfK.js.gz +0 -0
  123. codex/static_root/assets/admin-CIWyRJnH.dde0ee029f08.js +1 -0
  124. codex/static_root/assets/admin-CIWyRJnH.dde0ee029f08.js.br +0 -0
  125. codex/static_root/assets/admin-CIWyRJnH.dde0ee029f08.js.gz +0 -0
  126. codex/static_root/assets/admin-CIWyRJnH.js +1 -0
  127. codex/static_root/assets/admin-CIWyRJnH.js.br +0 -0
  128. codex/static_root/assets/admin-CIWyRJnH.js.gz +0 -0
  129. codex/static_root/assets/{admin-CWEjaFr5.7d4523387384.css → admin-DJ7pIXDQ.css} +1 -1
  130. codex/static_root/assets/admin-DJ7pIXDQ.css.br +0 -0
  131. codex/static_root/assets/admin-DJ7pIXDQ.css.gz +0 -0
  132. codex/static_root/assets/{admin-CWEjaFr5.css → admin-DJ7pIXDQ.e2a77af73ef2.css} +1 -1
  133. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.br +0 -0
  134. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.gz +0 -0
  135. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css +1 -0
  136. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css.br +0 -0
  137. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css.gz +0 -0
  138. codex/static_root/assets/admin-menu-B9bzD6hV.css +1 -0
  139. codex/static_root/assets/admin-menu-B9bzD6hV.css.br +0 -0
  140. codex/static_root/assets/admin-menu-B9bzD6hV.css.gz +0 -0
  141. codex/static_root/assets/admin-menu-BHOUwxhf.1ed26b58fb9f.js +1 -0
  142. codex/static_root/assets/admin-menu-BHOUwxhf.1ed26b58fb9f.js.br +0 -0
  143. codex/static_root/assets/admin-menu-BHOUwxhf.1ed26b58fb9f.js.gz +0 -0
  144. codex/static_root/assets/admin-menu-BHOUwxhf.js +1 -0
  145. codex/static_root/assets/admin-menu-BHOUwxhf.js.br +0 -0
  146. codex/static_root/assets/admin-menu-BHOUwxhf.js.gz +0 -0
  147. codex/static_root/assets/admin-settings-button-progress-DHIl0C8k.85a213c96423.js +1 -0
  148. codex/static_root/assets/admin-settings-button-progress-DHIl0C8k.85a213c96423.js.br +0 -0
  149. codex/static_root/assets/admin-settings-button-progress-DHIl0C8k.85a213c96423.js.gz +0 -0
  150. codex/static_root/assets/admin-settings-button-progress-DHIl0C8k.js +1 -0
  151. codex/static_root/assets/admin-settings-button-progress-DHIl0C8k.js.br +0 -0
  152. codex/static_root/assets/admin-settings-button-progress-DHIl0C8k.js.gz +0 -0
  153. codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.2548c49a853e.css +1 -0
  154. codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.css +1 -0
  155. codex/static_root/assets/browser-6T4uwUjJ.7dd4a7f74df6.js +1 -0
  156. codex/static_root/assets/browser-6T4uwUjJ.7dd4a7f74df6.js.br +0 -0
  157. codex/static_root/assets/browser-6T4uwUjJ.7dd4a7f74df6.js.gz +0 -0
  158. codex/static_root/assets/browser-6T4uwUjJ.js +1 -0
  159. codex/static_root/assets/browser-6T4uwUjJ.js.br +0 -0
  160. codex/static_root/assets/browser-6T4uwUjJ.js.gz +0 -0
  161. codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css +1 -0
  162. codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css.br +0 -0
  163. codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css.gz +0 -0
  164. codex/static_root/assets/browser-Br5CorL4.css +1 -0
  165. codex/static_root/assets/browser-Br5CorL4.css.br +0 -0
  166. codex/static_root/assets/browser-Br5CorL4.css.gz +0 -0
  167. codex/static_root/assets/change-password-dialog-BfiQBpUn.48db4c906920.js +1 -0
  168. codex/static_root/assets/change-password-dialog-BfiQBpUn.48db4c906920.js.br +0 -0
  169. codex/static_root/assets/change-password-dialog-BfiQBpUn.48db4c906920.js.gz +0 -0
  170. codex/static_root/assets/change-password-dialog-BfiQBpUn.js +1 -0
  171. codex/static_root/assets/change-password-dialog-BfiQBpUn.js.br +0 -0
  172. codex/static_root/assets/change-password-dialog-BfiQBpUn.js.gz +0 -0
  173. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css +1 -0
  174. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.br +0 -0
  175. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.gz +0 -0
  176. codex/static_root/assets/change-password-dialog-DrIXdKUC.css +1 -0
  177. codex/static_root/assets/change-password-dialog-DrIXdKUC.css.br +0 -0
  178. codex/static_root/assets/change-password-dialog-DrIXdKUC.css.gz +0 -0
  179. codex/static_root/assets/confirm-dialog-B7w6z2rf.472011c06253.css +1 -0
  180. codex/static_root/assets/confirm-dialog-B7w6z2rf.css +1 -0
  181. codex/static_root/assets/confirm-dialog-Iyuhxfyi.cf28325e58b7.js +1 -0
  182. codex/static_root/assets/confirm-dialog-Iyuhxfyi.cf28325e58b7.js.br +0 -0
  183. codex/static_root/assets/confirm-dialog-Iyuhxfyi.cf28325e58b7.js.gz +0 -0
  184. codex/static_root/assets/confirm-dialog-Iyuhxfyi.js +1 -0
  185. codex/static_root/assets/confirm-dialog-Iyuhxfyi.js.br +0 -0
  186. codex/static_root/assets/confirm-dialog-Iyuhxfyi.js.gz +0 -0
  187. codex/static_root/assets/datetime-column-Dnxh9sRh.b6a92a6bcce9.js +1 -0
  188. codex/static_root/assets/datetime-column-Dnxh9sRh.b6a92a6bcce9.js.br +0 -0
  189. codex/static_root/assets/datetime-column-Dnxh9sRh.b6a92a6bcce9.js.gz +0 -0
  190. codex/static_root/assets/datetime-column-Dnxh9sRh.js +1 -0
  191. codex/static_root/assets/datetime-column-Dnxh9sRh.js.br +0 -0
  192. codex/static_root/assets/datetime-column-Dnxh9sRh.js.gz +0 -0
  193. codex/static_root/assets/filter-CmOjoKbH.ea79c4727d92.js +1 -0
  194. codex/static_root/assets/filter-CmOjoKbH.ea79c4727d92.js.br +0 -0
  195. codex/static_root/assets/filter-CmOjoKbH.ea79c4727d92.js.gz +0 -0
  196. codex/static_root/assets/filter-CmOjoKbH.js +1 -0
  197. codex/static_root/assets/filter-CmOjoKbH.js.br +0 -0
  198. codex/static_root/assets/filter-CmOjoKbH.js.gz +0 -0
  199. codex/static_root/assets/flag-tab-1PeNvDA9.2fc60db57915.js +1 -0
  200. codex/static_root/assets/flag-tab-1PeNvDA9.2fc60db57915.js.br +0 -0
  201. codex/static_root/assets/flag-tab-1PeNvDA9.2fc60db57915.js.gz +0 -0
  202. codex/static_root/assets/flag-tab-1PeNvDA9.js +1 -0
  203. codex/static_root/assets/flag-tab-1PeNvDA9.js.br +0 -0
  204. codex/static_root/assets/flag-tab-1PeNvDA9.js.gz +0 -0
  205. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css +1 -0
  206. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.br +0 -0
  207. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.gz +0 -0
  208. codex/static_root/assets/flag-tab-CqWovuBu.css +1 -0
  209. codex/static_root/assets/flag-tab-CqWovuBu.css.br +0 -0
  210. codex/static_root/assets/flag-tab-CqWovuBu.css.gz +0 -0
  211. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css +1 -0
  212. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css.br +0 -0
  213. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css.gz +0 -0
  214. codex/static_root/assets/group-tab-DkIN1Heu.css +1 -0
  215. codex/static_root/assets/group-tab-DkIN1Heu.css.br +0 -0
  216. codex/static_root/assets/group-tab-DkIN1Heu.css.gz +0 -0
  217. codex/static_root/assets/group-tab-Zl_C7M7Z.dbeed7f2d08f.js +1 -0
  218. codex/static_root/assets/group-tab-Zl_C7M7Z.dbeed7f2d08f.js.br +0 -0
  219. codex/static_root/assets/group-tab-Zl_C7M7Z.dbeed7f2d08f.js.gz +0 -0
  220. codex/static_root/assets/group-tab-Zl_C7M7Z.js +1 -0
  221. codex/static_root/assets/group-tab-Zl_C7M7Z.js.br +0 -0
  222. codex/static_root/assets/group-tab-Zl_C7M7Z.js.gz +0 -0
  223. codex/static_root/assets/http-error-YNrrsTPg.73e9978dc0ce.js +1 -0
  224. codex/static_root/assets/http-error-YNrrsTPg.73e9978dc0ce.js.br +0 -0
  225. codex/static_root/assets/http-error-YNrrsTPg.73e9978dc0ce.js.gz +0 -0
  226. codex/static_root/assets/http-error-YNrrsTPg.js +1 -0
  227. codex/static_root/assets/http-error-YNrrsTPg.js.br +0 -0
  228. codex/static_root/assets/http-error-YNrrsTPg.js.gz +0 -0
  229. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css +1 -0
  230. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css.br +0 -0
  231. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css.gz +0 -0
  232. codex/static_root/assets/index-CL_6g4tJ.css +1 -0
  233. codex/static_root/assets/index-CL_6g4tJ.css.br +0 -0
  234. codex/static_root/assets/index-CL_6g4tJ.css.gz +0 -0
  235. codex/static_root/assets/index-j5K-C_JC.65c2dc5af141.js +1 -0
  236. codex/static_root/assets/index-j5K-C_JC.65c2dc5af141.js.br +0 -0
  237. codex/static_root/assets/index-j5K-C_JC.65c2dc5af141.js.gz +0 -0
  238. codex/static_root/assets/index-j5K-C_JC.js +1 -0
  239. codex/static_root/assets/index-j5K-C_JC.js.br +0 -0
  240. codex/static_root/assets/index-j5K-C_JC.js.gz +0 -0
  241. codex/static_root/assets/library-tab-CxKs8G-K.c6bfd6d53b17.js +1 -0
  242. codex/static_root/assets/library-tab-CxKs8G-K.c6bfd6d53b17.js.br +0 -0
  243. codex/static_root/assets/library-tab-CxKs8G-K.c6bfd6d53b17.js.gz +0 -0
  244. codex/static_root/assets/library-tab-CxKs8G-K.js +1 -0
  245. codex/static_root/assets/library-tab-CxKs8G-K.js.br +0 -0
  246. codex/static_root/assets/library-tab-CxKs8G-K.js.gz +0 -0
  247. codex/static_root/assets/{library-tab-Bh7ErAk7.7c44200ee727.css → library-tab-Wew8YOLv.0c1780a6b68e.css} +1 -1
  248. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.br +0 -0
  249. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.gz +0 -0
  250. codex/static_root/assets/{library-tab-Bh7ErAk7.css → library-tab-Wew8YOLv.css} +1 -1
  251. codex/static_root/assets/library-tab-Wew8YOLv.css.br +0 -0
  252. codex/static_root/assets/library-tab-Wew8YOLv.css.gz +0 -0
  253. codex/static_root/assets/main-H14uUxuN.cc1511f0f146.js +35 -0
  254. codex/static_root/assets/main-H14uUxuN.cc1511f0f146.js.br +0 -0
  255. codex/static_root/assets/main-H14uUxuN.cc1511f0f146.js.gz +0 -0
  256. codex/static_root/assets/main-H14uUxuN.js +35 -0
  257. codex/static_root/assets/main-H14uUxuN.js.br +0 -0
  258. codex/static_root/assets/main-H14uUxuN.js.gz +0 -0
  259. codex/static_root/assets/pager-full-pdf-DcRg28qt.ca9cdb9619ff.js +1 -0
  260. codex/static_root/assets/pager-full-pdf-DcRg28qt.ca9cdb9619ff.js.br +0 -0
  261. codex/static_root/assets/pager-full-pdf-DcRg28qt.ca9cdb9619ff.js.gz +0 -0
  262. codex/static_root/assets/pager-full-pdf-DcRg28qt.js +1 -0
  263. codex/static_root/assets/pager-full-pdf-DcRg28qt.js.br +0 -0
  264. codex/static_root/assets/pager-full-pdf-DcRg28qt.js.gz +0 -0
  265. codex/static_root/assets/pagination-toolbar-BgoV4zqc.ab5fa1be17a3.js +1 -0
  266. codex/static_root/assets/pagination-toolbar-BgoV4zqc.ab5fa1be17a3.js.br +0 -0
  267. codex/static_root/assets/pagination-toolbar-BgoV4zqc.ab5fa1be17a3.js.gz +0 -0
  268. codex/static_root/assets/pagination-toolbar-BgoV4zqc.js +1 -0
  269. codex/static_root/assets/pagination-toolbar-BgoV4zqc.js.br +0 -0
  270. codex/static_root/assets/pagination-toolbar-BgoV4zqc.js.gz +0 -0
  271. codex/static_root/assets/{pdf-doc-BcRNpoaW.882f6e967869.js → pdf-doc-BbuJd_VS.225d8590d020.js} +3 -3
  272. codex/static_root/assets/pdf-doc-BbuJd_VS.225d8590d020.js.br +0 -0
  273. codex/static_root/assets/pdf-doc-BbuJd_VS.225d8590d020.js.gz +0 -0
  274. codex/static_root/assets/{pdf-doc-BcRNpoaW.js → pdf-doc-BbuJd_VS.js} +3 -3
  275. codex/static_root/assets/pdf-doc-BbuJd_VS.js.br +0 -0
  276. codex/static_root/assets/pdf-doc-BbuJd_VS.js.gz +0 -0
  277. codex/static_root/assets/reader-DORea4Al.d8e756bb0027.js +2 -0
  278. codex/static_root/assets/reader-DORea4Al.d8e756bb0027.js.br +0 -0
  279. codex/static_root/assets/reader-DORea4Al.d8e756bb0027.js.gz +0 -0
  280. codex/static_root/assets/reader-DORea4Al.js +2 -0
  281. codex/static_root/assets/reader-DORea4Al.js.br +0 -0
  282. codex/static_root/assets/reader-DORea4Al.js.gz +0 -0
  283. codex/static_root/assets/{reader-DveZZr9x.7b21b9f8f628.css → reader-OpKdTZ_B.css} +1 -1
  284. codex/static_root/assets/reader-OpKdTZ_B.css.br +0 -0
  285. codex/static_root/assets/reader-OpKdTZ_B.css.gz +0 -0
  286. codex/static_root/assets/{reader-DveZZr9x.css → reader-OpKdTZ_B.ebd1512b7014.css} +1 -1
  287. codex/static_root/assets/reader-OpKdTZ_B.ebd1512b7014.css.br +0 -0
  288. codex/static_root/assets/reader-OpKdTZ_B.ebd1512b7014.css.gz +0 -0
  289. codex/static_root/assets/relation-chips-kqofGdNg.0c7a53962f2b.js +1 -0
  290. codex/static_root/assets/relation-chips-kqofGdNg.0c7a53962f2b.js.br +0 -0
  291. codex/static_root/assets/relation-chips-kqofGdNg.0c7a53962f2b.js.gz +0 -0
  292. codex/static_root/assets/relation-chips-kqofGdNg.js +1 -0
  293. codex/static_root/assets/relation-chips-kqofGdNg.js.br +0 -0
  294. codex/static_root/assets/relation-chips-kqofGdNg.js.gz +0 -0
  295. codex/static_root/assets/settings-drawer-C-hgtHJt.0eaf7e00ee9b.js +2 -0
  296. codex/static_root/assets/settings-drawer-C-hgtHJt.0eaf7e00ee9b.js.br +0 -0
  297. codex/static_root/assets/settings-drawer-C-hgtHJt.0eaf7e00ee9b.js.gz +0 -0
  298. codex/static_root/assets/settings-drawer-C-hgtHJt.js +2 -0
  299. codex/static_root/assets/settings-drawer-C-hgtHJt.js.br +0 -0
  300. codex/static_root/assets/settings-drawer-C-hgtHJt.js.gz +0 -0
  301. codex/static_root/assets/{stats-tab-DpfGsVX3.1cb66f2649a9.css → stats-tab-BAYTqQNg.5f715428c394.css} +1 -1
  302. codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.br +0 -0
  303. codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.gz +0 -0
  304. codex/static_root/assets/{stats-tab-DpfGsVX3.css → stats-tab-BAYTqQNg.css} +1 -1
  305. codex/static_root/assets/stats-tab-BAYTqQNg.css.br +0 -0
  306. codex/static_root/assets/stats-tab-BAYTqQNg.css.gz +0 -0
  307. codex/static_root/assets/stats-tab-C7iJCFa5.f1039eba03c2.js +1 -0
  308. codex/static_root/assets/stats-tab-C7iJCFa5.f1039eba03c2.js.br +0 -0
  309. codex/static_root/assets/stats-tab-C7iJCFa5.f1039eba03c2.js.gz +0 -0
  310. codex/static_root/assets/stats-tab-C7iJCFa5.js +1 -0
  311. codex/static_root/assets/stats-tab-C7iJCFa5.js.br +0 -0
  312. codex/static_root/assets/stats-tab-C7iJCFa5.js.gz +0 -0
  313. codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css +1 -0
  314. codex/static_root/assets/{task-tab-1XiWn9xP.06cb8e1b794d.css.br → task-tab--cXi48kg.5dfd6890a1c2.css.br} +1 -1
  315. codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css.gz +0 -0
  316. codex/static_root/assets/task-tab--cXi48kg.css +1 -0
  317. codex/static_root/assets/{task-tab-1XiWn9xP.css.br → task-tab--cXi48kg.css.br} +1 -1
  318. codex/static_root/assets/task-tab--cXi48kg.css.gz +0 -0
  319. codex/static_root/assets/task-tab-Drfz5uaT.0b387dcd4f5a.js +1 -0
  320. codex/static_root/assets/task-tab-Drfz5uaT.0b387dcd4f5a.js.br +0 -0
  321. codex/static_root/assets/task-tab-Drfz5uaT.0b387dcd4f5a.js.gz +0 -0
  322. codex/static_root/assets/task-tab-Drfz5uaT.js +1 -0
  323. codex/static_root/assets/task-tab-Drfz5uaT.js.br +0 -0
  324. codex/static_root/assets/task-tab-Drfz5uaT.js.gz +0 -0
  325. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css +1 -0
  326. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.br +4 -0
  327. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.gz +0 -0
  328. codex/static_root/assets/transition-5LRFTPo5.css +1 -0
  329. codex/static_root/assets/transition-5LRFTPo5.css.br +4 -0
  330. codex/static_root/assets/transition-5LRFTPo5.css.gz +0 -0
  331. codex/static_root/assets/transition-CQVFPpmZ.ba35e475243a.js +1 -0
  332. codex/static_root/assets/transition-CQVFPpmZ.ba35e475243a.js.br +0 -0
  333. codex/static_root/assets/transition-CQVFPpmZ.ba35e475243a.js.gz +0 -0
  334. codex/static_root/assets/transition-CQVFPpmZ.js +1 -0
  335. codex/static_root/assets/transition-CQVFPpmZ.js.br +0 -0
  336. codex/static_root/assets/transition-CQVFPpmZ.js.gz +0 -0
  337. codex/static_root/assets/unauthorized-Cfxq6rru.968d6e6e57bd.js +1 -0
  338. codex/static_root/assets/unauthorized-Cfxq6rru.968d6e6e57bd.js.br +0 -0
  339. codex/static_root/assets/unauthorized-Cfxq6rru.968d6e6e57bd.js.gz +0 -0
  340. codex/static_root/assets/unauthorized-Cfxq6rru.js +1 -0
  341. codex/static_root/assets/unauthorized-Cfxq6rru.js.br +0 -0
  342. codex/static_root/assets/unauthorized-Cfxq6rru.js.gz +0 -0
  343. codex/static_root/assets/user-tab-icKcK_Qd.c29142ed5212.js +1 -0
  344. codex/static_root/assets/user-tab-icKcK_Qd.c29142ed5212.js.br +0 -0
  345. codex/static_root/assets/user-tab-icKcK_Qd.c29142ed5212.js.gz +0 -0
  346. codex/static_root/assets/user-tab-icKcK_Qd.js +1 -0
  347. codex/static_root/assets/user-tab-icKcK_Qd.js.br +0 -0
  348. codex/static_root/assets/user-tab-icKcK_Qd.js.gz +0 -0
  349. codex/static_root/manifest.3eee2b4822b7.json +712 -0
  350. codex/static_root/manifest.3eee2b4822b7.json.br +0 -0
  351. codex/static_root/manifest.3eee2b4822b7.json.gz +0 -0
  352. codex/static_root/manifest.json +377 -300
  353. codex/static_root/manifest.json.br +0 -0
  354. codex/static_root/manifest.json.gz +0 -0
  355. codex/static_root/staticfiles.json +1 -1
  356. codex/status_controller.py +5 -6
  357. codex/threads.py +1 -1
  358. codex/urls/api/auth.py +1 -1
  359. codex/urls/api/browser.py +1 -1
  360. codex/views/admin/library.py +18 -13
  361. codex/views/admin/stats.py +23 -16
  362. codex/views/auth.py +42 -77
  363. codex/views/bookmark.py +16 -153
  364. codex/views/browser/annotate/__init__.py +1 -0
  365. codex/views/browser/annotate/bookmark.py +112 -0
  366. codex/views/browser/annotate/card.py +61 -0
  367. codex/views/browser/annotate/order.py +247 -0
  368. codex/views/browser/breadcrumbs.py +90 -11
  369. codex/views/browser/browser.py +44 -110
  370. codex/views/browser/choices.py +15 -18
  371. codex/views/browser/cover.py +10 -20
  372. codex/views/browser/filters/bookmark.py +18 -19
  373. codex/views/browser/filters/field.py +8 -3
  374. codex/views/browser/filters/filter.py +69 -0
  375. codex/views/browser/filters/group.py +9 -6
  376. codex/views/browser/filters/search/fts.py +5 -19
  377. codex/views/browser/filters/search/parse.py +54 -24
  378. codex/views/browser/group_mtime.py +83 -0
  379. codex/views/browser/metadata/__init__.py +1 -0
  380. codex/views/browser/metadata/annotate.py +109 -0
  381. codex/views/browser/metadata/copy_intersections.py +90 -0
  382. codex/views/browser/metadata/metadata.py +83 -0
  383. codex/views/browser/metadata/query_intersections.py +112 -0
  384. codex/views/browser/mtime.py +2 -10
  385. codex/views/browser/order_by.py +22 -22
  386. codex/views/browser/page_in_bounds.py +2 -2
  387. codex/views/browser/paginate.py +9 -15
  388. codex/views/browser/params.py +64 -0
  389. codex/views/browser/title.py +1 -6
  390. codex/views/browser/validate.py +68 -33
  391. codex/views/download.py +1 -1
  392. codex/views/mixins.py +27 -15
  393. codex/views/opds/const.py +2 -3
  394. codex/views/opds/urls.py +2 -2
  395. codex/views/opds/util.py +2 -3
  396. codex/views/opds/v1/entry/links.py +3 -1
  397. codex/views/opds/v1/facets.py +65 -12
  398. codex/views/opds/v1/feed.py +5 -64
  399. codex/views/opds/v1/links.py +5 -4
  400. codex/views/opds/v2/feed.py +1 -28
  401. codex/views/opds/v2/links.py +26 -1
  402. codex/views/opds/v2/publications.py +5 -6
  403. codex/views/opds/v2/top_links.py +3 -6
  404. codex/views/public.py +2 -2
  405. codex/views/reader/arcs.py +0 -3
  406. codex/views/reader/books.py +57 -41
  407. codex/views/reader/page.py +10 -4
  408. codex/views/reader/{init.py → params.py} +37 -31
  409. codex/views/reader/reader.py +1 -2
  410. codex/views/session.py +43 -54
  411. codex/views/timezone.py +54 -0
  412. codex/views/version.py +1 -1
  413. {codex-1.7.0a0.dist-info → codex-1.7.0a2.dist-info}/METADATA +1 -1
  414. {codex-1.7.0a0.dist-info → codex-1.7.0a2.dist-info}/RECORD +417 -383
  415. codex/serializers/choices.py +0 -196
  416. codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js +0 -1
  417. codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.br +0 -0
  418. codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.gz +0 -0
  419. codex/static_root/assets/VCheckbox-CWiqcZ7a.js +0 -1
  420. codex/static_root/assets/VCheckbox-CWiqcZ7a.js.br +0 -0
  421. codex/static_root/assets/VCheckbox-CWiqcZ7a.js.gz +0 -0
  422. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js +0 -1
  423. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.br +0 -0
  424. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.gz +0 -0
  425. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js +0 -1
  426. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.br +0 -0
  427. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.gz +0 -0
  428. codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js +0 -1
  429. codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.br +0 -0
  430. codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.gz +0 -0
  431. codex/static_root/assets/VCombobox-D1_KU27A.js +0 -1
  432. codex/static_root/assets/VCombobox-D1_KU27A.js.br +0 -0
  433. codex/static_root/assets/VCombobox-D1_KU27A.js.gz +0 -0
  434. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css +0 -1
  435. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.br +0 -0
  436. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.gz +0 -0
  437. codex/static_root/assets/VDialog-38np3TSA.css +0 -1
  438. codex/static_root/assets/VDialog-38np3TSA.css.br +0 -0
  439. codex/static_root/assets/VDialog-38np3TSA.css.gz +0 -0
  440. codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js +0 -1
  441. codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.br +0 -0
  442. codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.gz +0 -0
  443. codex/static_root/assets/VDialog-GbxvFMMN.js +0 -1
  444. codex/static_root/assets/VDialog-GbxvFMMN.js.br +0 -0
  445. codex/static_root/assets/VDialog-GbxvFMMN.js.gz +0 -0
  446. codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js +0 -1
  447. codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.br +0 -0
  448. codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.gz +0 -0
  449. codex/static_root/assets/VExpansionPanels-Cywv_bEj.js +0 -1
  450. codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.br +0 -0
  451. codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.gz +0 -0
  452. codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js +0 -1
  453. codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.br +0 -0
  454. codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.gz +0 -0
  455. codex/static_root/assets/VRadioGroup-C0etmxpZ.js +0 -1
  456. codex/static_root/assets/VRadioGroup-C0etmxpZ.js.br +0 -0
  457. codex/static_root/assets/VRadioGroup-C0etmxpZ.js.gz +0 -0
  458. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css +0 -1
  459. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.br +0 -0
  460. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.gz +0 -0
  461. codex/static_root/assets/VSelect-Ca2bIOso.css +0 -1
  462. codex/static_root/assets/VSelect-Ca2bIOso.css.br +0 -0
  463. codex/static_root/assets/VSelect-Ca2bIOso.css.gz +0 -0
  464. codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js +0 -1
  465. codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.br +0 -0
  466. codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.gz +0 -0
  467. codex/static_root/assets/VSelect-txrnRiNJ.js +0 -1
  468. codex/static_root/assets/VSelect-txrnRiNJ.js.br +0 -0
  469. codex/static_root/assets/VSelect-txrnRiNJ.js.gz +0 -0
  470. codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js +0 -1
  471. codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.br +0 -0
  472. codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.gz +0 -0
  473. codex/static_root/assets/VSelectionControl-CY6RmcvW.js +0 -1
  474. codex/static_root/assets/VSelectionControl-CY6RmcvW.js.br +0 -0
  475. codex/static_root/assets/VSelectionControl-CY6RmcvW.js.gz +0 -0
  476. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css +0 -1
  477. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.br +0 -0
  478. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.gz +0 -0
  479. codex/static_root/assets/VSlideGroup-Dk_1upHt.css +0 -1
  480. codex/static_root/assets/VSlideGroup-Dk_1upHt.css.br +0 -0
  481. codex/static_root/assets/VSlideGroup-Dk_1upHt.css.gz +0 -0
  482. codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js +0 -1
  483. codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.br +0 -0
  484. codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.gz +0 -0
  485. codex/static_root/assets/VSlideGroup-DtEQMwY1.js +0 -1
  486. codex/static_root/assets/VSlideGroup-DtEQMwY1.js.br +0 -0
  487. codex/static_root/assets/VSlideGroup-DtEQMwY1.js.gz +0 -0
  488. codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js +0 -1
  489. codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.br +0 -0
  490. codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.gz +0 -0
  491. codex/static_root/assets/VTable-2af995xo.js +0 -1
  492. codex/static_root/assets/VTable-2af995xo.js.br +0 -0
  493. codex/static_root/assets/VTable-2af995xo.js.gz +0 -0
  494. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css +0 -1
  495. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.br +0 -0
  496. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.gz +0 -0
  497. codex/static_root/assets/VTextField-Crc3gdNh.css +0 -1
  498. codex/static_root/assets/VTextField-Crc3gdNh.css.br +0 -0
  499. codex/static_root/assets/VTextField-Crc3gdNh.css.gz +0 -0
  500. codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js +0 -1
  501. codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.br +0 -0
  502. codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.gz +0 -0
  503. codex/static_root/assets/VTextField-G6CMj7yO.js +0 -1
  504. codex/static_root/assets/VTextField-G6CMj7yO.js.br +0 -0
  505. codex/static_root/assets/VTextField-G6CMj7yO.js.gz +0 -0
  506. codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js +0 -1
  507. codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.br +0 -0
  508. codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.gz +0 -0
  509. codex/static_root/assets/VWindowItem-CzoGd6Ul.js +0 -1
  510. codex/static_root/assets/VWindowItem-CzoGd6Ul.js.br +0 -0
  511. codex/static_root/assets/VWindowItem-CzoGd6Ul.js.gz +0 -0
  512. codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.br +0 -0
  513. codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.gz +0 -0
  514. codex/static_root/assets/admin-CWEjaFr5.css.br +0 -0
  515. codex/static_root/assets/admin-CWEjaFr5.css.gz +0 -0
  516. codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js +0 -1
  517. codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.br +0 -0
  518. codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.gz +0 -0
  519. codex/static_root/assets/admin-CsPAIQeG.js +0 -1
  520. codex/static_root/assets/admin-CsPAIQeG.js.br +0 -0
  521. codex/static_root/assets/admin-CsPAIQeG.js.gz +0 -0
  522. codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js +0 -30
  523. codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.br +0 -0
  524. codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.gz +0 -0
  525. codex/static_root/assets/admin-drawer-panel-BAT7GA64.js +0 -30
  526. codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.br +0 -0
  527. codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.gz +0 -0
  528. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css +0 -1
  529. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css.br +0 -0
  530. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css.gz +0 -0
  531. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css +0 -1
  532. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css.br +0 -0
  533. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css.gz +0 -0
  534. codex/static_root/assets/browser-C18l93yc.923860009ef4.js +0 -1
  535. codex/static_root/assets/browser-C18l93yc.923860009ef4.js.br +0 -0
  536. codex/static_root/assets/browser-C18l93yc.923860009ef4.js.gz +0 -0
  537. codex/static_root/assets/browser-C18l93yc.js +0 -1
  538. codex/static_root/assets/browser-C18l93yc.js.br +0 -0
  539. codex/static_root/assets/browser-C18l93yc.js.gz +0 -0
  540. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css +0 -1
  541. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.br +0 -0
  542. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.gz +0 -0
  543. codex/static_root/assets/browser-DaAqlBYO.css +0 -1
  544. codex/static_root/assets/browser-DaAqlBYO.css.br +0 -0
  545. codex/static_root/assets/browser-DaAqlBYO.css.gz +0 -0
  546. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js +0 -1
  547. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.br +0 -0
  548. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.gz +0 -0
  549. codex/static_root/assets/change-password-dialog-BazJdNs9.js +0 -1
  550. codex/static_root/assets/change-password-dialog-BazJdNs9.js.br +0 -0
  551. codex/static_root/assets/change-password-dialog-BazJdNs9.js.gz +0 -0
  552. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css +0 -1
  553. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.br +0 -0
  554. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.gz +0 -0
  555. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css +0 -1
  556. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.br +0 -0
  557. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.gz +0 -0
  558. codex/static_root/assets/confirm-dialog-BmhedLCx.7c2103d319d4.css +0 -1
  559. codex/static_root/assets/confirm-dialog-BmhedLCx.css +0 -1
  560. codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js +0 -1
  561. codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.br +0 -0
  562. codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.gz +0 -0
  563. codex/static_root/assets/confirm-dialog-CbW3hlOp.js +0 -1
  564. codex/static_root/assets/confirm-dialog-CbW3hlOp.js.br +0 -0
  565. codex/static_root/assets/confirm-dialog-CbW3hlOp.js.gz +0 -0
  566. codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js +0 -1
  567. codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.br +0 -0
  568. codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.gz +0 -0
  569. codex/static_root/assets/datetime-column-uSqKZU37.js +0 -1
  570. codex/static_root/assets/datetime-column-uSqKZU37.js.br +0 -0
  571. codex/static_root/assets/datetime-column-uSqKZU37.js.gz +0 -0
  572. codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js +0 -1
  573. codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.br +0 -0
  574. codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.gz +0 -0
  575. codex/static_root/assets/filter-CBl5KEsB.js +0 -1
  576. codex/static_root/assets/filter-CBl5KEsB.js.br +0 -0
  577. codex/static_root/assets/filter-CBl5KEsB.js.gz +0 -0
  578. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js +0 -1
  579. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.br +0 -0
  580. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.gz +0 -0
  581. codex/static_root/assets/flag-tab-CT8pqM4r.js +0 -1
  582. codex/static_root/assets/flag-tab-CT8pqM4r.js.br +0 -0
  583. codex/static_root/assets/flag-tab-CT8pqM4r.js.gz +0 -0
  584. codex/static_root/assets/flag-tab-DBqpLKi7.css +0 -1
  585. codex/static_root/assets/flag-tab-DBqpLKi7.css.br +0 -0
  586. codex/static_root/assets/flag-tab-DBqpLKi7.css.gz +0 -0
  587. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css +0 -1
  588. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.br +0 -0
  589. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.gz +0 -0
  590. codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js +0 -1
  591. codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.br +0 -0
  592. codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.gz +0 -0
  593. codex/static_root/assets/group-tab-BOW9kigw.js +0 -1
  594. codex/static_root/assets/group-tab-BOW9kigw.js.br +0 -0
  595. codex/static_root/assets/group-tab-BOW9kigw.js.gz +0 -0
  596. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css +0 -1
  597. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.br +0 -0
  598. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.gz +0 -0
  599. codex/static_root/assets/group-tab-CBKuS3Iv.css +0 -1
  600. codex/static_root/assets/group-tab-CBKuS3Iv.css.br +0 -0
  601. codex/static_root/assets/group-tab-CBKuS3Iv.css.gz +0 -0
  602. codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js +0 -1
  603. codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.br +0 -4
  604. codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.gz +0 -0
  605. codex/static_root/assets/http-error-C6yuLApo.js +0 -1
  606. codex/static_root/assets/http-error-C6yuLApo.js.br +0 -4
  607. codex/static_root/assets/http-error-C6yuLApo.js.gz +0 -0
  608. codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.br +0 -2
  609. codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.gz +0 -0
  610. codex/static_root/assets/library-tab-Bh7ErAk7.css.br +0 -2
  611. codex/static_root/assets/library-tab-Bh7ErAk7.css.gz +0 -0
  612. codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js +0 -1
  613. codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.br +0 -0
  614. codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.gz +0 -0
  615. codex/static_root/assets/library-tab-D3WOtpE0.js +0 -1
  616. codex/static_root/assets/library-tab-D3WOtpE0.js.br +0 -0
  617. codex/static_root/assets/library-tab-D3WOtpE0.js.gz +0 -0
  618. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js +0 -6
  619. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.br +0 -0
  620. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.gz +0 -0
  621. codex/static_root/assets/main-CmjU2oTp.js +0 -6
  622. codex/static_root/assets/main-CmjU2oTp.js.br +0 -0
  623. codex/static_root/assets/main-CmjU2oTp.js.gz +0 -0
  624. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js +0 -1
  625. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.br +0 -0
  626. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.gz +0 -0
  627. codex/static_root/assets/pager-full-pdf-BH54_5f6.js +0 -1
  628. codex/static_root/assets/pager-full-pdf-BH54_5f6.js.br +0 -0
  629. codex/static_root/assets/pager-full-pdf-BH54_5f6.js.gz +0 -0
  630. codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js +0 -1
  631. codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.br +0 -0
  632. codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.gz +0 -0
  633. codex/static_root/assets/pagination-toolbar-JH3Kbffr.js +0 -1
  634. codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.br +0 -0
  635. codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.gz +0 -0
  636. codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.br +0 -0
  637. codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.gz +0 -0
  638. codex/static_root/assets/pdf-doc-BcRNpoaW.js.br +0 -0
  639. codex/static_root/assets/pdf-doc-BcRNpoaW.js.gz +0 -0
  640. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js +0 -2
  641. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.br +0 -0
  642. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.gz +0 -0
  643. codex/static_root/assets/reader-DIPRg2VB.js +0 -2
  644. codex/static_root/assets/reader-DIPRg2VB.js.br +0 -0
  645. codex/static_root/assets/reader-DIPRg2VB.js.gz +0 -0
  646. codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.br +0 -0
  647. codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.gz +0 -0
  648. codex/static_root/assets/reader-DveZZr9x.css.br +0 -0
  649. codex/static_root/assets/reader-DveZZr9x.css.gz +0 -0
  650. codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js +0 -1
  651. codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.br +0 -0
  652. codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.gz +0 -0
  653. codex/static_root/assets/relation-chips-3tTlR5QH.js +0 -1
  654. codex/static_root/assets/relation-chips-3tTlR5QH.js.br +0 -0
  655. codex/static_root/assets/relation-chips-3tTlR5QH.js.gz +0 -0
  656. codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js +0 -2
  657. codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.br +0 -0
  658. codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.gz +0 -0
  659. codex/static_root/assets/settings-drawer-BdyFhA_r.js +0 -2
  660. codex/static_root/assets/settings-drawer-BdyFhA_r.js.br +0 -0
  661. codex/static_root/assets/settings-drawer-BdyFhA_r.js.gz +0 -0
  662. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js +0 -1
  663. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.br +0 -0
  664. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.gz +0 -0
  665. codex/static_root/assets/stats-tab-DeKjwvmh.js +0 -1
  666. codex/static_root/assets/stats-tab-DeKjwvmh.js.br +0 -0
  667. codex/static_root/assets/stats-tab-DeKjwvmh.js.gz +0 -0
  668. codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.br +0 -0
  669. codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.gz +0 -0
  670. codex/static_root/assets/stats-tab-DpfGsVX3.css.br +0 -0
  671. codex/static_root/assets/stats-tab-DpfGsVX3.css.gz +0 -0
  672. codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css +0 -1
  673. codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css.gz +0 -0
  674. codex/static_root/assets/task-tab-1XiWn9xP.css +0 -1
  675. codex/static_root/assets/task-tab-1XiWn9xP.css.gz +0 -0
  676. codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js +0 -1
  677. codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.br +0 -0
  678. codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.gz +0 -0
  679. codex/static_root/assets/task-tab-C8D0qRP_.js +0 -1
  680. codex/static_root/assets/task-tab-C8D0qRP_.js.br +0 -0
  681. codex/static_root/assets/task-tab-C8D0qRP_.js.gz +0 -0
  682. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js +0 -1
  683. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.br +0 -0
  684. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.gz +0 -0
  685. codex/static_root/assets/unauthorized-BHgBRF4z.js +0 -1
  686. codex/static_root/assets/unauthorized-BHgBRF4z.js.br +0 -0
  687. codex/static_root/assets/unauthorized-BHgBRF4z.js.gz +0 -0
  688. codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js +0 -1
  689. codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.br +0 -0
  690. codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.gz +0 -0
  691. codex/static_root/assets/user-tab-BU31Z92y.js +0 -1
  692. codex/static_root/assets/user-tab-BU31Z92y.js.br +0 -0
  693. codex/static_root/assets/user-tab-BU31Z92y.js.gz +0 -0
  694. codex/static_root/js/choices-admin.8aa64c911203.json +0 -1
  695. codex/static_root/js/choices-admin.8aa64c911203.json.br +0 -0
  696. codex/static_root/js/choices-admin.8aa64c911203.json.gz +0 -0
  697. codex/static_root/js/choices-admin.json +0 -1
  698. codex/static_root/js/choices-admin.json.br +0 -0
  699. codex/static_root/js/choices-admin.json.gz +0 -0
  700. codex/static_root/js/choices.2f6b0359e1ef.json +0 -1
  701. codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
  702. codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
  703. codex/static_root/js/choices.json +0 -1
  704. codex/static_root/js/choices.json.br +0 -0
  705. codex/static_root/js/choices.json.gz +0 -0
  706. codex/static_root/manifest.45cb46e19686.json +0 -635
  707. codex/static_root/manifest.45cb46e19686.json.br +0 -0
  708. codex/static_root/manifest.45cb46e19686.json.gz +0 -0
  709. codex/views/browser/annotations.py +0 -339
  710. codex/views/browser/base.py +0 -139
  711. codex/views/browser/filters/annotations.py +0 -125
  712. codex/views/browser/metadata.py +0 -332
  713. {codex-1.7.0a0.dist-info → codex-1.7.0a2.dist-info}/LICENSE +0 -0
  714. {codex-1.7.0a0.dist-info → codex-1.7.0a2.dist-info}/WHEEL +0 -0
  715. {codex-1.7.0a0.dist-info → codex-1.7.0a2.dist-info}/entry_points.txt +0 -0
@@ -7,13 +7,13 @@ from codex.logger.logging import get_logger
7
7
  from codex.models.groups import Publisher
8
8
  from codex.serializers.browser.mtime import GroupsMtimeSerializer, MtimeSerializer
9
9
  from codex.util import max_none
10
- from codex.views.browser.filters.annotations import BrowserAnnotationsFilterView
10
+ from codex.views.browser.group_mtime import BrowserGroupMtimeView
11
11
  from codex.views.const import GROUP_MODEL_MAP
12
12
 
13
13
  LOG = get_logger(__name__)
14
14
 
15
15
 
16
- class MtimeView(BrowserAnnotationsFilterView):
16
+ class MtimeView(BrowserGroupMtimeView):
17
17
  """Get the mtimes for the submitted groups."""
18
18
 
19
19
  input_serializer_class = GroupsMtimeSerializer
@@ -22,11 +22,6 @@ class MtimeView(BrowserAnnotationsFilterView):
22
22
  REPARSE_JSON_FIELDS = frozenset({"groups", "filters"})
23
23
  TARGET = "mtime"
24
24
 
25
- def __init__(self, *args, **kwargs) -> None:
26
- """Initialize."""
27
- super().__init__(*args, **kwargs)
28
- self.init_bookmark_data()
29
-
30
25
  def _get_group_mtime(self, item):
31
26
  """Get one group's mtimes."""
32
27
  group = item["group"]
@@ -50,9 +45,6 @@ class MtimeView(BrowserAnnotationsFilterView):
50
45
  @extend_schema(parameters=[GroupsMtimeSerializer])
51
46
  def get(self, *args, **kwargs):
52
47
  """Get the mtimes for the submitted groups."""
53
- # Parse Request
54
- self.parse_params()
55
-
56
48
  max_mtime = self.get_max_groups_mtime()
57
49
 
58
50
  # Serialize Response
@@ -1,27 +1,29 @@
1
1
  """Base view for ordering the query."""
2
2
 
3
- from django.db.models.aggregates import Max, Min
4
-
5
3
  from codex.models import Comic
6
- from codex.views.browser.filters.annotations import (
7
- BrowserAnnotationsFilterView,
8
- )
4
+ from codex.views.browser.group_mtime import BrowserGroupMtimeView
9
5
 
10
6
 
11
- class BrowserOrderByView(BrowserAnnotationsFilterView):
7
+ class BrowserOrderByView(BrowserGroupMtimeView):
12
8
  """Base class for views that need ordering."""
13
9
 
14
- def set_order_key(self):
10
+ def __init__(self, *args, **kwargs):
11
+ """Initialize memoized vars."""
12
+ super().__init__(*args, **kwargs)
13
+ self._order_key: str = ""
14
+ self._comic_sort_names: tuple[str, ...] = ()
15
+
16
+ @property
17
+ def order_key(self):
15
18
  """Get the default order key for the view."""
16
- order_key: str = self.params["order_by"]
17
- if order_key == "search_score" and not self.fts_mode:
18
- # if no search scores, use sort_name, asc
19
- order_key = "sort_name"
20
- order_reverse = False
21
- else:
22
- order_reverse = self.params.get("order_reverse")
23
- self.order_key = order_key
24
- self.order_agg_func = Max if order_reverse else Min
19
+ if not self._order_key:
20
+ order_key: str = self.params["order_by"]
21
+ if (order_key == "search_score" and not self.fts_mode) or (
22
+ order_key == "filename" and not self.admin_flags["folder_view"]
23
+ ):
24
+ order_key = "sort_name"
25
+ self._order_key = order_key
26
+ return self._order_key
25
27
 
26
28
  def _add_comic_order_by(self, order_key, comic_sort_names):
27
29
  """Order by for comics (and covers)."""
@@ -29,7 +31,7 @@ class BrowserOrderByView(BrowserAnnotationsFilterView):
29
31
  order_key = self.order_key
30
32
  if order_key == "sort_name":
31
33
  if not comic_sort_names:
32
- comic_sort_names = self.comic_sort_names # type: ignore
34
+ comic_sort_names = self._comic_sort_names
33
35
  order_fields_head = [
34
36
  *comic_sort_names,
35
37
  "issue_number",
@@ -45,15 +47,13 @@ class BrowserOrderByView(BrowserAnnotationsFilterView):
45
47
  if order_key == "story_arc_number":
46
48
  order_fields_head += ["date"]
47
49
  elif order_key == "bookmark_updated_at":
48
- order_fields_head += ["updated_at"]
50
+ order_fields_head += ["bookmark_updated_at"]
49
51
  return order_fields_head
50
52
 
51
- def add_order_by(
52
- self, qs, model, order_key="", do_reverse=True, comic_sort_names=None
53
- ):
53
+ def add_order_by(self, qs, order_key="", do_reverse=True, comic_sort_names=None):
54
54
  """Create the order_by list."""
55
55
  order_fields_head = ()
56
- if model == Comic:
56
+ if qs.model is Comic:
57
57
  order_fields_head = self._add_comic_order_by(order_key, comic_sort_names)
58
58
  else:
59
59
  order_fields_head = ["order_value"]
@@ -1,13 +1,13 @@
1
1
  """Browser Page Bounds Checking."""
2
2
 
3
3
  from codex.logger.logging import get_logger
4
- from codex.views.browser.annotations import BrowserAnnotationsView
4
+ from codex.views.browser.annotate.card import BrowserAnnotateCardView
5
5
  from codex.views.util import Route
6
6
 
7
7
  LOG = get_logger(__name__)
8
8
 
9
9
 
10
- class BrowserPageInBoundsView(BrowserAnnotationsView):
10
+ class BrowserPageInBoundsView(BrowserAnnotateCardView):
11
11
  """Browser Page Bounds Checking."""
12
12
 
13
13
  def _get_back_one_page_route(self, num_pages):
@@ -5,14 +5,8 @@ from math import ceil
5
5
  from django.core.paginator import EmptyPage, Paginator
6
6
 
7
7
  from codex.logger.logging import get_logger
8
- from codex.models import (
9
- Comic,
10
- Folder,
11
- )
12
8
  from codex.views.browser.page_in_bounds import BrowserPageInBoundsView
13
- from codex.views.const import (
14
- MAX_OBJ_PER_PAGE,
15
- )
9
+ from codex.views.const import MAX_OBJ_PER_PAGE
16
10
 
17
11
  LOG = get_logger(__name__)
18
12
 
@@ -20,7 +14,7 @@ LOG = get_logger(__name__)
20
14
  class BrowserPaginateView(BrowserPageInBoundsView):
21
15
  """Paginate Groups and Books."""
22
16
 
23
- def _paginate_section(self, model, qs, page):
17
+ def _paginate_section(self, qs, page):
24
18
  """Paginate a group or Comic section."""
25
19
  orphans = 0 if self.model_group == "f" or self.params.get("q") else 5
26
20
  paginator = Paginator(qs, MAX_OBJ_PER_PAGE, orphans=orphans)
@@ -28,21 +22,21 @@ class BrowserPaginateView(BrowserPageInBoundsView):
28
22
  paginator_page = paginator.page(page)
29
23
  qs = paginator_page.object_list
30
24
  except EmptyPage:
31
- if model != Folder:
32
- model_name = self.model.__name__ if self.model else "UnknownGroup"
25
+ if self.model_group != "f":
26
+ model_name = qs.model.__name__ if qs.model else "UnknownGroup"
33
27
  LOG.warning(f"No {model_name}s on page {page}")
34
- qs = model.objects.none()
28
+ qs = qs.model.objects.none()
35
29
 
36
30
  return qs
37
31
 
38
32
  def _paginate_groups(self, group_qs):
39
33
  """Paginate the group object list before books."""
40
34
  page = self.kwargs.get("page", 1)
41
- return self._paginate_section(self.model, group_qs, page)
35
+ return self._paginate_section(group_qs, page)
42
36
 
43
37
  def _paginate_books(self, book_qs, total_group_count, page_group_count):
44
38
  """Paginate the book object list based on how many group/folders are showing."""
45
- group_remainder = page_group_count % MAX_OBJ_PER_PAGE
39
+ group_remainder = total_group_count % MAX_OBJ_PER_PAGE
46
40
  num_books_on_mixed_page = MAX_OBJ_PER_PAGE - group_remainder
47
41
  if page_group_count:
48
42
  # There are books after the groups on the same page
@@ -50,7 +44,7 @@ class BrowserPaginateView(BrowserPageInBoundsView):
50
44
  page_book_qs = book_qs[:num_books_on_mixed_page]
51
45
  else:
52
46
  # There are books after the groups on a new page
53
- book_offset = 0 if group_remainder else num_books_on_mixed_page
47
+ book_offset = 0 if not group_remainder else num_books_on_mixed_page
54
48
  page_book_qs = book_qs[book_offset:]
55
49
 
56
50
  # Which book page are we on after groups?
@@ -58,7 +52,7 @@ class BrowserPaginateView(BrowserPageInBoundsView):
58
52
  num_group_and_mixed_pages = ceil(total_group_count / MAX_OBJ_PER_PAGE)
59
53
  book_only_page = page - num_group_and_mixed_pages
60
54
 
61
- page_book_qs = self._paginate_section(Comic, page_book_qs, book_only_page)
55
+ page_book_qs = self._paginate_section(page_book_qs, book_only_page)
62
56
  return page_book_qs
63
57
 
64
58
  def paginate(self, group_qs, book_qs, group_count):
@@ -0,0 +1,64 @@
1
+ """Parse browser params."""
2
+
3
+ from types import MappingProxyType
4
+ from typing import Any
5
+
6
+ from codex.serializers.browser.settings import BrowserSettingsSerializer
7
+ from codex.views.const import FOLDER_GROUP, STORY_ARC_GROUP
8
+ from codex.views.session import SessionView
9
+ from codex.views.util import reparse_json_query_params
10
+
11
+
12
+ class BrowserParamsView(SessionView):
13
+ """Browser Params Parsing."""
14
+
15
+ input_serializer_class = BrowserSettingsSerializer
16
+ REPARSE_JSON_FIELDS = frozenset({"breadcrumbs", "filters", "show"})
17
+
18
+ def __init__(self, *args, **kwargs):
19
+ """Initialize properties."""
20
+ super().__init__(*args, **kwargs)
21
+ self._params: MappingProxyType[str, Any] | None = None
22
+
23
+ def _parse_query_params(self):
24
+ """Parse GET query parameters: filter object & snake case."""
25
+ query_params = reparse_json_query_params(
26
+ self.request.GET, self.REPARSE_JSON_FIELDS
27
+ )
28
+ if "q" not in query_params and (query := query_params.get("query")):
29
+ # parse query param for opds v2
30
+ query_params["q"] = query
31
+ return query_params
32
+
33
+ def validate_settings(self):
34
+ """Not used until browser/validate.py."""
35
+
36
+ @property
37
+ def params(self):
38
+ """Validate sbmitted settings and apply them over the session settings."""
39
+ if self._params is None:
40
+ data = self._parse_query_params()
41
+ serializer = self.input_serializer_class(data=data)
42
+ serializer.is_valid(raise_exception=True)
43
+
44
+ params: dict[str, Any] = {}
45
+ defaults = self.SESSION_DEFAULTS[self.SESSION_KEY]
46
+ params.update(defaults)
47
+ group = self.kwargs.get("group")
48
+ if group:
49
+ # order_by has a dynamic group based default
50
+ order_defaults = {
51
+ "order_by": "filename"
52
+ if group == FOLDER_GROUP
53
+ else "story_arc_number"
54
+ if group == STORY_ARC_GROUP
55
+ else "sort_name"
56
+ }
57
+ params.update(order_defaults)
58
+ validated_data = serializer.validated_data
59
+
60
+ if validated_data:
61
+ params.update(validated_data) # type: ignore
62
+ self._params = MappingProxyType(params)
63
+ self.validate_settings()
64
+ return self._params
@@ -1,17 +1,12 @@
1
1
  """Browser title."""
2
2
 
3
- from codex.models import BrowserGroupModel, Comic, Volume
3
+ from codex.models import Comic, Volume
4
4
  from codex.views.browser.breadcrumbs import BrowserBreadcrumbsView
5
5
 
6
6
 
7
7
  class BrowserTitleView(BrowserBreadcrumbsView):
8
8
  """Browser title methods."""
9
9
 
10
- def __init__(self, *args, **kwargs):
11
- """Set params for the type checker."""
12
- super().__init__(*args, **kwargs)
13
- self.group_instance: BrowserGroupModel | None = None
14
-
15
10
  def _get_root_group_name(self):
16
11
  if not self.model:
17
12
  reason = "No model set in browser"
@@ -3,13 +3,17 @@
3
3
  from copy import deepcopy
4
4
  from types import MappingProxyType
5
5
 
6
+ from rest_framework.exceptions import NotFound
7
+
8
+ from codex.choices import DEFAULT_BROWSER_ROUTE, mapping_to_dict
6
9
  from codex.exceptions import SeeOtherRedirectError
7
10
  from codex.logger.logging import get_logger
8
- from codex.serializers.choices import DEFAULTS
9
- from codex.views.browser.base import BrowserBaseView
11
+ from codex.models.groups import BrowserGroupModel
12
+ from codex.views.browser.filters.search.parse import SearchFilterView
10
13
  from codex.views.const import (
11
14
  COMIC_GROUP,
12
15
  FOLDER_GROUP,
16
+ GROUP_MODEL_MAP,
13
17
  ROOT_GROUP,
14
18
  STORY_ARC_GROUP,
15
19
  )
@@ -17,19 +21,55 @@ from codex.views.const import (
17
21
  LOG = get_logger(__name__)
18
22
 
19
23
 
20
- class BrowserValidateView(BrowserBaseView):
24
+ class BrowserValidateView(SearchFilterView):
21
25
  """Browser Settings and URL Validation."""
22
26
 
23
27
  DEFAULT_ROUTE = MappingProxyType(
24
- {
25
- "name": "browser",
26
- "params": deepcopy(DEFAULTS["breadcrumbs"][0]),
27
- }
28
+ {"name": "browser", "params": DEFAULT_BROWSER_ROUTE}
28
29
  )
29
30
 
31
+ def __init__(self, *args, **kwargs):
32
+ """Initialize properties."""
33
+ super().__init__(*args, **kwargs)
34
+ self._is_admin: bool | None = None
35
+ self._model_group: str = ""
36
+ self._model: type[BrowserGroupModel] | None = None
37
+ self._rel_prefix: str | None = None
38
+ self._valid_nav_groups: tuple[str, ...] | None = None
39
+
40
+ @property
41
+ def model_group(self):
42
+ """Memoize the model group."""
43
+ if not self._model_group:
44
+ group = self.kwargs["group"]
45
+ if group == ROOT_GROUP:
46
+ group = self.params["top_group"]
47
+ self._model_group = group
48
+ return self._model_group
49
+
50
+ @property
51
+ def model(self) -> type[BrowserGroupModel] | None:
52
+ """Memoize the model for the browse list."""
53
+ if not self._model:
54
+ model = GROUP_MODEL_MAP.get(self.model_group)
55
+ if model is None:
56
+ group = self.kwargs["group"]
57
+ detail = f"Cannot browse {group=}"
58
+ LOG.debug(detail)
59
+ raise NotFound(detail=detail)
60
+ self._model = model
61
+ return self._model
62
+
63
+ @property
64
+ def rel_prefix(self):
65
+ """Memoize model rel prefix."""
66
+ if self._rel_prefix is None:
67
+ self._rel_prefix = self.get_rel_prefix(self.model)
68
+ return self._rel_prefix
69
+
30
70
  def raise_redirect(self, reason, route_mask=None, settings_mask=None):
31
71
  """Redirect the client to a valid group url."""
32
- route = deepcopy(dict(self.DEFAULT_ROUTE))
72
+ route = mapping_to_dict(self.DEFAULT_ROUTE)
33
73
  if route_mask:
34
74
  route["params"].update(route_mask) # type: ignore
35
75
  settings = deepcopy(dict(self.params))
@@ -73,7 +113,7 @@ class BrowserValidateView(BrowserBaseView):
73
113
  settings_mask = {"top_group": valid_top_group, "breadcrumbs": breadcrumbs}
74
114
  self.raise_redirect(reason, route, settings_mask)
75
115
 
76
- def set_valid_browse_nav_groups(self, valid_top_groups):
116
+ def _get_valid_browse_nav_groups(self, valid_top_groups):
77
117
  """Get valid nav groups for the current settings.
78
118
 
79
119
  Valid nav groups are the top group and below that are also
@@ -96,7 +136,7 @@ class BrowserValidateView(BrowserBaseView):
96
136
  reason = f"Nav group {nav_group} unavailable, redirect to {ROOT_GROUP}"
97
137
  self.raise_redirect(reason)
98
138
 
99
- self.valid_nav_groups = tuple(valid_nav_groups)
139
+ return tuple(valid_nav_groups)
100
140
 
101
141
  def _validate_folder_settings(self):
102
142
  """Check that all the view variables for folder mode are set right."""
@@ -113,7 +153,7 @@ class BrowserValidateView(BrowserBaseView):
113
153
 
114
154
  valid_top_groups = (FOLDER_GROUP,)
115
155
  self._validate_top_group(valid_top_groups)
116
- self.valid_nav_groups = valid_top_groups
156
+ return valid_top_groups
117
157
 
118
158
  def _validate_browser_group_settings(self):
119
159
  """Check that all the view variables for browser mode are set right."""
@@ -132,29 +172,24 @@ class BrowserValidateView(BrowserBaseView):
132
172
 
133
173
  # Validate Browser nav_group
134
174
  # Redirect if nav group is wrong
135
- self.set_valid_browse_nav_groups(valid_top_groups)
175
+ return self._get_valid_browse_nav_groups(valid_top_groups)
136
176
 
137
- def _validate_story_arc_settings(self):
177
+ def _validate_story_arc_settings(self) -> tuple[str, ...]:
138
178
  """Validate story arc settings."""
139
179
  valid_top_groups = (STORY_ARC_GROUP,)
140
180
  self._validate_top_group(valid_top_groups)
141
- self.valid_nav_groups = valid_top_groups
142
-
143
- def validate_settings(self):
144
- """Validate group and top group settings."""
145
- group = self.kwargs["group"]
146
- if group == FOLDER_GROUP:
147
- self._validate_folder_settings()
148
- elif group == STORY_ARC_GROUP:
149
- self._validate_story_arc_settings()
150
- else:
151
- self._validate_browser_group_settings()
152
-
153
- # Validate order
154
- if self.order_key == "filename" and not self.admin_flags["folder_view"]:
155
- pks = self.kwargs["pks"]
156
- page = self.kwargs["page"]
157
- route_changes = {"group": group, "pks": pks, "page": page}
158
- reason = "order by filename not allowed by admin flag."
159
- settings_mask = {"order_by": "sort_name"}
160
- self.raise_redirect(reason, route_changes, settings_mask)
181
+ return valid_top_groups
182
+
183
+ @property
184
+ def valid_nav_groups(self) -> tuple[str, ...]:
185
+ """Memoize valid nav groups."""
186
+ if self._valid_nav_groups is None:
187
+ group = self.kwargs["group"]
188
+ if group == FOLDER_GROUP:
189
+ vng = self._validate_folder_settings()
190
+ elif group == STORY_ARC_GROUP:
191
+ vng = self._validate_story_arc_settings()
192
+ else:
193
+ vng = self._validate_browser_group_settings()
194
+ self._valid_nav_groups = vng
195
+ return self._valid_nav_groups
codex/views/download.py CHANGED
@@ -22,7 +22,7 @@ class DownloadView(AuthFilterAPIView):
22
22
  """Download a comic archive."""
23
23
  pk = kwargs.get("pk")
24
24
  try:
25
- group_acl_filter = self.get_group_acl_filter(Comic)
25
+ group_acl_filter = self.get_group_acl_filter(Comic, self.request.user)
26
26
  comic = (
27
27
  Comic.objects.filter(group_acl_filter)
28
28
  .only("path", "file_type")
codex/views/mixins.py CHANGED
@@ -12,7 +12,7 @@ class SharedAnnotationsMixin:
12
12
  """Cross view annotation methods."""
13
13
 
14
14
  @staticmethod
15
- def _get_order_groups(pks, model_group):
15
+ def _get_order_groups(model_group, pks):
16
16
  """Annotate sort_name."""
17
17
  if not pks or len(pks) > 1:
18
18
  order_groups = _SHOW_GROUPS
@@ -28,12 +28,11 @@ class SharedAnnotationsMixin:
28
28
  return order_groups
29
29
 
30
30
  @classmethod
31
- def alias_sort_names(cls, qs, model, pks, model_group, show=None):
31
+ def get_sort_name_annotations(cls, model, model_group, pks, show):
32
32
  """Annotate sort names for browser subclasses and reader."""
33
33
  sort_name_annotations = {}
34
- comic_sort_names = []
35
- if model == Comic:
36
- order_groups = cls._get_order_groups(pks, model_group)
34
+ if model is Comic:
35
+ order_groups = cls._get_order_groups(model_group, pks)
37
36
  for order_group in order_groups:
38
37
  if show and not show.get(order_group):
39
38
  continue
@@ -42,23 +41,19 @@ class SharedAnnotationsMixin:
42
41
  name_field = "name" if group_name == "volume" else "sort_name"
43
42
  sort_name = F(f"{group_name}__{name_field}")
44
43
  sort_name_annotations[ann_name] = sort_name
45
- comic_sort_names.append(ann_name)
46
- elif model == Volume:
44
+ elif model is Volume:
47
45
  sort_name_annotations["sort_name"] = F("name")
48
-
49
- if sort_name_annotations:
50
- qs = qs.alias(**sort_name_annotations)
51
- return qs, comic_sort_names
46
+ return sort_name_annotations
52
47
 
53
48
  @classmethod
54
- def annotate_group_names(cls, qs, model):
49
+ def annotate_group_names(cls, qs):
55
50
  """Annotate name fields by hoisting them up."""
56
51
  # Optimized to only lookup what is used on the frontend
57
52
  target = cls.TARGET # type: ignore
58
53
  if target not in frozenset({"browser", "opds1", "opds2", "reader"}):
59
54
  return qs
60
55
  group_names = {}
61
- if model == Comic:
56
+ if qs.model is Comic:
62
57
  if target != "reader":
63
58
  group_names["publisher_name"] = F("publisher__name")
64
59
  if target == "opds2":
@@ -69,8 +64,25 @@ class SharedAnnotationsMixin:
69
64
  "volume_name": F("volume__name"),
70
65
  }
71
66
  )
72
- elif model == Volume:
67
+ elif qs.model is Volume:
73
68
  group_names["series_name"] = F("series__name")
74
- elif model == Imprint:
69
+ elif qs.model is Imprint:
75
70
  group_names["publisher_name"] = F("publisher__name")
76
71
  return qs.annotate(**group_names)
72
+
73
+
74
+ class BookmarkSearchMixin:
75
+ """Create Bookmark Search kwargs."""
76
+
77
+ @staticmethod
78
+ def get_bookmark_search_kwargs(auth_filter, comic_filter=None):
79
+ """Get the search kwargs for a user's authentication state."""
80
+ # search kwargs are relative to the bookmark object.
81
+ search_kwargs = {}
82
+ search_kwargs.update(auth_filter)
83
+
84
+ if comic_filter:
85
+ for key, value in comic_filter.items():
86
+ search_kwargs[f"comic__{key}"] = value
87
+
88
+ return search_kwargs
codex/views/opds/const.py CHANGED
@@ -1,6 +1,5 @@
1
1
  """OPDS Common consts."""
2
2
 
3
- from collections.abc import Mapping
4
3
  from types import MappingProxyType
5
4
 
6
5
  from codex.models import (
@@ -63,7 +62,7 @@ class MimeType:
63
62
  HTML = "text/html"
64
63
  AUTH_BASIC = "http://opds-spec.org/auth/basic"
65
64
  COOKIE = "cookie"
66
- FILE_TYPE_MAP: Mapping[str, str] = MappingProxyType(
65
+ FILE_TYPE_MAP: MappingProxyType[str, str] = MappingProxyType(
67
66
  {
68
67
  "CBZ": "application/vnd.comicbook+zip",
69
68
  "CBR": "application/vnd.comicbook+rar",
@@ -71,7 +70,7 @@ class MimeType:
71
70
  "PDF": "application/pdf",
72
71
  }
73
72
  )
74
- SIMPLE_FILE_TYPE_MAP: Mapping[str, str] = MappingProxyType(
73
+ SIMPLE_FILE_TYPE_MAP: MappingProxyType[str, str] = MappingProxyType(
75
74
  {
76
75
  # PocketBooks needs app/zip
77
76
  "CBZ": "application/zip",
codex/views/opds/urls.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from django.urls import reverse
4
4
  from rest_framework.response import Response
5
5
 
6
- from codex.serializers.choices import DEFAULTS
6
+ from codex.choices import DEFAULT_BROWSER_ROUTE
7
7
  from codex.serializers.opds.urls import OPDSURLsSerializer
8
8
  from codex.views.auth import AuthGenericAPIView
9
9
  from codex.views.util import pop_name
@@ -19,7 +19,7 @@ class OPDSURLsView(AuthGenericAPIView):
19
19
  def get(self, *args, **kwargs):
20
20
  """Resolve the urls."""
21
21
  obj = {}
22
- route = DEFAULTS["breadcrumbs"][0]
22
+ route = DEFAULT_BROWSER_ROUTE
23
23
  route = pop_name(route)
24
24
  for version in _OPDS_VERSIONS:
25
25
  key = f"v{version}"
codex/views/opds/util.py CHANGED
@@ -5,11 +5,11 @@ from django.http.response import HttpResponseRedirect
5
5
  from django.urls import reverse
6
6
  from django.utils.http import urlencode
7
7
 
8
+ from codex.choices import DEFAULT_BROWSER_ROUTE
8
9
  from codex.models import (
9
10
  Contributor,
10
11
  ContributorPerson,
11
12
  )
12
- from codex.serializers.choices import DEFAULTS
13
13
  from codex.views.auth import GroupACLMixin
14
14
  from codex.views.opds.const import OPDS_M2M_MODELS
15
15
 
@@ -71,8 +71,7 @@ def full_redirect_view(url_name):
71
71
 
72
72
  def func(request):
73
73
  """Redirect to view, forwarding query strings and auth."""
74
- kwargs = DEFAULTS["breadcrumbs"][0]
75
- kwargs.pop("name", None)
74
+ kwargs = dict(DEFAULT_BROWSER_ROUTE)
76
75
  url = reverse(url_name, kwargs=kwargs)
77
76
 
78
77
  # Forward the query string.
@@ -82,7 +82,9 @@ class OPDS1EntryLinksMixin:
82
82
  else:
83
83
  mime_type = MimeType.NAV
84
84
 
85
- thr_count = 0 if self.fake else self.obj.child_count
85
+ thr_count = (
86
+ 0 if self.fake else 1 if self.obj.group == "c" else self.obj.child_count
87
+ )
86
88
  rel = Rel.ALTERNATE if metadata else "subsection"
87
89
 
88
90
  return OPDS1Link(rel, href, mime_type, thr_count=thr_count)