187 lines
6.7 KiB
Go
187 lines
6.7 KiB
Go
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
func (s *Store) UpsertReleasePackage(item ReleasePackage) (ReleasePackage, error) {
|
|
item.FileName = strings.TrimSpace(item.FileName)
|
|
if item.FileName == "" {
|
|
return ReleasePackage{}, errors.New("file name is required")
|
|
}
|
|
if item.CreatedAt == "" {
|
|
if existing, ok, err := s.GetReleasePackage(item.FileName); err == nil && ok {
|
|
item.CreatedAt = existing.CreatedAt
|
|
} else if err != nil {
|
|
return ReleasePackage{}, err
|
|
} else {
|
|
item.CreatedAt = Now()
|
|
}
|
|
}
|
|
if item.UpdatedAt == "" {
|
|
item.UpdatedAt = Now()
|
|
}
|
|
columns := []string{"product", "version", "platform", "arch", "file_name", "url", "sha256", "size_bytes", "enabled", "created_at", "updated_at"}
|
|
conn, d := s.active()
|
|
_, err := conn.Exec(d.rebind(d.upsert("release_packages", columns, []string{"file_name"})),
|
|
sanitize(item.Product), sanitize(item.Version), sanitize(item.Platform), sanitize(item.Arch), sanitize(item.FileName),
|
|
sanitizeLong(item.URL, 1200), sanitize(item.SHA256), item.SizeBytes, d.boolExpr(item.Enabled), item.CreatedAt, item.UpdatedAt)
|
|
if err != nil {
|
|
s.markFailover(err)
|
|
return ReleasePackage{}, err
|
|
}
|
|
stored, ok, err := s.GetReleasePackage(item.FileName)
|
|
if err != nil {
|
|
return ReleasePackage{}, err
|
|
}
|
|
if !ok {
|
|
return ReleasePackage{}, errors.New("release package was not persisted")
|
|
}
|
|
return stored, nil
|
|
}
|
|
|
|
func (s *Store) GetReleasePackage(fileName string) (ReleasePackage, bool, error) {
|
|
var item ReleasePackage
|
|
var enabled int
|
|
err := s.queryRow(releasePackageSelectSQL()+` WHERE file_name = ?`, strings.TrimSpace(fileName)).Scan(
|
|
&item.ID, &item.Product, &item.Version, &item.Platform, &item.Arch, &item.FileName, &item.URL,
|
|
&item.SHA256, &item.SizeBytes, &enabled, &item.CreatedAt, &item.UpdatedAt)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return ReleasePackage{}, false, nil
|
|
}
|
|
if err != nil {
|
|
return ReleasePackage{}, false, err
|
|
}
|
|
item.Enabled = enabled != 0
|
|
return item, true, nil
|
|
}
|
|
|
|
func (s *Store) ListReleasePackages() ([]ReleasePackage, error) {
|
|
rows, err := s.query(releasePackageSelectSQL() + ` ORDER BY file_name ASC`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []ReleasePackage{}
|
|
for rows.Next() {
|
|
var item ReleasePackage
|
|
var enabled int
|
|
if err := rows.Scan(&item.ID, &item.Product, &item.Version, &item.Platform, &item.Arch, &item.FileName, &item.URL,
|
|
&item.SHA256, &item.SizeBytes, &enabled, &item.CreatedAt, &item.UpdatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
item.Enabled = enabled != 0
|
|
items = append(items, item)
|
|
}
|
|
return items, rows.Err()
|
|
}
|
|
|
|
func (s *Store) DeleteReleasePackage(fileName string) error {
|
|
_, err := s.exec(`DELETE FROM release_packages WHERE file_name = ?`, strings.TrimSpace(fileName))
|
|
return err
|
|
}
|
|
|
|
func releasePackageSelectSQL() string {
|
|
return `SELECT id, product, version, platform, arch, file_name, url, sha256, size_bytes, enabled, created_at, updated_at FROM release_packages`
|
|
}
|
|
|
|
func (s *Store) UpsertReleaseNotice(item ReleaseNotice) (ReleaseNotice, error) {
|
|
now := Now()
|
|
item.Version = strings.TrimSpace(item.Version)
|
|
if item.Version == "" {
|
|
return ReleaseNotice{}, errors.New("version is required")
|
|
}
|
|
if item.CreatedAt == "" {
|
|
item.CreatedAt = now
|
|
}
|
|
item.UpdatedAt = now
|
|
if item.Channel == "" {
|
|
item.Channel = "stable"
|
|
}
|
|
if item.NoticeFile == "" {
|
|
item.NoticeFile = item.Version + ".json"
|
|
}
|
|
columns := []string{"version", "build", "channel", "title", "message", "release_notes", "message_md", "release_notes_md", "download_url", "notice_file", "raw_json", "published_at", "created_at", "updated_at"}
|
|
conn, d := s.active()
|
|
_, err := conn.Exec(d.rebind(d.upsert("release_notices", columns, []string{"version"})),
|
|
sanitize(item.Version), sanitize(item.Build), sanitize(item.Channel), sanitizeLong(item.Title, 500), sanitizeLong(item.Message, 4000),
|
|
sanitizeLong(item.ReleaseNotes, 12000), sanitizeLong(item.MessageMD, 12000), sanitizeLong(item.ReleaseNotesMD, 20000),
|
|
sanitizeLong(item.DownloadURL, 1200), sanitize(item.NoticeFile), item.RawJSON, sanitize(item.PublishedAt), item.CreatedAt, item.UpdatedAt)
|
|
if err != nil {
|
|
s.markFailover(err)
|
|
return ReleaseNotice{}, err
|
|
}
|
|
return s.GetReleaseNotice(item.Version)
|
|
}
|
|
|
|
func (s *Store) GetReleaseNotice(version string) (ReleaseNotice, error) {
|
|
item, err := scanReleaseNotice(s.queryRow(releaseNoticeSelectSQL()+` WHERE version = ?`, strings.TrimSpace(version)))
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return ReleaseNotice{}, errors.New("release notice not found")
|
|
}
|
|
return item, err
|
|
}
|
|
|
|
func (s *Store) ListReleaseNotices(limit int) ([]ReleaseNotice, error) {
|
|
if limit <= 0 || limit > 200 {
|
|
limit = 100
|
|
}
|
|
rows, err := s.query(releaseNoticeSelectSQL()+` ORDER BY published_at DESC, version DESC LIMIT ?`, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []ReleaseNotice{}
|
|
for rows.Next() {
|
|
item, err := scanReleaseNotice(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
return items, rows.Err()
|
|
}
|
|
|
|
func (s *Store) SaveReleaseNoticeRevision(version, raw, note, actor string) (ReleaseNoticeRevision, error) {
|
|
item := ReleaseNoticeRevision{Version: sanitize(version), RawJSON: raw, Note: sanitize(note), CreatedBy: firstNonEmpty(actor, "admin"), CreatedAt: Now()}
|
|
id, err := s.insertID(`INSERT INTO release_notice_revisions (version, raw_json, note, created_by, created_at) VALUES (?, ?, ?, ?, ?)`,
|
|
item.Version, item.RawJSON, item.Note, item.CreatedBy, item.CreatedAt)
|
|
if err != nil {
|
|
return ReleaseNoticeRevision{}, err
|
|
}
|
|
item.ID = id
|
|
return item, nil
|
|
}
|
|
|
|
func (s *Store) ListReleaseNoticeRevisions(version string, limit int) ([]ReleaseNoticeRevision, error) {
|
|
if limit <= 0 || limit > 100 {
|
|
limit = 20
|
|
}
|
|
rows, err := s.query(`SELECT id, version, raw_json, note, created_by, created_at FROM release_notice_revisions WHERE version = ? ORDER BY id DESC LIMIT ?`, strings.TrimSpace(version), limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []ReleaseNoticeRevision{}
|
|
for rows.Next() {
|
|
var item ReleaseNoticeRevision
|
|
if err := rows.Scan(&item.ID, &item.Version, &item.RawJSON, &item.Note, &item.CreatedBy, &item.CreatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
return items, rows.Err()
|
|
}
|
|
|
|
func (s *Store) GetReleaseNoticeRevision(version string, id int64) (ReleaseNoticeRevision, error) {
|
|
var item ReleaseNoticeRevision
|
|
err := s.queryRow(`SELECT id, version, raw_json, note, created_by, created_at FROM release_notice_revisions WHERE version = ? AND id = ?`, strings.TrimSpace(version), id).
|
|
Scan(&item.ID, &item.Version, &item.RawJSON, &item.Note, &item.CreatedBy, &item.CreatedAt)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return ReleaseNoticeRevision{}, errors.New("release notice revision not found")
|
|
}
|
|
return item, err
|
|
}
|