diff options
author | Michael Muré <batolettre@gmail.com> | 2018-08-02 22:33:45 +0200 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2018-08-02 22:33:45 +0200 |
commit | ed8f7eca9a8e0d1c448a7cc6240e2b7e357cf354 (patch) | |
tree | 0f02849e3e91e7ee543235e043185bb86275478b | |
parent | 9488467c754230288934dde4a49b9046e658986c (diff) | |
download | git-bug-ed8f7eca9a8e0d1c448a7cc6240e2b7e357cf354.tar.gz |
webui: add the http handlers for read/write git blob for media in comments
-rw-r--r-- | commands/webui.go | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/commands/webui.go b/commands/webui.go index b31013ad..d5560180 100644 --- a/commands/webui.go +++ b/commands/webui.go @@ -1,16 +1,22 @@ package commands import ( + "bytes" + "encoding/json" "fmt" "github.com/MichaelMure/git-bug/graphql" + "github.com/MichaelMure/git-bug/repository" + "github.com/MichaelMure/git-bug/util" "github.com/MichaelMure/git-bug/webui" "github.com/gorilla/mux" "github.com/phayes/freeport" "github.com/skratchdot/open-golang/open" "github.com/spf13/cobra" "github.com/vektah/gqlgen/handler" + "io/ioutil" "log" "net/http" + "time" ) var port int @@ -36,6 +42,8 @@ func runWebUI(cmd *cobra.Command, args []string) error { // Routes router.Path("/playground").Handler(handler.Playground("git-bug", "/graphql")) router.Path("/graphql").Handler(graphql.NewHandler(repo)) + router.Path("/gitfile/{hash}").Handler(newGitFileHandler(repo)) + router.Path("/upload").Methods("POST").Handler(newGitUploadFileHandler(repo)) router.PathPrefix("/").Handler(http.FileServer(webui.WebUIAssets)) open.Run(webUiAddr) @@ -45,6 +53,109 @@ func runWebUI(cmd *cobra.Command, args []string) error { return nil } +type gitFileHandler struct { + repo repository.Repo +} + +func newGitFileHandler(repo repository.Repo) http.Handler { + return &gitFileHandler{ + repo: repo, + } +} + +func (gfh *gitFileHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + hash := mux.Vars(r)["hash"] + + if !isGitHash(hash) { + http.Error(rw, "invalid git hash", http.StatusBadRequest) + return + } + + // TODO: this mean that the whole file will he buffered in memory + // This can be a problem for big files. There might be a way around + // that by implementing a io.ReadSeeker that would read and discard + // data when a seek is called. + data, err := gfh.repo.ReadData(util.Hash(hash)) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + http.ServeContent(rw, r, "", time.Now(), bytes.NewReader(data)) +} + +type gitUploadFileHandler struct { + repo repository.Repo +} + +func newGitUploadFileHandler(repo repository.Repo) http.Handler { + return &gitUploadFileHandler{ + repo: repo, + } +} + +func (gufh *gitUploadFileHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + // 100MB (github limit) + var maxUploadSize int64 = 100 * 1000 * 1000 + r.Body = http.MaxBytesReader(rw, r.Body, maxUploadSize) + if err := r.ParseMultipartForm(maxUploadSize); err != nil { + http.Error(rw, "file too big (100MB max)", http.StatusBadRequest) + return + } + + file, _, err := r.FormFile("uploadfile") + if err != nil { + http.Error(rw, "invalid file", http.StatusBadRequest) + return + } + defer file.Close() + fileBytes, err := ioutil.ReadAll(file) + if err != nil { + http.Error(rw, "invalid file", http.StatusBadRequest) + return + } + + filetype := http.DetectContentType(fileBytes) + if filetype != "image/jpeg" && filetype != "image/jpg" && + filetype != "image/gif" && filetype != "image/png" { + http.Error(rw, "invalid file type", http.StatusBadRequest) + return + } + + hash, err := gufh.repo.StoreData(fileBytes) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + type response struct { + Hash string `json:"hash"` + } + + resp := response{Hash: string(hash)} + + js, err := json.Marshal(resp) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + rw.Header().Set("Content-Type", "application/json") + rw.Write(js) +} + +func isGitHash(s string) bool { + if len(s) != 40 { + return false + } + for _, r := range s { + if (r < 'a' || r > 'z') && (r < '0' || r > '9') { + return false + } + } + return true +} + var webUICmd = &cobra.Command{ Use: "webui", Short: "Launch the web UI", |