diff --git a/backend/src/main/java/io/papermc/hangar/controller/internal/admin/AdminController.java b/backend/src/main/java/io/papermc/hangar/controller/internal/admin/AdminController.java index 6bee6e35c..92b15c2c3 100644 --- a/backend/src/main/java/io/papermc/hangar/controller/internal/admin/AdminController.java +++ b/backend/src/main/java/io/papermc/hangar/controller/internal/admin/AdminController.java @@ -11,6 +11,7 @@ import io.papermc.hangar.controller.extras.pagination.filters.log.LogProjectFilt import io.papermc.hangar.controller.extras.pagination.filters.log.LogSubjectFilter; import io.papermc.hangar.controller.extras.pagination.filters.log.LogUserFilter; import io.papermc.hangar.controller.extras.pagination.filters.log.LogVersionFilter; +import io.papermc.hangar.db.dao.internal.table.roles.RolesDAO; import io.papermc.hangar.model.api.PaginatedResult; import io.papermc.hangar.model.api.requests.RequestPagination; import io.papermc.hangar.model.common.NamedPermission; @@ -18,10 +19,12 @@ import io.papermc.hangar.model.common.roles.GlobalRole; import io.papermc.hangar.model.db.JobTable; import io.papermc.hangar.model.db.UserTable; import io.papermc.hangar.model.db.roles.GlobalRoleTable; +import io.papermc.hangar.model.db.roles.RoleTable; import io.papermc.hangar.model.internal.admin.health.MissingFileCheck; import io.papermc.hangar.model.internal.admin.health.UnhealthyProject; import io.papermc.hangar.model.internal.api.requests.StringContent; import io.papermc.hangar.model.internal.api.requests.admin.ChangePlatformVersionsForm; +import io.papermc.hangar.model.internal.api.requests.admin.ChangeRoleForm; import io.papermc.hangar.model.internal.api.responses.HealthReport; import io.papermc.hangar.model.internal.logs.HangarLoggedAction; import io.papermc.hangar.security.annotations.permission.PermissionRequired; @@ -42,6 +45,7 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -65,9 +69,10 @@ public class AdminController extends HangarComponent { private final UserService userService; private final ObjectMapper mapper; private final GlobalRoleService globalRoleService; + private final RolesDAO rolesDAO; @Autowired - public AdminController(final PlatformService platformService, final StatService statService, final HealthService healthService, final JobService jobService, final UserService userService, final ObjectMapper mapper, final GlobalRoleService globalRoleService) { + public AdminController(final PlatformService platformService, final StatService statService, final HealthService healthService, final JobService jobService, final UserService userService, final ObjectMapper mapper, final GlobalRoleService globalRoleService, final RolesDAO rolesDAO) { this.platformService = platformService; this.statService = statService; this.healthService = healthService; @@ -75,6 +80,7 @@ public class AdminController extends HangarComponent { this.userService = userService; this.mapper = mapper; this.globalRoleService = globalRoleService; + this.rolesDAO = rolesDAO; } @ResponseStatus(HttpStatus.OK) @@ -84,6 +90,17 @@ public class AdminController extends HangarComponent { this.platformService.updatePlatformVersions(form); } + @ResponseStatus(HttpStatus.OK) + @PostMapping(path = "/roles", consumes = MediaType.APPLICATION_JSON_VALUE) + @PermissionRequired(NamedPermission.MANUAL_VALUE_CHANGES) + @Transactional + public void changeRoles(@RequestBody final List<@Valid ChangeRoleForm> roles) { + for (final ChangeRoleForm role : roles) { + System.out.println(role.roleId()); + this.rolesDAO.update(role.roleId(), role.title(), role.color(), role.rank()); + } + } + @ResponseBody @PermissionRequired(NamedPermission.VIEW_STATS) @GetMapping(path = "/stats", produces = MediaType.APPLICATION_JSON_VALUE) diff --git a/backend/src/main/java/io/papermc/hangar/db/dao/internal/table/roles/RolesDAO.java b/backend/src/main/java/io/papermc/hangar/db/dao/internal/table/roles/RolesDAO.java index 96dda6bcb..1206d71f4 100644 --- a/backend/src/main/java/io/papermc/hangar/db/dao/internal/table/roles/RolesDAO.java +++ b/backend/src/main/java/io/papermc/hangar/db/dao/internal/table/roles/RolesDAO.java @@ -1,6 +1,7 @@ package io.papermc.hangar.db.dao.internal.table.roles; import io.papermc.hangar.model.db.roles.RoleTable; +import org.checkerframework.checker.nullness.qual.Nullable; import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper; import org.jdbi.v3.sqlobject.customizer.BindBean; import org.jdbi.v3.sqlobject.customizer.Timestamped; @@ -16,6 +17,9 @@ public interface RolesDAO { @SqlUpdate("INSERT INTO roles VALUES (:id, :now, :name, :category, :title, :color, :assignable, :rank, cast(:permission AS bit(64)))") void insert(@BindBean RoleTable roleTable); + @SqlUpdate("UPDATE roles VALUES SET title = :title, color = :color, rank = :rank WHERE id = :id") + void update(long id, String title, String color, @Nullable Integer rank); + @SqlQuery("SELECT id, created_at, name, category, title, color, assignable, rank, permission::bigint FROM roles WHERE id = :id") RoleTable getById(long id); } diff --git a/backend/src/main/java/io/papermc/hangar/model/db/roles/RoleTable.java b/backend/src/main/java/io/papermc/hangar/model/db/roles/RoleTable.java index cc0bf7849..fd8871083 100644 --- a/backend/src/main/java/io/papermc/hangar/model/db/roles/RoleTable.java +++ b/backend/src/main/java/io/papermc/hangar/model/db/roles/RoleTable.java @@ -30,7 +30,7 @@ public class RoleTable extends Table implements Named { this.permission = permission; } - private RoleTable(final long id, final String name, final RoleCategory category, final String title, final String color, final boolean assignable, final Integer rank, final Permission permission) { + public RoleTable(final long id, final String name, final RoleCategory category, final String title, final String color, final boolean assignable, final Integer rank, final Permission permission) { super(id); this.name = name; this.category = category; diff --git a/backend/src/main/java/io/papermc/hangar/model/internal/api/requests/admin/ChangeRoleForm.java b/backend/src/main/java/io/papermc/hangar/model/internal/api/requests/admin/ChangeRoleForm.java new file mode 100644 index 000000000..fadf89255 --- /dev/null +++ b/backend/src/main/java/io/papermc/hangar/model/internal/api/requests/admin/ChangeRoleForm.java @@ -0,0 +1,7 @@ +package io.papermc.hangar.model.internal.api.requests.admin; + +import jakarta.validation.constraints.NotBlank; +import org.checkerframework.checker.nullness.qual.Nullable; + +public record ChangeRoleForm(long roleId, @NotBlank String title, @NotBlank String color, @Nullable Integer rank) { +} diff --git a/backend/src/main/java/io/papermc/hangar/service/internal/perms/roles/GlobalRoleService.java b/backend/src/main/java/io/papermc/hangar/service/internal/perms/roles/GlobalRoleService.java index d529a073a..35106f010 100644 --- a/backend/src/main/java/io/papermc/hangar/service/internal/perms/roles/GlobalRoleService.java +++ b/backend/src/main/java/io/papermc/hangar/service/internal/perms/roles/GlobalRoleService.java @@ -5,11 +5,13 @@ import io.papermc.hangar.model.common.roles.GlobalRole; import io.papermc.hangar.model.db.roles.GlobalRoleTable; import java.util.List; import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class GlobalRoleService extends RoleService { + @Autowired public GlobalRoleService(final GlobalRolesDAO roleDao) { super(roleDao); } diff --git a/frontend/src/components/layout/Header.vue b/frontend/src/components/layout/Header.vue index aa5b7f256..53ccf77d3 100644 --- a/frontend/src/components/layout/Header.vue +++ b/frontend/src/components/layout/Header.vue @@ -341,8 +341,8 @@ function isRecent(date: string): boolean { {{ t("nav.user.stats") }} {{ t("nav.user.health") }} {{ t("nav.user.log") }} - - {{ t("nav.user.platformVersions") }} + + {{ t("nav.user.adminSettings") }} {{ t("nav.user.userList") }} diff --git a/frontend/src/lib b/frontend/src/lib index 6cac2d63b..e6e51d36f 160000 --- a/frontend/src/lib +++ b/frontend/src/lib @@ -1 +1 @@ -Subproject commit 6cac2d63bb9d266665b4931cf99bfb6b5742c23e +Subproject commit e6e51d36f08276d341a6a8eebc44426848405128 diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 712013468..f6e0424aa 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -91,7 +91,7 @@ "stats": "Stats", "health": "Hangar Health", "log": "User Action Log", - "platformVersions": "Platform Versions", + "adminSettings": "Admin settings", "userList": "User List", "logout": "Sign out", "error": { diff --git a/frontend/src/pages/admin/versions.vue b/frontend/src/pages/admin/settings.vue similarity index 60% rename from frontend/src/pages/admin/versions.vue rename to frontend/src/pages/admin/settings.vue index a799ec2a2..23963c552 100644 --- a/frontend/src/pages/admin/versions.vue +++ b/frontend/src/pages/admin/settings.vue @@ -1,8 +1,7 @@ diff --git a/frontend/src/types/api/users.d.ts b/frontend/src/types/api/users.d.ts index 340645e18..86da94fb3 100644 --- a/frontend/src/types/api/users.d.ts +++ b/frontend/src/types/api/users.d.ts @@ -7,7 +7,7 @@ declare module "hangar-api" { rank?: number | null; value: string; roleId: number; - category: RoleCategory; + roleCategory: RoleCategory; permissions: string; title: string; color: string;