codex 1.6.19__py3-none-any.whl → 1.7.0__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 (842) hide show
  1. codex/choices.py +419 -0
  2. codex/choices_to_json.py +122 -0
  3. codex/db.py +134 -0
  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 +3 -3
  13. codex/librarian/importer/const.py +7 -1
  14. codex/librarian/importer/create_fks.py +5 -2
  15. codex/librarian/importer/importerd.py +17 -12
  16. codex/librarian/importer/moved.py +44 -13
  17. codex/librarian/importer/tasks.py +2 -0
  18. codex/librarian/janitor/cleanup.py +21 -8
  19. codex/librarian/janitor/integrity.py +371 -0
  20. codex/librarian/janitor/janitor.py +50 -15
  21. codex/librarian/janitor/latest_version.py +2 -1
  22. codex/librarian/janitor/status.py +5 -0
  23. codex/librarian/janitor/tasks.py +37 -0
  24. codex/librarian/janitor/update.py +1 -1
  25. codex/librarian/librariand.py +37 -24
  26. codex/librarian/search/optimize.py +43 -0
  27. codex/librarian/search/remove.py +18 -46
  28. codex/librarian/search/searchd.py +14 -17
  29. codex/librarian/search/status.py +2 -1
  30. codex/librarian/search/tasks.py +4 -9
  31. codex/librarian/search/update.py +223 -301
  32. codex/librarian/watchdog/emitter.py +21 -19
  33. codex/librarian/watchdog/event_batcherd.py +0 -1
  34. codex/librarian/watchdog/observers.py +2 -1
  35. codex/migrations/0029_comicfts.py +58 -0
  36. codex/migrations/0030_nocase_collation_day_month_indexes_status_types.py +202 -0
  37. codex/models/admin.py +15 -11
  38. codex/models/base.py +9 -0
  39. codex/models/bookmark.py +3 -3
  40. codex/models/comic.py +68 -16
  41. codex/models/functions.py +60 -2
  42. codex/models/groups.py +6 -1
  43. codex/models/library.py +1 -3
  44. codex/models/paths.py +9 -3
  45. codex/models/query.py +6 -0
  46. codex/run.py +11 -9
  47. codex/serializers/admin/tasks.py +2 -2
  48. codex/serializers/browser/mixins.py +18 -14
  49. codex/serializers/browser/page.py +2 -0
  50. codex/serializers/browser/settings.py +4 -4
  51. codex/serializers/fields.py +9 -5
  52. codex/settings/settings.py +16 -17
  53. codex/signals/django_signals.py +4 -10
  54. codex/startup.py +7 -39
  55. codex/static_root/assets/VCheckbox-D_CWEmqR.84f2b49311e8.js +1 -0
  56. codex/static_root/assets/VCheckbox-D_CWEmqR.84f2b49311e8.js.br +0 -0
  57. codex/static_root/assets/VCheckbox-D_CWEmqR.84f2b49311e8.js.gz +0 -0
  58. codex/static_root/assets/VCheckbox-D_CWEmqR.js +1 -0
  59. codex/static_root/assets/VCheckbox-D_CWEmqR.js.br +0 -0
  60. codex/static_root/assets/VCheckbox-D_CWEmqR.js.gz +0 -0
  61. codex/static_root/assets/VCheckboxBtn-B1BhcFvi.0eaf3c516474.js +1 -0
  62. codex/static_root/assets/VCheckboxBtn-B1BhcFvi.0eaf3c516474.js.br +0 -0
  63. codex/static_root/assets/VCheckboxBtn-B1BhcFvi.0eaf3c516474.js.gz +0 -0
  64. codex/static_root/assets/VCheckboxBtn-B1BhcFvi.js +1 -0
  65. codex/static_root/assets/VCheckboxBtn-B1BhcFvi.js.br +0 -0
  66. codex/static_root/assets/VCheckboxBtn-B1BhcFvi.js.gz +0 -0
  67. codex/static_root/assets/VCombobox-CZAW6_3Q.0e2401e819a5.js +1 -0
  68. codex/static_root/assets/VCombobox-CZAW6_3Q.0e2401e819a5.js.br +0 -0
  69. codex/static_root/assets/VCombobox-CZAW6_3Q.0e2401e819a5.js.gz +0 -0
  70. codex/static_root/assets/VCombobox-CZAW6_3Q.js +1 -0
  71. codex/static_root/assets/VCombobox-CZAW6_3Q.js.br +0 -0
  72. codex/static_root/assets/VCombobox-CZAW6_3Q.js.gz +0 -0
  73. codex/static_root/assets/VDialog-CSHgHIlG.a0bcd336cb7b.js +1 -0
  74. codex/static_root/assets/VDialog-CSHgHIlG.a0bcd336cb7b.js.br +0 -0
  75. codex/static_root/assets/VDialog-CSHgHIlG.a0bcd336cb7b.js.gz +0 -0
  76. codex/static_root/assets/VDialog-CSHgHIlG.js +1 -0
  77. codex/static_root/assets/VDialog-CSHgHIlG.js.br +0 -0
  78. codex/static_root/assets/VDialog-CSHgHIlG.js.gz +0 -0
  79. codex/static_root/assets/VDialog-CSvrKKb2.css +1 -0
  80. codex/static_root/assets/VDialog-CSvrKKb2.css.br +0 -0
  81. codex/static_root/assets/VDialog-CSvrKKb2.css.gz +0 -0
  82. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css +1 -0
  83. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.br +0 -0
  84. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.gz +0 -0
  85. codex/static_root/assets/VExpansionPanels-CG6MpdMC.e96ae8afad97.js +1 -0
  86. codex/static_root/assets/VExpansionPanels-CG6MpdMC.e96ae8afad97.js.br +0 -0
  87. codex/static_root/assets/VExpansionPanels-CG6MpdMC.e96ae8afad97.js.gz +0 -0
  88. codex/static_root/assets/VExpansionPanels-CG6MpdMC.js +1 -0
  89. codex/static_root/assets/VExpansionPanels-CG6MpdMC.js.br +0 -0
  90. codex/static_root/assets/VExpansionPanels-CG6MpdMC.js.gz +0 -0
  91. codex/static_root/assets/VRadioGroup-CAgQxkiU.f26ecb0c3e34.js +1 -0
  92. codex/static_root/assets/VRadioGroup-CAgQxkiU.f26ecb0c3e34.js.br +0 -0
  93. codex/static_root/assets/VRadioGroup-CAgQxkiU.f26ecb0c3e34.js.gz +0 -0
  94. codex/static_root/assets/VRadioGroup-CAgQxkiU.js +1 -0
  95. codex/static_root/assets/VRadioGroup-CAgQxkiU.js.br +0 -0
  96. codex/static_root/assets/VRadioGroup-CAgQxkiU.js.gz +0 -0
  97. codex/static_root/assets/VSelect-C1gez8rl.9b11d2f00faf.js +1 -0
  98. codex/static_root/assets/VSelect-C1gez8rl.9b11d2f00faf.js.br +0 -0
  99. codex/static_root/assets/VSelect-C1gez8rl.9b11d2f00faf.js.gz +0 -0
  100. codex/static_root/assets/VSelect-C1gez8rl.js +1 -0
  101. codex/static_root/assets/VSelect-C1gez8rl.js.br +0 -0
  102. codex/static_root/assets/VSelect-C1gez8rl.js.gz +0 -0
  103. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css +1 -0
  104. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.br +0 -0
  105. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.gz +0 -0
  106. codex/static_root/assets/VSelect-DLu8bpcs.css +1 -0
  107. codex/static_root/assets/VSelect-DLu8bpcs.css.br +0 -0
  108. codex/static_root/assets/VSelect-DLu8bpcs.css.gz +0 -0
  109. codex/static_root/assets/VSelectionControl-DBqDlKjK.160beaa1b56c.js +1 -0
  110. codex/static_root/assets/VSelectionControl-DBqDlKjK.160beaa1b56c.js.br +0 -0
  111. codex/static_root/assets/VSelectionControl-DBqDlKjK.160beaa1b56c.js.gz +0 -0
  112. codex/static_root/assets/VSelectionControl-DBqDlKjK.js +1 -0
  113. codex/static_root/assets/VSelectionControl-DBqDlKjK.js.br +0 -0
  114. codex/static_root/assets/VSelectionControl-DBqDlKjK.js.gz +0 -0
  115. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css +1 -0
  116. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.br +0 -0
  117. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.gz +0 -0
  118. codex/static_root/assets/VSlideGroup-BtXPhMOT.css +1 -0
  119. codex/static_root/assets/VSlideGroup-BtXPhMOT.css.br +0 -0
  120. codex/static_root/assets/VSlideGroup-BtXPhMOT.css.gz +0 -0
  121. codex/static_root/assets/VSlideGroup-SqR_NAL1.40ba1d838a6e.js +1 -0
  122. codex/static_root/assets/VSlideGroup-SqR_NAL1.40ba1d838a6e.js.br +0 -0
  123. codex/static_root/assets/VSlideGroup-SqR_NAL1.40ba1d838a6e.js.gz +0 -0
  124. codex/static_root/assets/VSlideGroup-SqR_NAL1.js +1 -0
  125. codex/static_root/assets/VSlideGroup-SqR_NAL1.js.br +0 -0
  126. codex/static_root/assets/VSlideGroup-SqR_NAL1.js.gz +0 -0
  127. codex/static_root/assets/VTable-CYC-wMpk.8f15d66044da.js +1 -0
  128. codex/static_root/assets/VTable-CYC-wMpk.8f15d66044da.js.br +0 -0
  129. codex/static_root/assets/VTable-CYC-wMpk.8f15d66044da.js.gz +0 -0
  130. codex/static_root/assets/VTable-CYC-wMpk.js +1 -0
  131. codex/static_root/assets/VTable-CYC-wMpk.js.br +0 -0
  132. codex/static_root/assets/VTable-CYC-wMpk.js.gz +0 -0
  133. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css +1 -0
  134. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.br +0 -0
  135. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.gz +0 -0
  136. codex/static_root/assets/VTextField-BnCEPZIq.css +1 -0
  137. codex/static_root/assets/VTextField-BnCEPZIq.css.br +0 -0
  138. codex/static_root/assets/VTextField-BnCEPZIq.css.gz +0 -0
  139. codex/static_root/assets/VTextField-DMRKRbbT.911ac84d8c9d.js +1 -0
  140. codex/static_root/assets/VTextField-DMRKRbbT.911ac84d8c9d.js.br +0 -0
  141. codex/static_root/assets/VTextField-DMRKRbbT.911ac84d8c9d.js.gz +0 -0
  142. codex/static_root/assets/VTextField-DMRKRbbT.js +1 -0
  143. codex/static_root/assets/VTextField-DMRKRbbT.js.br +0 -0
  144. codex/static_root/assets/VTextField-DMRKRbbT.js.gz +0 -0
  145. codex/static_root/assets/VWindowItem-D0P2xNJl.6a10e3f3a153.js +1 -0
  146. codex/static_root/assets/VWindowItem-D0P2xNJl.6a10e3f3a153.js.br +0 -0
  147. codex/static_root/assets/VWindowItem-D0P2xNJl.6a10e3f3a153.js.gz +0 -0
  148. codex/static_root/assets/VWindowItem-D0P2xNJl.js +1 -0
  149. codex/static_root/assets/VWindowItem-D0P2xNJl.js.br +0 -0
  150. codex/static_root/assets/VWindowItem-D0P2xNJl.js.gz +0 -0
  151. codex/static_root/assets/admin-CD90VMen.4c2b6f2a5111.js +1 -0
  152. codex/static_root/assets/admin-CD90VMen.4c2b6f2a5111.js.br +0 -0
  153. codex/static_root/assets/admin-CD90VMen.4c2b6f2a5111.js.gz +0 -0
  154. codex/static_root/assets/admin-CD90VMen.js +1 -0
  155. codex/static_root/assets/admin-CD90VMen.js.br +0 -0
  156. codex/static_root/assets/admin-CD90VMen.js.gz +0 -0
  157. codex/static_root/assets/{admin-CWEjaFr5.7d4523387384.css → admin-DJ7pIXDQ.css} +1 -1
  158. codex/static_root/assets/admin-DJ7pIXDQ.css.br +0 -0
  159. codex/static_root/assets/admin-DJ7pIXDQ.css.gz +0 -0
  160. codex/static_root/assets/{admin-CWEjaFr5.css → admin-DJ7pIXDQ.e2a77af73ef2.css} +1 -1
  161. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.br +0 -0
  162. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.gz +0 -0
  163. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css +1 -0
  164. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css.br +0 -0
  165. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css.gz +0 -0
  166. codex/static_root/assets/admin-menu-B9bzD6hV.css +1 -0
  167. codex/static_root/assets/admin-menu-B9bzD6hV.css.br +0 -0
  168. codex/static_root/assets/admin-menu-B9bzD6hV.css.gz +0 -0
  169. codex/static_root/assets/admin-menu-BpEPGKr_.c9f9178c5a82.js +1 -0
  170. codex/static_root/assets/admin-menu-BpEPGKr_.c9f9178c5a82.js.br +0 -0
  171. codex/static_root/assets/admin-menu-BpEPGKr_.c9f9178c5a82.js.gz +0 -0
  172. codex/static_root/assets/admin-menu-BpEPGKr_.js +1 -0
  173. codex/static_root/assets/admin-menu-BpEPGKr_.js.br +0 -0
  174. codex/static_root/assets/admin-menu-BpEPGKr_.js.gz +0 -0
  175. codex/static_root/assets/admin-settings-button-progress-DDF4rY07.4f1158b650ab.js +1 -0
  176. codex/static_root/assets/admin-settings-button-progress-DDF4rY07.4f1158b650ab.js.br +0 -0
  177. codex/static_root/assets/admin-settings-button-progress-DDF4rY07.4f1158b650ab.js.gz +0 -0
  178. codex/static_root/assets/admin-settings-button-progress-DDF4rY07.js +1 -0
  179. codex/static_root/assets/admin-settings-button-progress-DDF4rY07.js.br +0 -0
  180. codex/static_root/assets/admin-settings-button-progress-DDF4rY07.js.gz +0 -0
  181. codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.2548c49a853e.css +1 -0
  182. codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.css +1 -0
  183. codex/static_root/assets/browser-C0KS3g2E.0bf1c9c6319c.js +1 -0
  184. codex/static_root/assets/browser-C0KS3g2E.0bf1c9c6319c.js.br +0 -0
  185. codex/static_root/assets/browser-C0KS3g2E.0bf1c9c6319c.js.gz +0 -0
  186. codex/static_root/assets/browser-C0KS3g2E.js +1 -0
  187. codex/static_root/assets/browser-C0KS3g2E.js.br +0 -0
  188. codex/static_root/assets/browser-C0KS3g2E.js.gz +0 -0
  189. codex/static_root/assets/browser-JFL2hLjt.21cb2f7335f7.css +1 -0
  190. codex/static_root/assets/browser-JFL2hLjt.21cb2f7335f7.css.br +0 -0
  191. codex/static_root/assets/browser-JFL2hLjt.21cb2f7335f7.css.gz +0 -0
  192. codex/static_root/assets/browser-JFL2hLjt.css +1 -0
  193. codex/static_root/assets/browser-JFL2hLjt.css.br +0 -0
  194. codex/static_root/assets/browser-JFL2hLjt.css.gz +0 -0
  195. codex/static_root/assets/change-password-dialog-DXJalgW4.a9f34729599d.js +1 -0
  196. codex/static_root/assets/change-password-dialog-DXJalgW4.a9f34729599d.js.br +0 -0
  197. codex/static_root/assets/change-password-dialog-DXJalgW4.a9f34729599d.js.gz +0 -0
  198. codex/static_root/assets/change-password-dialog-DXJalgW4.js +1 -0
  199. codex/static_root/assets/change-password-dialog-DXJalgW4.js.br +0 -0
  200. codex/static_root/assets/change-password-dialog-DXJalgW4.js.gz +0 -0
  201. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css +1 -0
  202. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.br +0 -0
  203. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.gz +0 -0
  204. codex/static_root/assets/change-password-dialog-DrIXdKUC.css +1 -0
  205. codex/static_root/assets/change-password-dialog-DrIXdKUC.css.br +0 -0
  206. codex/static_root/assets/change-password-dialog-DrIXdKUC.css.gz +0 -0
  207. codex/static_root/assets/confirm-dialog-B7w6z2rf.472011c06253.css +1 -0
  208. codex/static_root/assets/confirm-dialog-B7w6z2rf.css +1 -0
  209. codex/static_root/assets/confirm-dialog-CqDEpU9k.e1811488121d.js +1 -0
  210. codex/static_root/assets/confirm-dialog-CqDEpU9k.e1811488121d.js.br +0 -0
  211. codex/static_root/assets/confirm-dialog-CqDEpU9k.e1811488121d.js.gz +0 -0
  212. codex/static_root/assets/confirm-dialog-CqDEpU9k.js +1 -0
  213. codex/static_root/assets/confirm-dialog-CqDEpU9k.js.br +0 -0
  214. codex/static_root/assets/confirm-dialog-CqDEpU9k.js.gz +0 -0
  215. codex/static_root/assets/datetime-column-UxNaJr8b.c06a11531af3.js +1 -0
  216. codex/static_root/assets/datetime-column-UxNaJr8b.c06a11531af3.js.br +0 -0
  217. codex/static_root/assets/datetime-column-UxNaJr8b.c06a11531af3.js.gz +0 -0
  218. codex/static_root/assets/datetime-column-UxNaJr8b.js +1 -0
  219. codex/static_root/assets/datetime-column-UxNaJr8b.js.br +0 -0
  220. codex/static_root/assets/datetime-column-UxNaJr8b.js.gz +0 -0
  221. codex/static_root/assets/filter-DskcqZHA.e707b5a05b4b.js +1 -0
  222. codex/static_root/assets/filter-DskcqZHA.e707b5a05b4b.js.br +0 -0
  223. codex/static_root/assets/filter-DskcqZHA.e707b5a05b4b.js.gz +0 -0
  224. codex/static_root/assets/filter-DskcqZHA.js +1 -0
  225. codex/static_root/assets/filter-DskcqZHA.js.br +0 -0
  226. codex/static_root/assets/filter-DskcqZHA.js.gz +0 -0
  227. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css +1 -0
  228. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.br +0 -0
  229. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.gz +0 -0
  230. codex/static_root/assets/flag-tab-CqWovuBu.css +1 -0
  231. codex/static_root/assets/flag-tab-CqWovuBu.css.br +0 -0
  232. codex/static_root/assets/flag-tab-CqWovuBu.css.gz +0 -0
  233. codex/static_root/assets/flag-tab-xBeWEQ0w.582e77d9e885.js +1 -0
  234. codex/static_root/assets/flag-tab-xBeWEQ0w.582e77d9e885.js.br +0 -0
  235. codex/static_root/assets/flag-tab-xBeWEQ0w.582e77d9e885.js.gz +0 -0
  236. codex/static_root/assets/flag-tab-xBeWEQ0w.js +1 -0
  237. codex/static_root/assets/flag-tab-xBeWEQ0w.js.br +0 -0
  238. codex/static_root/assets/flag-tab-xBeWEQ0w.js.gz +0 -0
  239. codex/static_root/assets/group-tab-Czt2x61x.56e2886b1bac.js +1 -0
  240. codex/static_root/assets/group-tab-Czt2x61x.56e2886b1bac.js.br +0 -0
  241. codex/static_root/assets/group-tab-Czt2x61x.56e2886b1bac.js.gz +0 -0
  242. codex/static_root/assets/group-tab-Czt2x61x.js +1 -0
  243. codex/static_root/assets/group-tab-Czt2x61x.js.br +0 -0
  244. codex/static_root/assets/group-tab-Czt2x61x.js.gz +0 -0
  245. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css +1 -0
  246. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css.br +0 -0
  247. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css.gz +0 -0
  248. codex/static_root/assets/group-tab-DkIN1Heu.css +1 -0
  249. codex/static_root/assets/group-tab-DkIN1Heu.css.br +0 -0
  250. codex/static_root/assets/group-tab-DkIN1Heu.css.gz +0 -0
  251. codex/static_root/assets/http-error-NHcwE5e_.d49089e40589.js +1 -0
  252. codex/static_root/assets/http-error-NHcwE5e_.d49089e40589.js.br +0 -0
  253. codex/static_root/assets/http-error-NHcwE5e_.d49089e40589.js.gz +0 -0
  254. codex/static_root/assets/http-error-NHcwE5e_.js +1 -0
  255. codex/static_root/assets/http-error-NHcwE5e_.js.br +0 -0
  256. codex/static_root/assets/http-error-NHcwE5e_.js.gz +0 -0
  257. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css +1 -0
  258. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css.br +0 -0
  259. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css.gz +0 -0
  260. codex/static_root/assets/index-CL_6g4tJ.css +1 -0
  261. codex/static_root/assets/index-CL_6g4tJ.css.br +0 -0
  262. codex/static_root/assets/index-CL_6g4tJ.css.gz +0 -0
  263. codex/static_root/assets/index-DYNNO5kn.24a2d270253a.js +1 -0
  264. codex/static_root/assets/index-DYNNO5kn.24a2d270253a.js.br +0 -0
  265. codex/static_root/assets/index-DYNNO5kn.24a2d270253a.js.gz +0 -0
  266. codex/static_root/assets/index-DYNNO5kn.js +1 -0
  267. codex/static_root/assets/index-DYNNO5kn.js.br +0 -0
  268. codex/static_root/assets/index-DYNNO5kn.js.gz +0 -0
  269. codex/static_root/assets/library-tab-CgIqcjvj.60327dfa8ecb.js +1 -0
  270. codex/static_root/assets/library-tab-CgIqcjvj.60327dfa8ecb.js.br +0 -0
  271. codex/static_root/assets/library-tab-CgIqcjvj.60327dfa8ecb.js.gz +0 -0
  272. codex/static_root/assets/library-tab-CgIqcjvj.js +1 -0
  273. codex/static_root/assets/library-tab-CgIqcjvj.js.br +0 -0
  274. codex/static_root/assets/library-tab-CgIqcjvj.js.gz +0 -0
  275. codex/static_root/assets/{library-tab-Bh7ErAk7.7c44200ee727.css → library-tab-Wew8YOLv.0c1780a6b68e.css} +1 -1
  276. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.br +0 -0
  277. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.gz +0 -0
  278. codex/static_root/assets/{library-tab-Bh7ErAk7.css → library-tab-Wew8YOLv.css} +1 -1
  279. codex/static_root/assets/library-tab-Wew8YOLv.css.br +0 -0
  280. codex/static_root/assets/library-tab-Wew8YOLv.css.gz +0 -0
  281. codex/static_root/assets/main-B3EwXQ3Q.14dfc21e272c.js +35 -0
  282. codex/static_root/assets/main-B3EwXQ3Q.14dfc21e272c.js.br +0 -0
  283. codex/static_root/assets/main-B3EwXQ3Q.14dfc21e272c.js.gz +0 -0
  284. codex/static_root/assets/main-B3EwXQ3Q.js +35 -0
  285. codex/static_root/assets/main-B3EwXQ3Q.js.br +0 -0
  286. codex/static_root/assets/main-B3EwXQ3Q.js.gz +0 -0
  287. codex/static_root/assets/pager-full-pdf-YkzUXx0B.f39d84e2380a.js +1 -0
  288. codex/static_root/assets/pager-full-pdf-YkzUXx0B.f39d84e2380a.js.br +0 -0
  289. codex/static_root/assets/pager-full-pdf-YkzUXx0B.f39d84e2380a.js.gz +0 -0
  290. codex/static_root/assets/pager-full-pdf-YkzUXx0B.js +1 -0
  291. codex/static_root/assets/pager-full-pdf-YkzUXx0B.js.br +0 -0
  292. codex/static_root/assets/pager-full-pdf-YkzUXx0B.js.gz +0 -0
  293. codex/static_root/assets/pagination-toolbar-CrruiVov.3bf9b795350d.js +1 -0
  294. codex/static_root/assets/pagination-toolbar-CrruiVov.3bf9b795350d.js.br +0 -0
  295. codex/static_root/assets/pagination-toolbar-CrruiVov.3bf9b795350d.js.gz +0 -0
  296. codex/static_root/assets/pagination-toolbar-CrruiVov.js +1 -0
  297. codex/static_root/assets/pagination-toolbar-CrruiVov.js.br +0 -0
  298. codex/static_root/assets/pagination-toolbar-CrruiVov.js.gz +0 -0
  299. codex/static_root/assets/{pagination-toolbar-C45-onwe.4722195bb60b.css → pagination-toolbar-DGrxp2OD.css} +1 -1
  300. codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.br +0 -0
  301. codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.gz +0 -0
  302. codex/static_root/assets/{pagination-toolbar-C45-onwe.css → pagination-toolbar-DGrxp2OD.f960a624f04f.css} +1 -1
  303. codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.br +0 -0
  304. codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.gz +0 -0
  305. codex/static_root/assets/{pdf-doc-BjlRPuf4.0f056fa321b6.js → pdf-doc-ctqZIwOP.7e7b2c815ea4.js} +3 -3
  306. codex/static_root/assets/pdf-doc-ctqZIwOP.7e7b2c815ea4.js.br +0 -0
  307. codex/static_root/assets/pdf-doc-ctqZIwOP.7e7b2c815ea4.js.gz +0 -0
  308. codex/static_root/assets/{pdf-doc-BjlRPuf4.js → pdf-doc-ctqZIwOP.js} +3 -3
  309. codex/static_root/assets/pdf-doc-ctqZIwOP.js.br +0 -0
  310. codex/static_root/assets/pdf-doc-ctqZIwOP.js.gz +0 -0
  311. codex/static_root/assets/reader-DPLhdrJD.268417c618c5.js +2 -0
  312. codex/static_root/assets/reader-DPLhdrJD.268417c618c5.js.br +0 -0
  313. codex/static_root/assets/reader-DPLhdrJD.268417c618c5.js.gz +0 -0
  314. codex/static_root/assets/reader-DPLhdrJD.js +2 -0
  315. codex/static_root/assets/reader-DPLhdrJD.js.br +0 -0
  316. codex/static_root/assets/reader-DPLhdrJD.js.gz +0 -0
  317. codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css +1 -0
  318. codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css.br +0 -0
  319. codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css.gz +0 -0
  320. codex/static_root/assets/reader-nD70BeEz.css +1 -0
  321. codex/static_root/assets/reader-nD70BeEz.css.br +0 -0
  322. codex/static_root/assets/reader-nD70BeEz.css.gz +0 -0
  323. codex/static_root/assets/relation-chips-DOALMcWL.5d3b8100ba03.js +1 -0
  324. codex/static_root/assets/relation-chips-DOALMcWL.5d3b8100ba03.js.br +0 -0
  325. codex/static_root/assets/relation-chips-DOALMcWL.5d3b8100ba03.js.gz +0 -0
  326. codex/static_root/assets/relation-chips-DOALMcWL.js +1 -0
  327. codex/static_root/assets/relation-chips-DOALMcWL.js.br +0 -0
  328. codex/static_root/assets/relation-chips-DOALMcWL.js.gz +0 -0
  329. codex/static_root/assets/settings-drawer-BVj1U_LC.c68369e0c2de.js +2 -0
  330. codex/static_root/assets/settings-drawer-BVj1U_LC.c68369e0c2de.js.br +0 -0
  331. codex/static_root/assets/settings-drawer-BVj1U_LC.c68369e0c2de.js.gz +0 -0
  332. codex/static_root/assets/settings-drawer-BVj1U_LC.js +2 -0
  333. codex/static_root/assets/settings-drawer-BVj1U_LC.js.br +0 -0
  334. codex/static_root/assets/settings-drawer-BVj1U_LC.js.gz +0 -0
  335. codex/static_root/assets/{stats-tab-BXGisn5N.9b7a71e7fe28.css → stats-tab-BAYTqQNg.5f715428c394.css} +1 -1
  336. codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.br +0 -0
  337. codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.gz +0 -0
  338. codex/static_root/assets/{stats-tab-BXGisn5N.css → stats-tab-BAYTqQNg.css} +1 -1
  339. codex/static_root/assets/stats-tab-BAYTqQNg.css.br +0 -0
  340. codex/static_root/assets/stats-tab-BAYTqQNg.css.gz +0 -0
  341. codex/static_root/assets/stats-tab-DDLwwwnP.35305258097b.js +1 -0
  342. codex/static_root/assets/stats-tab-DDLwwwnP.35305258097b.js.br +0 -0
  343. codex/static_root/assets/stats-tab-DDLwwwnP.35305258097b.js.gz +0 -0
  344. codex/static_root/assets/stats-tab-DDLwwwnP.js +1 -0
  345. codex/static_root/assets/stats-tab-DDLwwwnP.js.br +0 -0
  346. codex/static_root/assets/stats-tab-DDLwwwnP.js.gz +0 -0
  347. codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css +1 -0
  348. codex/static_root/assets/{task-tab-1XiWn9xP.06cb8e1b794d.css.br → task-tab--cXi48kg.5dfd6890a1c2.css.br} +1 -1
  349. codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css.gz +0 -0
  350. codex/static_root/assets/task-tab--cXi48kg.css +1 -0
  351. codex/static_root/assets/{task-tab-1XiWn9xP.css.br → task-tab--cXi48kg.css.br} +1 -1
  352. codex/static_root/assets/task-tab--cXi48kg.css.gz +0 -0
  353. codex/static_root/assets/task-tab-BpP3n2dO.c853eb565200.js +1 -0
  354. codex/static_root/assets/task-tab-BpP3n2dO.c853eb565200.js.br +0 -0
  355. codex/static_root/assets/task-tab-BpP3n2dO.c853eb565200.js.gz +0 -0
  356. codex/static_root/assets/task-tab-BpP3n2dO.js +1 -0
  357. codex/static_root/assets/task-tab-BpP3n2dO.js.br +0 -0
  358. codex/static_root/assets/task-tab-BpP3n2dO.js.gz +0 -0
  359. codex/static_root/assets/transition-3g2arGgl.c6e6f91b7978.js +1 -0
  360. codex/static_root/assets/transition-3g2arGgl.c6e6f91b7978.js.br +0 -0
  361. codex/static_root/assets/transition-3g2arGgl.c6e6f91b7978.js.gz +0 -0
  362. codex/static_root/assets/transition-3g2arGgl.js +1 -0
  363. codex/static_root/assets/transition-3g2arGgl.js.br +0 -0
  364. codex/static_root/assets/transition-3g2arGgl.js.gz +0 -0
  365. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css +1 -0
  366. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.br +4 -0
  367. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.gz +0 -0
  368. codex/static_root/assets/transition-5LRFTPo5.css +1 -0
  369. codex/static_root/assets/transition-5LRFTPo5.css.br +4 -0
  370. codex/static_root/assets/transition-5LRFTPo5.css.gz +0 -0
  371. codex/static_root/assets/{unauthorized-muDsv-rC.css → unauthorized-BjhIc97q.728511c92cd0.css} +1 -1
  372. codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.br +0 -0
  373. codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.gz +0 -0
  374. codex/static_root/assets/{unauthorized-muDsv-rC.2166ec8b3a32.css → unauthorized-BjhIc97q.css} +1 -1
  375. codex/static_root/assets/unauthorized-BjhIc97q.css.br +0 -0
  376. codex/static_root/assets/unauthorized-BjhIc97q.css.gz +0 -0
  377. codex/static_root/assets/unauthorized-CdumQ1Vf.79d9a61eb572.js +1 -0
  378. codex/static_root/assets/unauthorized-CdumQ1Vf.79d9a61eb572.js.br +0 -0
  379. codex/static_root/assets/unauthorized-CdumQ1Vf.79d9a61eb572.js.gz +0 -0
  380. codex/static_root/assets/unauthorized-CdumQ1Vf.js +1 -0
  381. codex/static_root/assets/unauthorized-CdumQ1Vf.js.br +0 -0
  382. codex/static_root/assets/unauthorized-CdumQ1Vf.js.gz +0 -0
  383. codex/static_root/assets/user-tab-D6oOKZTP.05944b00c700.js +1 -0
  384. codex/static_root/assets/user-tab-D6oOKZTP.05944b00c700.js.br +0 -0
  385. codex/static_root/assets/user-tab-D6oOKZTP.05944b00c700.js.gz +0 -0
  386. codex/static_root/assets/user-tab-D6oOKZTP.js +1 -0
  387. codex/static_root/assets/user-tab-D6oOKZTP.js.br +0 -0
  388. codex/static_root/assets/user-tab-D6oOKZTP.js.gz +0 -0
  389. codex/static_root/manifest.c5f1de88b1ac.json +712 -0
  390. codex/static_root/manifest.c5f1de88b1ac.json.br +0 -0
  391. codex/static_root/manifest.c5f1de88b1ac.json.gz +0 -0
  392. codex/static_root/manifest.json +371 -294
  393. codex/static_root/manifest.json.br +0 -0
  394. codex/static_root/manifest.json.gz +0 -0
  395. codex/static_root/staticfiles.json +1 -1
  396. codex/status_controller.py +15 -10
  397. codex/threads.py +1 -1
  398. codex/urls/api/auth.py +1 -1
  399. codex/urls/api/browser.py +1 -1
  400. codex/views/admin/library.py +18 -13
  401. codex/views/admin/stats.py +23 -16
  402. codex/views/admin/tasks.py +45 -40
  403. codex/views/auth.py +50 -74
  404. codex/views/bookmark.py +16 -153
  405. codex/views/browser/annotate/__init__.py +1 -0
  406. codex/views/browser/annotate/bookmark.py +112 -0
  407. codex/views/browser/annotate/card.py +61 -0
  408. codex/views/browser/annotate/order.py +247 -0
  409. codex/views/browser/breadcrumbs.py +90 -11
  410. codex/views/browser/browser.py +82 -117
  411. codex/views/browser/choices.py +15 -18
  412. codex/views/browser/cover.py +18 -24
  413. codex/views/browser/filters/bookmark.py +18 -19
  414. codex/views/browser/filters/field.py +8 -3
  415. codex/views/browser/filters/filter.py +69 -0
  416. codex/views/browser/filters/group.py +9 -6
  417. codex/views/browser/filters/search/__init__.py +1 -0
  418. codex/views/browser/filters/search/aliases.py +81 -0
  419. codex/views/browser/filters/search/field/__init__.py +1 -0
  420. codex/views/browser/filters/search/field/column.py +53 -0
  421. codex/views/browser/filters/search/field/expression.py +177 -0
  422. codex/views/browser/filters/search/field/filter.py +70 -0
  423. codex/views/browser/filters/search/field/optimize.py +71 -0
  424. codex/views/browser/filters/search/field/parse.py +187 -0
  425. codex/views/browser/filters/search/fts.py +24 -0
  426. codex/views/browser/filters/search/parse.py +250 -0
  427. codex/views/browser/group_mtime.py +83 -0
  428. codex/views/browser/metadata/__init__.py +1 -0
  429. codex/views/browser/metadata/annotate.py +109 -0
  430. codex/views/browser/metadata/copy_intersections.py +90 -0
  431. codex/views/browser/metadata/metadata.py +83 -0
  432. codex/views/browser/metadata/query_intersections.py +112 -0
  433. codex/views/browser/mtime.py +2 -10
  434. codex/views/browser/order_by.py +22 -16
  435. codex/views/browser/page_in_bounds.py +88 -0
  436. codex/views/browser/paginate.py +32 -123
  437. codex/views/browser/params.py +64 -0
  438. codex/views/browser/title.py +1 -6
  439. codex/views/browser/validate.py +68 -33
  440. codex/views/const.py +0 -1
  441. codex/views/download.py +1 -1
  442. codex/views/mixins.py +27 -15
  443. codex/views/opds/const.py +2 -3
  444. codex/views/opds/urls.py +2 -2
  445. codex/views/opds/util.py +2 -3
  446. codex/views/opds/v1/entry/links.py +3 -1
  447. codex/views/opds/v1/facets.py +65 -12
  448. codex/views/opds/v1/feed.py +7 -65
  449. codex/views/opds/v1/links.py +5 -4
  450. codex/views/opds/v2/feed.py +2 -28
  451. codex/views/opds/v2/links.py +27 -2
  452. codex/views/opds/v2/publications.py +5 -6
  453. codex/views/opds/v2/top_links.py +3 -6
  454. codex/views/public.py +2 -2
  455. codex/views/reader/arcs.py +0 -3
  456. codex/views/reader/books.py +57 -41
  457. codex/views/reader/page.py +13 -7
  458. codex/views/reader/{init.py → params.py} +37 -31
  459. codex/views/reader/reader.py +1 -2
  460. codex/views/session.py +43 -54
  461. codex/views/timezone.py +54 -0
  462. codex/views/version.py +1 -1
  463. {codex-1.6.19.dist-info → codex-1.7.0.dist-info}/METADATA +15 -10
  464. {codex-1.6.19.dist-info → codex-1.7.0.dist-info}/RECORD +467 -484
  465. codex/_vendor/__init__.py +0 -0
  466. codex/_vendor/django_haystack-3.2.1.dist-info/AUTHORS +0 -127
  467. codex/_vendor/django_haystack-3.2.1.dist-info/INSTALLER +0 -1
  468. codex/_vendor/django_haystack-3.2.1.dist-info/LICENSE +0 -31
  469. codex/_vendor/django_haystack-3.2.1.dist-info/METADATA +0 -98
  470. codex/_vendor/django_haystack-3.2.1.dist-info/RECORD +0 -97
  471. codex/_vendor/django_haystack-3.2.1.dist-info/REQUESTED +0 -0
  472. codex/_vendor/django_haystack-3.2.1.dist-info/WHEEL +0 -5
  473. codex/_vendor/django_haystack-3.2.1.dist-info/top_level.txt +0 -1
  474. codex/_vendor/haystack/__init__.py +0 -80
  475. codex/_vendor/haystack/admin.py +0 -163
  476. codex/_vendor/haystack/apps.py +0 -31
  477. codex/_vendor/haystack/backends/__init__.py +0 -1109
  478. codex/_vendor/haystack/backends/elasticsearch2_backend.py +0 -390
  479. codex/_vendor/haystack/backends/elasticsearch5_backend.py +0 -483
  480. codex/_vendor/haystack/backends/elasticsearch7_backend.py +0 -586
  481. codex/_vendor/haystack/backends/elasticsearch_backend.py +0 -1141
  482. codex/_vendor/haystack/backends/simple_backend.py +0 -132
  483. codex/_vendor/haystack/backends/solr_backend.py +0 -991
  484. codex/_vendor/haystack/backends/whoosh_backend.py +0 -1104
  485. codex/_vendor/haystack/constants.py +0 -57
  486. codex/_vendor/haystack/exceptions.py +0 -57
  487. codex/_vendor/haystack/fields.py +0 -562
  488. codex/_vendor/haystack/forms.py +0 -135
  489. codex/_vendor/haystack/generic_views.py +0 -141
  490. codex/_vendor/haystack/indexes.py +0 -548
  491. codex/_vendor/haystack/inputs.py +0 -169
  492. codex/_vendor/haystack/management/__init__.py +0 -0
  493. codex/_vendor/haystack/management/commands/__init__.py +0 -0
  494. codex/_vendor/haystack/management/commands/build_solr_schema.py +0 -187
  495. codex/_vendor/haystack/management/commands/clear_index.py +0 -67
  496. codex/_vendor/haystack/management/commands/haystack_info.py +0 -22
  497. codex/_vendor/haystack/management/commands/rebuild_index.py +0 -65
  498. codex/_vendor/haystack/management/commands/update_index.py +0 -438
  499. codex/_vendor/haystack/manager.py +0 -105
  500. codex/_vendor/haystack/models.py +0 -257
  501. codex/_vendor/haystack/panels.py +0 -89
  502. codex/_vendor/haystack/query.py +0 -771
  503. codex/_vendor/haystack/routers.py +0 -14
  504. codex/_vendor/haystack/signals.py +0 -88
  505. codex/_vendor/haystack/templates/panels/haystack.html +0 -33
  506. codex/_vendor/haystack/templates/search_configuration/schema.xml +0 -1056
  507. codex/_vendor/haystack/templates/search_configuration/solrconfig.xml +0 -1446
  508. codex/_vendor/haystack/templatetags/__init__.py +0 -0
  509. codex/_vendor/haystack/templatetags/highlight.py +0 -131
  510. codex/_vendor/haystack/templatetags/more_like_this.py +0 -119
  511. codex/_vendor/haystack/urls.py +0 -5
  512. codex/_vendor/haystack/utils/__init__.py +0 -84
  513. codex/_vendor/haystack/utils/app_loading.py +0 -34
  514. codex/_vendor/haystack/utils/geo.py +0 -71
  515. codex/_vendor/haystack/utils/highlighting.py +0 -165
  516. codex/_vendor/haystack/utils/loading.py +0 -374
  517. codex/_vendor/haystack/utils/log.py +0 -21
  518. codex/_vendor/haystack/version.py +0 -16
  519. codex/_vendor/haystack/views.py +0 -253
  520. codex/integrity.py +0 -492
  521. codex/librarian/search/merge.py +0 -86
  522. codex/librarian/search/version.py +0 -63
  523. codex/search/__init__.py +0 -1
  524. codex/search/backend.py +0 -524
  525. codex/search/backend_search.py +0 -229
  526. codex/search/engine.py +0 -33
  527. codex/search/indexes.py +0 -79
  528. codex/search/query.py +0 -67
  529. codex/search/writing.py +0 -180
  530. codex/serializers/choices.py +0 -196
  531. codex/static_root/assets/VCheckbox-Cko1sQK-.170726b3b8a1.js +0 -1
  532. codex/static_root/assets/VCheckbox-Cko1sQK-.170726b3b8a1.js.br +0 -0
  533. codex/static_root/assets/VCheckbox-Cko1sQK-.170726b3b8a1.js.gz +0 -0
  534. codex/static_root/assets/VCheckbox-Cko1sQK-.js +0 -1
  535. codex/static_root/assets/VCheckbox-Cko1sQK-.js.br +0 -0
  536. codex/static_root/assets/VCheckbox-Cko1sQK-.js.gz +0 -0
  537. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js +0 -1
  538. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js.br +0 -0
  539. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js.gz +0 -0
  540. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.js +0 -1
  541. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.js.br +0 -0
  542. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.js.gz +0 -0
  543. codex/static_root/assets/VCombobox-Bjp6lffE.caf59fba486e.js +0 -1
  544. codex/static_root/assets/VCombobox-Bjp6lffE.caf59fba486e.js.br +0 -0
  545. codex/static_root/assets/VCombobox-Bjp6lffE.caf59fba486e.js.gz +0 -0
  546. codex/static_root/assets/VCombobox-Bjp6lffE.js +0 -1
  547. codex/static_root/assets/VCombobox-Bjp6lffE.js.br +0 -0
  548. codex/static_root/assets/VCombobox-Bjp6lffE.js.gz +0 -0
  549. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css +0 -1
  550. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.br +0 -0
  551. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.gz +0 -0
  552. codex/static_root/assets/VDialog-38np3TSA.css +0 -1
  553. codex/static_root/assets/VDialog-38np3TSA.css.br +0 -0
  554. codex/static_root/assets/VDialog-38np3TSA.css.gz +0 -0
  555. codex/static_root/assets/VDialog-BkpVGB70.6eea3ca762a5.js +0 -1
  556. codex/static_root/assets/VDialog-BkpVGB70.6eea3ca762a5.js.br +0 -0
  557. codex/static_root/assets/VDialog-BkpVGB70.6eea3ca762a5.js.gz +0 -0
  558. codex/static_root/assets/VDialog-BkpVGB70.js +0 -1
  559. codex/static_root/assets/VDialog-BkpVGB70.js.br +0 -0
  560. codex/static_root/assets/VDialog-BkpVGB70.js.gz +0 -0
  561. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js +0 -1
  562. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js.br +0 -0
  563. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js.gz +0 -0
  564. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.js +0 -1
  565. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.js.br +0 -0
  566. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.js.gz +0 -0
  567. codex/static_root/assets/VRadioGroup-D3Py5BfQ.a4f25edb86d3.js +0 -1
  568. codex/static_root/assets/VRadioGroup-D3Py5BfQ.a4f25edb86d3.js.br +0 -0
  569. codex/static_root/assets/VRadioGroup-D3Py5BfQ.a4f25edb86d3.js.gz +0 -0
  570. codex/static_root/assets/VRadioGroup-D3Py5BfQ.js +0 -1
  571. codex/static_root/assets/VRadioGroup-D3Py5BfQ.js.br +0 -0
  572. codex/static_root/assets/VRadioGroup-D3Py5BfQ.js.gz +0 -0
  573. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css +0 -1
  574. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.br +0 -0
  575. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.gz +0 -0
  576. codex/static_root/assets/VSelect-Ca2bIOso.css +0 -1
  577. codex/static_root/assets/VSelect-Ca2bIOso.css.br +0 -0
  578. codex/static_root/assets/VSelect-Ca2bIOso.css.gz +0 -0
  579. codex/static_root/assets/VSelect-DtvZsYZz.e98745d858eb.js +0 -1
  580. codex/static_root/assets/VSelect-DtvZsYZz.e98745d858eb.js.br +0 -0
  581. codex/static_root/assets/VSelect-DtvZsYZz.e98745d858eb.js.gz +0 -0
  582. codex/static_root/assets/VSelect-DtvZsYZz.js +0 -1
  583. codex/static_root/assets/VSelect-DtvZsYZz.js.br +0 -0
  584. codex/static_root/assets/VSelect-DtvZsYZz.js.gz +0 -0
  585. codex/static_root/assets/VSelectionControl-D6kmykQW.1e1fda62ceba.js +0 -1
  586. codex/static_root/assets/VSelectionControl-D6kmykQW.1e1fda62ceba.js.br +0 -0
  587. codex/static_root/assets/VSelectionControl-D6kmykQW.1e1fda62ceba.js.gz +0 -0
  588. codex/static_root/assets/VSelectionControl-D6kmykQW.js +0 -1
  589. codex/static_root/assets/VSelectionControl-D6kmykQW.js.br +0 -0
  590. codex/static_root/assets/VSelectionControl-D6kmykQW.js.gz +0 -0
  591. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css +0 -1
  592. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.br +0 -0
  593. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.gz +0 -0
  594. codex/static_root/assets/VSlideGroup-Dk_1upHt.css +0 -1
  595. codex/static_root/assets/VSlideGroup-Dk_1upHt.css.br +0 -0
  596. codex/static_root/assets/VSlideGroup-Dk_1upHt.css.gz +0 -0
  597. codex/static_root/assets/VSlideGroup-UGZWxpF5.360bdefcd215.js +0 -1
  598. codex/static_root/assets/VSlideGroup-UGZWxpF5.360bdefcd215.js.br +0 -0
  599. codex/static_root/assets/VSlideGroup-UGZWxpF5.360bdefcd215.js.gz +0 -0
  600. codex/static_root/assets/VSlideGroup-UGZWxpF5.js +0 -1
  601. codex/static_root/assets/VSlideGroup-UGZWxpF5.js.br +0 -0
  602. codex/static_root/assets/VSlideGroup-UGZWxpF5.js.gz +0 -0
  603. codex/static_root/assets/VTable-DXH_yQ0o.1149f56ad566.js +0 -1
  604. codex/static_root/assets/VTable-DXH_yQ0o.1149f56ad566.js.br +0 -0
  605. codex/static_root/assets/VTable-DXH_yQ0o.1149f56ad566.js.gz +0 -0
  606. codex/static_root/assets/VTable-DXH_yQ0o.js +0 -1
  607. codex/static_root/assets/VTable-DXH_yQ0o.js.br +0 -0
  608. codex/static_root/assets/VTable-DXH_yQ0o.js.gz +0 -0
  609. codex/static_root/assets/VTextField-Blqy56_L.26d8761e0155.js +0 -1
  610. codex/static_root/assets/VTextField-Blqy56_L.26d8761e0155.js.br +0 -0
  611. codex/static_root/assets/VTextField-Blqy56_L.26d8761e0155.js.gz +0 -0
  612. codex/static_root/assets/VTextField-Blqy56_L.js +0 -1
  613. codex/static_root/assets/VTextField-Blqy56_L.js.br +0 -0
  614. codex/static_root/assets/VTextField-Blqy56_L.js.gz +0 -0
  615. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css +0 -1
  616. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.br +0 -0
  617. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.gz +0 -0
  618. codex/static_root/assets/VTextField-Crc3gdNh.css +0 -1
  619. codex/static_root/assets/VTextField-Crc3gdNh.css.br +0 -0
  620. codex/static_root/assets/VTextField-Crc3gdNh.css.gz +0 -0
  621. codex/static_root/assets/VWindowItem-C8_ovV7e.afbc08414765.js +0 -1
  622. codex/static_root/assets/VWindowItem-C8_ovV7e.afbc08414765.js.br +0 -0
  623. codex/static_root/assets/VWindowItem-C8_ovV7e.afbc08414765.js.gz +0 -0
  624. codex/static_root/assets/VWindowItem-C8_ovV7e.js +0 -1
  625. codex/static_root/assets/VWindowItem-C8_ovV7e.js.br +0 -0
  626. codex/static_root/assets/VWindowItem-C8_ovV7e.js.gz +0 -0
  627. codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.br +0 -0
  628. codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.gz +0 -0
  629. codex/static_root/assets/admin-CWEjaFr5.css.br +0 -0
  630. codex/static_root/assets/admin-CWEjaFr5.css.gz +0 -0
  631. codex/static_root/assets/admin-DTRn8bBs.d031ea42d8d0.js +0 -1
  632. codex/static_root/assets/admin-DTRn8bBs.d031ea42d8d0.js.br +0 -0
  633. codex/static_root/assets/admin-DTRn8bBs.d031ea42d8d0.js.gz +0 -0
  634. codex/static_root/assets/admin-DTRn8bBs.js +0 -1
  635. codex/static_root/assets/admin-DTRn8bBs.js.br +0 -0
  636. codex/static_root/assets/admin-DTRn8bBs.js.gz +0 -0
  637. codex/static_root/assets/admin-drawer-panel-BaXFOcru.b1a44b05f482.js +0 -30
  638. codex/static_root/assets/admin-drawer-panel-BaXFOcru.b1a44b05f482.js.br +0 -0
  639. codex/static_root/assets/admin-drawer-panel-BaXFOcru.b1a44b05f482.js.gz +0 -0
  640. codex/static_root/assets/admin-drawer-panel-BaXFOcru.js +0 -30
  641. codex/static_root/assets/admin-drawer-panel-BaXFOcru.js.br +0 -0
  642. codex/static_root/assets/admin-drawer-panel-BaXFOcru.js.gz +0 -0
  643. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css +0 -1
  644. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css.br +0 -0
  645. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css.gz +0 -0
  646. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css +0 -1
  647. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css.br +0 -0
  648. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css.gz +0 -0
  649. codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js +0 -1
  650. codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js.br +0 -0
  651. codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js.gz +0 -0
  652. codex/static_root/assets/browser-BBpUyGmz.js +0 -1
  653. codex/static_root/assets/browser-BBpUyGmz.js.br +0 -0
  654. codex/static_root/assets/browser-BBpUyGmz.js.gz +0 -0
  655. codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css +0 -1
  656. codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css.br +0 -0
  657. codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css.gz +0 -0
  658. codex/static_root/assets/browser-Binc3n9H.css +0 -1
  659. codex/static_root/assets/browser-Binc3n9H.css.br +0 -0
  660. codex/static_root/assets/browser-Binc3n9H.css.gz +0 -0
  661. codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css +0 -1
  662. codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css.br +0 -0
  663. codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css.gz +0 -0
  664. codex/static_root/assets/change-password-dialog-Cebek1-c.css +0 -1
  665. codex/static_root/assets/change-password-dialog-Cebek1-c.css.br +0 -0
  666. codex/static_root/assets/change-password-dialog-Cebek1-c.css.gz +0 -0
  667. codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js +0 -1
  668. codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js.br +0 -0
  669. codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js.gz +0 -0
  670. codex/static_root/assets/change-password-dialog-DlHoLhDF.js +0 -1
  671. codex/static_root/assets/change-password-dialog-DlHoLhDF.js.br +0 -0
  672. codex/static_root/assets/change-password-dialog-DlHoLhDF.js.gz +0 -0
  673. codex/static_root/assets/confirm-dialog-BmhedLCx.7c2103d319d4.css +0 -1
  674. codex/static_root/assets/confirm-dialog-BmhedLCx.css +0 -1
  675. codex/static_root/assets/confirm-dialog-D3_s2DQy.9dde66036c72.js +0 -1
  676. codex/static_root/assets/confirm-dialog-D3_s2DQy.9dde66036c72.js.br +0 -0
  677. codex/static_root/assets/confirm-dialog-D3_s2DQy.9dde66036c72.js.gz +0 -0
  678. codex/static_root/assets/confirm-dialog-D3_s2DQy.js +0 -1
  679. codex/static_root/assets/confirm-dialog-D3_s2DQy.js.br +0 -0
  680. codex/static_root/assets/confirm-dialog-D3_s2DQy.js.gz +0 -0
  681. codex/static_root/assets/datetime-column-BxC1Li9e.3dc314b3295d.js +0 -1
  682. codex/static_root/assets/datetime-column-BxC1Li9e.3dc314b3295d.js.br +0 -0
  683. codex/static_root/assets/datetime-column-BxC1Li9e.3dc314b3295d.js.gz +0 -0
  684. codex/static_root/assets/datetime-column-BxC1Li9e.js +0 -1
  685. codex/static_root/assets/datetime-column-BxC1Li9e.js.br +0 -0
  686. codex/static_root/assets/datetime-column-BxC1Li9e.js.gz +0 -0
  687. codex/static_root/assets/filter-Bzk7x841.d0c3b602e62d.js +0 -1
  688. codex/static_root/assets/filter-Bzk7x841.d0c3b602e62d.js.br +0 -0
  689. codex/static_root/assets/filter-Bzk7x841.d0c3b602e62d.js.gz +0 -0
  690. codex/static_root/assets/filter-Bzk7x841.js +0 -1
  691. codex/static_root/assets/filter-Bzk7x841.js.br +0 -0
  692. codex/static_root/assets/filter-Bzk7x841.js.gz +0 -0
  693. codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js +0 -1
  694. codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js.br +0 -0
  695. codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js.gz +0 -0
  696. codex/static_root/assets/flag-tab-C2bI5zq3.js +0 -1
  697. codex/static_root/assets/flag-tab-C2bI5zq3.js.br +0 -0
  698. codex/static_root/assets/flag-tab-C2bI5zq3.js.gz +0 -0
  699. codex/static_root/assets/flag-tab-DBqpLKi7.css +0 -1
  700. codex/static_root/assets/flag-tab-DBqpLKi7.css.br +0 -0
  701. codex/static_root/assets/flag-tab-DBqpLKi7.css.gz +0 -0
  702. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css +0 -1
  703. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.br +0 -0
  704. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.gz +0 -0
  705. codex/static_root/assets/group-tab-5esH4lwX.a81fdd258117.js +0 -1
  706. codex/static_root/assets/group-tab-5esH4lwX.a81fdd258117.js.br +0 -0
  707. codex/static_root/assets/group-tab-5esH4lwX.a81fdd258117.js.gz +0 -0
  708. codex/static_root/assets/group-tab-5esH4lwX.js +0 -1
  709. codex/static_root/assets/group-tab-5esH4lwX.js.br +0 -0
  710. codex/static_root/assets/group-tab-5esH4lwX.js.gz +0 -0
  711. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css +0 -1
  712. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.br +0 -0
  713. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.gz +0 -0
  714. codex/static_root/assets/group-tab-CBKuS3Iv.css +0 -1
  715. codex/static_root/assets/group-tab-CBKuS3Iv.css.br +0 -0
  716. codex/static_root/assets/group-tab-CBKuS3Iv.css.gz +0 -0
  717. codex/static_root/assets/http-error-BTOBfcGY.52ced6f28420.js +0 -1
  718. codex/static_root/assets/http-error-BTOBfcGY.52ced6f28420.js.br +0 -0
  719. codex/static_root/assets/http-error-BTOBfcGY.52ced6f28420.js.gz +0 -0
  720. codex/static_root/assets/http-error-BTOBfcGY.js +0 -1
  721. codex/static_root/assets/http-error-BTOBfcGY.js.br +0 -0
  722. codex/static_root/assets/http-error-BTOBfcGY.js.gz +0 -0
  723. codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.br +0 -2
  724. codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.gz +0 -0
  725. codex/static_root/assets/library-tab-Bh7ErAk7.css.br +0 -2
  726. codex/static_root/assets/library-tab-Bh7ErAk7.css.gz +0 -0
  727. codex/static_root/assets/library-tab-DiPEdOF7.ece2d642a9dc.js +0 -1
  728. codex/static_root/assets/library-tab-DiPEdOF7.ece2d642a9dc.js.br +0 -0
  729. codex/static_root/assets/library-tab-DiPEdOF7.ece2d642a9dc.js.gz +0 -0
  730. codex/static_root/assets/library-tab-DiPEdOF7.js +0 -1
  731. codex/static_root/assets/library-tab-DiPEdOF7.js.br +0 -0
  732. codex/static_root/assets/library-tab-DiPEdOF7.js.gz +0 -0
  733. codex/static_root/assets/main-BPIPjzsc.66def8991e38.js +0 -6
  734. codex/static_root/assets/main-BPIPjzsc.66def8991e38.js.br +0 -0
  735. codex/static_root/assets/main-BPIPjzsc.66def8991e38.js.gz +0 -0
  736. codex/static_root/assets/main-BPIPjzsc.js +0 -6
  737. codex/static_root/assets/main-BPIPjzsc.js.br +0 -0
  738. codex/static_root/assets/main-BPIPjzsc.js.gz +0 -0
  739. codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js +0 -1
  740. codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js.br +0 -0
  741. codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js.gz +0 -0
  742. codex/static_root/assets/pager-full-pdf-CiyC6Al9.js +0 -1
  743. codex/static_root/assets/pager-full-pdf-CiyC6Al9.js.br +0 -0
  744. codex/static_root/assets/pager-full-pdf-CiyC6Al9.js.gz +0 -0
  745. codex/static_root/assets/pagination-toolbar-C45-onwe.4722195bb60b.css.br +0 -0
  746. codex/static_root/assets/pagination-toolbar-C45-onwe.4722195bb60b.css.gz +0 -0
  747. codex/static_root/assets/pagination-toolbar-C45-onwe.css.br +0 -0
  748. codex/static_root/assets/pagination-toolbar-C45-onwe.css.gz +0 -0
  749. codex/static_root/assets/pagination-toolbar-CkIzuyx1.00c354a82e6e.js +0 -1
  750. codex/static_root/assets/pagination-toolbar-CkIzuyx1.00c354a82e6e.js.br +0 -0
  751. codex/static_root/assets/pagination-toolbar-CkIzuyx1.00c354a82e6e.js.gz +0 -0
  752. codex/static_root/assets/pagination-toolbar-CkIzuyx1.js +0 -1
  753. codex/static_root/assets/pagination-toolbar-CkIzuyx1.js.br +0 -0
  754. codex/static_root/assets/pagination-toolbar-CkIzuyx1.js.gz +0 -0
  755. codex/static_root/assets/pdf-doc-BjlRPuf4.0f056fa321b6.js.br +0 -0
  756. codex/static_root/assets/pdf-doc-BjlRPuf4.0f056fa321b6.js.gz +0 -0
  757. codex/static_root/assets/pdf-doc-BjlRPuf4.js.br +0 -0
  758. codex/static_root/assets/pdf-doc-BjlRPuf4.js.gz +0 -0
  759. codex/static_root/assets/reader-_stAWL-4.5089e9144795.css +0 -1
  760. codex/static_root/assets/reader-_stAWL-4.5089e9144795.css.br +0 -0
  761. codex/static_root/assets/reader-_stAWL-4.5089e9144795.css.gz +0 -0
  762. codex/static_root/assets/reader-_stAWL-4.css +0 -1
  763. codex/static_root/assets/reader-_stAWL-4.css.br +0 -0
  764. codex/static_root/assets/reader-_stAWL-4.css.gz +0 -0
  765. codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js +0 -2
  766. codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js.br +0 -0
  767. codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js.gz +0 -0
  768. codex/static_root/assets/reader-ucxnLi2K.js +0 -2
  769. codex/static_root/assets/reader-ucxnLi2K.js.br +0 -0
  770. codex/static_root/assets/reader-ucxnLi2K.js.gz +0 -0
  771. codex/static_root/assets/relation-chips-CUSatZET.a58031ff8141.js +0 -1
  772. codex/static_root/assets/relation-chips-CUSatZET.a58031ff8141.js.br +0 -0
  773. codex/static_root/assets/relation-chips-CUSatZET.a58031ff8141.js.gz +0 -0
  774. codex/static_root/assets/relation-chips-CUSatZET.js +0 -1
  775. codex/static_root/assets/relation-chips-CUSatZET.js.br +0 -0
  776. codex/static_root/assets/relation-chips-CUSatZET.js.gz +0 -0
  777. codex/static_root/assets/settings-drawer-BSHTAsJ9.1d07ce084fc9.js +0 -2
  778. codex/static_root/assets/settings-drawer-BSHTAsJ9.1d07ce084fc9.js.br +0 -0
  779. codex/static_root/assets/settings-drawer-BSHTAsJ9.1d07ce084fc9.js.gz +0 -0
  780. codex/static_root/assets/settings-drawer-BSHTAsJ9.js +0 -2
  781. codex/static_root/assets/settings-drawer-BSHTAsJ9.js.br +0 -0
  782. codex/static_root/assets/settings-drawer-BSHTAsJ9.js.gz +0 -0
  783. codex/static_root/assets/stats-tab-BXGisn5N.9b7a71e7fe28.css.br +0 -0
  784. codex/static_root/assets/stats-tab-BXGisn5N.9b7a71e7fe28.css.gz +0 -0
  785. codex/static_root/assets/stats-tab-BXGisn5N.css.br +0 -0
  786. codex/static_root/assets/stats-tab-BXGisn5N.css.gz +0 -0
  787. codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js +0 -1
  788. codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js.br +0 -0
  789. codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js.gz +0 -0
  790. codex/static_root/assets/stats-tab-DKXVB2Cc.js +0 -1
  791. codex/static_root/assets/stats-tab-DKXVB2Cc.js.br +0 -0
  792. codex/static_root/assets/stats-tab-DKXVB2Cc.js.gz +0 -0
  793. codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css +0 -1
  794. codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css.gz +0 -0
  795. codex/static_root/assets/task-tab-1XiWn9xP.css +0 -1
  796. codex/static_root/assets/task-tab-1XiWn9xP.css.gz +0 -0
  797. codex/static_root/assets/task-tab-NORFAa9p.97e07e366ddd.js +0 -1
  798. codex/static_root/assets/task-tab-NORFAa9p.97e07e366ddd.js.br +0 -0
  799. codex/static_root/assets/task-tab-NORFAa9p.97e07e366ddd.js.gz +0 -0
  800. codex/static_root/assets/task-tab-NORFAa9p.js +0 -1
  801. codex/static_root/assets/task-tab-NORFAa9p.js.br +0 -0
  802. codex/static_root/assets/task-tab-NORFAa9p.js.gz +0 -0
  803. codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js +0 -1
  804. codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js.br +0 -0
  805. codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js.gz +0 -0
  806. codex/static_root/assets/unauthorized-RHaQZRfr.js +0 -1
  807. codex/static_root/assets/unauthorized-RHaQZRfr.js.br +0 -0
  808. codex/static_root/assets/unauthorized-RHaQZRfr.js.gz +0 -0
  809. codex/static_root/assets/unauthorized-muDsv-rC.2166ec8b3a32.css.br +0 -0
  810. codex/static_root/assets/unauthorized-muDsv-rC.2166ec8b3a32.css.gz +0 -0
  811. codex/static_root/assets/unauthorized-muDsv-rC.css.br +0 -0
  812. codex/static_root/assets/unauthorized-muDsv-rC.css.gz +0 -0
  813. codex/static_root/assets/user-tab-CHbyN1EW.e7206db08680.js +0 -1
  814. codex/static_root/assets/user-tab-CHbyN1EW.e7206db08680.js.br +0 -0
  815. codex/static_root/assets/user-tab-CHbyN1EW.e7206db08680.js.gz +0 -0
  816. codex/static_root/assets/user-tab-CHbyN1EW.js +0 -1
  817. codex/static_root/assets/user-tab-CHbyN1EW.js.br +0 -0
  818. codex/static_root/assets/user-tab-CHbyN1EW.js.gz +0 -0
  819. codex/static_root/js/choices-admin.1a20a5648f20.json +0 -1
  820. codex/static_root/js/choices-admin.1a20a5648f20.json.br +0 -0
  821. codex/static_root/js/choices-admin.1a20a5648f20.json.gz +0 -0
  822. codex/static_root/js/choices-admin.json +0 -1
  823. codex/static_root/js/choices-admin.json.br +0 -0
  824. codex/static_root/js/choices-admin.json.gz +0 -0
  825. codex/static_root/js/choices.2f6b0359e1ef.json +0 -1
  826. codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
  827. codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
  828. codex/static_root/js/choices.json +0 -1
  829. codex/static_root/js/choices.json.br +0 -0
  830. codex/static_root/js/choices.json.gz +0 -0
  831. codex/static_root/manifest.0fe31a6cb99f.json +0 -635
  832. codex/static_root/manifest.0fe31a6cb99f.json.br +0 -0
  833. codex/static_root/manifest.0fe31a6cb99f.json.gz +0 -0
  834. codex/templates/search/indexes/codex/comic_text.txt +0 -47
  835. codex/views/browser/annotations.py +0 -296
  836. codex/views/browser/base.py +0 -140
  837. codex/views/browser/filters/annotations.py +0 -103
  838. codex/views/browser/filters/search.py +0 -196
  839. codex/views/browser/metadata.py +0 -332
  840. {codex-1.6.19.dist-info → codex-1.7.0.dist-info}/LICENSE +0 -0
  841. {codex-1.6.19.dist-info → codex-1.7.0.dist-info}/WHEEL +0 -0
  842. {codex-1.6.19.dist-info → codex-1.7.0.dist-info}/entry_points.txt +0 -0
