mgmt_api.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package http
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log/slog"
  6. "net/http"
  7. "os"
  8. "github.com/mk6i/retro-aim-server/config"
  9. "github.com/mk6i/retro-aim-server/state"
  10. "github.com/google/uuid"
  11. )
  12. type UserManager interface {
  13. AllUsers() ([]state.User, error)
  14. InsertUser(u state.User) error
  15. }
  16. func StartManagementAPI(userManager UserManager, logger *slog.Logger) {
  17. uh := userHandler{
  18. UserManager: userManager,
  19. logger: logger,
  20. }
  21. mux := http.NewServeMux()
  22. mux.HandleFunc("/user", uh.ServeHTTP)
  23. //todo make port configurable
  24. addr := config.Address("", 8080)
  25. logger.Info("starting management API server", "addr", addr)
  26. if err := http.ListenAndServe(addr, mux); err != nil {
  27. logger.Error("unable to bind management API address address", "err", err.Error())
  28. os.Exit(1)
  29. }
  30. }
  31. type userHandler struct {
  32. UserManager
  33. logger *slog.Logger
  34. }
  35. func (uh userHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  36. switch r.Method {
  37. case http.MethodGet:
  38. uh.getUsers(w, r)
  39. case http.MethodPost:
  40. uh.createUser(w, r)
  41. default:
  42. http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
  43. }
  44. }
  45. // getUsers handles the GET /user endpoint.
  46. func (uh userHandler) getUsers(w http.ResponseWriter, _ *http.Request) {
  47. w.Header().Set("Content-Type", "application/json")
  48. users, err := uh.AllUsers()
  49. if err != nil {
  50. uh.logger.Error("error in GET /user", "err", err.Error())
  51. http.Error(w, "internal server error", http.StatusInternalServerError)
  52. return
  53. }
  54. if err := json.NewEncoder(w).Encode(users); err != nil {
  55. http.Error(w, err.Error(), http.StatusInternalServerError)
  56. return
  57. }
  58. }
  59. type CreateUser struct {
  60. state.User
  61. Password string `json:"password,omitempty"`
  62. }
  63. // createUser handles the POST /user endpoint.
  64. func (uh userHandler) createUser(w http.ResponseWriter, r *http.Request) {
  65. var newUser CreateUser
  66. if err := json.NewDecoder(r.Body).Decode(&newUser); err != nil {
  67. http.Error(w, "malformed input", http.StatusBadRequest)
  68. return
  69. }
  70. newUser.AuthKey = uuid.New().String()
  71. // todo does the request contain authkey?
  72. newUser.HashPassword(newUser.Password)
  73. if err := uh.InsertUser(newUser.User); err != nil {
  74. uh.logger.Error("error in GET /user", "err", err.Error())
  75. http.Error(w, "internal server error", http.StatusInternalServerError)
  76. return
  77. }
  78. w.WriteHeader(http.StatusCreated)
  79. fmt.Fprintln(w, "User account created successfully.")
  80. }