codex 1.7.3a1__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 (757) 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/migrations/0031_adminflag_banner.py +1 -1
  50. codex/models/admin.py +1 -1
  51. codex/models/base.py +3 -1
  52. codex/models/bookmark.py +4 -7
  53. codex/models/comic.py +2 -2
  54. codex/models/functions.py +12 -5
  55. codex/models/groups.py +1 -1
  56. codex/models/library.py +1 -1
  57. codex/models/paths.py +4 -4
  58. codex/models/query.py +8 -4
  59. codex/models/util.py +1 -1
  60. codex/permissions.py +1 -1
  61. codex/run.py +1 -1
  62. codex/serializers/admin/libraries.py +1 -3
  63. codex/serializers/admin/stats.py +4 -4
  64. codex/serializers/auth.py +4 -2
  65. codex/serializers/browser/choices.py +87 -9
  66. codex/serializers/browser/filters.py +9 -37
  67. codex/serializers/browser/metadata.py +2 -1
  68. codex/serializers/browser/mixins.py +7 -3
  69. codex/serializers/browser/mtime.py +3 -5
  70. codex/serializers/browser/page.py +5 -4
  71. codex/serializers/browser/settings.py +7 -5
  72. codex/serializers/fields/__init__.py +37 -0
  73. codex/serializers/fields/auth.py +45 -0
  74. codex/serializers/fields/browser.py +85 -0
  75. codex/serializers/fields/group.py +13 -0
  76. codex/serializers/fields/reader.py +22 -0
  77. codex/serializers/fields/sanitized.py +13 -0
  78. codex/serializers/fields/session.py +15 -0
  79. codex/serializers/fields/stats.py +36 -0
  80. codex/serializers/fields/vuetify.py +62 -0
  81. codex/serializers/models/base.py +1 -1
  82. codex/serializers/models/comic.py +2 -2
  83. codex/serializers/models/groups.py +0 -2
  84. codex/serializers/models/named.py +1 -1
  85. codex/serializers/models/pycountry.py +1 -1
  86. codex/serializers/opds/authentication.py +4 -2
  87. codex/serializers/opds/urls.py +2 -1
  88. codex/serializers/opds/v1.py +4 -3
  89. codex/serializers/opds/v2/feed.py +2 -1
  90. codex/serializers/opds/v2/links.py +23 -21
  91. codex/serializers/opds/v2/metadata.py +4 -8
  92. codex/serializers/opds/v2/progression.py +5 -3
  93. codex/serializers/opds/v2/publication.py +16 -18
  94. codex/serializers/opds/v2/unused.py +15 -8
  95. codex/serializers/reader.py +16 -14
  96. codex/serializers/redirect.py +2 -1
  97. codex/serializers/route.py +6 -4
  98. codex/serializers/settings.py +5 -3
  99. codex/serializers/versions.py +2 -1
  100. codex/settings/settings.py +4 -3
  101. codex/signals/django_signals.py +1 -1
  102. codex/static_root/assets/{VCheckbox-BV02IXFk.7b1ac0cc0c68.js → VCheckbox-CtTi6T7d.87331fa7e77f.js} +1 -1
  103. codex/static_root/assets/VCheckbox-CtTi6T7d.87331fa7e77f.js.br +0 -0
  104. codex/static_root/assets/VCheckbox-CtTi6T7d.87331fa7e77f.js.gz +0 -0
  105. codex/static_root/assets/{VCheckbox-BV02IXFk.js → VCheckbox-CtTi6T7d.js} +1 -1
  106. codex/static_root/assets/VCheckbox-CtTi6T7d.js.br +0 -0
  107. codex/static_root/assets/VCheckbox-CtTi6T7d.js.gz +0 -0
  108. codex/static_root/assets/{VCheckboxBtn-DRCMElDO.e3bc3b165786.js → VCheckboxBtn-DQafuWTH.dada5e0634ef.js} +1 -1
  109. codex/static_root/assets/VCheckboxBtn-DQafuWTH.dada5e0634ef.js.br +0 -0
  110. codex/static_root/assets/VCheckboxBtn-DQafuWTH.dada5e0634ef.js.gz +0 -0
  111. codex/static_root/assets/{VCheckboxBtn-DRCMElDO.js → VCheckboxBtn-DQafuWTH.js} +1 -1
  112. codex/static_root/assets/VCheckboxBtn-DQafuWTH.js.br +0 -0
  113. codex/static_root/assets/VCheckboxBtn-DQafuWTH.js.gz +0 -0
  114. codex/static_root/assets/{VCombobox-BUzWpAvZ.ec97d55d18d6.js → VCombobox-C6TX3Dhp.e619423a6463.js} +1 -1
  115. codex/static_root/assets/VCombobox-C6TX3Dhp.e619423a6463.js.br +0 -0
  116. codex/static_root/assets/VCombobox-C6TX3Dhp.e619423a6463.js.gz +0 -0
  117. codex/static_root/assets/{VCombobox-BUzWpAvZ.js → VCombobox-C6TX3Dhp.js} +1 -1
  118. codex/static_root/assets/VCombobox-C6TX3Dhp.js.br +0 -0
  119. codex/static_root/assets/VCombobox-C6TX3Dhp.js.gz +0 -0
  120. codex/static_root/assets/{VDialog-CvyPs47z.06bd89160727.js → VDialog-CknWq2kd.b2d301ec6ac5.js} +1 -1
  121. codex/static_root/assets/VDialog-CknWq2kd.b2d301ec6ac5.js.br +0 -0
  122. codex/static_root/assets/VDialog-CknWq2kd.b2d301ec6ac5.js.gz +0 -0
  123. codex/static_root/assets/{VDialog-CvyPs47z.js → VDialog-CknWq2kd.js} +1 -1
  124. codex/static_root/assets/VDialog-CknWq2kd.js.br +0 -0
  125. codex/static_root/assets/VDialog-CknWq2kd.js.gz +0 -0
  126. codex/static_root/assets/{VDivider-DxA4gr8D.a62a378b1691.js → VDivider-F4DUgr74.62bc92cab97d.js} +1 -1
  127. codex/static_root/assets/VDivider-F4DUgr74.62bc92cab97d.js.br +0 -0
  128. codex/static_root/assets/VDivider-F4DUgr74.62bc92cab97d.js.gz +0 -0
  129. codex/static_root/assets/{VDivider-DxA4gr8D.js → VDivider-F4DUgr74.js} +1 -1
  130. codex/static_root/assets/VDivider-F4DUgr74.js.br +0 -0
  131. codex/static_root/assets/VDivider-F4DUgr74.js.gz +0 -0
  132. codex/static_root/assets/{VExpansionPanels-_Hd_Icpj.4670cf36fda0.js → VExpansionPanels-CprYUTGT.39b8a50cde43.js} +1 -1
  133. codex/static_root/assets/VExpansionPanels-CprYUTGT.39b8a50cde43.js.br +0 -0
  134. codex/static_root/assets/VExpansionPanels-CprYUTGT.39b8a50cde43.js.gz +0 -0
  135. codex/static_root/assets/{VExpansionPanels-_Hd_Icpj.js → VExpansionPanels-CprYUTGT.js} +1 -1
  136. codex/static_root/assets/VExpansionPanels-CprYUTGT.js.br +0 -0
  137. codex/static_root/assets/VExpansionPanels-CprYUTGT.js.gz +0 -0
  138. codex/static_root/assets/{VForm-B4doHkrL.1f48583f2de6.js → VForm-DnWAUsrl.4ab0786d658e.js} +1 -1
  139. codex/static_root/assets/VForm-DnWAUsrl.4ab0786d658e.js.br +0 -0
  140. codex/static_root/assets/VForm-DnWAUsrl.4ab0786d658e.js.gz +0 -0
  141. codex/static_root/assets/{VForm-B4doHkrL.js → VForm-DnWAUsrl.js} +1 -1
  142. codex/static_root/assets/VForm-DnWAUsrl.js.br +0 -0
  143. codex/static_root/assets/VForm-DnWAUsrl.js.gz +0 -0
  144. codex/static_root/assets/{VRadioGroup-DT7JWkoW.28cd429e5a15.js → VRadioGroup-D71Rszum.befc87b0c476.js} +1 -1
  145. codex/static_root/assets/VRadioGroup-D71Rszum.befc87b0c476.js.br +0 -0
  146. codex/static_root/assets/VRadioGroup-D71Rszum.befc87b0c476.js.gz +0 -0
  147. codex/static_root/assets/{VRadioGroup-DT7JWkoW.js → VRadioGroup-D71Rszum.js} +1 -1
  148. codex/static_root/assets/VRadioGroup-D71Rszum.js.br +0 -0
  149. codex/static_root/assets/VRadioGroup-D71Rszum.js.gz +0 -0
  150. codex/static_root/assets/{VSelect-DtYhH7Mk.67eae5723992.js → VSelect-CbPDrHNj.4809fbbf00f0.js} +1 -1
  151. codex/static_root/assets/VSelect-CbPDrHNj.4809fbbf00f0.js.br +0 -0
  152. codex/static_root/assets/VSelect-CbPDrHNj.4809fbbf00f0.js.gz +0 -0
  153. codex/static_root/assets/{VSelect-DtYhH7Mk.js → VSelect-CbPDrHNj.js} +1 -1
  154. codex/static_root/assets/VSelect-CbPDrHNj.js.br +0 -0
  155. codex/static_root/assets/VSelect-CbPDrHNj.js.gz +0 -0
  156. codex/static_root/assets/{VSelectionControl-BJm6ORIw.efe501dcf742.js → VSelectionControl-It389cbo.ac75aee480a0.js} +1 -1
  157. codex/static_root/assets/VSelectionControl-It389cbo.ac75aee480a0.js.br +0 -0
  158. codex/static_root/assets/VSelectionControl-It389cbo.ac75aee480a0.js.gz +0 -0
  159. codex/static_root/assets/{VSelectionControl-BJm6ORIw.js → VSelectionControl-It389cbo.js} +1 -1
  160. codex/static_root/assets/VSelectionControl-It389cbo.js.br +0 -0
  161. codex/static_root/assets/VSelectionControl-It389cbo.js.gz +0 -0
  162. codex/static_root/assets/{VTable-Bpr_wGHh.65e8b5288ad7.js → VTable-D9e3lKk6.7cd0760008c7.js} +1 -1
  163. codex/static_root/assets/VTable-D9e3lKk6.7cd0760008c7.js.br +0 -0
  164. codex/static_root/assets/VTable-D9e3lKk6.7cd0760008c7.js.gz +0 -0
  165. codex/static_root/assets/{VTable-Bpr_wGHh.js → VTable-D9e3lKk6.js} +1 -1
  166. codex/static_root/assets/VTable-D9e3lKk6.js.br +0 -0
  167. codex/static_root/assets/VTable-D9e3lKk6.js.gz +0 -0
  168. codex/static_root/assets/{VWindowItem-C1nqmRqv.aa75e27fc15e.js → VWindowItem-B4VZ37cq.e45c5018cc73.js} +1 -1
  169. codex/static_root/assets/VWindowItem-B4VZ37cq.e45c5018cc73.js.br +0 -0
  170. codex/static_root/assets/VWindowItem-B4VZ37cq.e45c5018cc73.js.gz +0 -0
  171. codex/static_root/assets/{VWindowItem-C1nqmRqv.js → VWindowItem-B4VZ37cq.js} +1 -1
  172. codex/static_root/assets/VWindowItem-B4VZ37cq.js.br +0 -0
  173. codex/static_root/assets/VWindowItem-B4VZ37cq.js.gz +0 -0
  174. codex/static_root/assets/{admin-Do4UwPej.6beffbe88dd0.js → admin-Bkd8zuSF.2a29386f3488.js} +1 -1
  175. codex/static_root/assets/admin-Bkd8zuSF.2a29386f3488.js.br +0 -0
  176. codex/static_root/assets/admin-Bkd8zuSF.2a29386f3488.js.gz +0 -0
  177. codex/static_root/assets/{admin-Do4UwPej.js → admin-Bkd8zuSF.js} +1 -1
  178. codex/static_root/assets/admin-Bkd8zuSF.js.br +0 -0
  179. codex/static_root/assets/admin-Bkd8zuSF.js.gz +0 -0
  180. codex/static_root/assets/{admin-BYCwfr2h.581e490b1ec8.js → admin-CFTKGwmx.18915c5df4d3.js} +1 -1
  181. codex/static_root/assets/admin-CFTKGwmx.18915c5df4d3.js.br +0 -0
  182. codex/static_root/assets/admin-CFTKGwmx.18915c5df4d3.js.gz +0 -0
  183. codex/static_root/assets/{admin-BYCwfr2h.js → admin-CFTKGwmx.js} +1 -1
  184. codex/static_root/assets/admin-CFTKGwmx.js.br +0 -0
  185. codex/static_root/assets/admin-CFTKGwmx.js.gz +0 -0
  186. codex/static_root/assets/{admin-menu-DyaS3ZkH.34c055460f79.js → admin-menu-CxZqtPES.7b3a06ce4b92.js} +1 -1
  187. codex/static_root/assets/admin-menu-CxZqtPES.7b3a06ce4b92.js.br +0 -0
  188. codex/static_root/assets/admin-menu-CxZqtPES.7b3a06ce4b92.js.gz +0 -0
  189. codex/static_root/assets/{admin-menu-DyaS3ZkH.js → admin-menu-CxZqtPES.js} +1 -1
  190. codex/static_root/assets/admin-menu-CxZqtPES.js.br +0 -0
  191. codex/static_root/assets/admin-menu-CxZqtPES.js.gz +0 -0
  192. codex/static_root/assets/{admin-settings-button-progress-BKp0yruZ.550d96596ce5.js → admin-settings-button-progress-D2TfW_5T.8a9d411ee79d.js} +1 -1
  193. codex/static_root/assets/admin-settings-button-progress-D2TfW_5T.8a9d411ee79d.js.br +0 -0
  194. codex/static_root/assets/admin-settings-button-progress-D2TfW_5T.8a9d411ee79d.js.gz +0 -0
  195. codex/static_root/assets/{admin-settings-button-progress-BKp0yruZ.js → admin-settings-button-progress-D2TfW_5T.js} +1 -1
  196. codex/static_root/assets/admin-settings-button-progress-D2TfW_5T.js.br +0 -0
  197. codex/static_root/assets/admin-settings-button-progress-D2TfW_5T.js.gz +0 -0
  198. codex/static_root/assets/browser-Br2DgAdi.433cca495d61.js +1 -0
  199. codex/static_root/assets/browser-Br2DgAdi.433cca495d61.js.br +0 -0
  200. codex/static_root/assets/browser-Br2DgAdi.433cca495d61.js.gz +0 -0
  201. codex/static_root/assets/browser-Br2DgAdi.js +1 -0
  202. codex/static_root/assets/browser-Br2DgAdi.js.br +0 -0
  203. codex/static_root/assets/browser-Br2DgAdi.js.gz +0 -0
  204. codex/static_root/assets/{browser-CReWGhn_.521193ab0710.css → browser-DNzQvgkY.aea8b7d7ca40.css} +1 -1
  205. codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.br +0 -0
  206. codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.gz +0 -0
  207. codex/static_root/assets/{browser-CReWGhn_.css → browser-DNzQvgkY.css} +1 -1
  208. codex/static_root/assets/browser-DNzQvgkY.css.br +0 -0
  209. codex/static_root/assets/browser-DNzQvgkY.css.gz +0 -0
  210. codex/static_root/assets/{change-password-dialog-DB0tGBYA.8712454eb2b5.js → change-password-dialog-CSylx5Qb.319466c891c9.js} +1 -1
  211. codex/static_root/assets/change-password-dialog-CSylx5Qb.319466c891c9.js.br +0 -0
  212. codex/static_root/assets/change-password-dialog-CSylx5Qb.319466c891c9.js.gz +0 -0
  213. codex/static_root/assets/{change-password-dialog-DB0tGBYA.js → change-password-dialog-CSylx5Qb.js} +1 -1
  214. codex/static_root/assets/change-password-dialog-CSylx5Qb.js.br +0 -0
  215. codex/static_root/assets/change-password-dialog-CSylx5Qb.js.gz +0 -0
  216. codex/static_root/assets/{confirm-dialog-CUfR1UVh.d59ed57fbf3c.js → confirm-dialog-Bx2R2vgR.d42b6449c495.js} +1 -1
  217. codex/static_root/assets/confirm-dialog-Bx2R2vgR.d42b6449c495.js.br +0 -0
  218. codex/static_root/assets/confirm-dialog-Bx2R2vgR.d42b6449c495.js.gz +0 -0
  219. codex/static_root/assets/{confirm-dialog-CUfR1UVh.js → confirm-dialog-Bx2R2vgR.js} +1 -1
  220. codex/static_root/assets/confirm-dialog-Bx2R2vgR.js.br +0 -0
  221. codex/static_root/assets/confirm-dialog-Bx2R2vgR.js.gz +0 -0
  222. codex/static_root/assets/{datetime-column-DWwCltHX.be3a30e165e2.js → datetime-column-sOrWMDcU.9ad225af18db.js} +1 -1
  223. codex/static_root/assets/datetime-column-sOrWMDcU.9ad225af18db.js.br +2 -0
  224. codex/static_root/assets/datetime-column-sOrWMDcU.9ad225af18db.js.gz +0 -0
  225. codex/static_root/assets/{datetime-column-DWwCltHX.js → datetime-column-sOrWMDcU.js} +1 -1
  226. codex/static_root/assets/datetime-column-sOrWMDcU.js.br +2 -0
  227. codex/static_root/assets/datetime-column-sOrWMDcU.js.gz +0 -0
  228. codex/static_root/assets/{filter-DUzmOcWQ.62e2578018fc.js → filter-SgjvoAvL.094069d6978d.js} +1 -1
  229. codex/static_root/assets/filter-SgjvoAvL.094069d6978d.js.br +0 -0
  230. codex/static_root/assets/filter-SgjvoAvL.094069d6978d.js.gz +0 -0
  231. codex/static_root/assets/{filter-DUzmOcWQ.js → filter-SgjvoAvL.js} +1 -1
  232. codex/static_root/assets/filter-SgjvoAvL.js.br +0 -0
  233. codex/static_root/assets/filter-SgjvoAvL.js.gz +0 -0
  234. codex/static_root/assets/flag-tab-B_0tGWPg.e46d1782b327.js +1 -0
  235. codex/static_root/assets/flag-tab-B_0tGWPg.e46d1782b327.js.br +0 -0
  236. codex/static_root/assets/flag-tab-B_0tGWPg.e46d1782b327.js.gz +0 -0
  237. codex/static_root/assets/flag-tab-B_0tGWPg.js +1 -0
  238. codex/static_root/assets/flag-tab-B_0tGWPg.js.br +0 -0
  239. codex/static_root/assets/flag-tab-B_0tGWPg.js.gz +0 -0
  240. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css +1 -0
  241. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.br +0 -0
  242. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.gz +0 -0
  243. codex/static_root/assets/flag-tab-D2MYXCHk.css +1 -0
  244. codex/static_root/assets/flag-tab-D2MYXCHk.css.br +0 -0
  245. codex/static_root/assets/flag-tab-D2MYXCHk.css.gz +0 -0
  246. codex/static_root/assets/{forwardRefs-hLICxMEm.fd43ec456950.js → forwardRefs-DqbPK1-k.bb9d6863ac16.js} +1 -1
  247. codex/static_root/assets/forwardRefs-DqbPK1-k.bb9d6863ac16.js.br +0 -0
  248. codex/static_root/assets/forwardRefs-DqbPK1-k.bb9d6863ac16.js.gz +0 -0
  249. codex/static_root/assets/{forwardRefs-hLICxMEm.js → forwardRefs-DqbPK1-k.js} +1 -1
  250. codex/static_root/assets/forwardRefs-DqbPK1-k.js.br +0 -0
  251. codex/static_root/assets/forwardRefs-DqbPK1-k.js.gz +0 -0
  252. codex/static_root/assets/{group-tab-Ch6sd19Y.15f92ebc959d.js → group-tab-DXxQUa6C.f1f12f39b167.js} +1 -1
  253. codex/static_root/assets/group-tab-DXxQUa6C.f1f12f39b167.js.br +0 -0
  254. codex/static_root/assets/group-tab-DXxQUa6C.f1f12f39b167.js.gz +0 -0
  255. codex/static_root/assets/{group-tab-Ch6sd19Y.js → group-tab-DXxQUa6C.js} +1 -1
  256. codex/static_root/assets/group-tab-DXxQUa6C.js.br +0 -0
  257. codex/static_root/assets/group-tab-DXxQUa6C.js.gz +0 -0
  258. codex/static_root/assets/{http-error-BQoj78jv.fc5280352b17.js → http-error-BVMwwrFo.a7be6a26c9eb.js} +1 -1
  259. codex/static_root/assets/http-error-BVMwwrFo.a7be6a26c9eb.js.br +0 -0
  260. codex/static_root/assets/http-error-BVMwwrFo.a7be6a26c9eb.js.gz +0 -0
  261. codex/static_root/assets/{http-error-BQoj78jv.js → http-error-BVMwwrFo.js} +1 -1
  262. codex/static_root/assets/http-error-BVMwwrFo.js.br +0 -0
  263. codex/static_root/assets/http-error-BVMwwrFo.js.gz +0 -0
  264. codex/static_root/assets/{index-DtVx0ej4.9ca3e3d32eb8.js → index-DK0lSHDP.86f18c078fa9.js} +1 -1
  265. codex/static_root/assets/index-DK0lSHDP.86f18c078fa9.js.br +0 -0
  266. codex/static_root/assets/index-DK0lSHDP.86f18c078fa9.js.gz +0 -0
  267. codex/static_root/assets/{index-DtVx0ej4.js → index-DK0lSHDP.js} +1 -1
  268. codex/static_root/assets/index-DK0lSHDP.js.br +0 -0
  269. codex/static_root/assets/index-DK0lSHDP.js.gz +0 -0
  270. codex/static_root/assets/{library-tab-DEvrF6PF.c7a68c22664c.js → library-tab-NhXuvZ4F.1e8ac3b7c168.js} +1 -1
  271. codex/static_root/assets/library-tab-NhXuvZ4F.1e8ac3b7c168.js.br +0 -0
  272. codex/static_root/assets/library-tab-NhXuvZ4F.1e8ac3b7c168.js.gz +0 -0
  273. codex/static_root/assets/{library-tab-DEvrF6PF.js → library-tab-NhXuvZ4F.js} +1 -1
  274. codex/static_root/assets/library-tab-NhXuvZ4F.js.br +0 -0
  275. codex/static_root/assets/library-tab-NhXuvZ4F.js.gz +0 -0
  276. codex/static_root/assets/{main-DTplblFl.b8e4b708287f.js → main-CYgubU7H.50aa39cf9565.js} +3 -3
  277. codex/static_root/assets/main-CYgubU7H.50aa39cf9565.js.br +0 -0
  278. codex/static_root/assets/main-CYgubU7H.50aa39cf9565.js.gz +0 -0
  279. codex/static_root/assets/{main-DTplblFl.js → main-CYgubU7H.js} +3 -3
  280. codex/static_root/assets/main-CYgubU7H.js.br +0 -0
  281. codex/static_root/assets/main-CYgubU7H.js.gz +0 -0
  282. codex/static_root/assets/pager-full-pdf---TZiAf5.a6269ab85085.js +1 -0
  283. codex/static_root/assets/pager-full-pdf---TZiAf5.a6269ab85085.js.br +0 -0
  284. codex/static_root/assets/pager-full-pdf---TZiAf5.a6269ab85085.js.gz +0 -0
  285. codex/static_root/assets/pager-full-pdf---TZiAf5.js +1 -0
  286. codex/static_root/assets/pager-full-pdf---TZiAf5.js.br +0 -0
  287. codex/static_root/assets/pager-full-pdf---TZiAf5.js.gz +0 -0
  288. codex/static_root/assets/{pagination-toolbar-DHVJWGeE.c70de5ca6915.js → pagination-toolbar-CeWXU_qA.abe0805da1cc.js} +1 -1
  289. codex/static_root/assets/pagination-toolbar-CeWXU_qA.abe0805da1cc.js.br +0 -0
  290. codex/static_root/assets/pagination-toolbar-CeWXU_qA.abe0805da1cc.js.gz +0 -0
  291. codex/static_root/assets/{pagination-toolbar-DHVJWGeE.js → pagination-toolbar-CeWXU_qA.js} +1 -1
  292. codex/static_root/assets/pagination-toolbar-CeWXU_qA.js.br +0 -0
  293. codex/static_root/assets/pagination-toolbar-CeWXU_qA.js.gz +0 -0
  294. codex/static_root/assets/{pdf-doc-DjtoQWxA.2c9fd3017300.js → pdf-doc-Dws_otkd.d215eca27da5.js} +1 -1
  295. codex/static_root/assets/pdf-doc-Dws_otkd.d215eca27da5.js.br +0 -0
  296. codex/static_root/assets/{pdf-doc-DjtoQWxA.js.gz → pdf-doc-Dws_otkd.d215eca27da5.js.gz} +0 -0
  297. codex/static_root/assets/{pdf-doc-DjtoQWxA.js → pdf-doc-Dws_otkd.js} +1 -1
  298. codex/static_root/assets/pdf-doc-Dws_otkd.js.br +0 -0
  299. codex/static_root/assets/{pdf-doc-DjtoQWxA.2c9fd3017300.js.gz → pdf-doc-Dws_otkd.js.gz} +0 -0
  300. codex/static_root/assets/{reader-DIjUh67D.js → reader-BCxYgZHF.dde3c4ac39a5.js} +2 -2
  301. codex/static_root/assets/reader-BCxYgZHF.dde3c4ac39a5.js.br +0 -0
  302. codex/static_root/assets/reader-BCxYgZHF.dde3c4ac39a5.js.gz +0 -0
  303. codex/static_root/assets/{reader-DIjUh67D.061a8b501e35.js → reader-BCxYgZHF.js} +2 -2
  304. codex/static_root/assets/reader-BCxYgZHF.js.br +0 -0
  305. codex/static_root/assets/reader-BCxYgZHF.js.gz +0 -0
  306. codex/static_root/assets/{relation-chips-ByFsclaN.2b9dc61299f6.js → relation-chips-DNRRCvrw.b1bc75fb9349.js} +1 -1
  307. codex/static_root/assets/relation-chips-DNRRCvrw.b1bc75fb9349.js.br +0 -0
  308. codex/static_root/assets/relation-chips-DNRRCvrw.b1bc75fb9349.js.gz +0 -0
  309. codex/static_root/assets/{relation-chips-ByFsclaN.js → relation-chips-DNRRCvrw.js} +1 -1
  310. codex/static_root/assets/relation-chips-DNRRCvrw.js.br +0 -0
  311. codex/static_root/assets/relation-chips-DNRRCvrw.js.gz +0 -0
  312. codex/static_root/assets/{settings-drawer-DWa5PBWW.js → settings-drawer-BuB29L5p.fe2eeea0058f.js} +2 -2
  313. codex/static_root/assets/settings-drawer-BuB29L5p.fe2eeea0058f.js.br +0 -0
  314. codex/static_root/assets/settings-drawer-BuB29L5p.fe2eeea0058f.js.gz +0 -0
  315. codex/static_root/assets/{settings-drawer-DWa5PBWW.dee5ebeb24fe.js → settings-drawer-BuB29L5p.js} +2 -2
  316. codex/static_root/assets/settings-drawer-BuB29L5p.js.br +0 -0
  317. codex/static_root/assets/settings-drawer-BuB29L5p.js.gz +0 -0
  318. codex/static_root/assets/{stats-tab-B_i6PH1G.js → stats-tab-D0zymxU6.d5267113b51e.js} +1 -1
  319. codex/static_root/assets/stats-tab-D0zymxU6.d5267113b51e.js.br +0 -0
  320. codex/static_root/assets/stats-tab-D0zymxU6.d5267113b51e.js.gz +0 -0
  321. codex/static_root/assets/{stats-tab-B_i6PH1G.f11e0562b20d.js → stats-tab-D0zymxU6.js} +1 -1
  322. codex/static_root/assets/stats-tab-D0zymxU6.js.br +0 -0
  323. codex/static_root/assets/stats-tab-D0zymxU6.js.gz +0 -0
  324. codex/static_root/assets/{task-tab-DOEbnSf2.fe4907da1530.js → task-tab-CI9RLdMS.120f395dc9c6.js} +1 -1
  325. codex/static_root/assets/task-tab-CI9RLdMS.120f395dc9c6.js.br +0 -0
  326. codex/static_root/assets/task-tab-CI9RLdMS.120f395dc9c6.js.gz +0 -0
  327. codex/static_root/assets/{task-tab-DOEbnSf2.js → task-tab-CI9RLdMS.js} +1 -1
  328. codex/static_root/assets/task-tab-CI9RLdMS.js.br +0 -0
  329. codex/static_root/assets/task-tab-CI9RLdMS.js.gz +0 -0
  330. codex/static_root/assets/{unauthorized-Cblht_KD.e0c38cb1a24c.js → unauthorized-BNwg_Xvu.a894b96156e0.js} +1 -1
  331. codex/static_root/assets/unauthorized-BNwg_Xvu.a894b96156e0.js.br +0 -0
  332. codex/static_root/assets/unauthorized-BNwg_Xvu.a894b96156e0.js.gz +0 -0
  333. codex/static_root/assets/{unauthorized-Cblht_KD.js → unauthorized-BNwg_Xvu.js} +1 -1
  334. codex/static_root/assets/unauthorized-BNwg_Xvu.js.br +0 -0
  335. codex/static_root/assets/unauthorized-BNwg_Xvu.js.gz +0 -0
  336. codex/static_root/assets/{user-tab-CdvLJrTe.e52c18781b89.js → user-tab-w9LgIMMi.4a89c7b37486.js} +1 -1
  337. codex/static_root/assets/user-tab-w9LgIMMi.4a89c7b37486.js.br +0 -0
  338. codex/static_root/assets/user-tab-w9LgIMMi.4a89c7b37486.js.gz +0 -0
  339. codex/static_root/assets/{user-tab-CdvLJrTe.js → user-tab-w9LgIMMi.js} +1 -1
  340. codex/static_root/assets/user-tab-w9LgIMMi.js.br +0 -0
  341. codex/static_root/assets/user-tab-w9LgIMMi.js.gz +0 -0
  342. codex/static_root/manifest.514e63b9f805.json +735 -0
  343. codex/static_root/manifest.514e63b9f805.json.br +0 -0
  344. codex/static_root/manifest.514e63b9f805.json.gz +0 -0
  345. codex/static_root/manifest.json +305 -305
  346. codex/static_root/manifest.json.br +0 -0
  347. codex/static_root/manifest.json.gz +0 -0
  348. codex/static_root/staticfiles.json +1 -1
  349. codex/status_controller.py +9 -12
  350. codex/urls/root.py +4 -3
  351. codex/views/admin/api_key.py +1 -4
  352. codex/views/admin/library.py +4 -4
  353. codex/views/admin/stats.py +10 -10
  354. codex/views/admin/tasks.py +9 -9
  355. codex/views/auth.py +3 -8
  356. codex/views/bookmark.py +3 -3
  357. codex/views/browser/annotate/card.py +2 -2
  358. codex/views/browser/annotate/order.py +6 -7
  359. codex/views/browser/bookmark.py +3 -1
  360. codex/views/browser/breadcrumbs.py +6 -5
  361. codex/views/browser/browser.py +2 -2
  362. codex/views/browser/choices.py +6 -7
  363. codex/views/browser/cover.py +6 -3
  364. codex/views/browser/download.py +2 -1
  365. codex/views/browser/filters/bookmark.py +1 -1
  366. codex/views/browser/filters/field.py +1 -1
  367. codex/views/browser/filters/filter.py +6 -8
  368. codex/views/browser/filters/group.py +8 -8
  369. codex/views/browser/filters/search/field/expression.py +1 -2
  370. codex/views/browser/filters/search/field/optimize.py +1 -1
  371. codex/views/browser/filters/search/field/parse.py +2 -2
  372. codex/views/browser/filters/search/parse.py +4 -19
  373. codex/views/browser/group_mtime.py +1 -1
  374. codex/views/browser/metadata/copy_intersections.py +1 -1
  375. codex/views/browser/metadata/metadata.py +1 -1
  376. codex/views/browser/mtime.py +1 -1
  377. codex/views/browser/order_by.py +3 -5
  378. codex/views/browser/params.py +1 -1
  379. codex/views/browser/settings.py +1 -1
  380. codex/views/browser/validate.py +8 -5
  381. codex/views/const.py +0 -3
  382. codex/views/frontend.py +1 -1
  383. codex/views/mixins.py +3 -2
  384. codex/views/opds/authentication_v1.py +1 -1
  385. codex/views/opds/const.py +4 -4
  386. codex/views/opds/util.py +3 -3
  387. codex/views/opds/v1/entry/entry.py +4 -2
  388. codex/views/opds/v1/entry/links.py +4 -5
  389. codex/views/opds/v1/facets.py +8 -4
  390. codex/views/opds/v1/feed.py +5 -5
  391. codex/views/opds/v1/links.py +11 -6
  392. codex/views/opds/v2/const.py +5 -2
  393. codex/views/opds/v2/feed.py +3 -3
  394. codex/views/opds/v2/progression.py +8 -9
  395. codex/views/opds/v2/publications.py +10 -20
  396. codex/views/public.py +1 -1
  397. codex/views/reader/books.py +3 -2
  398. codex/views/reader/page.py +3 -3
  399. codex/views/reader/params.py +2 -2
  400. codex/views/reader/reader.py +6 -6
  401. codex/views/reader/settings.py +1 -1
  402. codex/views/session.py +8 -2
  403. codex/views/settings.py +2 -2
  404. codex/views/timezone.py +2 -2
  405. codex/views/util.py +10 -9
  406. codex/views/version.py +1 -1
  407. {codex-1.7.3a1.dist-info → codex-1.7.4.dist-info}/METADATA +3 -1
  408. {codex-1.7.3a1.dist-info → codex-1.7.4.dist-info}/RECORD +587 -579
  409. {codex-1.7.3a1.dist-info → codex-1.7.4.dist-info}/WHEEL +1 -1
  410. codex/serializers/fields.py +0 -183
  411. codex/static_root/assets/VCheckbox-BV02IXFk.7b1ac0cc0c68.js.br +0 -0
  412. codex/static_root/assets/VCheckbox-BV02IXFk.7b1ac0cc0c68.js.gz +0 -0
  413. codex/static_root/assets/VCheckbox-BV02IXFk.js.br +0 -0
  414. codex/static_root/assets/VCheckbox-BV02IXFk.js.gz +0 -0
  415. codex/static_root/assets/VCheckboxBtn-DRCMElDO.e3bc3b165786.js.br +0 -0
  416. codex/static_root/assets/VCheckboxBtn-DRCMElDO.e3bc3b165786.js.gz +0 -0
  417. codex/static_root/assets/VCheckboxBtn-DRCMElDO.js.br +0 -0
  418. codex/static_root/assets/VCheckboxBtn-DRCMElDO.js.gz +0 -0
  419. codex/static_root/assets/VCombobox-BUzWpAvZ.ec97d55d18d6.js.br +0 -0
  420. codex/static_root/assets/VCombobox-BUzWpAvZ.ec97d55d18d6.js.gz +0 -0
  421. codex/static_root/assets/VCombobox-BUzWpAvZ.js.br +0 -0
  422. codex/static_root/assets/VCombobox-BUzWpAvZ.js.gz +0 -0
  423. codex/static_root/assets/VDialog-CvyPs47z.06bd89160727.js.br +0 -0
  424. codex/static_root/assets/VDialog-CvyPs47z.06bd89160727.js.gz +0 -0
  425. codex/static_root/assets/VDialog-CvyPs47z.js.br +0 -0
  426. codex/static_root/assets/VDialog-CvyPs47z.js.gz +0 -0
  427. codex/static_root/assets/VDivider-DxA4gr8D.a62a378b1691.js.br +0 -0
  428. codex/static_root/assets/VDivider-DxA4gr8D.a62a378b1691.js.gz +0 -0
  429. codex/static_root/assets/VDivider-DxA4gr8D.js.br +0 -0
  430. codex/static_root/assets/VDivider-DxA4gr8D.js.gz +0 -0
  431. codex/static_root/assets/VExpansionPanels-_Hd_Icpj.4670cf36fda0.js.br +0 -0
  432. codex/static_root/assets/VExpansionPanels-_Hd_Icpj.4670cf36fda0.js.gz +0 -0
  433. codex/static_root/assets/VExpansionPanels-_Hd_Icpj.js.br +0 -0
  434. codex/static_root/assets/VExpansionPanels-_Hd_Icpj.js.gz +0 -0
  435. codex/static_root/assets/VForm-B4doHkrL.1f48583f2de6.js.br +0 -0
  436. codex/static_root/assets/VForm-B4doHkrL.1f48583f2de6.js.gz +0 -0
  437. codex/static_root/assets/VForm-B4doHkrL.js.br +0 -0
  438. codex/static_root/assets/VForm-B4doHkrL.js.gz +0 -0
  439. codex/static_root/assets/VRadioGroup-DT7JWkoW.28cd429e5a15.js.br +0 -0
  440. codex/static_root/assets/VRadioGroup-DT7JWkoW.28cd429e5a15.js.gz +0 -0
  441. codex/static_root/assets/VRadioGroup-DT7JWkoW.js.br +0 -0
  442. codex/static_root/assets/VRadioGroup-DT7JWkoW.js.gz +0 -0
  443. codex/static_root/assets/VSelect-DtYhH7Mk.67eae5723992.js.br +0 -0
  444. codex/static_root/assets/VSelect-DtYhH7Mk.67eae5723992.js.gz +0 -0
  445. codex/static_root/assets/VSelect-DtYhH7Mk.js.br +0 -0
  446. codex/static_root/assets/VSelect-DtYhH7Mk.js.gz +0 -0
  447. codex/static_root/assets/VSelectionControl-BJm6ORIw.efe501dcf742.js.br +0 -0
  448. codex/static_root/assets/VSelectionControl-BJm6ORIw.efe501dcf742.js.gz +0 -0
  449. codex/static_root/assets/VSelectionControl-BJm6ORIw.js.br +0 -0
  450. codex/static_root/assets/VSelectionControl-BJm6ORIw.js.gz +0 -0
  451. codex/static_root/assets/VTable-Bpr_wGHh.65e8b5288ad7.js.br +0 -0
  452. codex/static_root/assets/VTable-Bpr_wGHh.65e8b5288ad7.js.gz +0 -0
  453. codex/static_root/assets/VTable-Bpr_wGHh.js.br +0 -0
  454. codex/static_root/assets/VTable-Bpr_wGHh.js.gz +0 -0
  455. codex/static_root/assets/VWindowItem-C1nqmRqv.aa75e27fc15e.js.br +0 -0
  456. codex/static_root/assets/VWindowItem-C1nqmRqv.aa75e27fc15e.js.gz +0 -0
  457. codex/static_root/assets/VWindowItem-C1nqmRqv.js.br +0 -0
  458. codex/static_root/assets/VWindowItem-C1nqmRqv.js.gz +0 -0
  459. codex/static_root/assets/admin-BYCwfr2h.581e490b1ec8.js.br +0 -0
  460. codex/static_root/assets/admin-BYCwfr2h.581e490b1ec8.js.gz +0 -0
  461. codex/static_root/assets/admin-BYCwfr2h.js.br +0 -0
  462. codex/static_root/assets/admin-BYCwfr2h.js.gz +0 -0
  463. codex/static_root/assets/admin-Do4UwPej.6beffbe88dd0.js.br +0 -0
  464. codex/static_root/assets/admin-Do4UwPej.6beffbe88dd0.js.gz +0 -0
  465. codex/static_root/assets/admin-Do4UwPej.js.br +0 -0
  466. codex/static_root/assets/admin-Do4UwPej.js.gz +0 -0
  467. codex/static_root/assets/admin-menu-DyaS3ZkH.34c055460f79.js.br +0 -0
  468. codex/static_root/assets/admin-menu-DyaS3ZkH.34c055460f79.js.gz +0 -0
  469. codex/static_root/assets/admin-menu-DyaS3ZkH.js.br +0 -0
  470. codex/static_root/assets/admin-menu-DyaS3ZkH.js.gz +0 -0
  471. codex/static_root/assets/admin-settings-button-progress-BKp0yruZ.550d96596ce5.js.br +0 -0
  472. codex/static_root/assets/admin-settings-button-progress-BKp0yruZ.550d96596ce5.js.gz +0 -0
  473. codex/static_root/assets/admin-settings-button-progress-BKp0yruZ.js.br +0 -0
  474. codex/static_root/assets/admin-settings-button-progress-BKp0yruZ.js.gz +0 -0
  475. codex/static_root/assets/browser-BcXpHHP5.ef6076284520.js +0 -1
  476. codex/static_root/assets/browser-BcXpHHP5.ef6076284520.js.br +0 -0
  477. codex/static_root/assets/browser-BcXpHHP5.ef6076284520.js.gz +0 -0
  478. codex/static_root/assets/browser-BcXpHHP5.js +0 -1
  479. codex/static_root/assets/browser-BcXpHHP5.js.br +0 -0
  480. codex/static_root/assets/browser-BcXpHHP5.js.gz +0 -0
  481. codex/static_root/assets/browser-CReWGhn_.521193ab0710.css.br +0 -0
  482. codex/static_root/assets/browser-CReWGhn_.521193ab0710.css.gz +0 -0
  483. codex/static_root/assets/browser-CReWGhn_.css.br +0 -0
  484. codex/static_root/assets/browser-CReWGhn_.css.gz +0 -0
  485. codex/static_root/assets/change-password-dialog-DB0tGBYA.8712454eb2b5.js.br +0 -0
  486. codex/static_root/assets/change-password-dialog-DB0tGBYA.8712454eb2b5.js.gz +0 -0
  487. codex/static_root/assets/change-password-dialog-DB0tGBYA.js.br +0 -0
  488. codex/static_root/assets/change-password-dialog-DB0tGBYA.js.gz +0 -0
  489. codex/static_root/assets/confirm-dialog-CUfR1UVh.d59ed57fbf3c.js.br +0 -0
  490. codex/static_root/assets/confirm-dialog-CUfR1UVh.d59ed57fbf3c.js.gz +0 -0
  491. codex/static_root/assets/confirm-dialog-CUfR1UVh.js.br +0 -0
  492. codex/static_root/assets/confirm-dialog-CUfR1UVh.js.gz +0 -0
  493. codex/static_root/assets/datetime-column-DWwCltHX.be3a30e165e2.js.br +0 -2
  494. codex/static_root/assets/datetime-column-DWwCltHX.be3a30e165e2.js.gz +0 -0
  495. codex/static_root/assets/datetime-column-DWwCltHX.js.br +0 -2
  496. codex/static_root/assets/datetime-column-DWwCltHX.js.gz +0 -0
  497. codex/static_root/assets/filter-DUzmOcWQ.62e2578018fc.js.br +0 -0
  498. codex/static_root/assets/filter-DUzmOcWQ.62e2578018fc.js.gz +0 -0
  499. codex/static_root/assets/filter-DUzmOcWQ.js.br +0 -0
  500. codex/static_root/assets/filter-DUzmOcWQ.js.gz +0 -0
  501. codex/static_root/assets/flag-tab-DHGfv0Q3.2b7ef394b850.css +0 -1
  502. codex/static_root/assets/flag-tab-DHGfv0Q3.2b7ef394b850.css.br +0 -0
  503. codex/static_root/assets/flag-tab-DHGfv0Q3.2b7ef394b850.css.gz +0 -0
  504. codex/static_root/assets/flag-tab-DHGfv0Q3.css +0 -1
  505. codex/static_root/assets/flag-tab-DHGfv0Q3.css.br +0 -0
  506. codex/static_root/assets/flag-tab-DHGfv0Q3.css.gz +0 -0
  507. codex/static_root/assets/flag-tab-DI0mJlXh.35d270069e4f.js +0 -1
  508. codex/static_root/assets/flag-tab-DI0mJlXh.35d270069e4f.js.br +0 -0
  509. codex/static_root/assets/flag-tab-DI0mJlXh.35d270069e4f.js.gz +0 -0
  510. codex/static_root/assets/flag-tab-DI0mJlXh.js +0 -1
  511. codex/static_root/assets/flag-tab-DI0mJlXh.js.br +0 -0
  512. codex/static_root/assets/flag-tab-DI0mJlXh.js.gz +0 -0
  513. codex/static_root/assets/forwardRefs-hLICxMEm.fd43ec456950.js.br +0 -0
  514. codex/static_root/assets/forwardRefs-hLICxMEm.fd43ec456950.js.gz +0 -0
  515. codex/static_root/assets/forwardRefs-hLICxMEm.js.br +0 -0
  516. codex/static_root/assets/forwardRefs-hLICxMEm.js.gz +0 -0
  517. codex/static_root/assets/group-tab-Ch6sd19Y.15f92ebc959d.js.br +0 -0
  518. codex/static_root/assets/group-tab-Ch6sd19Y.15f92ebc959d.js.gz +0 -0
  519. codex/static_root/assets/group-tab-Ch6sd19Y.js.br +0 -0
  520. codex/static_root/assets/group-tab-Ch6sd19Y.js.gz +0 -0
  521. codex/static_root/assets/http-error-BQoj78jv.fc5280352b17.js.br +0 -0
  522. codex/static_root/assets/http-error-BQoj78jv.fc5280352b17.js.gz +0 -0
  523. codex/static_root/assets/http-error-BQoj78jv.js.br +0 -0
  524. codex/static_root/assets/http-error-BQoj78jv.js.gz +0 -0
  525. codex/static_root/assets/index-DtVx0ej4.9ca3e3d32eb8.js.br +0 -0
  526. codex/static_root/assets/index-DtVx0ej4.9ca3e3d32eb8.js.gz +0 -0
  527. codex/static_root/assets/index-DtVx0ej4.js.br +0 -0
  528. codex/static_root/assets/index-DtVx0ej4.js.gz +0 -0
  529. codex/static_root/assets/library-tab-DEvrF6PF.c7a68c22664c.js.br +0 -0
  530. codex/static_root/assets/library-tab-DEvrF6PF.c7a68c22664c.js.gz +0 -0
  531. codex/static_root/assets/library-tab-DEvrF6PF.js.br +0 -0
  532. codex/static_root/assets/library-tab-DEvrF6PF.js.gz +0 -0
  533. codex/static_root/assets/main-DTplblFl.b8e4b708287f.js.br +0 -0
  534. codex/static_root/assets/main-DTplblFl.b8e4b708287f.js.gz +0 -0
  535. codex/static_root/assets/main-DTplblFl.js.br +0 -0
  536. codex/static_root/assets/main-DTplblFl.js.gz +0 -0
  537. codex/static_root/assets/pager-full-pdf-JIU1UvrN.627b621aa583.js +0 -1
  538. codex/static_root/assets/pager-full-pdf-JIU1UvrN.627b621aa583.js.br +0 -0
  539. codex/static_root/assets/pager-full-pdf-JIU1UvrN.627b621aa583.js.gz +0 -0
  540. codex/static_root/assets/pager-full-pdf-JIU1UvrN.js +0 -1
  541. codex/static_root/assets/pager-full-pdf-JIU1UvrN.js.br +0 -0
  542. codex/static_root/assets/pager-full-pdf-JIU1UvrN.js.gz +0 -0
  543. codex/static_root/assets/pagination-toolbar-DHVJWGeE.c70de5ca6915.js.br +0 -0
  544. codex/static_root/assets/pagination-toolbar-DHVJWGeE.c70de5ca6915.js.gz +0 -0
  545. codex/static_root/assets/pagination-toolbar-DHVJWGeE.js.br +0 -0
  546. codex/static_root/assets/pagination-toolbar-DHVJWGeE.js.gz +0 -0
  547. codex/static_root/assets/pdf-doc-DjtoQWxA.2c9fd3017300.js.br +0 -0
  548. codex/static_root/assets/pdf-doc-DjtoQWxA.js.br +0 -0
  549. codex/static_root/assets/reader-DIjUh67D.061a8b501e35.js.br +0 -0
  550. codex/static_root/assets/reader-DIjUh67D.061a8b501e35.js.gz +0 -0
  551. codex/static_root/assets/reader-DIjUh67D.js.br +0 -0
  552. codex/static_root/assets/reader-DIjUh67D.js.gz +0 -0
  553. codex/static_root/assets/relation-chips-ByFsclaN.2b9dc61299f6.js.br +0 -0
  554. codex/static_root/assets/relation-chips-ByFsclaN.2b9dc61299f6.js.gz +0 -0
  555. codex/static_root/assets/relation-chips-ByFsclaN.js.br +0 -0
  556. codex/static_root/assets/relation-chips-ByFsclaN.js.gz +0 -0
  557. codex/static_root/assets/settings-drawer-DWa5PBWW.dee5ebeb24fe.js.br +0 -0
  558. codex/static_root/assets/settings-drawer-DWa5PBWW.dee5ebeb24fe.js.gz +0 -0
  559. codex/static_root/assets/settings-drawer-DWa5PBWW.js.br +0 -0
  560. codex/static_root/assets/settings-drawer-DWa5PBWW.js.gz +0 -0
  561. codex/static_root/assets/stats-tab-B_i6PH1G.f11e0562b20d.js.br +0 -0
  562. codex/static_root/assets/stats-tab-B_i6PH1G.f11e0562b20d.js.gz +0 -0
  563. codex/static_root/assets/stats-tab-B_i6PH1G.js.br +0 -0
  564. codex/static_root/assets/stats-tab-B_i6PH1G.js.gz +0 -0
  565. codex/static_root/assets/task-tab-DOEbnSf2.fe4907da1530.js.br +0 -0
  566. codex/static_root/assets/task-tab-DOEbnSf2.fe4907da1530.js.gz +0 -0
  567. codex/static_root/assets/task-tab-DOEbnSf2.js.br +0 -0
  568. codex/static_root/assets/task-tab-DOEbnSf2.js.gz +0 -0
  569. codex/static_root/assets/unauthorized-Cblht_KD.e0c38cb1a24c.js.br +0 -0
  570. codex/static_root/assets/unauthorized-Cblht_KD.e0c38cb1a24c.js.gz +0 -0
  571. codex/static_root/assets/unauthorized-Cblht_KD.js.br +0 -0
  572. codex/static_root/assets/unauthorized-Cblht_KD.js.gz +0 -0
  573. codex/static_root/assets/user-tab-CdvLJrTe.e52c18781b89.js.br +0 -0
  574. codex/static_root/assets/user-tab-CdvLJrTe.e52c18781b89.js.gz +0 -0
  575. codex/static_root/assets/user-tab-CdvLJrTe.js.br +0 -0
  576. codex/static_root/assets/user-tab-CdvLJrTe.js.gz +0 -0
  577. codex/static_root/manifest.e3e070ebb908.json +0 -735
  578. codex/static_root/manifest.e3e070ebb908.json.br +0 -0
  579. codex/static_root/manifest.e3e070ebb908.json.gz +0 -0
  580. /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css → VCheckbox-CvH8ekHL.016ed8d222c4.css} +0 -0
  581. /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css.br → VCheckbox-CvH8ekHL.016ed8d222c4.css.br} +0 -0
  582. /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css.gz → VCheckbox-CvH8ekHL.016ed8d222c4.css.gz} +0 -0
  583. /codex/static_root/assets/{VCheckbox-CMKdyl0R.css → VCheckbox-CvH8ekHL.css} +0 -0
  584. /codex/static_root/assets/{VCheckbox-CMKdyl0R.css.br → VCheckbox-CvH8ekHL.css.br} +0 -0
  585. /codex/static_root/assets/{VCheckbox-CMKdyl0R.css.gz → VCheckbox-CvH8ekHL.css.gz} +0 -0
  586. /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css → VCombobox-BQHELb_o.9f25a34994e2.css} +0 -0
  587. /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css.br → VCombobox-BQHELb_o.9f25a34994e2.css.br} +0 -0
  588. /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css.gz → VCombobox-BQHELb_o.9f25a34994e2.css.gz} +0 -0
  589. /codex/static_root/assets/{VCombobox-bwEYrXCg.css → VCombobox-BQHELb_o.css} +0 -0
  590. /codex/static_root/assets/{VCombobox-bwEYrXCg.css.br → VCombobox-BQHELb_o.css.br} +0 -0
  591. /codex/static_root/assets/{VCombobox-bwEYrXCg.css.gz → VCombobox-BQHELb_o.css.gz} +0 -0
  592. /codex/static_root/assets/{VDialog-Dyd05WHA.b07aca713774.css → VDialog-DWos4S54.b07aca713774.css} +0 -0
  593. /codex/static_root/assets/{VDialog-Dyd05WHA.b07aca713774.css.br → VDialog-DWos4S54.b07aca713774.css.br} +0 -0
  594. /codex/static_root/assets/{VDialog-Dyd05WHA.b07aca713774.css.gz → VDialog-DWos4S54.b07aca713774.css.gz} +0 -0
  595. /codex/static_root/assets/{VDialog-Dyd05WHA.css → VDialog-DWos4S54.css} +0 -0
  596. /codex/static_root/assets/{VDialog-Dyd05WHA.css.br → VDialog-DWos4S54.css.br} +0 -0
  597. /codex/static_root/assets/{VDialog-Dyd05WHA.css.gz → VDialog-DWos4S54.css.gz} +0 -0
  598. /codex/static_root/assets/{VDivider-DE8MJPGz.3d2e17799e5c.css → VDivider-DU47sRrT.3d2e17799e5c.css} +0 -0
  599. /codex/static_root/assets/{VDivider-DE8MJPGz.3d2e17799e5c.css.br → VDivider-DU47sRrT.3d2e17799e5c.css.br} +0 -0
  600. /codex/static_root/assets/{VDivider-DE8MJPGz.3d2e17799e5c.css.gz → VDivider-DU47sRrT.3d2e17799e5c.css.gz} +0 -0
  601. /codex/static_root/assets/{VDivider-DE8MJPGz.css → VDivider-DU47sRrT.css} +0 -0
  602. /codex/static_root/assets/{VDivider-DE8MJPGz.css.br → VDivider-DU47sRrT.css.br} +0 -0
  603. /codex/static_root/assets/{VDivider-DE8MJPGz.css.gz → VDivider-DU47sRrT.css.gz} +0 -0
  604. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css → VExpansionPanels-RsCANmDP.5b17872981df.css} +0 -0
  605. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css.br → VExpansionPanels-RsCANmDP.5b17872981df.css.br} +0 -0
  606. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css.gz → VExpansionPanels-RsCANmDP.5b17872981df.css.gz} +0 -0
  607. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css → VExpansionPanels-RsCANmDP.css} +0 -0
  608. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css.br → VExpansionPanels-RsCANmDP.css.br} +0 -0
  609. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css.gz → VExpansionPanels-RsCANmDP.css.gz} +0 -0
  610. /codex/static_root/assets/{VForm-v1Gmu6E1.138c0b89b6fc.css → VForm-DxBt30-N.138c0b89b6fc.css} +0 -0
  611. /codex/static_root/assets/{VForm-v1Gmu6E1.138c0b89b6fc.css.br → VForm-DxBt30-N.138c0b89b6fc.css.br} +0 -0
  612. /codex/static_root/assets/{VForm-v1Gmu6E1.138c0b89b6fc.css.gz → VForm-DxBt30-N.138c0b89b6fc.css.gz} +0 -0
  613. /codex/static_root/assets/{VForm-v1Gmu6E1.css → VForm-DxBt30-N.css} +0 -0
  614. /codex/static_root/assets/{VForm-v1Gmu6E1.css.br → VForm-DxBt30-N.css.br} +0 -0
  615. /codex/static_root/assets/{VForm-v1Gmu6E1.css.gz → VForm-DxBt30-N.css.gz} +0 -0
  616. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css → VRadioGroup-Cp9mZ7cb.8e3741381961.css} +0 -0
  617. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css.br → VRadioGroup-Cp9mZ7cb.8e3741381961.css.br} +0 -0
  618. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css.gz → VRadioGroup-Cp9mZ7cb.8e3741381961.css.gz} +0 -0
  619. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css → VRadioGroup-Cp9mZ7cb.css} +0 -0
  620. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css.br → VRadioGroup-Cp9mZ7cb.css.br} +0 -0
  621. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css.gz → VRadioGroup-Cp9mZ7cb.css.gz} +0 -0
  622. /codex/static_root/assets/{VSelect-8MFoaOUz.6309f7bf17bb.css → VSelect-CP_CVb8s.6309f7bf17bb.css} +0 -0
  623. /codex/static_root/assets/{VSelect-8MFoaOUz.6309f7bf17bb.css.br → VSelect-CP_CVb8s.6309f7bf17bb.css.br} +0 -0
  624. /codex/static_root/assets/{VSelect-8MFoaOUz.6309f7bf17bb.css.gz → VSelect-CP_CVb8s.6309f7bf17bb.css.gz} +0 -0
  625. /codex/static_root/assets/{VSelect-8MFoaOUz.css → VSelect-CP_CVb8s.css} +0 -0
  626. /codex/static_root/assets/{VSelect-8MFoaOUz.css.br → VSelect-CP_CVb8s.css.br} +0 -0
  627. /codex/static_root/assets/{VSelect-8MFoaOUz.css.gz → VSelect-CP_CVb8s.css.gz} +0 -0
  628. /codex/static_root/assets/{VSelectionControl-DLxcLoTI.cc18de4e83f6.css → VSelectionControl-DPpfgCW2.cc18de4e83f6.css} +0 -0
  629. /codex/static_root/assets/{VSelectionControl-DLxcLoTI.cc18de4e83f6.css.br → VSelectionControl-DPpfgCW2.cc18de4e83f6.css.br} +0 -0
  630. /codex/static_root/assets/{VSelectionControl-DLxcLoTI.cc18de4e83f6.css.gz → VSelectionControl-DPpfgCW2.cc18de4e83f6.css.gz} +0 -0
  631. /codex/static_root/assets/{VSelectionControl-DLxcLoTI.css → VSelectionControl-DPpfgCW2.css} +0 -0
  632. /codex/static_root/assets/{VSelectionControl-DLxcLoTI.css.br → VSelectionControl-DPpfgCW2.css.br} +0 -0
  633. /codex/static_root/assets/{VSelectionControl-DLxcLoTI.css.gz → VSelectionControl-DPpfgCW2.css.gz} +0 -0
  634. /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css → VTable-BnxSZ_W5.c36f0a6a30cf.css} +0 -0
  635. /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css.br → VTable-BnxSZ_W5.c36f0a6a30cf.css.br} +0 -0
  636. /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css.gz → VTable-BnxSZ_W5.c36f0a6a30cf.css.gz} +0 -0
  637. /codex/static_root/assets/{VTable-Y5Sc3hJd.css → VTable-BnxSZ_W5.css} +0 -0
  638. /codex/static_root/assets/{VTable-Y5Sc3hJd.css.br → VTable-BnxSZ_W5.css.br} +0 -0
  639. /codex/static_root/assets/{VTable-Y5Sc3hJd.css.gz → VTable-BnxSZ_W5.css.gz} +0 -0
  640. /codex/static_root/assets/{VWindowItem-ByIod57Y.css → VWindowItem-CWBhiE_Y.css} +0 -0
  641. /codex/static_root/assets/{VWindowItem-ByIod57Y.css.br → VWindowItem-CWBhiE_Y.css.br} +0 -0
  642. /codex/static_root/assets/{VWindowItem-ByIod57Y.css.gz → VWindowItem-CWBhiE_Y.css.gz} +0 -0
  643. /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css → VWindowItem-CWBhiE_Y.f7fb19752bf3.css} +0 -0
  644. /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css.br → VWindowItem-CWBhiE_Y.f7fb19752bf3.css.br} +0 -0
  645. /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css.gz → VWindowItem-CWBhiE_Y.f7fb19752bf3.css.gz} +0 -0
  646. /codex/static_root/assets/{admin-VRLEt4I5.06cb213f624d.css → admin-C3iCIUnm.06cb213f624d.css} +0 -0
  647. /codex/static_root/assets/{admin-VRLEt4I5.06cb213f624d.css.br → admin-C3iCIUnm.06cb213f624d.css.br} +0 -0
  648. /codex/static_root/assets/{admin-VRLEt4I5.06cb213f624d.css.gz → admin-C3iCIUnm.06cb213f624d.css.gz} +0 -0
  649. /codex/static_root/assets/{admin-VRLEt4I5.css → admin-C3iCIUnm.css} +0 -0
  650. /codex/static_root/assets/{admin-VRLEt4I5.css.br → admin-C3iCIUnm.css.br} +0 -0
  651. /codex/static_root/assets/{admin-VRLEt4I5.css.gz → admin-C3iCIUnm.css.gz} +0 -0
  652. /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css → admin-menu-B3iXsOyy.c13b7df2ff57.css} +0 -0
  653. /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css.br → admin-menu-B3iXsOyy.c13b7df2ff57.css.br} +0 -0
  654. /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css.gz → admin-menu-B3iXsOyy.c13b7df2ff57.css.gz} +0 -0
  655. /codex/static_root/assets/{admin-menu-B9bzD6hV.css → admin-menu-B3iXsOyy.css} +0 -0
  656. /codex/static_root/assets/{admin-menu-B9bzD6hV.css.br → admin-menu-B3iXsOyy.css.br} +0 -0
  657. /codex/static_root/assets/{admin-menu-B9bzD6hV.css.gz → admin-menu-B3iXsOyy.css.gz} +0 -0
  658. /codex/static_root/assets/{admin-settings-button-progress-DUUQfVsZ.2548c49a853e.css → admin-settings-button-progress-BGB22oTD.2548c49a853e.css} +0 -0
  659. /codex/static_root/assets/{admin-settings-button-progress-DUUQfVsZ.css → admin-settings-button-progress-BGB22oTD.css} +0 -0
  660. /codex/static_root/assets/{change-password-dialog-C_EOKOn9.a30e68c6e303.css → change-password-dialog-D0ymWcl_.a30e68c6e303.css} +0 -0
  661. /codex/static_root/assets/{change-password-dialog-C_EOKOn9.a30e68c6e303.css.br → change-password-dialog-D0ymWcl_.a30e68c6e303.css.br} +0 -0
  662. /codex/static_root/assets/{change-password-dialog-C_EOKOn9.a30e68c6e303.css.gz → change-password-dialog-D0ymWcl_.a30e68c6e303.css.gz} +0 -0
  663. /codex/static_root/assets/{change-password-dialog-C_EOKOn9.css → change-password-dialog-D0ymWcl_.css} +0 -0
  664. /codex/static_root/assets/{change-password-dialog-C_EOKOn9.css.br → change-password-dialog-D0ymWcl_.css.br} +0 -0
  665. /codex/static_root/assets/{change-password-dialog-C_EOKOn9.css.gz → change-password-dialog-D0ymWcl_.css.gz} +0 -0
  666. /codex/static_root/assets/{confirm-dialog-54rblwf7.9b5915b112c0.css → confirm-dialog-B1ABbGMU.9b5915b112c0.css} +0 -0
  667. /codex/static_root/assets/{confirm-dialog-54rblwf7.9b5915b112c0.css.br → confirm-dialog-B1ABbGMU.9b5915b112c0.css.br} +0 -0
  668. /codex/static_root/assets/{confirm-dialog-54rblwf7.css → confirm-dialog-B1ABbGMU.css} +0 -0
  669. /codex/static_root/assets/{confirm-dialog-54rblwf7.css.br → confirm-dialog-B1ABbGMU.css.br} +0 -0
  670. /codex/static_root/assets/{datetime-column-DeCthByU.1f3bf499e063.css → datetime-column-BavtvLnf.1f3bf499e063.css} +0 -0
  671. /codex/static_root/assets/{datetime-column-DeCthByU.css → datetime-column-BavtvLnf.css} +0 -0
  672. /codex/static_root/assets/{forwardRefs-zKOZsbbr.9b56b4459240.css → forwardRefs-CFNX6kJ2.9b56b4459240.css} +0 -0
  673. /codex/static_root/assets/{forwardRefs-zKOZsbbr.9b56b4459240.css.br → forwardRefs-CFNX6kJ2.9b56b4459240.css.br} +0 -0
  674. /codex/static_root/assets/{forwardRefs-zKOZsbbr.9b56b4459240.css.gz → forwardRefs-CFNX6kJ2.9b56b4459240.css.gz} +0 -0
  675. /codex/static_root/assets/{forwardRefs-zKOZsbbr.css → forwardRefs-CFNX6kJ2.css} +0 -0
  676. /codex/static_root/assets/{forwardRefs-zKOZsbbr.css.br → forwardRefs-CFNX6kJ2.css.br} +0 -0
  677. /codex/static_root/assets/{forwardRefs-zKOZsbbr.css.gz → forwardRefs-CFNX6kJ2.css.gz} +0 -0
  678. /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css → group-tab-_vKWzoyd.948e907b1e6b.css} +0 -0
  679. /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css.br → group-tab-_vKWzoyd.948e907b1e6b.css.br} +0 -0
  680. /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css.gz → group-tab-_vKWzoyd.948e907b1e6b.css.gz} +0 -0
  681. /codex/static_root/assets/{group-tab-DkIN1Heu.css → group-tab-_vKWzoyd.css} +0 -0
  682. /codex/static_root/assets/{group-tab-DkIN1Heu.css.br → group-tab-_vKWzoyd.css.br} +0 -0
  683. /codex/static_root/assets/{group-tab-DkIN1Heu.css.gz → group-tab-_vKWzoyd.css.gz} +0 -0
  684. /codex/static_root/assets/{http-error-DEJmFobt.8c13689ae574.css → http-error-CODU7jcH.8c13689ae574.css} +0 -0
  685. /codex/static_root/assets/{http-error-DEJmFobt.8c13689ae574.css.br → http-error-CODU7jcH.8c13689ae574.css.br} +0 -0
  686. /codex/static_root/assets/{http-error-DEJmFobt.8c13689ae574.css.gz → http-error-CODU7jcH.8c13689ae574.css.gz} +0 -0
  687. /codex/static_root/assets/{http-error-DEJmFobt.css → http-error-CODU7jcH.css} +0 -0
  688. /codex/static_root/assets/{http-error-DEJmFobt.css.br → http-error-CODU7jcH.css.br} +0 -0
  689. /codex/static_root/assets/{http-error-DEJmFobt.css.gz → http-error-CODU7jcH.css.gz} +0 -0
  690. /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css → index-BHXJTQ4V.523d7b3d350f.css} +0 -0
  691. /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css.br → index-BHXJTQ4V.523d7b3d350f.css.br} +0 -0
  692. /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css.gz → index-BHXJTQ4V.523d7b3d350f.css.gz} +0 -0
  693. /codex/static_root/assets/{index-CL_6g4tJ.css → index-BHXJTQ4V.css} +0 -0
  694. /codex/static_root/assets/{index-CL_6g4tJ.css.br → index-BHXJTQ4V.css.br} +0 -0
  695. /codex/static_root/assets/{index-CL_6g4tJ.css.gz → index-BHXJTQ4V.css.gz} +0 -0
  696. /codex/static_root/assets/{library-tab-Ce6qaeCV.75baedb7e976.css → library-tab-CgsXOX_r.75baedb7e976.css} +0 -0
  697. /codex/static_root/assets/{library-tab-Ce6qaeCV.75baedb7e976.css.br → library-tab-CgsXOX_r.75baedb7e976.css.br} +0 -0
  698. /codex/static_root/assets/{library-tab-Ce6qaeCV.75baedb7e976.css.gz → library-tab-CgsXOX_r.75baedb7e976.css.gz} +0 -0
  699. /codex/static_root/assets/{library-tab-Ce6qaeCV.css → library-tab-CgsXOX_r.css} +0 -0
  700. /codex/static_root/assets/{library-tab-Ce6qaeCV.css.br → library-tab-CgsXOX_r.css.br} +0 -0
  701. /codex/static_root/assets/{library-tab-Ce6qaeCV.css.gz → library-tab-CgsXOX_r.css.gz} +0 -0
  702. /codex/static_root/assets/{main-BZ73p_WW.css → main-K8cER0IH.css} +0 -0
  703. /codex/static_root/assets/{main-BZ73p_WW.css.br → main-K8cER0IH.css.br} +0 -0
  704. /codex/static_root/assets/{main-BZ73p_WW.css.gz → main-K8cER0IH.css.gz} +0 -0
  705. /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css → main-K8cER0IH.d529e8b3f52a.css} +0 -0
  706. /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css.br → main-K8cER0IH.d529e8b3f52a.css.br} +0 -0
  707. /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css.gz → main-K8cER0IH.d529e8b3f52a.css.gz} +0 -0
  708. /codex/static_root/assets/{pagination-toolbar-DSe0TkMm.css → pagination-toolbar-D5VQREy5.css} +0 -0
  709. /codex/static_root/assets/{pagination-toolbar-DSe0TkMm.css.br → pagination-toolbar-D5VQREy5.css.br} +0 -0
  710. /codex/static_root/assets/{pagination-toolbar-DSe0TkMm.css.gz → pagination-toolbar-D5VQREy5.css.gz} +0 -0
  711. /codex/static_root/assets/{pagination-toolbar-DSe0TkMm.dcb0eba65827.css → pagination-toolbar-D5VQREy5.dcb0eba65827.css} +0 -0
  712. /codex/static_root/assets/{pagination-toolbar-DSe0TkMm.dcb0eba65827.css.br → pagination-toolbar-D5VQREy5.dcb0eba65827.css.br} +0 -0
  713. /codex/static_root/assets/{pagination-toolbar-DSe0TkMm.dcb0eba65827.css.gz → pagination-toolbar-D5VQREy5.dcb0eba65827.css.gz} +0 -0
  714. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css → pdf-doc-B4cGW_Hl.b94aac7e3313.css} +0 -0
  715. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css.br → pdf-doc-B4cGW_Hl.b94aac7e3313.css.br} +0 -0
  716. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css.gz → pdf-doc-B4cGW_Hl.b94aac7e3313.css.gz} +0 -0
  717. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css → pdf-doc-B4cGW_Hl.css} +0 -0
  718. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css.br → pdf-doc-B4cGW_Hl.css.br} +0 -0
  719. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css.gz → pdf-doc-B4cGW_Hl.css.gz} +0 -0
  720. /codex/static_root/assets/{reader-B3hgta6g.2ed32f08e906.css → reader-D_3ruSqa.2ed32f08e906.css} +0 -0
  721. /codex/static_root/assets/{reader-B3hgta6g.2ed32f08e906.css.br → reader-D_3ruSqa.2ed32f08e906.css.br} +0 -0
  722. /codex/static_root/assets/{reader-B3hgta6g.2ed32f08e906.css.gz → reader-D_3ruSqa.2ed32f08e906.css.gz} +0 -0
  723. /codex/static_root/assets/{reader-B3hgta6g.css → reader-D_3ruSqa.css} +0 -0
  724. /codex/static_root/assets/{reader-B3hgta6g.css.br → reader-D_3ruSqa.css.br} +0 -0
  725. /codex/static_root/assets/{reader-B3hgta6g.css.gz → reader-D_3ruSqa.css.gz} +0 -0
  726. /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css → relation-chips-DpbzrZxT.01269a188e01.css} +0 -0
  727. /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css.br → relation-chips-DpbzrZxT.01269a188e01.css.br} +0 -0
  728. /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css.gz → relation-chips-DpbzrZxT.01269a188e01.css.gz} +0 -0
  729. /codex/static_root/assets/{relation-chips-ByfWwuQc.css → relation-chips-DpbzrZxT.css} +0 -0
  730. /codex/static_root/assets/{relation-chips-ByfWwuQc.css.br → relation-chips-DpbzrZxT.css.br} +0 -0
  731. /codex/static_root/assets/{relation-chips-ByfWwuQc.css.gz → relation-chips-DpbzrZxT.css.gz} +0 -0
  732. /codex/static_root/assets/{settings-drawer-CqJ4gXLq.75a6ea969e71.css → settings-drawer-DMSsWF8c.75a6ea969e71.css} +0 -0
  733. /codex/static_root/assets/{settings-drawer-CqJ4gXLq.75a6ea969e71.css.br → settings-drawer-DMSsWF8c.75a6ea969e71.css.br} +0 -0
  734. /codex/static_root/assets/{settings-drawer-CqJ4gXLq.75a6ea969e71.css.gz → settings-drawer-DMSsWF8c.75a6ea969e71.css.gz} +0 -0
  735. /codex/static_root/assets/{settings-drawer-CqJ4gXLq.css → settings-drawer-DMSsWF8c.css} +0 -0
  736. /codex/static_root/assets/{settings-drawer-CqJ4gXLq.css.br → settings-drawer-DMSsWF8c.css.br} +0 -0
  737. /codex/static_root/assets/{settings-drawer-CqJ4gXLq.css.gz → settings-drawer-DMSsWF8c.css.gz} +0 -0
  738. /codex/static_root/assets/{stats-tab-BlXGStge.9fdb0106124d.css → stats-tab-WvF2acoZ.9fdb0106124d.css} +0 -0
  739. /codex/static_root/assets/{stats-tab-BlXGStge.9fdb0106124d.css.br → stats-tab-WvF2acoZ.9fdb0106124d.css.br} +0 -0
  740. /codex/static_root/assets/{stats-tab-BlXGStge.9fdb0106124d.css.gz → stats-tab-WvF2acoZ.9fdb0106124d.css.gz} +0 -0
  741. /codex/static_root/assets/{stats-tab-BlXGStge.css → stats-tab-WvF2acoZ.css} +0 -0
  742. /codex/static_root/assets/{stats-tab-BlXGStge.css.br → stats-tab-WvF2acoZ.css.br} +0 -0
  743. /codex/static_root/assets/{stats-tab-BlXGStge.css.gz → stats-tab-WvF2acoZ.css.gz} +0 -0
  744. /codex/static_root/assets/{task-tab-EGlhcKTH.478e74041f80.css → task-tab-DfdUY9Rc.478e74041f80.css} +0 -0
  745. /codex/static_root/assets/{task-tab-EGlhcKTH.478e74041f80.css.br → task-tab-DfdUY9Rc.478e74041f80.css.br} +0 -0
  746. /codex/static_root/assets/{task-tab-EGlhcKTH.478e74041f80.css.gz → task-tab-DfdUY9Rc.478e74041f80.css.gz} +0 -0
  747. /codex/static_root/assets/{task-tab-EGlhcKTH.css → task-tab-DfdUY9Rc.css} +0 -0
  748. /codex/static_root/assets/{task-tab-EGlhcKTH.css.br → task-tab-DfdUY9Rc.css.br} +0 -0
  749. /codex/static_root/assets/{task-tab-EGlhcKTH.css.gz → task-tab-DfdUY9Rc.css.gz} +0 -0
  750. /codex/static_root/assets/{unauthorized-VnIXUO1w.c5536d9dae75.css → unauthorized-CsSak07X.c5536d9dae75.css} +0 -0
  751. /codex/static_root/assets/{unauthorized-VnIXUO1w.c5536d9dae75.css.br → unauthorized-CsSak07X.c5536d9dae75.css.br} +0 -0
  752. /codex/static_root/assets/{unauthorized-VnIXUO1w.c5536d9dae75.css.gz → unauthorized-CsSak07X.c5536d9dae75.css.gz} +0 -0
  753. /codex/static_root/assets/{unauthorized-VnIXUO1w.css → unauthorized-CsSak07X.css} +0 -0
  754. /codex/static_root/assets/{unauthorized-VnIXUO1w.css.br → unauthorized-CsSak07X.css.br} +0 -0
  755. /codex/static_root/assets/{unauthorized-VnIXUO1w.css.gz → unauthorized-CsSak07X.css.gz} +0 -0
  756. {codex-1.7.3a1.dist-info → codex-1.7.4.dist-info}/LICENSE +0 -0
  757. {codex-1.7.3a1.dist-info → codex-1.7.4.dist-info}/entry_points.txt +0 -0