codex/views/bookmark.py CHANGED
@@ -1,180 +1,41 @@
1
1
  """Bookmark views."""
2
2
 
3
- from django.db.models.expressions import F
4
- from django.db.models.functions import Now
5
3
  from drf_spectacular.utils import extend_schema
6
4
  from rest_framework.response import Response
7
5
 
8
- from codex.librarian.mp_queue import LIBRARIAN_QUEUE
9
- from codex.librarian.notifier.tasks import NotifierTask
6
+ from codex.librarian.bookmark.update import BookmarkUpdate
10
7
  from codex.logger.logging import get_logger
11
- from codex.models import Bookmark, Comic
12
8
  from codex.serializers.models.bookmark import (
13
9
  BookmarkFinishedSerializer,
14
10
  BookmarkSerializer,
15
11
  )
16
12
  from codex.views.auth import (
13
+ AuthFilterAPIView,
17
14
  AuthFilterGenericAPIView,
18
15
  )
19
16
  from codex.views.const import FILTER_ONLY_GROUP_RELATION
20
17
 
21
18
  LOG = get_logger(__name__)
22
- VERTICAL_READING_DIRECTIONS = frozenset({"ttb", "btt"})
23
- _BOOKMARK_UPDATE_FIELDS = frozenset(
24
- {
25
- "page",
26
- "finished",
27
- "fit_to",
28
- "two_pages",
29
- "reading_direction",
30
- }
31
- )
32
- _COMIC_ONLY_FIELDS = ("pk", "page_count")
33
-
34
-
35
- class BookmarkFilterBaseView(AuthFilterGenericAPIView):
36
- """API Views that get Bookmarks."""
37
19
 
