diff --git a/backend/api.go b/backend/api.go index 032512b..eeaa1f1 100644 --- a/backend/api.go +++ b/backend/api.go @@ -23,7 +23,7 @@ func (h *ApiHandler) ServeLoginPost(writer http.ResponseWriter, request *http.Re body, err := io.ReadAll(bodyReader) _ = bodyReader.Close() if err != nil { - http.Error(writer, err.Error(), http.StatusBadRequest) + WriteError(writer, http.StatusBadRequest, "failed to read body", err) return } @@ -34,19 +34,19 @@ func (h *ApiHandler) ServeLoginPost(writer http.ResponseWriter, request *http.Re loginBody := LoginBody{} err = json.Unmarshal(body, &loginBody) if err != nil { - http.Error(writer, err.Error(), http.StatusBadRequest) + WriteError(writer, http.StatusBadRequest, "failed to read body", err) return } success, err := h.db.ValidateRootPassword(loginBody.Password) if err != nil { - log.Println("Error logging in:", err) - http.Error(writer, "failed to read database", http.StatusInternalServerError) + WriteError(writer, http.StatusInternalServerError, "failed to read database", err) return } if !success { - http.Error(writer, "invalid password", http.StatusUnauthorized) + log.Printf("failed login from '%s'", request.RemoteAddr) + WriteError(writer, http.StatusUnauthorized, "invalid password", nil) return } @@ -62,14 +62,9 @@ func (h *ApiHandler) ServeLoginPost(writer http.ResponseWriter, request *http.Re cookie.HttpOnly = true http.SetCookie(writer, &cookie) - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - err = json.NewEncoder(writer).Encode(map[string]interface{}{}) - if err != nil { - http.Error(writer, "failed to serialize results", http.StatusInternalServerError) - return - } + WriteResponse(writer, http.StatusOK, map[string]interface{}{}) + log.Printf("successful login from '%s'", request.RemoteAddr) } func (h *ApiHandler) ServeLogoutPost(writer http.ResponseWriter, request *http.Request) { @@ -85,13 +80,9 @@ func (h *ApiHandler) ServeLogoutPost(writer http.ResponseWriter, request *http.R h.authToken = nil - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - err := json.NewEncoder(writer).Encode(map[string]interface{}{}) - if err != nil { - http.Error(writer, "failed to serialize results", http.StatusInternalServerError) - return - } + WriteResponse(writer, http.StatusOK, map[string]interface{}{}) + + log.Printf("successful logout from '%s'", request.RemoteAddr) } func (h *ApiHandler) ProcessAuth(next http.Handler, required bool) http.Handler { @@ -103,7 +94,7 @@ func (h *ApiHandler) ProcessAuth(next http.Handler, required bool) http.Handler } if !isAuthorized && required { - http.Error(writer, "authentication required", http.StatusUnauthorized) + WriteError(writer, http.StatusUnauthorized, "authentication required", nil) return } @@ -115,3 +106,19 @@ func IsAuthorized(request *http.Request) bool { value := request.Context().Value(isAuthorizedContextKey) return value != nil && value.(bool) } + +func WriteResponse(writer http.ResponseWriter, code int, body any) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(code) + _ = json.NewEncoder(writer).Encode(body) +} + +func WriteError(writer http.ResponseWriter, code int, message string, err error) { + if err != nil { + log.Println(err) + } + + WriteResponse(writer, code, map[string]interface{}{ + "message": message, + }) +} diff --git a/backend/blog.go b/backend/blog.go index 9f14d02..e70ee74 100644 --- a/backend/blog.go +++ b/backend/blog.go @@ -3,7 +3,6 @@ package main import ( "archive/tar" "backend/md" - "encoding/json" "errors" "fmt" "io" @@ -63,7 +62,7 @@ func ParseArticle(reader io.Reader, filePrefix string) (*Article, error) { readmeBytes, found := tarFiles["README.md"] if !found { - return nil, errors.New("README.md not found") + return nil, errors.New("file 'README.md' not found") } usedFiles := make(map[string]ArticleFile) @@ -163,7 +162,7 @@ func (h *ApiHandler) ServeBlogGet(writer http.ResponseWriter, request *http.Requ } else { offset, err = strconv.Atoi(offsetStr) if err != nil || offset < 0 { - http.Error(writer, "invalid offset", http.StatusBadRequest) + WriteError(writer, http.StatusBadRequest, "invalid offset", nil) return } } @@ -174,69 +173,56 @@ func (h *ApiHandler) ServeBlogGet(writer http.ResponseWriter, request *http.Requ } else { limit, err = strconv.Atoi(limitStr) if err != nil || limit <= 0 || limit > 100 { - http.Error(writer, "invalid limit", http.StatusBadRequest) + WriteError(writer, http.StatusBadRequest, "invalid limit", nil) return } } articles, err := h.db.GetBlogArticles(IsAuthorized(request), offset, limit) if err != nil { - log.Println("Error getting articles:", err) - http.Error(writer, "failed to query database", http.StatusInternalServerError) + WriteError(writer, http.StatusInternalServerError, "failed to query database", err) return } - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - err = json.NewEncoder(writer).Encode(articles) - if err != nil { - http.Error(writer, "failed to serialize results", http.StatusInternalServerError) - } + WriteResponse(writer, http.StatusOK, articles) } func (h *ApiHandler) ServeBlogPut(writer http.ResponseWriter, request *http.Request) { err := request.ParseMultipartForm(10 * 1024 * 1024) if err != nil { - http.Error(writer, "failed to parse multipart form", http.StatusBadRequest) + WriteError(writer, http.StatusBadRequest, "failed to parse multipart form", nil) return } file, _, err := request.FormFile("file") if err != nil { - http.Error(writer, "failed to parse file", http.StatusBadRequest) + WriteError(writer, http.StatusBadRequest, "failed to parse file", nil) return } defer func() { _ = file.Close() }() - log.Println("Creating new blog article") + log.Println("creating new blog article ...") id, commit, err := h.db.CreateBlogArticle() if err != nil { - log.Println("Error creating new blog article:", err) - http.Error(writer, "failed to add article to database", http.StatusInternalServerError) + WriteError(writer, http.StatusInternalServerError, "failed to write database", err) return } article, err := ParseArticle(file, "/api/blog/"+strconv.FormatInt(id, 10)+"/file/") if err != nil { _ = commit(nil) - log.Println("Error creating new blog article:", err) - http.Error(writer, "failed to add article to database", http.StatusInternalServerError) + WriteError(writer, http.StatusInternalServerError, "failed to parse article: "+err.Error(), nil) return } err = commit(article) - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - err = json.NewEncoder(writer).Encode(map[string]interface{}{ + WriteResponse(writer, http.StatusOK, map[string]interface{}{ "id": id, }) - if err != nil { - http.Error(writer, "failed to serialize results", http.StatusInternalServerError) - } } func (h *ApiHandler) ServeBlogGetSingle(writer http.ResponseWriter, request *http.Request) { diff --git a/backend/db.go b/backend/db.go index b1ea2df..4170776 100644 --- a/backend/db.go +++ b/backend/db.go @@ -18,7 +18,7 @@ type Database struct { } func NewDatabase(path string, rootPassword string) (*Database, error) { - log.Println("Opening database '" + path + "'") + log.Println("opening database '" + path + "'") db, err := sql.Open("sqlite3", path) if err != nil { @@ -37,7 +37,7 @@ func NewDatabase(path string, rootPassword string) (*Database, error) { func (db *Database) Close() { err := db.db.Close() if err != nil { - log.Println("Error closing database:", err.Error()) + log.Println("error closing database:", err.Error()) } } @@ -209,7 +209,7 @@ func migrate(db *sql.DB, rootPassword string) error { return err } - log.Println("Checking database schema version") + log.Println("checking database schema version") var curVersion int err = tx.QueryRow("SELECT version FROM schema_info").Scan(&curVersion) if err != nil { @@ -217,7 +217,7 @@ func migrate(db *sql.DB, rootPassword string) error { } if curVersion == -1 { - log.Println("Database is empty") + log.Println("database is empty") err = createV1Tables(tx, rootPassword) if err != nil { @@ -225,7 +225,7 @@ func migrate(db *sql.DB, rootPassword string) error { return err } } else { - log.Println("Database schema version is", curVersion) + log.Println("database schema version is", curVersion) if curVersion != 1 { return errors.New("unsupported database schema version") @@ -236,7 +236,7 @@ func migrate(db *sql.DB, rootPassword string) error { } func createV1Tables(tx *sql.Tx, rootPassword string) error { - log.Println("Creating tables for schema version 1") + log.Println("creating tables for schema version 1") salt := make([]byte, 32) _, _ = rand.Read(salt)