erudit 3.0.0-dev.1 → 3.0.0-dev.11

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.
Files changed (254) hide show
  1. package/app/app.vue +195 -172
  2. package/app/components/Loading.vue +23 -23
  3. package/app/components/SiteAside.vue +393 -382
  4. package/app/components/SiteMain.vue +32 -35
  5. package/app/components/ads/BannerTemplate.vue +51 -51
  6. package/app/components/ads/BottomBanner.vue +45 -45
  7. package/app/components/ads/LeftBanner.vue +50 -50
  8. package/app/components/aside/AsideListItem.vue +74 -74
  9. package/app/components/aside/AsideMajor.vue +56 -56
  10. package/app/components/aside/AsideMinor.vue +71 -71
  11. package/app/components/aside/major/PaneContentScroll.vue +23 -23
  12. package/app/components/aside/major/PaneSwitch.vue +54 -54
  13. package/app/components/aside/major/PaneSwitchButton.vue +63 -63
  14. package/app/components/aside/major/SiteInfo.vue +85 -85
  15. package/app/components/aside/major/panes/Language.vue +79 -79
  16. package/app/components/aside/major/panes/Pages.vue +34 -34
  17. package/app/components/aside/major/panes/Search.vue +11 -11
  18. package/app/components/aside/major/panes/nav/Nav.vue +87 -91
  19. package/app/components/aside/major/panes/nav/NavBook.vue +87 -86
  20. package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -24
  21. package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -16
  22. package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -105
  23. package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -32
  24. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -40
  25. package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -60
  26. package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -34
  27. package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -80
  28. package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -24
  29. package/app/components/aside/major/panes/other/ItemContent.vue +29 -29
  30. package/app/components/aside/major/panes/other/ItemGenerator.vue +13 -15
  31. package/app/components/aside/major/panes/other/ItemTheme.vue +54 -54
  32. package/app/components/aside/major/panes/other/Other.vue +16 -16
  33. package/app/components/aside/minor/AsideMinorContributor.vue +5 -5
  34. package/app/components/aside/minor/AsideMinorNews.vue +11 -11
  35. package/app/components/aside/minor/AsideMinorPane.vue +15 -15
  36. package/app/components/aside/minor/AsideMinorTopLink.vue +67 -67
  37. package/app/components/aside/minor/Contribute.vue +145 -145
  38. package/app/components/aside/minor/content/AsideMinorContent.vue +92 -92
  39. package/app/components/aside/minor/topic/AsideMinorTopic.vue +32 -32
  40. package/app/components/aside/minor/topic/TopicContributors.vue +177 -177
  41. package/app/components/aside/minor/topic/TopicNav.vue +49 -49
  42. package/app/components/aside/minor/topic/TopicToc.vue +219 -203
  43. package/app/components/aside/minor/topic/TopicTocItem.vue +30 -31
  44. package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
  45. package/app/components/bitran/BitranContent.vue +91 -63
  46. package/app/components/bitran/RenderWrapper.vue +10 -10
  47. package/app/components/contributor/ContributorAvatar.vue +45 -43
  48. package/app/components/contributor/ContributorListItem.vue +35 -35
  49. package/app/components/main/topic/MainTopic.vue +78 -79
  50. package/app/components/main/topic/TopicPartSwitch.vue +118 -118
  51. package/app/components/main/utils/Breadcrumb.vue +70 -75
  52. package/app/components/main/utils/ContentDecoration.vue +29 -29
  53. package/app/components/main/utils/ContentDescription.vue +19 -19
  54. package/app/components/main/utils/ContentPopover.vue +188 -176
  55. package/app/components/main/utils/ContentPopovers.vue +111 -105
  56. package/app/components/main/utils/ContentReferences.vue +70 -70
  57. package/app/components/main/utils/ContentSection.vue +45 -45
  58. package/app/components/main/utils/ContentTitle.vue +63 -39
  59. package/app/components/main/utils/reference/ReferenceGroup.vue +38 -38
  60. package/app/components/main/utils/reference/ReferenceItem.vue +68 -68
  61. package/app/components/main/utils/reference/ReferenceSource.vue +116 -116
  62. package/app/components/preview/Preview.vue +186 -177
  63. package/app/components/preview/PreviewDisplay.vue +139 -139
  64. package/app/components/preview/PreviewFooterAction.vue +73 -73
  65. package/app/components/preview/PreviewLoading.vue +14 -14
  66. package/app/components/preview/PreviewScreen.vue +141 -99
  67. package/app/components/preview/display/Alert.vue +50 -50
  68. package/app/components/preview/display/Custom.vue +18 -18
  69. package/app/components/preview/display/GenericLink.vue +48 -48
  70. package/app/components/preview/display/PageLink.vue +20 -20
  71. package/app/components/preview/display/Unique.vue +55 -49
  72. package/app/components/transition/Fade.vue +19 -19
  73. package/app/components/tree/TreeContainer.vue +11 -11
  74. package/app/components/tree/TreeItem.vue +89 -89
  75. package/app/composables/bitran.ts +108 -127
  76. package/app/composables/bitranContent.ts +93 -37
  77. package/app/composables/bitranLocation.ts +7 -7
  78. package/app/composables/contentData.ts +36 -36
  79. package/app/composables/contentPage.ts +157 -156
  80. package/app/composables/contentRoute.ts +45 -45
  81. package/app/composables/darkMagic.ts +24 -24
  82. package/app/composables/externalApi.ts +63 -63
  83. package/app/composables/favicon.ts +8 -8
  84. package/app/composables/formatText.ts +86 -86
  85. package/app/composables/majorPane.ts +60 -60
  86. package/app/composables/phrases.ts +81 -80
  87. package/app/composables/theme.ts +29 -29
  88. package/app/composables/url.ts +33 -33
  89. package/app/pages/_test/preview.vue +110 -110
  90. package/app/pages/article/[...articleId].vue +3 -3
  91. package/app/pages/book/[...bookId].vue +47 -47
  92. package/app/pages/group/[...groupId].vue +64 -65
  93. package/app/pages/index.vue +32 -32
  94. package/app/pages/members.vue +6 -6
  95. package/app/pages/practice/[...practice].vue +3 -3
  96. package/app/pages/summary/[...summaryId].vue +3 -3
  97. package/app/public/favicon/article.svg +5 -5
  98. package/app/public/favicon/default.svg +3 -3
  99. package/app/public/favicon/practice.svg +3 -3
  100. package/app/public/favicon/summary.svg +4 -4
  101. package/app/public/logotype.svg +2 -2
  102. package/app/scripts/_immediate.js +9 -9
  103. package/app/scripts/aside/index.ts +59 -59
  104. package/app/scripts/aside/major/nav.ts +26 -26
  105. package/app/scripts/aside/minor/state.ts +37 -37
  106. package/app/scripts/aside/minor/topic.ts +3 -3
  107. package/app/scripts/flag.ts +28 -28
  108. package/app/scripts/og.ts +27 -27
  109. package/app/scripts/preview/build.ts +80 -73
  110. package/app/scripts/preview/data/alert.ts +19 -19
  111. package/app/scripts/preview/data/custom.ts +8 -8
  112. package/app/scripts/preview/data/genericLink.ts +24 -24
  113. package/app/scripts/preview/data/pageLink.ts +22 -20
  114. package/app/scripts/preview/data/unique.ts +72 -70
  115. package/app/scripts/preview/data.ts +24 -24
  116. package/app/scripts/preview/display.ts +37 -37
  117. package/app/scripts/preview/footer.ts +9 -9
  118. package/app/scripts/preview/request.ts +51 -51
  119. package/app/scripts/preview/state.ts +63 -63
  120. package/app/styles/_immediate.css +7 -7
  121. package/app/styles/_util.scss +43 -43
  122. package/app/styles/_utils.scss +44 -44
  123. package/app/styles/app.scss +91 -91
  124. package/app/styles/def/_bp.scss +27 -27
  125. package/app/styles/def/_size.scss +7 -7
  126. package/app/styles/def/_z.scss +5 -5
  127. package/app/styles/normalize.scss +63 -63
  128. package/app/styles/partials/_darkMagic.scss +5 -5
  129. package/app/styles/partials/_fnav.scss +15 -15
  130. package/app/styles/partials/_preview.scss +5 -5
  131. package/bin/erudit.mjs +2 -0
  132. package/const.ts +4 -0
  133. package/globalPath.ts +21 -21
  134. package/globals/bitran.ts +1 -47
  135. package/globals/content.ts +22 -22
  136. package/globals/contributor.ts +5 -5
  137. package/globals/erudit.ts +5 -5
  138. package/globals/register.ts +18 -18
  139. package/languages/en.ts +94 -95
  140. package/languages/ru.ts +98 -99
  141. package/module/bitran.ts +66 -34
  142. package/module/config.ts +35 -34
  143. package/module/imports.ts +66 -46
  144. package/module/index.ts +49 -47
  145. package/module/logger.ts +10 -10
  146. package/module/paths.ts +22 -22
  147. package/module/problemGenerators.ts +46 -0
  148. package/module/restart.ts +61 -61
  149. package/nuxt.config.ts +129 -111
  150. package/package.json +19 -13
  151. package/server/api/aside/major/nav/bookIds.ts +5 -5
  152. package/server/api/aside/major/nav/bookNav/[...bookId].ts +20 -20
  153. package/server/api/aside/major/nav/global.ts +7 -7
  154. package/server/api/aside/minor/news.ts +7 -7
  155. package/server/api/aside/minor/path.ts +77 -78
  156. package/server/api/bitran/content/{[location].ts → [...location].ts} +8 -7
  157. package/server/api/bitran/toc/{[location].ts → [...location].ts} +7 -7
  158. package/server/api/content/data.ts +72 -72
  159. package/server/api/contributor/count.ts +6 -6
  160. package/server/api/fake/content.ts +11 -11
  161. package/server/api/fake/shared/languages.ts +12 -12
  162. package/server/api/language/functions.ts +12 -12
  163. package/server/api/language/phrase/[phraseId].ts +19 -19
  164. package/server/api/language/phraseIds.ts +8 -8
  165. package/server/api/preview/page/[...parts].ts +52 -51
  166. package/server/api/preview/unique/[location].ts +60 -55
  167. package/server/plugin/bitran/content.ts +208 -187
  168. package/server/plugin/bitran/{products → elements}/include.ts +225 -230
  169. package/server/plugin/bitran/location.ts +25 -25
  170. package/server/plugin/bitran/toc.ts +89 -83
  171. package/server/plugin/bitran/transpiler.ts +9 -46
  172. package/server/plugin/build/close.ts +12 -10
  173. package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
  174. package/server/plugin/build/jobs/content/generic.ts +192 -176
  175. package/server/plugin/build/jobs/content/parse.ts +109 -100
  176. package/server/plugin/build/jobs/content/path.ts +6 -6
  177. package/server/plugin/build/jobs/content/type/book.ts +9 -9
  178. package/server/plugin/build/jobs/content/type/group.ts +37 -37
  179. package/server/plugin/build/jobs/content/type/topic.ts +36 -36
  180. package/server/plugin/build/jobs/contributors.ts +66 -66
  181. package/server/plugin/build/jobs/language.ts +36 -36
  182. package/server/plugin/build/jobs/nav.ts +214 -209
  183. package/server/plugin/build/process.ts +27 -25
  184. package/server/plugin/build/rebuild.ts +66 -55
  185. package/server/plugin/build/setup.ts +19 -21
  186. package/server/plugin/content/context.ts +116 -112
  187. package/server/plugin/db/entities/Book.ts +7 -7
  188. package/server/plugin/db/entities/Content.ts +49 -49
  189. package/server/plugin/db/entities/Contribution.ts +10 -10
  190. package/server/plugin/db/entities/Contributor.ts +16 -16
  191. package/server/plugin/db/entities/File.ts +10 -0
  192. package/server/plugin/db/entities/Group.ts +14 -14
  193. package/server/plugin/db/entities/Hash.ts +15 -15
  194. package/server/plugin/db/entities/Topic.ts +20 -20
  195. package/server/plugin/db/entities/Unique.ts +21 -21
  196. package/server/plugin/db/reset.ts +12 -0
  197. package/server/plugin/db/setup.ts +49 -34
  198. package/server/plugin/global.ts +16 -18
  199. package/server/plugin/importer.ts +12 -12
  200. package/server/plugin/index.ts +9 -9
  201. package/server/plugin/logger.ts +23 -23
  202. package/server/plugin/nav/node.ts +26 -26
  203. package/server/plugin/nav/utils.ts +133 -129
  204. package/server/plugin/repository/book.ts +21 -21
  205. package/server/plugin/repository/content.ts +237 -238
  206. package/server/plugin/repository/contributor.ts +8 -8
  207. package/server/plugin/repository/file.ts +10 -0
  208. package/server/plugin/repository/frontNav.ts +148 -148
  209. package/server/plugin/repository/topic.ts +32 -32
  210. package/server/tsconfig.json +9 -7
  211. package/shared/aside/minor.ts +51 -50
  212. package/shared/asset.ts +22 -15
  213. package/shared/bitran/contentId.ts +88 -0
  214. package/shared/bitran/stringContent.ts +6 -0
  215. package/shared/bitran/toc.ts +8 -8
  216. package/shared/content/context.ts +9 -9
  217. package/shared/content/data/base.ts +32 -32
  218. package/shared/content/data/index.ts +5 -5
  219. package/shared/content/data/type/book.ts +5 -5
  220. package/shared/content/data/type/group.ts +6 -6
  221. package/shared/content/data/type/topic.ts +11 -11
  222. package/shared/content/previousNext.ts +9 -9
  223. package/shared/contributor.ts +5 -5
  224. package/shared/frontNav.ts +41 -41
  225. package/shared/icons.ts +38 -38
  226. package/shared/image.ts +5 -5
  227. package/shared/link.ts +28 -25
  228. package/shared/popover.ts +8 -0
  229. package/shared/types/language.ts +74 -75
  230. package/shared/utils/objectsEqual.ts +4 -4
  231. package/shared/utils/stringColor.ts +9 -9
  232. package/test/contentId.test.ts +91 -0
  233. package/tsconfig.json +8 -8
  234. package/utils/contentPath.ts +67 -0
  235. package/utils/stress.ts +9 -9
  236. package/app/components/main/utils/ContentFlag.vue +0 -15
  237. package/app/styles/default.scss +0 -83
  238. package/server/plugin/bitran/products/link.ts +0 -116
  239. package/server/plugin/bitran/setup.ts +0 -9
  240. package/server/plugin/content/absoluteId.ts +0 -94
  241. package/shared/bitran/context.ts +0 -8
  242. package/shared/bitran/default.ts +0 -46
  243. package/shared/bitran/link/Link.vue +0 -167
  244. package/shared/bitran/link/factory.ts +0 -24
  245. package/shared/bitran/link/icon.svg +0 -3
  246. package/shared/bitran/link/languages/en.ts +0 -7
  247. package/shared/bitran/link/languages/ru.ts +0 -7
  248. package/shared/bitran/link/renderer.ts +0 -21
  249. package/shared/bitran/link/shared.ts +0 -17
  250. package/shared/bitran/link/target.ts +0 -134
  251. package/shared/bitran/link/transpiler.ts +0 -10
  252. package/shared/bitran/location.ts +0 -166
  253. package/test/bitran/link/target.test.ts +0 -141
  254. package/test/bitran/location.test.ts +0 -143