38
- def get_bookmark_search_kwargs(self, comic_filter=None):
39
- """Get the search kwargs for a user's authentication state."""
40
- search_kwargs = {}
41
20
 
42
- if comic_filter:
43
- for key, value in comic_filter.items():
44
- search_kwargs[f"comic__{key}"] = value
21
+ class BookmarkBaseView(AuthFilterAPIView):
22
+ """Base class for Bookmark Views."""
45
23
 
24
+ def get_bookmark_auth_filter(self):
25
+ """Filter only the user's bookmarks."""
46
26
  if self.request.user.is_authenticated:
47
- search_kwargs["user"] = self.request.user
27
+ key = "user_id"
28
+ value = self.request.user.pk
48
29
  else:
49
30
  if not self.request.session or not self.request.session.session_key:
50
31
  LOG.debug("no session, make one")
51
32
  self.request.session.save()
52
- search_kwargs["session_id"] = self.request.session.session_key
53
- return search_kwargs
54
-
55
-
56
- class BookmarkBaseView(BookmarkFilterBaseView):
57
- """Bookmark Updater."""
58
-
59
- @staticmethod
60
- def _update_bookmarks_validate_page(bm, updates):
61
- """Force bookmark page into valid range."""
62
- page = updates.get("page")
63
- if page is None:
64
- return
65
- max_page = bm.page_count + 1
66
- page = max(min(page, max_page), 0)
67
- if page == max_page:
68
- # Auto finish on bookmark last page
69
- bm.finished = True
70
- updates["page"] = page
71
-
72
- @staticmethod
73
- def _update_bookmarks_validate_two_pages(bm, updates):
74
- """Force vertical view to not use two pages."""
75
- rd = updates.get("reading_direction")
76
- if (
77
- bm.two_pages
78
- and rd in VERTICAL_READING_DIRECTIONS
79
- or bm.reading_direction in VERTICAL_READING_DIRECTIONS
80
- ):
81
- updates["two_pages"] = None
82
-
83
- def notify_library_changed(self):
84
- """Notify one user that their library changed."""
85
- if user := self.request.user:
86
- uid = user.id # type: ignore
87
- else:
88
- uid = self.request.session.session_key
89
- group = f"user_{uid}"
90
- task = NotifierTask("LIBRARY_CHANGED", group)
91
- LIBRARIAN_QUEUE.put(task)
33
+ key = "session_id"
34
+ value = self.request.session.session_key
35
+ return {key: value}
92
36
 
