From 543859e6f3b3a8cd4c61499a74bda610d3217626 Mon Sep 17 00:00:00 2001 From: Nicolai Van der Storm Date: Fri, 10 Jun 2022 12:19:52 +0200 Subject: [PATCH 1/5] feat(uesrprofile): email requirement and validation --- .idea/.gitignore | 8 +++ .idea/codeStyles/Project.xml | 67 +++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 ++ .idea/dataSources.xml | 12 ++++ .idea/git_toolbox_prj.xml | 15 +++++ .idea/jellyseerr.iml | 12 ++++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 ++ package.json | 2 + server/entity/User.ts | 2 + server/lib/settings.ts | 5 ++ server/routes/auth.ts | 11 +++ src/components/Layout/Sidebar/index.tsx | 8 +++ src/components/Layout/UserWarnings/index.tsx | 66 ++++++++++++++++++ src/components/Layout/index.tsx | 1 + .../Notifications/NotificationsEmail.tsx | 15 +++++ .../UserGeneralSettings/index.tsx | 16 +++-- src/hooks/useUser.ts | 1 + tailwind.config.js | 1 + yarn.lock | 12 ++++ 20 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/dataSources.xml create mode 100644 .idea/git_toolbox_prj.xml create mode 100644 .idea/jellyseerr.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 src/components/Layout/UserWarnings/index.tsx diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 000000000..ff5d00b02 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 000000000..79ee123c2 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 000000000..a12bac1c9 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:$PROJECT_DIR$/config/db/db.sqlite3 + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml new file mode 100644 index 000000000..02b915b85 --- /dev/null +++ b/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jellyseerr.iml b/.idea/jellyseerr.iml new file mode 100644 index 000000000..0c8867d7e --- /dev/null +++ b/.idea/jellyseerr.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..bb19e753c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..94a25f7f4 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index a25d16fdc..7d5bb637d 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "country-flag-icons": "^1.4.21", "csurf": "^1.11.0", "email-templates": "^8.0.10", + "email-validator": "^2.0.4", "express": "^4.17.3", "express-openapi-validator": "^4.13.6", "express-rate-limit": "^6.3.0", @@ -84,6 +85,7 @@ "@babel/cli": "^7.17.6", "@commitlint/cli": "^16.2.1", "@commitlint/config-conventional": "^16.2.1", + "@next/eslint-plugin-next": "^12.1.6", "@semantic-release/changelog": "^6.0.1", "@semantic-release/commit-analyzer": "^9.0.2", "@semantic-release/exec": "^6.0.3", diff --git a/server/entity/User.ts b/server/entity/User.ts index 157e7f24f..7fa6dc67d 100644 --- a/server/entity/User.ts +++ b/server/entity/User.ts @@ -137,6 +137,8 @@ export class User { @UpdateDateColumn() public updatedAt: Date; + public warnings: string[] = []; + constructor(init?: Partial) { Object.assign(this, init); } diff --git a/server/lib/settings.ts b/server/lib/settings.ts index 6b167d7c4..953fc3d02 100644 --- a/server/lib/settings.ts +++ b/server/lib/settings.ts @@ -134,6 +134,7 @@ interface FullPublicSettings extends PublicSettings { enablePushRegistration: boolean; locale: string; emailEnabled: boolean; + userEmailRequired: boolean; newPlexLogin: boolean; } @@ -159,6 +160,7 @@ export interface NotificationAgentSlack extends NotificationAgentConfig { export interface NotificationAgentEmail extends NotificationAgentConfig { options: { + userEmailRequired: boolean; emailFrom: string; smtpHost: string; smtpPort: number; @@ -335,6 +337,7 @@ class Settings { email: { enabled: false, options: { + userEmailRequired: false, emailFrom: '', smtpHost: '', smtpPort: 587, @@ -529,6 +532,8 @@ class Settings { enablePushRegistration: this.data.notifications.agents.webpush.enabled, locale: this.data.main.locale, emailEnabled: this.data.notifications.agents.email.enabled, + userEmailRequired: + this.data.notifications.agents.email.options.userEmailRequired, newPlexLogin: this.data.main.newPlexLogin, }; } diff --git a/server/routes/auth.ts b/server/routes/auth.ts index 7c92db627..209451511 100644 --- a/server/routes/auth.ts +++ b/server/routes/auth.ts @@ -9,6 +9,7 @@ import { Permission } from '../lib/permissions'; import { getSettings } from '../lib/settings'; import logger from '../logger'; import { isAuthenticated } from '../middleware/auth'; +import * as EmailValidator from 'email-validator'; const authRoutes = Router(); @@ -24,6 +25,16 @@ authRoutes.get('/me', isAuthenticated(), async (req, res) => { where: { id: req.user.id }, }); + // check if email is required in settings and if user has an valid email + const settings = await getSettings(); + if ( + settings.notifications.agents.email.options.userEmailRequired && + !EmailValidator.validate(user.email) + ) { + user.warnings.push('userEmailRequired'); + logger.warn(`User ${user.username} has no valid email address`); + } + return res.status(200).json(user); }); diff --git a/src/components/Layout/Sidebar/index.tsx b/src/components/Layout/Sidebar/index.tsx index 45716eeb5..821a3d2dc 100644 --- a/src/components/Layout/Sidebar/index.tsx +++ b/src/components/Layout/Sidebar/index.tsx @@ -14,6 +14,7 @@ import useClickOutside from '../../../hooks/useClickOutside'; import { Permission, useUser } from '../../../hooks/useUser'; import Transition from '../../Transition'; import VersionStatus from '../VersionStatus'; +import UserWarnings from '../UserWarnings'; const messages = defineMessages({ dashboard: 'Discover', @@ -177,6 +178,10 @@ const Sidebar: React.FC = ({ open, setClosed }) => { ); })} +
+ setClosed()} /> +
+ {hasPermission(Permission.ADMIN) && (
setClosed()} /> @@ -236,6 +241,9 @@ const Sidebar: React.FC = ({ open, setClosed }) => { ); })} +
+ +
{hasPermission(Permission.ADMIN) && (
diff --git a/src/components/Layout/UserWarnings/index.tsx b/src/components/Layout/UserWarnings/index.tsx new file mode 100644 index 000000000..fe621d2a9 --- /dev/null +++ b/src/components/Layout/UserWarnings/index.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import Link from 'next/link'; +import { ExclamationIcon } from '@heroicons/react/outline'; +import { defineMessages, useIntl } from 'react-intl'; +import { useUser } from '../../../hooks/useUser'; + +const messages = defineMessages({ + emailRequired: 'An email address is required.', + emailInvalid: 'Email address is invalid.', + passwordRequired: 'A password is required.', +}); + +interface UserWarningsProps { + onClick?: () => void; +} + +const UserWarnings: React.FC = ({ onClick }) => { + const intl = useIntl(); + const { user } = useUser(); + if (!user) { + return null; + } + + let res = null; + + //check if a user has warnings + if (user.warnings.length > 0) { + user.warnings.forEach((warning) => { + let link = ''; + let warningText = ''; + let warningTitle = ''; + switch (warning) { + case 'userEmailRequired': + link = '/profile/settings/'; + warningTitle = 'Profile is incomplete'; + warningText = intl.formatMessage(messages.emailRequired); + } + + res = ( + + { + if (e.key === 'Enter' && onClick) { + onClick(); + } + }} + role="button" + tabIndex={0} + className="mx-2 mb-2 flex items-center rounded-lg bg-yellow-500 p-2 text-xs text-white ring-1 ring-gray-700 transition duration-300 hover:bg-yellow-400" + > + +
+ {warningTitle} + {warningText} +
+
+ + ); + }); + } + + return res; +}; + +export default UserWarnings; diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index bde592778..b560c66e8 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -50,6 +50,7 @@ const Layout: React.FC = ({ children }) => {
+ setSidebarOpen(false)} />
diff --git a/src/components/Settings/Notifications/NotificationsEmail.tsx b/src/components/Settings/Notifications/NotificationsEmail.tsx index 403083903..e20a13055 100644 --- a/src/components/Settings/Notifications/NotificationsEmail.tsx +++ b/src/components/Settings/Notifications/NotificationsEmail.tsx @@ -16,6 +16,7 @@ const messages = defineMessages({ validationSmtpHostRequired: 'You must provide a valid hostname or IP address', validationSmtpPortRequired: 'You must provide a valid port number', agentenabled: 'Enable Agent', + userEmailRequired: 'Require user email', emailsender: 'Sender Address', smtpHost: 'SMTP Host', smtpPort: 'SMTP Port', @@ -125,6 +126,7 @@ const NotificationsEmail: React.FC = () => { { await axios.post('/api/v1/settings/notifications/email', { enabled: values.enabled, options: { + userEmailRequired: values.userEmailRequired, emailFrom: values.emailFrom, smtpHost: values.smtpHost, smtpPort: Number(values.smtpPort), @@ -241,6 +244,18 @@ const NotificationsEmail: React.FC = () => {
+
+ +
+ +
+
{
@@ -258,7 +261,12 @@ const UserGeneralSettings: React.FC = () => { id="email" name="email" type="text" - placeholder={user?.email} + placeholder="example@domain.com" + className={ + user?.warnings.find((w) => w === 'userEmailRequired') + ? 'border-2 border-red-400 focus:border-blue-600' + : '' + } />
{errors.email && touched.email && ( diff --git a/src/hooks/useUser.ts b/src/hooks/useUser.ts index 223cea326..4880a6315 100644 --- a/src/hooks/useUser.ts +++ b/src/hooks/useUser.ts @@ -13,6 +13,7 @@ export type { PermissionCheckOptions }; export interface User { id: number; + warnings: string[]; plexUsername?: string; username?: string; displayName: string; diff --git a/tailwind.config.js b/tailwind.config.js index d1d023c01..aeb8b7f4f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -2,6 +2,7 @@ const defaultTheme = require('tailwindcss/defaultTheme'); module.exports = { + important: true, mode: 'jit', content: ['./src/pages/**/*.{ts,tsx}', './src/components/**/*.{ts,tsx}'], theme: { diff --git a/yarn.lock b/yarn.lock index b32edc909..064253471 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1622,6 +1622,13 @@ dependencies: glob "7.1.7" +"@next/eslint-plugin-next@^12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.1.6.tgz#dde3f98831f15923b25244588d924c716956292e" + integrity sha512-yNUtJ90NEiYFT6TJnNyofKMPYqirKDwpahcbxBgSIuABwYOdkGwzos1ZkYD51Qf0diYwpQZBeVqElTk7Q2WNqw== + dependencies: + glob "7.1.7" + "@next/swc-android-arm64@12.1.0": version "12.1.0" resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" @@ -4780,6 +4787,11 @@ email-templates@^8.0.10: nodemailer "^6.7.2" preview-email "^3.0.5" +email-validator@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed" + integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ== + emoji-regex@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.0.1.tgz#77180edb279b99510a21b79b19e1dc283d8f3991" From cc69f66ba9ad0a3f0df4a2fa1c9363ab272ddc9e Mon Sep 17 00:00:00 2001 From: Nicolai Van der Storm Date: Fri, 10 Jun 2022 12:30:14 +0200 Subject: [PATCH 2/5] chore(.idea folder): removed .idea folder and added it to the .gitignore --- .gitignore | 3 ++ .idea/.gitignore | 8 ---- .idea/codeStyles/Project.xml | 67 ---------------------------- .idea/codeStyles/codeStyleConfig.xml | 5 --- .idea/dataSources.xml | 12 ----- .idea/git_toolbox_prj.xml | 15 ------- .idea/jellyseerr.iml | 12 ----- .idea/modules.xml | 8 ---- .idea/vcs.xml | 6 --- 9 files changed, 3 insertions(+), 133 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/codeStyles/Project.xml delete mode 100644 .idea/codeStyles/codeStyleConfig.xml delete mode 100644 .idea/dataSources.xml delete mode 100644 .idea/git_toolbox_prj.xml delete mode 100644 .idea/jellyseerr.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore index 7d606105b..41a0481fd 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ config/db/db.sqlite3-journal # VS Code .vscode/launch.json + +# Webstorm +.idea diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b81b..000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index ff5d00b02..000000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123c2..000000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml deleted file mode 100644 index a12bac1c9..000000000 --- a/.idea/dataSources.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - sqlite.xerial - true - org.sqlite.JDBC - jdbc:sqlite:$PROJECT_DIR$/config/db/db.sqlite3 - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml deleted file mode 100644 index 02b915b85..000000000 --- a/.idea/git_toolbox_prj.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/jellyseerr.iml b/.idea/jellyseerr.iml deleted file mode 100644 index 0c8867d7e..000000000 --- a/.idea/jellyseerr.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index bb19e753c..000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7f4..000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From d835336d330abfef5b15bc9febcb748a8154c7df Mon Sep 17 00:00:00 2001 From: Nicolai Van der Storm Date: Mon, 13 Jun 2022 14:21:05 +0200 Subject: [PATCH 3/5] feat(email validation): email requirement and validation + better importer --- server/lib/notifications/agents/email.ts | 41 +++++++--- server/routes/user/index.ts | 74 +++++++------------ src/components/Setup/LoginWithPlex.tsx | 2 +- src/components/Setup/SetupLogin.tsx | 2 +- .../UserList/JellyfinImportModal.tsx | 16 ++++ src/components/UserList/index.tsx | 4 +- 6 files changed, 79 insertions(+), 60 deletions(-) diff --git a/server/lib/notifications/agents/email.ts b/server/lib/notifications/agents/email.ts index a1dd7e4e4..cbed472fa 100644 --- a/server/lib/notifications/agents/email.ts +++ b/server/lib/notifications/agents/email.ts @@ -13,6 +13,7 @@ import { NotificationAgentKey, } from '../../settings'; import { BaseAgent, NotificationAgent, NotificationPayload } from './agent'; +import * as EmailValidator from 'email-validator'; class EmailAgent extends BaseAgent @@ -215,14 +216,23 @@ class EmailAgent this.getSettings(), payload.notifyUser.settings?.pgpKey ); - await email.send( - this.buildMessage( - type, - payload, - payload.notifyUser.email, - payload.notifyUser.displayName - ) - ); + if (EmailValidator.validate(payload.notifyUser.email)) { + await email.send( + this.buildMessage( + type, + payload, + payload.notifyUser.email, + payload.notifyUser.displayName + ) + ); + } else { + logger.warn('Invalid email address provided for user', { + label: 'Notifications', + recipient: payload.notifyUser.displayName, + type: Notification[type], + subject: payload.subject, + }); + } } catch (e) { logger.error('Error sending email notification', { label: 'Notifications', @@ -268,9 +278,18 @@ class EmailAgent this.getSettings(), user.settings?.pgpKey ); - await email.send( - this.buildMessage(type, payload, user.email, user.displayName) - ); + if (EmailValidator.validate(user.email)) { + await email.send( + this.buildMessage(type, payload, user.email, user.displayName) + ); + } else { + logger.warn('Invalid email address provided for user', { + label: 'Notifications', + recipient: user.displayName, + type: Notification[type], + subject: payload.subject, + }); + } } catch (e) { logger.error('Error sending email notification', { label: 'Notifications', diff --git a/server/routes/user/index.ts b/server/routes/user/index.ts index a45391acd..667efca20 100644 --- a/server/routes/user/index.ts +++ b/server/routes/user/index.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; import gravatarUrl from 'gravatar-url'; -import { findIndex, sortBy } from 'lodash'; +import { findIndex, forEach, sortBy } from 'lodash'; import { getRepository, In, Not } from 'typeorm'; import JellyfinAPI from '../../api/jellyfin'; import PlexTvAPI from '../../api/plextv'; @@ -492,62 +492,44 @@ router.post( ); jellyfinClient.setUserId(admin.jellyfinUserId ?? ''); - const jellyfinUsersResponse = await jellyfinClient.getUsers(); + //const jellyfinUsersResponse = await jellyfinClient.getUsers(); const createdUsers: User[] = []; const { hostname, externalHostname } = getSettings().jellyfin; const jellyfinHost = externalHostname && externalHostname.length > 0 ? externalHostname : hostname; - for (const account of jellyfinUsersResponse.users) { - if (account.Name) { - const user = await userRepository - .createQueryBuilder('user') - .where('user.jellyfinUserId = :id', { id: account.Id }) - .orWhere('user.email = :email', { - email: account.Name, - }) - .getOne(); - const avatar = account.PrimaryImageTag - ? `${jellyfinHost}/Users/${account.Id}/Images/Primary/?tag=${account.PrimaryImageTag}&quality=90` - : '/os_logo_square.png'; + forEach(body.jellyfinUserIds, async (jellyfinUserId) => { + jellyfinClient.setUserId(jellyfinUserId); + const jellyfinUser = await jellyfinClient.getUser(); - if (user) { - // Update the user's avatar with their Jellyfin thumbnail, in case it changed - user.avatar = avatar; - user.email = account.Name; - user.jellyfinUsername = account.Name; + const user = await userRepository.findOne({ + select: ['id', 'jellyfinUserId'], + where: { jellyfinUserId: jellyfinUserId }, + }); - // In case the user was previously a local account - if (user.userType === UserType.LOCAL) { - user.userType = UserType.JELLYFIN; - user.jellyfinUserId = account.Id; - } - await userRepository.save(user); - } else if (!body || body.jellyfinUserIds.includes(account.Id)) { - // logger.error('CREATED USER', { - // label: 'API', - // }); - - const newUser = new User({ - jellyfinUsername: account.Name, - jellyfinUserId: account.Id, - jellyfinDeviceId: Buffer.from( - `BOT_overseerr_${account.Name ?? ''}` - ).toString('base64'), - email: account.Name, - permissions: settings.main.defaultPermissions, - avatar, - userType: UserType.JELLYFIN, - }); - await userRepository.save(newUser); - createdUsers.push(newUser); - } + if (!user) { + const newUser = new User({ + jellyfinUsername: jellyfinUser.Name, + jellyfinUserId: jellyfinUser.Id, + jellyfinDeviceId: Buffer.from( + `BOT_jellyseerr_${jellyfinUser.Name ?? ''}` + ).toString('base64'), + email: jellyfinUser.Name, + permissions: settings.main.defaultPermissions, + avatar: jellyfinUser.PrimaryImageTag + ? `${jellyfinHost}/Users/${jellyfinUser.Id}/Images/Primary/?tag=${jellyfinUser.PrimaryImageTag}&quality=90` + : '/os_logo_square.png', + userType: UserType.JELLYFIN, + }); + + await userRepository.save(newUser); + createdUsers.push(newUser); } - } - return res.status(201).json(User.filterMany(createdUsers)); + return res.status(201).json(User.filterMany(createdUsers)); + }); } catch (e) { next({ status: 500, message: e.message }); } diff --git a/src/components/Setup/LoginWithPlex.tsx b/src/components/Setup/LoginWithPlex.tsx index 90d4425b4..4e5a10265 100644 --- a/src/components/Setup/LoginWithPlex.tsx +++ b/src/components/Setup/LoginWithPlex.tsx @@ -5,7 +5,7 @@ import { useUser } from '../../hooks/useUser'; import PlexLoginButton from '../PlexLoginButton'; const messages = defineMessages({ - welcome: 'Welcome to Overseerr', + welcome: 'Welcome to Jellyseerr', signinMessage: 'Get started by signing in with your Plex account', }); diff --git a/src/components/Setup/SetupLogin.tsx b/src/components/Setup/SetupLogin.tsx index d3d581b8a..09e48e161 100644 --- a/src/components/Setup/SetupLogin.tsx +++ b/src/components/Setup/SetupLogin.tsx @@ -9,7 +9,7 @@ import { MediaServerType } from '../../../server/constants/server'; import getConfig from 'next/config'; const messages = defineMessages({ - welcome: 'Welcome to Overseerr', + welcome: 'Welcome to Jellyseerr', signinMessage: 'Get started by signing in', signinWithJellyfin: 'Use your {mediaServerName} account', signinWithPlex: 'Use your Plex account', diff --git a/src/components/UserList/JellyfinImportModal.tsx b/src/components/UserList/JellyfinImportModal.tsx index 3e2f7ddf6..c3cf12a5f 100644 --- a/src/components/UserList/JellyfinImportModal.tsx +++ b/src/components/UserList/JellyfinImportModal.tsx @@ -9,6 +9,7 @@ import globalMessages from '../../i18n/globalMessages'; import Alert from '../Common/Alert'; import Modal from '../Common/Modal'; import getConfig from 'next/config'; +import { UserResultsResponse } from '../../../server/interfaces/api/userInterfaces'; interface JellyfinImportProps { onCancel?: () => void; @@ -30,6 +31,7 @@ const messages = defineMessages({ const JellyfinImportModal: React.FC = ({ onCancel, onComplete, + children, }) => { const intl = useIntl(); const settings = useSettings(); @@ -117,6 +119,20 @@ const JellyfinImportModal: React.FC = ({ } }; + const { data: existingUsers } = useSWR( + `/api/v1/user?take=${children}` + ); + + data?.forEach((user, pos) => { + if ( + existingUsers?.results.some( + (existingUser) => existingUser.jellyfinUserId === user.id + ) + ) { + delete data[pos]; + } + }); + return ( { setShowImportModal(false); revalidate(); }} - /> + > + {data.pageInfo.results} + )} From a483ca9837e12e2385d0e2407e52d6c64ae435e2 Mon Sep 17 00:00:00 2001 From: Nicolai Van der Storm Date: Mon, 13 Jun 2022 21:34:51 +0200 Subject: [PATCH 4/5] fix(jellyfinimportmodal): fix for importing all jellyfin users --- .../UserList/JellyfinImportModal.tsx | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/components/UserList/JellyfinImportModal.tsx b/src/components/UserList/JellyfinImportModal.tsx index c3cf12a5f..c57e06516 100644 --- a/src/components/UserList/JellyfinImportModal.tsx +++ b/src/components/UserList/JellyfinImportModal.tsx @@ -51,6 +51,18 @@ const JellyfinImportModal: React.FC = ({ revalidateOnMount: true, }); + const { data: existingUsers } = useSWR( + `/api/v1/user?take=${children}` + ); + + data?.forEach((user, pos) => { + if ( + existingUsers?.results.some((data) => data.jellyfinUserId === user.id) + ) { + data?.splice(pos, 1); + } + }); + const importUsers = async () => { setImporting(true); @@ -119,20 +131,6 @@ const JellyfinImportModal: React.FC = ({ } }; - const { data: existingUsers } = useSWR( - `/api/v1/user?take=${children}` - ); - - data?.forEach((user, pos) => { - if ( - existingUsers?.results.some( - (existingUser) => existingUser.jellyfinUserId === user.id - ) - ) { - delete data[pos]; - } - }); - return ( Date: Mon, 13 Jun 2022 23:13:22 +0200 Subject: [PATCH 5/5] fix(import all): fis for import all --- server/routes/user/index.ts | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/server/routes/user/index.ts b/server/routes/user/index.ts index 667efca20..5811fc05f 100644 --- a/server/routes/user/index.ts +++ b/server/routes/user/index.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; import gravatarUrl from 'gravatar-url'; -import { findIndex, forEach, sortBy } from 'lodash'; +import { findIndex, sortBy } from 'lodash'; import { getRepository, In, Not } from 'typeorm'; import JellyfinAPI from '../../api/jellyfin'; import PlexTvAPI from '../../api/plextv'; @@ -500,9 +500,13 @@ router.post( ? externalHostname : hostname; - forEach(body.jellyfinUserIds, async (jellyfinUserId) => { - jellyfinClient.setUserId(jellyfinUserId); - const jellyfinUser = await jellyfinClient.getUser(); + jellyfinClient.setUserId(admin.jellyfinUserId ?? ''); + const jellyfinUsers = await jellyfinClient.getUsers(); + + for (const jellyfinUserId of body.jellyfinUserIds) { + const jellyfinUser = jellyfinUsers.users.find( + (user) => user.Id === jellyfinUserId + ); const user = await userRepository.findOne({ select: ['id', 'jellyfinUserId'], @@ -511,14 +515,14 @@ router.post( if (!user) { const newUser = new User({ - jellyfinUsername: jellyfinUser.Name, - jellyfinUserId: jellyfinUser.Id, + jellyfinUsername: jellyfinUser?.Name, + jellyfinUserId: jellyfinUser?.Id, jellyfinDeviceId: Buffer.from( - `BOT_jellyseerr_${jellyfinUser.Name ?? ''}` + `BOT_jellyseerr_${jellyfinUser?.Name ?? ''}` ).toString('base64'), - email: jellyfinUser.Name, + email: jellyfinUser?.Name, permissions: settings.main.defaultPermissions, - avatar: jellyfinUser.PrimaryImageTag + avatar: jellyfinUser?.PrimaryImageTag ? `${jellyfinHost}/Users/${jellyfinUser.Id}/Images/Primary/?tag=${jellyfinUser.PrimaryImageTag}&quality=90` : '/os_logo_square.png', userType: UserType.JELLYFIN, @@ -527,9 +531,8 @@ router.post( await userRepository.save(newUser); createdUsers.push(newUser); } - - return res.status(201).json(User.filterMany(createdUsers)); - }); + } + return res.status(201).json(User.filterMany(createdUsers)); } catch (e) { next({ status: 500, message: e.message }); }