fixed PR issue

This commit is contained in:
2026-05-11 23:56:45 +02:00
parent edf3c9824e
commit 35afa8d8f1
15 changed files with 88 additions and 217 deletions
+3 -11
View File
@@ -156,16 +156,8 @@ func (h *ArtifactHandler) Download(w http.ResponseWriter, r *http.Request) {
}
func (h *ArtifactHandler) resolveRunIDs(w http.ResponseWriter, r *http.Request) (repoID, runID int64, ok bool) {
owner := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var u models.User
if found, _ := h.db.Where("username = ?", owner).Get(&u); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, 0, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", u.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
rID, ok := resolveRepoID(h.db, w, r)
if !ok {
return 0, 0, false
}
runID, err := strconv.ParseInt(chi.URLParam(r, "runID"), 10, 64)
@@ -173,7 +165,7 @@ func (h *ArtifactHandler) resolveRunIDs(w http.ResponseWriter, r *http.Request)
jsonError(w, "invalid run ID", http.StatusBadRequest)
return 0, 0, false
}
return repo.ID, runID, true
return rID, runID, true
}
func isUnder(root, path string) bool {
+1 -13
View File
@@ -323,19 +323,7 @@ func (h *EnvironmentHandler) UpdateDeploymentStatus(w http.ResponseWriter, r *ht
// ── Helpers ───────────────────────────────────────────────────────────────────
func (h *EnvironmentHandler) resolveRepo(w http.ResponseWriter, r *http.Request) (int64, bool) {
owner := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var u models.User
if found, _ := h.db.Where("username = ?", owner).Get(&u); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", u.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
return repo.ID, true
return resolveRepoID(h.db, w, r)
}
func (h *EnvironmentHandler) resolveEnv(w http.ResponseWriter, r *http.Request) (*models.Environment, bool) {
+1 -14
View File
@@ -132,20 +132,7 @@ func (h *IssueHandler) Reopen(w http.ResponseWriter, r *http.Request) {
}
func (h *IssueHandler) repoID(w http.ResponseWriter, r *http.Request) (int64, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var owner models.User
if found, _ := h.db.Where("username = ?", ownerName).Get(&owner); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
return repo.ID, true
return resolveRepoID(h.db, w, r)
}
func (h *IssueHandler) lookupIssue(w http.ResponseWriter, r *http.Request) (*models.Issue, bool) {
+6 -12
View File
@@ -48,19 +48,13 @@ type deployKeyResponse struct {
}
func (h *DeployKeyHandler) lookupRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, *models.User, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
repo, ok := resolveRepo(h.db, w, r)
if !ok {
return nil, nil, false
}
var owner models.User
if found, _ := h.db.Where("username = ?", ownerName).Get(&owner); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, nil, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, nil, false
}
return &repo, &owner, true
h.db.ID(repo.OwnerID).Get(&owner)
return repo, &owner, true
}
func (h *DeployKeyHandler) canManage(repo *models.Repository, callerID int64) bool {
+1 -26
View File
@@ -4,7 +4,6 @@ import (
"encoding/json"
"net/http"
"github.com/go-chi/chi/v5"
"xorm.io/xorm"
"github.com/forgeo/forgebucket/internal/api/middleware"
@@ -16,31 +15,7 @@ type LFSHandler struct{ db *xorm.Engine }
func NewLFSHandler(db *xorm.Engine) *LFSHandler { return &LFSHandler{db: db} }
func (h *LFSHandler) resolveRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var owner models.User
found, err := h.db.Where("username = ?", ownerName).Get(&owner)
if err != nil {
jsonError(w, "database error: "+err.Error(), http.StatusInternalServerError)
return nil, false
}
if !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
var repo models.Repository
found, err = h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo)
if err != nil {
jsonError(w, "database error: "+err.Error(), http.StatusInternalServerError)
return nil, false
}
if !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
return &repo, true
return resolveRepo(h.db, w, r)
}
func (h *LFSHandler) canManage(repo *models.Repository, callerID int64) bool {
+7 -14
View File
@@ -28,22 +28,15 @@ type memberResponse struct {
AddedAt string `json:"addedAt"`
}
// lookupRepoForMembers resolves the repo from URL params and returns the owner User.
// lookupRepoAndOwner resolves {owner}/{repo} and returns the repo + its creator user.
func (h *MemberHandler) lookupRepoAndOwner(w http.ResponseWriter, r *http.Request) (*models.Repository, *models.User, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
repo, ok := resolveRepo(h.db, w, r)
if !ok {
return nil, nil, false
}
var owner models.User
if found, _ := h.db.Where("username = ?", ownerName).Get(&owner); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, nil, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, nil, false
}
return &repo, &owner, true
h.db.ID(repo.OwnerID).Get(&owner)
return repo, &owner, true
}
// callerCanManage returns true if callerID is the repo owner or has admin permission.
+1 -13
View File
@@ -247,19 +247,7 @@ func (h *PipelineHandler) RetryJob(w http.ResponseWriter, r *http.Request) {
// ── Helpers ───────────────────────────────────────────────────────────────────
func (h *PipelineHandler) repoID(w http.ResponseWriter, r *http.Request) (int64, bool) {
owner := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var u models.User
if found, _ := h.db.Where("username = ?", owner).Get(&u); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", u.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
return repo.ID, true
return resolveRepoID(h.db, w, r)
}
func (h *PipelineHandler) lookupRun(w http.ResponseWriter, r *http.Request) (*models.PipelineRun, bool) {
+1 -23
View File
@@ -18,29 +18,7 @@ func NewPRSettingsHandler(db *xorm.Engine) *PRSettingsHandler {
}
func (h *PRSettingsHandler) resolveRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var owner models.User
found, err := h.db.Where("username = ?", ownerName).Get(&owner)
if err != nil {
jsonError(w, "database error: "+err.Error(), http.StatusInternalServerError)
return nil, false
}
if !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
var repo models.Repository
found, err = h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo)
if err != nil {
jsonError(w, "database error: "+err.Error(), http.StatusInternalServerError)
return nil, false
}
if !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
return &repo, true
return resolveRepo(h.db, w, r)
}
func (h *PRSettingsHandler) canManage(repo *models.Repository, callerID int64) bool {
+1 -17
View File
@@ -241,23 +241,7 @@ func (h *PRHandler) Update(w http.ResponseWriter, r *http.Request) {
}
func (h *PRHandler) repoIDFromURL(w http.ResponseWriter, r *http.Request) (int64, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var owner models.User
found, err := h.db.Where("username = ?", ownerName).Get(&owner)
if err != nil || !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
var repo models.Repository
found, err = h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo)
if err != nil || !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
return repo.ID, true
return resolveRepoID(h.db, w, r)
}
func (h *PRHandler) lookupPR(w http.ResponseWriter, r *http.Request) (*models.PullRequest, bool) {
+55
View File
@@ -0,0 +1,55 @@
package handlers
// repo_lookup.go — shared helper used by all handlers that resolve
// {owner}/{repo} URL params to a repository row.
//
// The owner segment can be either a user username (user-owned repo) or a
// workspace handle (workspace-owned repo). This tries user-namespace first,
// then workspace-namespace, so the lookup is always unambiguous.
import (
"net/http"
"github.com/go-chi/chi/v5"
"xorm.io/xorm"
"github.com/forgeo/forgebucket/internal/models"
)
// resolveRepoID resolves /{owner}/{repo} to a repository ID.
// It tries user namespace first, then workspace namespace.
// Returns (repoID, true) on success or writes a 404 and returns (0, false).
func resolveRepoID(db *xorm.Engine, w http.ResponseWriter, r *http.Request) (int64, bool) {
repo, ok := resolveRepo(db, w, r)
if !ok {
return 0, false
}
return repo.ID, true
}
// resolveRepo is the full repo lookup returning the Repository struct.
func resolveRepo(db *xorm.Engine, w http.ResponseWriter, r *http.Request) (*models.Repository, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
// 1. Try user namespace.
var u models.User
if found, _ := db.Where("username = ?", ownerName).Get(&u); found {
var repo models.Repository
if found2, _ := db.Where("owner_id = ? AND name = ?", u.ID, repoName).Get(&repo); found2 {
return &repo, true
}
}
// 2. Try workspace namespace.
var ws models.Workspace
if found, _ := db.Where("handle = ?", ownerName).Get(&ws); found {
var repo models.Repository
if found2, _ := db.Where("workspace_id = ? AND name = ?", ws.ID, repoName).Get(&repo); found2 {
return &repo, true
}
}
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
+1 -23
View File
@@ -242,29 +242,7 @@ func ResolveSecretsForRun(db *xorm.Engine, repoID, workspaceID, envID int64, ses
// ── Helpers ───────────────────────────────────────────────────────────────────
func (h *SecretHandler) resolveRepoID(w http.ResponseWriter, r *http.Request) (int64, bool) {
owner := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var u models.User
if found, _ := h.db.Where("username = ?", owner).Get(&u); !found {
// Try workspace
var ws models.Workspace
if found2, _ := h.db.Where("handle = ?", owner).Get(&ws); !found2 {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
var repo models.Repository
if found3, _ := h.db.Where("workspace_id = ? AND name = ?", ws.ID, repoName).Get(&repo); !found3 {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
return repo.ID, true
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", u.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return 0, false
}
return repo.ID, true
return resolveRepoID(h.db, w, r)
}
func (h *SecretHandler) resolveEnvID(w http.ResponseWriter, r *http.Request) (int64, bool) {
+2 -13
View File
@@ -6,7 +6,6 @@ import (
"strconv"
"time"
"github.com/go-chi/chi/v5"
"xorm.io/xorm"
gitdomain "github.com/forgeo/forgebucket/internal/domain/git"
@@ -69,23 +68,13 @@ type TimelineEvent struct {
//
// GET /api/v1/repos/:owner/:repo/timeline?limit=60
func (h *TimelineHandler) GetTimeline(w http.ResponseWriter, r *http.Request) {
owner := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
limit := 60
if l, err := strconv.Atoi(r.URL.Query().Get("limit")); err == nil && l > 0 && l <= 200 {
limit = l
}
// ── Resolve repo ──────────────────────────────────────────────────────────
var u models.User
if found, _ := h.db.Where("username = ?", owner).Get(&u); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", u.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
repo, ok := resolveRepo(h.db, w, r)
if !ok {
return
}
+1 -13
View File
@@ -30,19 +30,7 @@ type accessTokenResponse struct {
}
func (h *AccessTokenHandler) lookupRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var owner models.User
if found, _ := h.db.Where("username = ?", ownerName).Get(&owner); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
return &repo, true
return resolveRepo(h.db, w, r)
}
func (h *AccessTokenHandler) canManage(repo *models.Repository, callerID int64) bool {
+1 -13
View File
@@ -55,19 +55,7 @@ func toWebhookResp(wh models.Webhook) webhookResponse {
}
func (h *WebhookHandler) resolveRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
var owner models.User
if found, _ := h.db.Where("username = ?", ownerName).Get(&owner); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, false
}
return &repo, true
return resolveRepo(h.db, w, r)
}
func (h *WebhookHandler) canManage(repo *models.Repository, callerID int64) bool {
+6 -12
View File
@@ -22,19 +22,13 @@ type WorkflowHandler struct{ db *xorm.Engine }
func NewWorkflowHandler(db *xorm.Engine) *WorkflowHandler { return &WorkflowHandler{db: db} }
func (h *WorkflowHandler) resolveRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, *models.User, bool) {
ownerName := chi.URLParam(r, "owner")
repoName := chi.URLParam(r, "repo")
repo, ok := resolveRepo(h.db, w, r)
if !ok {
return nil, nil, false
}
var owner models.User
if found, _ := h.db.Where("username = ?", ownerName).Get(&owner); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, nil, false
}
var repo models.Repository
if found, _ := h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo); !found {
jsonError(w, "repository not found", http.StatusNotFound)
return nil, nil, false
}
return &repo, &owner, true
h.db.ID(repo.OwnerID).Get(&owner)
return repo, &owner, true
}
func (h *WorkflowHandler) canManage(repo *models.Repository, callerID int64) bool {