#1 Add post image API cruds

Merged
tovi merged 3 commits from feature/post-fk-cruds into develop 3 years ago
  1. +1
    -0
      .gitignore
  2. +51
    -0
      Api/PostHelper.go
  3. +50
    -0
      Api/PostImageHelper.go
  4. +127
    -0
      Api/PostImages.go
  5. +273
    -0
      Api/PostImages_test.go
  6. +1
    -28
      Api/Posts.go
  7. +79
    -33
      Api/Posts_test.go
  8. +3
    -0
      Api/Routes.go
  9. +33
    -0
      Database/PostImages.go
  10. +6
    -0
      Database/Posts.go
  11. +0
    -0
      Frontend/public/images/.gitkeep
  12. +12
    -0
      Makefile
  13. +14
    -6
      Models/Posts.go
  14. +67
    -0
      Util/Files.go
  15. +2
    -0
      go.mod
  16. +5
    -0
      go.sum
  17. +1
    -1
      main.go

+ 1
- 0
.gitignore View File

@ -0,0 +1 @@
/Frontend/public/images/*

+ 51
- 0
Api/PostHelper.go View File

@ -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 getPostId(r *http.Request) (string, error) {
var (
urlVars map[string]string
id string
ok bool
)
urlVars = mux.Vars(r)
id, ok = urlVars["postID"]
if !ok {
return id, errors.New("Could not get id")
}
return id, nil
}
func getPostById(w http.ResponseWriter, r *http.Request) (Models.Post, error) {
var (
postData Models.Post
id string
err error
)
id, err = getPostId(r)
if err != nil {
log.Printf("Error encountered getting id\n")
JsonReturn(w, 500, "An error occured")
return postData, err
}
postData, err = Database.GetPostById(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
}

+ 50
- 0
Api/PostImageHelper.go View File

@ -0,0 +1,50 @@
package Api
import (
"errors"
"log"
"net/http"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models"
"github.com/gorilla/mux"
)
func getPostImageId(r *http.Request) (string, error) {
var (
urlVars map[string]string
id string
ok bool
)
urlVars = mux.Vars(r)
id, ok = urlVars["imageID"]
if !ok {
return id, errors.New("Could not get id")
}
return id, nil
}
func getPostImageById(w http.ResponseWriter, r *http.Request) (Models.PostImage, error) {
var (
postImageData Models.PostImage
id string
err error
)
id, err = getPostImageId(r)
if err != nil {
log.Printf("Error encountered getting id\n")
JsonReturn(w, 500, "An error occured")
return postImageData, err
}
postImageData, err = Database.GetPostImageById(id)
if err != nil {
log.Printf("Could not find pet with id %s\n", id)
JsonReturn(w, 404, "Not found")
return postImageData, err
}
return postImageData, nil
}

+ 127
- 0
Api/PostImages.go View File

@ -0,0 +1,127 @@
package Api
import (
"encoding/json"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Util"
"github.com/gofrs/uuid"
)
func createPostImage(w http.ResponseWriter, r *http.Request) {
var (
postData Models.Post
postID string
postUUID uuid.UUID
postImage Models.PostImage
formData *multipart.Form
fileHeaders []*multipart.FileHeader
fileHeader *multipart.FileHeader
file multipart.File
fileBytes []byte
fileObject Util.FileObject
returnJson []byte
err error
)
postID, err = getPostId(r)
if err != nil {
log.Printf("Error encountered getting id\n")
JsonReturn(w, 500, "An error occured")
return
}
postUUID = uuid.FromStringOrNil(postID)
err = r.ParseMultipartForm(20 << 20)
if err != nil {
log.Printf("Error encountered parsing multipart form: %s\n", err.Error())
JsonReturn(w, 500, "An error occured")
return
}
formData = r.MultipartForm
fileHeaders = formData.File["files"]
for _, fileHeader = range fileHeaders {
file, err = fileHeader.Open()
if err != nil {
log.Printf("Error encountered while post image upload: %s\n", err.Error())
JsonReturn(w, 500, "An error occured")
return
}
defer file.Close()
fileBytes, err = ioutil.ReadAll(file)
if err != nil {
log.Printf("Error encountered while post image upload: %s\n", err.Error())
JsonReturn(w, 500, "An error occured")
return
}
fileObject, err = Util.WriteFile(fileBytes, "image")
if err != nil {
log.Printf("Error encountered while post image upload: %s\n", err.Error())
JsonReturn(w, 415, "Invalid filetype")
return
}
postImage = Models.PostImage{
PostID: postUUID,
Filepath: fileObject.Filepath,
Mimetype: fileObject.Mimetype,
Size: fileObject.Size,
}
err = Database.CreatePostImage(&postImage)
if err != nil {
log.Printf("Error encountered while creating post_image record: %s\n", err.Error())
JsonReturn(w, 500, "An error occured")
return
}
}
postData, err = getPostById(w, r)
if err != nil {
return
}
returnJson, err = json.MarshalIndent(postData, "", " ")
if err != nil {
JsonReturn(w, 500, "An error occured")
return
}
// Return updated json
w.WriteHeader(http.StatusOK)
w.Write(returnJson)
}
func deletePostImage(w http.ResponseWriter, r *http.Request) {
var (
postImageData Models.PostImage
err error
)
postImageData, err = getPostImageById(w, r)
if err != nil {
return
}
err = Database.DeletePostImage(&postImageData)
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)
}

+ 273
- 0
Api/PostImages_test.go View File

@ -0,0 +1,273 @@
package Api
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"net/http/httptest"
"os"
"path"
"path/filepath"
"runtime"
"strconv"
"testing"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models"
"github.com/gorilla/mux"
"gorm.io/gorm"
)
func init() {
// Fix working directory for tests
_, filename, _, _ := runtime.Caller(0)
dir := path.Join(path.Dir(filename), "..")
err := os.Chdir(dir)
if err != nil {
panic(err)
}
log.SetOutput(ioutil.Discard)
Database.Init()
r = mux.NewRouter()
}
func get(url string) (resp *http.Response, err error) {
for i := 0; i < 5; i++ {
resp, err = http.Get(url)
if err == nil {
return resp, err
}
}
return resp, err
}
// Image generates a *os.File with a random image using the loremflickr.com service
func fakeImage(width, height int, categories []string, prefix string, categoriesStrict bool) *os.File {
url := "https://loremflickr.com"
switch prefix {
case "g":
url += "/g"
case "p":
url += "/p"
case "red":
url += "/red"
case "green":
url += "/green"
case "blue":
url += "/blue"
}
url += string('/') + strconv.Itoa(width) + string('/') + strconv.Itoa(height)
if len(categories) > 0 {
url += string('/')
for _, category := range categories {
url += category + string(',')
}
if categoriesStrict {
url += "/all"
}
}
resp, err := get(url)
defer resp.Body.Close()
if err != nil {
panic(err)
}
f, err := ioutil.TempFile(os.TempDir(), "loremflickr-img-*.jpg")
if err != nil {
panic(err)
}
io.Copy(f, resp.Body)
err = f.Close()
if err != nil {
panic(err)
}
return f
}
func Test_createPostImages(t *testing.T) {
t.Log("Testing createPostImages...")
r.HandleFunc("/post/{postID}/image", createPostImage).Methods("POST")
ts := httptest.NewServer(r)
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)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
image := fakeImage(100, 100, []string{}, "", false)
image, err = os.Open(image.Name())
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("files", filepath.Base(image.Name()))
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
io.Copy(part, image)
writer.Close()
request, err := http.NewRequest(
"POST",
fmt.Sprintf(
"%s/post/%s/image",
ts.URL,
postData.ID,
),
body,
)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
request.Header.Add("Content-Type", writer.FormDataContentType())
client := &http.Client{}
res, err := client.Do(request)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
if res.StatusCode != http.StatusOK {
t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode)
}
defer res.Body.Close()
updatePostData := new(Models.Post)
err = json.NewDecoder(res.Body).Decode(updatePostData)
if err != nil {
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))
}
for _, f := range updatePostData.PostImages {
if _, err := os.Stat("./" + f.Filepath); errors.Is(err, os.ErrNotExist) {
t.Errorf(
"File ./%s does not exist",
f.Filepath,
)
} else {
os.Remove("./" + f.Filepath)
}
}
}
func Test_deletePostImages(t *testing.T) {
t.Log("Testing createPostImages...")
r.HandleFunc("/post/{postID}/image/{imageID}", deletePostImage).Methods("DELETE")
ts := httptest.NewServer(r)
defer ts.Close()
image := fakeImage(100, 100, []string{}, "", false)
image, err := os.Open(image.Name())
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
defer image.Close()
postData := Models.Post{
Title: "Test post",
Content: "Test content",
FrontPage: true,
Order: 1,
PostLinks: []Models.PostLink{
{
Type: "Facebook",
Link: "http://facebook.com/",
},
},
PostImages: []Models.PostImage{
{
Filepath: image.Name(),
},
},
}
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", "PostImages").
Delete(&postData)
req, err := http.NewRequest("DELETE", fmt.Sprintf(
"%s/post/%s/image/%s",
ts.URL,
postData.ID,
postData.PostImages[0].ID,
), nil)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode)
}
}

+ 1
- 28
Api/Posts.go View File

@ -2,7 +2,6 @@ package Api
import ( import (
"encoding/json" "encoding/json"
"errors"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
@ -12,36 +11,10 @@ import (
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Api/JsonSerialization" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Api/JsonSerialization"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
func getPostById(w http.ResponseWriter, r *http.Request) (Models.Post, error) {
var (
postData Models.Post
urlVars map[string]string
id string
ok bool
err error
)
urlVars = mux.Vars(r)
id, ok = urlVars["postID"]
if !ok {
log.Printf("Error encountered getting id\n")
JsonReturn(w, 500, "An error occured")
return postData, errors.New("Could not get id")
}
postData, err = Database.GetPostById(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
}
func getPosts(w http.ResponseWriter, r *http.Request) { func getPosts(w http.ResponseWriter, r *http.Request) {
var ( var (
posts []Models.Post posts []Models.Post


+ 79
- 33
Api/Posts_test.go View File

@ -7,25 +7,47 @@ import (
"log" "log"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os"
"path"
"runtime"
"strings" "strings"
"testing" "testing"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database"
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" "git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"gorm.io/gorm"
) )
func Test_getPosts(t *testing.T) {
var (
r *mux.Router
)
func init() {
// Fix working directory for tests
_, filename, _, _ := runtime.Caller(0)
dir := path.Join(path.Dir(filename), "..")
err := os.Chdir(dir)
if err != nil {
panic(err)
}
log.SetOutput(ioutil.Discard) log.SetOutput(ioutil.Discard)
Database.Init() Database.Init()
r := mux.NewRouter()
r = mux.NewRouter()
}
func Test_getPosts(t *testing.T) {
t.Log("Testing getPosts...")
r.HandleFunc("/post", getPosts).Methods("GET") r.HandleFunc("/post", getPosts).Methods("GET")
ts := httptest.NewServer(r) ts := httptest.NewServer(r)
defer ts.Close() defer ts.Close()
var err error
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
postData := Models.Post{ postData := Models.Post{
Title: "Test post", Title: "Test post",
@ -35,14 +57,21 @@ func Test_getPosts(t *testing.T) {
PostLinks: []Models.PostLink{ PostLinks: []Models.PostLink{
{ {
Type: "Facebook", Type: "Facebook",
Link: "http://google.com/",
Link: "http://facebook.com/",
}, },
}, },
} }
Database.CreatePost(&postData)
err = Database.CreatePost(&postData)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
defer Database.DB.Unscoped().Delete(&postData)
defer Database.DB.
Session(&gorm.Session{FullSaveAssociations: true}).
Unscoped().
Select("PostLinks").
Delete(&postData)
} }
res, err := http.Get(ts.URL + "/post?page=1&pageSize=10") res, err := http.Get(ts.URL + "/post?page=1&pageSize=10")
@ -66,10 +95,8 @@ func Test_getPosts(t *testing.T) {
} }
func Test_getPost(t *testing.T) { func Test_getPost(t *testing.T) {
log.SetOutput(ioutil.Discard)
Database.Init()
t.Log("Testing getPost...")
r := mux.NewRouter()
r.HandleFunc("/post/{postID}", getPost).Methods("GET") r.HandleFunc("/post/{postID}", getPost).Methods("GET")
ts := httptest.NewServer(r) ts := httptest.NewServer(r)
@ -84,12 +111,21 @@ func Test_getPost(t *testing.T) {
PostLinks: []Models.PostLink{ PostLinks: []Models.PostLink{
{ {
Type: "Facebook", Type: "Facebook",
Link: "http://google.com/",
Link: "http://facebook.com/",
}, },
}, },
} }
Database.CreatePost(&postData)
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)
res, err := http.Get(fmt.Sprintf( res, err := http.Get(fmt.Sprintf(
"%s/post/%s", "%s/post/%s",
@ -109,15 +145,11 @@ func Test_getPost(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error()) t.Errorf("Expected nil, recieved %s", err.Error())
} }
Database.DB.Unscoped().Delete(&postData)
} }
func Test_createPost(t *testing.T) { func Test_createPost(t *testing.T) {
log.SetOutput(ioutil.Discard)
Database.Init()
t.Log("Testing createPost...")
r := mux.NewRouter()
r.HandleFunc("/post", createPost).Methods("POST") r.HandleFunc("/post", createPost).Methods("POST")
ts := httptest.NewServer(r) ts := httptest.NewServer(r)
@ -132,7 +164,7 @@ func Test_createPost(t *testing.T) {
"order": 1, "order": 1,
"links": [{ "links": [{
"type": "Facebook", "type": "Facebook",
"link": "http://google.com/"
"link": "http://facebook.com/"
}] }]
} }
` `
@ -151,21 +183,23 @@ func Test_createPost(t *testing.T) {
t.Errorf("Expected nil, recieved %s", err.Error()) 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" { if postData.Title != "Test post" {
t.Errorf("Expected title \"Test post\", recieved \"%s\"", postData.Title) t.Errorf("Expected title \"Test post\", recieved \"%s\"", postData.Title)
} }
if postData.Content != "Test content" { if postData.Content != "Test content" {
t.Errorf("Expected content \"Test content\", recieved \"%s\"", postData.Content) t.Errorf("Expected content \"Test content\", recieved \"%s\"", postData.Content)
} }
Database.DB.Unscoped().Delete(&postData)
} }
func Test_deletePost(t *testing.T) { func Test_deletePost(t *testing.T) {
log.SetOutput(ioutil.Discard)
Database.Init()
t.Log("Testing deletePost...")
r := mux.NewRouter()
r.HandleFunc("/post/{postID}", deletePost).Methods("DELETE") r.HandleFunc("/post/{postID}", deletePost).Methods("DELETE")
ts := httptest.NewServer(r) ts := httptest.NewServer(r)
@ -180,12 +214,21 @@ func Test_deletePost(t *testing.T) {
PostLinks: []Models.PostLink{ PostLinks: []Models.PostLink{
{ {
Type: "Facebook", Type: "Facebook",
Link: "http://google.com/",
Link: "http://facebook.com/",
}, },
}, },
} }
Database.CreatePost(&postData)
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)
req, err := http.NewRequest("DELETE", fmt.Sprintf( req, err := http.NewRequest("DELETE", fmt.Sprintf(
"%s/post/%s", "%s/post/%s",
@ -208,15 +251,11 @@ func Test_deletePost(t *testing.T) {
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode) t.Errorf("Expected %d, recieved %d", http.StatusOK, res.StatusCode)
} }
Database.DB.Unscoped().Delete(&postData)
} }
func Test_updatePost(t *testing.T) { func Test_updatePost(t *testing.T) {
log.SetOutput(ioutil.Discard)
Database.Init()
t.Log("Testing updatePost...")
r := mux.NewRouter()
r.HandleFunc("/post/{postID}", updatePost).Methods("PUT") r.HandleFunc("/post/{postID}", updatePost).Methods("PUT")
ts := httptest.NewServer(r) ts := httptest.NewServer(r)
@ -231,12 +270,15 @@ func Test_updatePost(t *testing.T) {
PostLinks: []Models.PostLink{ PostLinks: []Models.PostLink{
{ {
Type: "Facebook", Type: "Facebook",
Link: "http://google.com/",
Link: "http://facebook.com/",
}, },
}, },
} }
Database.CreatePost(&postData)
err := Database.CreatePost(&postData)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
}
postJson := ` postJson := `
{ {
@ -273,6 +315,12 @@ func Test_updatePost(t *testing.T) {
t.Errorf("Expected nil, recieved %s", err.Error()) 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" { if updatePostData.Content != "New test content" {
t.Errorf("Expected \"New test content\", recieved %s", updatePostData.Content) t.Errorf("Expected \"New test content\", recieved %s", updatePostData.Content)
} }
@ -284,6 +332,4 @@ func Test_updatePost(t *testing.T) {
if updatePostData.Order != 2 { if updatePostData.Order != 2 {
t.Errorf("Expected 2, recieved %d", updatePostData.Order) t.Errorf("Expected 2, recieved %d", updatePostData.Order)
} }
Database.DB.Unscoped().Delete(&postData)
} }

+ 3
- 0
Api/Routes.go View File

@ -23,6 +23,9 @@ func InitApiEndpoints() *mux.Router {
router.HandleFunc("/post/{postID}", updatePost).Methods("PUT") router.HandleFunc("/post/{postID}", updatePost).Methods("PUT")
router.HandleFunc("/post/{postID}", deletePost).Methods("DELETE") router.HandleFunc("/post/{postID}", deletePost).Methods("DELETE")
router.HandleFunc("/post/{postID}/image", createPostImage).Methods("POST")
router.HandleFunc("/post/{postID}/image/{imageID}", deletePostImage).Methods("DELETE")
//router.PathPrefix("/").Handler(http.StripPrefix("/images/", http.FileServer(http.Dir("./uploads")))) //router.PathPrefix("/").Handler(http.StripPrefix("/images/", http.FileServer(http.Dir("./uploads"))))
return router return router


+ 33
- 0
Database/PostImages.go View File

@ -0,0 +1,33 @@
package Database
import (
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
func CreatePostImage(postImageData *Models.PostImage) error {
return DB.Session(&gorm.Session{FullSaveAssociations: true}).
Create(postImageData).
Error
}
func GetPostImageById(id string) (Models.PostImage, error) {
var (
postImageData Models.PostImage
err error
)
err = DB.Preload(clause.Associations).
First(&postImageData, "id = ?", id).
Error
return postImageData, err
}
func DeletePostImage(postImageData *Models.PostImage) error {
return DB.Session(&gorm.Session{FullSaveAssociations: true}).
Delete(postImageData).
Error
}

+ 6
- 0
Database/Posts.go View File

@ -70,12 +70,18 @@ func UpdatePost(id string, postData *Models.Post) (Models.Post, error) {
err error err error
) )
DB.Model(postData).
Where("id = ?", id).
Association("PostLinks").
Replace(postData.PostLinks)
err = DB.Model(&Models.Post{}). err = DB.Model(&Models.Post{}).
Select("*"). Select("*").
Omit("id", "created_at", "updated_at", "deleted_at"). Omit("id", "created_at", "updated_at", "deleted_at").
Where("id = ?", id). Where("id = ?", id).
Updates(postData). Updates(postData).
Error Error
if err != nil { if err != nil {
return Models.Post{}, err return Models.Post{}, err
} }


+ 0
- 0
Frontend/public/images/.gitkeep View File


+ 12
- 0
Makefile View File

@ -0,0 +1,12 @@
FLAC_FILES = $(shell find . -type d -not -path '*/\.git/*' -not -path '*\/.git' -not -path '.')
default: test build
build:
go build -o SuddenImpactRecords main
test:
for dir in ${FLAC_FILES}; do \
go test $$dir; \
done

+ 14
- 6
Models/Posts.go View File

@ -29,25 +29,33 @@ const (
type PostLink struct { type PostLink struct {
Base Base
PostID uuid.UUID `gorm:"type:uuid;column:post_foreign_key;not null;" json:"post_id"`
PostID uuid.UUID `gorm:"type:uuid;column:post_id;not null;" json:"post_id"`
Link string `gorm:"not null" json:"link"` Link string `gorm:"not null" json:"link"`
Type PostLinkType `gorm:"not null" json:"type"` Type PostLinkType `gorm:"not null" json:"type"`
} }
type PostImage struct { type PostImage struct {
Base Base
PostID uuid.UUID `gorm:"type:uuid;column:post_foreign_key;not null;" json:"post_id"`
PostID uuid.UUID `gorm:"type:uuid;column:post_id;not null;" json:"post_id"`
Filepath string `gorm:"not null" json:"filepath"` Filepath string `gorm:"not null" json:"filepath"`
Mimetype string `gorm:"not null" json:"mimetype"`
Size int64 `gorm:"not null"`
} }
type PostVideo struct { type PostVideo struct {
Base Base
PostID uuid.UUID `gorm:"type:uuid;column:post_foreign_key;not null;" json:"post_id"`
Filepath string `gorm:"not null" json:"filepath"`
PostID uuid.UUID `gorm:"type:uuid;column:post_id;not null;" json:"post_id"`
Filepath string `json:"filepath"`
Mimetype string `json:"mimetype"`
Size int64 `json:"size"`
Url string `json:"url"`
} }
type PostAudio struct { type PostAudio struct {
Base Base
PostID uuid.UUID `gorm:"type:uuid;column:post_foreign_key;not null;" json:"post_id"`
Filepath string `gorm:"not null" json:"filepath"`
PostID uuid.UUID `gorm:"type:uuid;column:post_id;not null;" json:"post_id"`
Filepath string `json:"filepath"`
Mimetype string `json:"mimetype"`
Size int64 `json:"size"`
Url string `json:"url"`
} }

+ 67
- 0
Util/Files.go View File

@ -0,0 +1,67 @@
package Util
import (
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/gabriel-vasile/mimetype"
)
type FileObject struct {
Filepath string
Mimetype string
Size int64
}
func WriteFile(fileBytes []byte, acceptedMime string) (FileObject, error) {
var (
mime *mimetype.MIME
mimeSplit []string
file *os.File
fi os.FileInfo
fileObject FileObject
err error
)
mime = mimetype.Detect(fileBytes)
mimeSplit = strings.Split(mime.String(), "/")
if mimeSplit[0] != acceptedMime {
return fileObject, errors.New("Invalid filetype provided")
}
file, err = ioutil.TempFile(
fmt.Sprintf(
"./Frontend/public/%ss/",
mimeSplit[0],
),
fmt.Sprintf(
"%ss-*%s",
mimeSplit[0],
mime.Extension(),
),
)
if err != nil {
return fileObject, err
}
defer file.Close()
_, err = file.Write(fileBytes)
fi, err = file.Stat()
if err != nil {
return fileObject, err
}
fileObject = FileObject{
Filepath: file.Name(),
Mimetype: mime.String(),
Size: fi.Size(),
}
return fileObject, err
}

+ 2
- 0
go.mod View File

@ -4,6 +4,7 @@ go 1.17
require ( require (
github.com/Kangaroux/go-map-schema v0.6.1 github.com/Kangaroux/go-map-schema v0.6.1
github.com/gabriel-vasile/mimetype v1.4.0
github.com/gofrs/uuid v4.2.0+incompatible github.com/gofrs/uuid v4.2.0+incompatible
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
gorm.io/driver/postgres v1.3.1 gorm.io/driver/postgres v1.3.1
@ -22,5 +23,6 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.4 // indirect github.com/jinzhu/now v1.1.4 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
) )

+ 5
- 0
go.sum View File

@ -11,6 +11,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro=
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@ -144,6 +146,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 h1:Ugb8sMTWuWRC3+sz5WeN/4kejDx9BvIwnPUiJBjJE+8=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -156,6 +160,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=


+ 1
- 1
main.go View File

@ -20,5 +20,5 @@ func main() {
// TODO: Run this within goroutine when running vue application // TODO: Run this within goroutine when running vue application
// Start and listen to requests // Start and listen to requests
http.ListenAndServe(":8080", router)
http.ListenAndServe(":8081", router)
} }

Loading…
Cancel
Save