The main server, and probably only repository in this org.
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

  1. package controllers
  2. import (
  3. "database/sql"
  4. "encoding/json"
  5. "fmt"
  6. "log"
  7. "net/http"
  8. "strconv"
  9. "git.aiterp.net/lucifer/lucifer/internal/httperr"
  10. "git.aiterp.net/lucifer/lucifer/internal/respond"
  11. "git.aiterp.net/lucifer/lucifer/models"
  12. "github.com/gorilla/mux"
  13. )
  14. // The GroupController is a controller for all group stuff.
  15. type GroupController struct {
  16. groups models.GroupRepository
  17. users models.UserRepository
  18. lights models.LightRepository
  19. }
  20. // getGroups (`GET /:id`): Get user by id
  21. func (c *GroupController) getGroups(w http.ResponseWriter, r *http.Request) {
  22. user := models.UserFromContext(r.Context())
  23. groups, err := c.groups.ListByUser(r.Context(), *user)
  24. if err != nil {
  25. log.Printf("Getting groups for user %s (%d) failed: %s", user.Name, user.ID, err)
  26. respond.Error(w, http.StatusInternalServerError, "internal_error", "Failed to get groups.")
  27. return
  28. }
  29. respond.Data(w, groups)
  30. }
  31. // getGroup (`GET /:group_id`): Get user by id
  32. func (c *GroupController) getGroup(w http.ResponseWriter, r *http.Request) {
  33. session := models.SessionFromContext(r.Context())
  34. idStr := mux.Vars(r)["group_id"]
  35. id, err := strconv.ParseInt(idStr, 10, 32)
  36. if err != nil {
  37. respond.Error(w, http.StatusBadRequest, "invalid_id", "The id"+idStr+"is not valid.")
  38. return
  39. }
  40. group, err := c.groups.FindByID(r.Context(), int(id))
  41. if err != nil || !group.Permission(session.UserID).Read {
  42. respond.Error(w, http.StatusNotFound, "not_found", "The group cannot be found or you are not authorized to view it.")
  43. return
  44. }
  45. respond.Data(w, group)
  46. }
  47. // getGroupLights (`GET /:group_id/light/`): Get user by id
  48. func (c *GroupController) getGroupLights(w http.ResponseWriter, r *http.Request) {
  49. session := models.SessionFromContext(r.Context())
  50. idStr := mux.Vars(r)["group_id"]
  51. id, err := strconv.ParseInt(idStr, 10, 32)
  52. if err != nil {
  53. respond.Error(w, http.StatusBadRequest, "invalid_id", "The id "+idStr+" is not valid.")
  54. return
  55. }
  56. group, err := c.groups.FindByID(r.Context(), int(id))
  57. if err != nil || !group.Permission(session.UserID).Read {
  58. respond.Error(w, http.StatusNotFound, "group_not_found", "The group cannot be found or you are not authorized to view it.")
  59. return
  60. }
  61. lights, err := c.lights.ListByGroup(r.Context(), group)
  62. if err != nil && err != sql.ErrNoRows {
  63. log.Printf("Getting lights for group %s (%d) failed: %s", group.Name, group.ID, err)
  64. respond.Error(w, http.StatusInternalServerError, "internal_error", "Failed to get groups.")
  65. return
  66. }
  67. respond.Data(w, lights)
  68. }
  69. // getGroupLight (`GET /:group_id/light/:light_id`): Get user by id
  70. func (c *GroupController) getGroupLight(w http.ResponseWriter, r *http.Request) {
  71. session := models.SessionFromContext(r.Context())
  72. groupIDStr := mux.Vars(r)["group_id"]
  73. groupID, err := strconv.ParseInt(groupIDStr, 10, 32)
  74. if err != nil {
  75. respond.Error(w, http.StatusBadRequest, "invalid_id", "The group id "+groupIDStr+" is not valid.")
  76. return
  77. }
  78. idStr := mux.Vars(r)["light_id"]
  79. id, err := strconv.ParseInt(idStr, 10, 32)
  80. if err != nil {
  81. respond.Error(w, http.StatusBadRequest, "invalid_id", "The light id "+idStr+" is not valid.")
  82. return
  83. }
  84. group, err := c.groups.FindByID(r.Context(), int(groupID))
  85. if err != nil || !group.Permission(session.UserID).Read {
  86. respond.Error(w, http.StatusNotFound, "group_not_found", "The group cannot be found or you are not authorized to view it.")
  87. return
  88. }
  89. light, err := c.lights.FindByID(r.Context(), int(id))
  90. if err != nil || light.GroupID != group.ID {
  91. fmt.Println(light, id)
  92. respond.Error(w, http.StatusNotFound, "light_not_found", "The light cannot be found in this group.")
  93. return
  94. }
  95. respond.Data(w, light)
  96. }
  97. // postGroup (`POST /`): Create a group.
  98. func (c *GroupController) postGroup(w http.ResponseWriter, r *http.Request) {
  99. user := models.UserFromContext(r.Context())
  100. postData := struct {
  101. Name string
  102. }{}
  103. if err := json.NewDecoder(r.Body).Decode(&postData); err != nil {
  104. respond.Error(w, http.StatusBadRequest, "invalid_json", "Input is not valid JSON.")
  105. return
  106. }
  107. if postData.Name == "" {
  108. respond.Error(w, http.StatusBadRequest, "invalid_name", "The name cannot be blank.")
  109. return
  110. }
  111. group, err := c.groups.Insert(r.Context(), models.Group{Name: postData.Name})
  112. if err != nil {
  113. httperr.Respond(w, err)
  114. return
  115. }
  116. permission := models.GroupPermission{
  117. GroupID: group.ID,
  118. UserID: user.ID,
  119. Read: true,
  120. Write: true,
  121. Delete: true,
  122. Create: true,
  123. Manage: true,
  124. }
  125. err = c.groups.UpdatePermissions(r.Context(), permission)
  126. if err != nil {
  127. httperr.Respond(w, err)
  128. return
  129. }
  130. group.Permissions = []models.GroupPermission{permission}
  131. respond.Data(w, group)
  132. }
  133. // updateGroup (`PUT/PATCH /:group_id`): Create a group.
  134. func (c *GroupController) updateGroup(w http.ResponseWriter, r *http.Request) {
  135. user := models.UserFromContext(r.Context())
  136. groupIDStr := mux.Vars(r)["group_id"]
  137. groupID, err := strconv.ParseInt(groupIDStr, 10, 32)
  138. if err != nil {
  139. respond.Error(w, http.StatusBadRequest, "invalid_id", "The group id "+groupIDStr+" is not valid.")
  140. return
  141. }
  142. postData := struct {
  143. Name string
  144. }{}
  145. if err := json.NewDecoder(r.Body).Decode(&postData); err != nil {
  146. respond.Error(w, http.StatusBadRequest, "invalid_json", "Input is not valid JSON.")
  147. return
  148. }
  149. if postData.Name == "" {
  150. respond.Error(w, http.StatusBadRequest, "invalid_name", "The name cannot be blank.")
  151. return
  152. }
  153. group, err := c.groups.FindByID(r.Context(), int(groupID))
  154. if err != nil {
  155. respond.Error(w, http.StatusNotFound, "group_not_found", "The group cannot be found or you are not authorized to view it.")
  156. return
  157. } else if !group.Permission(user.ID).Manage {
  158. respond.Error(w, http.StatusNotFound, "permission_denied", "Your transgression will be remembered.")
  159. return
  160. }
  161. group.Name = postData.Name
  162. err = c.groups.Update(r.Context(), group)
  163. if err != nil {
  164. httperr.Respond(w, err)
  165. return
  166. }
  167. respond.Data(w, group)
  168. }
  169. // updateGroupPermission (`PUT/PATCH /:group_id/permission/:user_id`): Update a user's permission on a group.
  170. func (c *GroupController) updateGroupPermission(w http.ResponseWriter, r *http.Request) {
  171. user := models.UserFromContext(r.Context())
  172. groupIDStr := mux.Vars(r)["group_id"]
  173. groupID, err := strconv.ParseInt(groupIDStr, 10, 32)
  174. if err != nil {
  175. respond.Error(w, http.StatusBadRequest, "invalid_id", "The group id "+groupIDStr+" is not valid.")
  176. return
  177. }
  178. userIDStr := mux.Vars(r)["user_id"]
  179. userID, err := strconv.ParseInt(userIDStr, 10, 32)
  180. if err != nil {
  181. respond.Error(w, http.StatusBadRequest, "invalid_id", "The user id "+userIDStr+" is not valid.")
  182. return
  183. }
  184. putData := struct {
  185. Read *bool `json:"read"`
  186. Write *bool `json:"write"`
  187. Create *bool `json:"create"`
  188. Delete *bool `json:"delete"`
  189. Manage *bool `json:"manage"`
  190. }{}
  191. if err := json.NewDecoder(r.Body).Decode(&putData); err != nil {
  192. respond.Error(w, http.StatusBadRequest, "invalid_json", "Input is not valid JSON.")
  193. return
  194. }
  195. if putData.Manage != nil {
  196. respond.Error(w, http.StatusBadRequest, "cannot_change_manage", "You cannot change the manage permission.")
  197. return
  198. }
  199. group, err := c.groups.FindByID(r.Context(), int(groupID))
  200. if err != nil {
  201. respond.Error(w, http.StatusNotFound, "group_not_found", "The group could not be found.")
  202. return
  203. } else if !group.Permission(user.ID).Manage {
  204. respond.Error(w, http.StatusForbidden, "permission_denied", "This transgression has been dispatched to the North Pole for review.")
  205. return
  206. }
  207. user2, err := c.users.FindByID(r.Context(), int(userID))
  208. if err == sql.ErrNoRows {
  209. respond.Error(w, http.StatusNotFound, "user_not_Found", "The user could not be found.")
  210. return
  211. } else if err != nil {
  212. httperr.Respond(w, err)
  213. return
  214. }
  215. permissions := group.Permission(user2.ID)
  216. if putData.Read != nil {
  217. permissions.Read = *putData.Read
  218. }
  219. if putData.Write != nil {
  220. permissions.Write = *putData.Write
  221. }
  222. if putData.Create != nil {
  223. permissions.Create = *putData.Create
  224. }
  225. if putData.Delete != nil {
  226. permissions.Delete = *putData.Delete
  227. }
  228. err = c.groups.UpdatePermissions(r.Context(), permissions)
  229. if err != nil {
  230. httperr.Respond(w, err)
  231. return
  232. }
  233. respond.Data(w, permissions)
  234. }
  235. // deleteGroup (`DELETE /:group_id`): Delete a group.
  236. func (c *GroupController) deleteGroup(w http.ResponseWriter, r *http.Request) {
  237. user := models.UserFromContext(r.Context())
  238. groupIDStr := mux.Vars(r)["group_id"]
  239. groupID, err := strconv.ParseInt(groupIDStr, 10, 32)
  240. if err != nil {
  241. respond.Error(w, http.StatusBadRequest, "invalid_id", "The group id "+groupIDStr+" is not valid.")
  242. return
  243. }
  244. group, err := c.groups.FindByID(r.Context(), int(groupID))
  245. if err != nil {
  246. respond.Error(w, http.StatusNotFound, "group_not_found", "The group cannot be found.")
  247. return
  248. } else if !group.Permission(user.ID).Manage {
  249. respond.Error(w, http.StatusNotFound, "permission_denied", "Your transgression will be remembered.")
  250. return
  251. }
  252. lights, err := c.lights.ListByGroup(r.Context(), group)
  253. if err != nil && err != sql.ErrNoRows {
  254. httperr.Respond(w, err)
  255. return
  256. }
  257. for _, light := range lights {
  258. light.GroupID = 0
  259. err := c.lights.Update(r.Context(), light)
  260. if err != nil {
  261. httperr.Respond(w, err)
  262. return
  263. }
  264. }
  265. err = c.groups.Remove(r.Context(), group)
  266. if err != nil {
  267. httperr.Respond(w, err)
  268. return
  269. }
  270. respond.Data(w, group)
  271. }
  272. // Mount mounts the controller
  273. func (c *GroupController) Mount(router *mux.Router, prefix string) {
  274. sub := router.PathPrefix(prefix).Subrouter()
  275. sub.HandleFunc("/", c.getGroups).Methods("GET")
  276. sub.HandleFunc("/", c.postGroup).Methods("POST")
  277. sub.HandleFunc("/{group_id}", c.getGroup).Methods("GET")
  278. sub.HandleFunc("/{group_id}", c.updateGroup).Methods("PUT", "PATCH")
  279. sub.HandleFunc("/{group_id}", c.deleteGroup).Methods("DELETE")
  280. sub.HandleFunc("/{group_id}/permission/{user_id}", c.updateGroupPermission).Methods("PUT", "PATCH")
  281. sub.HandleFunc("/{group_id}/light/", c.getGroupLights).Methods("GET")
  282. sub.HandleFunc("/{group_id}/light/{light_id}", c.getGroupLight).Methods("GET")
  283. }
  284. // NewGroupController creates a new GroupController.
  285. func NewGroupController(groups models.GroupRepository, users models.UserRepository, lights models.LightRepository) *GroupController {
  286. return &GroupController{groups: groups, users: users, lights: lights}
  287. }