diff --git a/server/entity/UserSettings.ts b/server/entity/UserSettings.ts index fb738c59..a3e6c7aa 100644 --- a/server/entity/UserSettings.ts +++ b/server/entity/UserSettings.ts @@ -57,6 +57,9 @@ export class UserSettings { @Column({ nullable: true }) public telegramSendSilently?: boolean; + @Column({ nullable: true }) + public watchlistSync?: boolean; + @Column({ type: 'text', nullable: true, diff --git a/server/interfaces/api/userSettingsInterfaces.ts b/server/interfaces/api/userSettingsInterfaces.ts index de7888b2..9f8aa0ba 100644 --- a/server/interfaces/api/userSettingsInterfaces.ts +++ b/server/interfaces/api/userSettingsInterfaces.ts @@ -14,6 +14,7 @@ export interface UserSettingsGeneralResponse { globalMovieQuotaLimit?: number; globalTvQuotaLimit?: number; globalTvQuotaDays?: number; + watchlistSync?: boolean; } export type NotificationAgentTypes = Record; diff --git a/server/lib/watchlistsync.ts b/server/lib/watchlistsync.ts index e5e02082..3f74f427 100644 --- a/server/lib/watchlistsync.ts +++ b/server/lib/watchlistsync.ts @@ -30,13 +30,18 @@ class WatchlistSync { private async syncUserWatchlist(user: User) { if (!user.plexToken) { - logger.debug('Skipping user watchlist sync for user without plex token', { + logger.warn('Skipping user watchlist sync for user without plex token', { label: 'Plex Watchlist Sync', userId: user.id, }); return; } + // Skip sync if user settings have it disabled + if (!user.settings?.watchlistSync) { + return; + } + const plexTvApi = new PlexTvAPI(user.plexToken); const response = await plexTvApi.getWatchlist({ size: 200 }); diff --git a/server/migration/1660627491586-AddWatchlistSyncUserSetting.ts b/server/migration/1660627491586-AddWatchlistSyncUserSetting.ts new file mode 100644 index 00000000..2067d189 --- /dev/null +++ b/server/migration/1660627491586-AddWatchlistSyncUserSetting.ts @@ -0,0 +1,33 @@ +import type { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddWatchlistSyncUserSetting1660627491586 + implements MigrationInterface +{ + name = 'AddWatchlistSyncUserSetting1660627491586'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "temporary_user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSync" boolean, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ); + await queryRunner.query( + `INSERT INTO "temporary_user_settings"("id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey") SELECT "id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey" FROM "user_settings"` + ); + await queryRunner.query(`DROP TABLE "user_settings"`); + await queryRunner.query( + `ALTER TABLE "temporary_user_settings" RENAME TO "user_settings"` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "user_settings" RENAME TO "temporary_user_settings"` + ); + await queryRunner.query( + `CREATE TABLE "user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ); + await queryRunner.query( + `INSERT INTO "user_settings"("id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey") SELECT "id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey" FROM "temporary_user_settings"` + ); + await queryRunner.query(`DROP TABLE "temporary_user_settings"`); + } +} diff --git a/server/routes/user/usersettings.ts b/server/routes/user/usersettings.ts index 84d95b39..2e5af2f7 100644 --- a/server/routes/user/usersettings.ts +++ b/server/routes/user/usersettings.ts @@ -63,6 +63,7 @@ userSettingsRoutes.get<{ id: string }, UserSettingsGeneralResponse>( globalMovieQuotaLimit: defaultQuotas.movie.quotaLimit, globalTvQuotaDays: defaultQuotas.tv.quotaDays, globalTvQuotaLimit: defaultQuotas.tv.quotaLimit, + watchlistSync: user.settings?.watchlistSync, }); } catch (e) { next({ status: 500, message: e.message }); @@ -114,12 +115,14 @@ userSettingsRoutes.post< locale: req.body.locale, region: req.body.region, originalLanguage: req.body.originalLanguage, + watchlistSync: req.body.watchlistSync, }); } else { user.settings.discordId = req.body.discordId; user.settings.locale = req.body.locale; user.settings.region = req.body.region; user.settings.originalLanguage = req.body.originalLanguage; + user.settings.watchlistSync = req.body.watchlistSync; } await userRepository.save(user); @@ -130,6 +133,7 @@ userSettingsRoutes.post< locale: user.settings.locale, region: user.settings.region, originalLanguage: user.settings.originalLanguage, + watchlistSync: user.settings.watchlistSync, }); } catch (e) { next({ status: 500, message: e.message }); diff --git a/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx b/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx index dd348ce7..1bcc998b 100644 --- a/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx +++ b/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx @@ -49,6 +49,8 @@ const messages = defineMessages({ discordIdTip: 'The multi-digit ID number associated with your Discord user account', validationDiscordId: 'You must provide a valid Discord user ID', + plexwatchlistsync: 'Plex Watchlist Auto-Request', + plexwatchlistsynctip: 'Automatically request Plex watchlist items.', }); const UserGeneralSettings = () => { @@ -122,6 +124,7 @@ const UserGeneralSettings = () => { movieQuotaDays: data?.movieQuotaDays, tvQuotaLimit: data?.tvQuotaLimit, tvQuotaDays: data?.tvQuotaDays, + watchlistSync: false, }} validationSchema={UserGeneralSettingsSchema} enableReinitialize @@ -409,6 +412,24 @@ const UserGeneralSettings = () => { )} +
+ +
+ { + setFieldValue('watchlistSync', !values.watchlistSync); + }} + /> +
+