@@ -1,68 +1,40 @@
1
1
  """Browser Settings Filter Serializers."""
2
2
 
3
- from rest_framework.serializers import BooleanField, ListField, Serializer
3
+ from rest_framework.serializers import ListField, Serializer
4
4
 
5
5
  from codex.serializers.fields import (
6
- BookmarkFilterField,
7
6
  VuetifyBooleanField,
8
- VuetifyCharField,
9
7
  VuetifyDecadeField,
10
8
  VuetifyFloatField,
11
9
  VuetifyIntegerField,
12
10
  )
11
+ from codex.serializers.fields.browser import BookmarkFilterField
13
12
 
14
13
 
15
- class BrowserFilterChoicesSerializer(Serializer):
16
- """All dynamic filters."""
17
-
18
- age_rating = BooleanField(read_only=True)
19
- community_rating = BooleanField(read_only=True)
20
- characters = BooleanField(read_only=True)
21
- country = BooleanField(read_only=True)
22
- critical_rating = BooleanField(read_only=True)
23
- contributors = BooleanField(read_only=True)
24
- decade = BooleanField(read_only=True)
25
- genres = BooleanField(read_only=True)
26
- file_type = BooleanField(read_only=True)
27
- identifier_type = BooleanField(read_only=True)
28
- monochrome = BooleanField(read_only=True)
29
- language = BooleanField(read_only=True)
30
- locations = BooleanField(read_only=True)
31
- original_format = BooleanField(read_only=True)
32
- reading_direction = BooleanField(read_only=True)
33
- series_groups = BooleanField(read_only=True)
34
- stories = BooleanField(read_only=True)
35
- story_arcs = BooleanField(read_only=True)
36
- tagger = BooleanField(read_only=True)
37
- tags = BooleanField(read_only=True)
38
- teams = BooleanField(read_only=True)
39
- year = BooleanField(read_only=True)
40
-
41
-
42
- class BrowserSettingsFilterSerializer(Serializer):
14
+ class BrowserSettingsFilterInputSerializer(Serializer):
43
15
  """Filter values for settings."""
