codex 1.7.3a2__py3-none-any.whl → 1.7.4__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 (578) hide show
  1. codex/asgi.py +2 -1
  2. codex/choices.py +12 -12
  3. codex/choices_to_json.py +8 -8
  4. codex/db.py +2 -2
  5. codex/exceptions.py +6 -7
  6. codex/librarian/bookmark/bookmarkd.py +8 -4
  7. codex/librarian/bookmark/update.py +82 -48
  8. codex/librarian/covers/create.py +10 -8
  9. codex/librarian/covers/path.py +6 -5
  10. codex/librarian/covers/purge.py +2 -2
  11. codex/librarian/importer/aggregate.py +2 -2
  12. codex/librarian/importer/cache.py +1 -4
  13. codex/librarian/importer/create_comics.py +2 -2
  14. codex/librarian/importer/create_covers.py +1 -1
  15. codex/librarian/importer/create_fks.py +4 -3
  16. codex/librarian/importer/deleted.py +3 -3
  17. codex/librarian/importer/extract.py +56 -37
  18. codex/librarian/importer/failed_imports.py +1 -1
  19. codex/librarian/importer/importer.py +3 -1
  20. codex/librarian/importer/importerd.py +3 -3
  21. codex/librarian/importer/link_comics.py +2 -1
  22. codex/librarian/importer/moved.py +2 -7
  23. codex/librarian/importer/query_fks.py +1 -4
  24. codex/librarian/importer/tasks.py +1 -1
  25. codex/librarian/janitor/integrity.py +27 -20
  26. codex/librarian/janitor/janitor.py +1 -1
  27. codex/librarian/janitor/latest_version.py +1 -1
  28. codex/librarian/janitor/update.py +2 -2
  29. codex/librarian/janitor/vacuum.py +1 -1
  30. codex/librarian/librariand.py +3 -2
  31. codex/librarian/notifier/notifierd.py +2 -1
  32. codex/librarian/search/optimize.py +1 -1
  33. codex/librarian/search/remove.py +1 -1
  34. codex/librarian/search/update.py +4 -4
  35. codex/librarian/telemeter/stats.py +7 -6
  36. codex/librarian/telemeter/telemeter.py +0 -1
  37. codex/librarian/watchdog/db_snapshot.py +3 -3
  38. codex/librarian/watchdog/dir_snapshot_diff.py +3 -4
  39. codex/librarian/watchdog/emitter.py +4 -4
  40. codex/librarian/watchdog/event_batcherd.py +2 -1
  41. codex/librarian/watchdog/events.py +1 -2
  42. codex/librarian/watchdog/observers.py +15 -10
  43. codex/logger/logging.py +1 -1
  44. codex/memory.py +3 -2
  45. codex/migrations/0001_init.py +1 -2
  46. codex/migrations/0014_pdf_issue_suffix_remove_cover_image_sort_name.py +1 -2
  47. codex/migrations/0018_rename_userbookmark_bookmark.py +1 -2
  48. codex/migrations/0028_telemeter.py +1 -5
  49. codex/models/base.py +3 -1
  50. codex/models/bookmark.py +4 -7
  51. codex/models/comic.py +2 -2
  52. codex/models/functions.py +12 -5
  53. codex/models/groups.py +1 -1
  54. codex/models/library.py +1 -1
  55. codex/models/paths.py +4 -4
  56. codex/models/query.py +8 -4
  57. codex/models/util.py +1 -1
  58. codex/permissions.py +1 -1
  59. codex/run.py +1 -1
  60. codex/serializers/admin/libraries.py +1 -3
  61. codex/serializers/admin/stats.py +4 -4
  62. codex/serializers/auth.py +4 -2
  63. codex/serializers/browser/choices.py +87 -9
  64. codex/serializers/browser/filters.py +9 -37
  65. codex/serializers/browser/metadata.py +2 -1
  66. codex/serializers/browser/mixins.py +7 -3
  67. codex/serializers/browser/mtime.py +3 -5
  68. codex/serializers/browser/page.py +5 -4
  69. codex/serializers/browser/settings.py +7 -5
  70. codex/serializers/fields/__init__.py +37 -0
  71. codex/serializers/fields/auth.py +45 -0
  72. codex/serializers/fields/browser.py +85 -0
  73. codex/serializers/fields/group.py +13 -0
  74. codex/serializers/fields/reader.py +22 -0
  75. codex/serializers/fields/sanitized.py +13 -0
  76. codex/serializers/fields/session.py +15 -0
  77. codex/serializers/fields/stats.py +36 -0
  78. codex/serializers/fields/vuetify.py +62 -0
  79. codex/serializers/models/base.py +1 -1
  80. codex/serializers/models/comic.py +2 -2
  81. codex/serializers/models/groups.py +0 -2
  82. codex/serializers/models/named.py +1 -1
  83. codex/serializers/models/pycountry.py +1 -1
  84. codex/serializers/opds/authentication.py +4 -2
  85. codex/serializers/opds/urls.py +2 -1
  86. codex/serializers/opds/v1.py +4 -3
  87. codex/serializers/opds/v2/feed.py +2 -1
  88. codex/serializers/opds/v2/links.py +23 -21
  89. codex/serializers/opds/v2/metadata.py +4 -8
  90. codex/serializers/opds/v2/progression.py +5 -3
  91. codex/serializers/opds/v2/publication.py +16 -18
  92. codex/serializers/opds/v2/unused.py +15 -8
  93. codex/serializers/reader.py +16 -14
  94. codex/serializers/redirect.py +2 -1
  95. codex/serializers/route.py +6 -4
  96. codex/serializers/settings.py +5 -3
  97. codex/serializers/versions.py +2 -1
  98. codex/settings/settings.py +4 -3
  99. codex/signals/django_signals.py +1 -1
  100. codex/static_root/assets/{VCheckbox-FaT6MGfu.f6732060f734.js → VCheckbox-CtTi6T7d.87331fa7e77f.js} +1 -1
  101. codex/static_root/assets/VCheckbox-CtTi6T7d.87331fa7e77f.js.br +0 -0
  102. codex/static_root/assets/VCheckbox-CtTi6T7d.87331fa7e77f.js.gz +0 -0
  103. codex/static_root/assets/{VCheckbox-FaT6MGfu.js → VCheckbox-CtTi6T7d.js} +1 -1
  104. codex/static_root/assets/VCheckbox-CtTi6T7d.js.br +0 -0
  105. codex/static_root/assets/VCheckbox-CtTi6T7d.js.gz +0 -0
  106. codex/static_root/assets/{VCheckboxBtn-CZ_P-qUM.847452d574cf.js → VCheckboxBtn-DQafuWTH.dada5e0634ef.js} +1 -1
  107. codex/static_root/assets/VCheckboxBtn-DQafuWTH.dada5e0634ef.js.br +0 -0
  108. codex/static_root/assets/VCheckboxBtn-DQafuWTH.dada5e0634ef.js.gz +0 -0
  109. codex/static_root/assets/{VCheckboxBtn-CZ_P-qUM.js → VCheckboxBtn-DQafuWTH.js} +1 -1
  110. codex/static_root/assets/VCheckboxBtn-DQafuWTH.js.br +0 -0
  111. codex/static_root/assets/VCheckboxBtn-DQafuWTH.js.gz +0 -0
  112. codex/static_root/assets/{VCombobox-C8QLNlSl.6f431e19a453.js → VCombobox-C6TX3Dhp.e619423a6463.js} +1 -1
  113. codex/static_root/assets/VCombobox-C6TX3Dhp.e619423a6463.js.br +0 -0
  114. codex/static_root/assets/VCombobox-C6TX3Dhp.e619423a6463.js.gz +0 -0
  115. codex/static_root/assets/{VCombobox-C8QLNlSl.js → VCombobox-C6TX3Dhp.js} +1 -1
  116. codex/static_root/assets/VCombobox-C6TX3Dhp.js.br +0 -0
  117. codex/static_root/assets/VCombobox-C6TX3Dhp.js.gz +0 -0
  118. codex/static_root/assets/{VDialog-RVLeW7je.c0c7eef71eec.js → VDialog-CknWq2kd.b2d301ec6ac5.js} +1 -1
  119. codex/static_root/assets/VDialog-CknWq2kd.b2d301ec6ac5.js.br +0 -0
  120. codex/static_root/assets/VDialog-CknWq2kd.b2d301ec6ac5.js.gz +0 -0
  121. codex/static_root/assets/{VDialog-RVLeW7je.js → VDialog-CknWq2kd.js} +1 -1
  122. codex/static_root/assets/VDialog-CknWq2kd.js.br +0 -0
  123. codex/static_root/assets/VDialog-CknWq2kd.js.gz +0 -0
  124. codex/static_root/assets/{VDivider-D1Ot4vR2.9dbee744fb3c.js → VDivider-F4DUgr74.62bc92cab97d.js} +1 -1
  125. codex/static_root/assets/VDivider-F4DUgr74.62bc92cab97d.js.br +0 -0
  126. codex/static_root/assets/VDivider-F4DUgr74.62bc92cab97d.js.gz +0 -0
  127. codex/static_root/assets/{VDivider-D1Ot4vR2.js → VDivider-F4DUgr74.js} +1 -1
  128. codex/static_root/assets/VDivider-F4DUgr74.js.br +0 -0
  129. codex/static_root/assets/VDivider-F4DUgr74.js.gz +0 -0
  130. codex/static_root/assets/{VExpansionPanels-DQilGHZk.43f06d0a45e0.js → VExpansionPanels-CprYUTGT.39b8a50cde43.js} +1 -1
  131. codex/static_root/assets/VExpansionPanels-CprYUTGT.39b8a50cde43.js.br +0 -0
  132. codex/static_root/assets/VExpansionPanels-CprYUTGT.39b8a50cde43.js.gz +0 -0
  133. codex/static_root/assets/{VExpansionPanels-DQilGHZk.js → VExpansionPanels-CprYUTGT.js} +1 -1
  134. codex/static_root/assets/VExpansionPanels-CprYUTGT.js.br +0 -0
  135. codex/static_root/assets/VExpansionPanels-CprYUTGT.js.gz +0 -0
  136. codex/static_root/assets/{VForm-DNmY-qFJ.81f3a5ff7ec3.js → VForm-DnWAUsrl.4ab0786d658e.js} +1 -1
  137. codex/static_root/assets/VForm-DnWAUsrl.4ab0786d658e.js.br +0 -0
  138. codex/static_root/assets/VForm-DnWAUsrl.4ab0786d658e.js.gz +0 -0
  139. codex/static_root/assets/{VForm-DNmY-qFJ.js → VForm-DnWAUsrl.js} +1 -1
  140. codex/static_root/assets/VForm-DnWAUsrl.js.br +0 -0
  141. codex/static_root/assets/VForm-DnWAUsrl.js.gz +0 -0
  142. codex/static_root/assets/{VRadioGroup-DoayJpcS.fe5e0e74ffee.js → VRadioGroup-D71Rszum.befc87b0c476.js} +1 -1
  143. codex/static_root/assets/VRadioGroup-D71Rszum.befc87b0c476.js.br +0 -0
  144. codex/static_root/assets/VRadioGroup-D71Rszum.befc87b0c476.js.gz +0 -0
  145. codex/static_root/assets/{VRadioGroup-DoayJpcS.js → VRadioGroup-D71Rszum.js} +1 -1
  146. codex/static_root/assets/VRadioGroup-D71Rszum.js.br +0 -0
  147. codex/static_root/assets/VRadioGroup-D71Rszum.js.gz +0 -0
  148. codex/static_root/assets/{VSelect-BSLmHX_P.9ab865ec0fad.js → VSelect-CbPDrHNj.4809fbbf00f0.js} +1 -1
  149. codex/static_root/assets/VSelect-CbPDrHNj.4809fbbf00f0.js.br +0 -0
  150. codex/static_root/assets/VSelect-CbPDrHNj.4809fbbf00f0.js.gz +0 -0
  151. codex/static_root/assets/{VSelect-BSLmHX_P.js → VSelect-CbPDrHNj.js} +1 -1
  152. codex/static_root/assets/VSelect-CbPDrHNj.js.br +0 -0
  153. codex/static_root/assets/VSelect-CbPDrHNj.js.gz +0 -0
  154. codex/static_root/assets/{VSelectionControl-TaKCeZgb.ad6c96efe57c.js → VSelectionControl-It389cbo.ac75aee480a0.js} +1 -1
  155. codex/static_root/assets/VSelectionControl-It389cbo.ac75aee480a0.js.br +0 -0
  156. codex/static_root/assets/VSelectionControl-It389cbo.ac75aee480a0.js.gz +0 -0
  157. codex/static_root/assets/{VSelectionControl-TaKCeZgb.js → VSelectionControl-It389cbo.js} +1 -1
  158. codex/static_root/assets/VSelectionControl-It389cbo.js.br +0 -0
  159. codex/static_root/assets/VSelectionControl-It389cbo.js.gz +0 -0
  160. codex/static_root/assets/{VTable-BfcOiEpa.77ef3973bb54.js → VTable-D9e3lKk6.7cd0760008c7.js} +1 -1
  161. codex/static_root/assets/VTable-D9e3lKk6.7cd0760008c7.js.br +0 -0
  162. codex/static_root/assets/VTable-D9e3lKk6.7cd0760008c7.js.gz +0 -0
  163. codex/static_root/assets/{VTable-BfcOiEpa.js → VTable-D9e3lKk6.js} +1 -1
  164. codex/static_root/assets/VTable-D9e3lKk6.js.br +0 -0
  165. codex/static_root/assets/VTable-D9e3lKk6.js.gz +0 -0
  166. codex/static_root/assets/{VWindowItem-D8lWcbQY.e4c75ad78718.js → VWindowItem-B4VZ37cq.e45c5018cc73.js} +1 -1
  167. codex/static_root/assets/VWindowItem-B4VZ37cq.e45c5018cc73.js.br +0 -0
  168. codex/static_root/assets/VWindowItem-B4VZ37cq.e45c5018cc73.js.gz +0 -0
  169. codex/static_root/assets/{VWindowItem-D8lWcbQY.js → VWindowItem-B4VZ37cq.js} +1 -1
  170. codex/static_root/assets/VWindowItem-B4VZ37cq.js.br +0 -0
  171. codex/static_root/assets/VWindowItem-B4VZ37cq.js.gz +0 -0
  172. codex/static_root/assets/{admin-CBLHOrM9.8c3c2268bc96.js → admin-Bkd8zuSF.2a29386f3488.js} +1 -1
  173. codex/static_root/assets/admin-Bkd8zuSF.2a29386f3488.js.br +0 -0
  174. codex/static_root/assets/admin-Bkd8zuSF.2a29386f3488.js.gz +0 -0
  175. codex/static_root/assets/{admin-CBLHOrM9.js → admin-Bkd8zuSF.js} +1 -1
  176. codex/static_root/assets/admin-Bkd8zuSF.js.br +0 -0
  177. codex/static_root/assets/admin-Bkd8zuSF.js.gz +0 -0
  178. codex/static_root/assets/{admin-80eqCqtz.d6deb9edb8cb.js → admin-CFTKGwmx.18915c5df4d3.js} +1 -1
  179. codex/static_root/assets/admin-CFTKGwmx.18915c5df4d3.js.br +0 -0
  180. codex/static_root/assets/admin-CFTKGwmx.18915c5df4d3.js.gz +0 -0
  181. codex/static_root/assets/{admin-80eqCqtz.js → admin-CFTKGwmx.js} +1 -1
  182. codex/static_root/assets/admin-CFTKGwmx.js.br +0 -0
  183. codex/static_root/assets/admin-CFTKGwmx.js.gz +0 -0
  184. codex/static_root/assets/{admin-menu-_aAGknKO.0c08c9bd2e7d.js → admin-menu-CxZqtPES.7b3a06ce4b92.js} +1 -1
  185. codex/static_root/assets/admin-menu-CxZqtPES.7b3a06ce4b92.js.br +0 -0
  186. codex/static_root/assets/admin-menu-CxZqtPES.7b3a06ce4b92.js.gz +0 -0
  187. codex/static_root/assets/{admin-menu-_aAGknKO.js → admin-menu-CxZqtPES.js} +1 -1
  188. codex/static_root/assets/admin-menu-CxZqtPES.js.br +0 -0
  189. codex/static_root/assets/admin-menu-CxZqtPES.js.gz +0 -0
  190. codex/static_root/assets/{admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js → admin-settings-button-progress-D2TfW_5T.8a9d411ee79d.js} +1 -1
  191. codex/static_root/assets/admin-settings-button-progress-D2TfW_5T.8a9d411ee79d.js.br +0 -0
  192. codex/static_root/assets/admin-settings-button-progress-D2TfW_5T.8a9d411ee79d.js.gz +0 -0
  193. codex/static_root/assets/{admin-settings-button-progress-BqRFyhjf.js → admin-settings-button-progress-D2TfW_5T.js} +1 -1
  194. codex/static_root/assets/admin-settings-button-progress-D2TfW_5T.js.br +0 -0
  195. codex/static_root/assets/admin-settings-button-progress-D2TfW_5T.js.gz +0 -0
  196. codex/static_root/assets/browser-Br2DgAdi.433cca495d61.js +1 -0
  197. codex/static_root/assets/browser-Br2DgAdi.433cca495d61.js.br +0 -0
  198. codex/static_root/assets/browser-Br2DgAdi.433cca495d61.js.gz +0 -0
  199. codex/static_root/assets/browser-Br2DgAdi.js +1 -0
  200. codex/static_root/assets/browser-Br2DgAdi.js.br +0 -0
  201. codex/static_root/assets/browser-Br2DgAdi.js.gz +0 -0
  202. codex/static_root/assets/{browser-chTZ1CM4.521193ab0710.css → browser-DNzQvgkY.aea8b7d7ca40.css} +1 -1
  203. codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.br +0 -0
  204. codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.gz +0 -0
  205. codex/static_root/assets/{browser-chTZ1CM4.css → browser-DNzQvgkY.css} +1 -1
  206. codex/static_root/assets/browser-DNzQvgkY.css.br +0 -0
  207. codex/static_root/assets/browser-DNzQvgkY.css.gz +0 -0
  208. codex/static_root/assets/{change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js → change-password-dialog-CSylx5Qb.319466c891c9.js} +1 -1
  209. codex/static_root/assets/change-password-dialog-CSylx5Qb.319466c891c9.js.br +0 -0
  210. codex/static_root/assets/change-password-dialog-CSylx5Qb.319466c891c9.js.gz +0 -0
  211. codex/static_root/assets/{change-password-dialog-1ZVP_Q2w.js → change-password-dialog-CSylx5Qb.js} +1 -1
  212. codex/static_root/assets/change-password-dialog-CSylx5Qb.js.br +0 -0
  213. codex/static_root/assets/change-password-dialog-CSylx5Qb.js.gz +0 -0
  214. codex/static_root/assets/{confirm-dialog-DqCey9Iq.e315d7f8f752.js → confirm-dialog-Bx2R2vgR.d42b6449c495.js} +1 -1
  215. codex/static_root/assets/confirm-dialog-Bx2R2vgR.d42b6449c495.js.br +0 -0
  216. codex/static_root/assets/confirm-dialog-Bx2R2vgR.d42b6449c495.js.gz +0 -0
  217. codex/static_root/assets/{confirm-dialog-DqCey9Iq.js → confirm-dialog-Bx2R2vgR.js} +1 -1
  218. codex/static_root/assets/confirm-dialog-Bx2R2vgR.js.br +0 -0
  219. codex/static_root/assets/confirm-dialog-Bx2R2vgR.js.gz +0 -0
  220. codex/static_root/assets/{datetime-column-CBA8bYeO.17a31f189d66.js → datetime-column-sOrWMDcU.9ad225af18db.js} +1 -1
  221. codex/static_root/assets/datetime-column-sOrWMDcU.9ad225af18db.js.br +2 -0
  222. codex/static_root/assets/datetime-column-sOrWMDcU.9ad225af18db.js.gz +0 -0
  223. codex/static_root/assets/{datetime-column-CBA8bYeO.js → datetime-column-sOrWMDcU.js} +1 -1
  224. codex/static_root/assets/datetime-column-sOrWMDcU.js.br +2 -0
  225. codex/static_root/assets/datetime-column-sOrWMDcU.js.gz +0 -0
  226. codex/static_root/assets/{filter-mnO3lLPo.659442401b16.js → filter-SgjvoAvL.094069d6978d.js} +1 -1
  227. codex/static_root/assets/filter-SgjvoAvL.094069d6978d.js.br +0 -0
  228. codex/static_root/assets/filter-SgjvoAvL.094069d6978d.js.gz +0 -0
  229. codex/static_root/assets/{filter-mnO3lLPo.js → filter-SgjvoAvL.js} +1 -1
  230. codex/static_root/assets/filter-SgjvoAvL.js.br +0 -0
  231. codex/static_root/assets/filter-SgjvoAvL.js.gz +0 -0
  232. codex/static_root/assets/{flag-tab-Bc677pNb.1b8a2f7c0dc3.js → flag-tab-B_0tGWPg.e46d1782b327.js} +1 -1
  233. codex/static_root/assets/flag-tab-B_0tGWPg.e46d1782b327.js.br +0 -0
  234. codex/static_root/assets/flag-tab-B_0tGWPg.e46d1782b327.js.gz +0 -0
  235. codex/static_root/assets/{flag-tab-Bc677pNb.js → flag-tab-B_0tGWPg.js} +1 -1
  236. codex/static_root/assets/flag-tab-B_0tGWPg.js.br +0 -0
  237. codex/static_root/assets/flag-tab-B_0tGWPg.js.gz +0 -0
  238. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css +1 -0
  239. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.br +0 -0
  240. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.gz +0 -0
  241. codex/static_root/assets/flag-tab-D2MYXCHk.css +1 -0
  242. codex/static_root/assets/flag-tab-D2MYXCHk.css.br +0 -0
  243. codex/static_root/assets/flag-tab-D2MYXCHk.css.gz +0 -0
  244. codex/static_root/assets/{forwardRefs-DPRKg5wq.6f09e9d22fa6.js → forwardRefs-DqbPK1-k.bb9d6863ac16.js} +1 -1
  245. codex/static_root/assets/forwardRefs-DqbPK1-k.bb9d6863ac16.js.br +0 -0
  246. codex/static_root/assets/forwardRefs-DqbPK1-k.bb9d6863ac16.js.gz +0 -0
  247. codex/static_root/assets/{forwardRefs-DPRKg5wq.js → forwardRefs-DqbPK1-k.js} +1 -1
  248. codex/static_root/assets/forwardRefs-DqbPK1-k.js.br +0 -0
  249. codex/static_root/assets/forwardRefs-DqbPK1-k.js.gz +0 -0
  250. codex/static_root/assets/{group-tab-BVlBrMwo.1127b51be6e7.js → group-tab-DXxQUa6C.f1f12f39b167.js} +1 -1
  251. codex/static_root/assets/group-tab-DXxQUa6C.f1f12f39b167.js.br +0 -0
  252. codex/static_root/assets/group-tab-DXxQUa6C.f1f12f39b167.js.gz +0 -0
  253. codex/static_root/assets/{group-tab-BVlBrMwo.js → group-tab-DXxQUa6C.js} +1 -1
  254. codex/static_root/assets/group-tab-DXxQUa6C.js.br +0 -0
  255. codex/static_root/assets/group-tab-DXxQUa6C.js.gz +0 -0
  256. codex/static_root/assets/{http-error-C9-_aEBF.d29b164e80de.js → http-error-BVMwwrFo.a7be6a26c9eb.js} +1 -1
  257. codex/static_root/assets/http-error-BVMwwrFo.a7be6a26c9eb.js.br +0 -0
  258. codex/static_root/assets/http-error-BVMwwrFo.a7be6a26c9eb.js.gz +0 -0
  259. codex/static_root/assets/{http-error-C9-_aEBF.js → http-error-BVMwwrFo.js} +1 -1
  260. codex/static_root/assets/http-error-BVMwwrFo.js.br +0 -0
  261. codex/static_root/assets/http-error-BVMwwrFo.js.gz +0 -0
  262. codex/static_root/assets/{index-9nBCksDQ.4561d2608773.js → index-DK0lSHDP.86f18c078fa9.js} +1 -1
  263. codex/static_root/assets/index-DK0lSHDP.86f18c078fa9.js.br +0 -0
  264. codex/static_root/assets/index-DK0lSHDP.86f18c078fa9.js.gz +0 -0
  265. codex/static_root/assets/{index-9nBCksDQ.js → index-DK0lSHDP.js} +1 -1
  266. codex/static_root/assets/index-DK0lSHDP.js.br +0 -0
  267. codex/static_root/assets/index-DK0lSHDP.js.gz +0 -0
  268. codex/static_root/assets/{library-tab-BMe3dKzy.22b6e123ecfb.js → library-tab-NhXuvZ4F.1e8ac3b7c168.js} +1 -1
  269. codex/static_root/assets/library-tab-NhXuvZ4F.1e8ac3b7c168.js.br +0 -0
  270. codex/static_root/assets/library-tab-NhXuvZ4F.1e8ac3b7c168.js.gz +0 -0
  271. codex/static_root/assets/{library-tab-BMe3dKzy.js → library-tab-NhXuvZ4F.js} +1 -1
  272. codex/static_root/assets/library-tab-NhXuvZ4F.js.br +0 -0
  273. codex/static_root/assets/library-tab-NhXuvZ4F.js.gz +0 -0
  274. codex/static_root/assets/{main-BbNUiWEb.565b616eb122.js → main-CYgubU7H.50aa39cf9565.js} +3 -3
  275. codex/static_root/assets/main-CYgubU7H.50aa39cf9565.js.br +0 -0
  276. codex/static_root/assets/main-CYgubU7H.50aa39cf9565.js.gz +0 -0
  277. codex/static_root/assets/{main-BbNUiWEb.js → main-CYgubU7H.js} +3 -3
  278. codex/static_root/assets/main-CYgubU7H.js.br +0 -0
  279. codex/static_root/assets/main-CYgubU7H.js.gz +0 -0
  280. codex/static_root/assets/pager-full-pdf---TZiAf5.a6269ab85085.js +1 -0
  281. codex/static_root/assets/pager-full-pdf---TZiAf5.a6269ab85085.js.br +0 -0
  282. codex/static_root/assets/pager-full-pdf---TZiAf5.a6269ab85085.js.gz +0 -0
  283. codex/static_root/assets/pager-full-pdf---TZiAf5.js +1 -0
  284. codex/static_root/assets/pager-full-pdf---TZiAf5.js.br +0 -0
  285. codex/static_root/assets/pager-full-pdf---TZiAf5.js.gz +0 -0
  286. codex/static_root/assets/{pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js → pagination-toolbar-CeWXU_qA.abe0805da1cc.js} +1 -1
  287. codex/static_root/assets/pagination-toolbar-CeWXU_qA.abe0805da1cc.js.br +0 -0
  288. codex/static_root/assets/pagination-toolbar-CeWXU_qA.abe0805da1cc.js.gz +0 -0
  289. codex/static_root/assets/{pagination-toolbar-Dx5JwWG-.js → pagination-toolbar-CeWXU_qA.js} +1 -1
  290. codex/static_root/assets/pagination-toolbar-CeWXU_qA.js.br +0 -0
  291. codex/static_root/assets/pagination-toolbar-CeWXU_qA.js.gz +0 -0
  292. codex/static_root/assets/{pdf-doc-6ZE_HmLT.10d1e16abc78.js → pdf-doc-Dws_otkd.d215eca27da5.js} +1 -1
  293. codex/static_root/assets/pdf-doc-Dws_otkd.d215eca27da5.js.br +0 -0
  294. codex/static_root/assets/pdf-doc-Dws_otkd.d215eca27da5.js.gz +0 -0
  295. codex/static_root/assets/{pdf-doc-6ZE_HmLT.js → pdf-doc-Dws_otkd.js} +1 -1
  296. codex/static_root/assets/pdf-doc-Dws_otkd.js.br +0 -0
  297. codex/static_root/assets/pdf-doc-Dws_otkd.js.gz +0 -0
  298. codex/static_root/assets/{reader-DdPKDuh5.0c55cef1e98b.js → reader-BCxYgZHF.dde3c4ac39a5.js} +2 -2
  299. codex/static_root/assets/reader-BCxYgZHF.dde3c4ac39a5.js.br +0 -0
  300. codex/static_root/assets/reader-BCxYgZHF.dde3c4ac39a5.js.gz +0 -0
  301. codex/static_root/assets/{reader-DdPKDuh5.js → reader-BCxYgZHF.js} +2 -2
  302. codex/static_root/assets/reader-BCxYgZHF.js.br +0 -0
  303. codex/static_root/assets/reader-BCxYgZHF.js.gz +0 -0
  304. codex/static_root/assets/{relation-chips-C96hi5jm.js → relation-chips-DNRRCvrw.b1bc75fb9349.js} +1 -1
  305. codex/static_root/assets/relation-chips-DNRRCvrw.b1bc75fb9349.js.br +0 -0
  306. codex/static_root/assets/relation-chips-DNRRCvrw.b1bc75fb9349.js.gz +0 -0
  307. codex/static_root/assets/{relation-chips-C96hi5jm.9f07c9eb533a.js → relation-chips-DNRRCvrw.js} +1 -1
  308. codex/static_root/assets/relation-chips-DNRRCvrw.js.br +0 -0
  309. codex/static_root/assets/relation-chips-DNRRCvrw.js.gz +0 -0
  310. codex/static_root/assets/{settings-drawer-CqbT1rid.js → settings-drawer-BuB29L5p.fe2eeea0058f.js} +2 -2
  311. codex/static_root/assets/settings-drawer-BuB29L5p.fe2eeea0058f.js.br +0 -0
  312. codex/static_root/assets/settings-drawer-BuB29L5p.fe2eeea0058f.js.gz +0 -0
  313. codex/static_root/assets/{settings-drawer-CqbT1rid.5639fa00b301.js → settings-drawer-BuB29L5p.js} +2 -2
  314. codex/static_root/assets/settings-drawer-BuB29L5p.js.br +0 -0
  315. codex/static_root/assets/settings-drawer-BuB29L5p.js.gz +0 -0
  316. codex/static_root/assets/{stats-tab-CkT2ZGUQ.b704fa46dc88.js → stats-tab-D0zymxU6.d5267113b51e.js} +1 -1
  317. codex/static_root/assets/stats-tab-D0zymxU6.d5267113b51e.js.br +0 -0
  318. codex/static_root/assets/stats-tab-D0zymxU6.d5267113b51e.js.gz +0 -0
  319. codex/static_root/assets/{stats-tab-CkT2ZGUQ.js → stats-tab-D0zymxU6.js} +1 -1
  320. codex/static_root/assets/stats-tab-D0zymxU6.js.br +0 -0
  321. codex/static_root/assets/stats-tab-D0zymxU6.js.gz +0 -0
  322. codex/static_root/assets/{task-tab-a-DcU3Tj.8c2f7bf3c4c9.js → task-tab-CI9RLdMS.120f395dc9c6.js} +1 -1
  323. codex/static_root/assets/task-tab-CI9RLdMS.120f395dc9c6.js.br +0 -0
  324. codex/static_root/assets/task-tab-CI9RLdMS.120f395dc9c6.js.gz +0 -0
  325. codex/static_root/assets/{task-tab-a-DcU3Tj.js → task-tab-CI9RLdMS.js} +1 -1
  326. codex/static_root/assets/task-tab-CI9RLdMS.js.br +0 -0
  327. codex/static_root/assets/task-tab-CI9RLdMS.js.gz +0 -0
  328. codex/static_root/assets/{unauthorized-BOl5YpL3.f3c4b52718d5.js → unauthorized-BNwg_Xvu.a894b96156e0.js} +1 -1
  329. codex/static_root/assets/unauthorized-BNwg_Xvu.a894b96156e0.js.br +0 -0
  330. codex/static_root/assets/unauthorized-BNwg_Xvu.a894b96156e0.js.gz +0 -0
  331. codex/static_root/assets/{unauthorized-BOl5YpL3.js → unauthorized-BNwg_Xvu.js} +1 -1
  332. codex/static_root/assets/unauthorized-BNwg_Xvu.js.br +0 -0
  333. codex/static_root/assets/unauthorized-BNwg_Xvu.js.gz +0 -0
  334. codex/static_root/assets/{user-tab-BBDZvD8G.aa4263a68b22.js → user-tab-w9LgIMMi.4a89c7b37486.js} +1 -1
  335. codex/static_root/assets/user-tab-w9LgIMMi.4a89c7b37486.js.br +0 -0
  336. codex/static_root/assets/user-tab-w9LgIMMi.4a89c7b37486.js.gz +0 -0
  337. codex/static_root/assets/{user-tab-BBDZvD8G.js → user-tab-w9LgIMMi.js} +1 -1
  338. codex/static_root/assets/user-tab-w9LgIMMi.js.br +0 -0
  339. codex/static_root/assets/user-tab-w9LgIMMi.js.gz +0 -0
  340. codex/static_root/{manifest.225989a17f49.json → manifest.514e63b9f805.json} +253 -253
  341. codex/static_root/manifest.514e63b9f805.json.br +0 -0
  342. codex/static_root/manifest.514e63b9f805.json.gz +0 -0
  343. codex/static_root/manifest.json +253 -253
  344. codex/static_root/manifest.json.br +0 -0
  345. codex/static_root/manifest.json.gz +0 -0
  346. codex/static_root/staticfiles.json +1 -1
  347. codex/status_controller.py +9 -12
  348. codex/urls/root.py +4 -3
  349. codex/views/admin/api_key.py +1 -4
  350. codex/views/admin/library.py +4 -4
  351. codex/views/admin/stats.py +10 -10
  352. codex/views/admin/tasks.py +9 -9
  353. codex/views/auth.py +3 -8
  354. codex/views/bookmark.py +3 -3
  355. codex/views/browser/annotate/card.py +2 -2
  356. codex/views/browser/annotate/order.py +6 -7
  357. codex/views/browser/bookmark.py +3 -1
  358. codex/views/browser/breadcrumbs.py +6 -5
  359. codex/views/browser/browser.py +2 -2
  360. codex/views/browser/choices.py +6 -7
  361. codex/views/browser/cover.py +6 -3
  362. codex/views/browser/download.py +2 -1
  363. codex/views/browser/filters/bookmark.py +1 -1
  364. codex/views/browser/filters/field.py +1 -1
  365. codex/views/browser/filters/filter.py +6 -8
  366. codex/views/browser/filters/group.py +8 -8
  367. codex/views/browser/filters/search/field/expression.py +1 -2
  368. codex/views/browser/filters/search/field/optimize.py +1 -1
  369. codex/views/browser/filters/search/field/parse.py +2 -2
  370. codex/views/browser/filters/search/parse.py +4 -19
  371. codex/views/browser/group_mtime.py +1 -1
  372. codex/views/browser/metadata/copy_intersections.py +1 -1
  373. codex/views/browser/metadata/metadata.py +1 -1
  374. codex/views/browser/mtime.py +1 -1
  375. codex/views/browser/order_by.py +3 -5
  376. codex/views/browser/params.py +1 -1
  377. codex/views/browser/settings.py +1 -1
  378. codex/views/browser/validate.py +8 -5
  379. codex/views/const.py +0 -3
  380. codex/views/frontend.py +1 -1
  381. codex/views/mixins.py +3 -2
  382. codex/views/opds/authentication_v1.py +1 -1
  383. codex/views/opds/const.py +4 -4
  384. codex/views/opds/util.py +3 -3
  385. codex/views/opds/v1/entry/entry.py +4 -2
  386. codex/views/opds/v1/entry/links.py +4 -5
  387. codex/views/opds/v1/facets.py +8 -4
  388. codex/views/opds/v1/feed.py +5 -5
  389. codex/views/opds/v1/links.py +11 -6
  390. codex/views/opds/v2/const.py +5 -2
  391. codex/views/opds/v2/feed.py +3 -3
  392. codex/views/opds/v2/progression.py +8 -9
  393. codex/views/opds/v2/publications.py +10 -20
  394. codex/views/public.py +1 -1
  395. codex/views/reader/books.py +3 -2
  396. codex/views/reader/page.py +3 -3
  397. codex/views/reader/params.py +2 -2
  398. codex/views/reader/reader.py +6 -6
  399. codex/views/reader/settings.py +1 -1
  400. codex/views/session.py +8 -2
  401. codex/views/settings.py +2 -2
  402. codex/views/timezone.py +2 -2
  403. codex/views/util.py +10 -9
  404. codex/views/version.py +1 -1
  405. {codex-1.7.3a2.dist-info → codex-1.7.4.dist-info}/METADATA +3 -1
  406. {codex-1.7.3a2.dist-info → codex-1.7.4.dist-info}/RECORD +409 -401
  407. {codex-1.7.3a2.dist-info → codex-1.7.4.dist-info}/WHEEL +1 -1
  408. codex/serializers/fields.py +0 -183
  409. codex/static_root/assets/VCheckbox-FaT6MGfu.f6732060f734.js.br +0 -0
  410. codex/static_root/assets/VCheckbox-FaT6MGfu.f6732060f734.js.gz +0 -0
  411. codex/static_root/assets/VCheckbox-FaT6MGfu.js.br +0 -0
  412. codex/static_root/assets/VCheckbox-FaT6MGfu.js.gz +0 -0
  413. codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.847452d574cf.js.br +0 -0
  414. codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.847452d574cf.js.gz +0 -0
  415. codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.js.br +0 -0
  416. codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.js.gz +0 -0
  417. codex/static_root/assets/VCombobox-C8QLNlSl.6f431e19a453.js.br +0 -0
  418. codex/static_root/assets/VCombobox-C8QLNlSl.6f431e19a453.js.gz +0 -0
  419. codex/static_root/assets/VCombobox-C8QLNlSl.js.br +0 -0
  420. codex/static_root/assets/VCombobox-C8QLNlSl.js.gz +0 -0
  421. codex/static_root/assets/VDialog-RVLeW7je.c0c7eef71eec.js.br +0 -0
  422. codex/static_root/assets/VDialog-RVLeW7je.c0c7eef71eec.js.gz +0 -0
  423. codex/static_root/assets/VDialog-RVLeW7je.js.br +0 -0
  424. codex/static_root/assets/VDialog-RVLeW7je.js.gz +0 -0
  425. codex/static_root/assets/VDivider-D1Ot4vR2.9dbee744fb3c.js.br +0 -0
  426. codex/static_root/assets/VDivider-D1Ot4vR2.9dbee744fb3c.js.gz +0 -0
  427. codex/static_root/assets/VDivider-D1Ot4vR2.js.br +0 -0
  428. codex/static_root/assets/VDivider-D1Ot4vR2.js.gz +0 -0
  429. codex/static_root/assets/VExpansionPanels-DQilGHZk.43f06d0a45e0.js.br +0 -0
  430. codex/static_root/assets/VExpansionPanels-DQilGHZk.43f06d0a45e0.js.gz +0 -0
  431. codex/static_root/assets/VExpansionPanels-DQilGHZk.js.br +0 -0
  432. codex/static_root/assets/VExpansionPanels-DQilGHZk.js.gz +0 -0
  433. codex/static_root/assets/VForm-DNmY-qFJ.81f3a5ff7ec3.js.br +0 -0
  434. codex/static_root/assets/VForm-DNmY-qFJ.81f3a5ff7ec3.js.gz +0 -0
  435. codex/static_root/assets/VForm-DNmY-qFJ.js.br +0 -0
  436. codex/static_root/assets/VForm-DNmY-qFJ.js.gz +0 -0
  437. codex/static_root/assets/VRadioGroup-DoayJpcS.fe5e0e74ffee.js.br +0 -0
  438. codex/static_root/assets/VRadioGroup-DoayJpcS.fe5e0e74ffee.js.gz +0 -0
  439. codex/static_root/assets/VRadioGroup-DoayJpcS.js.br +0 -0
  440. codex/static_root/assets/VRadioGroup-DoayJpcS.js.gz +0 -0
  441. codex/static_root/assets/VSelect-BSLmHX_P.9ab865ec0fad.js.br +0 -0
  442. codex/static_root/assets/VSelect-BSLmHX_P.9ab865ec0fad.js.gz +0 -0
  443. codex/static_root/assets/VSelect-BSLmHX_P.js.br +0 -0
  444. codex/static_root/assets/VSelect-BSLmHX_P.js.gz +0 -0
  445. codex/static_root/assets/VSelectionControl-TaKCeZgb.ad6c96efe57c.js.br +0 -0
  446. codex/static_root/assets/VSelectionControl-TaKCeZgb.ad6c96efe57c.js.gz +0 -0
  447. codex/static_root/assets/VSelectionControl-TaKCeZgb.js.br +0 -0
  448. codex/static_root/assets/VSelectionControl-TaKCeZgb.js.gz +0 -0
  449. codex/static_root/assets/VTable-BfcOiEpa.77ef3973bb54.js.br +0 -0
  450. codex/static_root/assets/VTable-BfcOiEpa.77ef3973bb54.js.gz +0 -0
  451. codex/static_root/assets/VTable-BfcOiEpa.js.br +0 -0
  452. codex/static_root/assets/VTable-BfcOiEpa.js.gz +0 -0
  453. codex/static_root/assets/VWindowItem-D8lWcbQY.e4c75ad78718.js.br +0 -0
  454. codex/static_root/assets/VWindowItem-D8lWcbQY.e4c75ad78718.js.gz +0 -0
  455. codex/static_root/assets/VWindowItem-D8lWcbQY.js.br +0 -0
  456. codex/static_root/assets/VWindowItem-D8lWcbQY.js.gz +0 -0
  457. codex/static_root/assets/admin-80eqCqtz.d6deb9edb8cb.js.br +0 -0
  458. codex/static_root/assets/admin-80eqCqtz.d6deb9edb8cb.js.gz +0 -0
  459. codex/static_root/assets/admin-80eqCqtz.js.br +0 -0
  460. codex/static_root/assets/admin-80eqCqtz.js.gz +0 -0
  461. codex/static_root/assets/admin-CBLHOrM9.8c3c2268bc96.js.br +0 -0
  462. codex/static_root/assets/admin-CBLHOrM9.8c3c2268bc96.js.gz +0 -0
  463. codex/static_root/assets/admin-CBLHOrM9.js.br +0 -0
  464. codex/static_root/assets/admin-CBLHOrM9.js.gz +0 -0
  465. codex/static_root/assets/admin-menu-_aAGknKO.0c08c9bd2e7d.js.br +0 -0
  466. codex/static_root/assets/admin-menu-_aAGknKO.0c08c9bd2e7d.js.gz +0 -0
  467. codex/static_root/assets/admin-menu-_aAGknKO.js.br +0 -0
  468. codex/static_root/assets/admin-menu-_aAGknKO.js.gz +0 -0
  469. codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js.br +0 -0
  470. codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js.gz +0 -0
  471. codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.js.br +0 -0
  472. codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.js.gz +0 -0
  473. codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js +0 -1
  474. codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js.br +0 -0
  475. codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js.gz +0 -0
  476. codex/static_root/assets/browser-DAprXYuP.js +0 -1
  477. codex/static_root/assets/browser-DAprXYuP.js.br +0 -0
  478. codex/static_root/assets/browser-DAprXYuP.js.gz +0 -0
  479. codex/static_root/assets/browser-chTZ1CM4.521193ab0710.css.br +0 -0
  480. codex/static_root/assets/browser-chTZ1CM4.521193ab0710.css.gz +0 -0
  481. codex/static_root/assets/browser-chTZ1CM4.css.br +0 -0
  482. codex/static_root/assets/browser-chTZ1CM4.css.gz +0 -0
  483. codex/static_root/assets/change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js.br +0 -0
  484. codex/static_root/assets/change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js.gz +0 -0
  485. codex/static_root/assets/change-password-dialog-1ZVP_Q2w.js.br +0 -0
  486. codex/static_root/assets/change-password-dialog-1ZVP_Q2w.js.gz +0 -0
  487. codex/static_root/assets/confirm-dialog-DqCey9Iq.e315d7f8f752.js.br +0 -0
  488. codex/static_root/assets/confirm-dialog-DqCey9Iq.e315d7f8f752.js.gz +0 -0
  489. codex/static_root/assets/confirm-dialog-DqCey9Iq.js.br +0 -0
  490. codex/static_root/assets/confirm-dialog-DqCey9Iq.js.gz +0 -0
  491. codex/static_root/assets/datetime-column-CBA8bYeO.17a31f189d66.js.br +0 -0
  492. codex/static_root/assets/datetime-column-CBA8bYeO.17a31f189d66.js.gz +0 -0
  493. codex/static_root/assets/datetime-column-CBA8bYeO.js.br +0 -0
  494. codex/static_root/assets/datetime-column-CBA8bYeO.js.gz +0 -0
  495. codex/static_root/assets/filter-mnO3lLPo.659442401b16.js.br +0 -0
  496. codex/static_root/assets/filter-mnO3lLPo.659442401b16.js.gz +0 -0
  497. codex/static_root/assets/filter-mnO3lLPo.js.br +0 -0
  498. codex/static_root/assets/filter-mnO3lLPo.js.gz +0 -0
  499. codex/static_root/assets/flag-tab-Bc677pNb.1b8a2f7c0dc3.js.br +0 -0
  500. codex/static_root/assets/flag-tab-Bc677pNb.1b8a2f7c0dc3.js.gz +0 -0
  501. codex/static_root/assets/flag-tab-Bc677pNb.js.br +0 -0
  502. codex/static_root/assets/flag-tab-Bc677pNb.js.gz +0 -0
  503. codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css +0 -1
  504. codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css.br +0 -0
  505. codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css.gz +0 -0
  506. codex/static_root/assets/flag-tab-glFvEgEl.css +0 -1
  507. codex/static_root/assets/flag-tab-glFvEgEl.css.br +0 -0
  508. codex/static_root/assets/flag-tab-glFvEgEl.css.gz +0 -0
  509. codex/static_root/assets/forwardRefs-DPRKg5wq.6f09e9d22fa6.js.br +0 -0
  510. codex/static_root/assets/forwardRefs-DPRKg5wq.6f09e9d22fa6.js.gz +0 -0
  511. codex/static_root/assets/forwardRefs-DPRKg5wq.js.br +0 -0
  512. codex/static_root/assets/forwardRefs-DPRKg5wq.js.gz +0 -0
  513. codex/static_root/assets/group-tab-BVlBrMwo.1127b51be6e7.js.br +0 -0
  514. codex/static_root/assets/group-tab-BVlBrMwo.1127b51be6e7.js.gz +0 -0
  515. codex/static_root/assets/group-tab-BVlBrMwo.js.br +0 -0
  516. codex/static_root/assets/group-tab-BVlBrMwo.js.gz +0 -0
  517. codex/static_root/assets/http-error-C9-_aEBF.d29b164e80de.js.br +0 -0
  518. codex/static_root/assets/http-error-C9-_aEBF.d29b164e80de.js.gz +0 -0
  519. codex/static_root/assets/http-error-C9-_aEBF.js.br +0 -0
  520. codex/static_root/assets/http-error-C9-_aEBF.js.gz +0 -0
  521. codex/static_root/assets/index-9nBCksDQ.4561d2608773.js.br +0 -0
  522. codex/static_root/assets/index-9nBCksDQ.4561d2608773.js.gz +0 -0
  523. codex/static_root/assets/index-9nBCksDQ.js.br +0 -0
  524. codex/static_root/assets/index-9nBCksDQ.js.gz +0 -0
  525. codex/static_root/assets/library-tab-BMe3dKzy.22b6e123ecfb.js.br +0 -0
  526. codex/static_root/assets/library-tab-BMe3dKzy.22b6e123ecfb.js.gz +0 -0
  527. codex/static_root/assets/library-tab-BMe3dKzy.js.br +0 -0
  528. codex/static_root/assets/library-tab-BMe3dKzy.js.gz +0 -0
  529. codex/static_root/assets/main-BbNUiWEb.565b616eb122.js.br +0 -0
  530. codex/static_root/assets/main-BbNUiWEb.565b616eb122.js.gz +0 -0
  531. codex/static_root/assets/main-BbNUiWEb.js.br +0 -0
  532. codex/static_root/assets/main-BbNUiWEb.js.gz +0 -0
  533. codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js +0 -1
  534. codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js.br +0 -0
  535. codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js.gz +0 -0
  536. codex/static_root/assets/pager-full-pdf-JwAUlsNI.js +0 -1
  537. codex/static_root/assets/pager-full-pdf-JwAUlsNI.js.br +0 -0
  538. codex/static_root/assets/pager-full-pdf-JwAUlsNI.js.gz +0 -0
  539. codex/static_root/assets/pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js.br +0 -0
  540. codex/static_root/assets/pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js.gz +0 -0
  541. codex/static_root/assets/pagination-toolbar-Dx5JwWG-.js.br +0 -0
  542. codex/static_root/assets/pagination-toolbar-Dx5JwWG-.js.gz +0 -0
  543. codex/static_root/assets/pdf-doc-6ZE_HmLT.10d1e16abc78.js.br +0 -0
  544. codex/static_root/assets/pdf-doc-6ZE_HmLT.10d1e16abc78.js.gz +0 -0
  545. codex/static_root/assets/pdf-doc-6ZE_HmLT.js.br +0 -0
  546. codex/static_root/assets/pdf-doc-6ZE_HmLT.js.gz +0 -0
  547. codex/static_root/assets/reader-DdPKDuh5.0c55cef1e98b.js.br +0 -0
  548. codex/static_root/assets/reader-DdPKDuh5.0c55cef1e98b.js.gz +0 -0
  549. codex/static_root/assets/reader-DdPKDuh5.js.br +0 -0
  550. codex/static_root/assets/reader-DdPKDuh5.js.gz +0 -0
  551. codex/static_root/assets/relation-chips-C96hi5jm.9f07c9eb533a.js.br +0 -0
  552. codex/static_root/assets/relation-chips-C96hi5jm.9f07c9eb533a.js.gz +0 -0
  553. codex/static_root/assets/relation-chips-C96hi5jm.js.br +0 -0
  554. codex/static_root/assets/relation-chips-C96hi5jm.js.gz +0 -0
  555. codex/static_root/assets/settings-drawer-CqbT1rid.5639fa00b301.js.br +0 -0
  556. codex/static_root/assets/settings-drawer-CqbT1rid.5639fa00b301.js.gz +0 -0
  557. codex/static_root/assets/settings-drawer-CqbT1rid.js.br +0 -0
  558. codex/static_root/assets/settings-drawer-CqbT1rid.js.gz +0 -0
  559. codex/static_root/assets/stats-tab-CkT2ZGUQ.b704fa46dc88.js.br +0 -0
  560. codex/static_root/assets/stats-tab-CkT2ZGUQ.b704fa46dc88.js.gz +0 -0
  561. codex/static_root/assets/stats-tab-CkT2ZGUQ.js.br +0 -0
  562. codex/static_root/assets/stats-tab-CkT2ZGUQ.js.gz +0 -0
  563. codex/static_root/assets/task-tab-a-DcU3Tj.8c2f7bf3c4c9.js.br +0 -0
  564. codex/static_root/assets/task-tab-a-DcU3Tj.8c2f7bf3c4c9.js.gz +0 -0
  565. codex/static_root/assets/task-tab-a-DcU3Tj.js.br +0 -0
  566. codex/static_root/assets/task-tab-a-DcU3Tj.js.gz +0 -0
  567. codex/static_root/assets/unauthorized-BOl5YpL3.f3c4b52718d5.js.br +0 -0
  568. codex/static_root/assets/unauthorized-BOl5YpL3.f3c4b52718d5.js.gz +0 -0
  569. codex/static_root/assets/unauthorized-BOl5YpL3.js.br +0 -0
  570. codex/static_root/assets/unauthorized-BOl5YpL3.js.gz +0 -0
  571. codex/static_root/assets/user-tab-BBDZvD8G.aa4263a68b22.js.br +0 -0
  572. codex/static_root/assets/user-tab-BBDZvD8G.aa4263a68b22.js.gz +0 -0
  573. codex/static_root/assets/user-tab-BBDZvD8G.js.br +0 -0
  574. codex/static_root/assets/user-tab-BBDZvD8G.js.gz +0 -0
  575. codex/static_root/manifest.225989a17f49.json.br +0 -0
  576. codex/static_root/manifest.225989a17f49.json.gz +0 -0
  577. {codex-1.7.3a2.dist-info → codex-1.7.4.dist-info}/LICENSE +0 -0
  578. {codex-1.7.3a2.dist-info → codex-1.7.4.dist-info}/entry_points.txt +0 -0
