diff --git a/__tests__/__snapshots__/settings.ts.snap b/__tests__/__snapshots__/settings.ts.snap index 8bb8f5e34f..d3fc7f9470 100644 --- a/__tests__/__snapshots__/settings.ts.snap +++ b/__tests__/__snapshots__/settings.ts.snap @@ -11,6 +11,7 @@ Object { "flags": Object { "clickbaitShieldEnabled": null, "defaultWriteTab": null, + "highlightsFirstEnabled": null, "sidebarBookmarksExpanded": null, "sidebarCustomFeedsExpanded": null, "sidebarOtherExpanded": null, @@ -48,6 +49,7 @@ Object { "flags": Object { "clickbaitShieldEnabled": null, "defaultWriteTab": null, + "highlightsFirstEnabled": null, "sidebarBookmarksExpanded": null, "sidebarCustomFeedsExpanded": null, "sidebarOtherExpanded": null, @@ -87,6 +89,7 @@ Object { "flags": Object { "clickbaitShieldEnabled": null, "defaultWriteTab": null, + "highlightsFirstEnabled": null, "sidebarBookmarksExpanded": null, "sidebarCustomFeedsExpanded": null, "sidebarOtherExpanded": null, @@ -126,6 +129,7 @@ Object { "flags": Object { "clickbaitShieldEnabled": null, "defaultWriteTab": null, + "highlightsFirstEnabled": null, "sidebarBookmarksExpanded": null, "sidebarCustomFeedsExpanded": null, "sidebarOtherExpanded": null, diff --git a/__tests__/integrations/feed.ts b/__tests__/integrations/feed.ts index 4efe6682dc..78e83305d6 100644 --- a/__tests__/integrations/feed.ts +++ b/__tests__/integrations/feed.ts @@ -27,6 +27,7 @@ import { Keyword, PostType, postTypes, + Settings, Source, SourceMember, User, @@ -772,6 +773,44 @@ describe('FeedPreferencesConfigGenerator', () => { expect(actual.config.experience_level).toBe('MORE_THAN_6_YEARS'); expect(actual.config.country).toBe('US'); }); + + it('should set highlights_first when user enabled it in settings', async () => { + await con.getRepository(Settings).save({ + userId: '1', + flags: { highlightsFirstEnabled: true }, + }); + + const generator: FeedConfigGenerator = new FeedPreferencesConfigGenerator( + config, + ); + + const actual = await generator.generate(ctx, { + user_id: '1', + page_size: 2, + offset: 3, + }); + + expect(actual.config.highlights_first).toBe(true); + }); + + it('should not set highlights_first when setting is disabled', async () => { + await con.getRepository(Settings).save({ + userId: '1', + flags: { highlightsFirstEnabled: false }, + }); + + const generator: FeedConfigGenerator = new FeedPreferencesConfigGenerator( + config, + ); + + const actual = await generator.generate(ctx, { + user_id: '1', + page_size: 2, + offset: 3, + }); + + expect(actual.config.highlights_first).toBeUndefined(); + }); }); describe('FeedLofnConfigGenerator', () => { diff --git a/__tests__/settings.ts b/__tests__/settings.ts index 3c3c0da1b6..848771e4b3 100644 --- a/__tests__/settings.ts +++ b/__tests__/settings.ts @@ -121,6 +121,7 @@ describe('mutation updateUserSettings', () => { sidebarSquadExpanded sidebarBookmarksExpanded clickbaitShieldEnabled + highlightsFirstEnabled defaultWriteTab } } @@ -157,6 +158,7 @@ describe('mutation updateUserSettings', () => { sidebarSquadExpanded: null, sidebarBookmarksExpanded: null, clickbaitShieldEnabled: null, + highlightsFirstEnabled: null, defaultWriteTab: null, }); }); @@ -176,6 +178,7 @@ describe('mutation updateUserSettings', () => { sidebarSquadExpanded: null, sidebarBookmarksExpanded: null, clickbaitShieldEnabled: null, + highlightsFirstEnabled: null, defaultWriteTab: null, }); @@ -312,10 +315,27 @@ describe('mutation updateUserSettings', () => { sidebarSquadExpanded: null, sidebarBookmarksExpanded: null, clickbaitShieldEnabled: null, + highlightsFirstEnabled: null, defaultWriteTab: null, }); }); + it('should persist highlightsFirstEnabled in user settings flags', async () => { + loggedUser = '1'; + + const repo = con.getRepository(Settings); + await repo.save(repo.create({ userId: '1' })); + + const res = await client.mutate(MUTATION, { + variables: { data: { flags: { highlightsFirstEnabled: true } } }, + }); + + expect(res.data.updateUserSettings.flags.highlightsFirstEnabled).toBe(true); + + const updated = await repo.findOneByOrFail({ userId: '1' }); + expect(updated.flags.highlightsFirstEnabled).toBe(true); + }); + it('should update but not remove user settings flags', async () => { loggedUser = '1'; @@ -347,6 +367,7 @@ describe('mutation updateUserSettings', () => { sidebarSquadExpanded: null, sidebarBookmarksExpanded: null, clickbaitShieldEnabled: null, + highlightsFirstEnabled: null, defaultWriteTab: null, }); }); diff --git a/src/entity/Settings.ts b/src/entity/Settings.ts index 1d5edec37c..3bded1c8e5 100644 --- a/src/entity/Settings.ts +++ b/src/entity/Settings.ts @@ -51,6 +51,7 @@ export type SettingsFlags = Partial<{ sidebarBookmarksExpanded: boolean; clickbaitShieldEnabled: boolean; browsingContextEnabled: boolean; + highlightsFirstEnabled: boolean; prompt: object; timezoneMismatchIgnore: string; lastPrompt: string; @@ -71,6 +72,7 @@ export type SettingsFlagsPublic = Pick< | 'sidebarBookmarksExpanded' | 'clickbaitShieldEnabled' | 'browsingContextEnabled' + | 'highlightsFirstEnabled' | 'prompt' | 'timezoneMismatchIgnore' | 'lastPrompt' diff --git a/src/integrations/feed/configs.ts b/src/integrations/feed/configs.ts index a7fcb40afd..28960eb0fc 100644 --- a/src/integrations/feed/configs.ts +++ b/src/integrations/feed/configs.ts @@ -7,7 +7,7 @@ import { FeedVersion, } from './types'; import { AnonymousFeedFilters, feedToFilters } from '../../common'; -import { postTypes } from '../../entity'; +import { postTypes, Settings } from '../../entity'; import { User } from '../../entity/user/User'; import { runInSpan } from '../../telemetry'; import { ILofnClient } from '../lofn'; @@ -215,7 +215,7 @@ export class FeedPreferencesConfigGenerator implements FeedConfigGenerator { const userId = opts.user_id; const feedId = this.opts.feedId || userId; - const [filters, user] = await Promise.all([ + const [filters, user, settings] = await Promise.all([ feedToFilters(ctx.con, feedId, userId), userId ? ctx.con.getRepository(User).findOne({ @@ -223,6 +223,12 @@ export class FeedPreferencesConfigGenerator implements FeedConfigGenerator { where: { id: userId }, }) : null, + userId + ? ctx.con.getRepository(Settings).findOne({ + select: ['userId', 'flags'], + where: { userId }, + }) + : null, ]); const config = addFiltersToConfig({ @@ -237,6 +243,9 @@ export class FeedPreferencesConfigGenerator implements FeedConfigGenerator { if (user?.flags?.country) { config.country = user.flags.country; } + if (settings?.flags?.highlightsFirstEnabled) { + config.highlights_first = true; + } return { config }; }); diff --git a/src/integrations/feed/types.ts b/src/integrations/feed/types.ts index 3400c67ecb..9db26c66e4 100644 --- a/src/integrations/feed/types.ts +++ b/src/integrations/feed/types.ts @@ -84,6 +84,7 @@ export type FeedConfig = { blocked_sources?: string[]; allowed_post_types?: string[]; highlights_limit?: number; + highlights_first?: boolean; allowed_content_curations?: string[]; blocked_title_words?: string[]; allowed_author_ids?: string[]; diff --git a/src/schema/settings.ts b/src/schema/settings.ts index 64c988e1f3..8bd8a3596d 100644 --- a/src/schema/settings.ts +++ b/src/schema/settings.ts @@ -77,6 +77,7 @@ export const typeDefs = /* GraphQL */ ` sidebarBookmarksExpanded: Boolean clickbaitShieldEnabled: Boolean browsingContextEnabled: Boolean + highlightsFirstEnabled: Boolean timezoneMismatchIgnore: String lastPrompt: String defaultWriteTab: DefaultWriteTab @@ -95,6 +96,7 @@ export const typeDefs = /* GraphQL */ ` sidebarBookmarksExpanded: Boolean clickbaitShieldEnabled: Boolean browsingContextEnabled: Boolean + highlightsFirstEnabled: Boolean prompt: JSONObject timezoneMismatchIgnore: String lastPrompt: String