44
16
 
45
17
  bookmark = BookmarkFilterField(required=False)
46
18
  # Dynamic filters
47
- age_rating = ListField(child=VuetifyCharField(), required=False)
19
+ age_rating = ListField(child=VuetifyIntegerField(), required=False)
48
20
  characters = ListField(child=VuetifyIntegerField(), required=False)
49
21
  community_rating = ListField(child=VuetifyFloatField(), required=False)
50
22
  country = ListField(child=VuetifyIntegerField(), required=False)
51
23
  contributors = ListField(child=VuetifyIntegerField(), required=False)
52
24
  critical_rating = ListField(child=VuetifyFloatField(), required=False)
53
25
  decade = ListField(child=VuetifyDecadeField(), required=False)
54
- file_type = ListField(child=VuetifyCharField(), required=False)
26
+ file_type = ListField(child=VuetifyIntegerField(), required=False)
55
27
  genres = ListField(child=VuetifyIntegerField(), required=False)
56
- identifier_type = ListField(child=VuetifyCharField(), required=False)
28
+ identifier_type = ListField(child=VuetifyIntegerField(), required=False)
57
29
  language = ListField(child=VuetifyIntegerField(), required=False)
58
30
  locations = ListField(child=VuetifyIntegerField(), required=False)
59
31
  monochrome = ListField(child=VuetifyBooleanField(), required=False)
