diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/config.ts | 18 | ||||
-rw-r--r-- | server/helpers/audit-logger.ts | 1 | ||||
-rw-r--r-- | server/initializers/config.ts | 10 | ||||
-rw-r--r-- | server/middlewares/validators/config.ts | 3 | ||||
-rw-r--r-- | server/models/video/video-query-builder.ts | 95 | ||||
-rw-r--r-- | server/tests/api/check-params/config.ts | 10 | ||||
-rw-r--r-- | server/tests/api/server/config.ts | 10 | ||||
-rw-r--r-- | server/tests/client.ts | 2 |
8 files changed, 87 insertions, 62 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 44f3d3ef7..24e7601ec 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -65,9 +65,15 @@ async function getConfig (req: express.Request, res: express.Response) { | |||
65 | instance: { | 65 | instance: { |
66 | name: CONFIG.INSTANCE.NAME, | 66 | name: CONFIG.INSTANCE.NAME, |
67 | shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, | 67 | shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, |
68 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, | ||
69 | isNSFW: CONFIG.INSTANCE.IS_NSFW, | 68 | isNSFW: CONFIG.INSTANCE.IS_NSFW, |
70 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | 69 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
70 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, | ||
71 | defaultTrendingRoute: CONFIG.INSTANCE.DEFAULT_TRENDING_ROUTE, | ||
72 | pages: { | ||
73 | hot: { | ||
74 | enabled: CONFIG.INSTANCE.PAGES.HOT.ENABLED | ||
75 | } | ||
76 | }, | ||
71 | customizations: { | 77 | customizations: { |
72 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT, | 78 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT, |
73 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS | 79 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS |
@@ -362,8 +368,16 @@ function customConfig (): CustomConfig { | |||
362 | categories: CONFIG.INSTANCE.CATEGORIES, | 368 | categories: CONFIG.INSTANCE.CATEGORIES, |
363 | 369 | ||
364 | isNSFW: CONFIG.INSTANCE.IS_NSFW, | 370 | isNSFW: CONFIG.INSTANCE.IS_NSFW, |
365 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, | ||
366 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | 371 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
372 | |||
373 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, | ||
374 | defaultTrendingRoute: CONFIG.INSTANCE.DEFAULT_TRENDING_ROUTE, | ||
375 | pages: { | ||
376 | hot: { | ||
377 | enabled: CONFIG.INSTANCE.PAGES.HOT.ENABLED | ||
378 | } | ||
379 | }, | ||
380 | |||
367 | customizations: { | 381 | customizations: { |
368 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS, | 382 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS, |
369 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT | 383 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT |
diff --git a/server/helpers/audit-logger.ts b/server/helpers/audit-logger.ts index 6aae5e821..e474959b2 100644 --- a/server/helpers/audit-logger.ts +++ b/server/helpers/audit-logger.ts | |||
@@ -230,6 +230,7 @@ const customConfigKeysToKeep = [ | |||
230 | 'instance-description', | 230 | 'instance-description', |
231 | 'instance-terms', | 231 | 'instance-terms', |
232 | 'instance-defaultClientRoute', | 232 | 'instance-defaultClientRoute', |
233 | 'instance-defaultTrendingRoute', | ||
233 | 'instance-defaultNSFWPolicy', | 234 | 'instance-defaultNSFWPolicy', |
234 | 'instance-customizations-javascript', | 235 | 'instance-customizations-javascript', |
235 | 'instance-customizations-css', | 236 | 'instance-customizations-css', |
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index c7ef9b497..e1f807752 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -278,8 +278,16 @@ const CONFIG = { | |||
278 | get CATEGORIES () { return config.get<number[]>('instance.categories') || [] }, | 278 | get CATEGORIES () { return config.get<number[]>('instance.categories') || [] }, |
279 | 279 | ||
280 | get IS_NSFW () { return config.get<boolean>('instance.is_nsfw') }, | 280 | get IS_NSFW () { return config.get<boolean>('instance.is_nsfw') }, |
281 | get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') }, | ||
282 | get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') }, | 281 | get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') }, |
282 | |||
283 | get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') }, | ||
284 | get DEFAULT_TRENDING_ROUTE () { return config.get<string>('instance.default_trending_route') }, | ||
285 | PAGES: { | ||
286 | HOT: { | ||
287 | get ENABLED () { return config.get<boolean>('instance.pages.hot.enabled') } | ||
288 | } | ||
289 | }, | ||
290 | |||
283 | CUSTOMIZATIONS: { | 291 | CUSTOMIZATIONS: { |
284 | get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') }, | 292 | get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') }, |
285 | get CSS () { return config.get<string>('instance.customizations.css') } | 293 | get CSS () { return config.get<string>('instance.customizations.css') } |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index faabf17d7..0efe1157f 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -15,8 +15,9 @@ const customConfigUpdateValidator = [ | |||
15 | body('instance.shortDescription').exists().withMessage('Should have a valid instance short description'), | 15 | body('instance.shortDescription').exists().withMessage('Should have a valid instance short description'), |
16 | body('instance.description').exists().withMessage('Should have a valid instance description'), | 16 | body('instance.description').exists().withMessage('Should have a valid instance description'), |
17 | body('instance.terms').exists().withMessage('Should have a valid instance terms'), | 17 | body('instance.terms').exists().withMessage('Should have a valid instance terms'), |
18 | body('instance.defaultClientRoute').exists().withMessage('Should have a valid instance default client route'), | ||
19 | body('instance.defaultNSFWPolicy').custom(isUserNSFWPolicyValid).withMessage('Should have a valid NSFW policy'), | 18 | body('instance.defaultNSFWPolicy').custom(isUserNSFWPolicyValid).withMessage('Should have a valid NSFW policy'), |
19 | body('instance.defaultClientRoute').exists().withMessage('Should have a valid instance default client route'), | ||
20 | body('instance.defaultTrendingRoute').exists().withMessage('Should have a valid instance default trending route'), | ||
20 | body('instance.customizations.css').exists().withMessage('Should have a valid instance CSS customization'), | 21 | body('instance.customizations.css').exists().withMessage('Should have a valid instance CSS customization'), |
21 | body('instance.customizations.javascript').exists().withMessage('Should have a valid instance JavaScript customization'), | 22 | body('instance.customizations.javascript').exists().withMessage('Should have a valid instance JavaScript customization'), |
22 | 23 | ||
diff --git a/server/models/video/video-query-builder.ts b/server/models/video/video-query-builder.ts index 8e0965244..3f31ac862 100644 --- a/server/models/video/video-query-builder.ts +++ b/server/models/video/video-query-builder.ts | |||
@@ -242,64 +242,49 @@ function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions) | |||
242 | } | 242 | } |
243 | 243 | ||
244 | // We don't exclude results in this so if we do a count we don't need to add this complex clause | 244 | // We don't exclude results in this so if we do a count we don't need to add this complex clause |
245 | if (options.trendingDays && options.isCount !== true) { | 245 | if (options.isCount !== true) { |
246 | const viewsGteDate = new Date(new Date().getTime() - (24 * 3600 * 1000) * options.trendingDays) | 246 | if (options.trendingDays) { |
247 | 247 | const viewsGteDate = new Date(new Date().getTime() - (24 * 3600 * 1000) * options.trendingDays) | |
248 | joins.push('LEFT JOIN "videoView" ON "video"."id" = "videoView"."videoId" AND "videoView"."startDate" >= :viewsGteDate') | 248 | |
249 | replacements.viewsGteDate = viewsGteDate | 249 | joins.push('LEFT JOIN "videoView" ON "video"."id" = "videoView"."videoId" AND "videoView"."startDate" >= :viewsGteDate') |
250 | 250 | replacements.viewsGteDate = viewsGteDate | |
251 | attributes.push('COALESCE(SUM("videoView"."views"), 0) AS "score"') | 251 | |
252 | 252 | attributes.push('COALESCE(SUM("videoView"."views"), 0) AS "score"') | |
253 | group = 'GROUP BY "video"."id"' | 253 | |
254 | } else if (options.hot && options.isCount !== true) { | 254 | group = 'GROUP BY "video"."id"' |
255 | /** | 255 | } else if (options.hot) { |
256 | * "Hotness" is a measure based on absolute view/comment/like/dislike numbers, | 256 | /** |
257 | * with fixed weights only applied to their log values. | 257 | * "Hotness" is a measure based on absolute view/comment/like/dislike numbers, |
258 | * | 258 | * with fixed weights only applied to their log values. |
259 | * This algorithm gives little chance for an old video to have a good score, | 259 | * |
260 | * for which recent spikes in interactions could be a sign of "hotness" and | 260 | * This algorithm gives little chance for an old video to have a good score, |
261 | * justify a better score. However there are multiple ways to achieve that | 261 | * for which recent spikes in interactions could be a sign of "hotness" and |
262 | * goal, which is left for later. Yes, this is a TODO :) | 262 | * justify a better score. However there are multiple ways to achieve that |
263 | * | 263 | * goal, which is left for later. Yes, this is a TODO :) |
264 | * note: weights and base score are in number of half-days. | 264 | * |
265 | * see https://github.com/reddit-archive/reddit/blob/master/r2/r2/lib/db/_sorts.pyx#L47-L58 | 265 | * note: weights and base score are in number of half-days. |
266 | */ | 266 | * see https://github.com/reddit-archive/reddit/blob/master/r2/r2/lib/db/_sorts.pyx#L47-L58 |
267 | const weights = { | 267 | */ |
268 | like: 3, | 268 | const weights = { |
269 | dislike: 3, | 269 | like: 3, |
270 | view: 1 / 12, | 270 | dislike: 3, |
271 | comment: 2 // a comment takes more time than a like to do, but can be done multiple times | 271 | view: 1 / 12, |
272 | } | 272 | comment: 2 // a comment takes more time than a like to do, but can be done multiple times |
273 | 273 | } | |
274 | cte.push( // TODO: exclude blocklisted comments | ||
275 | '"totalCommentsWithoutVideoAuthor" AS (' + | ||
276 | 'SELECT "video"."id", ' + | ||
277 | 'COUNT("replies"."id") - (' + | ||
278 | 'SELECT COUNT("authorReplies"."id") ' + | ||
279 | 'FROM "videoComment" AS "authorReplies" ' + | ||
280 | 'LEFT JOIN "account" ON "account"."id" = "authorReplies"."accountId" ' + | ||
281 | 'LEFT JOIN "videoChannel" ON "videoChannel"."accountId" = "account"."id" ' + | ||
282 | 'WHERE "video"."channelId" = "videoChannel"."id" ' + | ||
283 | ') as "value" ' + | ||
284 | 'FROM "videoComment" AS "replies" ' + | ||
285 | 'LEFT JOIN "video" ON "video"."id" = "replies"."videoId" ' + | ||
286 | 'WHERE "replies"."videoId" = "video"."id" ' + | ||
287 | 'GROUP BY "video"."id"' + | ||
288 | ')' | ||
289 | ) | ||
290 | 274 | ||
291 | joins.push('LEFT JOIN "totalCommentsWithoutVideoAuthor" ON "video"."id" = "totalCommentsWithoutVideoAuthor"."id"') | 275 | joins.push('LEFT JOIN "videoComment" ON "video"."id" = "videoComment"."videoId"') |
292 | 276 | ||
293 | attributes.push( | 277 | attributes.push( |
294 | `LOG(GREATEST(1, "video"."likes" - 1)) * ${weights.like} ` + // likes (+) | 278 | `LOG(GREATEST(1, "video"."likes" - 1)) * ${weights.like} ` + // likes (+) |
295 | `- LOG(GREATEST(1, "video"."dislikes" - 1)) * ${weights.dislike} ` + // dislikes (-) | 279 | `- LOG(GREATEST(1, "video"."dislikes" - 1)) * ${weights.dislike} ` + // dislikes (-) |
296 | `+ LOG("video"."views" + 1) * ${weights.view} ` + // views (+) | 280 | `+ LOG("video"."views" + 1) * ${weights.view} ` + // views (+) |
297 | `+ LOG(GREATEST(1, "totalCommentsWithoutVideoAuthor"."value")) * ${weights.comment} ` + // comments (+) | 281 | `+ LOG(GREATEST(1, COUNT(DISTINCT "videoComment"."id"))) * ${weights.comment} ` + // comments (+) |
298 | '+ (SELECT EXTRACT(epoch FROM "video"."publishedAt") / 47000) ' + // base score (in number of half-days) | 282 | '+ (SELECT EXTRACT(epoch FROM "video"."publishedAt") / 47000) ' + // base score (in number of half-days) |
299 | 'AS "score"' | 283 | 'AS "score"' |
300 | ) | 284 | ) |
301 | 285 | ||
302 | group = 'GROUP BY "video"."id", "totalCommentsWithoutVideoAuthor"."value"' | 286 | group = 'GROUP BY "video"."id"' |
287 | } | ||
303 | } | 288 | } |
304 | 289 | ||
305 | if (options.historyOfUser) { | 290 | if (options.historyOfUser) { |
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index e36cdeab2..e58e0cd9f 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -41,8 +41,16 @@ describe('Test config API validators', function () { | |||
41 | categories: [ 1, 2 ], | 41 | categories: [ 1, 2 ], |
42 | 42 | ||
43 | isNSFW: true, | 43 | isNSFW: true, |
44 | defaultClientRoute: '/videos/recently-added', | ||
45 | defaultNSFWPolicy: 'blur', | 44 | defaultNSFWPolicy: 'blur', |
45 | |||
46 | defaultClientRoute: '/videos/recently-added', | ||
47 | defaultTrendingRoute: '/videos/trending', | ||
48 | pages: { | ||
49 | hot: { | ||
50 | enabled: true | ||
51 | } | ||
52 | }, | ||
53 | |||
46 | customizations: { | 54 | customizations: { |
47 | javascript: 'alert("coucou")', | 55 | javascript: 'alert("coucou")', |
48 | css: 'body { background-color: red; }' | 56 | css: 'body { background-color: red; }' |
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index af25f4800..328f4852a 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -272,9 +272,17 @@ describe('Test config', function () { | |||
272 | languages: [ 'en', 'es' ], | 272 | languages: [ 'en', 'es' ], |
273 | categories: [ 1, 2 ], | 273 | categories: [ 1, 2 ], |
274 | 274 | ||
275 | defaultClientRoute: '/videos/recently-added', | ||
276 | isNSFW: true, | 275 | isNSFW: true, |
277 | defaultNSFWPolicy: 'blur' as 'blur', | 276 | defaultNSFWPolicy: 'blur' as 'blur', |
277 | |||
278 | defaultClientRoute: '/videos/recently-added', | ||
279 | defaultTrendingRoute: '/videos/trending', | ||
280 | pages: { | ||
281 | hot: { | ||
282 | enabled: true | ||
283 | } | ||
284 | }, | ||
285 | |||
278 | customizations: { | 286 | customizations: { |
279 | javascript: 'alert("coucou")', | 287 | javascript: 'alert("coucou")', |
280 | css: 'body { background-color: red; }' | 288 | css: 'body { background-color: red; }' |
diff --git a/server/tests/client.ts b/server/tests/client.ts index 7572fd34a..d608764ee 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -308,8 +308,8 @@ describe('Test a client controllers', function () { | |||
308 | shortDescription: 'my short description', | 308 | shortDescription: 'my short description', |
309 | description: 'my super description', | 309 | description: 'my super description', |
310 | terms: 'my super terms', | 310 | terms: 'my super terms', |
311 | defaultClientRoute: '/videos/recently-added', | ||
312 | defaultNSFWPolicy: 'blur', | 311 | defaultNSFWPolicy: 'blur', |
312 | defaultClientRoute: '/videos/recently-added', | ||
313 | customizations: { | 313 | customizations: { |
314 | javascript: 'alert("coucou")', | 314 | javascript: 'alert("coucou")', |
315 | css: 'body { background-color: red; }' | 315 | css: 'body { background-color: red; }' |