@@ -46,14 +46,14 @@ class DatabasePollingEmitter(EventEmitter, WorkerBaseMixin):
46
46
 
47
47
  _DIR_NOT_FOUND_TIMEOUT = 15 * 60
48
48
 
49
- def __init__( # noqa PLR0913
49
+ def __init__( # noqa: PLR0913
50
50
  self,
51
51
  event_queue,
52
52
  watch,
53
53
  timeout=DEFAULT_EMITTER_TIMEOUT,
54
54
  log_queue=None,
55
55
  librarian_queue=None,
56
- covers_only=False,
56
+ covers_only=False, # noqa: FBT002
57
57
  ):
58
58
  """Initialize snapshot methods."""
59
59
  self.init_worker(log_queue, librarian_queue)
@@ -72,7 +72,7 @@ class DatabasePollingEmitter(EventEmitter, WorkerBaseMixin):
72
72
  # default stat and listdir params
73
73
  )
74
74
 
75
- def poll(self, force=False):
75
+ def poll(self, force: bool):
76
76
  """Poll now, sooner than timeout."""
77
77
  self._force = force
78
78
  with self._poll_cond:
@@ -118,7 +118,7 @@ class DatabasePollingEmitter(EventEmitter, WorkerBaseMixin):
118
118
  return ok