60
- original_format = ListField(child=VuetifyCharField(), required=False)
61
- reading_direction = ListField(child=VuetifyCharField(), required=False)
32
+ original_format = ListField(child=VuetifyIntegerField(), required=False)
33
+ reading_direction = ListField(child=VuetifyIntegerField(), required=False)
62
34
  series_groups = ListField(child=VuetifyIntegerField(), required=False)
63
35
  stories = ListField(child=VuetifyIntegerField(), required=False)
64
36
  story_arcs = ListField(child=VuetifyIntegerField(), required=False)
65
- tagger = ListField(child=VuetifyCharField(), required=False)
37
+ tagger = ListField(child=VuetifyIntegerField(), required=False)
66
38
  tags = ListField(child=VuetifyIntegerField(), required=False)
67
39
  teams = ListField(child=VuetifyIntegerField(), required=False)
68
40
  year = ListField(child=VuetifyIntegerField(), required=False)
@@ -1,6 +1,7 @@
1
1
  """Codex Serializers for the metadata box."""
2
2
 
3
- from rest_framework.serializers import CharField, IntegerField, ListField, Serializer
3
+ from rest_framework.fields import CharField
4
+ from rest_framework.serializers import IntegerField, ListField, Serializer
4
5
 
5
6
  from codex.serializers.browser.mixins import BrowserAggregateSerializerMixin
