From 4cb80bbb3a4c38024099ccbdb2b290aab2aec218 Mon Sep 17 00:00:00 2001 From: Tovi Jaeschke-Rogers Date: Wed, 16 Mar 2022 20:37:10 +1030 Subject: [PATCH] Add user_id to post model Add update and delete cruds to user API --- Api/Auth/Passwords.go | 22 +++ Api/JsonSerialization/VerifyJson.go | 5 + Api/PostImages_test.go | 17 +-- Api/Posts.go | 10 +- Api/Posts_test.go | 149 +++++++------------ Api/Routes.go | 9 +- Api/UserHelper.go | 51 +++++++ Api/Users.go | 103 ++++++++++++- Api/Users_test.go | 222 ++++++++++++++++++++++++---- Database/Init.go | 51 +++++-- Database/Users.go | 53 ++++++- Models/Posts.go | 9 +- Models/Users.go | 2 +- 13 files changed, 533 insertions(+), 170 deletions(-) create mode 100644 Api/Auth/Passwords.go create mode 100644 Api/UserHelper.go diff --git a/Api/Auth/Passwords.go b/Api/Auth/Passwords.go new file mode 100644 index 0000000..779c48e --- /dev/null +++ b/Api/Auth/Passwords.go @@ -0,0 +1,22 @@ +package Auth + +import ( + "golang.org/x/crypto/bcrypt" +) + +func HashPassword(password string) (string, error) { + var ( + bytes []byte + err error + ) + bytes, err = bcrypt.GenerateFromPassword([]byte(password), 14) + return string(bytes), err +} + +func CheckPasswordHash(password, hash string) bool { + var ( + err error + ) + err = bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} diff --git a/Api/JsonSerialization/VerifyJson.go b/Api/JsonSerialization/VerifyJson.go index c0e1b17..2ad1554 100644 --- a/Api/JsonSerialization/VerifyJson.go +++ b/Api/JsonSerialization/VerifyJson.go @@ -40,6 +40,7 @@ func isFloatType(t reflect.Type) (yes bool) { func CanConvert(t reflect.Type, v reflect.Value) bool { isPtr := t.Kind() == reflect.Ptr isStruct := t.Kind() == reflect.Struct + isArray := t.Kind() == reflect.Array dstType := t // Check if v is a nil value. @@ -58,6 +59,10 @@ func CanConvert(t reflect.Type, v reflect.Value) bool { return v.Kind() == reflect.Map } + if isArray { + return v.Kind() == reflect.String + } + if t.Kind() == reflect.Slice { return v.Kind() == reflect.Slice } diff --git a/Api/PostImages_test.go b/Api/PostImages_test.go index 0bf0761..9ab1947 100644 --- a/Api/PostImages_test.go +++ b/Api/PostImages_test.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "io/ioutil" - "log" "mime/multipart" "net/http" "net/http/httptest" @@ -22,7 +21,6 @@ import ( "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" "github.com/gorilla/mux" - "gorm.io/gorm" ) func init() { @@ -34,8 +32,7 @@ func init() { panic(err) } - log.SetOutput(ioutil.Discard) - Database.Init() + Database.InitTest() r = mux.NewRouter() } @@ -181,12 +178,6 @@ func Test_createPostImages(t *testing.T) { t.Errorf("Expected nil, recieved %s", err.Error()) } - defer Database.DB. - Session(&gorm.Session{FullSaveAssociations: true}). - Unscoped(). - Select("PostLinks", "PostImages"). - Delete(&postData) - if len(updatePostData.PostImages) != 1 { t.Errorf("Expected len(updatePostData.PostImages) == 1, recieved %d", len(updatePostData.PostImages)) } @@ -243,12 +234,6 @@ func Test_deletePostImages(t *testing.T) { t.Errorf("Expected nil, recieved %s", err.Error()) } - defer Database.DB. - Session(&gorm.Session{FullSaveAssociations: true}). - Unscoped(). - Select("PostLinks", "PostImages"). - Delete(&postData) - req, err := http.NewRequest("DELETE", fmt.Sprintf( "%s/post/%s/image/%s", ts.URL, diff --git a/Api/Posts.go b/Api/Posts.go index e54af45..c39adb5 100644 --- a/Api/Posts.go +++ b/Api/Posts.go @@ -11,8 +11,6 @@ import ( "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Api/JsonSerialization" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" - - "github.com/gorilla/mux" ) func getPosts(w http.ResponseWriter, r *http.Request) { @@ -131,6 +129,7 @@ func createPost(w http.ResponseWriter, r *http.Request) { "audios", }, false) if err != nil { + panic(err) log.Printf("Invalid data provided to posts API: %s\n", err.Error()) JsonReturn(w, 405, "Invalid data") return @@ -158,15 +157,12 @@ func updatePost(w http.ResponseWriter, r *http.Request) { postData Models.Post requestBody []byte returnJson []byte - urlVars map[string]string id string - ok bool err error ) - urlVars = mux.Vars(r) - id, ok = urlVars["postID"] - if !ok { + id, err = getPostId(r) + if err != nil { log.Printf("Error encountered getting id\n") JsonReturn(w, 500, "An error occured") return diff --git a/Api/Posts_test.go b/Api/Posts_test.go index d0ce2d2..3f381a0 100644 --- a/Api/Posts_test.go +++ b/Api/Posts_test.go @@ -3,8 +3,6 @@ package Api import ( "encoding/json" "fmt" - "io/ioutil" - "log" "net/http" "net/http/httptest" "os" @@ -17,7 +15,6 @@ import ( "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" "github.com/gorilla/mux" - "gorm.io/gorm" ) var ( @@ -33,12 +30,34 @@ func init() { panic(err) } - log.SetOutput(ioutil.Discard) - Database.Init() + Database.InitTest() r = mux.NewRouter() } +func createTestPost() (Models.Post, error) { + + userData, err := createTestUser(true) + + postData := Models.Post{ + UserID: userData.ID, + Title: "Test post", + Content: "Test content", + FrontPage: true, + Order: 1, + PostLinks: []Models.PostLink{ + { + Type: "Facebook", + Link: "http://facebook.com/", + }, + }, + } + + err = Database.CreatePost(&postData) + return postData, err + +} + func Test_getPosts(t *testing.T) { t.Log("Testing getPosts...") @@ -49,29 +68,7 @@ func Test_getPosts(t *testing.T) { var err error for i := 0; i < 20; i++ { - postData := Models.Post{ - Title: "Test post", - Content: "Test content", - FrontPage: true, - Order: i, - PostLinks: []Models.PostLink{ - { - Type: "Facebook", - Link: "http://facebook.com/", - }, - }, - } - - err = Database.CreatePost(&postData) - if err != nil { - t.Errorf("Expected nil, recieved %s", err.Error()) - } - - defer Database.DB. - Session(&gorm.Session{FullSaveAssociations: true}). - Unscoped(). - Select("PostLinks"). - Delete(&postData) + createTestPost() } res, err := http.Get(ts.URL + "/post?page=1&pageSize=10") @@ -103,30 +100,12 @@ func Test_getPost(t *testing.T) { defer ts.Close() - postData := Models.Post{ - Title: "Test post", - Content: "Test content", - FrontPage: true, - Order: 1, - PostLinks: []Models.PostLink{ - { - Type: "Facebook", - Link: "http://facebook.com/", - }, - }, - } - - err := Database.CreatePost(&postData) + postData, err := createTestPost() if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() } - defer Database.DB. - Session(&gorm.Session{FullSaveAssociations: true}). - Unscoped(). - Select("PostLinks"). - Delete(&postData) - res, err := http.Get(fmt.Sprintf( "%s/post/%s", ts.URL, @@ -135,16 +114,36 @@ func Test_getPost(t *testing.T) { if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() } + if res.StatusCode != http.StatusOK { t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode) + t.FailNow() } getPostData := new(Models.Post) err = json.NewDecoder(res.Body).Decode(getPostData) if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() + } + + if getPostData.Title != "Test post" { + t.Errorf("Expected title \"Test post\", recieved %s", getPostData.Title) + t.FailNow() } + + if getPostData.Content != "Test content" { + t.Errorf("Expected content \"Test content\", recieved %s", getPostData.Content) + t.FailNow() + } + + if len(getPostData.PostLinks) != 1 { + t.Errorf("Expected len(PostLinks) == 1, recieved %d", len(getPostData.PostLinks)) + t.FailNow() + } + } func Test_createPost(t *testing.T) { @@ -156,8 +155,11 @@ func Test_createPost(t *testing.T) { defer ts.Close() + userData, err := createTestUser(true) + postJson := ` { + "user_id": "%s", "title": "Test post", "content": "Test content", "front_page": true, @@ -169,6 +171,8 @@ func Test_createPost(t *testing.T) { } ` + postJson = fmt.Sprintf(postJson, userData.ID.String()) + res, err := http.Post(ts.URL+"/post", "application/json", strings.NewReader(postJson)) if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) @@ -183,12 +187,6 @@ func Test_createPost(t *testing.T) { t.Errorf("Expected nil, recieved %s", err.Error()) } - defer Database.DB. - Session(&gorm.Session{FullSaveAssociations: true}). - Unscoped(). - Select("PostLinks"). - Delete(&postData) - if postData.Title != "Test post" { t.Errorf("Expected title \"Test post\", recieved \"%s\"", postData.Title) } @@ -206,30 +204,12 @@ func Test_deletePost(t *testing.T) { defer ts.Close() - postData := Models.Post{ - Title: "Test post", - Content: "Test content", - FrontPage: true, - Order: 1, - PostLinks: []Models.PostLink{ - { - Type: "Facebook", - Link: "http://facebook.com/", - }, - }, - } - - err := Database.CreatePost(&postData) + postData, err := createTestPost() if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() } - defer Database.DB. - Session(&gorm.Session{FullSaveAssociations: true}). - Unscoped(). - Select("PostLinks"). - Delete(&postData) - req, err := http.NewRequest("DELETE", fmt.Sprintf( "%s/post/%s", ts.URL, @@ -262,20 +242,7 @@ func Test_updatePost(t *testing.T) { defer ts.Close() - postData := Models.Post{ - Title: "Test post", - Content: "Test content", - FrontPage: true, - Order: 1, - PostLinks: []Models.PostLink{ - { - Type: "Facebook", - Link: "http://facebook.com/", - }, - }, - } - - err := Database.CreatePost(&postData) + postData, err := createTestPost() if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) } @@ -315,12 +282,6 @@ func Test_updatePost(t *testing.T) { t.Errorf("Expected nil, recieved %s", err.Error()) } - defer Database.DB. - Session(&gorm.Session{FullSaveAssociations: true}). - Unscoped(). - Select("PostLinks"). - Delete(&postData) - if updatePostData.Content != "New test content" { t.Errorf("Expected \"New test content\", recieved %s", updatePostData.Content) } diff --git a/Api/Routes.go b/Api/Routes.go index 4ce2674..366d8cd 100644 --- a/Api/Routes.go +++ b/Api/Routes.go @@ -17,17 +17,22 @@ func InitApiEndpoints() *mux.Router { // Define routes for posts api router.HandleFunc("/post", getPosts).Methods("GET") - router.HandleFunc("/frontPagePosts", getFrontPagePosts).Methods("GET") router.HandleFunc("/post", createPost).Methods("POST") - router.HandleFunc("/post/{postID}", createPost).Methods("GET") + router.HandleFunc("/post/{postID}", getPost).Methods("GET") router.HandleFunc("/post/{postID}", updatePost).Methods("PUT") router.HandleFunc("/post/{postID}", deletePost).Methods("DELETE") + router.HandleFunc("/frontPagePosts", getFrontPagePosts).Methods("GET") + router.HandleFunc("/post/{postID}/image", createPostImage).Methods("POST") router.HandleFunc("/post/{postID}/image/{imageID}", deletePostImage).Methods("DELETE") // Define routes for users api + router.HandleFunc("/user", getUsers).Methods("GET") router.HandleFunc("/user", createUser).Methods("POST") + router.HandleFunc("/user/{userID}", getUser).Methods("GET") + router.HandleFunc("/user/{userID}", updatePost).Methods("PUT") + router.HandleFunc("/user/{userID}", deletePost).Methods("DELETE") //router.PathPrefix("/").Handler(http.StripPrefix("/images/", http.FileServer(http.Dir("./uploads")))) diff --git a/Api/UserHelper.go b/Api/UserHelper.go new file mode 100644 index 0000000..7a658ee --- /dev/null +++ b/Api/UserHelper.go @@ -0,0 +1,51 @@ +package Api + +import ( + "errors" + "log" + "net/http" + + "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database" + "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" + + "github.com/gorilla/mux" +) + +func getUserId(r *http.Request) (string, error) { + var ( + urlVars map[string]string + id string + ok bool + ) + + urlVars = mux.Vars(r) + id, ok = urlVars["userID"] + if !ok { + return id, errors.New("Could not get id") + } + return id, nil +} + +func getUserById(w http.ResponseWriter, r *http.Request) (Models.User, error) { + var ( + postData Models.User + id string + err error + ) + + id, err = getUserId(r) + if err != nil { + log.Printf("Error encountered getting id\n") + JsonReturn(w, 500, "An error occured") + return postData, err + } + + postData, err = Database.GetUserById(id) + if err != nil { + log.Printf("Could not find pet with id %s\n", id) + JsonReturn(w, 404, "Not found") + return postData, err + } + + return postData, nil +} diff --git a/Api/Users.go b/Api/Users.go index c343b69..33f035d 100644 --- a/Api/Users.go +++ b/Api/Users.go @@ -8,6 +8,7 @@ import ( "net/url" "strconv" + "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Api/Auth" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Api/JsonSerialization" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" @@ -56,6 +57,29 @@ func getUsers(w http.ResponseWriter, r *http.Request) { w.Write(returnJson) } +func getUser(w http.ResponseWriter, r *http.Request) { + var ( + userData Models.User + returnJson []byte + err error + ) + + userData, err = getUserById(w, r) + if err != nil { + return + } + + returnJson, err = json.MarshalIndent(userData, "", " ") + if err != nil { + JsonReturn(w, 500, "An error occured") + return + } + + // Return updated json + w.WriteHeader(http.StatusOK) + w.Write(returnJson) +} + func createUser(w http.ResponseWriter, r *http.Request) { var ( userData Models.User @@ -87,16 +111,93 @@ func createUser(w http.ResponseWriter, r *http.Request) { } if userData.Password != userData.ConfirmPassword { - JsonReturn(w, 500, "invalid_password") + JsonReturn(w, 405, "invalid_password") + return + } + + userData.Password, err = Auth.HashPassword(userData.Password) + if err != nil { + JsonReturn(w, 500, "An error occured") return } err = Database.CreateUser(&userData) if err != nil { + JsonReturn(w, 500, "An error occured") + return + } + + // Return updated json + w.WriteHeader(http.StatusOK) +} + +func updateUser(w http.ResponseWriter, r *http.Request) { + var ( + userData Models.User + requestBody []byte + returnJson []byte + id string + err error + ) + + id, err = getUserId(r) + if err != nil { + log.Printf("Error encountered getting id\n") + JsonReturn(w, 500, "An error occured") + return + } + + requestBody, err = ioutil.ReadAll(r.Body) + if err != nil { + log.Printf("Error encountered reading POST body: %s\n", err.Error()) + JsonReturn(w, 500, "An error occured") + return + } + + userData, err = JsonSerialization.DeserializeUser(requestBody, []string{}, true) + if err != nil { + log.Printf("Invalid data provided to users API: %s\n", err.Error()) JsonReturn(w, 405, "Invalid data") return } + err = Database.UpdateUser(id, &userData) + if err != nil { + log.Printf("An error occured: %s\n", err.Error()) + JsonReturn(w, 500, "An error occured") + return + } + + returnJson, err = json.MarshalIndent(userData, "", " ") + if err != nil { + log.Printf("An error occured: %s\n", err.Error()) + JsonReturn(w, 500, "An error occured") + return + } + + // Return updated json + w.WriteHeader(http.StatusOK) + w.Write(returnJson) +} + +func deleteUser(w http.ResponseWriter, r *http.Request) { + var ( + userData Models.User + err error + ) + + userData, err = getUserById(w, r) + if err != nil { + return + } + + err = Database.DeleteUser(&userData) + if err != nil { + log.Printf("An error occured: %s\n", err.Error()) + JsonReturn(w, 500, "An error occured") + return + } + // Return updated json w.WriteHeader(http.StatusOK) } diff --git a/Api/Users_test.go b/Api/Users_test.go index 8007c12..162e83f 100644 --- a/Api/Users_test.go +++ b/Api/Users_test.go @@ -3,8 +3,6 @@ package Api import ( "encoding/json" "fmt" - "io/ioutil" - "log" "math/rand" "net/http" "net/http/httptest" @@ -13,11 +11,12 @@ import ( "runtime" "strings" "testing" + "time" + "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Api/Auth" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" "github.com/gorilla/mux" - "gorm.io/gorm" ) func init() { @@ -29,15 +28,14 @@ func init() { panic(err) } - log.SetOutput(ioutil.Discard) - Database.Init() + Database.InitTest() r = mux.NewRouter() } var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") -func RandStringRunes(n int) string { +func randString(n int) string { b := make([]rune, n) for i := range b { b[i] = letterRunes[rand.Intn(len(letterRunes))] @@ -45,6 +43,84 @@ func RandStringRunes(n int) string { return string(b) } +func createTestUser(random bool) (Models.User, error) { + now := time.Now() + + email := "email@email.com" + if random { + email = fmt.Sprintf("%s@email.com", randString(16)) + } + + password, err := Auth.HashPassword("password") + if err != nil { + return Models.User{}, err + } + + userData := Models.User{ + Email: email, + Password: password, + LastLogin: &now, + FirstName: "Hugh", + LastName: "Mann", + } + + err = Database.CreateUser(&userData) + return userData, err +} + +func Test_getUser(t *testing.T) { + t.Log("Testing getPost...") + + r.HandleFunc("/user/{userID}", getUser).Methods("GET") + + ts := httptest.NewServer(r) + + defer ts.Close() + + userData, err := createTestUser(false) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() + } + + res, err := http.Get(fmt.Sprintf( + "%s/user/%s", + ts.URL, + userData.ID, + )) + + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() + } + if res.StatusCode != http.StatusOK { + t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode) + t.FailNow() + } + + getUserData := new(Models.User) + err = json.NewDecoder(res.Body).Decode(getUserData) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() + } + + if getUserData.Email != "email@email.com" { + t.Errorf("Expected email \"email@email.com\", recieved %s", getUserData.Email) + t.FailNow() + } + + if getUserData.FirstName != "Hugh" { + t.Errorf("Expected email \"Hugh\", recieved %s", getUserData.FirstName) + t.FailNow() + } + + if getUserData.LastName != "Mann" { + t.Errorf("Expected email \"Mann\", recieved %s", getUserData.LastName) + t.FailNow() + } +} + func Test_getUsers(t *testing.T) { t.Log("Testing getUsers...") @@ -55,43 +131,30 @@ func Test_getUsers(t *testing.T) { var err error for i := 0; i < 20; i++ { - userData := Models.User{ - Email: fmt.Sprintf( - "%s@email.com", - RandStringRunes(16), - ), - Password: "password", - ConfirmPassword: "password", - } - - err = Database.CreateUser(&userData) - if err != nil { - t.Errorf("Expected nil, recieved %s", err.Error()) - } - - defer Database.DB. - Session(&gorm.Session{FullSaveAssociations: true}). - Unscoped(). - Delete(&userData) + createTestUser(true) } res, err := http.Get(ts.URL + "/user?page=1&pageSize=10") if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() } if res.StatusCode != http.StatusOK { t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode) + t.FailNow() } getUsersData := new([]Models.User) err = json.NewDecoder(res.Body).Decode(getUsersData) if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() } if len(*getUsersData) != 10 { t.Errorf("Expected 10, recieved %d", len(*getUsersData)) + t.FailNow() } } @@ -104,15 +167,18 @@ func Test_createUser(t *testing.T) { defer ts.Close() + email := fmt.Sprintf("%s@email.com", randString(16)) + postJson := ` { - "email": "email@email.com", + "email": "%s", "password": "password", "confirm_password": "password", "first_name": "Hugh", "last_name": "Mann" } ` + postJson = fmt.Sprintf(postJson, email) res, err := http.Post(ts.URL+"/user", "application/json", strings.NewReader(postJson)) if err != nil { @@ -124,9 +190,107 @@ func Test_createUser(t *testing.T) { t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode) return } +} + +func Test_updateUser(t *testing.T) { + t.Log("Testing updateUser...") + + r.HandleFunc("/user/{userID}", updateUser).Methods("PUT") + + ts := httptest.NewServer(r) + + defer ts.Close() + + userData, err := createTestUser(true) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + } + + email := fmt.Sprintf("%s@email.com", randString(16)) + + postJson := ` +{ + "email": "%s", + "first_name": "first", + "last_name": "last" +} +` + postJson = fmt.Sprintf(postJson, email) + + req, err := http.NewRequest("PUT", fmt.Sprintf( + "%s/user/%s", + ts.URL, + userData.ID, + ), strings.NewReader(postJson)) + + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + } + + // Fetch Request + res, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode) + } + + updateUserData := new(Models.User) + err = json.NewDecoder(res.Body).Decode(updateUserData) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + } + + if updateUserData.Email != email { + t.Errorf("Expected email \"%s\", recieved %s", email, updateUserData.Email) + } + + if updateUserData.FirstName != "first" { + t.Errorf("Expected FirstName \"first\", recieved %s", updateUserData.FirstName) + } + + if updateUserData.LastName != "last" { + t.Errorf("Expected LastName \"last\", recieved %s", updateUserData.LastName) + } +} + +func Test_deleteUser(t *testing.T) { + t.Log("Testing deleteUser...") + + r.HandleFunc("/user/{userID}", deleteUser).Methods("DELETE") + + ts := httptest.NewServer(r) + + defer ts.Close() + + userData, err := createTestUser(true) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + t.FailNow() + } + + req, err := http.NewRequest("DELETE", fmt.Sprintf( + "%s/user/%s", + ts.URL, + userData.ID, + ), nil) + + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + } + + // Fetch Request + res, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + defer res.Body.Close() - Database.DB.Model(Models.User{}). - Select("count(*) > 0"). - Where("email = ?", "email@email.com"). - Delete(Models.User{}) + if res.StatusCode != http.StatusOK { + t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode) + } } diff --git a/Database/Init.go b/Database/Init.go index 44c1930..20f5f92 100644 --- a/Database/Init.go +++ b/Database/Init.go @@ -10,14 +10,30 @@ import ( ) const dbUrl = "postgres://postgres:@localhost:5432/sudden_impact_records" +const dbTestUrl = "postgres://postgres:@localhost:5432/sudden_impact_records_test" var ( DB *gorm.DB ) +func GetModels() []interface{} { + return []interface{}{ + &Models.User{}, + &Models.PostImage{}, + &Models.PostVideo{}, + &Models.PostAudio{}, + &Models.PostLink{}, + &Models.Post{}, + &Models.SubscriptionEmailAttachment{}, + &Models.SubscriptionEmail{}, + &Models.Subscription{}, + } +} + func Init() { var ( - err error + model interface{} + err error ) log.Println("Initializing database...") @@ -28,22 +44,27 @@ func Init() { log.Fatalln(err) } - log.Println("Running AutoMigrate on Post tables...") + log.Println("Running AutoMigrate...") + + for _, model = range GetModels() { + DB.AutoMigrate(model) + } +} - // Post tables - DB.AutoMigrate(&Models.PostImage{}) - DB.AutoMigrate(&Models.PostVideo{}) - DB.AutoMigrate(&Models.PostAudio{}) - DB.AutoMigrate(&Models.PostLink{}) - DB.AutoMigrate(&Models.Post{}) +func InitTest() { + var ( + model interface{} + err error + ) - log.Println("Running AutoMigrate on Subscription tables...") + DB, err = gorm.Open(postgres.Open(dbTestUrl), &gorm.Config{}) - // Email subscription tables - DB.AutoMigrate(&Models.SubscriptionEmailAttachment{}) - DB.AutoMigrate(&Models.SubscriptionEmail{}) - DB.AutoMigrate(&Models.Subscription{}) + if err != nil { + log.Fatalln(err) + } - log.Println("Running AutoMigrate on User tables...") - DB.AutoMigrate(&Models.User{}) + for _, model = range GetModels() { + DB.Migrator().DropTable(model) + DB.AutoMigrate(model) + } } diff --git a/Database/Users.go b/Database/Users.go index e28b898..3f9d0a9 100644 --- a/Database/Users.go +++ b/Database/Users.go @@ -6,11 +6,28 @@ import ( "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" "gorm.io/gorm" + "gorm.io/gorm/clause" ) +func GetUserById(id string) (Models.User, error) { + var ( + userData Models.User + err error + ) + + err = DB.Preload(clause.Associations). + First(&userData, "id = ?", id). + Error + + userData.Password = "" + + return userData, err +} + func GetUsers(page, pageSize int) ([]Models.User, error) { var ( users []Models.User + i int err error ) @@ -30,6 +47,10 @@ func GetUsers(page, pageSize int) ([]Models.User, error) { Find(&users). Error + for i, _ = range users { + users[i].Password = "" + } + return users, err } @@ -57,7 +78,37 @@ func CheckUniqueEmail(email string) error { } func CreateUser(userData *Models.User) error { - return DB.Session(&gorm.Session{FullSaveAssociations: true}). + var ( + err error + ) + + err = DB.Session(&gorm.Session{FullSaveAssociations: true}). Create(userData). Error + + userData.Password = "" + + return err +} + +func UpdateUser(id string, userData *Models.User) error { + var ( + err error + ) + err = DB.Model(&Models.Post{}). + Select("*"). + Omit("id", "created_at", "updated_at", "deleted_at"). + Where("id = ?", id). + Updates(userData). + Error + + userData.Password = "" + + return err +} + +func DeleteUser(userData *Models.User) error { + return DB.Session(&gorm.Session{FullSaveAssociations: true}). + Delete(userData). + Error } diff --git a/Models/Posts.go b/Models/Posts.go index a7c5e0d..85760e7 100644 --- a/Models/Posts.go +++ b/Models/Posts.go @@ -6,10 +6,11 @@ import ( type Post struct { Base - Title string `gorm:"not null" json:"title"` - Content string `gorm:"not null" json:"content"` - FrontPage bool `gorm:"not null;type:boolean" json:"front_page"` - Order int `gorm:"not null" json:"order"` + UserID uuid.UUID `gorm:"type:uuid;column:user_id;not null;" json:"user_id"` + Title string `gorm:"not null" json:"title"` + Content string `gorm:"not null" json:"content"` + FrontPage bool `gorm:"not null;type:boolean" json:"front_page"` + Order int `gorm:"not null" json:"order"` PostLinks []PostLink `json:"links"` PostImages []PostImage `json:"images"` diff --git a/Models/Users.go b/Models/Users.go index 27401e4..ff3bc83 100644 --- a/Models/Users.go +++ b/Models/Users.go @@ -7,7 +7,7 @@ import ( type User struct { Base Email string `gorm:"not null;unique" json:"email"` - Password string `gorm:"not null" json:"password"` + Password string `gorm:"not null" json:"password,omitempty"` ConfirmPassword string `gorm:"-" json:"confirm_password"` LastLogin *time.Time `json:"last_login"` FirstName string `gorm:"not null" json:"first_name"`