diff --git a/backend/handlers/handle_user.go b/backend/handlers/handle_user.go
index 6293c9a..27b53b4 100644
--- a/backend/handlers/handle_user.go
+++ b/backend/handlers/handle_user.go
@@ -14,6 +14,10 @@ type UserCredentials struct {
Password string `json:"password" binding:"required"`
}
+type SetAdminInput struct {
+ Admin *bool `json:"admin" binding:"required"`
+}
+
func (store *Store) CreateUser(ctx *gin.Context) {
claimsVal, ok := ctx.Get("userClaims")
if !ok {
@@ -101,6 +105,57 @@ func (store *Store) UpdateUser(ctx *gin.Context) {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "will be implemented"})
}
+func (store *Store) SetUserAdmin(ctx *gin.Context) {
+ claimsVal, ok := ctx.Get("userClaims")
+ if !ok {
+ ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"})
+ return
+ }
+ claims, ok := claimsVal.(*jwt.MapClaims)
+ if !ok {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"})
+ return
+ }
+ if !(*claims)["admin"].(bool) {
+ ctx.JSON(http.StatusForbidden, gin.H{"error": "admin access required"})
+ return
+ }
+
+ callerIDF, ok := (*claims)["id"].(float64)
+ if !ok {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"})
+ return
+ }
+ callerID := uint(callerIDF)
+
+ targetID := ctx.Param("id")
+
+ var input SetAdminInput
+ if err := ctx.ShouldBindBodyWithJSON(&input); err != nil {
+ ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ var user models.User
+ if err := store.DB.First(&user, targetID).Error; err != nil {
+ ctx.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
+ return
+ }
+
+ if user.ID == callerID {
+ ctx.JSON(http.StatusBadRequest, gin.H{"error": "cannot change your own admin status"})
+ return
+ }
+
+ user.Admin = *input.Admin
+ if err := store.DB.Save(&user).Error; err != nil {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+ return
+ }
+
+ ctx.JSON(http.StatusOK, user)
+}
+
func (store *Store) DeleteUser(ctx *gin.Context) {
claimsVal, ok := ctx.Get("userClaims")
if !ok {
diff --git a/backend/main.go b/backend/main.go
index 56dfaac..fb038bd 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -97,6 +97,7 @@ func main() {
protected.DELETE("/user/:id", store.DeleteUser)
r.GET("/user", store.GetUsers)
protected.POST("/user", store.CreateUser)
+ protected.PATCH("/user/:id/admin", store.SetUserAdmin)
// AUTH
r.POST("/auth/login", store.Login)
diff --git a/nginx/vue/src/stores/auth.js b/nginx/vue/src/stores/auth.js
index 93110e3..e6ab2f1 100644
--- a/nginx/vue/src/stores/auth.js
+++ b/nginx/vue/src/stores/auth.js
@@ -59,6 +59,16 @@ export const useAuthStore = defineStore("auth", () => {
}
}
+ async function setUserAdmin(userId, admin) {
+ try {
+ const res = await axios.patch(`/api/user/${userId}/admin`, { admin });
+ return res.data;
+ } catch (err) {
+ console.error(err);
+ throw err;
+ }
+ }
+
return {
user,
@@ -69,5 +79,6 @@ export const useAuthStore = defineStore("auth", () => {
refreshToken,
logOut,
createUser,
+ setUserAdmin,
};
});
diff --git a/nginx/vue/src/views/admin/Admin.vue b/nginx/vue/src/views/admin/Admin.vue
index 7fba5fc..e0a58cc 100644
--- a/nginx/vue/src/views/admin/Admin.vue
+++ b/nginx/vue/src/views/admin/Admin.vue
@@ -8,6 +8,7 @@ import CreatePost from "./CreatePost.vue";
import CreateFavorite from "./CreateFavorite.vue";
import CreateActivity from "./CreateActivity.vue";
import CreateRowing from "./CreateRowing.vue";
+import ManageUsers from "./ManageUsers.vue";
const auth = useAuthStore();
@@ -21,6 +22,7 @@ const auth = useAuthStore();
+