6
7
  from codex.serializers.models.comic import ComicSerializer
@@ -5,7 +5,6 @@ from itertools import chain
5
5
 
6
6
  from rest_framework.serializers import (
7
7
  BooleanField,
8
- CharField,
9
8
  DecimalField,
10
9
  IntegerField,
11
10
  ListField,
@@ -14,6 +13,7 @@ from rest_framework.serializers import (
14
13
  )
15
14
 
16
15
  from codex.logger.logging import get_logger
16
+ from codex.serializers.fields.browser import TopGroupField
17
17
  from codex.util import max_none
18
18
  from codex.views.const import EPOCH_START
19
19
 
@@ -23,7 +23,7 @@ LOG = get_logger(__name__)
23
23
  class BrowserAggregateSerializerMixin(Serializer):
24
24
  """Mixin for browser, opds & metadata serializers."""
25
25
 
26
- group = CharField(read_only=True, max_length=1)
26
+ group = TopGroupField(read_only=True)
27
27
  ids = ListField(child=IntegerField(), read_only=True)
28
28
 
29
29
  # Aggregate Annotations
@@ -64,5 +64,9 @@ class BrowserAggregateSerializerMixin(Serializer):
64
64
  )
65
65
  mtime = self._get_max_updated_at(EPOCH_START, updated_ats)