93
- def _update_bookmarks(self, search_kwargs, updates):
94
- """Update existing bookmarks."""
95
- count = 0
96
- finished = False
97
- if not updates:
98
- return count, finished
99
- group_acl_filter = self.get_group_acl_filter(Bookmark)
100
- update_fields = set(updates.keys()) & _BOOKMARK_UPDATE_FIELDS
101
- update_fields.add("updated_at")
102
- only_fields = (*update_fields, "pk")
103
- existing_bookmarks = Bookmark.objects.filter(group_acl_filter).filter(
104
- **search_kwargs
105
- )
106
- if updates.get("page") is not None:
107
- existing_bookmarks = existing_bookmarks.annotate(
108
- page_count=F("comic__page_count")
109
- )
110
- existing_bookmarks = existing_bookmarks.only(*only_fields)
111
- update_bookmarks = []
112
- for bm in existing_bookmarks:
113
- self._update_bookmarks_validate_page(bm, updates)
114
- self._update_bookmarks_validate_two_pages(bm, updates)
115
- for key, value in updates.items():
116
- setattr(bm, key, value)
117
- bm.updated_at = Now()
118
- update_bookmarks.append(bm)
119
- count = len(update_bookmarks)
120
- if count:
121
- Bookmark.objects.bulk_update(update_bookmarks, tuple(update_fields))
122
- return count
123
37
 