@@ -1,238 +1,237 @@
1
- import type { ContentType } from 'erudit-cog/schema';
2
- import { Like } from 'typeorm';
3
-
4
- import { ERUDIT_SERVER } from '@server/global';
5
- import { DbContent } from '@server/db/entities/Content';
6
- import { DbContribution } from '@server/db/entities/Contribution';
7
-
8
- import { getContentContext } from '@server/content/context';
9
- import type { ContentGenericData } from '@shared/content/data/base';
10
- import { getIdsUp, getPreviousNextNav } from '../nav/utils';
11
- import { createContentLink, createTopicPartLink } from '@erudit/shared/link';
12
- import { getTopicPart } from './topic';
13
- import type { PreviousNextItem } from '@erudit/shared/content/previousNext';
14
- import type { NavNode } from '../nav/node';
15
- import { toAbsoluteContentId } from '../content/absoluteId';
16
-
17
- import type { ContentContributor } from '@erudit/shared/contributor';
18
- import { DbContributor } from '../db/entities/Contributor';
19
-
20
- export async function getContentGenericData(
21
- contentId: string,
22
- ): Promise<ContentGenericData> {
23
- const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
24
- where: { contentId },
25
- });
26
-
27
- if (!dbContent)
28
- throw createError({
29
- statusCode: 404,
30
- message: `Content item "${contentId}" not found!`,
31
- });
32
-
33
- const previousNext = await getPreviousNext(contentId);
34
- const decoration = await getContentDecoration(contentId);
35
- const flags = await getContentFlags(contentId);
36
-
37
- const contentPage: ContentGenericData = {
38
- contentId,
39
- type: dbContent.type,
40
- title: dbContent.title || undefined,
41
- description: dbContent.description || undefined,
42
- flags,
43
- previousNext,
44
- decoration,
45
- context: await getContentContext(contentId),
46
- seo: dbContent.seo,
47
- ogImage: dbContent.ogImage,
48
- dependencies: dbContent.dependencies
49
- ? await getContentDependencies(contentId, dbContent.dependencies)
50
- : undefined,
51
- references: dbContent.references,
52
- };
53
-
54
- return contentPage;
55
- }
56
-
57
- export async function getPreviousNext(contentId: string) {
58
- const { previousNav, nextNav } = await getPreviousNextNav(contentId);
59
-
60
- async function getItemData(navNode: NavNode): Promise<PreviousNextItem> {
61
- const title = await getContentTitle(navNode.id);
62
-
63
- const link = await (async () => {
64
- if (navNode.type === 'topic')
65
- return createTopicPartLink(
66
- await getTopicPart(navNode.id),
67
- navNode.id,
68
- );
69
-
70
- return createContentLink(navNode.type, navNode.id);
71
- })();
72
-
73
- return {
74
- title,
75
- link,
76
- };
77
- }
78
-
79
- return {
80
- previous: previousNav ? await getItemData(previousNav) : undefined,
81
- next: nextNav ? await getItemData(nextNav) : undefined,
82
- };
83
- }
84
-
85
- export async function getContentDecoration(contentId: string) {
86
- const idsUp = await getIdsUp(contentId);
87
-
88
- for (const id of idsUp) {
89
- const decoration = (
90
- await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
91
- select: ['decoration'],
92
- where: { contentId: id },
93
- })
94
- )?.decoration;
95
-
96
- if (decoration) return decoration;
97
- }
98
-
99
- return undefined;
100
- }
101
-
102
- export async function getContentFlags(contentId: string) {
103
- const idsUp = await getIdsUp(contentId);
104
- const flags: any = {};
105
-
106
- for (const id of idsUp.reverse()) {
107
- const dbFlags = (
108
- await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
109
- select: ['flags'],
110
- where: { contentId: id },
111
- })
112
- )?.flags;
113
-
114
- if (dbFlags)
115
- for (const [flagName, flagValue] of Object.entries(dbFlags))
116
- flags[flagName] = flagValue;
117
- }
118
-
119
- for (const [flagName, flagValue] of Object.entries(flags))
120
- if (flagValue === false) delete flags[flagName];
121
-
122
- return flags;
123
- }
124
-
125
- export async function getContentDependencies(
126
- contentId: string,
127
- strDependencies: string[],
128
- ) {
129
- const dependencyIds = strDependencies.map((rawDependency) =>
130
- toAbsoluteContentId(rawDependency, contentId),
131
- );
132
- const dependencies: Record<string, string> = {};
133
-
134
- for (const dependencyId of dependencyIds)
135
- dependencies[await getContentLink(dependencyId)] =
136
- await getContentTitle(dependencyId);
137
-
138
- return dependencies;
139
- }
140
-
141
- export async function getContentTitle(contentId: string) {
142
- const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
143
- select: ['title'],
144
- where: { contentId },
145
- });
146
-
147
- return dbContent?.title || contentId.split('/').pop()!;
148
- }
149
-
150
- export async function getContentLink(contentId: string) {
151
- const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
152
- select: ['type'],
153
- where: { contentId },
154
- });
155
-
156
- if (!dbContent)
157
- throw createError({
158
- statusCode: 404,
159
- statusText: `Missing "${contentId}" content item!`,
160
- });
161
-
162
- if (dbContent.type !== 'topic')
163
- return createContentLink(dbContent.type, contentId);
164
-
165
- const topicPart = await getTopicPart(contentId);
166
-
167
- return createTopicPartLink(topicPart, contentId);
168
- }
169
-
170
- export async function getFullContentId(contentId: string) {
171
- const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
172
- select: ['fullId'],
173
- where: { contentId },
174
- });
175
-
176
- return dbContent?.fullId;
177
- }
178
-
179
- export async function getContentContributors(contentId: string) {
180
- const contributorIds = await (async () => {
181
- const idHash: Record<string, true> = {};
182
-
183
- (
184
- await ERUDIT_SERVER.DB.manager.find(DbContribution, {
185
- select: ['contributorId'],
186
- where: { contentId },
187
- })
188
- ).forEach(
189
- (contribution) => (idHash[contribution.contributorId] = true),
190
- );
191
-
192
- const type: ContentType = (await ERUDIT_SERVER.DB.manager.findOne(
193
- DbContent,
194
- {
195
- select: ['type'],
196
- where: { contentId },
197
- },
198
- ))!.type;
199
-
200
- if (type === 'book' || type === 'group') {
201
- // Collecting contributors for all sub-content items
202
- (
203
- await ERUDIT_SERVER.DB.manager.find(DbContribution, {
204
- select: ['contributorId'],
205
- where: { contentId: Like(`${contentId}/%`) },
206
- })
207
- ).forEach(
208
- (contribution) => (idHash[contribution.contributorId] = true),
209
- );
210
- }
211
-
212
- return Object.keys(idHash);
213
- })();
214
-
215
- const contentContributors: ContentContributor[] = [];
216
-
217
- for (const contributorId of contributorIds) {
218
- const dbContributor = (await ERUDIT_SERVER.DB.manager.findOne(
219
- DbContributor,
220
- {
221
- select: ['contributorId', 'displayName', 'avatar'],
222
- where: { contributorId },
223
- },
224
- ))!;
225
-
226
- const contentContributor: ContentContributor = { contributorId };
227
-
228
- if (dbContributor.displayName)
229
- contentContributor.displayName = dbContributor.displayName;
230
-
231
- if (dbContributor.avatar)
232
- contentContributor.avatar = dbContributor.avatar;
233
-
234
- contentContributors.push(contentContributor);
235
- }
236
-
237
- return contentContributors.length ? contentContributors : undefined;
238
- }
1
+ import type { ContentType } from '@erudit-js/cog/schema';
2
+ import { Like } from 'typeorm';
3
+
4
+ import { ERUDIT_SERVER } from '@server/global';
5
+ import { DbContent } from '@server/db/entities/Content';
6
+ import { DbContribution } from '@server/db/entities/Contribution';
7
+ import { getContentContext } from '@server/content/context';
8
+ import { DbContributor } from '@server/db/entities/Contributor';
9
+ import { getIdsUp, getNavBookIds, getPreviousNextNav } from '@server/nav/utils';
10
+ import { getTopicPart } from './topic';
11
+ import type { NavNode } from '../nav/node';
12
+
13
+ import { createContentLink, createTopicPartLink } from '@erudit/shared/link';
14
+ import type { PreviousNextItem } from '@erudit/shared/content/previousNext';
15
+ import type { ContentContributor } from '@erudit/shared/contributor';
16
+ import type { ContentGenericData } from '@shared/content/data/base';
17
+ import { toAbsoluteContentId } from '@erudit/shared/bitran/contentId';
18
+
19
+ export async function getContentGenericData(
20
+ contentId: string,
21
+ ): Promise<ContentGenericData> {
22
+ const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
23
+ where: { contentId },
24
+ });
25
+
26
+ if (!dbContent)
27
+ throw createError({
28
+ statusCode: 404,
29
+ message: `Content item "${contentId}" not found!`,
30
+ });
31
+
32
+ const previousNext = await getPreviousNext(contentId);
33
+ const decoration = await getContentDecoration(contentId);
34
+ const flags = await getContentFlags(contentId);
35
+
36
+ const contentPage: ContentGenericData = {
37
+ contentId,
38
+ type: dbContent.type,
39
+ title: dbContent.title || undefined,
40
+ description: dbContent.description || undefined,
41
+ flags,
42
+ previousNext,
43
+ decoration,
44
+ context: await getContentContext(contentId),
45
+ seo: dbContent.seo,
46
+ ogImage: dbContent.ogImage,
47
+ dependencies: dbContent.dependencies
48
+ ? await getContentDependencies(contentId, dbContent.dependencies)
49
+ : undefined,
50
+ references: dbContent.references,
51
+ };
52
+
53
+ return contentPage;
54
+ }
55
+
56
+ export async function getPreviousNext(contentId: string) {
57
+ const { previousNav, nextNav } = await getPreviousNextNav(contentId);
58
+
59
+ async function getItemData(navNode: NavNode): Promise<PreviousNextItem> {
60
+ const title = await getContentTitle(navNode.id);
61
+
62
+ const link = await (async () => {
63
+ if (navNode.type === 'topic')
64
+ return createTopicPartLink(
65
+ await getTopicPart(navNode.id),
66
+ navNode.id,
67
+ );
68
+
69
+ return createContentLink(navNode.type, navNode.id);
70
+ })();
71
+
72
+ return {
73
+ title,
74
+ link,
75
+ };
76
+ }
77
+
78
+ return {
79
+ previous: previousNav ? await getItemData(previousNav) : undefined,
80
+ next: nextNav ? await getItemData(nextNav) : undefined,
81
+ };
82
+ }
83
+
84
+ export async function getContentDecoration(contentId: string) {
85
+ const idsUp = await getIdsUp(contentId);
86
+
87
+ for (const id of idsUp) {
88
+ const decoration = (
89
+ await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
90
+ select: ['decoration'],
91
+ where: { contentId: id },
92
+ })
93
+ )?.decoration;
94
+
95
+ if (decoration) return decoration;
96
+ }
97
+
98
+ return undefined;
99
+ }
100
+
101
+ export async function getContentFlags(contentId: string) {
102
+ const idsUp = await getIdsUp(contentId);
103
+ const flags: any = {};
104
+
105
+ for (const id of idsUp.reverse()) {
106
+ const dbFlags = (
107
+ await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
108
+ select: ['flags'],
109
+ where: { contentId: id },
110
+ })
111
+ )?.flags;
112
+
113
+ if (dbFlags)
114
+ for (const [flagName, flagValue] of Object.entries(dbFlags))
115
+ flags[flagName] = flagValue;
116
+ }
117
+
118
+ for (const [flagName, flagValue] of Object.entries(flags))
119
+ if (flagValue === false) delete flags[flagName];
120
+
121
+ return flags;
122
+ }
123
+
124
+ export async function getContentDependencies(
125
+ contentId: string,
126
+ strDependencies: string[],
127
+ ) {
128
+ const dependencyIds = strDependencies.map((rawDependency) =>
129
+ toAbsoluteContentId(rawDependency, contentId, getNavBookIds()),
130
+ );
131
+ const dependencies: Record<string, string> = {};
132
+
133
+ for (const dependencyId of dependencyIds)
134
+ dependencies[await getContentLink(dependencyId)] =
135
+ await getContentTitle(dependencyId);
136
+
137
+ return dependencies;
138
+ }
139
+
140
+ export async function getContentTitle(contentId: string) {
141
+ const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
142
+ select: ['title'],
143
+ where: { contentId },
144
+ });
145
+
146
+ return dbContent?.title || contentId.split('/').pop()!;
147
+ }
148
+
149
+ export async function getContentLink(contentId: string) {
150
+ const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
151
+ select: ['type'],
152
+ where: { contentId },
153
+ });
154
+
155
+ if (!dbContent)
156
+ throw createError({
157
+ statusCode: 404,
158
+ statusText: `Missing "${contentId}" content item!`,
159
+ });
160
+
161
+ if (dbContent.type !== 'topic')
162
+ return createContentLink(dbContent.type, contentId);
163
+
164
+ const topicPart = await getTopicPart(contentId);
165
+
166
+ return createTopicPartLink(topicPart, contentId);
167
+ }
168
+
169
+ export async function getFullContentId(contentId: string) {
170
+ const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
171
+ select: ['fullId'],
172
+ where: { contentId },
173
+ });
174
+
175
+ return dbContent?.fullId;
176
+ }
177
+
178
+ export async function getContentContributors(contentId: string) {
179
+ const contributorIds = await (async () => {
180
+ const idHash: Record<string, true> = {};
181
+
182
+ (
183
+ await ERUDIT_SERVER.DB.manager.find(DbContribution, {
184
+ select: ['contributorId'],
185
+ where: { contentId },
186
+ })
187
+ ).forEach(
188
+ (contribution) => (idHash[contribution.contributorId] = true),
189
+ );
190
+
191
+ const type: ContentType = (await ERUDIT_SERVER.DB.manager.findOne(
192
+ DbContent,
193
+ {
194
+ select: ['type'],
195
+ where: { contentId },
196
+ },
197
+ ))!.type;
198
+
199
+ if (type === 'book' || type === 'group') {
200
+ // Collecting contributors for all sub-content items
201
+ (
202
+ await ERUDIT_SERVER.DB.manager.find(DbContribution, {
203
+ select: ['contributorId'],
204
+ where: { contentId: Like(`${contentId}/%`) },
205
+ })
206
+ ).forEach(
207
+ (contribution) => (idHash[contribution.contributorId] = true),
208
+ );
209
+ }
210
+
211
+ return Object.keys(idHash);
212
+ })();
213
+
214
+ const contentContributors: ContentContributor[] = [];
215
+
216
+ for (const contributorId of contributorIds) {
217
+ const dbContributor = (await ERUDIT_SERVER.DB.manager.findOne(
218
+ DbContributor,
219
+ {
220
+ select: ['contributorId', 'displayName', 'avatar'],
221
+ where: { contributorId },
222
+ },
223
+ ))!;
224
+
225
+ const contentContributor: ContentContributor = { contributorId };
226
+
227
+ if (dbContributor.displayName)
228
+ contentContributor.displayName = dbContributor.displayName;
229
+
230
+ if (dbContributor.avatar)
231
+ contentContributor.avatar = dbContributor.avatar;
232
+
233
+ contentContributors.push(contentContributor);
234
+ }
235
+
236
+ return contentContributors.length ? contentContributors : undefined;
237
+ }
@@ -1,8 +1,8 @@
1
- import { DbContributor } from '@server/db/entities/Contributor';
2
- import { ERUDIT_SERVER } from '@server/global';
3
-
4
- export async function contributorExists(contributorId: string) {
5
- return await ERUDIT_SERVER.DB.manager.exists(DbContributor, {
6
- where: { contributorId },
7
- });
8
- }
1
+ import { DbContributor } from '@server/db/entities/Contributor';
2
+ import { ERUDIT_SERVER } from '@server/global';
3
+
4
+ export async function contributorExists(contributorId: string) {
5
+ return await ERUDIT_SERVER.DB.manager.exists(DbContributor, {
6
+ where: { contributorId },
7
+ });
8
+ }
@@ -0,0 +1,10 @@
1
+ import { ERUDIT_SERVER } from '@server/global';
2
+ import { DbFile } from '@server/db/entities/File';
3
+
4
+ export async function getFileFullPath(path: string) {
5
+ const dbFile = await ERUDIT_SERVER.DB.manager.findOne(DbFile, {
6
+ where: { path },
7
+ });
8
+
9
+ return dbFile?.fullPath;
10
+ }