api.spaceplanner.app

Spaceplanner API
git clone git://jacobedwards.org/api.spaceplanner.app
Log | Files | Refs

users.go (4955B)


      1 package main
      2 
      3 import (
      4 	"log"
      5 	"net/http"
      6 
      7 	"github.com/gin-gonic/gin"
      8 	"jacobedwards.org/spaceplanner.app/internal/backend"
      9 )
     10 
     11 type CreateUserParams struct {
     12 	Creds Credentials `json:"credentials" binding:"required"`
     13 	Email string `json:"email" binding:"required"`
     14 	EmailStrict *bool `json:"email_strict"`
     15 }
     16 
     17 type CodeReq struct {
     18 	Code string `json:"code"`
     19 }
     20 
     21 func (e *Env) CreateUser(c *gin.Context) {
     22 	var params CreateUserParams
     23 	if err := c.ShouldBind(&params); err != nil {
     24 		RespondError(c, http.StatusUnauthorized, "Unable to create user: %s", err.Error())
     25 		return
     26 	}
     27 
     28 	user, err := e.backend.CreateUser(params.Creds.Username, params.Creds.Password)
     29 	if err != nil {
     30 		RespondError(c, http.StatusBadRequest,
     31 		    "Unable to create user: %s", err.Error())
     32 		return
     33 	}
     34 
     35 	err = e.backend.UpdateUserSetting(nil, user.Name, "email", params.Email)
     36 	if err == nil && params.EmailStrict != nil {
     37 		err = e.backend.UpdateUserSetting(nil, user.Name, "email_strict", *params.EmailStrict)
     38 	}
     39 	if err != nil {
     40 		RespondError(c, 400, "Invalid Email or Email Policy: %s", err.Error())
     41 		err2 := e.backend.DeleteUser(user.Name)
     42 		if err2 != nil {
     43 			log.Printf("%s: User cannot be deleted: %s", user.Name, err2.Error())
     44 		}
     45 		return
     46 	}
     47 
     48 	if _, err := e.backend.VerifyEmail(user.Name, nil); err != nil {
     49 		log.Printf("Unable to send verification email: %s", err.Error())
     50 	}
     51 
     52 	Respond(c, http.StatusCreated, user)
     53 }
     54 
     55 func (e *Env) VerifiedUserEmail(c *gin.Context) {
     56 	user := c.Param("user")
     57 
     58 	emails, err := e.backend.UserEmails(user)
     59 	if err != nil {
     60 		RespondError(c, 500, "Unable to get user's emails")
     61 	} else {
     62 		Respond(c, 200, emails.Verified)
     63 	}
     64 }
     65 
     66 func (e *Env) VerifyUserEmailCode(c *gin.Context) {
     67 	user := c.Param("user")
     68 	var req CodeReq
     69 
     70 	if err := c.ShouldBind(&req); err != nil {
     71 		RespondError(c, 400, "Unable to read request: %s", err.Error())
     72 		return
     73 	}
     74 	if verified, err := e.backend.VerifyEmail(user, &req.Code); err != nil {
     75 		RespondError(c, 500, "Unable to verify email: %s", err.Error())
     76 	} else {
     77 		Respond(c, 200, gin.H{"valid": verified})
     78 	}
     79 }
     80 
     81 func (e *Env) SendUserEmailCode(c *gin.Context) {
     82 	user := c.Param("user")
     83 
     84 	if err := e.backend.SendVerificationEmail(user); err != nil {
     85 		RespondError(c, 500, "Unable to send verification email: %s", err.Error())
     86 	} else {
     87 		Respond(c, 200, nil)
     88 	}
     89 }
     90 
     91 func (e *Env) DeleteUser(c *gin.Context) {
     92 	user := c.Param("user")
     93 	err := e.backend.DeleteUser(user)
     94 	if err != nil {
     95 		RespondError(c, http.StatusBadRequest, "Unable to delete user: %s", err.Error())
     96 		return
     97 	}
     98 	Respond(c, http.StatusOK, backend.User{ Name: user })
     99 }
    100 
    101 func (e *Env) GetUser(c *gin.Context) {
    102 	name := c.Param("user")
    103 	if name == "" {
    104 		RespondError(c, http.StatusNotFound, "No username given")
    105 		return
    106 	}
    107 
    108 	user, err := e.backend.GetUser(nil, name)
    109 	if err != nil {
    110 		RespondError(c, http.StatusOK, "%q: Unable to get user: %s",
    111 		    name, err.Error())
    112 		return
    113 	}
    114 
    115 	Respond(c, http.StatusOK, user)
    116 }
    117 
    118 func (e *Env) GetUserSettings(c *gin.Context) {
    119 	user := c.Param("user")
    120 	if user == "" {
    121 		RespondError(c, http.StatusNotFound, "No username given")
    122 		return
    123 	}
    124 
    125 	settings, err := e.backend.GetUserSettings(nil, user)
    126 	if err != nil {
    127 		RespondError(c, 400, "Unable to get settings: %s", err.Error())
    128 	} else {
    129 		Respond(c, http.StatusOK, settings)
    130 	}
    131 }
    132 
    133 func (e *Env) UpdateUserSettings(c *gin.Context) {
    134 	user := c.Param("user")
    135 	if user == "" {
    136 		RespondError(c, http.StatusNotFound, "No username given")
    137 		return
    138 	}
    139 
    140 	patches := make([]backend.Patch, 16)
    141 	if err := c.ShouldBind(&patches); err != nil {
    142 		RespondError(c, 400, "Unable to read patchset")
    143 		return
    144 	}
    145 
    146 	tx, err := e.backend.DB.Begin()
    147 	if err != nil {
    148 		RespondError(c, 500, "Unable to begin transaction")
    149 		return
    150 	}
    151 	defer tx.Rollback()
    152 
    153 	settings, err := e.backend.GetUserSettings(tx, user)
    154 	if err != nil {
    155 		RespondError(c, 400, "Unable to get settings")
    156 		return
    157 	}
    158 
    159 	if err = applyPatchset(settings, patches); err != nil {
    160 		RespondError(c, 400, "Unable to apply patches: %s", err.Error())
    161 		return
    162 	}
    163 
    164 	if _, err := e.backend.DeleteUserSettings(tx, user); err != nil {
    165 		RespondError(c, 400, "Unable to truncate settings: %s", err.Error())
    166 		return
    167 	}
    168 	if err := e.backend.UpdateUserSettings(tx, user, settings); err != nil {
    169 		RespondError(c, 400, "Unable to set settings: %s", err.Error())
    170 		return
    171 	}
    172 	if err = tx.Commit(); err != nil {
    173 		RespondError(c, 400, "Unable to commit transaction: %s", err.Error())
    174 		return
    175 	}
    176 
    177 	Respond(c, http.StatusOK, settings)
    178 }
    179 
    180 // In the future I want to return an array of backend.Service types
    181 func (e *Env) UserService(c *gin.Context) {
    182 	type body struct {
    183 		Services []string `json:"services"`
    184 	}
    185 
    186 	service, err := e.backend.UserService(c.Param("user"))
    187 	if err != nil {
    188 		RespondError(c, 500, "Unable to get service")
    189 	} else {
    190 		var body body
    191 		body.Services = make([]string, 0, 1)
    192 		if service != nil {
    193 			body.Services = append(body.Services, *service)
    194 		}
    195 		Respond(c, 200, body)
    196 	}
    197 }