66
66
  if obj.bmua_is_max:
67
- mtime: datetime = max_none(mtime, obj.bookmark_updated_at, EPOCH_START) # type: ignore
67
+ mtime: datetime | None = max_none(
68
+ mtime, obj.bookmark_updated_at, EPOCH_START
69
+ )
70
+ if mtime is None:
71
+ return 0
68
72
  return int(mtime.timestamp() * 1000)
@@ -1,17 +1,15 @@
1
1
  """Group Mtimes."""
2
2
 
3
- from rest_framework.serializers import CharField, Serializer
3
+ from rest_framework.serializers import Serializer
4
4
 
5
- from codex.serializers.browser.settings import BrowserSettingsFilterSerializer
5
+ from codex.serializers.browser.settings import BrowserFilterChoicesInputSerilalizer
6
6
  from codex.serializers.fields import TimestampField
7
7
  from codex.serializers.route import SimpleRouteSerializer
8
8
 
9
9
 
10
- class GroupsMtimeSerializer(Serializer):
10
+ class GroupsMtimeSerializer(BrowserFilterChoicesInputSerilalizer):
11
11
  """Groups Mtimes."""
12
12
 
13
- filters = BrowserSettingsFilterSerializer(required=False)
14
- q = CharField(allow_blank=True, required=False)
15
13
  groups = SimpleRouteSerializer(many=True, required=True)
