This is an automated email from the git hooks/post-receive script. New commit to branch bow-v2-go in repository bow. See https://gitlab.nuiton.org/chorem/bow.git commit 0c81e25b8982d895573583aa39b46fdae38a017b Author: Benjamin <poussin@codelutin.com> Date: Fri Apr 10 00:53:27 2020 +0200 factorisation des appels sql --- cmd/bow/main.go | 2 +- migrate/001_init_schema.sql | 10 +- pkg/http/userResource.go | 46 ++++-- pkg/repository/bookmarkRepository.go | 24 +++- pkg/repository/database.go | 52 +++++-- pkg/repository/userRepository.go | 254 +++++++--------------------------- pkg/repository/userRepository_test.go | 20 +++ pkg/utils/error.go | 5 + 8 files changed, 175 insertions(+), 238 deletions(-) diff --git a/cmd/bow/main.go b/cmd/bow/main.go index 6a6fc9f..2edef6c 100644 --- a/cmd/bow/main.go +++ b/cmd/bow/main.go @@ -11,7 +11,7 @@ import ( func main() { databaseURL := os.Getenv("DATABASE_URL") log.Println("Init database") - repository.Init(databaseURL) + repository.Init(databaseURL, true) // u := model.BowUser{ID: utils.GenUUID(), Login: "bpoussin", Emails: []string{"benjamin@pouss.in"}, Password: "toto"} diff --git a/migrate/001_init_schema.sql b/migrate/001_init_schema.sql index a40815a..415c082 100644 --- a/migrate/001_init_schema.sql +++ b/migrate/001_init_schema.sql @@ -163,7 +163,7 @@ GRANT INSERT ON bowUser TO nobody; GRANT INSERT ON pageHistory TO nobody; -- tout le monde a le droit de faire certaine chose, on restraint les updates au champs qui peuvent varier -GRANT SELECT, INSERT, DELETE, TRIGGER ON bowUser TO PUBLIC; +GRANT SELECT, DELETE, TRIGGER ON bowUser TO PUBLIC; GRANT UPDATE (updateDate, password, tokens, emails, unconfirmedEmails, authenticationInfo, autoScreenshot, autoFavicon, maxTagInCloud, maxResult, actions) ON bowUser TO PUBLIC; GRANT SELECT, INSERT, DELETE, TRIGGER ON bowgroup TO PUBLIC; GRANT UPDATE(updateDate, description, tokens, admin, writer, reader) ON bowgroup TO PUBLIC; @@ -216,10 +216,16 @@ CREATE POLICY actionHistory_access ON actionHistory -- droit specifique pour nobody -- il peut lire tous les id, login, email, password -- il peut creer de nouveau utilisateur -CREATE POLICY bowUser_nobody_access ON bowUser TO nobody +CREATE POLICY bowUser_nobody_access ON bowUser FOR SELECT + TO nobody USING (true); +CREATE POLICY bowUser_nobody_insert ON bowUser + FOR INSERT + TO nobody + WITH CHECK (true); + ---- create above / drop below ---- DROP TABLE actionHistory; diff --git a/pkg/http/userResource.go b/pkg/http/userResource.go index bf60624..758f09b 100644 --- a/pkg/http/userResource.go +++ b/pkg/http/userResource.go @@ -92,7 +92,7 @@ func createUser(w http.ResponseWriter, r *http.Request) { id, err := repository.CreateUser(data["login"], data["password"]) if err != nil { - http.Error(w, fmt.Sprintf("%s", err), 400) + utils.Throw(w, err) return } @@ -100,10 +100,12 @@ func createUser(w http.ResponseWriter, r *http.Request) { } func deleteUser(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] log.Println("deleteUser", id) - err := repository.DeleteUser(id) + err := repository.DeleteUser(currentUserID, id) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -115,6 +117,8 @@ updateUserPassword body: {"password": "xxxx", "oldPassword": "yyyy"} */ func updateUserPassword(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] log.Println("updateUserPassword", id) @@ -125,7 +129,7 @@ func updateUserPassword(w http.ResponseWriter, r *http.Request) { return } - err = repository.UpdateUserPassword(id, data["password"], data["oldPassword"], false) + err = repository.UpdateUserPassword(currentUserID, id, data["password"], data["oldPassword"], false) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -138,6 +142,8 @@ body: {"name": "for application toto", "expiration": 1586081695000} return: {"token": "uuid"} */ func addUserToken(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] var data model.Token @@ -149,7 +155,7 @@ func addUserToken(w http.ResponseWriter, r *http.Request) { log.Println("addUserToken", id, data.Name, data.Expiration) - token, err := repository.AddUserToken(id, data.Name, data.Expiration) + token, err := repository.AddUserToken(currentUserID, id, data.Name, data.Expiration) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -164,6 +170,8 @@ body: {"name": "for application toto", "expiration": 1586081695000} return: {"token": "uuid"} */ func addUserUnconfirmedEmail(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] var data model.UnconfirmedEmails @@ -175,7 +183,7 @@ func addUserUnconfirmedEmail(w http.ResponseWriter, r *http.Request) { log.Println("addUserUnconfirmedEmail", id) - token, err := repository.AddUserUnconfirmedEmail(id, data.Email) + token, err := repository.AddUserUnconfirmedEmail(currentUserID, id, data.Email) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -187,6 +195,8 @@ func addUserUnconfirmedEmail(w http.ResponseWriter, r *http.Request) { } func updateUserAuthenticationInfo(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] var auth model.AuthenticationInfo err := json.NewDecoder(r.Body).Decode(&auth) @@ -197,7 +207,7 @@ func updateUserAuthenticationInfo(w http.ResponseWriter, r *http.Request) { log.Println("updateUserAuthenticationInfo", id, auth) - err = repository.UpdateUserAuthenticationInfo(id, auth) + err = repository.UpdateUserAuthenticationInfo(currentUserID, id, auth) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -205,6 +215,8 @@ func updateUserAuthenticationInfo(w http.ResponseWriter, r *http.Request) { } func updateUserActions(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] var actions []model.Action err := json.NewDecoder(r.Body).Decode(&actions) @@ -215,7 +227,7 @@ func updateUserActions(w http.ResponseWriter, r *http.Request) { log.Println("updateUserActions", id, actions) - err = repository.UpdateUserActions(id, actions) + err = repository.UpdateUserActions(currentUserID, id, actions) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -223,6 +235,8 @@ func updateUserActions(w http.ResponseWriter, r *http.Request) { } func updateUserAutoScreenshot(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] var data map[string]bool @@ -234,7 +248,7 @@ func updateUserAutoScreenshot(w http.ResponseWriter, r *http.Request) { log.Println("updateUserAutoScreenshot", id, data) - err = repository.UpdateUserAutoScreenshot(id, data["autoscreenshot"]) + err = repository.UpdateUserAutoScreenshot(currentUserID, id, data["autoscreenshot"]) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -242,6 +256,8 @@ func updateUserAutoScreenshot(w http.ResponseWriter, r *http.Request) { } func updateUserAutoFavicon(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] var data map[string]bool @@ -253,7 +269,7 @@ func updateUserAutoFavicon(w http.ResponseWriter, r *http.Request) { log.Println("updateUserAutoFavicon", id, data) - err = repository.UpdateUserAutoFavicon(id, data["autofavicon"]) + err = repository.UpdateUserAutoFavicon(currentUserID, id, data["autofavicon"]) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -261,6 +277,8 @@ func updateUserAutoFavicon(w http.ResponseWriter, r *http.Request) { } func updateUserMaxTagInCloud(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] var data map[string]int8 @@ -272,7 +290,7 @@ func updateUserMaxTagInCloud(w http.ResponseWriter, r *http.Request) { log.Println("updateUserMaxTagInCloud", id, data) - err = repository.UpdateUserMaxTagInCloud(id, data["maxtagincloud"]) + err = repository.UpdateUserMaxTagInCloud(currentUserID, id, data["maxtagincloud"]) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -280,6 +298,8 @@ func updateUserMaxTagInCloud(w http.ResponseWriter, r *http.Request) { } func updateUserMaxResult(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] var data map[string]int8 @@ -291,7 +311,7 @@ func updateUserMaxResult(w http.ResponseWriter, r *http.Request) { log.Println("updateUserMaxResult", id, data) - err = repository.UpdateUserMaxResult(id, data["maxresult"]) + err = repository.UpdateUserMaxResult(currentUserID, id, data["maxresult"]) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -299,10 +319,12 @@ func updateUserMaxResult(w http.ResponseWriter, r *http.Request) { } func confirmUserEmail(w http.ResponseWriter, r *http.Request) { + currentUserID := r.Context().Value(utils.UserID).(string) + id := mux.Vars(r)["id"] token := mux.Vars(r)["token"] - err := repository.ConfirmUserEmail(id, token) + err := repository.ConfirmUserEmail(currentUserID, id, token) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return diff --git a/pkg/repository/bookmarkRepository.go b/pkg/repository/bookmarkRepository.go index f90ac04..39c72ff 100644 --- a/pkg/repository/bookmarkRepository.go +++ b/pkg/repository/bookmarkRepository.go @@ -12,19 +12,37 @@ import ( /* BookmarkJSON retourne le bookmark au format json */ -func BookmarkJSON(id string) (string, error) { +func BookmarkJSON(currentUserID string, id string) (string, error) { + tx, err := db.Begin(context.Background()) + if err != nil { + return "", utils.NewHTTPError500(err, currentUserID) + } + defer tx.Rollback(context.Background()) + _, err = db.Exec(context.Background(), fmt.Sprintf(`SET ROLE "%[1]s";`, currentUserID)) + if err != nil { + return "", utils.NewHTTPError500(err, currentUserID) + } + var pgjson pgtype.JSON row := db.QueryRow(context.Background(), `WITH __all AS (select * from bookmark where id=$1) SELECT json_agg(__all.*) as j FROM __all`, id) err := row.Scan(&pgjson) if err != nil { - return "", err + return "", utils.NewHTTPError500(err, currentUserID) + } + + err = tx.Commit(context.Background()) + if err != nil { + return "", utils.NewHTTPError500(err, currentUserID) } var result string err = pgjson.AssignTo(&result) + if err != nil { + return "", utils.NewHTTPError500(err, currentUserID) + } - return result, err + return result, nil } /* diff --git a/pkg/repository/database.go b/pkg/repository/database.go index a925fa8..b029559 100644 --- a/pkg/repository/database.go +++ b/pkg/repository/database.go @@ -12,6 +12,7 @@ import ( "github.com/jackc/pgx/v4" "github.com/jackc/pgx/v4/pgxpool" "github.com/jackc/tern/migrate" + "gitlab.chorem.org/chorem/bow/pkg/utils" ) var db *pgxpool.Pool @@ -26,8 +27,10 @@ type errorLineExtract struct { /* Init initialise la connexion a la base en utilisant */ -func Init(databaseURL string) { - migrateDatabase(databaseURL) +func Init(databaseURL string, doMigration bool) { + if (doMigration) { + migrateDatabase(databaseURL) + } poolConfig, err := pgxpool.ParseConfig(databaseURL) if err != nil { @@ -152,39 +155,60 @@ func migrateDatabase(databaseURL string) { } } -func execOnOneRow(currentUserID string, presql string, sql string, postsql string, arguments ...interface{}) error { +type query struct { + asNobody bool + presql string + sql string + postsql string +} + +func (q *query)setPreSQL(sql string, arguments ...interface{}) { + q.presql = fmt.Sprintf(sql, arguments...) +} + +func (q *query)setSQL(sql string, arguments ...interface{}) { + q.sql = fmt.Sprintf(sql, arguments...) +} + +func (q *query)setPostSQL(sql string, arguments ...interface{}) { + q.postsql = fmt.Sprintf(sql, arguments...) +} + +func (q *query)execOnOneRow(currentUserID string, arguments ...interface{}) error { tx, err := db.Begin(context.Background()) if err != nil { return utils.NewHTTPError500(err, currentUserID) } defer tx.Rollback(context.Background()) - if presql != nil { - _, err = db.Exec(context.Background(), fmt.Sprintf(presql, currentUserID)) + if q.presql != "" { + _, err = db.Exec(context.Background(), q.presql, pgx.QuerySimpleProtocol(true)) if err != nil { return utils.NewHTTPError500(err, currentUserID) } } - _, err = db.Exec(context.Background(), fmt.Sprintf(` - SET ROLE "%[1]s"; - `, currentUserID)) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) + if !q.asNobody { + _, err = db.Exec(context.Background(), fmt.Sprintf(` + SET ROLE "%[1]s"; + `, currentUserID)) + if err != nil { + return utils.NewHTTPError500(err, currentUserID) + } } - modif, err := db.Exec(context.Background(), sql, arguments) + modif, err := db.Exec(context.Background(), q.sql, arguments...) if err != nil { return utils.NewHTTPError500(err, currentUserID) } if modif.RowsAffected() != 1 { - return return utils.NewHTTPError(fmt.Sprintf("User not found '%s'", id), currentUserID, 404) + return utils.NewHTTPError(fmt.Sprintf("User not found '%v'", arguments), currentUserID, 404) } - if postsql != nil { - _, err = db.Exec(context.Background(), fmt.Sprintf(postsql, currentUserID)) + if q.postsql != "" { + _, err = db.Exec(context.Background(), q.postsql, pgx.QuerySimpleProtocol(true)) if err != nil { return utils.NewHTTPError500(err, currentUserID) } diff --git a/pkg/repository/userRepository.go b/pkg/repository/userRepository.go index 20c234d..f5db52f 100644 --- a/pkg/repository/userRepository.go +++ b/pkg/repository/userRepository.go @@ -3,7 +3,6 @@ package repository import ( "context" "encoding/json" - "errors" "fmt" "log" "time" @@ -98,14 +97,12 @@ func CheckUserPasswordForEmail(loginOrEmail string, password string) (string, er var hash string row := db.QueryRow(context.Background(), `select id, password from bowuser where login=$1 or emails @> $2::text[]`, loginOrEmail, fmt.Sprintf(`{"%s"}`, loginOrEmail)) err := row.Scan(&uuid, &hash) - if err != nil {CREATE POLICY bowUser_access ON bowUser - FOR ALL - USING (id = current_user::uuid); + if err != nil { return "", err } if !utils.CheckPassword(password, hash) { - return "", fmt.Errorf("Password mismatch for %s", loginOrEmail) + return "", utils.NewHTTPError(fmt.Sprintf("Password mismatch for %s", loginOrEmail), "nobody", 401) } var result string @@ -128,7 +125,7 @@ func CreateUser(login string, password string) (string, error) { uuid, err := utils.GenUUID() if err != nil { - return "",utils.NewHTTPError500(err, login) + return "", utils.NewHTTPError500(err, login) } currentUserID := uuid @@ -142,74 +139,29 @@ func CreateUser(login string, password string) (string, error) { log.Println("create user", string(userAsJSON)) - tx, err := db.Begin(context.Background()) - if err != nil { - return "", utils.NewHTTPError500(err, currentUserID) - } - defer tx.Rollback(context.Background()) - - // pas d'argument sql donc pas de requete preparer, on peut en mettre 3 - _, err = db.Exec(context.Background(), fmt.Sprintf(` + q := &query{asNobody: true, sql: `INSERT INTO bowUser AS t SELECT * FROM json_populate_record(NULL::bowUser, $1::json);`} + q.setPostSQL(` CREATE ROLE "%[1]s"; GRANT "%[1]s" TO nobody; - SET ROLE "%[1]s"; - `, currentUserID)) - if err != nil { - return "", utils.NewHTTPError500(err, currentUserID) - } - - modif, err := db.Exec(context.Background(), ` - INSERT INTO bowUser AS t SELECT * FROM json_populate_record(NULL::bowUser, $1::json); - `, string(userAsJSON)) - - if err != nil || modif.RowsAffected() != 1 { - return "", utils.errors.New("No user created") - } + `, currentUserID) - err = tx.Commit(context.Background()) - if err != nil { - return "", utils.NewHTTPError500(err, currentUserID) - } + err = q.execOnOneRow(currentUserID, userAsJSON) - return user.ID, nil + return user.ID, err } /* DeleteUser suppression d'un nouveau bookmark */ func DeleteUser(currentUserID string, id string) error { - tx, err := db.Begin(context.Background()) - if err != nil { - return "", utils.NewHTTPError500(err, currentUserID) - } - defer tx.Rollback(context.Background()) - - _, err = db.Exec(context.Background(), fmt.Sprintf(` - SET ROLE "%[1]s"; - `, currentUserID)) - if err != nil { - return "", utils.NewHTTPError500(err, currentUserID) - } - - modif, err := db.Exec(context.Background(), ` - DELETE FROM bowuser WHERE id=$1;`, id) - if modif.RowsAffected() != 1 { - return fmt.Errorf("No user found for id '%s'", id) - } - - _, err = db.Exec(context.Background(), fmt.Sprintf(` + q := &query{sql: `DELETE FROM bowuser WHERE id=$1;`} + q.setPostSQL(` RESET ROLE; DROP ROLE IF EXISTS "%s"; - `, currentUserID)) - if err != nil { - return "", utils.NewHTTPError500(err, currentUserID) - } - - err = tx.Commit(context.Background()) - if err != nil { - return "", utils.NewHTTPError500(err, currentUserID) - } - + `, currentUserID) + + err := q.execOnOneRow(currentUserID, id) + return err } @@ -226,34 +178,10 @@ func UpdateUserPassword(currentUserID string, id string, password string, oldPas return utils.NewHTTPError500(err, currentUserID) } - tx, err := db.Begin(context.Background()) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - defer tx.Rollback(context.Background()) - - _, err = db.Exec(context.Background(), fmt.Sprintf(` - SET ROLE "%[1]s"; - `, currentUserID)) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } + q := &query{sql: `update bowuser SET password=$2 where id=$1`} + err = q.execOnOneRow(currentUserID, id, hash) - modif, err := db.Exec(context.Background(), `update bowuser SET password=$2 where id=$1;`, id, hash) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - if modif.RowsAffected() != 1 { - return return utils.NewHTTPError(fmt.Sprintf("User not found '%s'", id), currentUserID, 404) - } - - err = tx.Commit(context.Background()) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - return nil + return err } /* @@ -270,35 +198,10 @@ func AddUserToken(currentUserID string, id string, name string, expiration time. return token, err } - tx, err := db.Begin(context.Background()) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - defer tx.Rollback(context.Background()) - - _, err = db.Exec(context.Background(), fmt.Sprintf(` - SET ROLE "%[1]s"; - `, currentUserID)) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - modif, err := db.Exec(context.Background(), `update bowuser SET tokens=coalesce(tokens, '[]'::jsonb) || $2::jsonb where id=$1;`, id, json) - - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - if modif.RowsAffected() != 1 { - return return utils.NewHTTPError(fmt.Sprintf("User not found '%s'", id), currentUserID, 404) - } + q := &query{sql: `update bowuser SET tokens=coalesce(tokens, '[]'::jsonb) || $2::jsonb where id=$1;`} + err = q.execOnOneRow(currentUserID, id, json) - err = tx.Commit(context.Background()) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - return token, nil + return token, err } /* @@ -315,33 +218,8 @@ func AddUserUnconfirmedEmail(currentUserID string, id string, email string) (str return token, err } - tx, err := db.Begin(context.Background()) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - defer tx.Rollback(context.Background()) - - _, err = db.Exec(context.Background(), fmt.Sprintf(` - SET ROLE "%[1]s"; - `, currentUserID)) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - modif, err := db.Exec(context.Background(), `update bowuser SET unconfirmedemails=coalesce(unconfirmedemails, '[]'::jsonb) || $2::jsonb where id=$1;`, id, json) - - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - if modif.RowsAffected() != 1 { - return return utils.NewHTTPError(fmt.Sprintf("User not found '%s'", id), currentUserID, 404) - } - - err = tx.Commit(context.Background()) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } + q := &query{sql: `update bowuser SET unconfirmedemails=coalesce(unconfirmedemails, '[]'::jsonb) || $2::jsonb where id=$1;`} + err = q.execOnOneRow(currentUserID, id, json) return token, nil } @@ -353,55 +231,27 @@ func UpdateUserAuthenticationInfo(currentUserID string, id string, auth model.Au authAsJSON, err := json.Marshal(auth) if err != nil { return err - } - - tx, err := db.Begin(context.Background()) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - defer tx.Rollback(context.Background()) + } - _, err = db.Exec(context.Background(), fmt.Sprintf(` - SET ROLE "%[1]s"; - `, currentUserID)) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - modif, err := db.Exec(context.Background(), ` - UPDATE bowuser + q := &query{sql: `UPDATE bowuser SET (authenticationinfo) = (SELECT * FROM json_populate_record(NULL::authenticationinfo, $2::json)) - WHERE id=$1`, id, string(authAsJSON)) - - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } + WHERE id=$1`} + err = q.execOnOneRow(currentUserID, id, string(authAsJSON)) - if modif.RowsAffected() != 1 { - return return utils.NewHTTPError(fmt.Sprintf("User not found '%s'", id), currentUserID, 404) - } - - err = tx.Commit(context.Background()) - if err != nil { - return utils.NewHTTPError500(err, currentUserID) - } - - return nil + return err } /* UpdateUserActions met a jour les actions utilisateur */ -func UpdateUserActions(id string, actions []model.Action) error { +func UpdateUserActions(currentUserID string, id string, actions []model.Action) error { json, err := json.Marshal(actions) if err != nil { return err } - modif, err := db.Exec(context.Background(), `update bowuser SET actions=$2::jsonb where id=$1;`, id, json) - if modif.RowsAffected() != 1 { - return fmt.Errorf("No user found for id '%s'", id) - } + q := &query{sql: `update bowuser SET actions=$2::jsonb where id=$1;`} + err = q.execOnOneRow(currentUserID, id, json) return err } @@ -409,11 +259,9 @@ func UpdateUserActions(id string, actions []model.Action) error { /* UpdateUserAutoScreenshot met a jour le boolean d'auto screenshot de la page */ -func UpdateUserAutoScreenshot(id string, value bool) error { - modif, err := db.Exec(context.Background(), `update bowuser SET autoScreenshot=$2 where id=$1;`, id, value) - if modif.RowsAffected() != 1 { - return fmt.Errorf("No user found for id '%s'", id) - } +func UpdateUserAutoScreenshot(currentUserID string, id string, value bool) error { + q := &query{sql: `update bowuser SET autoScreenshot=$2 where id=$1;`} + err := q.execOnOneRow(currentUserID, id, value) return err } @@ -421,11 +269,9 @@ func UpdateUserAutoScreenshot(id string, value bool) error { /* UpdateUserAutoFavicon met a jour le boolean d'auto favicon de la page */ -func UpdateUserAutoFavicon(id string, value bool) error { - modif, err := db.Exec(context.Background(), `update bowuser SET autoFavicon=$2 where id=$1;`, id, value) - if modif.RowsAffected() != 1 { - return fmt.Errorf("No user found for id '%s'", id) - } +func UpdateUserAutoFavicon(currentUserID string, id string, value bool) error { + q := &query{sql: `update bowuser SET autoFavicon=$2 where id=$1;`} + err := q.execOnOneRow(currentUserID, id, value) return err } @@ -433,11 +279,9 @@ func UpdateUserAutoFavicon(id string, value bool) error { /* UpdateUserMaxTagInCloud met a jour le nombre d'element du nuage de tag */ -func UpdateUserMaxTagInCloud(id string, value int8) error { - modif, err := db.Exec(context.Background(), `update bowuser SET maxTagInCloud=$2 where id=$1;`, id, value) - if modif.RowsAffected() != 1 { - return fmt.Errorf("No user found for id '%s'", id) - } +func UpdateUserMaxTagInCloud(currentUserID string, id string, value int8) error { + q := &query{sql: `update bowuser SET maxTagInCloud=$2 where id=$1;`} + err := q.execOnOneRow(currentUserID, id, value) return err } @@ -445,11 +289,9 @@ func UpdateUserMaxTagInCloud(id string, value int8) error { /* UpdateUserMaxResult met a jour le nombre d'element affiché dans une page de resultat */ -func UpdateUserMaxResult(id string, value int8) error { - modif, err := db.Exec(context.Background(), `update bowuser SET maxResult=$2 where id=$1;`, id, value) - if modif.RowsAffected() != 1 { - return fmt.Errorf("No user found for id '%s'", id) - } +func UpdateUserMaxResult(currentUserID string, id string, value int8) error { + q := &query{sql: `update bowuser SET maxResult=$2 where id=$1;`} + err := q.execOnOneRow(currentUserID, id, value) return err } @@ -457,7 +299,7 @@ func UpdateUserMaxResult(id string, value int8) error { /* ConfirmUserEmail verif et confirme un email */ -func ConfirmUserEmail(id string, token string) error { +func ConfirmUserEmail(currentUserID string, id string, token string) error { // le but est de simplement faire passer du statut non confirmer à confirmer un email // si on le retrouve pour l'utilisateur et que le token est le bon. // mais avec le schema de base choisi c'est un poil compliqué @@ -467,7 +309,9 @@ func ConfirmUserEmail(id string, token string) error { // - on update la ligne en faisant passer l'email dans les emails valides (ajout dans emails, suppression dans unconfirmedemails) // - on garanti que personne n'a deja cette email, sinon on ne fait rien (il reste en a confirmer) jsonPathToCheckToken := fmt.Sprintf(`$[*].token ? (@ == "%s")`, token) - modif, err := db.Exec(context.Background(), ` + + + q := &query{sql: ` with ue as (select jsonb_array_elements(unconfirmedemails) as json from bowuser where b.id=$1 and unconfirmedemails @? $3), @@ -482,10 +326,8 @@ func ConfirmUserEmail(id string, token string) error { unconfirmedemails=unconfirmedemails - (data.index::int - 1) from data where b.id=$1 and b.unconfirmedemails @? $3 and - (select count(id) from bowuser where emails @> ('{' || data.email || '}')::text[]) = 0;`, id, token, jsonPathToCheckToken) + (select count(id) from bowuser where emails @> ('{' || data.email || '}')::text[]) = 0;`} + err := q.execOnOneRow(currentUserID, id, token, jsonPathToCheckToken) - if modif.RowsAffected() != 1 { - return errors.New("No user found to for this token") - } return err } diff --git a/pkg/repository/userRepository_test.go b/pkg/repository/userRepository_test.go new file mode 100644 index 0000000..3fed714 --- /dev/null +++ b/pkg/repository/userRepository_test.go @@ -0,0 +1,20 @@ +package repository + +import ( + "testing" + "regexp" +) + +func TestCreateUser(t *testing.T) { + // Init("postgres://dbuser:xxxxxxxx@localhost:5432/bow", false) + // id, err := CreateUser("poussin.test@pouss.in", "xxxxxxxx") + + // if err != nil { + // t.Error("TestCreateUser can't create user", err) + // } + + // matched, err := regexp.MatchString(`^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$`, id) + // if !matched || err != nil { + // t.Error("TestCreateUser bad id format", matched, err) + // } +} diff --git a/pkg/utils/error.go b/pkg/utils/error.go index 1c7afe3..a39c386 100644 --- a/pkg/utils/error.go +++ b/pkg/utils/error.go @@ -3,6 +3,7 @@ package utils import ( "fmt" "net/http" + "log" ) /* @@ -45,8 +46,12 @@ func NewHTTPError500(err error, currentUserID string) *httpError { func Throw(w http.ResponseWriter, err error) { if err, ok := err.(*httpError); ok { + if err.StatusCode >= 500 { + log.Println(err) + } http.Error(w, fmt.Sprintf("%s", err), err.StatusCode) } else { + log.Println(err) http.Error(w, fmt.Sprintf("%s", err), 500) } } -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.