119
119
 
120
120
  @property
121
- def timeout(self) -> int | None: # type: ignore
121
+ def timeout(self) -> int | None: # type: ignore[reportIncompatibleMethodOverride]
122
122
  """Get the timeout for this emitter from its library."""
123
123
  # The timeout from the constructor, self._timeout, is thrown away in favor
124
124
  # of a dynamic timeout from the database.
@@ -1,4 +1,5 @@
1
- """Batch watchdog events into bulk database tasks.
1
+ """
2
+ Batch watchdog events into bulk database tasks.
2
3
 
3
4
  Watchdog actually starts events as bulk events with the DirSnapshotDiff
4
5
  but the built-in filesystem event emitters serialize them, so the most
@@ -198,8 +198,7 @@ class CodexLibraryEventHandler(CodexEventHandlerBase):
198
198
  task = WatchdogEventTask(self.library_pk, sub_event)
199
199
  self.librarian_queue.put(task)
200
200
 
201
- # Calls stub event dispatchers
202
- # super().dispatch(event)
201
+ # Do not call super dispatch to call stub event dispatchers
203
202
  except Exception:
204
203
  self.log.exception(f"{self.__class__.__name__} dispatch")
205
204
 
@@ -1,5 +1,6 @@
1
1
  """The Codex Library Watchdog Observer threads."""
