diff --git a/controllers/group-controller.go b/controllers/group-controller.go index 97ca3e6..45aa908 100644 --- a/controllers/group-controller.go +++ b/controllers/group-controller.go @@ -2,11 +2,14 @@ package controllers import ( "database/sql" + "encoding/json" "fmt" "log" "net/http" "strconv" + "git.aiterp.net/lucifer/lucifer/internal/httperr" + "git.aiterp.net/lucifer/lucifer/internal/respond" "git.aiterp.net/lucifer/lucifer/models" "github.com/gorilla/mux" @@ -33,11 +36,11 @@ func (c *GroupController) getGroups(w http.ResponseWriter, r *http.Request) { respond.Data(w, groups) } -// getGroup (`GET /:id`): Get user by id +// getGroup (`GET /:group_id`): Get user by id func (c *GroupController) getGroup(w http.ResponseWriter, r *http.Request) { session := models.SessionFromContext(r.Context()) - idStr := mux.Vars(r)["id"] + idStr := mux.Vars(r)["group_id"] id, err := strconv.ParseInt(idStr, 10, 32) if err != nil { respond.Error(w, http.StatusBadRequest, "invalid_id", "The id"+idStr+"is not valid.") @@ -53,11 +56,11 @@ func (c *GroupController) getGroup(w http.ResponseWriter, r *http.Request) { respond.Data(w, group) } -// getGroupLights (`GET /:id/light/`): Get user by id +// getGroupLights (`GET /:group_id/light/`): Get user by id func (c *GroupController) getGroupLights(w http.ResponseWriter, r *http.Request) { session := models.SessionFromContext(r.Context()) - idStr := mux.Vars(r)["id"] + idStr := mux.Vars(r)["group_id"] id, err := strconv.ParseInt(idStr, 10, 32) if err != nil { respond.Error(w, http.StatusBadRequest, "invalid_id", "The id "+idStr+" is not valid.") @@ -80,7 +83,7 @@ func (c *GroupController) getGroupLights(w http.ResponseWriter, r *http.Request) respond.Data(w, lights) } -// getGroupLight (`GET /:group_id/light/:id`): Get user by id +// getGroupLight (`GET /:group_id/light/:light_id`): Get user by id func (c *GroupController) getGroupLight(w http.ResponseWriter, r *http.Request) { session := models.SessionFromContext(r.Context()) @@ -91,7 +94,7 @@ func (c *GroupController) getGroupLight(w http.ResponseWriter, r *http.Request) return } - idStr := mux.Vars(r)["id"] + idStr := mux.Vars(r)["light_id"] id, err := strconv.ParseInt(idStr, 10, 32) if err != nil { respond.Error(w, http.StatusBadRequest, "invalid_id", "The light id "+idStr+" is not valid.") @@ -114,14 +117,100 @@ func (c *GroupController) getGroupLight(w http.ResponseWriter, r *http.Request) respond.Data(w, light) } +// postGroup (`POST /`): Create a group. +func (c *GroupController) postGroup(w http.ResponseWriter, r *http.Request) { + user := models.UserFromContext(r.Context()) + + postData := struct { + Name string + }{} + if err := json.NewDecoder(r.Body).Decode(&postData); err != nil { + respond.Error(w, http.StatusBadRequest, "invalid_json", "Input is not valid JSON.") + return + } + if postData.Name == "" { + respond.Error(w, http.StatusBadRequest, "invalid_name", "The name cannot be blank.") + return + } + + group, err := c.groups.Insert(r.Context(), models.Group{Name: postData.Name}) + if err != nil { + httperr.Respond(w, err) + return + } + + permission := models.GroupPermission{ + GroupID: group.ID, + UserID: user.ID, + Read: true, + Write: true, + Delete: true, + Create: true, + Manage: true, + } + + err = c.groups.UpdatePermissions(r.Context(), permission) + if err != nil { + httperr.Respond(w, err) + return + } + + group.Permissions = []models.GroupPermission{permission} + respond.Data(w, group) +} + +// updateGroup (`PUT/PATCH /:group_id`): Create a group. +func (c *GroupController) updateGroup(w http.ResponseWriter, r *http.Request) { + user := models.UserFromContext(r.Context()) + + groupIDStr := mux.Vars(r)["group_id"] + groupID, err := strconv.ParseInt(groupIDStr, 10, 32) + if err != nil { + respond.Error(w, http.StatusBadRequest, "invalid_id", "The group id "+groupIDStr+" is not valid.") + return + } + + postData := struct { + Name string + }{} + if err := json.NewDecoder(r.Body).Decode(&postData); err != nil { + respond.Error(w, http.StatusBadRequest, "invalid_json", "Input is not valid JSON.") + return + } + if postData.Name == "" { + respond.Error(w, http.StatusBadRequest, "invalid_name", "The name cannot be blank.") + return + } + + group, err := c.groups.FindByID(r.Context(), int(groupID)) + if err != nil { + respond.Error(w, http.StatusNotFound, "group_not_found", "The group cannot be found or you are not authorized to view it.") + return + } else if !group.Permission(user.ID).Manage { + respond.Error(w, http.StatusNotFound, "permission_denied", "Your transgression will be remembered.") + return + } + + group.Name = postData.Name + err = c.groups.Update(r.Context(), group) + if err != nil { + httperr.Respond(w, err) + return + } + + respond.Data(w, group) +} + // Mount mounts the controller func (c *GroupController) Mount(router *mux.Router, prefix string) { sub := router.PathPrefix(prefix).Subrouter() sub.HandleFunc("/", c.getGroups).Methods("GET") - sub.HandleFunc("/{id}", c.getGroup).Methods("GET") - sub.HandleFunc("/{id}/light/", c.getGroupLights).Methods("GET") - sub.HandleFunc("/{group_id}/light/{id}", c.getGroupLight).Methods("GET") + sub.HandleFunc("/", c.postGroup).Methods("POST") + sub.HandleFunc("/{group_id}", c.getGroup).Methods("GET") + sub.HandleFunc("/{group_id}", c.updateGroup).Methods("PUT", "PATCH") + sub.HandleFunc("/{group_id}/light/", c.getGroupLights).Methods("GET") + sub.HandleFunc("/{group_id}/light/{light_id}", c.getGroupLight).Methods("GET") } // NewGroupController creates a new GroupController. diff --git a/database/sqlite/group-repository.go b/database/sqlite/group-repository.go index 0028217..ee75f80 100644 --- a/database/sqlite/group-repository.go +++ b/database/sqlite/group-repository.go @@ -110,11 +110,22 @@ func (r *groupRepository) ListByUser(ctx context.Context, user models.User) ([]m } func (r *groupRepository) Insert(ctx context.Context, group models.Group) (models.Group, error) { - panic("not implemented") + res, err := db.NamedExecContext(ctx, "INSERT INTO `group` (name) VALUES(:name)", group) + if err != nil { + return models.Group{}, err + } + + id, err := res.LastInsertId() + if err != nil { + return models.Group{}, err + } + + group.ID = int(id) + return group, nil } func (r *groupRepository) Update(ctx context.Context, group models.Group) error { - _, err := db.NamedExecContext(ctx, "UPDATE group SET name=:name WHERE id=:id", group) + _, err := db.NamedExecContext(ctx, "UPDATE `group` SET name=:name WHERE id=:id", group) return err } @@ -124,7 +135,7 @@ func (r *groupRepository) UpdatePermissions(ctx context.Context, permission mode } func (r *groupRepository) Remove(ctx context.Context, group models.Group) error { - _, err := db.NamedExecContext(ctx, "DELETE FROM group WHERE id=:id LIMIT 1", group) + _, err := db.NamedExecContext(ctx, "DELETE FROM `group` WHERE id=:id LIMIT 1", group) return err }