Add update username method

This commit is contained in:
Marco Realacci 2022-11-18 17:18:46 +01:00
parent 626b7fa3e9
commit 7c2c993dc3
10 changed files with 82 additions and 9 deletions

View file

@ -28,7 +28,6 @@ func (rt *_router) wrap(fn httpRouterHandler) func(http.ResponseWriter, *http.Re
if err != nil { if err != nil {
rt.baseLogger.WithError(err).Info("User not authorized") rt.baseLogger.WithError(err).Info("User not authorized")
w.WriteHeader(http.StatusUnauthorized)
return return
} }

View file

@ -8,6 +8,9 @@ import (
func (rt *_router) Handler() http.Handler { func (rt *_router) Handler() http.Handler {
// Register routes // Register routes
rt.router.POST("/session", rt.wrap(rt.PostSession)) rt.router.POST("/session", rt.wrap(rt.PostSession))
rt.router.PUT("/users/:user_id/username", rt.wrap(rt.UpdateUsername))
rt.router.GET("/", rt.getHelloWorld) rt.router.GET("/", rt.getHelloWorld)
rt.router.GET("/context", rt.wrap(rt.getContextReply)) rt.router.GET("/context", rt.wrap(rt.getContextReply))

View file

@ -4,6 +4,7 @@ import (
"errors" "errors"
"strings" "strings"
"github.com/notherealmarco/WASAPhoto/service/api/reqcontext"
"github.com/notherealmarco/WASAPhoto/service/database" "github.com/notherealmarco/WASAPhoto/service/database"
) )
@ -42,9 +43,19 @@ func (b *BearerAuth) Authorized(db database.AppDatabase) (bool, error) {
return state, nil return state, nil
} }
func (b *BearerAuth) UserAuthorized(db database.AppDatabase, uid string) (bool, error) { func (b *BearerAuth) UserAuthorized(db database.AppDatabase, uid string) (reqcontext.AuthStatus, error) {
if b.token == uid { if b.token == uid {
return b.Authorized(db) auth, err := b.Authorized(db)
if err != nil {
return -1, err
}
if auth {
return reqcontext.AUTHORIZED, nil
} else {
return reqcontext.UNAUTHORIZED, nil
}
} }
return false, nil return reqcontext.FORBIDDEN, nil
} }

View file

@ -2,8 +2,10 @@ package authorization
import ( import (
"errors" "errors"
"net/http"
"github.com/notherealmarco/WASAPhoto/service/api/reqcontext" "github.com/notherealmarco/WASAPhoto/service/api/reqcontext"
"github.com/notherealmarco/WASAPhoto/service/database"
) )
func BuildAuth(header string) (reqcontext.Authorization, error) { func BuildAuth(header string) (reqcontext.Authorization, error) {
@ -16,3 +18,21 @@ func BuildAuth(header string) (reqcontext.Authorization, error) {
} }
return auth, nil return auth, nil
} }
func SendAuthorizationError(f func(db database.AppDatabase, uid string) (reqcontext.AuthStatus, error), uid string, db database.AppDatabase, w http.ResponseWriter) bool {
auth, err := f(db, uid)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
// todo: log error and write it to the response
return false
}
if auth == reqcontext.UNAUTHORIZED {
w.WriteHeader(http.StatusUnauthorized)
return false
}
if auth == reqcontext.FORBIDDEN {
w.WriteHeader(http.StatusForbidden)
return false
}
return true
}

View file

@ -14,7 +14,7 @@ type _reqbody struct {
} }
type _respbody struct { type _respbody struct {
UID string `json:"uid"` UID string `json:"user_id"`
} }
// getContextReply is an example of HTTP endpoint that returns "Hello World!" as a plain text. The signature of this // getContextReply is an example of HTTP endpoint that returns "Hello World!" as a plain text. The signature of this

View file

