repos / git-pr

a self-hosted git collaboration server
git clone https://github.com/picosh/git-pr.git

Eric Bower  ·  2025-08-22

models.go

  1package git
  2
  3import (
  4	"database/sql"
  5	"database/sql/driver"
  6	"encoding/json"
  7	"fmt"
  8	"time"
  9
 10	"github.com/bluekeyes/go-gitdiff/gitdiff"
 11)
 12
 13type Status string
 14
 15const (
 16	StatusOpen     Status = "open"
 17	StatusClosed   Status = "closed"
 18	StatusAccepted Status = "accepted"
 19	StatusReviewed Status = "reviewed"
 20)
 21
 22// User is a db model for users.
 23type User struct {
 24	ID        int64     `db:"id"`
 25	Pubkey    string    `db:"pubkey"`
 26	Name      string    `db:"name"`
 27	CreatedAt time.Time `db:"created_at"`
 28	UpdatedAt time.Time `db:"updated_at"`
 29}
 30
 31// Acl is a db model for access control.
 32type Acl struct {
 33	ID         int64          `db:"id"`
 34	Pubkey     sql.NullString `db:"pubkey"`
 35	IpAddress  sql.NullString `db:"ip_address"`
 36	Permission string         `db:"permission"`
 37	CreatedAt  time.Time      `db:"created_at"`
 38}
 39
 40// Repo is a container for patch requests.
 41type Repo struct {
 42	ID        int64     `db:"id"`
 43	Name      string    `db:"name"`
 44	UserID    int64     `db:"user_id"`
 45	CreatedAt time.Time `db:"created_at"`
 46	UpdatedAt time.Time `db:"updated_at"`
 47}
 48
 49// PatchRequest is a database model for patches submitted to a Repo.
 50type PatchRequest struct {
 51	ID        int64     `db:"id"`
 52	UserID    int64     `db:"user_id"`
 53	RepoID    int64     `db:"repo_id"`
 54	Name      string    `db:"name"`
 55	Text      string    `db:"text"`
 56	Status    Status    `db:"status"`
 57	CreatedAt time.Time `db:"created_at"`
 58	UpdatedAt time.Time `db:"updated_at"`
 59	// only used for aggregate queries
 60	LastUpdated string `db:"last_updated"`
 61}
 62
 63type Patchset struct {
 64	ID             int64     `db:"id"`
 65	UserID         int64     `db:"user_id"`
 66	PatchRequestID int64     `db:"patch_request_id"`
 67	Review         bool      `db:"review"`
 68	CreatedAt      time.Time `db:"created_at"`
 69}
 70
 71// Patch is a database model for a single entry in a patchset.
 72// This usually corresponds to a git commit.
 73type Patch struct {
 74	ID            int64          `db:"id"`
 75	UserID        int64          `db:"user_id"`
 76	PatchsetID    int64          `db:"patchset_id"`
 77	AuthorName    string         `db:"author_name"`
 78	AuthorEmail   string         `db:"author_email"`
 79	AuthorDate    time.Time      `db:"author_date"`
 80	Title         string         `db:"title"`
 81	Body          string         `db:"body"`
 82	BodyAppendix  string         `db:"body_appendix"`
 83	CommitSha     string         `db:"commit_sha"`
 84	ContentSha    string         `db:"content_sha"`
 85	BaseCommitSha sql.NullString `db:"base_commit_sha"`
 86	RawText       string         `db:"raw_text"`
 87	CreatedAt     time.Time      `db:"created_at"`
 88	Files         []*gitdiff.File
 89}
 90
 91func (p *Patch) CalcDiff() string {
 92	return p.RawText
 93}
 94
 95// EventLog is a event log for RSS or other notification systems.
 96type EventLog struct {
 97	ID             int64         `db:"id"`
 98	UserID         int64         `db:"user_id"`
 99	RepoID         sql.NullInt64 `db:"repo_id"`
100	PatchRequestID sql.NullInt64 `db:"patch_request_id"`
101	PatchsetID     sql.NullInt64 `db:"patchset_id"`
102	Event          string        `db:"event"`
103	CreatedAt      time.Time     `db:"created_at"`
104	Data           EventData     `db:"data"`
105}
106
107type EventData struct {
108	Name    string `json:"name,omitempty"`
109	Status  Status `json:"status,omitempty"`
110	Comment string `json:"comment,omitempty"`
111}
112
113func (e EventData) String() string {
114	b, _ := json.Marshal(e)
115	bs := string(b)
116	if bs == "{}" {
117		return ""
118	}
119	return bs
120}
121
122func (e *EventData) Scan(value any) error {
123	if value == nil || value == "" {
124		return nil
125	}
126
127	var byt []byte
128	switch v := value.(type) {
129	case []byte:
130		byt = v
131	case string:
132		byt = []byte(v)
133	default:
134		return fmt.Errorf("cannot scan %T into EventData", value)
135	}
136
137	if len(byt) == 0 {
138		return nil
139	}
140
141	return json.Unmarshal(byt, e)
142}
143
144func (e EventData) Value() (driver.Value, error) {
145	return json.Marshal(e)
146}