package handlers import ( "fmt" "net/url" "strings" "polar/internal/git" "polar/internal/web/middleware" "github.com/gofiber/fiber/v2" ) // RepoNewFilePage renders the web form for creating a file. // GET /:owner/:repo/new-file func (h *Handler) RepoNewFilePage(c *fiber.Ctx) error { return h.renderFileForm(c, "file") } // RepoNewFolderPage renders the form for creating a folder. Git cannot store // empty directories, so the folder is tracked through a .gitkeep placeholder. // GET /:owner/:repo/new-folder func (h *Handler) RepoNewFolderPage(c *fiber.Ctx) error { return h.renderFileForm(c, "folder") } func (h *Handler) renderFileForm(c *fiber.Ctx, mode string) error { r, diskPath, err := h.loadAuthorizedRepo(c, true) if err != nil { return nil } titleKey := "file.new_file" if mode == "folder" { titleKey = "file.new_folder" } ref := strings.TrimSpace(c.Query("ref")) if ref == "" { ref, _ = git.EnsureDefaultBranch(c.UserContext(), diskPath, r.DefaultBranch) } subPath := strings.Trim(strings.ReplaceAll(c.Query("path"), "\\", "/"), "/") data := h.baseData(c, h.tr(c, titleKey)) data["Repo"] = r data["Ref"] = ref data["SubPath"] = subPath data["Mode"] = mode data["ActiveTab"] = "code" data["CanWrite"] = true data["Branches"], _ = git.ListBranches(c.UserContext(), diskPath) return h.render(c, fiber.StatusOK, "file_new", data) } // RepoCreateFileSubmit commits a new file to the selected branch. // POST /:owner/:repo/new-file func (h *Handler) RepoCreateFileSubmit(c *fiber.Ctx) error { r, diskPath, err := h.loadAuthorizedRepo(c, true) if err != nil { return nil } u := middleware.CurrentUser(c) ref := strings.TrimSpace(c.FormValue("ref")) if ref == "" || !git.BranchExists(c.UserContext(), diskPath, ref) { ref, _ = git.EnsureDefaultBranch(c.UserContext(), diskPath, r.DefaultBranch) } filePath := strings.TrimSpace(c.FormValue("path")) message := strings.TrimSpace(c.FormValue("message")) content := c.FormValue("content") backTo := fmt.Sprintf("/%s/%s/new-file?ref=%s", r.OwnerUsername, r.Name, url.QueryEscape(ref)) clean, cerr := git.CleanSubPath(filePath) if cerr != nil || clean == "" { h.setFlashT(c, "flash.path_invalid") return c.Redirect(backTo, fiber.StatusSeeOther) } if blob, rerr := git.ReadBlob(c.UserContext(), diskPath, ref, clean); rerr == nil && blob != nil { h.setFlashT(c, "flash.file_exists") return c.Redirect(backTo+"&path="+url.QueryEscape(clean), fiber.StatusSeeOther) } if message == "" { message = "Add " + clean } if _, werr := git.WriteFileCommit(c.UserContext(), diskPath, ref, clean, []byte(content), message, u.Username, u.Email); werr != nil { h.setFlashT(c, "flash.file_create_failed") return c.Redirect(backTo+"&path="+url.QueryEscape(clean), fiber.StatusSeeOther) } h.setFlashT(c, "flash.file_created") return c.Redirect(fmt.Sprintf("/%s/%s/blob/%s/%s", r.OwnerUsername, r.Name, ref, clean), fiber.StatusSeeOther) } // RepoCreateFolderSubmit commits a .gitkeep placeholder so the new folder is // tracked by git. // POST /:owner/:repo/new-folder func (h *Handler) RepoCreateFolderSubmit(c *fiber.Ctx) error { r, diskPath, err := h.loadAuthorizedRepo(c, true) if err != nil { return nil } u := middleware.CurrentUser(c) ref := strings.TrimSpace(c.FormValue("ref")) if ref == "" || !git.BranchExists(c.UserContext(), diskPath, ref) { ref, _ = git.EnsureDefaultBranch(c.UserContext(), diskPath, r.DefaultBranch) } folder := strings.TrimSpace(c.FormValue("path")) message := strings.TrimSpace(c.FormValue("message")) backTo := fmt.Sprintf("/%s/%s/new-folder?ref=%s", r.OwnerUsername, r.Name, url.QueryEscape(ref)) clean, cerr := git.CleanSubPath(folder) if cerr != nil || clean == "" { h.setFlashT(c, "flash.path_invalid") return c.Redirect(backTo, fiber.StatusSeeOther) } if message == "" { message = "Create folder " + clean } if _, werr := git.WriteFileCommit(c.UserContext(), diskPath, ref, clean+"/.gitkeep", nil, message, u.Username, u.Email); werr != nil { h.setFlashT(c, "flash.folder_create_failed") return c.Redirect(backTo, fiber.StatusSeeOther) } h.setFlashT(c, "flash.folder_created") return c.Redirect(fmt.Sprintf("/%s/%s/tree/%s/%s", r.OwnerUsername, r.Name, ref, clean), fiber.StatusSeeOther) }