2
2
 
3
+ from watchdog.events import FileSystemEvent, FileSystemEventHandler
3
4
  from watchdog.observers import Observer
4
5
  from watchdog.observers.api import (
5
6
  DEFAULT_OBSERVER_TIMEOUT,
@@ -98,14 +99,16 @@ class UatuMixin(BaseObserver, WorkerBaseMixin):
98
99
  except Exception:
99
100
  self.log.exception(f"{self.__class__.__name__} sync library watches")
100
101
 
101
- def schedule( # type: ignore
102
+ def schedule(
102
103
  self,
103
- event_handler,
104
- path,
105
- recursive=False,
106
- _event_filter=None,
107
- ):
108
- """Override BaseObserver for Codex emitter class.
104
+ event_handler: FileSystemEventHandler,
105
+ path: str,
106
+ *,
107
+ recursive: bool = False,
108
+ event_filter: list[type[FileSystemEvent]] | None = None, # noqa: ARG002, F841, RUF100
109
+ ) -> ObservedWatch:
110
+ """
111
+ Override BaseObserver for Codex emitter class.
109
112
 
110
113
  https://pythonhosted.org/watchdog/_modules/watchdog/observers/api.html#BaseObserver
111
114
  """
@@ -137,9 +140,11 @@ class UatuMixin(BaseObserver, WorkerBaseMixin):
137
140
  # watchdog class structure doesn't work that way.
138
141
 
139
142
 
140
- class LibraryEventObserver(UatuMixin, Observer): # type: ignore
143
+ class LibraryEventObserver(UatuMixin, Observer): # type: ignore[reportGeneralTypeIssues]
141
144
  """Regular observer."""
142
145
 
146
+ # Observer is a dynamically generated class by platform at runtime.
147
+
143
148
  ENABLE_FIELD = "events"
144
149
 
145
150
 
@@ -156,7 +161,7 @@ class LibraryPollingObserver(UatuMixin):
156
161
  *args, emitter_class=DatabasePollingEmitter, timeout=timeout, **kwargs
157
162
  )
158
163
 
159
- def poll(self, library_pks, force=False):
164
+ def poll(self, library_pks, force: bool):
160
165
  """Poll each requested emitter."""
161
166
  try:
162
167
  qs = Library.objects.all()
@@ -165,7 +170,7 @@ class LibraryPollingObserver(UatuMixin):
165
170
  paths = frozenset(qs.values_list("path", flat=True))
166
171
 
167
172
  for emitter in self.emitters:
168
- polling_emitter: DatabasePollingEmitter = emitter # type: ignore
173
+ polling_emitter: DatabasePollingEmitter = emitter # type: ignore[reportAssignmentType]
169
174
  if emitter.watch.path in paths:
170
175
  polling_emitter.poll(force)
171
176
  except Exception:
codex/logger/logging.py CHANGED
@@ -20,7 +20,7 @@ class CodexQueueHandler(QueueHandler):
20
20
  super().enqueue(record)
21
21
 
22
22
 
23
- LOG_HANDLER = CodexQueueHandler(LOG_QUEUE) # type: ignore
23
+ LOG_HANDLER = CodexQueueHandler(LOG_QUEUE)
24
24
 
25
25
 
26
26
  def _ensure_handler(logger, queue):
codex/memory.py CHANGED
@@ -26,7 +26,7 @@ def get_cgroups1_mem_limit():
26
26
  with Path(MEMORY_STAT_PATH).open("r") as mem_stat_file:
27
27
  for line in mem_stat_file:
28
28
  parts = line.split()
29
- if not parts or len(parts) < 2: # noqa PLR2004
29
+ if not parts or len(parts) < 2: # noqa: PLR2004
30
30
  continue
31
31
  if "hierarchical_memory_limit" in parts[0]:
32
32
  return int(parts[1])
@@ -34,7 +34,8 @@ def get_cgroups1_mem_limit():
34
34
 
35
35
 
36
36
  def get_mem_limit(divisor="b"):
37
- """Get the current memlimit.
37
+ """
38
+ Get the current memlimit.
38
39
 
39
40
  If we're in a container set the limit too.
40
41
  """
@@ -632,8 +632,7 @@ class Migration(migrations.Migration):
632
632
  default=None,
633
633
  max_length=6,
634
634
  null=True,
635
- # Removed in the future
636
- # validators=[codex.models.validate_fit_to_choice],
635
+ # Old code dependent validators removed in the future
637
636
  ),
638
637
  ),
