From 310cdb36df1601bca5e57f0bc796c44111b8435f Mon Sep 17 00:00:00 2001 From: TheCatLady <52870424+TheCatLady@users.noreply.github.com> Date: Sun, 30 May 2021 19:38:52 -0400 Subject: [PATCH] fix(plex): do not fail to import Plex users when Plex Home has managed users (#1699) * fix(plex): do not fail to import Plex users when Plex Home has managed users * fix: default display name to email when user has no username also, do not set username or plexUsername when it is the same as the user's email address * fix(ui): user display name placeholder should reflect fallback logic if username is not set * fix(ui): hide email addresses of other users if logged-in user does not have Manage Users permission * fix: always set Plex username even if same as user's email * fix: remove unnecessary permission check * fix: transform email addresses to lowercase --- server/entity/User.ts | 12 ++- server/routes/auth.ts | 9 +-- server/routes/user/index.ts | 80 +++++++++---------- .../RequestModal/AdvancedRequester/index.tsx | 18 +++-- src/components/UserList/index.tsx | 8 +- .../UserProfile/ProfileHeader/index.tsx | 2 +- .../UserGeneralSettings/index.tsx | 4 +- 7 files changed, 70 insertions(+), 63 deletions(-) diff --git a/server/entity/User.ts b/server/entity/User.ts index 5e83dd068..45802195a 100644 --- a/server/entity/User.ts +++ b/server/entity/User.ts @@ -48,11 +48,17 @@ export class User { @PrimaryGeneratedColumn() public id: number; - @Column({ unique: true }) + @Column({ + unique: true, + transformer: { + from: (value: string): string => value.toLowerCase(), + to: (value: string): string => value.toLowerCase(), + }, + }) public email: string; @Column({ nullable: true }) - public plexUsername: string; + public plexUsername?: string; @Column({ nullable: true }) public username?: string; @@ -220,7 +226,7 @@ export class User { @AfterLoad() public setDisplayName(): void { - this.displayName = this.username || this.plexUsername; + this.displayName = this.username || this.plexUsername || this.email; } public async getQuota(): Promise { diff --git a/server/routes/auth.ts b/server/routes/auth.ts index abc44d4f0..03fd0bad8 100644 --- a/server/routes/auth.ts +++ b/server/routes/auth.ts @@ -43,7 +43,7 @@ authRoutes.post('/plex', async (req, res, next) => { let user = await userRepository .createQueryBuilder('user') .where('user.plexId = :id', { id: account.id }) - .orWhere('LOWER(user.email) = :email', { + .orWhere('user.email = :email', { email: account.email.toLowerCase(), }) .getOne(); @@ -65,9 +65,6 @@ authRoutes.post('/plex', async (req, res, next) => { user.plexId = account.id; } - if (user.username === account.username) { - user.username = ''; - } await userRepository.save(user); } else { // Here we check if it's the first user. If it is, we create the user with no check @@ -177,7 +174,7 @@ authRoutes.post('/local', async (req, res, next) => { const user = await userRepository .createQueryBuilder('user') .select(['user.id', 'user.password']) - .where('LOWER(user.email) = :email', { email: body.email.toLowerCase() }) + .where('user.email = :email', { email: body.email.toLowerCase() }) .getOne(); const isCorrectCredentials = await user?.passwordMatch(body.password); @@ -244,7 +241,7 @@ authRoutes.post('/reset-password', async (req, res) => { const user = await userRepository .createQueryBuilder('user') - .where('LOWER(user.email) = :email', { email: body.email.toLowerCase() }) + .where('user.email = :email', { email: body.email.toLowerCase() }) .getOne(); if (user) { diff --git a/server/routes/user/index.ts b/server/routes/user/index.ts index 28dc2bd81..4bccc772d 100644 --- a/server/routes/user/index.ts +++ b/server/routes/user/index.ts @@ -31,7 +31,7 @@ router.get('/', async (req, res, next) => { break; case 'displayname': query = query.orderBy( - '(CASE WHEN user.username IS NULL THEN user.plexUsername ELSE user.username END)', + "(CASE WHEN (user.username IS NULL OR user.username = '') THEN (CASE WHEN (user.plexUsername IS NULL OR user.plexUsername = '') THEN user.email ELSE LOWER(user.plexUsername) END) ELSE LOWER(user.username) END)", 'ASC' ); break; @@ -84,7 +84,7 @@ router.post( const existingUser = await userRepository .createQueryBuilder('user') - .where('LOWER(user.email) = :email', { + .where('user.email = :email', { email: body.email.toLowerCase(), }) .getOne(); @@ -396,51 +396,45 @@ router.post( for (const rawUser of plexUsersResponse.MediaContainer.User) { const account = rawUser.$; - const user = await userRepository - .createQueryBuilder('user') - .where('user.plexId = :id', { id: account.id }) - .orWhere('LOWER(user.email) = :email', { - email: account.email.toLowerCase(), - }) - .getOne(); - - if (user) { - // Update the user's avatar with their Plex thumbnail, in case it changed - user.avatar = account.thumb; - user.email = account.email; - user.plexUsername = account.username; - - // In case the user was previously a local account - if (user.userType === UserType.LOCAL) { - user.userType = UserType.PLEX; - user.plexId = parseInt(account.id); - - if (user.username === account.username) { - user.username = ''; + if (account.email) { + const user = await userRepository + .createQueryBuilder('user') + .where('user.plexId = :id', { id: account.id }) + .orWhere('user.email = :email', { + email: account.email.toLowerCase(), + }) + .getOne(); + + if (user) { + // Update the user's avatar with their Plex thumbnail, in case it changed + user.avatar = account.thumb; + user.email = account.email; + user.plexUsername = account.username; + + // In case the user was previously a local account + if (user.userType === UserType.LOCAL) { + user.userType = UserType.PLEX; + user.plexId = parseInt(account.id); + } + await userRepository.save(user); + } else { + if (await mainPlexTv.checkUserAccess(parseInt(account.id))) { + const newUser = new User({ + plexUsername: account.username, + email: account.email, + permissions: settings.main.defaultPermissions, + plexId: parseInt(account.id), + plexToken: '', + avatar: account.thumb, + userType: UserType.PLEX, + }); + await userRepository.save(newUser); + createdUsers.push(newUser); } - } - await userRepository.save(user); - } else { - // Check to make sure it's a real account - if ( - account.email && - account.username && - (await mainPlexTv.checkUserAccess(parseInt(account.id))) - ) { - const newUser = new User({ - plexUsername: account.username, - email: account.email, - permissions: settings.main.defaultPermissions, - plexId: parseInt(account.id), - plexToken: '', - avatar: account.thumb, - userType: UserType.PLEX, - }); - await userRepository.save(newUser); - createdUsers.push(newUser); } } } + return res.status(201).json(User.filterMany(createdUsers)); } catch (e) { next({ status: 500, message: e.message }); diff --git a/src/components/RequestModal/AdvancedRequester/index.tsx b/src/components/RequestModal/AdvancedRequester/index.tsx index 20dbbde0e..2db67a6d8 100644 --- a/src/components/RequestModal/AdvancedRequester/index.tsx +++ b/src/components/RequestModal/AdvancedRequester/index.tsx @@ -522,9 +522,12 @@ const AdvancedRequester: React.FC = ({ {selectedUser.displayName} - - ({selectedUser.email}) - + {selectedUser.displayName.toLowerCase() !== + selectedUser.email && ( + + ({selectedUser.email}) + + )} @@ -569,9 +572,12 @@ const AdvancedRequester: React.FC = ({ {user.displayName} - - ({user.email}) - + {user.displayName.toLowerCase() !== + user.email && ( + + ({user.email}) + + )} {selected && ( { {user.displayName} -
- {user.email} -
+ {user.displayName.toLowerCase() !== user.email && ( +
+ {user.email} +
+ )} diff --git a/src/components/UserProfile/ProfileHeader/index.tsx b/src/components/UserProfile/ProfileHeader/index.tsx index 89e15b98b..a1f971fc6 100644 --- a/src/components/UserProfile/ProfileHeader/index.tsx +++ b/src/components/UserProfile/ProfileHeader/index.tsx @@ -65,7 +65,7 @@ const ProfileHeader: React.FC = ({ {user.displayName} - {user.email && ( + {user.email && user.displayName.toLowerCase() !== user.email && ( ({user.email}) diff --git a/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx b/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx index aff9013b8..b98a1d066 100644 --- a/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx +++ b/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx @@ -188,7 +188,9 @@ const UserGeneralSettings: React.FC = () => { id="displayName" name="displayName" type="text" - placeholder={user?.displayName} + placeholder={ + user?.plexUsername ? user.plexUsername : user?.email + } /> {errors.displayName && touched.displayName && (