You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
340 lines
10 KiB
340 lines
10 KiB
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"
|
|
)
|
|
|
|
// The GroupController is a controller for all group stuff.
|
|
type GroupController struct {
|
|
groups models.GroupRepository
|
|
users models.UserRepository
|
|
lights models.LightRepository
|
|
}
|
|
|
|
// getGroups (`GET /:id`): Get user by id
|
|
func (c *GroupController) getGroups(w http.ResponseWriter, r *http.Request) {
|
|
user := models.UserFromContext(r.Context())
|
|
|
|
groups, err := c.groups.ListByUser(r.Context(), *user)
|
|
if err != nil {
|
|
log.Printf("Getting groups for user %s (%d) failed: %s", user.Name, user.ID, err)
|
|
respond.Error(w, http.StatusInternalServerError, "internal_error", "Failed to get groups.")
|
|
return
|
|
}
|
|
|
|
respond.Data(w, groups)
|
|
}
|
|
|
|
// 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)["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.")
|
|
return
|
|
}
|
|
|
|
group, err := c.groups.FindByID(r.Context(), int(id))
|
|
if err != nil || !group.Permission(session.UserID).Read {
|
|
respond.Error(w, http.StatusNotFound, "not_found", "The group cannot be found or you are not authorized to view it.")
|
|
return
|
|
}
|
|
|
|
respond.Data(w, group)
|
|
}
|
|
|
|
// 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)["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.")
|
|
return
|
|
}
|
|
|
|
group, err := c.groups.FindByID(r.Context(), int(id))
|
|
if err != nil || !group.Permission(session.UserID).Read {
|
|
respond.Error(w, http.StatusNotFound, "group_not_found", "The group cannot be found or you are not authorized to view it.")
|
|
return
|
|
}
|
|
|
|
lights, err := c.lights.ListByGroup(r.Context(), group)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
log.Printf("Getting lights for group %s (%d) failed: %s", group.Name, group.ID, err)
|
|
respond.Error(w, http.StatusInternalServerError, "internal_error", "Failed to get groups.")
|
|
return
|
|
}
|
|
|
|
respond.Data(w, lights)
|
|
}
|
|
|
|
// 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())
|
|
|
|
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
|
|
}
|
|
|
|
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.")
|
|
return
|
|
}
|
|
|
|
group, err := c.groups.FindByID(r.Context(), int(groupID))
|
|
if err != nil || !group.Permission(session.UserID).Read {
|
|
respond.Error(w, http.StatusNotFound, "group_not_found", "The group cannot be found or you are not authorized to view it.")
|
|
return
|
|
}
|
|
|
|
light, err := c.lights.FindByID(r.Context(), int(id))
|
|
if err != nil || light.GroupID != group.ID {
|
|
fmt.Println(light, id)
|
|
respond.Error(w, http.StatusNotFound, "light_not_found", "The light cannot be found in this group.")
|
|
return
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
// updateGroupPermission (`PUT/PATCH /:group_id/permission/:user_id`): Update a user's permission on a group.
|
|
func (c *GroupController) updateGroupPermission(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
|
|
}
|
|
|
|
userIDStr := mux.Vars(r)["user_id"]
|
|
userID, err := strconv.ParseInt(userIDStr, 10, 32)
|
|
if err != nil {
|
|
respond.Error(w, http.StatusBadRequest, "invalid_id", "The user id "+userIDStr+" is not valid.")
|
|
return
|
|
}
|
|
|
|
putData := struct {
|
|
Read *bool `json:"read"`
|
|
Write *bool `json:"write"`
|
|
Create *bool `json:"create"`
|
|
Delete *bool `json:"delete"`
|
|
Manage *bool `json:"manage"`
|
|
}{}
|
|
if err := json.NewDecoder(r.Body).Decode(&putData); err != nil {
|
|
respond.Error(w, http.StatusBadRequest, "invalid_json", "Input is not valid JSON.")
|
|
return
|
|
}
|
|
if putData.Manage != nil {
|
|
respond.Error(w, http.StatusBadRequest, "cannot_change_manage", "You cannot change the manage permission.")
|
|
return
|
|
}
|
|
|
|
group, err := c.groups.FindByID(r.Context(), int(groupID))
|
|
if err != nil {
|
|
respond.Error(w, http.StatusNotFound, "group_not_found", "The group could not be found.")
|
|
return
|
|
} else if !group.Permission(user.ID).Manage {
|
|
respond.Error(w, http.StatusForbidden, "permission_denied", "This transgression has been dispatched to the North Pole for review.")
|
|
return
|
|
}
|
|
|
|
user2, err := c.users.FindByID(r.Context(), int(userID))
|
|
if err == sql.ErrNoRows {
|
|
respond.Error(w, http.StatusNotFound, "user_not_Found", "The user could not be found.")
|
|
return
|
|
} else if err != nil {
|
|
httperr.Respond(w, err)
|
|
return
|
|
}
|
|
|
|
permissions := group.Permission(user2.ID)
|
|
if putData.Read != nil {
|
|
permissions.Read = *putData.Read
|
|
}
|
|
if putData.Write != nil {
|
|
permissions.Write = *putData.Write
|
|
}
|
|
if putData.Create != nil {
|
|
permissions.Create = *putData.Create
|
|
}
|
|
if putData.Delete != nil {
|
|
permissions.Delete = *putData.Delete
|
|
}
|
|
|
|
err = c.groups.UpdatePermissions(r.Context(), permissions)
|
|
if err != nil {
|
|
httperr.Respond(w, err)
|
|
return
|
|
}
|
|
|
|
respond.Data(w, permissions)
|
|
}
|
|
|
|
// deleteGroup (`DELETE /:group_id`): Delete a group.
|
|
func (c *GroupController) deleteGroup(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
|
|
}
|
|
|
|
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.")
|
|
return
|
|
} else if !group.Permission(user.ID).Manage {
|
|
respond.Error(w, http.StatusNotFound, "permission_denied", "Your transgression will be remembered.")
|
|
return
|
|
}
|
|
|
|
lights, err := c.lights.ListByGroup(r.Context(), group)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
httperr.Respond(w, err)
|
|
return
|
|
}
|
|
|
|
for _, light := range lights {
|
|
light.GroupID = 0
|
|
err := c.lights.Update(r.Context(), light)
|
|
if err != nil {
|
|
httperr.Respond(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
err = c.groups.Remove(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("/", 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}", c.deleteGroup).Methods("DELETE")
|
|
sub.HandleFunc("/{group_id}/permission/{user_id}", c.updateGroupPermission).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.
|
|
func NewGroupController(groups models.GroupRepository, users models.UserRepository, lights models.LightRepository) *GroupController {
|
|
return &GroupController{groups: groups, users: users, lights: lights}
|
|
}
|