124
- @staticmethod
125
- def _create_bookmarks_validate_two_pages(updates):
126
- """Force vertical view to not use two pages."""
127
- if (
128
- updates.get("two_pages")
129
- and updates.get("reading_direction") in VERTICAL_READING_DIRECTIONS
130
- ):
131
- updates.pop("two_pages", None)
132
-
133
- def _create_bookmarks(self, comic_filter, search_kwargs, updates):
134
- """Create new bookmarks for comics that don't exist yet."""
135
- count = 0
136
- self._create_bookmarks_validate_two_pages(updates)
137
- if not updates:
138
- return count
139
- create_bookmarks = []
140
- group_acl_filter = self.get_group_acl_filter(Comic)
141
- exclude = {}
142
- for key, value in search_kwargs.items():
143
- exclude["bookmark__" + key] = value
144
- create_bookmark_comics = (
145
- Comic.objects.filter(group_acl_filter)
146
- .filter(**comic_filter)
147
- .exclude(**exclude)
148
- .only(*_COMIC_ONLY_FIELDS)
149
- )
150
- for comic in create_bookmark_comics:
151
- defaults = {"comic": comic}
152
- defaults.update(updates)
153
- for key, value in search_kwargs.items():
154
- if not key.startswith("comic"):
155
- defaults[key] = value
156
-
157
- bm = Bookmark(**defaults)
158
- create_bookmarks.append(bm)
159
- count = len(create_bookmarks)
160
- if count:
161
- Bookmark.objects.bulk_create(
162
- create_bookmarks,
163
- update_fields=tuple(_BOOKMARK_UPDATE_FIELDS),
164
- unique_fields=Bookmark._meta.unique_together[0], # type: ignore
165
- )
166
- return count
167
-
168
- def update_bookmarks(self, updates, comic_filter):
169
- """Update a user bookmark."""
170
- search_kwargs = self.get_bookmark_search_kwargs(comic_filter)
171
- count = self._update_bookmarks(search_kwargs, updates)
172
- count = +self._create_bookmarks(comic_filter, search_kwargs, updates)
173
- if count:
174
- self.notify_library_changed()
175
-
176
-
177
- class BookmarkView(BookmarkBaseView):
38
+ class BookmarkView(AuthFilterGenericAPIView, BookmarkBaseView, BookmarkUpdate):
178
39
  """User Bookmark View."""
