@drodil/backstage-plugin-qeta-backend 3.47.2 → 3.48.0
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.
- package/dist/database/DatabaseQetaStore.cjs.js +317 -1896
- package/dist/database/DatabaseQetaStore.cjs.js.map +1 -1
- package/dist/database/QetaStore.cjs.js.map +1 -1
- package/dist/database/stores/AnswersStore.cjs.js +253 -0
- package/dist/database/stores/AnswersStore.cjs.js.map +1 -0
- package/dist/database/stores/AttachmentsStore.cjs.js +72 -0
- package/dist/database/stores/AttachmentsStore.cjs.js.map +1 -0
- package/dist/database/stores/BaseStore.cjs.js +117 -0
- package/dist/database/stores/BaseStore.cjs.js.map +1 -0
- package/dist/database/stores/CollectionsStore.cjs.js +268 -0
- package/dist/database/stores/CollectionsStore.cjs.js.map +1 -0
- package/dist/database/stores/CommentsStore.cjs.js +136 -0
- package/dist/database/stores/CommentsStore.cjs.js.map +1 -0
- package/dist/database/stores/EntitiesStore.cjs.js +148 -0
- package/dist/database/stores/EntitiesStore.cjs.js.map +1 -0
- package/dist/database/stores/PostsStore.cjs.js +606 -0
- package/dist/database/stores/PostsStore.cjs.js.map +1 -0
- package/dist/database/stores/StatsStore.cjs.js +222 -0
- package/dist/database/stores/StatsStore.cjs.js.map +1 -0
- package/dist/database/stores/TagsStore.cjs.js +214 -0
- package/dist/database/stores/TagsStore.cjs.js.map +1 -0
- package/dist/database/stores/TemplatesStore.cjs.js +134 -0
- package/dist/database/stores/TemplatesStore.cjs.js.map +1 -0
- package/dist/database/stores/UsersStore.cjs.js +144 -0
- package/dist/database/stores/UsersStore.cjs.js.map +1 -0
- package/dist/service/PermissionManager.cjs.js +39 -28
- package/dist/service/PermissionManager.cjs.js.map +1 -1
- package/dist/service/routes/answers.cjs.js +47 -47
- package/dist/service/routes/answers.cjs.js.map +1 -1
- package/dist/service/routes/collections.cjs.js +24 -32
- package/dist/service/routes/collections.cjs.js.map +1 -1
- package/dist/service/routes/helpers.cjs.js +9 -13
- package/dist/service/routes/helpers.cjs.js.map +1 -1
- package/dist/service/routes/posts.cjs.js +33 -45
- package/dist/service/routes/posts.cjs.js.map +1 -1
- package/dist/service/routes/routeUtil.cjs.js +2 -1
- package/dist/service/routes/routeUtil.cjs.js.map +1 -1
- package/dist/service/types.cjs.js +1 -0
- package/dist/service/types.cjs.js.map +1 -1
- package/dist/service/util.cjs.js +174 -115
- package/dist/service/util.cjs.js.map +1 -1
- package/migrations/20251217_votes_count.js +48 -0
- package/migrations/20251218_posts_counts.js +47 -0
- package/migrations/20251218_x_collections_posts_count.js +26 -0
- package/package.json +26 -26
|
@@ -1,84 +1,33 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
4
|
+
var PostsStore = require('./stores/PostsStore.cjs.js');
|
|
5
|
+
var AnswersStore = require('./stores/AnswersStore.cjs.js');
|
|
6
|
+
var CommentsStore = require('./stores/CommentsStore.cjs.js');
|
|
7
|
+
var CollectionsStore = require('./stores/CollectionsStore.cjs.js');
|
|
8
|
+
var StatsStore = require('./stores/StatsStore.cjs.js');
|
|
9
|
+
var TagsStore = require('./stores/TagsStore.cjs.js');
|
|
10
|
+
var UsersStore = require('./stores/UsersStore.cjs.js');
|
|
11
|
+
var EntitiesStore = require('./stores/EntitiesStore.cjs.js');
|
|
12
|
+
var TemplatesStore = require('./stores/TemplatesStore.cjs.js');
|
|
13
|
+
var AttachmentsStore = require('./stores/AttachmentsStore.cjs.js');
|
|
8
14
|
|
|
9
15
|
const migrationsDir = backendPluginApi.resolvePackagePath(
|
|
10
16
|
"@drodil/backstage-plugin-qeta-backend",
|
|
11
17
|
"migrations"
|
|
12
18
|
);
|
|
13
|
-
function isQetaFilter(filter) {
|
|
14
|
-
return filter.hasOwnProperty("property");
|
|
15
|
-
}
|
|
16
|
-
function parseFilter(filter, query, db, type = "post", negate = false) {
|
|
17
|
-
if (pluginPermissionNode.isNotCriteria(filter)) {
|
|
18
|
-
return parseFilter(filter.not, query, db, type, !negate);
|
|
19
|
-
}
|
|
20
|
-
if (isQetaFilter(filter)) {
|
|
21
|
-
const values = lodash.compact(filter.values) ?? [];
|
|
22
|
-
let fk = "posts.id";
|
|
23
|
-
if (type === "answer") {
|
|
24
|
-
fk = "answers.postId";
|
|
25
|
-
} else if (type === "collection") {
|
|
26
|
-
fk = "collection_posts.postId";
|
|
27
|
-
}
|
|
28
|
-
if (filter.property === "tags") {
|
|
29
|
-
const postIds = db("tags").leftJoin("post_tags", "tags.id", "post_tags.tagId").where("tags.tag", "in", values).select("post_tags.postId");
|
|
30
|
-
query.whereIn(fk, postIds);
|
|
31
|
-
return query;
|
|
32
|
-
}
|
|
33
|
-
if (filter.property === "tag.experts") {
|
|
34
|
-
if (type === "post") {
|
|
35
|
-
const postIds = db("tags").leftJoin("post_tags", "tags.id", "post_tags.tagId").leftJoin("tag_experts", "tag_experts.tagId", "tags.id").where("tag_experts.entityRef", "in", values).select("post_tags.postId");
|
|
36
|
-
query.whereIn(fk, postIds);
|
|
37
|
-
return query;
|
|
38
|
-
} else if (type === "answer") {
|
|
39
|
-
const answerIds = db("answers").leftJoin("posts", "answers.postId", "posts.id").leftJoin("post_tags", "post_tags.postId", "posts.id").leftJoin("post_tags", "tags.id", "post_tags.tagId").leftJoin("tag_experts", "tag_experts.tagId", "tags.id").where("tag_experts.entityRef", "in", values).select("answers.id");
|
|
40
|
-
query.whereIn(fk, answerIds);
|
|
41
|
-
return query;
|
|
42
|
-
} else if (type === "tags") {
|
|
43
|
-
const tagIds = db("tag_experts").leftJoin("tags", "tag_experts.tagId", "tags.id").where("tag_experts.entityRef", "in", values).select("tag_experts.tagId");
|
|
44
|
-
query.whereIn(fk, tagIds);
|
|
45
|
-
return query;
|
|
46
|
-
} else if (type === "collection") {
|
|
47
|
-
const collectionIds = db("collection_posts").leftJoin("posts", "collection_posts.postId", "posts.id").leftJoin("post_tags", "post_tags.postId", "posts.id").leftJoin("post_tags", "tags.id", "post_tags.tagId").leftJoin("tag_experts", "tag_experts.tagId", "tags.id").where("tag_experts.entityRef", "in", values).select("collection_posts.collectionId");
|
|
48
|
-
query.whereIn(fk, collectionIds);
|
|
49
|
-
return query;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (filter.property === "entityRefs") {
|
|
53
|
-
const postIds = db("entities").leftJoin("post_entities", "entities.id", "post_entities.entityId").where("entities.entity_ref", "in", values).select("post_entities.postId");
|
|
54
|
-
query.whereIn(fk, postIds);
|
|
55
|
-
return query;
|
|
56
|
-
}
|
|
57
|
-
if (values.length === 0) {
|
|
58
|
-
return query.whereNull(filter.property);
|
|
59
|
-
}
|
|
60
|
-
return query.whereIn(filter.property, values);
|
|
61
|
-
}
|
|
62
|
-
return query[negate ? "andWhereNot" : "andWhere"](function filterFunction() {
|
|
63
|
-
if (pluginPermissionNode.isOrCriteria(filter)) {
|
|
64
|
-
for (const subFilter of filter.anyOf ?? []) {
|
|
65
|
-
this.orWhere(
|
|
66
|
-
(subQuery) => parseFilter(subFilter, subQuery, db, type, false)
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
} else if (pluginPermissionNode.isAndCriteria(filter)) {
|
|
70
|
-
for (const subFilter of filter.allOf ?? []) {
|
|
71
|
-
this.andWhere(
|
|
72
|
-
(subQuery) => parseFilter(subFilter, subQuery, db, type, false)
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
19
|
class DatabaseQetaStore {
|
|
79
|
-
constructor(
|
|
80
|
-
this.
|
|
81
|
-
this.
|
|
20
|
+
constructor(postsStore, answersStore, commentsStore, collectionsStore, statsStore, tagsStore, usersStore, entitiesStore, templatesStore, attachmentsStore) {
|
|
21
|
+
this.postsStore = postsStore;
|
|
22
|
+
this.answersStore = answersStore;
|
|
23
|
+
this.commentsStore = commentsStore;
|
|
24
|
+
this.collectionsStore = collectionsStore;
|
|
25
|
+
this.statsStore = statsStore;
|
|
26
|
+
this.tagsStore = tagsStore;
|
|
27
|
+
this.usersStore = usersStore;
|
|
28
|
+
this.entitiesStore = entitiesStore;
|
|
29
|
+
this.templatesStore = templatesStore;
|
|
30
|
+
this.attachmentsStore = attachmentsStore;
|
|
82
31
|
}
|
|
83
32
|
static async create({
|
|
84
33
|
database,
|
|
@@ -88,1946 +37,418 @@ class DatabaseQetaStore {
|
|
|
88
37
|
const client = await database.getClient();
|
|
89
38
|
if (!database.migrations?.skip && !skipMigrations) {
|
|
90
39
|
await client.migrate.latest({
|
|
91
|
-
// nosonar
|
|
92
40
|
directory: migrationsDir
|
|
93
41
|
});
|
|
94
42
|
}
|
|
95
|
-
|
|
43
|
+
const commentsStore = new CommentsStore.CommentsStore(client);
|
|
44
|
+
const tagsStore = new TagsStore.TagsStore(client, tagDatabase);
|
|
45
|
+
const entitiesStore = new EntitiesStore.EntitiesStore(client);
|
|
46
|
+
const usersStore = new UsersStore.UsersStore(client);
|
|
47
|
+
const templatesStore = new TemplatesStore.TemplatesStore(client, tagsStore, entitiesStore);
|
|
48
|
+
const attachmentsStore = new AttachmentsStore.AttachmentsStore(client);
|
|
49
|
+
const postsStore = new PostsStore.PostsStore(
|
|
50
|
+
client,
|
|
51
|
+
commentsStore,
|
|
52
|
+
tagsStore,
|
|
53
|
+
entitiesStore,
|
|
54
|
+
attachmentsStore,
|
|
55
|
+
tagDatabase
|
|
56
|
+
);
|
|
57
|
+
const answersStore = new AnswersStore.AnswersStore(
|
|
58
|
+
client,
|
|
59
|
+
commentsStore,
|
|
60
|
+
postsStore,
|
|
61
|
+
attachmentsStore
|
|
62
|
+
);
|
|
63
|
+
const collectionsStore = new CollectionsStore.CollectionsStore(
|
|
64
|
+
client,
|
|
65
|
+
postsStore,
|
|
66
|
+
attachmentsStore
|
|
67
|
+
);
|
|
68
|
+
const statsStore = new StatsStore.StatsStore(client);
|
|
69
|
+
postsStore.setAnswersStore(answersStore);
|
|
70
|
+
return new DatabaseQetaStore(
|
|
71
|
+
postsStore,
|
|
72
|
+
answersStore,
|
|
73
|
+
commentsStore,
|
|
74
|
+
collectionsStore,
|
|
75
|
+
statsStore,
|
|
76
|
+
tagsStore,
|
|
77
|
+
usersStore,
|
|
78
|
+
entitiesStore,
|
|
79
|
+
templatesStore,
|
|
80
|
+
attachmentsStore
|
|
81
|
+
);
|
|
96
82
|
}
|
|
97
83
|
async getPosts(user_ref, options, filters, opts) {
|
|
98
|
-
|
|
99
|
-
const query = this.getPostsBaseQuery(user_ref);
|
|
100
|
-
if (options.type) {
|
|
101
|
-
query.where("posts.type", options.type);
|
|
102
|
-
}
|
|
103
|
-
if (options.fromDate && options.toDate) {
|
|
104
|
-
query.whereBetween("posts.created", [
|
|
105
|
-
`${options.fromDate} 00:00:00.000+00`,
|
|
106
|
-
`${options.toDate} 23:59:59.999+00`
|
|
107
|
-
]);
|
|
108
|
-
} else if (options.fromDate) {
|
|
109
|
-
query.where("posts.created", ">=", `${options.fromDate} 00:00:00.000+00`);
|
|
110
|
-
} else if (options.toDate) {
|
|
111
|
-
query.where("posts.created", "<=", `${options.toDate} 23:59:59.999+00`);
|
|
112
|
-
}
|
|
113
|
-
if (options.author) {
|
|
114
|
-
if (Array.isArray(options.author)) {
|
|
115
|
-
query.whereIn("posts.author", options.author);
|
|
116
|
-
} else {
|
|
117
|
-
query.where("posts.author", "=", options.author);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
if (options.excludeAuthors) {
|
|
121
|
-
query.whereNotIn("posts.author", options.excludeAuthors);
|
|
122
|
-
}
|
|
123
|
-
if (options.status) {
|
|
124
|
-
if (options.status === "draft") {
|
|
125
|
-
query.where("posts.author", "=", user_ref);
|
|
126
|
-
}
|
|
127
|
-
query.where("posts.status", "=", options.status);
|
|
128
|
-
} else if (includeDraftFilter) {
|
|
129
|
-
query.where((q) => {
|
|
130
|
-
q.where("posts.status", "active").orWhere((q2) => {
|
|
131
|
-
q2.where("posts.status", "draft").where(
|
|
132
|
-
"posts.author",
|
|
133
|
-
"=",
|
|
134
|
-
user_ref
|
|
135
|
-
);
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
if (filters) {
|
|
140
|
-
parseFilter(filters, query, this.db);
|
|
141
|
-
}
|
|
142
|
-
if (options.searchQuery) {
|
|
143
|
-
this.applySearchQuery(
|
|
144
|
-
query,
|
|
145
|
-
["posts.title", "posts.content"],
|
|
146
|
-
options.searchQuery
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
if (options.tags) {
|
|
150
|
-
const tags = backstagePluginQetaCommon.filterTags(options.tags);
|
|
151
|
-
if (options.tagsRelation === "or") {
|
|
152
|
-
query.innerJoin("post_tags", "posts.id", "post_tags.postId");
|
|
153
|
-
query.innerJoin("tags", "post_tags.tagId", "tags.id");
|
|
154
|
-
query.whereIn("tags.tag", tags);
|
|
155
|
-
} else {
|
|
156
|
-
tags.forEach((t, i) => {
|
|
157
|
-
query.innerJoin(`post_tags AS qt${i}`, "posts.id", `qt${i}.postId`);
|
|
158
|
-
query.innerJoin(`tags AS t${i}`, `qt${i}.tagId`, `t${i}.id`);
|
|
159
|
-
query.where(`t${i}.tag`, "=", t);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
if (options.entities) {
|
|
164
|
-
const entityValues = Array.isArray(options.entities) ? options.entities : [options.entities];
|
|
165
|
-
if (options.entitiesRelation === "or") {
|
|
166
|
-
query.innerJoin("post_entities", "posts.id", "post_entities.postId").innerJoin("entities", "post_entities.entityId", "entities.id").whereIn("entities.entity_ref", entityValues);
|
|
167
|
-
} else {
|
|
168
|
-
entityValues.forEach((t, i) => {
|
|
169
|
-
query.innerJoin(
|
|
170
|
-
`post_entities AS pe${i}`,
|
|
171
|
-
"posts.id",
|
|
172
|
-
`pe${i}.postId`
|
|
173
|
-
);
|
|
174
|
-
query.innerJoin(`entities AS e${i}`, `pe${i}.entityId`, `e${i}.id`);
|
|
175
|
-
query.where(`e${i}.entity_ref`, "=", t);
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (options.collectionId) {
|
|
180
|
-
query.innerJoin(
|
|
181
|
-
"collection_posts",
|
|
182
|
-
"posts.id",
|
|
183
|
-
"collection_posts.postId"
|
|
184
|
-
);
|
|
185
|
-
query.where("collection_posts.collectionId", options.collectionId);
|
|
186
|
-
} else if (options.orderBy === "rank") {
|
|
187
|
-
query.innerJoin(
|
|
188
|
-
"collection_posts",
|
|
189
|
-
"posts.id",
|
|
190
|
-
"collection_posts.postId"
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
if (options.orderBy === "rank") {
|
|
194
|
-
query.groupBy("rank");
|
|
195
|
-
}
|
|
196
|
-
if (options.noAnswers) {
|
|
197
|
-
query.whereNull("answers.postId");
|
|
198
|
-
}
|
|
199
|
-
if (options.hasAnswers) {
|
|
200
|
-
query.whereNotNull("answers.postId");
|
|
201
|
-
}
|
|
202
|
-
if (options.noCorrectAnswer) {
|
|
203
|
-
query.leftJoin("answers as correct_answer", (builder) => {
|
|
204
|
-
builder.on("posts.id", "correct_answer.postId").on("correct_answer.correct", this.db.raw("?", [true]));
|
|
205
|
-
});
|
|
206
|
-
query.whereNull("correct_answer.postId");
|
|
207
|
-
}
|
|
208
|
-
if (options.noVotes) {
|
|
209
|
-
query.whereNull("post_votes.postId");
|
|
210
|
-
}
|
|
211
|
-
if (options.favorite) {
|
|
212
|
-
query.where("user_favorite.user", "=", user_ref);
|
|
213
|
-
query.whereNotNull("user_favorite.postId");
|
|
214
|
-
}
|
|
215
|
-
if (options.includeTrend || options.orderBy === "trend") {
|
|
216
|
-
query.select(
|
|
217
|
-
this.db.raw(
|
|
218
|
-
`(
|
|
219
|
-
(SELECT COALESCE(SUM(score), 0) FROM post_votes WHERE "postId" = posts.id) * 200 +
|
|
220
|
-
(SELECT COALESCE(COUNT(*), 0) FROM answers WHERE "postId" = posts.id) * 100 +
|
|
221
|
-
(SELECT COALESCE(COUNT(*), 0) FROM user_favorite WHERE "postId" = posts.id) * 50 +
|
|
222
|
-
(SELECT COALESCE(COUNT(*), 0) FROM post_views WHERE "postId" = posts.id) * 10 +
|
|
223
|
-
(SELECT COALESCE(COUNT(*), 0) FROM comments WHERE "postId" = posts.id) * 30
|
|
224
|
-
) /
|
|
225
|
-
POWER(
|
|
226
|
-
EXTRACT(EPOCH FROM (now() - posts.created)) / 172800 + 1,
|
|
227
|
-
1.5
|
|
228
|
-
) as trend`
|
|
229
|
-
)
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
if (options.ids) {
|
|
233
|
-
query.whereIn("posts.id", options.ids);
|
|
234
|
-
}
|
|
235
|
-
const totalQuery = query.clone();
|
|
236
|
-
if (options.random) {
|
|
237
|
-
query.orderByRaw("RANDOM()");
|
|
238
|
-
} else if (options.orderBy) {
|
|
239
|
-
query.orderBy(options.orderBy, options.order ? options.order : "desc");
|
|
240
|
-
} else {
|
|
241
|
-
query.orderBy("created", "desc");
|
|
242
|
-
}
|
|
243
|
-
if (options.limit) {
|
|
244
|
-
query.limit(options.limit);
|
|
245
|
-
}
|
|
246
|
-
if (options.offset) {
|
|
247
|
-
query.offset(options.offset);
|
|
248
|
-
}
|
|
249
|
-
const results = await Promise.all([
|
|
250
|
-
query,
|
|
251
|
-
includeTotal ? this.db(totalQuery.as("totalQuery")).count("* as CNT").first() : void 0
|
|
252
|
-
]);
|
|
253
|
-
const rows = results[0];
|
|
254
|
-
const total = this.mapToInteger(results[1]?.CNT);
|
|
255
|
-
return {
|
|
256
|
-
posts: await Promise.all(
|
|
257
|
-
rows.map(async (val) => {
|
|
258
|
-
return this.mapPostEntity(val, user_ref, {
|
|
259
|
-
...opts,
|
|
260
|
-
includeAnswers: options.includeAnswers ?? opts?.includeAnswers,
|
|
261
|
-
includeVotes: options.includeVotes ?? opts?.includeVotes,
|
|
262
|
-
includeEntities: options.includeEntities ?? opts?.includeEntities,
|
|
263
|
-
includeAttachments: options.includeAttachments ?? opts?.includeAttachments,
|
|
264
|
-
includeExperts: options.includeExperts ?? opts?.includeExperts
|
|
265
|
-
});
|
|
266
|
-
})
|
|
267
|
-
),
|
|
268
|
-
total
|
|
269
|
-
};
|
|
84
|
+
return this.postsStore.getPosts(user_ref, options, filters, opts);
|
|
270
85
|
}
|
|
271
86
|
async getPost(user_ref, id, recordView, options) {
|
|
272
|
-
|
|
273
|
-
"posts.id",
|
|
274
|
-
"=",
|
|
275
|
-
id
|
|
276
|
-
);
|
|
277
|
-
if (!rows || rows.length === 0) {
|
|
278
|
-
return null;
|
|
279
|
-
}
|
|
280
|
-
const post = rows[0];
|
|
281
|
-
if ((recordView === void 0 || recordView) && post.status === "active") {
|
|
282
|
-
this.recordPostView(id, user_ref);
|
|
283
|
-
}
|
|
284
|
-
return await this.mapPostEntity(post, user_ref, options);
|
|
87
|
+
return this.postsStore.getPost(user_ref, id, recordView, options);
|
|
285
88
|
}
|
|
286
89
|
async getPostByAnswerId(user_ref, answerId, recordView, options) {
|
|
287
|
-
|
|
288
|
-
if (!rows || rows.length === 0) {
|
|
289
|
-
return null;
|
|
290
|
-
}
|
|
291
|
-
if (recordView === void 0 || recordView) {
|
|
292
|
-
this.recordPostView(rows[0].id, user_ref);
|
|
293
|
-
}
|
|
294
|
-
return await this.mapPostEntity(
|
|
295
|
-
rows[0],
|
|
90
|
+
return this.postsStore.getPostByAnswerId(
|
|
296
91
|
user_ref,
|
|
92
|
+
answerId,
|
|
93
|
+
recordView,
|
|
297
94
|
options
|
|
298
95
|
);
|
|
299
96
|
}
|
|
300
97
|
async createPost(options) {
|
|
301
|
-
|
|
98
|
+
return this.postsStore.createPost(options);
|
|
99
|
+
}
|
|
100
|
+
async updatePost(options) {
|
|
101
|
+
return this.postsStore.updatePost(options);
|
|
102
|
+
}
|
|
103
|
+
async deletePost(id, permanently) {
|
|
104
|
+
return this.postsStore.deletePost(id, permanently);
|
|
105
|
+
}
|
|
106
|
+
async votePost(user_ref, postId, score) {
|
|
107
|
+
return this.postsStore.votePost(user_ref, postId, score);
|
|
108
|
+
}
|
|
109
|
+
async deletePostVote(user_ref, postId) {
|
|
110
|
+
return this.postsStore.deletePostVote(user_ref, postId);
|
|
111
|
+
}
|
|
112
|
+
async favoritePost(user_ref, postId) {
|
|
113
|
+
return this.postsStore.favoritePost(user_ref, postId);
|
|
114
|
+
}
|
|
115
|
+
async unfavoritePost(user_ref, postId) {
|
|
116
|
+
return this.postsStore.unfavoritePost(user_ref, postId);
|
|
117
|
+
}
|
|
118
|
+
async getUsersWhoFavoritedPost(postId) {
|
|
119
|
+
return this.postsStore.getUsersWhoFavoritedPost(postId);
|
|
120
|
+
}
|
|
121
|
+
async getAnswers(user_ref, options, filters, opts) {
|
|
122
|
+
return this.answersStore.getAnswers(user_ref, options, filters, opts);
|
|
123
|
+
}
|
|
124
|
+
async getAnswer(answerId, user_ref, options) {
|
|
125
|
+
return this.answersStore.getAnswer(answerId, user_ref, options);
|
|
126
|
+
}
|
|
127
|
+
async answerPost(user_ref, questionId, answer, created, images, anonymous, options) {
|
|
128
|
+
return this.answersStore.answerPost(
|
|
302
129
|
user_ref,
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
author,
|
|
130
|
+
questionId,
|
|
131
|
+
answer,
|
|
306
132
|
created,
|
|
307
|
-
tags,
|
|
308
|
-
entities,
|
|
309
133
|
images,
|
|
310
134
|
anonymous,
|
|
311
|
-
|
|
312
|
-
headerImage,
|
|
313
|
-
url,
|
|
314
|
-
opts,
|
|
315
|
-
status = "active"
|
|
316
|
-
} = options;
|
|
317
|
-
const posts = await this.db.insert(
|
|
318
|
-
{
|
|
319
|
-
author: author ?? user_ref,
|
|
320
|
-
title,
|
|
321
|
-
content,
|
|
322
|
-
created,
|
|
323
|
-
anonymous: anonymous ?? false,
|
|
324
|
-
type: type ?? "question",
|
|
325
|
-
headerImage,
|
|
326
|
-
url,
|
|
327
|
-
status,
|
|
328
|
-
published: status === "active" ? created : null
|
|
329
|
-
},
|
|
330
|
-
["id"]
|
|
331
|
-
).into("posts").returning([
|
|
332
|
-
"id",
|
|
333
|
-
"author",
|
|
334
|
-
"title",
|
|
335
|
-
"content",
|
|
336
|
-
"created",
|
|
337
|
-
"anonymous",
|
|
338
|
-
"type",
|
|
339
|
-
"status",
|
|
340
|
-
"url"
|
|
341
|
-
]);
|
|
342
|
-
await Promise.all([
|
|
343
|
-
this.addTags(posts[0].id, tags),
|
|
344
|
-
this.addEntities(posts[0].id, entities)
|
|
345
|
-
]);
|
|
346
|
-
await this.updateAttachments(
|
|
347
|
-
"postId",
|
|
348
|
-
content ?? "",
|
|
349
|
-
images ?? [],
|
|
350
|
-
posts[0].id,
|
|
351
|
-
headerImage
|
|
135
|
+
options
|
|
352
136
|
);
|
|
353
|
-
return this.mapPostEntity(posts[0], user_ref, opts);
|
|
354
|
-
}
|
|
355
|
-
async commentPost(post_id, user_ref, content, created, options) {
|
|
356
|
-
await this.db.insert({
|
|
357
|
-
author: user_ref,
|
|
358
|
-
content,
|
|
359
|
-
created,
|
|
360
|
-
postId: post_id
|
|
361
|
-
}).into("comments");
|
|
362
|
-
return await this.getPost(user_ref, post_id, false, options);
|
|
363
|
-
}
|
|
364
|
-
async updatePostComment(post_id, id, user_ref, content, options) {
|
|
365
|
-
const query = this.db("comments").where("id", "=", id).where("postId", "=", post_id);
|
|
366
|
-
await query.update({ content, updatedBy: user_ref, updated: /* @__PURE__ */ new Date() });
|
|
367
|
-
return this.getPost(user_ref, post_id, false, options);
|
|
368
|
-
}
|
|
369
|
-
async deletePostComment(post_id, id, user_ref, permanently, options) {
|
|
370
|
-
const query = this.db("comments").where("id", "=", id).where("postId", "=", post_id);
|
|
371
|
-
if (permanently) {
|
|
372
|
-
await query.delete();
|
|
373
|
-
} else {
|
|
374
|
-
await query.update({ status: "deleted" });
|
|
375
|
-
}
|
|
376
|
-
return this.getPost(user_ref, post_id, false, options);
|
|
377
137
|
}
|
|
378
|
-
async
|
|
379
|
-
|
|
380
|
-
author: user_ref,
|
|
381
|
-
content,
|
|
382
|
-
created,
|
|
383
|
-
answerId: answer_id
|
|
384
|
-
}).into("comments");
|
|
385
|
-
return this.getAnswer(answer_id, user_ref, options);
|
|
386
|
-
}
|
|
387
|
-
async updateAnswerComment(answer_id, id, user_ref, content, options) {
|
|
388
|
-
const query = this.db("comments").where("id", "=", id).where("answerId", "=", answer_id);
|
|
389
|
-
await query.update({ content, updatedBy: user_ref, updated: /* @__PURE__ */ new Date() });
|
|
390
|
-
return this.getAnswer(answer_id, user_ref, options);
|
|
391
|
-
}
|
|
392
|
-
async deleteAnswerComment(answer_id, id, user_ref, permanently, options) {
|
|
393
|
-
const query = this.db("comments").where("id", "=", id).where("answerId", "=", answer_id);
|
|
394
|
-
if (permanently) {
|
|
395
|
-
await query.delete();
|
|
396
|
-
} else {
|
|
397
|
-
await query.update({ status: "deleted" });
|
|
398
|
-
}
|
|
399
|
-
return this.getAnswer(answer_id, user_ref, options);
|
|
400
|
-
}
|
|
401
|
-
async updatePost(options) {
|
|
402
|
-
const {
|
|
403
|
-
id,
|
|
138
|
+
async updateAnswer(user_ref, questionId, answerId, answer, author, images, options) {
|
|
139
|
+
return this.answersStore.updateAnswer(
|
|
404
140
|
user_ref,
|
|
405
|
-
|
|
406
|
-
|
|
141
|
+
questionId,
|
|
142
|
+
answerId,
|
|
143
|
+
answer,
|
|
407
144
|
author,
|
|
408
|
-
tags,
|
|
409
|
-
entities,
|
|
410
145
|
images,
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
146
|
+
options
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
async deleteAnswer(id) {
|
|
150
|
+
return this.answersStore.deleteAnswer(id);
|
|
151
|
+
}
|
|
152
|
+
async voteAnswer(user_ref, answerId, score) {
|
|
153
|
+
return this.answersStore.voteAnswer(user_ref, answerId, score);
|
|
154
|
+
}
|
|
155
|
+
async deleteAnswerVote(user_ref, answerId) {
|
|
156
|
+
return this.answersStore.deleteAnswerVote(user_ref, answerId);
|
|
157
|
+
}
|
|
158
|
+
async markAnswerCorrect(postId, answerId) {
|
|
159
|
+
return this.answersStore.markAnswerCorrect(postId, answerId);
|
|
160
|
+
}
|
|
161
|
+
async markAnswerIncorrect(postId, answerId) {
|
|
162
|
+
return this.answersStore.markAnswerIncorrect(postId, answerId);
|
|
163
|
+
}
|
|
164
|
+
async clickPost(user_ref, postId) {
|
|
165
|
+
const vote = await this.postsStore.getPostVote(user_ref, postId);
|
|
166
|
+
const score = (vote?.score || 0) + 1;
|
|
167
|
+
await this.postsStore.votePost(user_ref, postId, score);
|
|
168
|
+
}
|
|
169
|
+
async commentPost(post_id, user_ref, content, created) {
|
|
170
|
+
await this.commentsStore.commentPost(post_id, user_ref, content, created);
|
|
171
|
+
return this.getPost(user_ref, post_id);
|
|
172
|
+
}
|
|
173
|
+
async commentAnswer(answer_id, user_ref, content, created) {
|
|
174
|
+
await this.commentsStore.commentAnswer(
|
|
175
|
+
answer_id,
|
|
176
|
+
user_ref,
|
|
422
177
|
content,
|
|
423
|
-
|
|
424
|
-
author,
|
|
425
|
-
url,
|
|
426
|
-
updatedBy: setUpdatedBy ? user_ref : void 0,
|
|
427
|
-
updated: setUpdatedBy ? /* @__PURE__ */ new Date() : void 0,
|
|
428
|
-
status,
|
|
429
|
-
published: shouldSetPublished ? /* @__PURE__ */ new Date() : void 0
|
|
430
|
-
});
|
|
431
|
-
if (!rows) {
|
|
432
|
-
return null;
|
|
433
|
-
}
|
|
434
|
-
await Promise.all([
|
|
435
|
-
this.addTags(id, tags, true),
|
|
436
|
-
this.addEntities(id, entities, true)
|
|
437
|
-
]);
|
|
438
|
-
await this.updateAttachments(
|
|
439
|
-
"postId",
|
|
440
|
-
content ?? "",
|
|
441
|
-
images ?? [],
|
|
442
|
-
id,
|
|
443
|
-
headerImage
|
|
178
|
+
created
|
|
444
179
|
);
|
|
445
|
-
return
|
|
180
|
+
return this.getAnswer(answer_id, user_ref);
|
|
446
181
|
}
|
|
447
|
-
async
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
return rows2 > 0;
|
|
451
|
-
}
|
|
452
|
-
const rows = await this.db("posts").where("id", "=", id).update({
|
|
453
|
-
status: "deleted"
|
|
454
|
-
});
|
|
455
|
-
return rows > 0;
|
|
182
|
+
async updatePostComment(post_id, id, user_ref, content) {
|
|
183
|
+
await this.commentsStore.updatePostComment(post_id, id, user_ref, content);
|
|
184
|
+
return this.getPost(user_ref, post_id);
|
|
456
185
|
}
|
|
457
|
-
async
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
created,
|
|
464
|
-
anonymous: anonymous ?? false
|
|
465
|
-
}).into("answers").returning("id");
|
|
466
|
-
await this.updateAttachments(
|
|
467
|
-
"answerId",
|
|
468
|
-
answer,
|
|
469
|
-
images ?? [],
|
|
470
|
-
answers[0].id
|
|
186
|
+
async updateAnswerComment(answer_id, id, user_ref, content) {
|
|
187
|
+
await this.commentsStore.updateAnswerComment(
|
|
188
|
+
answer_id,
|
|
189
|
+
id,
|
|
190
|
+
user_ref,
|
|
191
|
+
content
|
|
471
192
|
);
|
|
472
|
-
return this.getAnswer(
|
|
193
|
+
return this.getAnswer(answer_id, user_ref);
|
|
473
194
|
}
|
|
474
|
-
async
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
content: answer,
|
|
478
|
-
author,
|
|
479
|
-
updatedBy: user_ref,
|
|
480
|
-
updated: /* @__PURE__ */ new Date()
|
|
481
|
-
});
|
|
482
|
-
if (!rows) {
|
|
483
|
-
return null;
|
|
484
|
-
}
|
|
485
|
-
await this.updateAttachments("answerId", answer, images ?? [], answerId);
|
|
486
|
-
return this.getAnswer(answerId, user_ref, options);
|
|
195
|
+
async deletePostComment(post_id, id, user_ref) {
|
|
196
|
+
await this.commentsStore.deletePostComment(post_id, id);
|
|
197
|
+
return this.getPost(user_ref, post_id);
|
|
487
198
|
}
|
|
488
|
-
async
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
if (includeStatusFilter) {
|
|
492
|
-
query.where("answers.status", "=", "active");
|
|
493
|
-
}
|
|
494
|
-
if (options.fromDate && options.toDate) {
|
|
495
|
-
query.whereBetween("answers.created", [
|
|
496
|
-
`${options.fromDate} 00:00:00.000+00`,
|
|
497
|
-
`${options.toDate} 23:59:59.999+00`
|
|
498
|
-
]);
|
|
499
|
-
}
|
|
500
|
-
if (options.author) {
|
|
501
|
-
query.where("answers.author", "=", options.author);
|
|
502
|
-
}
|
|
503
|
-
if (filters) {
|
|
504
|
-
parseFilter(filters, query, this.db, "answer");
|
|
505
|
-
}
|
|
506
|
-
if (options.tags) {
|
|
507
|
-
const tags = backstagePluginQetaCommon.filterTags(options.tags);
|
|
508
|
-
if (options.tagsRelation === "or") {
|
|
509
|
-
query.innerJoin("post_tags", "answers.postId", "post_tags.postId");
|
|
510
|
-
query.innerJoin("tags", "post_tags.tagId", "tags.id");
|
|
511
|
-
query.whereIn("tags.tag", tags);
|
|
512
|
-
} else {
|
|
513
|
-
tags.forEach((t, i) => {
|
|
514
|
-
query.innerJoin(
|
|
515
|
-
`post_tags AS at${i}`,
|
|
516
|
-
"answers.postId",
|
|
517
|
-
`at${i}.postId`
|
|
518
|
-
);
|
|
519
|
-
query.innerJoin(`tags AS t${i}`, `at${i}.tagId`, `t${i}.id`);
|
|
520
|
-
query.where(`t${i}.tag`, "=", t);
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
if (options.entities) {
|
|
525
|
-
if (options.entitiesRelation === "or") {
|
|
526
|
-
query.innerJoin(
|
|
527
|
-
"post_entities",
|
|
528
|
-
"answers.postId",
|
|
529
|
-
"post_entities.postId"
|
|
530
|
-
);
|
|
531
|
-
query.innerJoin("entities", "post_entities.entityId", "entities.id");
|
|
532
|
-
query.whereIn("entities.entity_ref", options.entities);
|
|
533
|
-
} else {
|
|
534
|
-
options.entities.forEach((t, i) => {
|
|
535
|
-
query.innerJoin(
|
|
536
|
-
`post_entities AS pe${i}`,
|
|
537
|
-
"answers.postId",
|
|
538
|
-
`pe${i}.postId`
|
|
539
|
-
);
|
|
540
|
-
query.innerJoin(`entities AS e${i}`, `pe${i}.entityId`, `e${i}.id`);
|
|
541
|
-
query.where(`e${i}.entity_ref`, "=", t);
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
if (options.noCorrectAnswer) {
|
|
546
|
-
query.where("correct", "=", false);
|
|
547
|
-
}
|
|
548
|
-
if (options.noVotes) {
|
|
549
|
-
query.whereNull("answer_votes.answerId");
|
|
550
|
-
}
|
|
551
|
-
if (options.searchQuery) {
|
|
552
|
-
this.applySearchQuery(query, ["answers.content"], options.searchQuery);
|
|
553
|
-
}
|
|
554
|
-
const totalQuery = query.clone();
|
|
555
|
-
if (options.orderBy) {
|
|
556
|
-
query.orderBy(options.orderBy, options.order ? options.order : "desc");
|
|
557
|
-
} else {
|
|
558
|
-
query.orderBy("created", "desc");
|
|
559
|
-
}
|
|
560
|
-
if (options.limit) {
|
|
561
|
-
query.limit(options.limit);
|
|
562
|
-
}
|
|
563
|
-
if (options.offset) {
|
|
564
|
-
query.offset(options.offset);
|
|
565
|
-
}
|
|
566
|
-
if (options.ids) {
|
|
567
|
-
query.whereIn("answers.id", options.ids);
|
|
568
|
-
}
|
|
569
|
-
const results = await Promise.all([
|
|
570
|
-
query,
|
|
571
|
-
this.db(totalQuery.as("totalQuery")).count("* as CNT").first()
|
|
572
|
-
]);
|
|
573
|
-
const rows = results[0];
|
|
574
|
-
const total = this.mapToInteger(results[1]?.CNT);
|
|
575
|
-
return {
|
|
576
|
-
answers: await Promise.all(
|
|
577
|
-
rows.map(async (val) => {
|
|
578
|
-
return this.mapAnswer(val, user_ref, opts);
|
|
579
|
-
})
|
|
580
|
-
),
|
|
581
|
-
total
|
|
582
|
-
};
|
|
199
|
+
async deleteAnswerComment(answer_id, id, user_ref) {
|
|
200
|
+
await this.commentsStore.deleteAnswerComment(answer_id, id);
|
|
201
|
+
return this.getAnswer(answer_id, user_ref);
|
|
583
202
|
}
|
|
584
|
-
async
|
|
585
|
-
|
|
586
|
-
const query = this.getAnswerBaseQuery().where("id", "=", answerId);
|
|
587
|
-
if (includeStatusFilter) {
|
|
588
|
-
query.where("answers.status", "=", "active");
|
|
589
|
-
}
|
|
590
|
-
const answers = await query.select();
|
|
591
|
-
return this.mapAnswer(answers[0], user_ref, options);
|
|
203
|
+
async getCollections(user_ref, options, opts) {
|
|
204
|
+
return this.collectionsStore.getCollections(user_ref, options, opts);
|
|
592
205
|
}
|
|
593
|
-
async
|
|
594
|
-
|
|
595
|
-
const query = this.db("comments");
|
|
596
|
-
if (options?.ids) {
|
|
597
|
-
query.whereIn("id", options.ids);
|
|
598
|
-
}
|
|
599
|
-
if (includeStatusFilter) {
|
|
600
|
-
query.where("status", "=", "active");
|
|
601
|
-
}
|
|
602
|
-
const comments = await query.select();
|
|
603
|
-
return await Promise.all(comments.map(this.mapComment));
|
|
206
|
+
async getCollection(user_ref, id, options) {
|
|
207
|
+
return this.collectionsStore.getCollection(user_ref, id, options);
|
|
604
208
|
}
|
|
605
|
-
async
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
query.where("status", "=", "active");
|
|
610
|
-
}
|
|
611
|
-
if (opts?.postId) {
|
|
612
|
-
query.andWhere("comments.postId", "=", opts.postId);
|
|
613
|
-
}
|
|
614
|
-
if (opts?.answerId) {
|
|
615
|
-
query.andWhere("comments.answerId", "=", opts.answerId);
|
|
616
|
-
}
|
|
617
|
-
const comments = await query.select();
|
|
618
|
-
if (comments.length === 0) {
|
|
619
|
-
return null;
|
|
620
|
-
}
|
|
621
|
-
return await this.mapComment(comments[0]);
|
|
209
|
+
async createCollection(options) {
|
|
210
|
+
return this.collectionsStore.createCollection(
|
|
211
|
+
options
|
|
212
|
+
);
|
|
622
213
|
}
|
|
623
|
-
async
|
|
624
|
-
|
|
625
|
-
if (permanently) {
|
|
626
|
-
return !!await query.delete();
|
|
627
|
-
}
|
|
628
|
-
const rows = await query.update({ status: "deleted" });
|
|
629
|
-
return rows > 0;
|
|
214
|
+
async updateCollection(options) {
|
|
215
|
+
return this.collectionsStore.updateCollection(options);
|
|
630
216
|
}
|
|
631
|
-
async
|
|
632
|
-
|
|
633
|
-
if (existingRows.length) {
|
|
634
|
-
await this.db("post_votes").where("author", "=", user_ref).where("postId", "=", postId).increment("score", 1);
|
|
635
|
-
} else {
|
|
636
|
-
await this.db.insert({
|
|
637
|
-
author: user_ref,
|
|
638
|
-
postId,
|
|
639
|
-
score: 1,
|
|
640
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
641
|
-
}).onConflict().ignore().into("post_votes");
|
|
642
|
-
}
|
|
217
|
+
async deleteCollection(id) {
|
|
218
|
+
return this.collectionsStore.deleteCollection(id);
|
|
643
219
|
}
|
|
644
|
-
async
|
|
645
|
-
return
|
|
220
|
+
async addPostToCollection(user_ref, id, postId, options) {
|
|
221
|
+
return this.collectionsStore.addPostToCollection(
|
|
222
|
+
user_ref,
|
|
223
|
+
id,
|
|
224
|
+
postId,
|
|
225
|
+
options
|
|
226
|
+
);
|
|
646
227
|
}
|
|
647
|
-
async
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
655
|
-
},
|
|
656
|
-
["postId"]
|
|
657
|
-
).onConflict().ignore().into("post_votes");
|
|
658
|
-
return id && id.length > 0;
|
|
228
|
+
async removePostFromCollection(user_ref, id, postId, options) {
|
|
229
|
+
return this.collectionsStore.removePostFromCollection(
|
|
230
|
+
user_ref,
|
|
231
|
+
id,
|
|
232
|
+
postId,
|
|
233
|
+
options
|
|
234
|
+
);
|
|
659
235
|
}
|
|
660
|
-
async
|
|
661
|
-
|
|
662
|
-
{
|
|
663
|
-
user: user_ref,
|
|
664
|
-
postId
|
|
665
|
-
},
|
|
666
|
-
["postId"]
|
|
667
|
-
).onConflict().ignore().into("user_favorite");
|
|
668
|
-
return id && id.length > 0;
|
|
236
|
+
async getUsersForCollection(collectionId) {
|
|
237
|
+
return this.collectionsStore.getUsersForCollection(collectionId);
|
|
669
238
|
}
|
|
670
|
-
async
|
|
671
|
-
return
|
|
239
|
+
async followCollection(user_ref, collectionId) {
|
|
240
|
+
return this.collectionsStore.followCollection(user_ref, collectionId);
|
|
672
241
|
}
|
|
673
|
-
async
|
|
674
|
-
|
|
675
|
-
const users = await query.select("user");
|
|
676
|
-
return users.map((u) => u.user);
|
|
242
|
+
async unfollowCollection(user_ref, collectionId) {
|
|
243
|
+
return this.collectionsStore.unfollowCollection(user_ref, collectionId);
|
|
677
244
|
}
|
|
678
|
-
async
|
|
679
|
-
return
|
|
245
|
+
async getUserCollections(user_ref, options) {
|
|
246
|
+
return this.collectionsStore.getUserCollections(user_ref, options);
|
|
680
247
|
}
|
|
681
|
-
async
|
|
682
|
-
|
|
683
|
-
const id = await this.db.insert(
|
|
684
|
-
{
|
|
685
|
-
author: user_ref,
|
|
686
|
-
answerId,
|
|
687
|
-
score,
|
|
688
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
689
|
-
},
|
|
690
|
-
["answerId"]
|
|
691
|
-
).onConflict().ignore().into("answer_votes");
|
|
692
|
-
return id && id.length > 0;
|
|
248
|
+
async getPostRank(collectionId, postId) {
|
|
249
|
+
return this.collectionsStore.getPostRank(collectionId, postId);
|
|
693
250
|
}
|
|
694
|
-
async
|
|
695
|
-
return
|
|
251
|
+
async getTopRankedPostId(collectionId) {
|
|
252
|
+
return this.collectionsStore.getTopRankedPostId(collectionId);
|
|
696
253
|
}
|
|
697
|
-
async
|
|
698
|
-
return
|
|
254
|
+
async getBottomRankedPostId(collectionId) {
|
|
255
|
+
return this.collectionsStore.getBottomRankedPostId(collectionId);
|
|
699
256
|
}
|
|
700
|
-
async
|
|
701
|
-
|
|
702
|
-
const query = this.getTagBaseQuery();
|
|
703
|
-
if (options?.noDescription) {
|
|
704
|
-
query.whereNull("tags.description");
|
|
705
|
-
}
|
|
706
|
-
if (options?.searchQuery) {
|
|
707
|
-
this.applySearchQuery(
|
|
708
|
-
query,
|
|
709
|
-
["tags.tag", "tags.description"],
|
|
710
|
-
options.searchQuery
|
|
711
|
-
);
|
|
712
|
-
}
|
|
713
|
-
if (options?.ids) {
|
|
714
|
-
query.whereIn("tags.id", options.ids);
|
|
715
|
-
}
|
|
716
|
-
if (filters) {
|
|
717
|
-
parseFilter(filters, query, this.db);
|
|
718
|
-
}
|
|
719
|
-
const totalQuery = query.clone();
|
|
720
|
-
if (options?.orderBy) {
|
|
721
|
-
query.orderBy(options?.orderBy, options?.order || "desc");
|
|
722
|
-
}
|
|
723
|
-
if (options?.limit) {
|
|
724
|
-
query.limit(options.limit);
|
|
725
|
-
}
|
|
726
|
-
if (options?.offset) {
|
|
727
|
-
query.offset(options.offset);
|
|
728
|
-
}
|
|
729
|
-
const results = await Promise.all([
|
|
730
|
-
query,
|
|
731
|
-
this.db(totalQuery.as("totalQuery")).count("* as CNT").first()
|
|
732
|
-
]);
|
|
733
|
-
const rows = results[0];
|
|
734
|
-
const total = this.mapToInteger(results[1]?.CNT);
|
|
735
|
-
return {
|
|
736
|
-
total,
|
|
737
|
-
tags: await Promise.all(
|
|
738
|
-
rows.map(async (tag) => {
|
|
739
|
-
return {
|
|
740
|
-
id: tag.id,
|
|
741
|
-
tag: tag.tag,
|
|
742
|
-
description: tag.description,
|
|
743
|
-
postsCount: this.mapToInteger(tag.postsCount),
|
|
744
|
-
followerCount: this.mapToInteger(tag.followerCount),
|
|
745
|
-
experts: includeExperts ? await this.getTagExpertsById(tag.id) : void 0
|
|
746
|
-
};
|
|
747
|
-
})
|
|
748
|
-
)
|
|
749
|
-
};
|
|
257
|
+
async getNextRankedPostId(collectionId, postId) {
|
|
258
|
+
return this.collectionsStore.getNextRankedPostId(collectionId, postId);
|
|
750
259
|
}
|
|
751
|
-
async
|
|
752
|
-
|
|
753
|
-
const tags = await query.where("tags.id", "=", id);
|
|
754
|
-
if (tags.length === 0) {
|
|
755
|
-
return null;
|
|
756
|
-
}
|
|
757
|
-
return {
|
|
758
|
-
id: tags[0].id,
|
|
759
|
-
tag: tags[0].tag,
|
|
760
|
-
description: tags[0].description,
|
|
761
|
-
postsCount: this.mapToInteger(tags[0].postsCount),
|
|
762
|
-
followerCount: this.mapToInteger(tags[0].followerCount),
|
|
763
|
-
experts: await this.getTagExpertsById(tags[0].id)
|
|
764
|
-
};
|
|
260
|
+
async getPreviousRankedPostId(collectionId, postId) {
|
|
261
|
+
return this.collectionsStore.getPreviousRankedPostId(collectionId, postId);
|
|
765
262
|
}
|
|
766
|
-
async
|
|
767
|
-
|
|
768
|
-
const tags = await query.where("tags.tag", "=", tag);
|
|
769
|
-
if (tags.length === 0) {
|
|
770
|
-
return null;
|
|
771
|
-
}
|
|
772
|
-
return {
|
|
773
|
-
id: tags[0].id,
|
|
774
|
-
tag: tags[0].tag,
|
|
775
|
-
description: tags[0].description,
|
|
776
|
-
postsCount: this.mapToInteger(tags[0].postsCount),
|
|
777
|
-
followerCount: this.mapToInteger(tags[0].followerCount),
|
|
778
|
-
experts: await this.getTagExpertsById(tags[0].id)
|
|
779
|
-
};
|
|
263
|
+
async updatePostRank(collectionId, postId, rank) {
|
|
264
|
+
return this.collectionsStore.updatePostRank(collectionId, postId, rank);
|
|
780
265
|
}
|
|
781
|
-
async
|
|
782
|
-
|
|
783
|
-
return !!await query.delete();
|
|
266
|
+
async getTags(options, filters) {
|
|
267
|
+
return this.tagsStore.getTags(options, filters);
|
|
784
268
|
}
|
|
785
269
|
async getTagExperts(tags) {
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
270
|
+
return this.tagsStore.getTagExperts(tags);
|
|
271
|
+
}
|
|
272
|
+
async getTag(tag) {
|
|
273
|
+
return this.tagsStore.getTag(tag);
|
|
274
|
+
}
|
|
275
|
+
async getTagById(id) {
|
|
276
|
+
return this.tagsStore.getTagById(id);
|
|
792
277
|
}
|
|
793
278
|
async createTag(tag, description, experts) {
|
|
794
|
-
|
|
795
|
-
const ret = await this.db.insert({ tag: trimmed, description }).into("tags").returning(["id"]).onConflict("tag").ignore();
|
|
796
|
-
if (ret && experts && experts.length > 0) {
|
|
797
|
-
await this.updateTagExperts(ret[0].id, experts);
|
|
798
|
-
}
|
|
799
|
-
return this.getTag(trimmed);
|
|
279
|
+
return this.tagsStore.createTag(tag, description, experts);
|
|
800
280
|
}
|
|
801
281
|
async updateTag(id, description, experts) {
|
|
802
|
-
|
|
803
|
-
if (experts && experts.length > 0) {
|
|
804
|
-
await this.updateTagExperts(id, experts);
|
|
805
|
-
}
|
|
806
|
-
return this.getTagById(id);
|
|
282
|
+
return this.tagsStore.updateTag(id, description, experts);
|
|
807
283
|
}
|
|
808
|
-
async
|
|
809
|
-
|
|
810
|
-
|
|
284
|
+
async deleteTag(id) {
|
|
285
|
+
return this.tagsStore.deleteTag(id);
|
|
286
|
+
}
|
|
287
|
+
async getEntities(options) {
|
|
288
|
+
return this.entitiesStore.getEntities(options);
|
|
289
|
+
}
|
|
290
|
+
async getEntity(entity_ref) {
|
|
291
|
+
return this.entitiesStore.getEntity(entity_ref);
|
|
811
292
|
}
|
|
812
293
|
async getUsers(options) {
|
|
813
|
-
|
|
814
|
-
if (options?.entityRefs) {
|
|
815
|
-
query.whereIn("unique_authors.author", options.entityRefs);
|
|
816
|
-
}
|
|
817
|
-
const totalQuery = query.clone();
|
|
818
|
-
if (options?.orderBy) {
|
|
819
|
-
query.orderBy(options?.orderBy, options?.order || "desc");
|
|
820
|
-
}
|
|
821
|
-
if (options?.limit) {
|
|
822
|
-
query.limit(options.limit);
|
|
823
|
-
}
|
|
824
|
-
if (options?.offset) {
|
|
825
|
-
query.offset(options.offset);
|
|
826
|
-
}
|
|
827
|
-
const results = await Promise.all([
|
|
828
|
-
query,
|
|
829
|
-
this.db(totalQuery.as("totalQuery")).count("* as CNT").first()
|
|
830
|
-
]);
|
|
831
|
-
const rows = results[0];
|
|
832
|
-
const total = this.mapToInteger(results[1]?.CNT);
|
|
833
|
-
return {
|
|
834
|
-
total,
|
|
835
|
-
users: rows.map((r) => ({
|
|
836
|
-
userRef: r.author,
|
|
837
|
-
totalViews: this.mapToInteger(r.totalViews),
|
|
838
|
-
totalQuestions: this.mapToInteger(r.totalQuestions),
|
|
839
|
-
totalAnswers: this.mapToInteger(r.totalAnswers),
|
|
840
|
-
totalComments: this.mapToInteger(r.postComments) + this.mapToInteger(r.answerComments),
|
|
841
|
-
totalVotes: this.mapToInteger(r.postVotes) + this.mapToInteger(r.answerVotes),
|
|
842
|
-
totalArticles: this.mapToInteger(r.totalArticles),
|
|
843
|
-
totalFollowers: this.mapToInteger(r.totalFollowers),
|
|
844
|
-
totalLinks: this.mapToInteger(r.totalLinks)
|
|
845
|
-
}))
|
|
846
|
-
};
|
|
294
|
+
return this.usersStore.getUsers(options);
|
|
847
295
|
}
|
|
848
296
|
async getUser(user_ref) {
|
|
849
|
-
|
|
850
|
-
const rows = await q.where("author", user_ref);
|
|
851
|
-
if (rows.length === 0) {
|
|
852
|
-
return null;
|
|
853
|
-
}
|
|
854
|
-
return {
|
|
855
|
-
userRef: rows[0].author,
|
|
856
|
-
totalViews: this.mapToInteger(rows[0].totalViews),
|
|
857
|
-
totalQuestions: this.mapToInteger(rows[0].totalQuestions),
|
|
858
|
-
totalAnswers: this.mapToInteger(rows[0].totalAnswers),
|
|
859
|
-
totalComments: this.mapToInteger(rows[0].postComments) + this.mapToInteger(rows[0].answerComments),
|
|
860
|
-
totalVotes: this.mapToInteger(rows[0].postVotes) + this.mapToInteger(rows[0].answerVotes),
|
|
861
|
-
totalArticles: this.mapToInteger(rows[0].totalArticles),
|
|
862
|
-
totalFollowers: this.mapToInteger(rows[0].totalFollowers),
|
|
863
|
-
totalLinks: this.mapToInteger(rows[0].totalLinks)
|
|
864
|
-
};
|
|
297
|
+
return this.usersStore.getUser(user_ref);
|
|
865
298
|
}
|
|
866
|
-
async
|
|
867
|
-
|
|
868
|
-
"collections",
|
|
869
|
-
"user_collections.collectionId",
|
|
870
|
-
"collections.id"
|
|
871
|
-
).select("*");
|
|
872
|
-
return {
|
|
873
|
-
collections: await Promise.all(
|
|
874
|
-
rows.map(async (val) => {
|
|
875
|
-
return this.mapCollectionEntity(val, user_ref, options);
|
|
876
|
-
})
|
|
877
|
-
),
|
|
878
|
-
count: rows.length
|
|
879
|
-
};
|
|
299
|
+
async getUserTags(user_ref, filters) {
|
|
300
|
+
return this.tagsStore.getUserTags(user_ref, filters);
|
|
880
301
|
}
|
|
881
|
-
async
|
|
882
|
-
|
|
883
|
-
return users.map((user) => user.userRef);
|
|
302
|
+
async followTag(user_ref, tag) {
|
|
303
|
+
return this.tagsStore.followTag(user_ref, tag);
|
|
884
304
|
}
|
|
885
|
-
async
|
|
886
|
-
|
|
887
|
-
{
|
|
888
|
-
userRef: user_ref,
|
|
889
|
-
collectionId
|
|
890
|
-
},
|
|
891
|
-
["collectionId"]
|
|
892
|
-
).into("user_collections");
|
|
893
|
-
return true;
|
|
305
|
+
async unfollowTag(user_ref, tag) {
|
|
306
|
+
return this.tagsStore.unfollowTag(user_ref, tag);
|
|
894
307
|
}
|
|
895
|
-
async
|
|
896
|
-
|
|
897
|
-
return true;
|
|
308
|
+
async getUserEntities(user_ref) {
|
|
309
|
+
return this.entitiesStore.getUserEntities(user_ref);
|
|
898
310
|
}
|
|
899
|
-
async
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
const tags = await query.select("tags.tag");
|
|
905
|
-
return {
|
|
906
|
-
tags: tags.map((tag) => tag.tag),
|
|
907
|
-
count: tags.length
|
|
908
|
-
};
|
|
311
|
+
async followEntity(user_ref, entityRef) {
|
|
312
|
+
return this.entitiesStore.followEntity(user_ref, entityRef);
|
|
313
|
+
}
|
|
314
|
+
async unfollowEntity(user_ref, entityRef) {
|
|
315
|
+
return this.entitiesStore.unfollowEntity(user_ref, entityRef);
|
|
909
316
|
}
|
|
910
317
|
async getUsersForTags(tags) {
|
|
911
|
-
|
|
912
|
-
return [];
|
|
913
|
-
}
|
|
914
|
-
const followingUsersQuery = this.db("user_tags").leftJoin("tags", "user_tags.tagId", "tags.id").whereIn("tags.tag", tags).select("userRef");
|
|
915
|
-
const [followingUsers, experts] = await Promise.all([
|
|
916
|
-
followingUsersQuery,
|
|
917
|
-
this.getTagExperts(tags)
|
|
918
|
-
]);
|
|
919
|
-
return [
|
|
920
|
-
.../* @__PURE__ */ new Set([...followingUsers.map((user) => user.userRef), ...experts])
|
|
921
|
-
];
|
|
318
|
+
return this.tagsStore.getUsersForTags(tags);
|
|
922
319
|
}
|
|
923
|
-
async
|
|
924
|
-
|
|
925
|
-
if (!tagId) {
|
|
926
|
-
return false;
|
|
927
|
-
}
|
|
928
|
-
await this.db.insert(
|
|
929
|
-
{
|
|
930
|
-
userRef: user_ref,
|
|
931
|
-
tagId: tagId.id
|
|
932
|
-
},
|
|
933
|
-
["tagId"]
|
|
934
|
-
).into("user_tags");
|
|
935
|
-
return true;
|
|
320
|
+
async getUsersForEntities(entityRefs) {
|
|
321
|
+
return this.entitiesStore.getUsersForEntities(entityRefs);
|
|
936
322
|
}
|
|
937
|
-
async
|
|
938
|
-
|
|
939
|
-
if (!tagId) {
|
|
940
|
-
return false;
|
|
941
|
-
}
|
|
942
|
-
await this.db("user_tags").where("userRef", user_ref).where("tagId", tagId.id).delete();
|
|
943
|
-
return true;
|
|
323
|
+
async getFollowedUsers(user_ref) {
|
|
324
|
+
return this.usersStore.getFollowedUsers(user_ref);
|
|
944
325
|
}
|
|
945
|
-
async
|
|
946
|
-
|
|
947
|
-
if (options?.entityRefs) {
|
|
948
|
-
query.whereIn("entities.entity_ref", options.entityRefs);
|
|
949
|
-
}
|
|
950
|
-
const totalQuery = query.clone();
|
|
951
|
-
if (options?.orderBy) {
|
|
952
|
-
query.orderBy(options?.orderBy, options?.order || "desc");
|
|
953
|
-
}
|
|
954
|
-
if (options?.limit) {
|
|
955
|
-
query.limit(options.limit);
|
|
956
|
-
}
|
|
957
|
-
if (options?.offset) {
|
|
958
|
-
query.offset(options.offset);
|
|
959
|
-
}
|
|
960
|
-
const results = await Promise.all([
|
|
961
|
-
query,
|
|
962
|
-
this.db(totalQuery.as("totalQuery")).count("* as CNT").first()
|
|
963
|
-
]);
|
|
964
|
-
const rows = results[0];
|
|
965
|
-
const total = this.mapToInteger(results[1]?.CNT);
|
|
966
|
-
return {
|
|
967
|
-
total,
|
|
968
|
-
entities: rows.map((entity) => {
|
|
969
|
-
return {
|
|
970
|
-
id: entity.id,
|
|
971
|
-
entityRef: entity.entity_ref,
|
|
972
|
-
postsCount: this.mapToInteger(entity.postsCount),
|
|
973
|
-
followerCount: this.mapToInteger(entity.followerCount)
|
|
974
|
-
};
|
|
975
|
-
})
|
|
976
|
-
};
|
|
326
|
+
async followUser(user_ref, followedUserRef) {
|
|
327
|
+
return this.usersStore.followUser(user_ref, followedUserRef);
|
|
977
328
|
}
|
|
978
|
-
async
|
|
979
|
-
|
|
980
|
-
const rows = await query.where("entity_ref", "=", entity_ref);
|
|
981
|
-
if (rows.length === 0) {
|
|
982
|
-
return null;
|
|
983
|
-
}
|
|
984
|
-
return {
|
|
985
|
-
id: rows[0].id,
|
|
986
|
-
entityRef: rows[0].entity_ref,
|
|
987
|
-
postsCount: this.mapToInteger(rows[0].postsCount),
|
|
988
|
-
followerCount: this.mapToInteger(rows[0].followerCount)
|
|
989
|
-
};
|
|
329
|
+
async unfollowUser(user_ref, followedUserRef) {
|
|
330
|
+
return this.usersStore.unfollowUser(user_ref, followedUserRef);
|
|
990
331
|
}
|
|
991
|
-
async
|
|
992
|
-
|
|
993
|
-
return {
|
|
994
|
-
entityRefs: entities.map((e) => e.entityRef),
|
|
995
|
-
count: entities.length
|
|
996
|
-
};
|
|
332
|
+
async getGlobalStats() {
|
|
333
|
+
return this.statsStore.getGlobalStats();
|
|
997
334
|
}
|
|
998
|
-
async
|
|
999
|
-
|
|
1000
|
-
return [];
|
|
1001
|
-
}
|
|
1002
|
-
const users = await this.db("user_entities").whereIn("entityRef", entityRefs).select("userRef");
|
|
1003
|
-
return users.map((user) => user.userRef);
|
|
335
|
+
async getUserStats(user_ref) {
|
|
336
|
+
return this.statsStore.getUserStats(user_ref);
|
|
1004
337
|
}
|
|
1005
|
-
async
|
|
1006
|
-
|
|
1007
|
-
userRef: user_ref,
|
|
1008
|
-
entityRef
|
|
1009
|
-
}).into("user_entities");
|
|
1010
|
-
return true;
|
|
338
|
+
async getTemplates() {
|
|
339
|
+
return this.templatesStore.getTemplates();
|
|
1011
340
|
}
|
|
1012
|
-
async
|
|
1013
|
-
|
|
1014
|
-
return true;
|
|
341
|
+
async getTemplate(id) {
|
|
342
|
+
return this.templatesStore.getTemplate(id);
|
|
1015
343
|
}
|
|
1016
|
-
async
|
|
1017
|
-
|
|
1018
|
-
return {
|
|
1019
|
-
followedUserRefs: entities.map((e) => e.followedUserRef),
|
|
1020
|
-
count: entities.length
|
|
1021
|
-
};
|
|
344
|
+
async createTemplate(options) {
|
|
345
|
+
return this.templatesStore.createTemplate(options);
|
|
1022
346
|
}
|
|
1023
|
-
async
|
|
1024
|
-
|
|
1025
|
-
return users.map((user) => user.userRef);
|
|
347
|
+
async deleteTemplate(id) {
|
|
348
|
+
return this.templatesStore.deleteTemplate(id);
|
|
1026
349
|
}
|
|
1027
|
-
async
|
|
1028
|
-
|
|
1029
|
-
userRef: user_ref,
|
|
1030
|
-
followedUserRef
|
|
1031
|
-
}).into("user_users");
|
|
1032
|
-
return true;
|
|
350
|
+
async updateTemplate(options) {
|
|
351
|
+
return this.templatesStore.updateTemplate(options);
|
|
1033
352
|
}
|
|
1034
|
-
async
|
|
1035
|
-
|
|
1036
|
-
|
|
353
|
+
async getAIAnswer(postId) {
|
|
354
|
+
return this.postsStore.getAIAnswer(postId);
|
|
355
|
+
}
|
|
356
|
+
async saveAIAnswer(postId, response) {
|
|
357
|
+
return this.postsStore.saveAIAnswer(postId, response);
|
|
358
|
+
}
|
|
359
|
+
async deleteAIAnswer(postId) {
|
|
360
|
+
return this.postsStore.deleteAIAnswer(postId);
|
|
361
|
+
}
|
|
362
|
+
async postAttachment({
|
|
363
|
+
uuid,
|
|
364
|
+
locationType,
|
|
365
|
+
locationUri,
|
|
366
|
+
extension,
|
|
367
|
+
mimeType,
|
|
368
|
+
binaryImage,
|
|
369
|
+
path,
|
|
370
|
+
creator
|
|
371
|
+
}) {
|
|
372
|
+
return this.attachmentsStore.postAttachment({
|
|
373
|
+
uuid,
|
|
374
|
+
locationType,
|
|
375
|
+
locationUri,
|
|
376
|
+
extension,
|
|
377
|
+
mimeType,
|
|
378
|
+
binaryImage,
|
|
379
|
+
path,
|
|
380
|
+
creator
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
async getAttachment(uuid) {
|
|
384
|
+
return this.attachmentsStore.getAttachment(uuid);
|
|
385
|
+
}
|
|
386
|
+
async deleteAttachment(uuid) {
|
|
387
|
+
return this.attachmentsStore.deleteAttachment(uuid);
|
|
1037
388
|
}
|
|
389
|
+
async getDeletableAttachments(dayLimit) {
|
|
390
|
+
return this.attachmentsStore.getDeletableAttachments(dayLimit);
|
|
391
|
+
}
|
|
392
|
+
// Stats
|
|
1038
393
|
async getMostUpvotedPosts({
|
|
1039
394
|
author,
|
|
1040
395
|
options
|
|
1041
396
|
}) {
|
|
1042
|
-
|
|
1043
|
-
if (author) {
|
|
1044
|
-
query.where("q.author", "=", author);
|
|
1045
|
-
}
|
|
1046
|
-
if (options?.period) {
|
|
1047
|
-
query.where("q.created", ">", options.period);
|
|
1048
|
-
}
|
|
1049
|
-
if (options?.type) {
|
|
1050
|
-
query.where("q.type", "=", options.type);
|
|
1051
|
-
}
|
|
1052
|
-
if (options?.limit) {
|
|
1053
|
-
query.limit(options.limit);
|
|
1054
|
-
}
|
|
1055
|
-
const rows = await query;
|
|
1056
|
-
rows.map((row, index) => {
|
|
1057
|
-
row.position = index + 1;
|
|
1058
|
-
});
|
|
1059
|
-
return rows;
|
|
397
|
+
return this.statsStore.getMostUpvotedPosts({ author, options });
|
|
1060
398
|
}
|
|
1061
399
|
async getTotalPosts({
|
|
1062
400
|
author,
|
|
1063
401
|
options
|
|
1064
402
|
}) {
|
|
1065
|
-
|
|
1066
|
-
if (author) {
|
|
1067
|
-
query.where("q.author", "=", author);
|
|
1068
|
-
}
|
|
1069
|
-
if (options?.period) {
|
|
1070
|
-
query.where("q.created", ">", options.period);
|
|
1071
|
-
}
|
|
1072
|
-
if (options?.type) {
|
|
1073
|
-
query.where("q.type", "=", options.type);
|
|
1074
|
-
}
|
|
1075
|
-
if (options?.limit) {
|
|
1076
|
-
query.limit(options.limit);
|
|
1077
|
-
}
|
|
1078
|
-
const rows = await query;
|
|
1079
|
-
if (!author) {
|
|
1080
|
-
rows.map((row, index) => {
|
|
1081
|
-
row.position = index + 1;
|
|
1082
|
-
});
|
|
1083
|
-
}
|
|
1084
|
-
return rows;
|
|
403
|
+
return this.statsStore.getTotalPosts({ author, options });
|
|
1085
404
|
}
|
|
1086
405
|
async getMostUpvotedAnswers({
|
|
1087
406
|
author,
|
|
1088
407
|
options
|
|
1089
408
|
}) {
|
|
1090
|
-
|
|
1091
|
-
if (author) {
|
|
1092
|
-
query.where("a.author", "=", author);
|
|
1093
|
-
}
|
|
1094
|
-
if (options?.period) {
|
|
1095
|
-
query.where("a.created", ">", options.period);
|
|
1096
|
-
}
|
|
1097
|
-
if (options?.limit) {
|
|
1098
|
-
query.limit(options.limit);
|
|
1099
|
-
}
|
|
1100
|
-
const rows = await query;
|
|
1101
|
-
rows.map((row, index) => {
|
|
1102
|
-
row.position = index + 1;
|
|
1103
|
-
});
|
|
1104
|
-
return rows;
|
|
409
|
+
return this.statsStore.getMostUpvotedAnswers({ author, options });
|
|
1105
410
|
}
|
|
1106
411
|
async getMostUpvotedCorrectAnswers({
|
|
1107
412
|
author,
|
|
1108
413
|
options
|
|
1109
414
|
}) {
|
|
1110
|
-
|
|
1111
|
-
if (author) {
|
|
1112
|
-
query.where("a.author", "=", author);
|
|
1113
|
-
}
|
|
1114
|
-
if (options?.period) {
|
|
1115
|
-
query.where("a.created", ">", options.period);
|
|
1116
|
-
}
|
|
1117
|
-
if (options?.limit) {
|
|
1118
|
-
query.limit(options.limit);
|
|
1119
|
-
}
|
|
1120
|
-
const rows = await query;
|
|
1121
|
-
rows.map((row, index) => {
|
|
1122
|
-
row.position = index + 1;
|
|
1123
|
-
});
|
|
1124
|
-
return rows;
|
|
415
|
+
return this.statsStore.getMostUpvotedCorrectAnswers({ author, options });
|
|
1125
416
|
}
|
|
1126
417
|
async getTotalAnswers({
|
|
1127
418
|
author,
|
|
1128
419
|
options
|
|
1129
420
|
}) {
|
|
1130
|
-
|
|
1131
|
-
if (author) {
|
|
1132
|
-
query.where("a.author", "=", author);
|
|
1133
|
-
}
|
|
1134
|
-
if (options?.period) {
|
|
1135
|
-
query.where("a.created", ">", options.period);
|
|
1136
|
-
}
|
|
1137
|
-
if (options?.limit) {
|
|
1138
|
-
query.limit(options.limit);
|
|
1139
|
-
}
|
|
1140
|
-
const rows = await query;
|
|
1141
|
-
if (!author) {
|
|
1142
|
-
rows.map((row, index) => {
|
|
1143
|
-
row.position = index + 1;
|
|
1144
|
-
});
|
|
1145
|
-
}
|
|
1146
|
-
return rows;
|
|
1147
|
-
}
|
|
1148
|
-
async postAttachment({
|
|
1149
|
-
uuid,
|
|
1150
|
-
locationType,
|
|
1151
|
-
locationUri,
|
|
1152
|
-
extension,
|
|
1153
|
-
mimeType,
|
|
1154
|
-
binaryImage,
|
|
1155
|
-
path,
|
|
1156
|
-
creator,
|
|
1157
|
-
postId,
|
|
1158
|
-
answerId,
|
|
1159
|
-
collectionId
|
|
1160
|
-
}) {
|
|
1161
|
-
const attachments = await this.db.insert(
|
|
1162
|
-
{
|
|
1163
|
-
uuid,
|
|
1164
|
-
locationType,
|
|
1165
|
-
locationUri,
|
|
1166
|
-
extension,
|
|
1167
|
-
mimeType,
|
|
1168
|
-
path,
|
|
1169
|
-
binaryImage,
|
|
1170
|
-
creator,
|
|
1171
|
-
created: /* @__PURE__ */ new Date(),
|
|
1172
|
-
postId,
|
|
1173
|
-
answerId,
|
|
1174
|
-
collectionId
|
|
1175
|
-
},
|
|
1176
|
-
["id", "uuid", "locationUri", "locationType"]
|
|
1177
|
-
).into("attachments");
|
|
1178
|
-
return attachments[0];
|
|
1179
|
-
}
|
|
1180
|
-
async deleteAttachment(uuid) {
|
|
1181
|
-
const query = this.db("attachments").where("uuid", "=", uuid);
|
|
1182
|
-
return !!await query.delete();
|
|
1183
|
-
}
|
|
1184
|
-
async getAttachment(uuid) {
|
|
1185
|
-
const rawAttachment = await this.db("attachments").where("uuid", "=", uuid).first();
|
|
1186
|
-
if (!rawAttachment) {
|
|
1187
|
-
return void 0;
|
|
1188
|
-
}
|
|
1189
|
-
return this.mapAttachment(rawAttachment);
|
|
1190
|
-
}
|
|
1191
|
-
async getDeletableAttachments(dayLimit) {
|
|
1192
|
-
const now = /* @__PURE__ */ new Date();
|
|
1193
|
-
now.setDate(now.getDate() - dayLimit);
|
|
1194
|
-
return this.db("attachments").whereNull("postId").whereNull("answerId").whereNull("collectionId").where(`created`, "<=", now).select();
|
|
1195
|
-
}
|
|
1196
|
-
async getTotalViews(user_ref, lastDays, excludeUser) {
|
|
1197
|
-
const now = /* @__PURE__ */ new Date();
|
|
1198
|
-
if (lastDays) {
|
|
1199
|
-
now.setDate(now.getDate() - lastDays);
|
|
1200
|
-
}
|
|
1201
|
-
const postViewsQuery = this.db("post_views").innerJoin("posts", "post_views.postId", "posts.id").where("posts.author", user_ref);
|
|
1202
|
-
if (lastDays) {
|
|
1203
|
-
postViewsQuery.where("posts.created", ">", now);
|
|
1204
|
-
}
|
|
1205
|
-
if (excludeUser) {
|
|
1206
|
-
postViewsQuery.where("post_views.author", "!=", user_ref);
|
|
1207
|
-
}
|
|
1208
|
-
const answerViewsQuery = this.db("post_views").innerJoin("answers", "post_views.postId", "answers.postId").innerJoin("posts", "post_views.postId", "posts.id").where("answers.author", user_ref).whereNot("posts.author", user_ref);
|
|
1209
|
-
if (lastDays) {
|
|
1210
|
-
answerViewsQuery.where("answers.created", ">", now);
|
|
1211
|
-
}
|
|
1212
|
-
if (excludeUser) {
|
|
1213
|
-
answerViewsQuery.where("post_views.author", "!=", user_ref);
|
|
1214
|
-
}
|
|
1215
|
-
const postViews = await postViewsQuery.count("* as total");
|
|
1216
|
-
const answerViews = await answerViewsQuery.count("* as total");
|
|
1217
|
-
return Number(postViews[0].total) + Number(answerViews[0].total);
|
|
421
|
+
return this.statsStore.getTotalAnswers({ author, options });
|
|
1218
422
|
}
|
|
1219
|
-
async
|
|
1220
|
-
|
|
1221
|
-
...user,
|
|
1222
|
-
date
|
|
1223
|
-
}).onConflict(["userRef", "date"]).merge();
|
|
423
|
+
async getCount(table, filters) {
|
|
424
|
+
return this.statsStore.getCount(table, filters);
|
|
1224
425
|
}
|
|
1225
426
|
async saveGlobalStats(date) {
|
|
1226
|
-
|
|
1227
|
-
totalQuestions: await this.getCount("posts", { type: "question" }),
|
|
1228
|
-
totalAnswers: await this.getCount("answers"),
|
|
1229
|
-
totalUsers: await this.getUsersCount(),
|
|
1230
|
-
totalTags: await this.getCount("tags"),
|
|
1231
|
-
totalViews: await this.getCount("post_views"),
|
|
1232
|
-
totalComments: await this.getCount("comments"),
|
|
1233
|
-
totalVotes: await this.getCount("post_votes") + await this.getCount("answer_votes"),
|
|
1234
|
-
totalArticles: await this.getCount("posts", { type: "article" }),
|
|
1235
|
-
totalLinks: await this.getCount("posts", { type: "link" }),
|
|
1236
|
-
date
|
|
1237
|
-
}).onConflict(["date"]).merge();
|
|
427
|
+
return this.statsStore.saveGlobalStats(date);
|
|
1238
428
|
}
|
|
1239
|
-
async
|
|
1240
|
-
return this.
|
|
429
|
+
async saveUserStats(user, date) {
|
|
430
|
+
return this.statsStore.saveUserStats(user, date);
|
|
1241
431
|
}
|
|
1242
|
-
async
|
|
1243
|
-
return this.
|
|
432
|
+
async getTotalViews(user_ref, lastDays, excludeUser) {
|
|
433
|
+
return this.statsStore.getTotalViews(user_ref, lastDays, excludeUser);
|
|
1244
434
|
}
|
|
1245
435
|
async cleanStats(days, date) {
|
|
1246
|
-
|
|
1247
|
-
now.setDate(now.getDate() - days);
|
|
1248
|
-
await this.db("user_stats").where("date", "<=", now).delete();
|
|
1249
|
-
await this.db("global_stats").where("date", "<=", now).delete();
|
|
1250
|
-
}
|
|
1251
|
-
async getCount(table, filters) {
|
|
1252
|
-
const query = this.db(table);
|
|
1253
|
-
if (filters?.author) {
|
|
1254
|
-
query.where("author", filters.author);
|
|
1255
|
-
}
|
|
1256
|
-
if (filters?.type) {
|
|
1257
|
-
query.where("type", filters.type);
|
|
1258
|
-
}
|
|
1259
|
-
const result = await query.count("* as total").first();
|
|
1260
|
-
return this.mapToInteger(result?.total);
|
|
1261
|
-
}
|
|
1262
|
-
async getCollections(user_ref, options, opts) {
|
|
1263
|
-
const query = this.getCollectionsBaseQuery();
|
|
1264
|
-
if (options.owner) {
|
|
1265
|
-
query.where("owner", options.owner);
|
|
1266
|
-
}
|
|
1267
|
-
if (options.fromDate && options.toDate) {
|
|
1268
|
-
query.whereBetween("collections.created", [
|
|
1269
|
-
`${options.fromDate} 00:00:00.000+00`,
|
|
1270
|
-
`${options.toDate} 23:59:59.999+00`
|
|
1271
|
-
]);
|
|
1272
|
-
}
|
|
1273
|
-
if (options.searchQuery) {
|
|
1274
|
-
this.applySearchQuery(
|
|
1275
|
-
query,
|
|
1276
|
-
["collections.title", "collections.description"],
|
|
1277
|
-
options.searchQuery
|
|
1278
|
-
);
|
|
1279
|
-
}
|
|
1280
|
-
if (options.tags) {
|
|
1281
|
-
const tags = backstagePluginQetaCommon.filterTags(options.tags);
|
|
1282
|
-
if (options.tagsRelation === "or") {
|
|
1283
|
-
query.leftJoin(
|
|
1284
|
-
"post_tags",
|
|
1285
|
-
"collection_posts.postId",
|
|
1286
|
-
"post_tags.postId"
|
|
1287
|
-
);
|
|
1288
|
-
query.leftJoin("tags", "post_tags.tagId", "tags.id");
|
|
1289
|
-
query.where((qb) => {
|
|
1290
|
-
qb.whereIn("tags.tag", tags).orWhereNull("collection_posts.postId");
|
|
1291
|
-
});
|
|
1292
|
-
} else {
|
|
1293
|
-
tags.forEach((t, i) => {
|
|
1294
|
-
query.innerJoin(
|
|
1295
|
-
`post_tags AS qt${i}`,
|
|
1296
|
-
"collection_posts.postId",
|
|
1297
|
-
`qt${i}.postId`
|
|
1298
|
-
);
|
|
1299
|
-
query.innerJoin(`tags AS t${i}`, `qt${i}.tagId`, `t${i}.id`);
|
|
1300
|
-
query.where(`t${i}.tag`, "=", t);
|
|
1301
|
-
});
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
if (options.entities) {
|
|
1305
|
-
const entityValues = Array.isArray(options.entities) ? options.entities : [options.entities];
|
|
1306
|
-
if (options.entitiesRelation === "or") {
|
|
1307
|
-
query.leftJoin(
|
|
1308
|
-
"post_entities",
|
|
1309
|
-
"collection_posts.postId",
|
|
1310
|
-
"post_entities.postId"
|
|
1311
|
-
);
|
|
1312
|
-
query.leftJoin("entities", "post_entities.entityId", "entities.id");
|
|
1313
|
-
query.where((qb) => {
|
|
1314
|
-
qb.whereIn("entities.entity_ref", entityValues).orWhereNull(
|
|
1315
|
-
"collection_posts.postId"
|
|
1316
|
-
);
|
|
1317
|
-
});
|
|
1318
|
-
} else {
|
|
1319
|
-
entityValues.forEach((t, i) => {
|
|
1320
|
-
query.innerJoin(
|
|
1321
|
-
`post_entities AS pe${i}`,
|
|
1322
|
-
"collection_posts.postId",
|
|
1323
|
-
`pe${i}.postId`
|
|
1324
|
-
);
|
|
1325
|
-
query.innerJoin(`entities AS e${i}`, `pe${i}.entityId`, `e${i}.id`);
|
|
1326
|
-
query.where(`e${i}.entity_ref`, "=", t);
|
|
1327
|
-
});
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
if (options.ids) {
|
|
1331
|
-
query.whereIn("collections.id", options.ids);
|
|
1332
|
-
}
|
|
1333
|
-
if (opts?.filters) {
|
|
1334
|
-
parseFilter(opts.filters, query, this.db);
|
|
1335
|
-
}
|
|
1336
|
-
const totalQuery = query.clone();
|
|
1337
|
-
if (options.orderBy) {
|
|
1338
|
-
query.orderBy(options.orderBy, options.order || "desc");
|
|
1339
|
-
} else {
|
|
1340
|
-
query.orderBy("created", "desc");
|
|
1341
|
-
}
|
|
1342
|
-
if (options.limit) {
|
|
1343
|
-
query.limit(options.limit);
|
|
1344
|
-
}
|
|
1345
|
-
if (options.offset) {
|
|
1346
|
-
query.offset(options.offset);
|
|
1347
|
-
}
|
|
1348
|
-
const results = await Promise.all([
|
|
1349
|
-
query,
|
|
1350
|
-
this.db(totalQuery.as("totalQuery")).count("* as CNT").first()
|
|
1351
|
-
]);
|
|
1352
|
-
const rows = results[0];
|
|
1353
|
-
const total = this.mapToInteger(results[1]?.CNT);
|
|
1354
|
-
return {
|
|
1355
|
-
collections: await Promise.all(
|
|
1356
|
-
rows.map(async (val) => {
|
|
1357
|
-
return this.mapCollectionEntity(val, user_ref, {
|
|
1358
|
-
...opts,
|
|
1359
|
-
includePosts: options.includePosts ?? opts?.includePosts,
|
|
1360
|
-
includeExperts: options.includeExperts ?? opts?.includeExperts
|
|
1361
|
-
});
|
|
1362
|
-
})
|
|
1363
|
-
),
|
|
1364
|
-
total
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
async getCollection(user_ref, id, options) {
|
|
1368
|
-
const collections = await this.db("collections").where("id", "=", id);
|
|
1369
|
-
if (collections.length === 0) {
|
|
1370
|
-
return null;
|
|
1371
|
-
}
|
|
1372
|
-
return this.mapCollectionEntity(collections[0], user_ref, options);
|
|
1373
|
-
}
|
|
1374
|
-
async createCollection(options) {
|
|
1375
|
-
const { user_ref, title, description, created, images, headerImage, opts } = options;
|
|
1376
|
-
const collections = await this.db.insert(
|
|
1377
|
-
{
|
|
1378
|
-
owner: user_ref,
|
|
1379
|
-
title,
|
|
1380
|
-
description,
|
|
1381
|
-
created,
|
|
1382
|
-
headerImage
|
|
1383
|
-
},
|
|
1384
|
-
["id"]
|
|
1385
|
-
).into("collections").returning(["id", "title", "description", "created", "headerImage"]);
|
|
1386
|
-
await this.updateAttachments(
|
|
1387
|
-
"collectionId",
|
|
1388
|
-
description ?? "",
|
|
1389
|
-
images ?? [],
|
|
1390
|
-
collections[0].id,
|
|
1391
|
-
headerImage
|
|
1392
|
-
);
|
|
1393
|
-
return this.mapCollectionEntity(collections[0], user_ref, opts);
|
|
1394
|
-
}
|
|
1395
|
-
async updateCollection(options) {
|
|
1396
|
-
const { id, user_ref, title, description, images, headerImage, opts } = options;
|
|
1397
|
-
const query = this.db("collections").where("collections.id", "=", id);
|
|
1398
|
-
const rows = await query.update({
|
|
1399
|
-
title,
|
|
1400
|
-
description,
|
|
1401
|
-
headerImage
|
|
1402
|
-
});
|
|
1403
|
-
if (!rows) {
|
|
1404
|
-
return null;
|
|
1405
|
-
}
|
|
1406
|
-
await this.updateAttachments(
|
|
1407
|
-
"collectionId",
|
|
1408
|
-
description ?? "",
|
|
1409
|
-
images ?? [],
|
|
1410
|
-
id,
|
|
1411
|
-
headerImage
|
|
1412
|
-
);
|
|
1413
|
-
return await this.getCollection(user_ref, id, opts);
|
|
1414
|
-
}
|
|
1415
|
-
async deleteCollection(id) {
|
|
1416
|
-
const query = this.db("collections").where("id", "=", id);
|
|
1417
|
-
return !!await query.delete();
|
|
1418
|
-
}
|
|
1419
|
-
async addPostToCollection(user_ref, id, postId, options) {
|
|
1420
|
-
await this.db.insert({
|
|
1421
|
-
collectionId: id,
|
|
1422
|
-
postId
|
|
1423
|
-
}).into("collection_posts").onConflict().ignore();
|
|
1424
|
-
return await this.getCollection(user_ref, id, options);
|
|
1425
|
-
}
|
|
1426
|
-
async removePostFromCollection(user_ref, id, postId, options) {
|
|
1427
|
-
await this.db("collection_posts").where("collectionId", id).where("postId", postId).delete();
|
|
1428
|
-
return await this.getCollection(user_ref, id, options);
|
|
1429
|
-
}
|
|
1430
|
-
async getTemplates() {
|
|
1431
|
-
const templates = await this.db("templates").select("*");
|
|
1432
|
-
return {
|
|
1433
|
-
templates: await Promise.all(
|
|
1434
|
-
templates.map((t) => this.mapTemplateEntity(t))
|
|
1435
|
-
),
|
|
1436
|
-
total: templates.length
|
|
1437
|
-
};
|
|
1438
|
-
}
|
|
1439
|
-
async createTemplate(options) {
|
|
1440
|
-
const {
|
|
1441
|
-
title,
|
|
1442
|
-
questionTitle,
|
|
1443
|
-
questionContent,
|
|
1444
|
-
description,
|
|
1445
|
-
tags,
|
|
1446
|
-
entities
|
|
1447
|
-
} = options;
|
|
1448
|
-
const templates = await this.db.insert(
|
|
1449
|
-
{
|
|
1450
|
-
title,
|
|
1451
|
-
description,
|
|
1452
|
-
questionTitle,
|
|
1453
|
-
questionContent
|
|
1454
|
-
},
|
|
1455
|
-
["id"]
|
|
1456
|
-
).into("templates").returning([
|
|
1457
|
-
"id",
|
|
1458
|
-
"title",
|
|
1459
|
-
"description",
|
|
1460
|
-
"questionTitle",
|
|
1461
|
-
"questionContent"
|
|
1462
|
-
]);
|
|
1463
|
-
await Promise.all([
|
|
1464
|
-
this.addTags(templates[0].id, tags, true, "template_tags", "templateId"),
|
|
1465
|
-
this.addEntities(
|
|
1466
|
-
templates[0].id,
|
|
1467
|
-
entities,
|
|
1468
|
-
true,
|
|
1469
|
-
"template_entities",
|
|
1470
|
-
"templateId"
|
|
1471
|
-
)
|
|
1472
|
-
]);
|
|
1473
|
-
return this.mapTemplateEntity(templates[0]);
|
|
1474
|
-
}
|
|
1475
|
-
async getTemplate(id) {
|
|
1476
|
-
const templates = await this.db("templates").where("id", "=", id);
|
|
1477
|
-
if (templates.length === 0) {
|
|
1478
|
-
return null;
|
|
1479
|
-
}
|
|
1480
|
-
return this.mapTemplateEntity(templates[0]);
|
|
1481
|
-
}
|
|
1482
|
-
async deleteTemplate(id) {
|
|
1483
|
-
const query = this.db("templates").where("id", "=", id);
|
|
1484
|
-
return !!await query.delete();
|
|
1485
|
-
}
|
|
1486
|
-
async updateTemplate(options) {
|
|
1487
|
-
const {
|
|
1488
|
-
id,
|
|
1489
|
-
title,
|
|
1490
|
-
description,
|
|
1491
|
-
questionTitle,
|
|
1492
|
-
questionContent,
|
|
1493
|
-
tags,
|
|
1494
|
-
entities
|
|
1495
|
-
} = options;
|
|
1496
|
-
const query = this.db("templates").where("templates.id", "=", id);
|
|
1497
|
-
const rows = await query.update({
|
|
1498
|
-
title,
|
|
1499
|
-
description,
|
|
1500
|
-
questionTitle,
|
|
1501
|
-
questionContent
|
|
1502
|
-
});
|
|
1503
|
-
if (!rows) {
|
|
1504
|
-
return null;
|
|
1505
|
-
}
|
|
1506
|
-
await Promise.all([
|
|
1507
|
-
this.addTags(id, tags, true, "template_tags", "templateId"),
|
|
1508
|
-
this.addEntities(id, entities, true, "template_entities", "templateId")
|
|
1509
|
-
]);
|
|
1510
|
-
return await this.getTemplate(id);
|
|
1511
|
-
}
|
|
1512
|
-
async getAIAnswer(postId) {
|
|
1513
|
-
const row = await this.db("post_ai_answers").where("postId", postId).select().first();
|
|
1514
|
-
if (!row) {
|
|
1515
|
-
return null;
|
|
1516
|
-
}
|
|
1517
|
-
return {
|
|
1518
|
-
answer: row.answer,
|
|
1519
|
-
created: row.created
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
async saveAIAnswer(postId, response) {
|
|
1523
|
-
await this.db.insert({
|
|
1524
|
-
postId,
|
|
1525
|
-
answer: response.answer,
|
|
1526
|
-
created: /* @__PURE__ */ new Date()
|
|
1527
|
-
}).into("post_ai_answers").onConflict().ignore();
|
|
436
|
+
return this.statsStore.cleanStats(days, date);
|
|
1528
437
|
}
|
|
1529
|
-
async
|
|
1530
|
-
return
|
|
1531
|
-
}
|
|
1532
|
-
async getPostRank(collectionId, postId) {
|
|
1533
|
-
const rank = await this.db("collection_posts").where("collectionId", collectionId).where("postId", postId).select("rank").first();
|
|
1534
|
-
return rank?.rank ?? null;
|
|
1535
|
-
}
|
|
1536
|
-
async getTopRankedPostId(collectionId) {
|
|
1537
|
-
const post = await this.db("collection_posts").where("collectionId", collectionId).orderBy("rank", "desc").limit(1).select(["postId", "rank"]);
|
|
1538
|
-
return post[0] ? { postId: post[0].postId, rank: post[0].rank } : null;
|
|
1539
|
-
}
|
|
1540
|
-
async getBottomRankedPostId(collectionId) {
|
|
1541
|
-
const post = await this.db("collection_posts").where("collectionId", collectionId).orderBy("rank", "asc").limit(1).select(["postId", "rank"]);
|
|
1542
|
-
return post[0] ? { postId: post[0].postId, rank: post[0].rank } : null;
|
|
1543
|
-
}
|
|
1544
|
-
async getNextRankedPostId(collectionId, postId) {
|
|
1545
|
-
const rank = await this.getPostRank(collectionId, postId);
|
|
1546
|
-
if (rank === null) {
|
|
1547
|
-
return null;
|
|
1548
|
-
}
|
|
1549
|
-
const post = await this.db("collection_posts").where("collectionId", collectionId).where("rank", ">", rank).orderBy("rank", "asc").select(["postId", "rank"]).first();
|
|
1550
|
-
return post ? { postId: post.postId, rank: post.rank } : null;
|
|
1551
|
-
}
|
|
1552
|
-
async getPreviousRankedPostId(collectionId, postId) {
|
|
1553
|
-
const rank = await this.getPostRank(collectionId, postId);
|
|
1554
|
-
if (rank === null) {
|
|
1555
|
-
return null;
|
|
1556
|
-
}
|
|
1557
|
-
const post = await this.db("collection_posts").where("collectionId", collectionId).where("rank", "<", rank).orderBy("rank", "desc").select(["postId", "rank"]).first();
|
|
1558
|
-
return post ? { postId: post.postId, rank: post.rank } : null;
|
|
438
|
+
async getUsersCount() {
|
|
439
|
+
return this.usersStore.getUsersCount();
|
|
1559
440
|
}
|
|
1560
|
-
async
|
|
1561
|
-
|
|
441
|
+
async getFollowingUsers(user_ref) {
|
|
442
|
+
return this.usersStore.getFollowingUsers(user_ref);
|
|
1562
443
|
}
|
|
1563
444
|
async getEntityLinks() {
|
|
1564
|
-
|
|
1565
|
-
const entityLinksMap = /* @__PURE__ */ new Map();
|
|
1566
|
-
for (const row of rows) {
|
|
1567
|
-
const entityRef = row.entityRef;
|
|
1568
|
-
const link = {
|
|
1569
|
-
title: row.title,
|
|
1570
|
-
url: row.url,
|
|
1571
|
-
type: "qeta"
|
|
1572
|
-
};
|
|
1573
|
-
if (!entityLinksMap.has(entityRef)) {
|
|
1574
|
-
entityLinksMap.set(entityRef, []);
|
|
1575
|
-
}
|
|
1576
|
-
entityLinksMap.get(entityRef).push(link);
|
|
1577
|
-
}
|
|
1578
|
-
return Array.from(entityLinksMap.entries()).map(([entityRef, links]) => ({
|
|
1579
|
-
entityRef,
|
|
1580
|
-
links
|
|
1581
|
-
}));
|
|
1582
|
-
}
|
|
1583
|
-
async getTagExpertsById(id) {
|
|
1584
|
-
const rows = await this.db("tag_experts").where("tagId", id).select("entityRef");
|
|
1585
|
-
return rows.map((r) => r.entityRef);
|
|
1586
|
-
}
|
|
1587
|
-
async updateTagExperts(id, experts) {
|
|
1588
|
-
await this.db("tag_experts").where("tagId", id).delete();
|
|
1589
|
-
await this.db.insert(experts.map((e) => ({ tagId: id, entityRef: e }))).into("tag_experts").onConflict(["tagId", "entityRef"]).merge();
|
|
1590
|
-
}
|
|
1591
|
-
getEntitiesBaseQuery() {
|
|
1592
|
-
const entityId = this.db.ref("entities.id");
|
|
1593
|
-
const entityRef = this.db.ref("entities.entity_ref");
|
|
1594
|
-
const postsCount = this.db("post_entities").where("post_entities.entityId", entityId).count("*").as("postsCount");
|
|
1595
|
-
const followerCount = this.db("user_entities").where("user_entities.entityRef", entityRef).count("*").as("followerCount");
|
|
1596
|
-
return this.db("entities").rightJoin("post_entities", "entities.id", "post_entities.entityId").orderBy("postsCount", "desc").select("id", "entity_ref", postsCount, followerCount).groupBy("entities.id");
|
|
1597
|
-
}
|
|
1598
|
-
getTagBaseQuery() {
|
|
1599
|
-
const tagRef = this.db.ref("tags.id");
|
|
1600
|
-
const postsCount = this.db("post_tags").where("post_tags.tagId", tagRef).count("*").as("postsCount");
|
|
1601
|
-
const followerCount = this.db("user_tags").where("user_tags.tagId", tagRef).count("*").as("followerCount");
|
|
1602
|
-
return this.db("tags").leftJoin("post_tags", "tags.id", "post_tags.tagId").orderBy("postsCount", "desc").select("id", "tag", "description", postsCount, followerCount).groupBy("tags.id");
|
|
1603
|
-
}
|
|
1604
|
-
getUserBaseQuery() {
|
|
1605
|
-
if (this.db.client.config.client !== "pg") {
|
|
1606
|
-
return this.db("posts").select([
|
|
1607
|
-
"author",
|
|
1608
|
-
this.db.raw("0 as totalViews"),
|
|
1609
|
-
this.db.raw("0 as totalQuestions"),
|
|
1610
|
-
this.db.raw("0 as totalArticles"),
|
|
1611
|
-
this.db.raw("0 as totalLinks"),
|
|
1612
|
-
this.db.raw("0 as totalAnswers"),
|
|
1613
|
-
this.db.raw("0 as answerComments"),
|
|
1614
|
-
this.db.raw("0 as postComments"),
|
|
1615
|
-
this.db.raw("0 as answerVotes"),
|
|
1616
|
-
this.db.raw("0 as postVotes"),
|
|
1617
|
-
this.db.raw("0 as totalFollowers")
|
|
1618
|
-
]).distinct();
|
|
1619
|
-
}
|
|
1620
|
-
const authorRef = this.db.ref("unique_authors.author");
|
|
1621
|
-
const views = this.db("post_views").where("post_views.author", authorRef).count("*").as("totalViews");
|
|
1622
|
-
const questions = this.db("posts").where("posts.author", authorRef).where("posts.type", "question").count("*").as("totalQuestions");
|
|
1623
|
-
const articles = this.db("posts").where("posts.author", authorRef).where("posts.type", "article").count("*").as("totalArticles");
|
|
1624
|
-
const links = this.db("posts").where("posts.author", authorRef).where("posts.type", "link").count("*").as("totalLinks");
|
|
1625
|
-
const answers = this.db("answers").where("answers.author", authorRef).count("*").as("totalAnswers");
|
|
1626
|
-
const comments = this.db("comments").where("comments.author", authorRef).count("*").as("comments");
|
|
1627
|
-
const aVotes = this.db("answer_votes").where("answer_votes.author", authorRef).count("*").as("answerVotes");
|
|
1628
|
-
const pVotes = this.db("post_votes").where("post_votes.author", authorRef).count("*").as("postVotes");
|
|
1629
|
-
const followers = this.db("user_users").where("user_users.followedUserRef", authorRef).count("*").as("totalFollowers");
|
|
1630
|
-
return this.db("unique_authors").select(
|
|
1631
|
-
"author",
|
|
1632
|
-
views,
|
|
1633
|
-
questions,
|
|
1634
|
-
answers,
|
|
1635
|
-
articles,
|
|
1636
|
-
links,
|
|
1637
|
-
comments,
|
|
1638
|
-
pVotes,
|
|
1639
|
-
aVotes,
|
|
1640
|
-
followers
|
|
1641
|
-
);
|
|
445
|
+
return this.entitiesStore.getEntityLinks();
|
|
1642
446
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
* strings instead numbers for count and sum functions.
|
|
1646
|
-
* @param val
|
|
1647
|
-
*/
|
|
1648
|
-
mapToInteger = (val) => {
|
|
1649
|
-
return typeof val === "string" ? Number.parseInt(val, 10) : val ?? 0;
|
|
1650
|
-
};
|
|
1651
|
-
async mapCollectionEntity(val, user_ref, options) {
|
|
1652
|
-
const { postFilters, includePosts = true } = options ?? {};
|
|
1653
|
-
const results = await Promise.all([
|
|
1654
|
-
includePosts ? this.getPosts(
|
|
1655
|
-
user_ref,
|
|
1656
|
-
{ collectionId: val.id, includeEntities: true },
|
|
1657
|
-
postFilters,
|
|
1658
|
-
{
|
|
1659
|
-
tagsFilter: options?.tagFilters,
|
|
1660
|
-
includeComments: false,
|
|
1661
|
-
includeAnswers: false,
|
|
1662
|
-
includeAttachments: false,
|
|
1663
|
-
includeVotes: false,
|
|
1664
|
-
includeTotal: false,
|
|
1665
|
-
includeExperts: options?.includeExperts ?? false
|
|
1666
|
-
}
|
|
1667
|
-
) : { posts: [] },
|
|
1668
|
-
this.db("attachments").where("collectionId", val.id).select("id"),
|
|
1669
|
-
this.db("user_collections").count("*").as("followers").where("collectionId", val.id).first(),
|
|
1670
|
-
options?.includeExperts ?? true ? this.getCollectionExperts(val.id) : void 0
|
|
1671
|
-
]);
|
|
1672
|
-
const entities = lodash.compact([
|
|
1673
|
-
...new Set(results[0].posts.map((p) => p.entities).flat())
|
|
1674
|
-
]);
|
|
1675
|
-
const tags = lodash.compact([
|
|
1676
|
-
...new Set(results[0].posts.map((p) => p.tags).flat())
|
|
1677
|
-
]);
|
|
1678
|
-
return {
|
|
1679
|
-
id: val.id,
|
|
1680
|
-
title: val.title,
|
|
1681
|
-
owner: val.owner,
|
|
1682
|
-
description: val.description,
|
|
1683
|
-
created: val.created,
|
|
1684
|
-
posts: results[0].posts,
|
|
1685
|
-
headerImage: val.headerImage,
|
|
1686
|
-
postsCount: this.mapToInteger(val.postsCount),
|
|
1687
|
-
entities,
|
|
1688
|
-
tags,
|
|
1689
|
-
images: results[1].map((r) => r.id),
|
|
1690
|
-
followers: this.mapToInteger(results[2].count),
|
|
1691
|
-
experts: results[3]
|
|
1692
|
-
};
|
|
1693
|
-
}
|
|
1694
|
-
async getCollectionExperts(collectionId) {
|
|
1695
|
-
const rows = await this.db("tag_experts").leftJoin("tags", "tag_experts.tagId", "tags.id").leftJoin("post_tags", "post_tags.tagId", "tags.id").leftJoin(
|
|
1696
|
-
"collection_posts",
|
|
1697
|
-
"collection_posts.postId",
|
|
1698
|
-
"post_tags.postId"
|
|
1699
|
-
).where("collection_posts.collectionId", collectionId).select("tag_experts.entityRef");
|
|
1700
|
-
return [...new Set(rows.map((r) => r.entityRef))];
|
|
1701
|
-
}
|
|
1702
|
-
async mapTemplateEntity(val) {
|
|
1703
|
-
const additionalInfo = await Promise.all([
|
|
1704
|
-
this.getRelatedTags(val.id, "template_tags", "templateId"),
|
|
1705
|
-
this.getRelatedEntities(val.id, "template_entities", "templateId")
|
|
1706
|
-
]);
|
|
1707
|
-
return {
|
|
1708
|
-
id: val.id,
|
|
1709
|
-
title: val.title,
|
|
1710
|
-
description: val.description,
|
|
1711
|
-
questionTitle: val.questionTitle ?? void 0,
|
|
1712
|
-
questionContent: val.questionContent ?? void 0,
|
|
1713
|
-
tags: additionalInfo[0],
|
|
1714
|
-
entities: additionalInfo[1]
|
|
1715
|
-
};
|
|
1716
|
-
}
|
|
1717
|
-
async mapPostEntity(val, user_ref, options) {
|
|
1718
|
-
const {
|
|
1719
|
-
includeTags = true,
|
|
1720
|
-
includeAnswers = true,
|
|
1721
|
-
includeVotes = true,
|
|
1722
|
-
includeEntities = true,
|
|
1723
|
-
includeComments = true,
|
|
1724
|
-
includeAttachments = true,
|
|
1725
|
-
includeExperts = true,
|
|
1726
|
-
tagsFilter
|
|
1727
|
-
} = options ?? {};
|
|
1728
|
-
const additionalInfo = await Promise.all([
|
|
1729
|
-
includeTags ? this.getRelatedTags(val.id, "post_tags", "postId", tagsFilter) : void 0,
|
|
1730
|
-
includeAnswers ? this.getPostAnswers(val.id, user_ref, {
|
|
1731
|
-
...options,
|
|
1732
|
-
includePost: false,
|
|
1733
|
-
filter: options?.answersFilter
|
|
1734
|
-
}) : void 0,
|
|
1735
|
-
includeVotes ? this.getPostVotes(val.id) : void 0,
|
|
1736
|
-
includeEntities ? this.getRelatedEntities(val.id) : void 0,
|
|
1737
|
-
includeComments ? this.getPostComments(val.id, options?.commentsFilter) : void 0,
|
|
1738
|
-
includeAttachments ? this.db("attachments").select("id").where("postId", val.id) : void 0,
|
|
1739
|
-
includeExperts ? this.getPostExperts(val.id) : void 0
|
|
1740
|
-
]);
|
|
1741
|
-
return {
|
|
1742
|
-
id: val.id,
|
|
1743
|
-
author: val.anonymous && val.author !== user_ref ? "anonymous" : val.author,
|
|
1744
|
-
own: val.author === user_ref,
|
|
1745
|
-
title: val.title,
|
|
1746
|
-
content: val.content,
|
|
1747
|
-
created: val.created,
|
|
1748
|
-
updated: val.updated,
|
|
1749
|
-
updatedBy: val.updatedBy,
|
|
1750
|
-
status: val.status,
|
|
1751
|
-
score: this.mapToInteger(val.score),
|
|
1752
|
-
views: this.mapToInteger(val.views),
|
|
1753
|
-
answersCount: this.mapToInteger(val.answersCount),
|
|
1754
|
-
correctAnswer: this.mapToInteger(val.correctAnswers) > 0,
|
|
1755
|
-
commentsCount: this.mapToInteger(val.commentsCount),
|
|
1756
|
-
favorite: this.mapToInteger(val.favorite) > 0,
|
|
1757
|
-
tags: additionalInfo[0],
|
|
1758
|
-
answers: additionalInfo[1],
|
|
1759
|
-
votes: additionalInfo[2],
|
|
1760
|
-
entities: additionalInfo[3],
|
|
1761
|
-
trend: this.mapToInteger(val.trend),
|
|
1762
|
-
comments: additionalInfo[4],
|
|
1763
|
-
ownVote: additionalInfo[2]?.find((v) => v.author === user_ref)?.score,
|
|
1764
|
-
anonymous: val.anonymous,
|
|
1765
|
-
type: val.type,
|
|
1766
|
-
headerImage: val.headerImage,
|
|
1767
|
-
url: val.url ?? void 0,
|
|
1768
|
-
images: additionalInfo[5]?.map((r) => r.id),
|
|
1769
|
-
experts: additionalInfo[6],
|
|
1770
|
-
published: val.published ? val.published : void 0
|
|
1771
|
-
};
|
|
1772
|
-
}
|
|
1773
|
-
mapComment(val) {
|
|
1774
|
-
return {
|
|
1775
|
-
id: val.id,
|
|
1776
|
-
author: val.author,
|
|
1777
|
-
content: val.content,
|
|
1778
|
-
created: val.created,
|
|
1779
|
-
updated: val.updated,
|
|
1780
|
-
updatedBy: val.updatedBy,
|
|
1781
|
-
status: val.status
|
|
1782
|
-
};
|
|
1783
|
-
}
|
|
1784
|
-
async mapAnswer(val, user_ref, options) {
|
|
1785
|
-
const {
|
|
1786
|
-
includeVotes = true,
|
|
1787
|
-
includeComments = true,
|
|
1788
|
-
includePost = true,
|
|
1789
|
-
includeExperts = true
|
|
1790
|
-
} = options ?? {};
|
|
1791
|
-
const additionalInfo = await Promise.all([
|
|
1792
|
-
includeVotes ? this.getAnswerVotes(val.id) : void 0,
|
|
1793
|
-
includeComments ? this.getAnswerComments(val.id, options?.commentsFilter) : void 0,
|
|
1794
|
-
includePost ? this.getPost(user_ref, val.postId, false) : void 0,
|
|
1795
|
-
this.db("attachments").select("id").where("answerId", val.id),
|
|
1796
|
-
includeExperts ? this.getAnswerExperts(val.id) : void 0
|
|
1797
|
-
]);
|
|
1798
|
-
return {
|
|
1799
|
-
id: val.id,
|
|
1800
|
-
postId: val.postId,
|
|
1801
|
-
own: val.author === user_ref,
|
|
1802
|
-
author: val.anonymous && val.author !== user_ref ? "anonymous" : val.author,
|
|
1803
|
-
content: val.content,
|
|
1804
|
-
correct: val.correct,
|
|
1805
|
-
created: val.created,
|
|
1806
|
-
updated: val.updated,
|
|
1807
|
-
updatedBy: val.updatedBy,
|
|
1808
|
-
score: this.mapToInteger(val.score),
|
|
1809
|
-
status: val.status,
|
|
1810
|
-
votes: additionalInfo[0],
|
|
1811
|
-
comments: additionalInfo[1],
|
|
1812
|
-
anonymous: val.anonymous,
|
|
1813
|
-
post: additionalInfo[2] ?? void 0,
|
|
1814
|
-
images: additionalInfo[3].map((r) => r.id),
|
|
1815
|
-
experts: additionalInfo[4] ?? void 0
|
|
1816
|
-
};
|
|
1817
|
-
}
|
|
1818
|
-
mapVote(val) {
|
|
1819
|
-
return {
|
|
1820
|
-
author: val.author,
|
|
1821
|
-
score: val.score,
|
|
1822
|
-
timestamp: val.timestamp
|
|
1823
|
-
};
|
|
1824
|
-
}
|
|
1825
|
-
mapAttachment(val) {
|
|
1826
|
-
return {
|
|
1827
|
-
...val,
|
|
1828
|
-
created: val.created instanceof Date ? val.created : new Date(val.created)
|
|
1829
|
-
};
|
|
1830
|
-
}
|
|
1831
|
-
async getRelatedTags(id, tableName = "post_tags", columnName = "postId", tagsFilter) {
|
|
1832
|
-
const query = this.db("tags").leftJoin(tableName, "tags.id", `${tableName}.tagId`).where(`${tableName}.${columnName}`, "=", id);
|
|
1833
|
-
if (tagsFilter) {
|
|
1834
|
-
parseFilter(tagsFilter, query, this.db, "tags");
|
|
1835
|
-
}
|
|
1836
|
-
const rows = await query.select();
|
|
1837
|
-
return rows.map((val) => val.tag);
|
|
1838
|
-
}
|
|
1839
|
-
async getPostComments(postId, commentsFilter, opts) {
|
|
1840
|
-
const { includeStatusFilter = true } = opts ?? {};
|
|
1841
|
-
const query = this.db("comments").where("comments.postId", "=", postId).orderBy("created");
|
|
1842
|
-
if (includeStatusFilter) {
|
|
1843
|
-
query.where("comments.status", "=", "active");
|
|
1844
|
-
}
|
|
1845
|
-
if (commentsFilter) {
|
|
1846
|
-
parseFilter(commentsFilter, query, this.db, "comments");
|
|
1847
|
-
}
|
|
1848
|
-
const rows = await query.select();
|
|
1849
|
-
return rows.map((val) => this.mapComment(val));
|
|
1850
|
-
}
|
|
1851
|
-
async getPostExperts(postId) {
|
|
1852
|
-
const rows = await this.db("tag_experts").leftJoin("post_tags", "tag_experts.tagId", "post_tags.tagId").where("post_tags.postId", postId).select("tag_experts.entityRef");
|
|
1853
|
-
return [...new Set(rows.map((r) => r.entityRef))];
|
|
1854
|
-
}
|
|
1855
|
-
async getAnswerComments(answerId, commentsFilter, opts) {
|
|
1856
|
-
const { includeStatusFilter = true } = opts ?? {};
|
|
1857
|
-
const query = this.db("comments").where("comments.answerId", "=", answerId).orderBy("created");
|
|
1858
|
-
if (includeStatusFilter) {
|
|
1859
|
-
query.where("comments.status", "=", "active");
|
|
1860
|
-
}
|
|
1861
|
-
if (commentsFilter) {
|
|
1862
|
-
parseFilter(commentsFilter, query, this.db, "comments");
|
|
1863
|
-
}
|
|
1864
|
-
const rows = await query.select();
|
|
1865
|
-
return rows.map((val) => this.mapComment(val));
|
|
1866
|
-
}
|
|
1867
|
-
async getRelatedEntities(id, tableName = "post_entities", columnName = "postId") {
|
|
1868
|
-
const rows = await this.db("entities").leftJoin(tableName, "entities.id", `${tableName}.entityId`).where(`${tableName}.${columnName}`, "=", id).select();
|
|
1869
|
-
return rows.map((val) => val.entity_ref);
|
|
1870
|
-
}
|
|
1871
|
-
async getPostVotes(postId) {
|
|
1872
|
-
const rows = await this.db("post_votes").where("postId", "=", postId).select();
|
|
1873
|
-
return rows.map((val) => this.mapVote(val));
|
|
1874
|
-
}
|
|
1875
|
-
async getAnswerVotes(answerId) {
|
|
1876
|
-
const rows = await this.db("answer_votes").where("answerId", "=", answerId).select();
|
|
1877
|
-
return rows.map((val) => this.mapVote(val));
|
|
1878
|
-
}
|
|
1879
|
-
async getAnswerExperts(answerId) {
|
|
1880
|
-
const rows = await this.db("tag_experts").leftJoin("tags", "tag_experts.tagId", "tags.id").leftJoin("post_tags", "post_tags.tagId", "tags.id").leftJoin("answers", "answers.postId", "post_tags.postId").where("answers.id", answerId).select("tag_experts.entityRef");
|
|
1881
|
-
return [...new Set(rows.map((r) => r.entityRef))];
|
|
1882
|
-
}
|
|
1883
|
-
getAnswerBaseQuery() {
|
|
1884
|
-
const postRef = this.db.ref("answers.id");
|
|
1885
|
-
const score = this.db("answer_votes").where("answer_votes.answerId", postRef).sum("score").as("score");
|
|
1886
|
-
return this.db("answers").leftJoin("answer_votes", "answers.id", "answer_votes.answerId").select("answers.*", score).groupBy("answers.id");
|
|
1887
|
-
}
|
|
1888
|
-
async getPostAnswers(postId, user_ref, options) {
|
|
1889
|
-
const { includeStatusFilter = true } = options ?? {};
|
|
1890
|
-
const query = this.getAnswerBaseQuery().where("postId", "=", postId).orderBy("answers.correct", "desc").orderBy("answers.created");
|
|
1891
|
-
if (includeStatusFilter) {
|
|
1892
|
-
query.where("answers.status", "=", "active");
|
|
1893
|
-
}
|
|
1894
|
-
if (options?.filter) {
|
|
1895
|
-
parseFilter(options.filter, query, this.db, "answer");
|
|
1896
|
-
}
|
|
1897
|
-
const rows = await query.select();
|
|
1898
|
-
return await Promise.all(
|
|
1899
|
-
rows.map(async (val) => {
|
|
1900
|
-
return this.mapAnswer(val, user_ref, options);
|
|
1901
|
-
})
|
|
1902
|
-
);
|
|
1903
|
-
}
|
|
1904
|
-
async recordPostView(postId, user_ref) {
|
|
1905
|
-
await this.db.insert({
|
|
1906
|
-
author: user_ref,
|
|
1907
|
-
postId,
|
|
1908
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
1909
|
-
}).into("post_views");
|
|
1910
|
-
}
|
|
1911
|
-
getPostsBaseQuery(user, opts) {
|
|
1912
|
-
const { includeStatusFilter = true } = opts ?? {};
|
|
1913
|
-
const postRef = this.db.ref("posts.id");
|
|
1914
|
-
const score = this.db("post_votes").where("post_votes.postId", postRef).sum("score").as("score");
|
|
1915
|
-
const views = this.db("post_views").where("post_views.postId", postRef).count("*").as("views");
|
|
1916
|
-
const answersCount = this.db("answers").where("answers.postId", postRef).count("*").as("answersCount");
|
|
1917
|
-
if (includeStatusFilter) {
|
|
1918
|
-
answersCount.where("answers.status", "=", "active");
|
|
1919
|
-
}
|
|
1920
|
-
const correctAnswers = this.db("answers").where("answers.postId", postRef).where("answers.correct", "=", true).count("*").as("correctAnswers");
|
|
1921
|
-
if (includeStatusFilter) {
|
|
1922
|
-
correctAnswers.where("answers.status", "=", "active");
|
|
1923
|
-
}
|
|
1924
|
-
const commentsCount = this.db("comments").where("comments.postId", postRef).count("*").as("commentsCount");
|
|
1925
|
-
const favorite = this.db("user_favorite").where("user_favorite.user", "=", user).where("user_favorite.postId", postRef).count("*").as("favorite");
|
|
1926
|
-
return this.db("posts").select(
|
|
1927
|
-
"posts.*",
|
|
1928
|
-
score,
|
|
1929
|
-
views,
|
|
1930
|
-
answersCount,
|
|
1931
|
-
correctAnswers,
|
|
1932
|
-
commentsCount,
|
|
1933
|
-
favorite
|
|
1934
|
-
).leftJoin("post_votes", "posts.id", "post_votes.postId").leftJoin("post_views", "posts.id", "post_views.postId").leftJoin("answers", "posts.id", "answers.postId").leftJoin("comments", "posts.id", "comments.postId").leftJoin("user_favorite", "posts.id", "user_favorite.postId").groupBy("posts.id");
|
|
1935
|
-
}
|
|
1936
|
-
getCollectionsBaseQuery() {
|
|
1937
|
-
const collectionRef = this.db.ref("collections.id");
|
|
1938
|
-
const postsCount = this.db("collection_posts").leftJoin("posts", "collection_posts.postId", "posts.id").where("collection_posts.collectionId", collectionRef).where("posts.status", "=", "active").count("*").as("postsCount");
|
|
1939
|
-
return this.db("collections").select("collections.*", postsCount).leftJoin(
|
|
1940
|
-
"collection_posts",
|
|
1941
|
-
"collections.id",
|
|
1942
|
-
"collection_posts.collectionId"
|
|
1943
|
-
).leftJoin("posts", "collection_posts.postId", "posts.id").groupBy("collections.id");
|
|
1944
|
-
}
|
|
1945
|
-
async addTags(id, tagsInput, removeOld, tableName = "post_tags", columnName = "postId") {
|
|
1946
|
-
const tags = backstagePluginQetaCommon.filterTags(tagsInput);
|
|
1947
|
-
if (removeOld) {
|
|
1948
|
-
await this.db(tableName).where(columnName, "=", id).delete();
|
|
1949
|
-
}
|
|
1950
|
-
if (!tags || tags.length === 0) {
|
|
1951
|
-
return;
|
|
1952
|
-
}
|
|
1953
|
-
const existingTags = await this.db("tags").whereIn("tag", tags).returning("id").select();
|
|
1954
|
-
const newTags = tags.filter((t) => !existingTags.some((e) => e.tag === t));
|
|
1955
|
-
const allTags = {
|
|
1956
|
-
...tagDb.TAGS,
|
|
1957
|
-
...await this.tagDatabase?.getTags()
|
|
1958
|
-
};
|
|
1959
|
-
const tagIds = (await Promise.all(
|
|
1960
|
-
[...new Set(newTags)].map(async (tag) => {
|
|
1961
|
-
const trimmed = tag.trim();
|
|
1962
|
-
const description = trimmed in allTags ? allTags[trimmed] : void 0;
|
|
1963
|
-
return this.db.insert({ tag: trimmed, description }).into("tags").returning("id").onConflict("tag").ignore();
|
|
1964
|
-
})
|
|
1965
|
-
)).flat().map((tag) => tag.id).concat(existingTags.map((t) => t.id));
|
|
1966
|
-
await Promise.all(
|
|
1967
|
-
tagIds.map(async (tagId) => {
|
|
1968
|
-
await this.db.insert({ [columnName]: id, tagId }).into(tableName).onConflict().ignore();
|
|
1969
|
-
})
|
|
1970
|
-
);
|
|
1971
|
-
}
|
|
1972
|
-
async addEntities(id, entitiesInput, removeOld, tableName = "post_entities", columnName = "postId") {
|
|
1973
|
-
if (removeOld) {
|
|
1974
|
-
await this.db(tableName).where(columnName, "=", id).delete();
|
|
1975
|
-
}
|
|
1976
|
-
const regex = /\w+:\w+\/\w+/g;
|
|
1977
|
-
const entities = entitiesInput?.filter((input) => input.match(regex));
|
|
1978
|
-
if (!entities || entities.length === 0) {
|
|
1979
|
-
return;
|
|
1980
|
-
}
|
|
1981
|
-
const existingEntities = await this.db("entities").whereIn("entity_ref", entities).returning("id").select();
|
|
1982
|
-
const newEntities = entities.filter(
|
|
1983
|
-
(t) => !existingEntities.some((e) => e.entity_ref === t)
|
|
1984
|
-
);
|
|
1985
|
-
const entityIds = (await Promise.all(
|
|
1986
|
-
[...new Set(newEntities)].map(
|
|
1987
|
-
async (entity) => await this.db.insert({ entity_ref: entity }).into("entities").returning("id").onConflict("entity_ref").ignore()
|
|
1988
|
-
)
|
|
1989
|
-
)).flat().map((entity) => entity.id).concat(existingEntities.map((c) => c.id));
|
|
1990
|
-
await Promise.all(
|
|
1991
|
-
entityIds.map(async (entityId) => {
|
|
1992
|
-
await this.db.insert({ [columnName]: id, entityId }).into(tableName).onConflict().ignore();
|
|
1993
|
-
})
|
|
1994
|
-
);
|
|
1995
|
-
}
|
|
1996
|
-
async markAnswer(postId, answerId, correct) {
|
|
1997
|
-
if (correct) {
|
|
1998
|
-
const exists = await this.db("answers").select("id").where("correct", "=", true).where("postId", "=", postId);
|
|
1999
|
-
if (exists && exists.length > 0) {
|
|
2000
|
-
return false;
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
|
-
const query = this.db("answers").onConflict().ignore().where("answers.id", "=", answerId).where("postId", "=", postId);
|
|
2004
|
-
const ret = await query.update({ correct }, ["id"]);
|
|
2005
|
-
return ret !== void 0 && ret?.length > 0;
|
|
447
|
+
async getComments(options, opts) {
|
|
448
|
+
return this.commentsStore.getComments(options, opts);
|
|
2006
449
|
}
|
|
2007
|
-
async
|
|
2008
|
-
|
|
2009
|
-
await this.db("attachments").whereIn("id", images).update({ [key]: id });
|
|
2010
|
-
}
|
|
2011
|
-
const attachments = await this.db("attachments").where(key, id).select("uuid");
|
|
2012
|
-
const uuids = attachments.map((a) => a.uuid);
|
|
2013
|
-
const toRemove = uuids.filter((uuid) => {
|
|
2014
|
-
return !(content.includes(uuid) || headerImage?.includes(uuid));
|
|
2015
|
-
});
|
|
2016
|
-
await this.db("attachments").whereIn("uuid", toRemove).update({ [key]: null });
|
|
2017
|
-
}
|
|
2018
|
-
applySearchQuery(query, columns, searchQuery) {
|
|
2019
|
-
if (this.db.client.config.client === "pg") {
|
|
2020
|
-
query.whereRaw(
|
|
2021
|
-
`((to_tsvector(CONCAT(${columns.join(
|
|
2022
|
-
","
|
|
2023
|
-
)})) @@ to_tsquery(quote_literal(?) || ':*')))`,
|
|
2024
|
-
[`${searchQuery}`]
|
|
2025
|
-
);
|
|
2026
|
-
} else {
|
|
2027
|
-
query.whereRaw(`LOWER(CONCAT(${columns.join(",")})) LIKE LOWER(?)`, [
|
|
2028
|
-
`%${searchQuery}%`
|
|
2029
|
-
]);
|
|
2030
|
-
}
|
|
450
|
+
async getComment(commentId, opts) {
|
|
451
|
+
return this.commentsStore.getComment(commentId, opts);
|
|
2031
452
|
}
|
|
2032
453
|
}
|
|
2033
454
|
|