mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-15 00:30:02 +00:00
Minor bugfixes in setup process
Improved UX with small hints
This commit is contained in:
@@ -7,16 +7,21 @@ import React, {useEffect, useState} from "react";
|
||||
import {useAuth} from "Frontend/util/auth";
|
||||
import * as Yup from "yup";
|
||||
import UserUpdateDto from "Frontend/generated/de/grimsi/gameyfin/users/dto/UserUpdateDto";
|
||||
import {EmailConfirmationEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
|
||||
import {EmailConfirmationEndpoint, MessageEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
|
||||
import {SmallInfoField} from "Frontend/components/general/SmallInfoField";
|
||||
import {toast} from "sonner";
|
||||
import {removeAvatar, uploadAvatar} from "Frontend/endpoints/AvatarEndpoint";
|
||||
import Avatar from "Frontend/components/general/Avatar";
|
||||
|
||||
export default function ProfileManagement() {
|
||||
const [configSaved, setConfigSaved] = useState(false);
|
||||
const auth = useAuth();
|
||||
const [avatar, setAvatar] = useState<any>();
|
||||
const [configSaved, setConfigSaved] = useState(false);
|
||||
const [messagesEnabled, setMessagesEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
MessageEndpoint.isEnabled().then(setMessagesEnabled);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (configSaved) {
|
||||
@@ -122,8 +127,8 @@ export default function ProfileManagement() {
|
||||
isDisabled={auth.state.user?.managedBySso}/>
|
||||
<div className="flex flex-row gap-4">
|
||||
<Input name="email" label="Email" type="email" autocomplete="email"
|
||||
isDisabled={auth.state.user?.managedBySso}/>
|
||||
{auth.state.user?.emailConfirmed === false &&
|
||||
isDisabled={auth.state.user?.managedBySso || !messagesEnabled}/>
|
||||
{(auth.state.user?.emailConfirmed === false && !auth.state.user.managedBySso) &&
|
||||
<Tooltip content="Resend email confirmation message">
|
||||
<Button isIconOnly
|
||||
onPress={() => {
|
||||
@@ -131,6 +136,7 @@ export default function ProfileManagement() {
|
||||
() => toast.success("You will receive an email shortly")
|
||||
)
|
||||
}}
|
||||
isDisabled={!messagesEnabled}
|
||||
variant="ghost"
|
||||
className="size-14"
|
||||
>
|
||||
@@ -139,6 +145,14 @@ export default function ProfileManagement() {
|
||||
</Tooltip>
|
||||
}
|
||||
</div>
|
||||
{!messagesEnabled &&
|
||||
<div className="flex flex-row gap-2 text-warning -mt-5">
|
||||
<Info/>
|
||||
<small>
|
||||
Email services are disabled. Please contact your administrator.
|
||||
</small>
|
||||
</div>
|
||||
}
|
||||
<Section title="Security"/>
|
||||
<Input name="newPassword" label="New Password" type="password"
|
||||
autocomplete="new-password" isDisabled={auth.state.user?.managedBySso}/>
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as Yup from 'yup';
|
||||
import Wizard from "Frontend/components/wizard/Wizard";
|
||||
import WizardStep from "Frontend/components/wizard/WizardStep";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import {GearFine, HandWaving, Palette, User} from "@phosphor-icons/react";
|
||||
import {HandWaving, Palette, User} from "@phosphor-icons/react";
|
||||
import {Card} from "@nextui-org/react";
|
||||
import {SetupEndpoint} from "Frontend/generated/endpoints";
|
||||
import {ThemeSelector} from "Frontend/components/theming/ThemeSelector";
|
||||
@@ -76,17 +76,6 @@ function UserStep() {
|
||||
);
|
||||
}
|
||||
|
||||
function SettingsStep() {
|
||||
return (
|
||||
<div className="flex flex-col size-full items-center">
|
||||
<div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
|
||||
<h4>Settings</h4>
|
||||
<p>Configure your settings</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SetupView() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -131,9 +120,6 @@ function SetupView() {
|
||||
>
|
||||
<UserStep/>
|
||||
</WizardStep>
|
||||
<WizardStep icon={<GearFine/>}>
|
||||
<SettingsStep/>
|
||||
</WizardStep>
|
||||
</Wizard>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -3,18 +3,12 @@ package de.grimsi.gameyfin.setup
|
||||
import com.vaadin.flow.server.auth.AnonymousAllowed
|
||||
import com.vaadin.hilla.Endpoint
|
||||
import com.vaadin.hilla.exception.EndpointException
|
||||
import de.grimsi.gameyfin.core.Roles
|
||||
import de.grimsi.gameyfin.users.RoleService
|
||||
import de.grimsi.gameyfin.users.UserService
|
||||
import de.grimsi.gameyfin.users.dto.UserInfoDto
|
||||
import de.grimsi.gameyfin.users.dto.UserRegistrationDto
|
||||
import de.grimsi.gameyfin.users.entities.User
|
||||
|
||||
@Endpoint
|
||||
class SetupEndpoint(
|
||||
private val setupService: SetupService,
|
||||
private val roleService: RoleService,
|
||||
private val userService: UserService
|
||||
private val setupService: SetupService
|
||||
) {
|
||||
@AnonymousAllowed
|
||||
fun isSetupCompleted(): Boolean {
|
||||
@@ -24,15 +18,6 @@ class SetupEndpoint(
|
||||
@AnonymousAllowed
|
||||
fun registerSuperAdmin(superAdminRegistration: UserRegistrationDto): UserInfoDto {
|
||||
if (setupService.isSetupCompleted()) throw EndpointException("Setup already completed")
|
||||
|
||||
val user = User(
|
||||
username = superAdminRegistration.username,
|
||||
password = superAdminRegistration.password,
|
||||
email = superAdminRegistration.email,
|
||||
roles = setOf(roleService.toRole(Roles.SUPERADMIN))
|
||||
)
|
||||
|
||||
val superAdmin = setupService.createInitialAdminUser(user)
|
||||
return userService.toUserInfo(superAdmin)
|
||||
return setupService.createInitialAdminUser(superAdminRegistration)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package de.grimsi.gameyfin.setup
|
||||
import de.grimsi.gameyfin.core.Roles
|
||||
import de.grimsi.gameyfin.users.RoleService
|
||||
import de.grimsi.gameyfin.users.UserService
|
||||
import de.grimsi.gameyfin.users.dto.UserInfoDto
|
||||
import de.grimsi.gameyfin.users.dto.UserRegistrationDto
|
||||
import de.grimsi.gameyfin.users.entities.User
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@@ -24,7 +26,16 @@ class SetupService(
|
||||
/**
|
||||
* Creates the initial user with Super-Admin permissions
|
||||
*/
|
||||
fun createInitialAdminUser(superAdmin: User): User {
|
||||
return userService.registerOrUpdateUser(superAdmin, Roles.SUPERADMIN)
|
||||
fun createInitialAdminUser(registration: UserRegistrationDto): UserInfoDto {
|
||||
val superAdmin = User(
|
||||
username = registration.username,
|
||||
password = registration.password,
|
||||
email = registration.email,
|
||||
roles = setOf(roleService.toRole(Roles.SUPERADMIN)),
|
||||
enabled = true
|
||||
)
|
||||
|
||||
val user = userService.registerOrUpdateUser(superAdmin, Roles.SUPERADMIN)
|
||||
return userService.toUserInfo(user)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package de.grimsi.gameyfin.shared.token
|
||||
|
||||
import de.grimsi.gameyfin.users.entities.User
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import jakarta.transaction.Transactional
|
||||
|
||||
abstract class TokenService<T : TokenType>(
|
||||
private val type: T,
|
||||
@@ -11,7 +10,6 @@ abstract class TokenService<T : TokenType>(
|
||||
|
||||
private val log = KotlinLogging.logger {}
|
||||
|
||||
@Transactional
|
||||
open fun generate(user: User): Token<T> {
|
||||
val token = Token(
|
||||
creator = user,
|
||||
@@ -26,7 +24,6 @@ abstract class TokenService<T : TokenType>(
|
||||
return tokenRepository.save(token)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
open fun generateWithPayload(user: User, payload: Map<String, String>): Token<T> {
|
||||
val token = Token(
|
||||
creator = user,
|
||||
@@ -42,7 +39,6 @@ abstract class TokenService<T : TokenType>(
|
||||
return tokenRepository.save(token)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
open fun get(secret: String, type: T): Token<T>? {
|
||||
val token = tokenRepository.findBySecret(secret) ?: return null
|
||||
|
||||
@@ -55,12 +51,10 @@ abstract class TokenService<T : TokenType>(
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
open fun getPayload(secret: String): Map<String, String>? {
|
||||
return tokenRepository.findBySecret(secret)?.payload
|
||||
}
|
||||
|
||||
@Transactional
|
||||
open fun delete(token: Token<T>) {
|
||||
try {
|
||||
tokenRepository.delete(token)
|
||||
@@ -69,7 +63,6 @@ abstract class TokenService<T : TokenType>(
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
open fun validate(secret: String): TokenValidationResult {
|
||||
val token = tokenRepository.findBySecret(secret) ?: return TokenValidationResult.INVALID
|
||||
return if (token.expired) TokenValidationResult.EXPIRED else TokenValidationResult.VALID
|
||||
|
||||
@@ -179,10 +179,10 @@ class UserService(
|
||||
}
|
||||
}
|
||||
|
||||
fun registerUserFromInvitation(user: UserRegistrationDto, email: String): User {
|
||||
fun registerUserFromInvitation(registration: UserRegistrationDto, email: String): User {
|
||||
val user = User(
|
||||
username = user.username,
|
||||
password = passwordEncoder.encode(user.password),
|
||||
username = registration.username,
|
||||
password = passwordEncoder.encode(registration.password),
|
||||
email = email,
|
||||
emailConfirmed = true,
|
||||
enabled = true,
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.grimsi.gameyfin.users.registration
|
||||
|
||||
import de.grimsi.gameyfin.core.Utils
|
||||
import de.grimsi.gameyfin.core.events.UserInvitationEvent
|
||||
import de.grimsi.gameyfin.core.events.UserRegistrationEvent
|
||||
import de.grimsi.gameyfin.shared.token.TokenDto
|
||||
import de.grimsi.gameyfin.shared.token.TokenRepository
|
||||
import de.grimsi.gameyfin.shared.token.TokenService
|
||||
@@ -48,7 +49,10 @@ class InvitationService(
|
||||
val email = invitationToken.payload[EMAIL_KEY] ?: return TokenValidationResult.INVALID
|
||||
if (invitationToken.expired) return TokenValidationResult.EXPIRED
|
||||
|
||||
userService.registerUserFromInvitation(registration, email)
|
||||
val user = userService.registerUserFromInvitation(registration, email)
|
||||
super.delete(invitationToken)
|
||||
eventPublisher.publishEvent(UserRegistrationEvent(this, user, Utils.getBaseUrl()))
|
||||
|
||||
return TokenValidationResult.VALID
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user