16
14
 
17
15
 
@@ -1,17 +1,18 @@
1
1
  """Browser Page Serializer."""
2
2
 
3
- from rest_framework.serializers import (
3
+ from rest_framework.fields import (
4
4
  BooleanField,
5
5
  CharField,
6
6
  DecimalField,
7
7
  IntegerField,
8
- Serializer,
9
8
  )
9
+ from rest_framework.serializers import Serializer
10
10
 
11
11
  from codex.serializers.browser.mixins import (
12
12
  BrowserAggregateSerializerMixin,
13
13
  )
14
- from codex.serializers.fields import BreadcrumbsField, TimestampField
14
+ from codex.serializers.fields import TimestampField
15
+ from codex.serializers.fields.browser import BreadcrumbsField, TopGroupField
15
16
 
16
17
 
17
18
  class BrowserCardSerializer(BrowserAggregateSerializerMixin):
@@ -57,7 +58,7 @@ class BrowserPageSerializer(Serializer):
57
58
  title = BrowserTitleSerializer(read_only=True)
58
59
  zero_pad = IntegerField(read_only=True)
59
60
  libraries_exist = BooleanField(read_only=True)
60
- model_group = CharField(read_only=True)
61
+ model_group = TopGroupField(read_only=True)
61
62
  num_pages = IntegerField(read_only=True)
62
63
  groups = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
63
64
  books = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
@@ -9,8 +9,9 @@ from rest_framework.serializers import (
9
9
  )
10
10
 
11
11
  from codex.choices import BROWSER_ORDER_BY_CHOICES
12
- from codex.serializers.browser.filters import BrowserSettingsFilterSerializer
13
- from codex.serializers.fields import BreadcrumbsField, TimestampField, TopGroupField
12
+ from codex.serializers.browser.filters import BrowserSettingsFilterInputSerializer
13
+ from codex.serializers.fields import TimestampField
14
+ from codex.serializers.fields.browser import BreadcrumbsField, TopGroupField
14
15
  from codex.serializers.route import SimpleRouteSerializer
15
16
 
16
17
 
@@ -26,7 +27,8 @@ class BrowserSettingsShowGroupFlagsSerializer(Serializer):
26
27
  class BrowserFilterChoicesInputSerilalizer(Serializer):
27
28
  """Browser Settings for the filter choices response."""
28
29
 
29
- filters = BrowserSettingsFilterSerializer(required=False)
30
+ filters = BrowserSettingsFilterInputSerializer(required=False)
31
+ # NOT Sanitized because so complex.
30
32
  q = CharField(allow_blank=True, required=False)
31
33
 
32
34
 
@@ -51,7 +53,6 @@ class BrowserCoverInputSerializer(BrowserCoverInputSerializerBase):
51
53
  class BrowserSettingsSerializerBase(BrowserCoverInputSerializerBase):
52
54
  """Base Serializer for Browser & OPDS Settings."""
53
55
 
54
- # search_results_limit = IntegerField(required=False)
55
56
  top_group = TopGroupField(required=False)
56
57
 
57
58
 
@@ -64,7 +65,8 @@ class OPDSSettingsSerializer(BrowserSettingsSerializerBase):
64
65
 
65
66
 
66
67
  class BrowserSettingsSerializer(BrowserSettingsSerializerBase):
67
- """Browser Settings that the user can change.
68
+ """
69
+ Browser Settings that the user can change.
68
70
 
69
71
  This is the only browse serializer that's submitted.
70
72
  """
@@ -0,0 +1,37 @@
1
+ """Custom Serializer Fields."""
2
+
3
+ from codex.serializers.fields.auth import TimestampField, TimezoneField
4
+ from codex.serializers.fields.group import BrowseGroupField
5
+ from codex.serializers.fields.reader import FitToField, ReadingDirectionField
6
+ from codex.serializers.fields.sanitized import SanitizedCharField
7
+ from codex.serializers.fields.session import SessionKeyField
8
+ from codex.serializers.fields.stats import (
9
+ CountDictField,
10
+ SerializerChoicesField,
11
+ StringListMultipleChoiceField,
12
+ )
13
+ from codex.serializers.fields.vuetify import (
14
+ VuetifyBooleanField,
15
+ VuetifyCharField,
16
+ VuetifyDecadeField,
17
+ VuetifyFloatField,
18
+ VuetifyIntegerField,
19
+ )
20
+
21
+ __all__ = (
22
+ "TimestampField",
23
+ "TimezoneField",
24
+ "BrowseGroupField",
25
+ "SanitizedCharField",
26
+ "StringListMultipleChoiceField",
27
+ "SerializerChoicesField",
28
+ "CountDictField",
29
+ "VuetifyFloatField",
30
+ "VuetifyIntegerField",
31
+ "VuetifyCharField",
32
+ "VuetifyBooleanField",
33
+ "VuetifyDecadeField",
34
+ "FitToField",
35
+ "ReadingDirectionField",
36
+ "SessionKeyField",
37
+ )
@@ -0,0 +1,45 @@
1
+ """Custom fields."""
2
+
3
+ from datetime import datetime, timezone
4
+ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
5
+
6
+ from rest_framework.exceptions import ValidationError
7
+ from rest_framework.serializers import (
8
+ CharField,
9
+ IntegerField,
10
+ )
11
+
12
+ from codex.logger.logging import get_logger
13
+
14
+ LOG = get_logger(__name__)
15
+
16
+
17
+ class TimestampField(IntegerField):
18
+ """IntegerTimestampField."""
19
+
20
+ def to_representation(self, value) -> int:
21
+ """Convert to Jascript millisecond int timestamp from datetime, or castable."""
22
+ if isinstance(value, datetime):
23
+ value = value.timestamp()
24
+ return int(float(value) * 1000)
25
+
26
+ def to_internal_value(self, data) -> datetime: # type: ignore[reportIncompatibleMethodOverride]
27
+ """Convert from castable, likely string to datetime."""
28
+ return datetime.fromtimestamp(float(data) / 1000, tz=timezone.utc)
29
+
30
+
31
+ def validate_timezone(data):
32
+ """Validate Timezone."""
33
+ try:
34
+ ZoneInfo(data)
35
+ except ZoneInfoNotFoundError as exc:
36
+ raise ValidationError from exc
37
+ return data
38
+
39
+
40
+ class TimezoneField(CharField):
41
+ """Timezone field."""
42
+
43
+ def __init__(self, *args, **kwargs):
44
+ """Call Charfield with defaults."""
45
+ super().__init__(*args, min_length=2, validators=[validate_timezone], **kwargs)
@@ -0,0 +1,85 @@
1
+ """Custom fields."""
2
+
3
+ from abc import ABC
4
+
5
+ import pycountry
6
+ from rest_framework.serializers import (
7
+ ChoiceField,
8
+ ListField,
9
+ )
10
+
11
+ from codex.choices import (
12
+ BROWSER_BOOKMARK_FILTER_CHOICES,
13
+ BROWSER_TOP_GROUP_CHOICES,
14
+ DUMMY_NULL_NAME,
15
+ )
16
+ from codex.logger.logging import get_logger
17
+ from codex.serializers.fields.sanitized import SanitizedCharField
18
+ from codex.serializers.route import RouteSerializer
19
+
20
+ LOG = get_logger(__name__)
21
+
22
+
23
+ class TopGroupField(ChoiceField):
24
+ """Valid Top Groups Only."""
25
+
26
+ class_choices = tuple(BROWSER_TOP_GROUP_CHOICES.keys())
27
+
28
+ def __init__(self, *args, **kwargs):
29
+ """Initialize with choices."""
30
+ super().__init__(*args, choices=self.class_choices, **kwargs)
31
+
32
+
33
+ class BookmarkFilterField(ChoiceField):
34
+ """Bookmark Choice Field."""
35
+
36
+ def __init__(self, *args, **kwargs):
37
+ """Use bookmark filter choices."""
38
+ super().__init__(
39
+ *args, choices=tuple(BROWSER_BOOKMARK_FILTER_CHOICES.keys()), **kwargs
40
+ )
41
+
42
+
43
+ class PyCountryField(SanitizedCharField, ABC):
44
+ """Serialize to a long pycountry name."""
45
+
46
+ LOOKUP_MODULE = pycountry.countries
47
+ _ALPHA_2_LEN = 2
48
+
49
+ def to_representation(self, value):
50
+ """Lookup the name with pycountry, just copy the value on fail."""
51
+ if not value:
52
+ return ""
53
+ if value == DUMMY_NULL_NAME:
54
+ return value
55
+ try:
56
+ # fix for https://github.com/flyingcircusio/pycountry/issues/41
57
+ lookup_obj = (
58
+ self.LOOKUP_MODULE.get(alpha_2=value)
59
+ if len(value) == self._ALPHA_2_LEN
60
+ else self.LOOKUP_MODULE.lookup(value)
61
+ )
62
+ # If lookup fails, return the key as the name
63
+ except Exception:
64
+ LOG.warning(f"Could not serialize name with pycountry {value}")
65
+ return value
66
+ else:
67
+ return lookup_obj.name if lookup_obj else value
68
+
69
+
70
+ class CountryField(PyCountryField):
71
+ """Serializer to long country name."""
72
+
73
+ LOOKUP_MODULE = pycountry.countries
74
+
75
+
76
+ class LanguageField(PyCountryField):
77
+ """Serializer to long language name."""
78
+
79
+ LOOKUP_MODULE = pycountry.languages
80
+
81
+
82
+ class BreadcrumbsField(ListField):
83
+ """And Array of Routes."""
84
+
85
+ child = RouteSerializer()
@@ -0,0 +1,13 @@
1
+ """Browser Group Field."""
2
+
3
+ from rest_framework.fields import ChoiceField
4
+
5
+ from codex.choices import BROWSER_GROUP_CHOICES
6
+
7
+
8
+ class BrowseGroupField(ChoiceField):
9
+ """BrowseGroup Field."""
10
+
11
+ def __init__(self, *args, **kwargs):
12
+ """Add choices."""
13
+ super().__init__(*args, choices=tuple(BROWSER_GROUP_CHOICES.keys()), **kwargs)
@@ -0,0 +1,22 @@
1
+ """Reader Fields."""
2
+
3
+ from rest_framework.serializers import ChoiceField
4
+
5
+ from codex.models import Bookmark
6
+ from codex.models.comic import ReadingDirection
7
+
8
+
9
+ class FitToField(ChoiceField):
10
+ """Bookmark FitTo Fieild."""
11
+
12
+ def __init__(self, *args, **kwargs):
13
+ """Add Choices."""
14
+ super().__init__(*args, choices=Bookmark.FitTo.values, **kwargs)
15
+
16
+
17
+ class ReadingDirectionField(ChoiceField):
18
+ """Reading Direction Field."""
19
+
20
+ def __init__(self, *args, **kwargs):
21
+ """Add Choices."""
22
+ super().__init__(*args, choices=ReadingDirection.values, **kwargs)
@@ -0,0 +1,13 @@
1
+ """Sanitied Fields."""
2
+
3
+ from nh3 import clean
4
+ from rest_framework.fields import CharField
5
+
6
+
7
+ class SanitizedCharField(CharField):
8
+ """Sanitize CharField using NH3."""
9
+
10
+ def to_internal_value(self, data):
11
+ """Sanitize CharField using NH3."""
12
+ sanitized_data = clean(data)
13
+ return super().to_internal_value(sanitized_data)
@@ -0,0 +1,15 @@
1
+ """Session Custom Fields."""
2
+
3
+ from rest_framework.fields import ChoiceField
4
+
5
+ from codex.choices import BROWSER_DEFAULTS, READER_DEFAULTS
6
+
7
+ _SESSION_KEYS = (*READER_DEFAULTS.keys(), *BROWSER_DEFAULTS.keys(), "filters")
8
+
9
+
10
+ class SessionKeyField(ChoiceField):
11
+ """Session Key Field."""
12
+
13
+ def __init__(self, *args, **kwargs):
14
+ """Add choices."""
15
+ super().__init__(*args, choices=_SESSION_KEYS, **kwargs)
@@ -0,0 +1,36 @@
1
+ """Custom Vuetify fields."""
2
+
3
+ from rest_framework.fields import DictField, IntegerField
4
+ from rest_framework.serializers import MultipleChoiceField
5
+
6
+ from codex.logger.logging import get_logger
7
+
8
+ LOG = get_logger(__name__)
9
+
10
+
11
+ class StringListMultipleChoiceField(MultipleChoiceField):
12
+ """A Multiple Choice Field expressed as as a comma delimited string."""
13
+
14
+ def to_internal_value(self, data):
15
+ """Convert comma delimited strings to sets."""
16
+ if isinstance(data, str):
17
+ data = frozenset(data.split(","))
18
+ return super().to_internal_value(data) # type: ignore[reportIncompatibleMethodOverride]
19
+
20
+
21
+ class SerializerChoicesField(StringListMultipleChoiceField):
22
+ """A String List Multiple Choice Field limited to a specified serializer's fields."""
23
+
24
+ def __init__(self, *args, serializer=None, **kwargs):
25
+ """Limit choices to fields from serializers."""
26
+ if not serializer:
27
+ reason = "serializer required for this field."
28
+ raise ValueError(reason)
29
+ choices = serializer().get_fields().keys()
30
+ super().__init__(*args, choices=choices, **kwargs)
31
+
32
+
33
+ class CountDictField(DictField):
34
+ """Dict for counting things."""
35
+
36
+ child = IntegerField(read_only=True)
@@ -0,0 +1,62 @@
1
+ """Custom Vuetify fields."""
2
+
3
+ from django.utils.translation import gettext_lazy as _
4
+ from rest_framework.exceptions import ValidationError
5
+ from rest_framework.serializers import (
6
+ BooleanField,
7
+ CharField,
8
+ FloatField,
9
+ IntegerField,
10
+ )
11
+
12
+ from codex.choices import VUETIFY_NULL_CODE
13
+ from codex.logger.logging import get_logger
14
+
15
+ LOG = get_logger(__name__)
16
+
17
+
18
+ class VuetifyNullCodeFieldMixin:
19
+ """Convert Vuetify null codes to None."""
20
+
21
+ NULL_CODE = VUETIFY_NULL_CODE
22
+
23
+ def to_internal_value(self, data):
24
+ """Convert numeric null code to None."""
25
+ return None if data == self.NULL_CODE else data
26
+
27
+
28
+ class VuetifyFloatField(VuetifyNullCodeFieldMixin, FloatField): # type: ignore[reportIncompatibleMethodOverride]
29
+ """Float Field with null code conversion."""
30
+
31
+
32
+ class VuetifyIntegerField(VuetifyNullCodeFieldMixin, IntegerField): # type: ignore[reportIncompatibleMethodOverride]
33
+ """Integer Field with null code conversion."""
34
+
35
+
36
+ class VuetifyCharField(VuetifyNullCodeFieldMixin, CharField): # type: ignore[reportIncompatibleMethodOverride]
37
+ """Char Field with null code conversion."""
38
+
39
+ NULL_CODE = str(VUETIFY_NULL_CODE)
40
+
41
+
42
+ class VuetifyBooleanField(VuetifyNullCodeFieldMixin, BooleanField): # type: ignore[reportIncompatibleMethodOverride]
43
+ """Boolean Field with null code conversion."""
44
+
45
+
46
+ def validate_decade(decade):
47
+ """Validate decades."""
48
+ # * We don't need a whole db call just to be perfectly accurate
49
+ # * -1s are decoded back into None before validation
50
+ if decade is not None and decade % 10 != 0:
51
+ raise ValidationError(_("Invalid decade: ") + f"{decade}")
52
+ return True
53
+
54
+
55
+ class VuetifyDecadeField(VuetifyIntegerField):
56
+ """Integer field with null code conversion and decade validation."""
57
+
58
+ VALIDATORS = (validate_decade,)
59
+
60
+ def __init__(self, *args, **kwargs):
61
+ """Use decade validator."""
62
+ super().__init__(*args, validators=self.VALIDATORS, **kwargs)
@@ -6,7 +6,7 @@ from rest_framework.serializers import ModelSerializer, SerializerMetaclass
6
6
  class BaseModelSerializer(ModelSerializer):
7
7
  """BaseModel Serializer for inheritance."""
8
8
 
9
- class Meta(SerializerMetaclass): # type: ignore
9
+ class Meta(SerializerMetaclass): # type: ignore[reportIncompatibleVariableOverride]
10
10
  """Use explicit metaclass instead of python 3 method."""
11
11
 
12
12
  abstract = True
@@ -38,8 +38,8 @@ class ComicSerializer(BaseModelSerializer):
38
38
  pk = IntegerField(source="id")
39
39
 
40
40
  # Annotations
41
- # issue_count = IntegerField(allow_null=True)
42
- # volume_count = IntegerField(allow_null=True)
41
+ # issue_count = IntegerField(allow_null=True) could be 1
42
+ # volume_count = IntegerField(allow_null=True) could be 1
43
43
 
44
44
  # Group FKs
45
45
  publisher = PublisherSerializer(allow_null=True)
@@ -43,7 +43,6 @@ class SeriesSerializer(GroupModelSerializer):
43
43
  """Configure model."""
44
44
 
45
45
  model = Series
46
- # fields = (*NamedModelMeta.fields, "volume_count")
47
46
 
48
47
 
49
48
  class VolumeSerializer(GroupModelSerializer):
@@ -53,4 +52,3 @@ class VolumeSerializer(GroupModelSerializer):
53
52
  """Configure model."""
54
53
 
55
54
  model = Volume
56
- # fields = (*NamedModelMeta.fields, "issue_count")
@@ -1,6 +1,6 @@
1
1
  """Named model Serializers."""
2
2
 
3
- from rest_framework.serializers import CharField
3
+ from rest_framework.fields import CharField
4
4
 
5
5
  from codex.models import (
6
6
  AgeRating,
@@ -5,7 +5,7 @@ from codex.models import (
5
5
  Country,
6
6
  Language,
7
7
  )
8
- from codex.serializers.fields import CountryField, LanguageField
8
+ from codex.serializers.fields.browser import CountryField, LanguageField
9
9
  from codex.serializers.models.named import NamedModelSerializer
10
10
 
11
11
  LOG = get_logger(__name__)
@@ -1,9 +1,11 @@
1
- """OPDS Authentication 1.0 Serializer.
1
+ """
2
+ OPDS Authentication 1.0 Serializer.
2
3
 
3
4
  https://drafts.opds.io/schema/authentication.schema.json
4
5
  """
5
6
 
6
- from rest_framework.serializers import CharField, IntegerField, Serializer
7
+ from rest_framework.fields import CharField
8
+ from rest_framework.serializers import IntegerField, Serializer
7
9
 
8
10
 
9
11
  class OPDSAuth1LinksSerializer(Serializer):
@@ -1,6 +1,7 @@
1
1
  """OPDS URLs."""
2
2
 
3
- from rest_framework.serializers import CharField, Serializer
3
+ from rest_framework.fields import CharField
4
+ from rest_framework.serializers import Serializer
4
5
 
5
6
 
6
7
  class OPDSURLsSerializer(Serializer):
@@ -2,16 +2,17 @@
2
2
 
3
3
  from zoneinfo import ZoneInfo
4
4
 
5
- from rest_framework.serializers import (
5
+ from rest_framework.fields import (
6
6
  BooleanField,
7
7
  CharField,
8
8
  DateField,
9
9
  DateTimeField,
10
10
  DictField,
11
11
  IntegerField,
12
- Serializer,
13
12
  )
13
+ from rest_framework.serializers import Serializer
14
14
 
15
+ from codex.serializers.fields.browser import TopGroupField
15
16
  from codex.serializers.models.pycountry import LanguageSerializer
16
17
 
17
18
  UTC_TZ = ZoneInfo("UTC")
@@ -25,7 +26,7 @@ class OPDS1TemplateLinkSerializer(Serializer):
25
26
  mime_type = CharField(read_only=True)
26
27
  title = CharField(read_only=True, required=False)
27
28
  length = IntegerField(read_only=True, required=False)
28
- facet_group = CharField(read_only=True, required=False)
29
+ facet_group = TopGroupField(read_only=True, required=False)
29
30
  facet_active = BooleanField(read_only=True, required=False)
30
31
  thr_count = IntegerField(read_only=True, required=False)
31
32
  pse_count = IntegerField(read_only=True, required=False)