179
40
 
180
41
  serializer_class = BookmarkSerializer
@@ -198,10 +59,12 @@ class BookmarkView(BookmarkBaseView):
198
59
  """Update bookmarks recursively."""
199
60
  updates = self._parse_params()
200
61
 
62
+ auth_filter = self.get_bookmark_auth_filter()
63
+
201
64
  group = self.kwargs.get("group")
202
- pks = self.kwargs.get("pks")
203
65
  rel = FILTER_ONLY_GROUP_RELATION[group] + "__in"
66
+ pks = self.kwargs.get("pks")
204
67
  comic_filter = {rel: pks}
205
68
 
206
- self.update_bookmarks(updates, comic_filter)
69
+ self.update_bookmarks(auth_filter, comic_filter, updates)
207
70
  return Response()
@@ -0,0 +1 @@
1
+ """Browser annotation methods."""
@@ -0,0 +1,112 @@
1
+ """Base view for metadata annotations."""
2
+
3
+ from django.db.models import (
4
+ Case,
5
+ F,
6
+ Sum,
7
+ Value,
8
+ When,
9
+ )
10
+ from django.db.models.fields import BooleanField, PositiveSmallIntegerField
11
+ from django.db.models.functions import Least
12
+ from django.db.models.functions.comparison import Coalesce
13
+
14
+ from codex.logger.logging import get_logger
15
+ from codex.models import (
16
+ Comic,
17
+ )
18
+ from codex.models.functions import JsonGroupArray
19
+ from codex.views.browser.annotate.order import BrowserAnnotateOrderView
20
+
21
+ LOG = get_logger(__name__)
22
+
23
+
24
+ class BrowserAnnotateBookmarkView(BrowserAnnotateOrderView):
25
+ """Base class for views that need special metadata annotations."""
26
+
27
+ def _get_group_bookmark_page_annotation(
28
+ self, qs, bm_rel, bm_filter, page_rel, finished_rel
29
+ ):
30
+ """Get bookmark page subquery."""
31
+ finished_filter = {finished_rel: True}
32
+ prefix = "" if qs.model is Comic else self.rel_prefix
33
+ page_count = prefix + "page_count"
34
+ # Can't use a filtered relation for page & finished because of this
35
+ # page_count case.
36
+ bookmark_page_case = Case(
37
+ When(**{bm_rel: None}, then=0),
38
+ When(**finished_filter, then=page_count),
39
+ default=page_rel,
40
+ output_field=PositiveSmallIntegerField(),
41
+ )
42
+ return Sum(
43
+ bookmark_page_case,
44
+ default=0,
45
+ filter=bm_filter,
46
+ output_field=PositiveSmallIntegerField(),
47
+ distinct=True,
48
+ )
49
+
50
+ @classmethod
51
+ def _get_group_bookmark_finished_annotation(cls, qs, bm_filter, finished_rel):
52
+ """Get finished_count subquery."""
53
+ finished_count = Sum(
54
+ finished_rel,
55
+ default=0,
56
+ filter=bm_filter,
57
+ output_field=PositiveSmallIntegerField(),
58
+ # distinct breaks this sum and only returns one. idk why.
59
+ )
60
+ qs = qs.alias(finished_count=finished_count)
61
+
62
+ finished_aggregate = Case(
63
+ When(finished_count=F("child_count"), then=True),
64
+ When(finished_count=0, then=False),
65
+ default=None,
66
+ output_field=BooleanField(),
67
+ )
68
+ return qs, finished_aggregate
69
+
70
+ def annotate_bookmarks(self, qs):
71
+ """Hoist up bookmark annotations."""
72
+ bm_rel = self._get_bm_rel(qs.model)
73
+ bm_filter = self._get_my_bookmark_filter(bm_rel)
74
+ page_rel = f"{bm_rel}__page"
75
+ finished_rel = f"{bm_rel}__finished"
76
+
77
+ if qs.model is Comic:
78
+ bookmark_page = Sum(page_rel, filter=bm_filter, default=0)
79
+ finished_aggregate = Sum(finished_rel, filter=bm_filter, default=False)
80
+ else:
81
+ bookmark_page = self._get_group_bookmark_page_annotation(
82
+ qs, bm_rel, bm_filter, page_rel, finished_rel
83
+ )
84
+ qs, finished_aggregate = self._get_group_bookmark_finished_annotation(
85
+ qs, bm_filter, finished_rel
86
+ )
87
+
88
+ if (
89
+ (self.TARGET == "browser" and qs.model is Comic)
90
+ or self.is_opds_acquisition
91
+ or self.TARGET == "metadata"
92
+ ):
93
+ qs = qs.annotate(page=bookmark_page)
94
+ else:
95
+ qs = qs.alias(page=bookmark_page)
96
+
97
+ qs = qs.annotate(finished=finished_aggregate)
98
+
99
+ if not self.bmua_is_max:
100
+ mbmua = self.get_max_bookmark_updated_at_aggregate(qs.model, JsonGroupArray)
101
+ qs = qs.annotate(bookmark_updated_ats=mbmua)
102
+ return qs
103
+
104
+ def annotate_progress(self, qs):
105
+ """Compute progress for each member of a qs."""
106
+ # Requires bookmark and annotation hoisted from bookmarks.
107
+ # Requires page_count native to comic or aggregated
108
+ # Page counts can be null with metadata turned off.
109
+ # Least guard is for rare instances when bookmarks are set to
110
+ # invalid high values
111
+ progress = Least(Coalesce(F("page"), 0) * 100.0 / F("page_count"), Value(100.0))
112
+ return qs.annotate(progress=progress)
@@ -0,0 +1,61 @@
1
+ """Base view for metadata annotations."""
2
+
3
+ from types import MappingProxyType
4
+
5
+ from django.db.models import (
6
+ Value,
7
+ )
8
+ from django.db.models.aggregates import Count
9
+ from django.db.models.fields import CharField
10
+
11
+ from codex.logger.logging import get_logger
12
+ from codex.models.comic import Comic
13
+ from codex.models.functions import JsonGroupArray
14
+ from codex.models.groups import BrowserGroupModel, Imprint, Publisher, Series, Volume
15
+ from codex.views.browser.annotate.bookmark import BrowserAnnotateBookmarkView
16
+
17
+ _GROUP_BY: MappingProxyType[type[BrowserGroupModel], str] = MappingProxyType(
18
+ {Publisher: "sort_name", Imprint: "sort_name", Series: "sort_name", Volume: "name"}
19
+ )
20
+ LOG = get_logger(__name__)
21
+
22
+
23
+ class BrowserAnnotateCardView(BrowserAnnotateBookmarkView):
24
+ """Base class for views that need special metadata annotations."""
25
+
26
+ def add_group_by(self, qs):
27
+ """Get the group by for the model."""
28
+ if group_by := _GROUP_BY.get(qs.model): # type: ignore
29
+ qs = qs.group_by(group_by)
30
+ return qs
31
+
32
+ def _annotate_child_count(self, qs):
33
+ """Annotate child chount for card."""
34
+ if qs.model is Comic:
35
+ return qs
36
+ rel = self.rel_prefix + "pk"
37
+ count_func = Count(rel, distinct=True)
38
+ ann = {"child_count": count_func}
39
+ if self.TARGET == "opds2":
40
+ if qs.model is not Comic:
41
+ qs = qs.alias(**ann)
42
+ else:
43
+ qs = qs.annotate(**ann)
44
+ return qs
45
+
46
+ def _annotate_group(self, qs):
47
+ """Annotate Group."""
48
+ value = "c" if qs.model is Comic else self.model_group # type: ignore
49
+ return qs.annotate(group=Value(value, CharField(max_length=1)))
50
+
51
+ def annotate_card_aggregates(self, qs):
52
+ """Annotate aggregates that appear the browser card."""
53
+ if qs.model is Comic:
54
+ # comic adds order_value for cards late
55
+ qs = self.annotate_order_value(qs)
56
+ qs = self._annotate_group(qs)
57
+ qs = self.annotate_group_names(qs)
58
+ qs = self._annotate_child_count(qs)
59
+ qs = self.annotate_bookmarks(qs)
60
+ qs = self.annotate_progress(qs)
61
+ return qs.annotate(updated_ats=JsonGroupArray("updated_at", distinct=True))
@@ -0,0 +1,247 @@
1
+ """Base view for metadata annotations."""
2
+
3
+ from os import sep
4
+ from types import MappingProxyType
5
+
6
+ from django.db.models import (
7
+ F,
8
+ FilteredRelation,
9
+ Q,
10
+ Value,
11
+ )
12
+ from django.db.models.aggregates import Avg, Max, Min, Sum
13
+ from django.db.models.fields import CharField
14
+ from django.db.models.functions import Reverse, Right, StrIndex
15
+
16
+ from codex.logger.logging import get_logger
17
+ from codex.models import (
18
+ Comic,
19
+ Folder,
20
+ StoryArc,
21
+ )
22
+ from codex.models.functions import ComicFTSRank, JsonGroupArray
23
+ from codex.views.browser.order_by import (
24
+ BrowserOrderByView,
25
+ )
26
+ from codex.views.const import (
27
+ NONE_INTEGERFIELD,
28
+ STORY_ARC_GROUP,
29
+ )
30
+ from codex.views.mixins import SharedAnnotationsMixin
31
+
32
+ _ORDER_AGGREGATE_FUNCS = MappingProxyType(
33
+ # These are annotated to order_value because they're simple relations
34
+ {
35
+ "age_rating": Avg,
36
+ "community_rating": Avg,
37
+ "created_at": Min,
38
+ "critical_rating": Avg,
39
+ "date": Min,
40
+ "page_count": Sum,
41
+ "size": Sum,
42
+ "updated_at": Min,
43
+ }
44
+ )
45
+ _ANNOTATED_ORDER_FIELDS = frozenset(
46
+ # These are annotated with their own functions
47
+ {
48
+ "filename",
49
+ "sort_name",
50
+ "search_score",
51
+ "bookmark_updated_at",
52
+ "story_arc_number",
53
+ }
54
+ )
55
+
56
+ LOG = get_logger(__name__)
57
+
58
+
59
+ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
60
+ """Base class for views that need special metadata annotations."""
61
+
62
+ CARD_TARGETS = frozenset({"browser", "metadata"})
63
+ _OPDS_TARGETS = frozenset({"opds1", "opds2"})
64
+ _PAGE_COUNT_TARGETS = frozenset(CARD_TARGETS | _OPDS_TARGETS)
65
+ _COVER_AND_CARD_TARGETS = frozenset(CARD_TARGETS | {"cover"})
66
+
67
+ def __init__(self, *args, **kwargs):
68
+ """Set params for the type checker."""
69
+ super().__init__(*args, **kwargs)
70
+ self._order_agg_func: type[Min | Max] | None = None
71
+ self._is_opds_acquisition: bool | None = None
72
+ self._opds_acquisition_groups: frozenset[str] | None = None
73
+ self.bmua_is_max = False
74
+
75
+ @property
76
+ def opds_acquisition_groups(self):
77
+ """Memoize the opds acquisition groups."""
78
+ if self._opds_acquisition_groups is None:
79
+ groups = {"a", "f", "c"}
80
+ groups |= {*self.valid_nav_groups[-2:]}
81
+ self._opds_acquisition_groups = frozenset(groups)
82
+ return self._opds_acquisition_groups
83
+
84
+ @property
85
+ def is_opds_acquisition(self):
86
+ """Memoize if we're in an opds acquisition view."""
87
+ if self._is_opds_acquisition is None:
88
+ is_opds_acquisition = self.TARGET in self._OPDS_TARGETS
89
+ if is_opds_acquisition:
90
+ group = self.kwargs.get("group")
91
+ is_opds_acquisition &= group in self.opds_acquisition_groups
92
+ if is_opds_acquisition and group == "a":
93
+ pks = self.kwargs["pks"]
94
+ is_opds_acquisition &= bool(pks and 0 not in pks)
95
+ self._is_opds_acquisition = is_opds_acquisition
96
+ return self._is_opds_acquisition
97
+
98
+ @property
99
+ def order_agg_func(self):
100
+ """Get the order aggregate function."""
101
+ if self._order_agg_func is None:
102
+ order_reverse = self.params.get("order_reverse")
103
+ self._order_agg_func = Max if order_reverse else Min
104
+ return self._order_agg_func
105
+
106
+ def _alias_sort_names(self, qs):
107
+ """Annotate sort_name."""
108
+ if self.order_key != "sort_name" and not (
109
+ qs.model is StoryArc and self.order_key == "story_arc_number"
110
+ ):
111
+ return qs
112
+ pks = self.kwargs.get("pks")
113
+ show = MappingProxyType(self.params["show"]) # type: ignore
114
+ # TODO too many annotations for order?
115
+ # Move other annotations to card.
116
+ # eager publisher for imprint of course
117
+ sort_name_annotations = self.get_sort_name_annotations(
118
+ qs.model, self.model_group, pks, show
119
+ )
120
+ if sort_name_annotations:
121
+ qs = qs.alias(**sort_name_annotations)
122
+ if qs.model is Comic:
123
+ self._comic_sort_names = tuple(sort_name_annotations.keys())
124
+ return qs
125
+
126
+ def _alias_filename(self, qs):
127
+ """Calculate filename from path in the db."""
128
+ if self.order_key != "filename":
129
+ return qs
130
+ if qs.model is Folder:
131
+ filename = F("name")
132
+ else:
133
+ prefix = "" if qs.model == Comic else self.rel_prefix
134
+ path_rel = prefix + "path"
135
+ filename = self.order_agg_func(
136
+ Right(
137
+ path_rel,
138
+ StrIndex(Reverse(F(path_rel)), Value(sep)) - 1, # type: ignore
139
+ output_field=CharField(),
140
+ )
141
+ )
142
+ return qs.alias(filename=filename)
143
+
144
+ def _alias_story_arc_number(self, qs):
145
+ if self.order_key != "story_arc_number":
146
+ return qs
147
+
148
+ # Get story_arc__pk
149
+ group = self.kwargs["group"]
150
+ pks = self.kwargs["pks"]
151
+ if group == STORY_ARC_GROUP and pks:
152
+ story_arc_pks = pks
153
+ else:
154
+ story_arc_pks = self.params.get("filters", {}).get( # type: ignore
155
+ "story_arcs", ()
156
+ )
157
+
158
+ # If we have one annotate it.
159
+ if story_arc_pks:
160
+ rel = self.get_rel_prefix(qs.model) + "story_arc_numbers"
161
+ condition_rel = "pk" if qs.model is StoryArc else rel + "__story_arc"
162
+ condition = Q(**{f"{condition_rel}__in": story_arc_pks})
163
+ qs = qs.alias(
164
+ selected_story_arc_number=FilteredRelation(rel, condition=condition),
165
+ )
166
+ story_arc_number = self.order_agg_func("selected_story_arc_number__number")
167
+ else:
168
+ story_arc_number = NONE_INTEGERFIELD
169
+
170
+ return qs.alias(story_arc_number=story_arc_number)
171
+
172
+ def _annotate_page_count(self, qs):
173
+ """Hoist up total page_count of children."""
174
+ # Used for sorting and progress
175
+ if qs.model is Comic or (
176
+ self.order_key != "page_count"
177
+ and self.TARGET not in self._PAGE_COUNT_TARGETS
178
+ ):
179
+ return qs
180
+
181
+ rel = self.rel_prefix + "page_count"
182
+ page_count_sum = Sum(rel, distinct=True)
183
+ if self.TARGET == "browser":
184
+ qs = qs.alias(page_count=page_count_sum)
185
+ else:
186
+ qs = qs.annotate(page_count=page_count_sum)
187
+ return qs
188
+
189
+ def _annotate_bookmark_updated_at(self, qs):
190
+ if self.is_opds_acquisition or self.order_key == "bookmark_updated_at":
191
+ bmua_agg = self.get_max_bookmark_updated_at_aggregate(
192
+ qs.model, agg_func=self.order_agg_func
193
+ )
194
+ # This is used by annotate.bookmark to avoid a
195
+ # similar query.
196
+ self.bmua_is_max = self.order_agg_func is Max
197
+ qs = qs.annotate(bookmark_updated_at=bmua_agg)
198
+ # This is used by the serializer to compute mtime
199
+ return qs.annotate(bmua_is_max=Value(self.bmua_is_max))
200
+
201
+ def annotate_order_value(self, qs):
202
+ """Annotate a main key for sorting and browser card display."""
203
+ # Determine order func
204
+ if self.TARGET == "metadata":
205
+ return qs
206
+ if qs.model is Folder and self.order_key == "filename":
207
+ order_value = F("name")
208
+ elif qs.model is Comic or self.order_key in _ANNOTATED_ORDER_FIELDS:
209
+ # These are annotated in browser_annotaions
210
+ order_value = F(self.order_key)
211
+ else:
212
+ agg_func = _ORDER_AGGREGATE_FUNCS[self.order_key]
213
+ agg_func = self.order_agg_func if agg_func == Min else agg_func
214
+ field = self.rel_prefix + self.order_key
215
+ order_value = agg_func(field)
216
+
217
+ if self.TARGET == "browser":
218
+ qs = qs.annotate(order_value=order_value)
219
+ else:
220
+ qs = qs.alias(order_value=order_value)
221
+ return qs
222
+
223
+ def _annotate_search_scores(self, qs):
224
+ """Annotate Search Scores."""
225
+ if (
226
+ self.TARGET not in self._COVER_AND_CARD_TARGETS
227
+ or self.order_key != "search_score"
228
+ ):
229
+ return qs
230
+
231
+ # Rank is always the max of the relations, cannot aggregate?
232
+ # group by here fixes duplicates with story_arc, probably because it's a long relation
233
+ return qs.annotate(search_score=ComicFTSRank()).group_by("id")
234
+
235
+ def annotate_order_aggregates(self, qs):
236
+ """Annotate common aggregates between browser and metadata."""
237
+ qs = qs.annotate(ids=JsonGroupArray("id", distinct=True))
238
+ qs = self._annotate_search_scores(qs)
239
+ qs = self._alias_sort_names(qs)
240
+ qs = self._alias_filename(qs)
241
+ qs = self._alias_story_arc_number(qs)
242
+ qs = self._annotate_page_count(qs)
243
+ qs = self._annotate_bookmark_updated_at(qs)
244
+ if qs.model is not Comic:
245
+ # comic orders on indexed fields when it can
246
+ qs = self.annotate_order_value(qs)
247
+ return qs