235 lines
4.8 KiB
Go
235 lines
4.8 KiB
Go
package board
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/gob"
|
|
"fmt"
|
|
"sort"
|
|
|
|
"codeflow.dananglin.me.uk/apollo/canal/internal/database"
|
|
bolt "go.etcd.io/bbolt"
|
|
)
|
|
|
|
type Board struct {
|
|
db *bolt.DB
|
|
}
|
|
|
|
// Open reads the board from the database.
|
|
// If no board exists then a new one will be created.
|
|
func Open(path string) (Board, error) {
|
|
db, err := database.OpenDatabase(path)
|
|
if err != nil {
|
|
return Board{}, fmt.Errorf("unable to open the database, %w", err)
|
|
}
|
|
|
|
board := Board{
|
|
db: db,
|
|
}
|
|
|
|
statusList, err := board.StatusList()
|
|
if err != nil {
|
|
return Board{}, err
|
|
}
|
|
|
|
if len(statusList) == 0 {
|
|
newStatusList := defaultStatusList()
|
|
|
|
boltItems := make([]database.BoltItem, len(newStatusList))
|
|
|
|
for i := range newStatusList {
|
|
boltItems[i] = &newStatusList[i]
|
|
}
|
|
|
|
if _, err := database.WriteMany(db, database.StatusBucket, boltItems); err != nil {
|
|
return Board{}, fmt.Errorf("unable to save the default status list to the database, %w", err)
|
|
}
|
|
}
|
|
|
|
return board, nil
|
|
}
|
|
|
|
func (b *Board) Close() error {
|
|
if b.db == nil {
|
|
return nil
|
|
}
|
|
|
|
return b.db.Close()
|
|
}
|
|
|
|
// StatusList returns the ordered list of statuses from the database.
|
|
func (b *Board) StatusList() ([]Status, error) {
|
|
data, err := database.ReadAll(b.db, database.StatusBucket)
|
|
if err != nil {
|
|
return []Status{}, fmt.Errorf("unable to read the status list, %w", err)
|
|
}
|
|
|
|
statuses := make([]Status, len(data))
|
|
|
|
for i, d := range data {
|
|
buf := bytes.NewBuffer(d)
|
|
|
|
decoder := gob.NewDecoder(buf)
|
|
|
|
var s Status
|
|
|
|
if err := decoder.Decode(&s); err != nil {
|
|
return []Status{}, fmt.Errorf("unable to decode data, %w", err)
|
|
}
|
|
|
|
statuses[i] = s
|
|
}
|
|
|
|
sort.Sort(ByStatusOrder(statuses))
|
|
|
|
return statuses, nil
|
|
}
|
|
|
|
// TODO: Finish implementation.
|
|
func (b *Board) ReadStatus() (Status, error) {
|
|
return Status{}, nil
|
|
}
|
|
|
|
// TODO: Finish implementation.
|
|
func (b *Board) NewStatus() error {
|
|
return nil
|
|
}
|
|
|
|
// TODO: Finish implementation.
|
|
func (b *Board) UpdateStatus() error {
|
|
return nil
|
|
}
|
|
|
|
// TODO: Finish implementation.
|
|
func (b *Board) DeleteStatus() error {
|
|
return nil
|
|
}
|
|
|
|
type CardArgs struct {
|
|
NewTitle string
|
|
NewContent string
|
|
}
|
|
|
|
// CreateCard creates a card in the database.
|
|
func (b *Board) CreateCard(args CardArgs) error {
|
|
statusList, err := b.StatusList()
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read the status list, %w", err)
|
|
}
|
|
|
|
if len(statusList) == 0 {
|
|
return statusListEmptyError{}
|
|
}
|
|
|
|
card := Card{
|
|
ID: -1,
|
|
Title: args.NewTitle,
|
|
Content: args.NewContent,
|
|
}
|
|
|
|
cardID, err := database.Write(b.db, database.CardBucket, &card)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to write card to the database, %w", err)
|
|
}
|
|
|
|
initialStatus := statusList[0]
|
|
|
|
initialStatus.AddCardID(cardID)
|
|
|
|
if _, err := database.Write(b.db, database.StatusBucket, &initialStatus); err != nil {
|
|
return fmt.Errorf("unable to write the %s status to the database, %w", initialStatus.Name, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Card returns a Card value from the database.
|
|
func (b *Board) Card(id int) (Card, error) {
|
|
data, err := database.Read(b.db, database.CardBucket, id)
|
|
if err != nil {
|
|
return Card{}, fmt.Errorf("unable to read card [%d] from the database, %w", id, err)
|
|
}
|
|
|
|
var card Card
|
|
|
|
buf := bytes.NewBuffer(data)
|
|
|
|
decoder := gob.NewDecoder(buf)
|
|
|
|
if err := decoder.Decode(&card); err != nil {
|
|
return Card{}, fmt.Errorf("unable to decode data, %w", err)
|
|
}
|
|
|
|
return card, nil
|
|
}
|
|
|
|
// CardList returns a list of Card values from the database.
|
|
// TODO: function needs testing.
|
|
func (b *Board) CardList(ids []int) ([]Card, error) {
|
|
data, err := database.ReadMany(b.db, database.CardBucket, ids)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to read card list from the database, %w", err)
|
|
}
|
|
|
|
cards := make([]Card, len(data))
|
|
|
|
for i, d := range data {
|
|
buf := bytes.NewBuffer(d)
|
|
|
|
decoder := gob.NewDecoder(buf)
|
|
|
|
var c Card
|
|
|
|
if err := decoder.Decode(&c); err != nil {
|
|
return nil, fmt.Errorf("unable to decode data, %w", err)
|
|
}
|
|
|
|
cards[i] = c
|
|
}
|
|
|
|
return cards, nil
|
|
}
|
|
|
|
type UpdateCardArgs struct {
|
|
CardID int
|
|
CardArgs
|
|
}
|
|
|
|
// UpdateCard modifies an existing card in the database.
|
|
func (b *Board) UpdateCard(args UpdateCardArgs) error {
|
|
card, err := b.Card(args.CardID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(args.NewTitle) > 0 {
|
|
card.Title = args.NewTitle
|
|
}
|
|
|
|
if len(args.NewContent) > 0 {
|
|
card.Content = args.NewContent
|
|
}
|
|
|
|
if _, err := database.Write(b.db, database.CardBucket, &card); err != nil {
|
|
return fmt.Errorf("unable to write card to the database, %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type UpdateCardStatusArgs struct {
|
|
CardID int
|
|
OldStatusID int
|
|
NewStatusID int
|
|
}
|
|
|
|
// UpdateCardStatus moves a card between statuses.
|
|
// TODO: finish implementation.
|
|
func (b *Board) UpdateCardStatus(args UpdateCardStatusArgs) error {
|
|
return nil
|
|
}
|
|
|
|
// DeleteCard deletes a card from the database.
|
|
// TODO: finish implementation.
|
|
func (b *Board) DeleteCard(id int) error {
|
|
return nil
|
|
}
|