mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 16:20:04 +00:00
Finalize onboarding of super admin user
This commit is contained in:
@@ -5,8 +5,9 @@ import WizardStep from "Frontend/components/wizard/WizardStep";
|
|||||||
import Input from "Frontend/components/Input";
|
import Input from "Frontend/components/Input";
|
||||||
import {GearFine, HandWaving, Palette, User} from "@phosphor-icons/react";
|
import {GearFine, HandWaving, Palette, User} from "@phosphor-icons/react";
|
||||||
import {Card} from "@nextui-org/react";
|
import {Card} from "@nextui-org/react";
|
||||||
import {UserEndpoint} from "Frontend/generated/endpoints";
|
import {SetupEndpoint} from "Frontend/generated/endpoints";
|
||||||
import {ThemeSelector} from "Frontend/components/theming/ThemeSelector";
|
import {ThemeSelector} from "Frontend/components/theming/ThemeSelector";
|
||||||
|
import {useNavigate} from "react-router-dom";
|
||||||
|
|
||||||
function WelcomeStep() {
|
function WelcomeStep() {
|
||||||
return (
|
return (
|
||||||
@@ -82,17 +83,28 @@ function SettingsStep() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SetupView = () => (
|
function SetupView() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
<div className="flex size-full gradient-primary">
|
<div className="flex size-full gradient-primary">
|
||||||
<Card className="w-3/4 h-3/4 min-w-[500px] m-auto p-8">
|
<Card className="w-3/4 h-3/4 min-w-[500px] m-auto p-8">
|
||||||
<Wizard
|
<Wizard
|
||||||
initialValues={{username: '', email: '', password: '', passwordRepeat: ''}}
|
initialValues={{username: '', email: '', password: '', passwordRepeat: ''}}
|
||||||
onSubmit={(values: any) => UserEndpoint.registerInitialSuperAdmin({
|
onSubmit={
|
||||||
|
async (values: any) => {
|
||||||
|
try {
|
||||||
|
await SetupEndpoint.registerSuperAdmin({
|
||||||
username: values.username,
|
username: values.username,
|
||||||
password: values.password,
|
password: values.password,
|
||||||
email: values.email
|
email: values.email
|
||||||
|
});
|
||||||
|
navigate('/login');
|
||||||
|
} catch (e) {
|
||||||
|
alert("An error occurred while completing the setup. Please try again.")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
).then(() => alert("Successfully registered!"))}
|
|
||||||
>
|
>
|
||||||
<WizardStep icon={<HandWaving/>}>
|
<WizardStep icon={<HandWaving/>}>
|
||||||
<WelcomeStep/>
|
<WelcomeStep/>
|
||||||
@@ -124,6 +136,7 @@ const SetupView = () => (
|
|||||||
</Wizard>
|
</Wizard>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default SetupView;
|
export default SetupView;
|
||||||
@@ -34,19 +34,17 @@ class SetupDataLoader(
|
|||||||
fun setupUsers() {
|
fun setupUsers() {
|
||||||
val superadmin = User(
|
val superadmin = User(
|
||||||
username = "admin",
|
username = "admin",
|
||||||
password = "admin",
|
password = "admin"
|
||||||
roles = listOf(roleRepository.findByRolename(Roles.SUPERADMIN.roleName)!!)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
userService.registerUser(superadmin)
|
userService.registerUser(superadmin, Roles.SUPERADMIN)
|
||||||
|
|
||||||
val user = User(
|
val user = User(
|
||||||
username = "user",
|
username = "user",
|
||||||
password = "user",
|
password = "user"
|
||||||
roles = listOf(roleRepository.findByRolename(Roles.USER.roleName)!!)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
userService.registerUser(user)
|
userService.registerUser(user, Roles.USER)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setupRoles() {
|
fun setupRoles() {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package de.grimsi.gameyfin.setup
|
||||||
|
|
||||||
|
import com.vaadin.flow.server.auth.AnonymousAllowed
|
||||||
|
import de.grimsi.gameyfin.config.Roles
|
||||||
|
import de.grimsi.gameyfin.users.RoleService
|
||||||
|
import de.grimsi.gameyfin.users.UserService
|
||||||
|
import de.grimsi.gameyfin.users.dto.UserInfo
|
||||||
|
import de.grimsi.gameyfin.users.dto.UserRegistration
|
||||||
|
import de.grimsi.gameyfin.users.entities.User
|
||||||
|
import dev.hilla.Endpoint
|
||||||
|
import dev.hilla.exception.EndpointException
|
||||||
|
|
||||||
|
@Endpoint
|
||||||
|
class SetupEndpoint(
|
||||||
|
private val setupService: SetupService,
|
||||||
|
private val roleService: RoleService,
|
||||||
|
private val userService: UserService
|
||||||
|
) {
|
||||||
|
@AnonymousAllowed
|
||||||
|
fun isSetupCompleted(): Boolean {
|
||||||
|
return setupService.isSetupCompleted()
|
||||||
|
}
|
||||||
|
|
||||||
|
@AnonymousAllowed
|
||||||
|
fun registerSuperAdmin(superAdminRegistration: UserRegistration): UserInfo {
|
||||||
|
if (setupService.isSetupCompleted()) throw EndpointException("Setup already completed")
|
||||||
|
|
||||||
|
val user = User(
|
||||||
|
username = superAdminRegistration.username,
|
||||||
|
password = superAdminRegistration.password,
|
||||||
|
email = superAdminRegistration.email,
|
||||||
|
roles = listOf(roleService.toRole(Roles.SUPERADMIN))
|
||||||
|
)
|
||||||
|
|
||||||
|
val superAdmin = setupService.createInitialAdminUser(user)
|
||||||
|
return userService.toUserInfo(superAdmin)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,13 @@ package de.grimsi.gameyfin.setup
|
|||||||
|
|
||||||
import de.grimsi.gameyfin.config.Roles
|
import de.grimsi.gameyfin.config.Roles
|
||||||
import de.grimsi.gameyfin.users.RoleService
|
import de.grimsi.gameyfin.users.RoleService
|
||||||
|
import de.grimsi.gameyfin.users.UserService
|
||||||
|
import de.grimsi.gameyfin.users.entities.User
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class SetupService(
|
class SetupService(
|
||||||
|
private val userService: UserService,
|
||||||
private val roleService: RoleService
|
private val roleService: RoleService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -17,4 +20,11 @@ class SetupService(
|
|||||||
fun isSetupCompleted(): Boolean {
|
fun isSetupCompleted(): Boolean {
|
||||||
return roleService.getUserCountForRole(Roles.SUPERADMIN) > 0
|
return roleService.getUserCountForRole(Roles.SUPERADMIN) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the initial user with Super-Admin permissions
|
||||||
|
*/
|
||||||
|
fun createInitialAdminUser(superAdmin: User): User {
|
||||||
|
return userService.registerUser(superAdmin, Roles.SUPERADMIN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,11 +20,12 @@ class RoleService(
|
|||||||
return r.users.size
|
return r.users.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toRoles(roles: Collection<String>): List<Role> {
|
fun toRoles(roles: Collection<Roles>): List<Role> {
|
||||||
return roles.mapNotNull { r -> roleRepository.findByRolename(r) }
|
return roles.mapNotNull { r -> roleRepository.findByRolename(r.roleName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toRole(role: String): Role {
|
fun toRole(role: Roles): Role {
|
||||||
return roleRepository.findByRolename(role) ?: throw RuntimeException("Role $role does not exist")
|
return roleRepository.findByRolename(role.roleName)
|
||||||
|
?: throw RuntimeException("Role ${role.roleName} does not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,11 +6,9 @@ import de.grimsi.gameyfin.users.dto.UserRegistration
|
|||||||
import de.grimsi.gameyfin.users.entities.User
|
import de.grimsi.gameyfin.users.entities.User
|
||||||
import dev.hilla.Endpoint
|
import dev.hilla.Endpoint
|
||||||
import jakarta.annotation.security.PermitAll
|
import jakarta.annotation.security.PermitAll
|
||||||
import org.springframework.http.HttpStatus
|
|
||||||
import org.springframework.security.core.Authentication
|
import org.springframework.security.core.Authentication
|
||||||
import org.springframework.security.core.GrantedAuthority
|
import org.springframework.security.core.GrantedAuthority
|
||||||
import org.springframework.security.core.context.SecurityContextHolder
|
import org.springframework.security.core.context.SecurityContextHolder
|
||||||
import org.springframework.web.server.ResponseStatusException
|
|
||||||
|
|
||||||
@Endpoint
|
@Endpoint
|
||||||
class UserEndpoint(
|
class UserEndpoint(
|
||||||
@@ -31,21 +29,13 @@ class UserEndpoint(
|
|||||||
return userService.toUserInfo(user)
|
return userService.toUserInfo(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
@PermitAll
|
|
||||||
fun registerInitialSuperAdmin(registration: UserRegistration): UserInfo {
|
|
||||||
if (roleService.getUserCountForRole(Roles.SUPERADMIN) > 0) throw ResponseStatusException(HttpStatus.UNAUTHORIZED)
|
|
||||||
val superAdmin: User = registerUser(registration, listOf(Roles.SUPERADMIN))
|
|
||||||
return userService.toUserInfo(superAdmin)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun registerUser(registration: UserRegistration, roles: List<Roles>): User {
|
private fun registerUser(registration: UserRegistration, roles: List<Roles>): User {
|
||||||
val user = User(
|
val user = User(
|
||||||
username = registration.username,
|
username = registration.username,
|
||||||
password = registration.password,
|
password = registration.password,
|
||||||
email = registration.email,
|
email = registration.email
|
||||||
roles = roles.map { r -> roleService.toRole(r.roleName) }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return userService.registerUser(user)
|
return userService.registerUser(user, roles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.grimsi.gameyfin.users
|
package de.grimsi.gameyfin.users
|
||||||
|
|
||||||
|
import de.grimsi.gameyfin.config.Roles
|
||||||
import de.grimsi.gameyfin.users.dto.UserInfo
|
import de.grimsi.gameyfin.users.dto.UserInfo
|
||||||
import de.grimsi.gameyfin.users.entities.Role
|
import de.grimsi.gameyfin.users.entities.Role
|
||||||
import de.grimsi.gameyfin.users.entities.User
|
import de.grimsi.gameyfin.users.entities.User
|
||||||
@@ -18,7 +19,8 @@ import org.springframework.stereotype.Service
|
|||||||
@Transactional
|
@Transactional
|
||||||
class UserService(
|
class UserService(
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
private val passwordEncoder: PasswordEncoder
|
private val passwordEncoder: PasswordEncoder,
|
||||||
|
private val roleService: RoleService
|
||||||
) : UserDetailsService {
|
) : UserDetailsService {
|
||||||
|
|
||||||
override fun loadUserByUsername(username: String): UserDetails {
|
override fun loadUserByUsername(username: String): UserDetails {
|
||||||
@@ -36,8 +38,13 @@ class UserService(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerUser(user: User): User {
|
fun registerUser(user: User, role: Roles): User {
|
||||||
|
return registerUser(user, listOf(role))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerUser(user: User, roles: List<Roles>): User {
|
||||||
user.password = passwordEncoder.encode(user.password)
|
user.password = passwordEncoder.encode(user.password)
|
||||||
|
user.roles = roleService.toRoles(roles)
|
||||||
return userRepository.save(user)
|
return userRepository.save(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,5 +33,5 @@ class User(
|
|||||||
joinColumns = [JoinColumn(name = "user_id", referencedColumnName = "id")],
|
joinColumns = [JoinColumn(name = "user_id", referencedColumnName = "id")],
|
||||||
inverseJoinColumns = [JoinColumn(name = "role_id", referencedColumnName = "id")]
|
inverseJoinColumns = [JoinColumn(name = "role_id", referencedColumnName = "id")]
|
||||||
)
|
)
|
||||||
var roles: Collection<Role>
|
var roles: Collection<Role> = emptyList()
|
||||||
)
|
)
|
||||||
Reference in New Issue
Block a user