diff --git a/internal/api/api.go b/internal/api/api.go index 2e664d4..f44f55f 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -6,11 +6,9 @@ import ( "net/http" "time" - "git.freecumextremist.com/grumbulon/pomme/internal" "git.freecumextremist.com/grumbulon/pomme/internal/db" "github.com/go-chi/chi/v5" "github.com/go-chi/jwtauth/v5" - "github.com/go-chi/render" ) type key int @@ -44,7 +42,7 @@ func API() http.Handler { api.Use(jwtauth.Verifier(tokenAuth)) api.Use(jwtauth.Authenticator) - api.Post("/check", Ingest) + api.With(SetDBMiddleware).Post("/upload", RecieveFile) api.Get("/private", AuthTest) }) @@ -59,17 +57,6 @@ func API() http.Handler { return api } -// Ingest is a function to ingest Zonefiles. -func Ingest(w http.ResponseWriter, r *http.Request) { - _ = &internal.ZoneRequest{} - - // todo write to database, maybe? - - // todo -- add functions to apply to master zonefile if above check is OK. - - render.Status(r, http.StatusAccepted) -} - // AuthTest is for testing protected routes. func AuthTest(w http.ResponseWriter, r *http.Request) { _, claims, _ := jwtauth.FromContext(r.Context()) diff --git a/internal/api/auth.go b/internal/api/auth.go index 193f3ca..73b092d 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -72,6 +72,7 @@ func Login(w http.ResponseWriter, r *http.Request) { Name: "jwt", // Must be named "jwt" or else the token cannot be searched for by jwtauth.Verifier. Value: token, }) + w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode( internal.Response{ @@ -98,6 +99,7 @@ func Logout(w http.ResponseWriter, r *http.Request) { Name: "jwt", Value: "", }) + w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode( diff --git a/internal/api/zone.go b/internal/api/zone.go new file mode 100644 index 0000000..664b8eb --- /dev/null +++ b/internal/api/zone.go @@ -0,0 +1,118 @@ +package api + +import ( + "bytes" + "io" + "log" + "net/http" + "os" + "strings" + + "git.freecumextremist.com/grumbulon/pomme/internal" + "github.com/go-chi/jwtauth/v5" + "github.com/go-chi/render" + "gorm.io/gorm" +) + +func RecieveFile(w http.ResponseWriter, r *http.Request) { + _, claims, _ := jwtauth.FromContext(r.Context()) + + var buf bytes.Buffer + + r.Body = http.MaxBytesReader(w, r.Body, .5*1024*1024) // approx 500 kb max upload + + file, header, err := r.FormFile("file") + if err != nil { + http.Error(w, "request body too large", http.StatusRequestEntityTooLarge) + + return + } + + defer file.Close() //nolint: errcheck + + name := strings.Split(header.Filename, ".") + + _, err = io.Copy(&buf, file) + + if err != nil { + http.Error(w, "internal server error", http.StatusInternalServerError) + + return + } + + f, err := os.CreateTemp("", "tmpfile-") + if err != nil { + http.Error(w, "internal server error", http.StatusInternalServerError) + + return + } + + log.Println(f.Name()) + + // close and remove the temporary file at the end of the program + defer func() { + if err = f.Close(); err != nil { + http.Error(w, "internal server error", http.StatusInternalServerError) + + return + } + }() + + defer os.Remove(f.Name()) //nolint: errcheck + + // write data to the temporary file + if _, err = f.Write(buf.Bytes()); err != nil { + http.Error(w, "internal server error", http.StatusInternalServerError) + + return + } + + err = os.WriteFile(f.Name(), buf.Bytes(), 0o600) + + if err != nil { + http.Error(w, "internal server error", http.StatusInternalServerError) + + return + } + + buf.Reset() + + zoneReq := newZoneRequest(name[0], claims["username"].(string)) + + db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB) + if !ok { + http.Error(w, "internal server error", http.StatusInternalServerError) + } + + db.Create(zoneReq) + + parseFile(zoneReq) +} + +func newZoneRequest(filename string, user string) *internal.ZoneRequest { + return &internal.ZoneRequest{ + User: user, + Zone: &internal.Zone{ + FileName: filename, + RequestID: "1", + Body: "aaaaaaaaaaaaaaaaa", + }, + } +} + +func parseFile(z *internal.ZoneRequest) bool { + err := z.Parse() + + return err == nil +} + +// Ingest is a function to ingest Zonefiles. +func Ingest(w http.ResponseWriter, r *http.Request) { + _ = &internal.ZoneRequest{} + + // todo write to database, maybe? + + // todo -- add functions to apply to master zonefile if above check is OK. + + render.Status(r, http.StatusAccepted) +} diff --git a/internal/db/db.go b/internal/db/db.go index 028e13d..018cf24 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -14,7 +14,7 @@ func InitDb() *gorm.DB { } // Migrate the schema - err = db.AutoMigrate(&internal.User{}) + err = db.AutoMigrate(&internal.User{}, &internal.ZoneRequest{}) if err != nil { panic("failed to run DB migration") } diff --git a/internal/zone.go b/internal/zone.go index 5293846..aa38af5 100644 --- a/internal/zone.go +++ b/internal/zone.go @@ -13,23 +13,14 @@ import ( type ZoneRequest struct { *Zone - User *User `json:"user,omitempty"` - RequestID string `json:"id"` -} - -// ZoneResponse represents a Zone file request response. -type ZoneResponse struct { - *Zone - - User *User `json:"user,omitempty"` - Elapsed int64 `json:"elapsed"` + User string `json:"user,omitempty" gorm:"foreignKey:username;references:User"` } // Zone struct represents a zonefile. type Zone struct { - ID string `json:"id"` - UserID string `json:"user_id"` //nolint: tagliatelle - Body string `json:"body"` + FileName string `json:"name"` + RequestID string `json:"id"` + Body string `json:"body"` } // User struct represents a user.