118 lines
3.5 KiB
Go
118 lines
3.5 KiB
Go
package store
|
|
|
|
import (
|
|
"database/sql"
|
|
"time"
|
|
)
|
|
|
|
type FileRecord struct {
|
|
ID string
|
|
Filename string
|
|
R2Key string
|
|
SizeBytes int64
|
|
ContentType string
|
|
UploadedAt time.Time
|
|
ExpiresAt *time.Time
|
|
PasswordHash *string
|
|
DeleteToken string
|
|
DownloadCount int64
|
|
BatchID *string
|
|
}
|
|
|
|
type Store struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func New(db *sql.DB) *Store {
|
|
return &Store{db: db}
|
|
}
|
|
|
|
func (s *Store) Create(f *FileRecord) error {
|
|
_, err := s.db.Exec(
|
|
`INSERT INTO files (id, filename, r2_key, size_bytes, content_type, expires_at, password_hash, delete_token, batch_id)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
f.ID, f.Filename, f.R2Key, f.SizeBytes, f.ContentType, f.ExpiresAt, f.PasswordHash, f.DeleteToken, f.BatchID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) Get(id string) (*FileRecord, error) {
|
|
f := &FileRecord{}
|
|
err := s.db.QueryRow(
|
|
`SELECT id, filename, r2_key, size_bytes, content_type, uploaded_at, expires_at, password_hash, delete_token, download_count, batch_id
|
|
FROM files WHERE id = ?`, id,
|
|
).Scan(&f.ID, &f.Filename, &f.R2Key, &f.SizeBytes, &f.ContentType, &f.UploadedAt, &f.ExpiresAt, &f.PasswordHash, &f.DeleteToken, &f.DownloadCount, &f.BatchID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
func (s *Store) IncrementDownloads(id string) error {
|
|
_, err := s.db.Exec(`UPDATE files SET download_count = download_count + 1 WHERE id = ?`, id)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) Delete(id string) error {
|
|
_, err := s.db.Exec(`DELETE FROM files WHERE id = ?`, id)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) DeleteByToken(token string) (*FileRecord, error) {
|
|
f := &FileRecord{}
|
|
err := s.db.QueryRow(
|
|
`SELECT id, filename, r2_key, size_bytes, content_type, uploaded_at, expires_at, password_hash, delete_token, download_count, batch_id
|
|
FROM files WHERE delete_token = ?`, token,
|
|
).Scan(&f.ID, &f.Filename, &f.R2Key, &f.SizeBytes, &f.ContentType, &f.UploadedAt, &f.ExpiresAt, &f.PasswordHash, &f.DeleteToken, &f.DownloadCount, &f.BatchID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_, err = s.db.Exec(`DELETE FROM files WHERE delete_token = ?`, token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
func (s *Store) ListExpired() ([]*FileRecord, error) {
|
|
rows, err := s.db.Query(
|
|
`SELECT id, filename, r2_key, size_bytes, content_type, uploaded_at, expires_at, password_hash, delete_token, download_count, batch_id
|
|
FROM files WHERE expires_at IS NOT NULL AND expires_at <= datetime('now')`,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var files []*FileRecord
|
|
for rows.Next() {
|
|
f := &FileRecord{}
|
|
if err := rows.Scan(&f.ID, &f.Filename, &f.R2Key, &f.SizeBytes, &f.ContentType, &f.UploadedAt, &f.ExpiresAt, &f.PasswordHash, &f.DeleteToken, &f.DownloadCount, &f.BatchID); err != nil {
|
|
return nil, err
|
|
}
|
|
files = append(files, f)
|
|
}
|
|
return files, rows.Err()
|
|
}
|
|
|
|
func (s *Store) GetBatch(batchID string) ([]*FileRecord, error) {
|
|
rows, err := s.db.Query(
|
|
`SELECT id, filename, r2_key, size_bytes, content_type, uploaded_at, expires_at, password_hash, delete_token, download_count, batch_id
|
|
FROM files WHERE batch_id = ? ORDER BY filename`, batchID,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var files []*FileRecord
|
|
for rows.Next() {
|
|
f := &FileRecord{}
|
|
if err := rows.Scan(&f.ID, &f.Filename, &f.R2Key, &f.SizeBytes, &f.ContentType, &f.UploadedAt, &f.ExpiresAt, &f.PasswordHash, &f.DeleteToken, &f.DownloadCount, &f.BatchID); err != nil {
|
|
return nil, err
|
|
}
|
|
files = append(files, f)
|
|
}
|
|
return files, rows.Err()
|
|
}
|