add book store

This commit is contained in:
rmanach 2025-01-03 16:18:39 +01:00
parent e0d7eeadc3
commit ae27d07170
6 changed files with 89 additions and 31 deletions

View File

@ -9,6 +9,8 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
const URL = "/"
func Handler() func(http.ResponseWriter, *http.Request) { func Handler() func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
switch r.Method { switch r.Method {

View File

@ -12,6 +12,8 @@ import (
"librapi/templates" "librapi/templates"
) )
const URL = "/login"
var ( var (
ErrInvalidUsername = errors.New("username must not be empty") ErrInvalidUsername = errors.New("username must not be empty")
ErrInvalidPassword = errors.New("password must not be empty") ErrInvalidPassword = errors.New("password must not be empty")

View File

@ -4,10 +4,8 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"io"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"os"
"strconv" "strconv"
"strings" "strings"
@ -17,7 +15,10 @@ import (
"librapi/templates" "librapi/templates"
) )
const MaxFileSize = 200 // in MB const (
URL = "/upload"
MaxFileSize = 200 // in MB
)
var ( var (
ErrInvalidName = errors.New("book name must not be empty") ErrInvalidName = errors.New("book name must not be empty")
@ -99,13 +100,13 @@ func (bf *BookForm) IsSuccess() bool {
return bf.Method == http.MethodPost && bf.Error == "" && !bf.HasErrors() return bf.Method == http.MethodPost && bf.Error == "" && !bf.HasErrors()
} }
func Handler(a services.IAuthenticate) func(http.ResponseWriter, *http.Request) { func Handler(a services.IAuthenticate, s services.IStore) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
switch r.Method { switch r.Method {
case http.MethodGet: case http.MethodGet:
getUploadFile(w, r) getUploadFile(w, r)
case http.MethodPost: case http.MethodPost:
postUploadFile(w, r, a) postUploadFile(w, r, a, s)
default: default:
http.Error(w, "method not allowed", http.StatusMethodNotAllowed) http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
} }
@ -163,7 +164,7 @@ func extractBookForm(r *http.Request) BookForm {
return bf return bf
} }
func postUploadFile(w http.ResponseWriter, r *http.Request, a services.IAuthenticate) { func postUploadFile(w http.ResponseWriter, r *http.Request, a services.IAuthenticate, s services.IStore) {
uploadForm := templates.GetUploadForm() uploadForm := templates.GetUploadForm()
if !a.IsLogged(r) { if !a.IsLogged(r) {
@ -171,6 +172,7 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, a services.IAuthenti
if err := uploadForm.Execute(buf, &BookForm{Error: services.ErrUnauthorized.Error()}); err != nil { if err := uploadForm.Execute(buf, &BookForm{Error: services.ErrUnauthorized.Error()}); err != nil {
log.Err(err).Msg("unable to generate template") log.Err(err).Msg("unable to generate template")
http.Error(w, "unexpected error occurred", http.StatusInternalServerError) http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
return
} }
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
@ -183,6 +185,7 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, a services.IAuthenti
if err := uploadForm.Execute(buf, &bf); err != nil { if err := uploadForm.Execute(buf, &bf); err != nil {
log.Err(err).Msg("unable to generate template") log.Err(err).Msg("unable to generate template")
http.Error(w, "unexpected error occurred", http.StatusInternalServerError) http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
return
} }
if bf.HasErrors() { if bf.HasErrors() {
@ -194,9 +197,8 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, a services.IAuthenti
filename := bf.File.Value.GetFilename() filename := bf.File.Value.GetFilename()
log.Info().Str("filename", filename).Msg("file is uploading...") log.Info().Str("filename", filename).Msg("file is uploading...")
dst, err := os.Create(filename) if err := s.Save(filename, bf.File.Value.file); err != nil {
if err != nil { if err := uploadForm.Execute(buf, &BookForm{Error: err.Error()}); err != nil {
if err := uploadForm.Execute(buf, &BookForm{Error: "unexpected error occurred while creating file"}); err != nil {
log.Err(err).Msg("unable to generate template") log.Err(err).Msg("unable to generate template")
http.Error(w, "unexpected error occurred", http.StatusInternalServerError) http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
} }
@ -206,20 +208,6 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, a services.IAuthenti
return return
} }
defer dst.Close()
if _, err := io.Copy(dst, bf.File.Value.file); err != nil {
if err := uploadForm.Execute(buf, &BookForm{Error: "unexpected error occurred while uploading file"}); err != nil {
log.Err(err).Msg("unable to generate template")
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, buf.String())
return
}
buf.Reset() buf.Reset()
if err := uploadForm.Execute(buf, &BookForm{Method: http.MethodPost}); err != nil { if err := uploadForm.Execute(buf, &BookForm{Method: http.MethodPost}); err != nil {
log.Err(err).Msg("unable to generate template") log.Err(err).Msg("unable to generate template")

View File

@ -27,16 +27,18 @@ func main() {
defer fnCancel() defer fnCancel()
auth := services.NewAuthentication(ctx) auth := services.NewAuthentication(ctx)
bs := services.NewBookStore(services.GetEnv().GetDir())
srv := server.NewServer( srv := server.NewServer(
ctx, ctx,
services.GetEnv().GetPort(), services.GetEnv().GetPort(),
server.NewHandler("/", home.Handler()), server.NewHandler(home.URL, home.Handler()),
server.NewHandler("/upload", upload.Handler(auth)), server.NewHandler(upload.URL, upload.Handler(auth, bs)),
server.NewHandler("/login", login.Handler(auth)), server.NewHandler(login.URL, login.Handler(auth)),
) )
srv.Serve() srv.Serve()
<-srv.Done() <-srv.Done()
<-auth.Done() <-auth.Done()
<-bs.Done()
} }

69
services/book_store.go Normal file
View File

@ -0,0 +1,69 @@
package services
import (
"errors"
"io"
"os"
"path/filepath"
"sync"
"github.com/rs/zerolog/log"
)
var (
ErrFileCreation = errors.New("unexpected error occurred while creating book file")
ErrFileCopy = errors.New("unexpected error occurred while copying book file")
)
type IStore interface {
Save(name string, content io.ReadCloser) error
}
var _ IStore = (*BookStore)(nil)
type BookStore struct {
processing *sync.WaitGroup
dir string
}
func NewBookStore(dir string) *BookStore {
if err := os.MkdirAll(dir, 0755); err != nil { //nolint
log.Fatal().Err(err).Msg("unable to create store dir")
}
return &BookStore{
processing: &sync.WaitGroup{},
dir: dir,
}
}
func (bs *BookStore) Done() <-chan struct{} {
chDone := make(chan struct{})
go func() {
bs.processing.Wait()
chDone <- struct{}{}
log.Info().Msg("book store processing done")
}()
return chDone
}
func (bs *BookStore) Save(name string, content io.ReadCloser) error {
bs.processing.Add(1)
defer bs.processing.Done()
defer content.Close()
dst, err := os.Create(filepath.Join(GetEnv().GetDir(), name))
if err != nil {
log.Err(err).Msg(ErrFileCreation.Error())
return ErrFileCreation
}
defer dst.Close()
if _, err := io.Copy(dst, content); err != nil {
log.Err(err).Msg(ErrFileCopy.Error())
return ErrFileCopy
}
return nil
}

View File

@ -71,11 +71,6 @@ func newEnv() environment {
if storeDir == "" { if storeDir == "" {
storeDir = defaultMainDir storeDir = defaultMainDir
} }
if err := os.MkdirAll(storeDir, 0755); err != nil { //nolint
log.Fatal().Err(err).Msg("unable to create store dir")
}
env.storeDir = storeDir env.storeDir = storeDir
return env return env