// // tank // // Import and Playlist Daemon for autoradio project // // // Copyright (C) 2017-2019 Christian Pointner <equinox@helsinki.at> // // This file is part of tank. // // tank is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // tank is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with tank. If not, see <http://www.gnu.org/licenses/>. // package store import ( "fmt" "net/url" "strconv" "strings" "github.com/jinzhu/gorm" ) func (p *Playlist) BeforeSave() error { for idx := range p.Entries { p.Entries[idx].LineNum = uint(idx) if p.Entries[idx].File != nil { p.Entries[idx].URI = "" // this will be regenerated in AfterFind() } else if p.Entries[idx].URI != "" { uri, err := url.Parse(p.Entries[idx].URI) if err != nil { return fmt.Errorf("playlist entry #%d is invalid: %v", idx, err) } if uri.Scheme == FileURIScheme { if uri.Host == "" || uri.Path == "" { return fmt.Errorf("playlist entry #%d is invalid: uri must be in the format %s://<show>/<file-id>", idx, FileURIScheme) } fileID, err := strconv.ParseUint(strings.TrimPrefix(uri.Path, "/"), 10, 64) if err != nil { return fmt.Errorf("playlist entry #%d is invalid: %v", idx, err) } p.Entries[idx].File = &File{ID: fileID, ShowName: uri.Host} p.Entries[idx].URI = "" // this will be regenerated in AfterFind() } } else { return fmt.Errorf("playlist entry #%d is invalid, entries must either contain a File or have a URI set", idx) } } return nil } func (p *Playlist) AfterSave(tx *gorm.DB) error { return tx.Preload("Entries.File").First(p, p.ID).Error } func (p *Playlist) AfterFind() error { for idx := range p.Entries { if p.Entries[idx].File != nil { urihost := p.Entries[idx].File.ShowName uripath := strconv.FormatUint(p.Entries[idx].File.ID, 10) uri := url.URL{Scheme: FileURIScheme, Host: urihost, Path: uripath} p.Entries[idx].URI = uri.String() } } return nil } func (st *Store) ListPlaylists(show string) (playlists Playlists, err error) { err = st.db.Where("show_name = ?", show).Preload("Entries", func(db *gorm.DB) *gorm.DB { return db.Order("playlist_entries.line_num asc") }).Preload("Entries.File").Find(&playlists).Error return } func (st *Store) CreatePlaylist(show string, playlist Playlist) (*Playlist, error) { if _, err := st.CreateShow(show); err != nil { return nil, err } playlist.ID = 0 playlist.ShowName = show err := st.db.Create(&playlist).Error return &playlist, err } func (st *Store) GetPlaylist(show string, id uint64) (playlist *Playlist, err error) { playlist = &Playlist{} // we have to make sure that the playlist actually belongs to <show> since permissions are enforced // based on show membership err = st.db.Where("show_name = ?", show).Preload("Entries", func(db *gorm.DB) *gorm.DB { return db.Order("playlist_entries.line_num ASC") }).Preload("Entries.File").First(playlist, id).Error return } func (st *Store) UpdatePlaylist(show string, id uint64, playlist Playlist) (out *Playlist, err error) { tx := st.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() if err == nil { err = fmt.Errorf("runtime panic: %+v", r) } } }() if err = tx.Error; err != nil { return } // make sure the file exists and actually belongs to <show> since permissions are enforced // based on show membership if err = tx.Where("show_name = ?", show).First(&Playlist{}, id).Error; err != nil { tx.Rollback() return } if err = tx.Delete(&PlaylistEntry{}, "playlist_id = ?", id).Error; err != nil { tx.Rollback() return } playlist.ID = id playlist.ShowName = show if err = tx.Save(&playlist).Error; err != nil { tx.Rollback() return } err = tx.Commit().Error out = &playlist return } func (st *Store) DeletePlaylist(show string, id uint64) (err error) { // we have to make sure that the playlist actually belongs to <show> since permissions are enforced // based on show membership result := st.db.Where("show_name = ?", show).Delete(&Playlist{ID: id}) if err = result.Error; err != nil { return } if result.RowsAffected == 0 { return ErrNotFound } return }