Skip to content
Snippets Groups Projects
files.go 3.63 KiB
Newer Older
Christian Pointner's avatar
Christian Pointner committed
//
//  tank
//
//  Import and Playlist Daemon for autoradio project
//
//
//  Copyright (C) 2017-2018 Christian Pointner <equinox@helsinki.at>
Christian Pointner's avatar
Christian Pointner committed
//
//  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"
	"os"
	"path/filepath"
func (st *Store) GetFilePath(group string, id uint64) string {
	filename := fmt.Sprintf("%d%s", id, st.audio.Format.Extension())
	return filepath.Join(st.getGroupPath(group), filename)
}

Christian Pointner's avatar
Christian Pointner committed
func (st *Store) ListFiles(group string) (files Files, err error) {
	// TODO: why does this not work?
	// err = st.db.Model(&Group{Name: group}).Related(&files).Error
	err = st.db.Where("group_name = ?", group).Find(&files).Error
func (st *Store) CreateFile(group string, file File) (*File, error) {
	if _, err := st.CreateGroup(group); err != nil {
		return nil, err
	}
	file.ID = 0
	file.GroupName = group
	err := st.db.Create(&file).Error
	return &file, err
func (st *Store) GetFile(group string, id uint64) (file *File, err error) {
	file = &File{}
	// we have to make sure that the file actually belongs to <group>
	// otherwise a bad user can trick us into returning files for groups it
	// normally has no access to
	err = st.db.Where("group_name = ?", group).First(file, id).Error
func (st *Store) UpdateFile(group string, id uint64, file File) (*File, error) {
	tx := st.db.Begin()
	if err := tx.First(&File{}, id).Error; err != nil {
		tx.Rollback()
		return nil, err
	}

	file.ID = id
	file.GroupName = group
	err := tx.Save(&file).Error
func (st *Store) getFileUsage(tx *gorm.DB, id uint64) (playlists Playlists, err error) {
	sub := tx.Model(PlaylistEntry{}).Select("playlist_id").Where("file_id = ?", id).Group("playlist_id").SubQuery()
	err = tx.Where("id in ?", sub).Find(&playlists).Error
	return
}

func (st *Store) GetFileUsage(group string, id uint64) (playlists Playlists, err error) {
	tx := st.db.Begin()
	// make sure the file exists and actually belongs to <group>
	cnt := 0
	if err = tx.Model(&File{ID: id}).Where("group_name = ?", group).Count(&cnt).Error; err != nil {
		return
	}
	if cnt == 0 {
		return nil, ErrNotFound
	}
	playlists, err = st.getFileUsage(tx, id)
	tx.Rollback() // this transaction shouldn't have changed anything anyway
	return
}

func (st *Store) DeleteFile(group string, id uint64) error {
	tx := st.db.Begin()
	// make sure the file exists and actually belongs to <group>
	if err := tx.Where("group_name = ?", group).First(&File{}, id).Error; err != nil {
		tx.Rollback()
	if err := tx.Delete(&File{ID: id}).Error; err != nil {
		// we assume this is due to a FK constraint -> file in use by playlist_entry
		playlists, err := st.getFileUsage(tx, id)
		tx.Rollback() // this transaction shouldn't have changed anything anyway

		if err != nil {
			return err
		}
		return &ErrFileInUse{Playlists: playlists}
	filename := st.GetFilePath(group, id)
	if err := os.Remove(filename); err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("unable to delete file '%s': %v", filename, err)
	}
	return nil