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
pull/1700/head
TheCatLady 4 years ago committed by GitHub
parent 6603dffe95
commit 310cdb36df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -48,11 +48,17 @@ export class User {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
public id: number; 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; public email: string;
@Column({ nullable: true }) @Column({ nullable: true })
public plexUsername: string; public plexUsername?: string;
@Column({ nullable: true }) @Column({ nullable: true })
public username?: string; public username?: string;
@ -220,7 +226,7 @@ export class User {
@AfterLoad() @AfterLoad()
public setDisplayName(): void { public setDisplayName(): void {
this.displayName = this.username || this.plexUsername; this.displayName = this.username || this.plexUsername || this.email;
} }
public async getQuota(): Promise<QuotaResponse> { public async getQuota(): Promise<QuotaResponse> {

@ -43,7 +43,7 @@ authRoutes.post('/plex', async (req, res, next) => {
let user = await userRepository let user = await userRepository
.createQueryBuilder('user') .createQueryBuilder('user')
.where('user.plexId = :id', { id: account.id }) .where('user.plexId = :id', { id: account.id })
.orWhere('LOWER(user.email) = :email', { .orWhere('user.email = :email', {
email: account.email.toLowerCase(), email: account.email.toLowerCase(),
}) })
.getOne(); .getOne();
@ -65,9 +65,6 @@ authRoutes.post('/plex', async (req, res, next) => {
user.plexId = account.id; user.plexId = account.id;
} }
if (user.username === account.username) {
user.username = '';
}
await userRepository.save(user); await userRepository.save(user);
} else { } else {
// Here we check if it's the first user. If it is, we create the user with no check // 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 const user = await userRepository
.createQueryBuilder('user') .createQueryBuilder('user')
.select(['user.id', 'user.password']) .select(['user.id', 'user.password'])
.where('LOWER(user.email) = :email', { email: body.email.toLowerCase() }) .where('user.email = :email', { email: body.email.toLowerCase() })
.getOne(); .getOne();
const isCorrectCredentials = await user?.passwordMatch(body.password); const isCorrectCredentials = await user?.passwordMatch(body.password);
@ -244,7 +241,7 @@ authRoutes.post('/reset-password', async (req, res) => {
const user = await userRepository const user = await userRepository
.createQueryBuilder('user') .createQueryBuilder('user')
.where('LOWER(user.email) = :email', { email: body.email.toLowerCase() }) .where('user.email = :email', { email: body.email.toLowerCase() })
.getOne(); .getOne();
if (user) { if (user) {

@ -31,7 +31,7 @@ router.get('/', async (req, res, next) => {
break; break;
case 'displayname': case 'displayname':
query = query.orderBy( 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' 'ASC'
); );
break; break;
@ -84,7 +84,7 @@ router.post(
const existingUser = await userRepository const existingUser = await userRepository
.createQueryBuilder('user') .createQueryBuilder('user')
.where('LOWER(user.email) = :email', { .where('user.email = :email', {
email: body.email.toLowerCase(), email: body.email.toLowerCase(),
}) })
.getOne(); .getOne();
@ -396,10 +396,11 @@ router.post(
for (const rawUser of plexUsersResponse.MediaContainer.User) { for (const rawUser of plexUsersResponse.MediaContainer.User) {
const account = rawUser.$; const account = rawUser.$;
if (account.email) {
const user = await userRepository const user = await userRepository
.createQueryBuilder('user') .createQueryBuilder('user')
.where('user.plexId = :id', { id: account.id }) .where('user.plexId = :id', { id: account.id })
.orWhere('LOWER(user.email) = :email', { .orWhere('user.email = :email', {
email: account.email.toLowerCase(), email: account.email.toLowerCase(),
}) })
.getOne(); .getOne();
@ -414,19 +415,10 @@ router.post(
if (user.userType === UserType.LOCAL) { if (user.userType === UserType.LOCAL) {
user.userType = UserType.PLEX; user.userType = UserType.PLEX;
user.plexId = parseInt(account.id); user.plexId = parseInt(account.id);
if (user.username === account.username) {
user.username = '';
}
} }
await userRepository.save(user); await userRepository.save(user);
} else { } else {
// Check to make sure it's a real account if (await mainPlexTv.checkUserAccess(parseInt(account.id))) {
if (
account.email &&
account.username &&
(await mainPlexTv.checkUserAccess(parseInt(account.id)))
) {
const newUser = new User({ const newUser = new User({
plexUsername: account.username, plexUsername: account.username,
email: account.email, email: account.email,
@ -441,6 +433,8 @@ router.post(
} }
} }
} }
}
return res.status(201).json(User.filterMany(createdUsers)); return res.status(201).json(User.filterMany(createdUsers));
} catch (e) { } catch (e) {
next({ status: 500, message: e.message }); next({ status: 500, message: e.message });

@ -522,9 +522,12 @@ const AdvancedRequester: React.FC<AdvancedRequesterProps> = ({
<span className="block ml-3"> <span className="block ml-3">
{selectedUser.displayName} {selectedUser.displayName}
</span> </span>
{selectedUser.displayName.toLowerCase() !==
selectedUser.email && (
<span className="ml-1 text-gray-400 truncate"> <span className="ml-1 text-gray-400 truncate">
({selectedUser.email}) ({selectedUser.email})
</span> </span>
)}
</span> </span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 text-gray-500 pointer-events-none"> <span className="absolute inset-y-0 right-0 flex items-center pr-2 text-gray-500 pointer-events-none">
<ChevronDownIcon className="w-5 h-5" /> <ChevronDownIcon className="w-5 h-5" />
@ -569,9 +572,12 @@ const AdvancedRequester: React.FC<AdvancedRequesterProps> = ({
<span className="flex-shrink-0 block ml-3"> <span className="flex-shrink-0 block ml-3">
{user.displayName} {user.displayName}
</span> </span>
{user.displayName.toLowerCase() !==
user.email && (
<span className="ml-1 text-gray-400 truncate"> <span className="ml-1 text-gray-400 truncate">
({user.email}) ({user.email})
</span> </span>
)}
</span> </span>
{selected && ( {selected && (
<span <span

@ -602,9 +602,11 @@ const UserList: React.FC = () => {
{user.displayName} {user.displayName}
</a> </a>
</Link> </Link>
{user.displayName.toLowerCase() !== user.email && (
<div className="text-sm leading-5 text-gray-300"> <div className="text-sm leading-5 text-gray-300">
{user.email} {user.email}
</div> </div>
)}
</div> </div>
</div> </div>
</Table.TD> </Table.TD>

@ -65,7 +65,7 @@ const ProfileHeader: React.FC<ProfileHeaderProps> = ({
{user.displayName} {user.displayName}
</a> </a>
</Link> </Link>
{user.email && ( {user.email && user.displayName.toLowerCase() !== user.email && (
<span className="text-sm text-gray-400 sm:text-lg sm:ml-2"> <span className="text-sm text-gray-400 sm:text-lg sm:ml-2">
({user.email}) ({user.email})
</span> </span>

@ -188,7 +188,9 @@ const UserGeneralSettings: React.FC = () => {
id="displayName" id="displayName"
name="displayName" name="displayName"
type="text" type="text"
placeholder={user?.displayName} placeholder={
user?.plexUsername ? user.plexUsername : user?.email
}
/> />
</div> </div>
{errors.displayName && touched.displayName && ( {errors.displayName && touched.displayName && (

Loading…
Cancel
Save