@ -1,14 +1,35 @@
package api package api
import ( import (
"encoding/json"
"net/http" "net/http"
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
"github.com/notherealmarco/WASAPhoto/service/api/authorization"
"github.com/notherealmarco/WASAPhoto/service/api/reqcontext" "github.com/notherealmarco/WASAPhoto/service/api/reqcontext"
"github.com/notherealmarco/WASAPhoto/service/structures"
) )
func (rt *_router) UpdateUsername(w http.ResponseWriter, r *http.Request, ps httprouter.Params, ctx reqcontext.RequestContext) { func (rt *_router) UpdateUsername(w http.ResponseWriter, r *http.Request, ps httprouter.Params, ctx reqcontext.RequestContext) {
auth, err := ctx.Auth.UserAuthorized(rt.db, r.URL.Path // todo: prendere il coso giusto dal path) uid := ps.ByName("user_id")
if !authorization.SendAuthorizationError(ctx.Auth.UserAuthorized, uid, rt.db, w) {
return
}
var req structures.UserDetails
err := json.NewDecoder(r.Body).Decode(&req) //todo: capire se serve close
if err != nil {
w.WriteHeader(http.StatusBadRequest) // todo: move to DecodeOrBadRequest helper
return
}
err = rt.db.UpdateUsername(uid, req.Name)
if err != nil {
w.WriteHeader(http.StatusInternalServerError) // todo: is not ok, maybe let's use a helper
return
}
w.WriteHeader(http.StatusNoContent) // todo: change to 204 also in API spec
} }

View file

@ -12,6 +12,14 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type AuthStatus int
const (
AUTHORIZED = 0
UNAUTHORIZED = 1
FORBIDDEN = 2
)
// RequestContext is the context of the request, for request-dependent parameters // RequestContext is the context of the request, for request-dependent parameters
type RequestContext struct { type RequestContext struct {
// ReqUUID is the request unique ID // ReqUUID is the request unique ID
@ -26,5 +34,5 @@ type RequestContext struct {
type Authorization interface { type Authorization interface {
GetType() string GetType() string
Authorized(db database.AppDatabase) (bool, error) Authorized(db database.AppDatabase) (bool, error)
UserAuthorized(db database.AppDatabase, uid string) (bool, error) UserAuthorized(db database.AppDatabase, uid string) (AuthStatus, error)
} }

View file

@ -40,7 +40,7 @@ import (
type AppDatabase interface { type AppDatabase interface {
UserExists(uid string) (bool, error) UserExists(uid string) (bool, error)
GetUserID(name string) (string, error) GetUserID(name string) (string, error)
SetName(name string) error UpdateUsername(uid, name string) error
CreateUser(name string) (string, error) CreateUser(name string) (string, error)
FollowUser(uid string, follow string) error FollowUser(uid string, follow string) error
UnfollowUser(uid string, unfollow string) error UnfollowUser(uid string, unfollow string) error

View file

@ -11,7 +11,7 @@ import (
// Check if user exists // Check if user exists
func (db *appdbimpl) UserExists(uid string) (bool, error) { func (db *appdbimpl) UserExists(uid string) (bool, error) {
var name string var name string
err := db.c.QueryRow(`SELECT "name" FROM "users" WHERE "uid" = ?`, name).Scan(&name) err := db.c.QueryRow(`SELECT "name" FROM "users" WHERE "uid" = ?`, uid).Scan(&name)
if db_errors.EmptySet(err) { if db_errors.EmptySet(err) {
return false, nil return false, nil
@ -38,6 +38,12 @@ func (db *appdbimpl) CreateUser(name string) (string, error) {
return uid.String(), err return uid.String(), err
} }
// Update username
func (db *appdbimpl) UpdateUsername(uid string, name string) error {
_, err := db.c.Exec(`UPDATE "users" SET "name" = ? WHERE "uid" = ?`, name, uid)
return err
}
// Follow a user // Follow a user
func (db *appdbimpl) FollowUser(uid string, follow string) error { func (db *appdbimpl) FollowUser(uid string, follow string) error {
_, err := db.c.Exec(`INSERT INTO "follows" ("follower", "followed") VALUES (?, ?)`, uid, follow) _, err := db.c.Exec(`INSERT INTO "follows" ("follower", "followed") VALUES (?, ?)`, uid, follow)

View file

@ -0,0 +1,5 @@
package structures
type UserDetails struct {
Name string `json:"name"`
}