Newer
Older
// tank, Import and Playlist Daemon for Aura project
// Copyright (C) 2017-2020 Christian Pointner <equinox@helsinki.at>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// This program 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 Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import (
"fmt"
"os"
"path/filepath"
)

Ernesto Rico Schmidt
committed
func (st *Store) GetFilePath(showID uint64, fileID uint64) string {
filename := fmt.Sprintf("%d%s", fileID, st.Audio.Format.Extension())
return filepath.Join(st.getShowPath(showID), filename)

Ernesto Rico Schmidt
committed
func (st *Store) ListFiles(showID uint64, offset, limit int) (files []File, err error) {
err = st.db.Where("show_id = ?", showID).Order("id").Offset(offset).Limit(limit).Find(&files).Error

Ernesto Rico Schmidt
committed
func (st *Store) CreateFile(showID uint64, file File) (*File, error) {
if _, err := st.CreateShow(showID); err != nil {
return nil, err
}
file.ID = 0

Ernesto Rico Schmidt
committed
file.ShowID = showID
err := st.db.Create(&file).Error
return &file, err

Ernesto Rico Schmidt
committed
func (st *Store) GetFile(showID uint64, fileID uint64) (file *File, err error) {
// we have to make sure that the file actually belongs to <show> since permissions are enforced
// based on show membership

Ernesto Rico Schmidt
committed
err = st.db.Where("show_id = ?", showID).First(file, fileID).Error

Ernesto Rico Schmidt
committed
func (st *Store) UpdateFile(showID uint64, id uint64, file File) (out *File, err error) {
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

Ernesto Rico Schmidt
committed
if err = tx.Where("show_id = ?", showID).First(&File{}, id).Error; err != nil {

Ernesto Rico Schmidt
committed
file.ShowID = showID
if err = tx.Save(&file).Error; err != nil {
err = tx.Commit().Error
out = &file
return

Ernesto Rico Schmidt
committed
func (st *Store) UpdateFileMetadata(showID uint64, id uint64, metadata map[string]string) (file *File, 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

Ernesto Rico Schmidt
committed
if err = tx.Where("show_id = ?", showID).First(&file).Error; err != nil {
if file.Source.Import.State != ImportDone {
err = ErrFileImportNotDone
return

Ernesto Rico Schmidt
committed
if fields, err = st.metadataFieldsToFile(showID, id, metadata); err != nil {

Ernesto Rico Schmidt
committed
if err = tx.Model(&file).Where("show_id = ?", showID).Update(fields).Error; err != nil {

Ernesto Rico Schmidt
committed
func (st *Store) updateFile(showID uint64, id uint64, values ...interface{}) (file *File, err error) {
file = &File{ID: id}

Ernesto Rico Schmidt
committed
if err = st.db.Model(&file).Where("show_id = ?", showID).Update(values...).Error; err != nil {

Ernesto Rico Schmidt
committed
func (st *Store) SetFileImportStateInitializing(showID uint64, id uint64) (file *File, err error) {
file = &File{ID: id}

Ernesto Rico Schmidt
committed
result := st.db.Model(&file).Where("show_id = ? and source__import__state = ?", showID, ImportNew).Update("source__import__state", ImportInitializing)
if result.Error != nil {
return nil, result.Error
}
if result.RowsAffected != 1 {
return nil, ErrFileNotNew
}
return file, nil
}

Ernesto Rico Schmidt
committed
func (st *Store) SetFileImportStatePending(showID uint64, id uint64) (file *File, err error) {
return st.updateFile(showID, id, "source__import__state", ImportPending)

Ernesto Rico Schmidt
committed
func (st *Store) SetFileImportStateRunning(showID uint64, id uint64) (file *File, err error) {
return st.updateFile(showID, id, "source__import__state", ImportRunning)

Ernesto Rico Schmidt
committed
func (st *Store) SetFileImportStateDone(showID uint64, id uint64) (*File, error) {
fields, err := st.metadataFieldsFromFile(showID, id)
fields["source__import__state"] = ImportDone

Ernesto Rico Schmidt
committed
return st.updateFile(showID, id, fields)

Ernesto Rico Schmidt
committed
func (st *Store) SetFileImportStateAborted(showID uint64, id uint64, error string) (file *File, err error) {
fields := make(map[string]interface{})
fields["source__import__state"] = ImportAborted
fields["source__import__error"] = error

Ernesto Rico Schmidt
committed
return st.updateFile(showID, id, fields)

Ernesto Rico Schmidt
committed
func (st *Store) UpdateFileSourceHash(showID uint64, id uint64, hash string) (*File, error) {
return st.updateFile(showID, id, "source__hash", hash)
func (st *Store) getFileUsage(id uint64, playlists *[]Playlist) (err error) {
sub := st.db.Model(PlaylistEntry{}).Select("playlist_id").Where("file_id = ?", id).Group("playlist_id").SubQuery()
err = st.db.Where("id in ?", sub).Find(playlists).Error
return
}

Ernesto Rico Schmidt
committed
func (st *Store) GetFileUsage(showID uint64, id uint64) (playlists []Playlist, err error) {
// make sure the file exists and actually belongs to <show> since permissions are enforced
// based on show membership
cnt := 0

Ernesto Rico Schmidt
committed
if err = st.db.Model(&File{ID: id}).Where("show_id = ?", showID).Count(&cnt).Error; err != nil {
return
}
if cnt == 0 {
return nil, ErrNotFound
}
return
}

Ernesto Rico Schmidt
committed
func (st *Store) DeleteFile(showID uint64, id uint64) (err error) {
// make sure the file actually belongs to <show> since permissions are enforced
// based on show membership

Ernesto Rico Schmidt
committed
result := st.db.Where("show_id = ?", showID).Delete(&File{ID: id})
// we assume this is due to a FK constraint -> file in use by playlist_entry
if err = st.getFileUsage(id, &usageErr.Playlists); err != nil {
if result.RowsAffected == 0 {
return ErrNotFound
}

Ernesto Rico Schmidt
committed
filename := st.GetFilePath(showID, id)
if err := os.Remove(filename); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("unable to delete file '%s': %v", filename, err)
}