639
638
  ("two_pages", models.BooleanField(default=None, null=True)),
@@ -151,8 +151,7 @@ class Migration(migrations.Migration):
151
151
  field=models.CharField(
152
152
  default="comic",
153
153
  max_length=5,
154
- # Removed in the future
155
- # validators=[codex.models.validate_file_format_choice],
154
+ # codex dependent validators removed in the future
156
155
  ),
157
156
  ),
158
157
  migrations.AddField(
@@ -28,8 +28,7 @@ class Migration(migrations.Migration):
28
28
  blank=True,
29
29
  default="",
30
30
  max_length=6,
31
- # removed in the future
32
- # validators=[codex.models.validate_fit_to_choice],
31
+ # Code dependent validators removed in the future
33
32
  ),
34
33
  ),
35
34
  migrations.AlterField(
@@ -1,16 +1,12 @@
1
1
  """Generated by Django 5.0.6 on 2024-07-02 21:01."""
2
2
 
3
- from typing import ClassVar
4
-
5
3
  from django.db import migrations, models
6
4
 
7
5
 
8
6
  class Migration(migrations.Migration):
9
7
  """Migrate db."""
10
8
 
11
- dependencies: ClassVar[list] = [ # type: ignore
12
- ("codex", "0027_import_order_and_covers"),
13
- ]
9
+ dependencies = [("codex", "0027_import_order_and_covers")]
14
10
 
15
11
  operations = [
16
12
  migrations.AlterField(
codex/models/base.py CHANGED
@@ -27,9 +27,11 @@ class BaseModel(Model):
27
27
  updated_at = DateTimeField(auto_now=True)
28
28
  objects = GroupByManager()
29
29
 
30
- class Meta(ModelBase): # type: ignore
30
+ class Meta(ModelBase): # type: ignore[reportIncompatibleVariableOverride]
31
31
  """Without this a real table is created and joined to."""
32
32
 
33
+ # Model.Meta is not inheritable.
34
+
33
35
  abstract = True
34
36
  get_latest_by = "updated_at"
35
37
 
codex/models/bookmark.py CHANGED
@@ -23,18 +23,15 @@ def cascade_if_user_null(
23
23
  sub_objs,
24
24
  using, # noqa: ARG001
25
25
  ):
26
- """Cascade only if the user field is null.
26
+ """
27
+ Cascade only if the user field is null.
27
28
 
28
29
  Do this to keep deleting ephemeral session data from Bookmark table.
29
30
  Adapted from:
30
31
  https://github.com/django/django/blob/master/django/db/models/deletion.py#L23
31
32
  """
32
- null_user_sub_objs = []
33
- for sub_obj in sub_objs:
34
- # only cascade the ones with null user fields.
35
- if sub_obj.user is None:
36
- null_user_sub_objs.append(sub_obj)
37
-
33
+ # only cascade the ones with null user fields.
34
+ null_user_sub_objs = [sub_obj for sub_obj in sub_objs if sub_obj.user is None]
38
35
  if null_user_sub_objs:
39
36
  collector.collect(
40
37
  null_user_sub_objs,
codex/models/comic.py CHANGED
@@ -263,7 +263,7 @@ class Comic(WatchedPathBrowserGroup):
263
263
 
264
264
  @classmethod
265
265
  def get_title(
266
- cls, obj, volume=True, zero_pad=None, name=True, filename_fallback=False
266
+ cls, obj, volume: bool, name: bool, filename_fallback: bool, zero_pad=None
267
267
  ):
268
268
  """Create the comic title for display."""
269
269
  names = []
@@ -293,7 +293,7 @@ class Comic(WatchedPathBrowserGroup):
293
293
 
294
294
  def __str__(self):
295
295
  """Most common text representation for logging."""
296
- return self.get_title(self, filename_fallback=True)
296
+ return self.get_title(self, volume=True, name=True, filename_fallback=True)
297
297
 
298
298
  def issue(self) -> str:
299
299
  """Combine issue parts for search."""
codex/models/functions.py CHANGED
@@ -14,7 +14,10 @@ class JsonGroupArray(Aggregate):
14
14
  allow_distinct = True
15
15
  function = "JSON_GROUP_ARRAY"
16
16
  name = "JsonGroupArray"
17
- output_field = JSONField() # type: ignore
17
+
18
+ def __init__(self, *args, **kwargs):
19
+ """output_field is set in the constructor."""
20
+ super().__init__(*args, output_field=JSONField(), **kwargs)
18
21
 
19
22
 
20
23
  class GroupConcat(Aggregate):
@@ -25,7 +28,10 @@ class GroupConcat(Aggregate):
25
28
  allow_distinct = True
26
29
  function = "GROUP_CONCAT"
27
30
  name = "GroupConcat"
28
- output_field = CharField() # type: ignore
31
+
32
+ def __init__(self, *args, **kwargs):
33
+ """output_field is set in the constructor."""
34
+ super().__init__(*args, output_field=CharField(), **kwargs)
29
35
 
30
36
 
31
37
  @OneToOneField.register_lookup
@@ -36,8 +42,6 @@ class FTS5Match(Lookup):
36
42
 
37
43
  def as_sql(self, compiler, connection):
38
44
  """Generate MATCH sql."""
39
- # lhs, lhs_params = self.process_lhs(compiler, connection)
40
- # fts_table = lhs.split(".")[0]
41
45
  rhs, rhs_params = self.process_rhs(compiler, connection)
42
46
  # MATCH works on the table itself not the one_to_one rel.
43
47
  # Force the table name without substitutions by the optimizer
@@ -67,4 +71,7 @@ class ComicFTSRank(Func):
67
71
 
68
72
  function = "rank"
69
73
  template = '("codex_comicfts"."rank" * -1)'
70
- output_field = FloatField() # type: ignore
74
+
75
+ def __init__(self, *args, **kwargs):
76
+ """output_field is set in the constructor."""
77
+ super().__init__(*args, output_field=FloatField(), **kwargs)
codex/models/groups.py CHANGED
@@ -136,7 +136,7 @@ class WatchedPathBrowserGroup(BrowserGroupModel, WatchedPath):
136
136
  super().presave()
137
137
  WatchedPath.presave(self)
138
138
 
139
- class Meta(WatchedPath.Meta): # type: ignore
139
+ class Meta(BrowserGroupModel.Meta, WatchedPath.Meta):
140
140
  """Use Mixin Meta."""
141
141
 
142
142
  abstract = True
codex/models/library.py CHANGED
@@ -23,7 +23,7 @@ __all__ = ("Library", "validate_dir_exists")
23
23
  def validate_dir_exists(path):
24
24
  """Validate that a library exists."""
25
25
  if not Path(path).is_dir():
26
- raise ValidationError(_(f"{path} is not a directory"), params={"path": path})
26
+ raise ValidationError(_("{path} is not a directory"), params={"path": path})
27
27
 
28
28
 
29
29
  class Library(BaseModel):
codex/models/paths.py CHANGED
@@ -36,11 +36,11 @@ class WatchedPath(BaseModel):
36
36
  st[0] = st_record.st_mode
37
37
  st[1] = st_record.st_ino
38
38
  # st[2] = st_record.st_dev is ignored by diff
39
- # st[3] = st_record.st_nlink
40
- # st[4] = st_record.st_uid
41
- # st[5] = st_record.st_gid
39
+ # st[3] = st_record.st_nlink ignored
40
+ # st[4] = st_record.st_uid ignored
41
+ # st[5] = st_record.st_gid ignored
42
42
  st[6] = st_record.st_size
43
- # st[7] = st_record.st_atime
43
+ # st[7] = st_record.st_atime ignored
44
44
  st[8] = st_record.st_mtime
45
45
  self.stat = st
46
46
 
codex/models/query.py CHANGED
@@ -45,7 +45,7 @@ class GroupByQuery(Query):
45
45
  self.force_group_by_table = ""
46
46
  self.force_group_by_fields = ()
47
47
 
48
- def get_compiler(self, using=None, connection=None, elide_empty=True):
48
+ def get_compiler(self, using=None, connection=None, elide_empty=True): # noqa: FBT002
49
49
  """Use the custom compiler instead of SQLCompiler."""
50
50
  if self.compiler == "SQLCompiler":
51
51
  if using is None and connection is None:
@@ -59,7 +59,11 @@ class GroupByQuery(Query):
59
59
  )
60
60
  else:
61
61
  # Normal super() operation.
62
- compiler = super().get_compiler(using, connection, elide_empty) # type: ignore
62
+ compiler = super().get_compiler(
63
+ using=using,
64
+ connection=connection,
65
+ elide_empty=elide_empty, # type: ignore[reportCallIssue]
66
+ )
63
67
 
64
68
  return compiler
65
69
 
@@ -82,13 +86,13 @@ class GroupByQuerySet(QuerySet):
82
86
 
83
87
  def group_by(self, *fields, model=None):
84
88
  """Force group_by operator."""
85
- obj = self._chain() # type: ignore
89
+ obj = self._chain() # type: ignore[reportAttributeAccessIssue]
86
90
  obj.query.set_force_group_by(fields, model=model)
87
91
  return obj
88
92
 
89
93
  def demote_joins(self, tables):
90
94
  """Force INNER JOINS."""
91
- obj = self._chain() # type: ignore
95
+ obj = self._chain() # type: ignore[reportAttributeAccessIssue]
92
96
  obj.query.demote_joins(tables)
93
97
  return obj
94
98
 
codex/models/util.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Utilities for models."""
2
2
 
3
3
  _ARTICLES = frozenset(
4
- ("a", "an", "the") # en # noqa RUF005
4
+ ("a", "an", "the") # en # noqa: RUF005
5
5
  + ("un", "unos", "unas", "el", "los", "la", "las") # es
6
6
  + ("un", "une", "le", "les", "la", "les", "l'") # fr
7
7
  + ("o", "a", "os") # pt
codex/permissions.py CHANGED
@@ -8,7 +8,7 @@ from codex.models import Timestamp
8
8
  class HasAPIKeyOrIsAdminUser(BasePermission):
9
9
  """Does the request have the current api key."""
10
10
 
11
- def has_permission(self, request, view): # type: ignore
11
+ def has_permission(self, request, view):
12
12
  """Test the request api key against the database."""
13
13
  data = request.GET if request.method == "GET" else request.POST
14
14
  api_key = data.get("apiKey")
codex/run.py CHANGED
@@ -63,7 +63,7 @@ def run():
63
63
  serve(
64
64
  application,
65
65
  HYPERCORN_CONFIG,
66
- shutdown_trigger=SHUTDOWN_EVENT.wait, # type: ignore
66
+ shutdown_trigger=SHUTDOWN_EVENT.wait,
67
67
  )
68
68
  )
69
69
  librarian.stop()
@@ -85,6 +85,4 @@ class AdminFolderSerializer(Serializer):
85
85
 
86
86
  def validate_show_hidden(self, show_hidden):
87
87
  """Snakecase the showHidden field."""
88
- return (
89
- show_hidden == "true" or self.initial_data.get("showHidden") == "true" # type: ignore
90
- )
88
+ return show_hidden == "true" or self.initial_data.get("showHidden") == "true"
@@ -19,8 +19,8 @@ FILE_TYPES_CHOICES = ("CBZ", "CBR", "CBT", "PDF", "UNKNOWN")
19
19
  class StatsSystemSerializer(Serializer):
20
20
  """Platform System Information."""
21
21
 
22
- name = CharField(required=False, read_only=True)
23
- release = CharField(required=False, read_only=True)
22
+ name = CharField(read_only=True, required=False)
23
+ release = CharField(read_only=True, required=False)
24
24
 
25
25
 
26
26
  class StatsPlatformSerializer(Serializer):
@@ -42,7 +42,7 @@ class StatsConfigSerializer(Serializer):
42
42
  user_registered_count = IntegerField(required=False, read_only=True)
43
43
  auth_group_count = IntegerField(required=False, read_only=True)
44
44
  # Only for api
45
- api_key = CharField(required=False, read_only=True)
45
+ api_key = CharField(read_only=True, required=False)
46
46
 
47
47
 
48
48
  class StatsSessionsSerializer(Serializer):
@@ -123,4 +123,4 @@ class AdminStatsRequestSerializer(Serializer):
123
123
  class APIKeySerializer(Serializer):
124
124
  """API Key."""
125
125
 
126
- api_key = CharField(source="name")
126
+ api_key = CharField(source="name", read_only=True)
codex/serializers/auth.py CHANGED
@@ -8,6 +8,8 @@ from rest_framework.serializers import (
8
8
  )
9
9
 
10
10
  from codex.models import AdminFlag
11
+ from codex.serializers.fields.auth import TimezoneField
12
+ from codex.serializers.fields.sanitized import SanitizedCharField
11
13
  from codex.serializers.models.base import BaseModelSerializer
12
14
 
13
15
 
@@ -49,7 +51,7 @@ class UserSerializer(BaseModelSerializer):
49
51
  class TimezoneSerializer(Serializer):
50
52
  """Serialize Timezone submission from front end."""
51
53
 
52
- timezone = CharField(min_length=2)
54
+ timezone = TimezoneField(write_only=True)
53
55
 
54
56
 
55
57
  class UserCreateSerializer(BaseModelSerializer, TimezoneSerializer):
@@ -67,7 +69,7 @@ class UserLoginSerializer(UserCreateSerializer):
67
69
  """Serialize user login input."""
68
70
 
69
71
  # specify this so it doesn't trigger the username unique constraint.
70
- username = CharField(min_length=2)
72
+ username = SanitizedCharField(min_length=2)
71
73
 
72
74
  class Meta(UserCreateSerializer.Meta):
73
75
  """Explicit meta inheritance required."""
@@ -2,28 +2,106 @@
2
2
 
3
3
  from types import MappingProxyType
4
4
 
5
- from rest_framework.fields import ListField, SerializerMethodField
6
- from rest_framework.serializers import CharField, Serializer
5
+ from rest_framework.fields import (
6
+ BooleanField,
7
+ CharField,
8
+ ListField,
9
+ SerializerMethodField,
10
+ )
11
+ from rest_framework.serializers import Serializer
7
12
 
8
- from codex.serializers.browser.filters import BrowserSettingsFilterSerializer
9
13
  from codex.serializers.fields import (
14
+ VuetifyBooleanField,
10
15
  VuetifyCharField,
16
+ VuetifyDecadeField,
17
+ VuetifyFloatField,
11
18
  VuetifyIntegerField,
12
19
  )
20
+ from codex.serializers.fields.browser import BookmarkFilterField
13
21
  from codex.serializers.models.pycountry import CountrySerializer, LanguageSerializer
14
22
 
15
23
 
16
- class BrowserChoicesCharPkSerializer(Serializer):
24
+ class BrowserFilterChoicesSerializer(Serializer):
25
+ """All dynamic filters."""
26
+
27
+ age_rating = BooleanField(read_only=True)
28
+ community_rating = BooleanField(read_only=True)
29
+ characters = BooleanField(read_only=True)
30
+ country = BooleanField(read_only=True)
31
+ critical_rating = BooleanField(read_only=True)
32
+ contributors = BooleanField(read_only=True)
33
+ decade = BooleanField(read_only=True)
34
+ genres = BooleanField(read_only=True)
35
+ file_type = BooleanField(read_only=True)
36
+ identifier_type = BooleanField(read_only=True)
37
+ monochrome = BooleanField(read_only=True)
38
+ language = BooleanField(read_only=True)
39
+ locations = BooleanField(read_only=True)
40
+ original_format = BooleanField(read_only=True)
41
+ reading_direction = BooleanField(read_only=True)
42
+ series_groups = BooleanField(read_only=True)
43
+ stories = BooleanField(read_only=True)
44
+ story_arcs = BooleanField(read_only=True)
45
+ tagger = BooleanField(read_only=True)
46
+ tags = BooleanField(read_only=True)
47
+ teams = BooleanField(read_only=True)
48
+ year = BooleanField(read_only=True)
49
+
50
+
51
+ class BrowserSettingsFilterSerializer(Serializer):
52
+ """Filter values for settings."""
53
+
54
+ bookmark = BookmarkFilterField(required=False, read_only=True)
55
+ # Dynamic filters
56
+ age_rating = ListField(child=VuetifyCharField(), required=False, read_only=True)
57
+ characters = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
58
+ community_rating = ListField(
59
+ child=VuetifyFloatField(), required=False, read_only=True
60
+ )
61
+ country = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
62
+ contributors = ListField(
63
+ child=VuetifyIntegerField(), required=False, read_only=True
64
+ )
65
+ critical_rating = ListField(
66
+ child=VuetifyFloatField(), required=False, read_only=True
67
+ )
68
+ decade = ListField(child=VuetifyDecadeField(), required=False, read_only=True)
69
+ file_type = ListField(child=VuetifyCharField(), required=False, read_only=True)
70
+ genres = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
71
+ identifier_type = ListField(
72
+ child=VuetifyCharField(), required=False, read_only=True
73
+ )
74
+ language = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
75
+ locations = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
76
+ monochrome = ListField(child=VuetifyBooleanField(), required=False, read_only=True)
77
+ original_format = ListField(
78
+ child=VuetifyCharField(), required=False, read_only=True
79
+ )
80
+ reading_direction = ListField(
81
+ child=VuetifyCharField(), required=False, read_only=True
82
+ )
83
+ series_groups = ListField(
84
+ child=VuetifyIntegerField(), required=False, read_only=True
85
+ )
86
+ stories = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
87
+ story_arcs = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
88
+ tagger = ListField(child=VuetifyCharField(), required=False, read_only=True)
89
+ tags = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
90
+ teams = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
91
+ year = ListField(child=VuetifyIntegerField(), required=False, read_only=True)
92
+
93
+
94
+ class BrowserChoicesIntegerPkSerializer(Serializer):
17
95
  """Named Model Serializer."""
18
96
 
19
- pk = VuetifyCharField(read_only=True)
97
+ pk = VuetifyIntegerField(read_only=True)
20
98
  name = CharField(read_only=True)
21
99
 
22
100
 
23
- class BrowserChoicesIntegerPkSerializer(BrowserChoicesCharPkSerializer):
101
+ class BrowserChoicesCharPkSerializer(BrowserChoicesIntegerPkSerializer):
24
102
  """Named Model Serailizer with pk = char hack for languages & countries."""
25
103
 
26
- pk = VuetifyIntegerField(read_only=True)
104
+ pk = VuetifyCharField(read_only=True)
27
105
 
28
106
 
29
107
  _CHOICES_NAME_SERIALIZER_MAP = MappingProxyType(
@@ -50,9 +128,9 @@ class BrowserChoicesFilterSerializer(Serializer):
50
128
  if serializer_class:
51
129
  value = serializer_class(choices, many=True).data
52
130
  elif not serializer_class and field_name in _LIST_FIELDS:
53
- field: ListField = (
131
+ field: ListField = ( # type: ignore[reportAssignmentType]
54
132
  BrowserSettingsFilterSerializer().get_fields().get(field_name)
55
- ) # type: ignore
133
+ )
56
134
  value = field.to_representation(choices)
57
135
  else:
58
136
  value = BrowserChoicesIntegerPkSerializer(choices, many=True).data