// // tank // // Import and Playlist Daemon for autoradio project // // // Copyright (C) 2017-2018 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://<group>/<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, GroupName: 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) AfterFind() error { for idx := range p.Entries { if p.Entries[idx].File != nil { urihost := p.Entries[idx].File.GroupName 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(group string) (playlists Playlists, err error) { err = st.db.Where("group_name = ?", group).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(group string, playlist Playlist) (*Playlist, error) { if _, err := st.CreateGroup(group); err != nil { return nil, err } playlist.ID = 0 playlist.GroupName = group err := st.db.Create(&playlist).Error // TODO: the returned playlist object will not contain properly initialized File Objects return &playlist, err } func (st *Store) GetPlaylist(group string, id uint64) (playlist *Playlist, err error) { playlist = &Playlist{} // we have to make sure that the playlist actually belongs to <group> // otherwise a bad user can trick us into returning playlists for groups it // normally has no access to err = st.db.Where("group_name = ?", group).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(group string, id uint64, playlist Playlist) (*Playlist, error) { // TODO: implement this return nil, ErrNotImplented } func (st *Store) DeletePlaylist(group string, id uint64) (err error) { tx := st.db.Begin() if err = tx.First(&Playlist{}, id).Error; err != nil { tx.Rollback() return } if err = tx.Delete(&Playlist{ID: id}).Error; err != nil { tx.Rollback() return } tx.Commit() return }