{"action":"created","issue":{"url":"https://api.github.com/repos/octobercms/october/issues/3780","repository_url":"https://api.github.com/repos/octobercms/october","labels_url":"https://api.github.com/repos/octobercms/october/issues/3780/labels{/name}","comments_url":"https://api.github.com/repos/octobercms/october/issues/3780/comments","events_url":"https://api.github.com/repos/octobercms/october/issues/3780/events","html_url":"https://github.com/octobercms/october/issues/3780","id":359710802,"node_id":"MDU6SXNzdWUzNTk3MTA4MDI=","number":3780,"title":"Potential problem with File","user":{"login":"WaskiWabit","id":10679529,"node_id":"MDQ6VXNlcjEwNjc5NTI5","avatar_url":"https://avatars3.githubusercontent.com/u/10679529?v=4","gravatar_id":"","url":"https://api.github.com/users/WaskiWabit","html_url":"https://github.com/WaskiWabit","followers_url":"https://api.github.com/users/WaskiWabit/followers","following_url":"https://api.github.com/users/WaskiWabit/following{/other_user}","gists_url":"https://api.github.com/users/WaskiWabit/gists{/gist_id}","starred_url":"https://api.github.com/users/WaskiWabit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/WaskiWabit/subscriptions","organizations_url":"https://api.github.com/users/WaskiWabit/orgs","repos_url":"https://api.github.com/users/WaskiWabit/repos","events_url":"https://api.github.com/users/WaskiWabit/events{/privacy}","received_events_url":"https://api.github.com/users/WaskiWabit/received_events","type":"User","site_admin":false},"labels":[{"id":67885483,"node_id":"MDU6TGFiZWw2Nzg4NTQ4Mw==","url":"https://api.github.com/repos/octobercms/october/labels/Type:%20Question","name":"Type: Question","color":"cc317c","default":false},{"id":143615025,"node_id":"MDU6TGFiZWwxNDM2MTUwMjU=","url":"https://api.github.com/repos/octobercms/october/labels/Type:%20Unconfirmed%20Bug","name":"Type: Unconfirmed Bug","color":"f7c6c7","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":10,"created_at":"2018-09-13T01:39:35Z","updated_at":"2018-09-14T19:46:58Z","closed_at":null,"author_association":"NONE","body":"##### Expected behavior\r\nTo be able to attach mp3 files to a model via attach one when the mp3 files are on the same file system, (not uploaded via the backend interface).\r\n\r\n##### Actual behavior\r\nI have a folder full of mp3 mixes that I am trying to migrate from an old site to October. When using my AudioUpload controller in the backend (which is a standard model + attach one), everything works as expected. I am able to upload a mix in the backend, and download it via the frontend component. But who wants to upload years of mixes right? So I wrote an artisan command that scans a directory for mixes, then places them within October. But when processing and saving a mix via artisan command, then attaching it to a model, the file (in system_files) does not receive an **attachment_id**. And I believe this results in the following errors.\r\n\r\n**Backend Error** (when I load the AudioUpload controllers index method)\r\nCall to a member function getFilename() on null\r\n\r\n**Frontend Error** (when I attempt to download the mix via component)\r\nThe audio field is required.\r\n\r\n**These errors do not happen when 2 things are in place.** \r\n1. The file is uploaded via uploader instead of taken from the local disk.\r\n2. The system file has an attachment_id (even though it's a nullable field).\r\n\r\nI guess my question is why isn't an attachment_id being applied to the system_file when I use the artisan command, but when I upload a file thru the interface, it has an attachment_id. \r\n\r\nHere is the command. It's very procedural (and dirty with my use of explode lol), but it gets the job done :) Sorta\r\n```\r\n<?php\r\n\r\nnamespace WaskiWabit\\Dt\\Console;\r\n\r\nuse Illuminate\\Console\\Command;\r\nuse Symfony\\Component\\Console\\Input\\InputOption;\r\nuse Symfony\\Component\\Console\\Input\\InputArgument;\r\nuse Backend\\Models\\User;\r\nuse WaskiWabit\\Dt\\Models\\AudioUpload;\r\nuse getID3;\r\nuse System\\Models\\File;\r\n\r\nclass ProcessMixes extends Command {\r\n\r\n    /**\r\n     * @var string The console command name.\r\n     */\r\n    protected $name = 'dt:processmixes';\r\n\r\n    /**\r\n     * @var string The console command description.\r\n     */\r\n    protected $description = 'Adds mixes from the old dt to the new.';\r\n\r\n    /**\r\n     * @var string The directory where the mixes are.\r\n     */\r\n    protected $directory = '/nfs/c09/h01/mnt/127200/domains/dev.dubterrain.net/html/storage/mixes';\r\n    \r\n    /**\r\n     * @var string The directory where the mixes are.\r\n     */\r\n    protected $movedDirectory = '/nfs/c09/h01/mnt/127200/domains/dev.dubterrain.net/html/storage/app/uploads/public';\r\n\r\n    /**\r\n     * Execute the console command.\r\n     * @return void\r\n     */\r\n    public function handle() {\r\n        $mixes = scandir($this->directory);\r\n        $mix_count = count($mixes);\r\n        $mix_path = '';\r\n\r\n        if ($mix_count == 0) {\r\n            $this->error('There are 0 mixes to process!');\r\n            exit;\r\n        }\r\n\r\n        $this->info('Processing ' . $mix_count . ' mixes');\r\n        $i = 1;\r\n        foreach ($mixes as $mix) {\r\n            if ($mix != '.' && $mix != '..') {\r\n                // files path\r\n                $mix_path = $this->directory . '/' . $mix;\r\n\r\n                // strip out the djs name\r\n                $exp = explode(' ', $mix);\r\n                $dj_name = $exp[0];\r\n                $mix_date = $exp[2];\r\n                $mix_date = explode('.mp3', $mix_date);\r\n                $mix_date = $mix_date[0];\r\n                $mix_name = explode('.mp3', $mix);\r\n                $mix_name = $mix_name[0];\r\n\r\n                $this->output->writeln($i . '. Processing mix by ' . $dj_name . ' recorded on ' . $mix_date . '.');\r\n\r\n                // locate user\r\n                $backend_user = User::where('login', '=', $dj_name)->first();\r\n                if (!$backend_user instanceof \\Backend\\Models\\User) {\r\n                    $this->error('User ' . $dj_name . ' doesnt exist in the system!');\r\n                    continue;\r\n                }\r\n                \r\n                // make sure mix doesnt already exist\r\n\r\n                // Verify Mp3 via ID3\r\n                $id3 = new getID3;\r\n                $audioInfo = $id3->analyze($mix_path);\r\n\r\n                if ($audioInfo['audio']['bitrate_mode'] != 'cbr') {\r\n                    $this->error('Invalid bitrate mode. Must be (CBR) Constant Bitrate.');\r\n                }\r\n\r\n                if ($audioInfo['audio']['channels'] != '2') {\r\n                    $this->error('Invalid number of audio channels. Must be 2 (Stereo).');\r\n                }\r\n\r\n                if ($audioInfo['audio']['sample_rate'] != '44100') {\r\n                    $this->error('Invalid sample rate. Must be 44100.');\r\n                }\r\n\r\n                if ($audioInfo['audio']['bitrate'] != '128000') {\r\n                    $this->error('Invalid bitrate. Must be 128kbps.');\r\n                }\r\n\r\n                // get highest attachment id for this user and of this type\r\n                //$attachment_id = File::where('content_type', 'audio/mpeg')->max('attachment_id');\r\n\r\n                $file = new File;\r\n                $file->file_name = $mix_name;\r\n                $file->data = $mix_path;\r\n                $file->is_public = true;\r\n                $file->save();\r\n                \r\n                //$file->attachment_id = $attachment_id;\r\n                //$file->save();\r\n                \r\n                // get disk name for directory structure\r\n                $disk_name = $file->disk_name;\r\n                $folder_1 = substr($disk_name, 0, 3);\r\n                $folder_2 = substr($disk_name, 3, 3);\r\n                $folder_3 = substr($disk_name, 6, 3);\r\n                \r\n                // copy file over\r\n                copy($mix_path, $this->movedDirectory . '/' . $folder_1 . '/' . $folder_2 . '/' . $folder_3 . '/' . $disk_name);\r\n                \r\n                // save audio upload\r\n                $au = new AudioUpload();\r\n                $au->backend_users_id = $backend_user->id;\r\n                $au->duration = $audioInfo['playtime_string'];\r\n                $au->recorded_at = $mix_date;\r\n                $au->audio()->add($file);\r\n                $au->save();\r\n\r\n                break;\r\n                // bottom\r\n                ++$i;\r\n            }\r\n        }\r\n\r\n        $this->info('Processed ' . $i . ' mixes! All done!');\r\n    }\r\n\r\n    /**\r\n     * Get the console command arguments.\r\n     * @return array\r\n     */\r\n    protected function getArguments() {\r\n        return [];\r\n    }\r\n\r\n    /**\r\n     * Get the console command options.\r\n     * @return array\r\n     */\r\n    protected function getOptions() {\r\n        return [];\r\n    }\r\n\r\n}\r\n\r\n```\r\nAnd here is the associated AudioUpload model\r\n```\r\n<?php namespace WaskiWabit\\Dt\\Models;\r\n\r\nuse Model;\r\nuse BackendAuth;\r\nuse WaskiWabit\\Dt\\Models\\Settings;\r\nuse WaskiWabit\\Dt\\Classes\\FtpAudioFile;\r\nuse WaskiWabit\\Dt\\Classes\\AudioUploadHelper;\r\n\r\n/**\r\n * AudioUpload Model\r\n */\r\nclass AudioUpload extends Model\r\n{\r\n    use \\October\\Rain\\Database\\Traits\\Validation;\r\n\r\n    /**\r\n     * @var string The database table used by the model.\r\n     */\r\n    public $table = 'waskiwabit_audiouploader_audio_uploads';\r\n\r\n    /**\r\n     * @var array Validation rules\r\n     */\r\n    public $rules = [\r\n        'recorded_at' => 'required',\r\n        'audio' => 'required',\r\n        'duration' => 'required'\r\n    ];\r\n\r\n    /**\r\n     * @var array Guarded fields\r\n     */\r\n    protected $guarded = ['*'];\r\n\r\n    /**\r\n     * @var array Fillable fields\r\n     */\r\n    protected $fillable = [];\r\n\r\n    /**\r\n     * @var array Relations\r\n     */\r\n    public $hasOne = [];\r\n    public $hasMany = [];\r\n    public $belongsTo = [\r\n        'backend_users' => ['Backend\\Models\\User']\r\n    ];\r\n    public $belongsToMany = [];\r\n    public $morphTo = [];\r\n    public $morphOne = [];\r\n    public $morphMany = [];\r\n    public $attachOne = [\r\n        'audio' => 'System\\Models\\File'\r\n    ];\r\n    public $attachMany = [];\r\n\r\n    /**\r\n     * Attach user id to record\r\n     */\r\n    public function beforeCreate() {\r\n        \r\n        if(BackendAuth::getUser() instanceof \\Backend\\Models\\User) {\r\n            $backendUser = BackendAuth::getUser();\r\n            $this->backend_users_id = $backendUser->id;\r\n        }\r\n        $this->tot_downloads = 0;\r\n        $this->tot_views = 0;\r\n        $this->in_rotation = 0;\r\n    }\r\n\r\n    public function beforeDelete() {\r\n        if($this->in_rotation == 1) {\r\n            // remove file from ftp\r\n            $ftp = new FtpAudioFile($this, AudioUploadHelper::getAudioFileName($this, BackendAuth::getUser()));\r\n            $ftp->remAudioFile();\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nAny help would be great. And like I said, I think I'm mimicking the upload process, but maybe I'm missing something. Thanks!\r\n \r\n##### October build\r\n442\r\n"},"comment":{"url":"https://api.github.com/repos/octobercms/october/issues/comments/421465637","html_url":"https://github.com/octobercms/october/issues/3780#issuecomment-421465637","issue_url":"https://api.github.com/repos/octobercms/october/issues/3780","id":421465637,"node_id":"MDEyOklzc3VlQ29tbWVudDQyMTQ2NTYzNw==","user":{"login":"WaskiWabit","id":10679529,"node_id":"MDQ6VXNlcjEwNjc5NTI5","avatar_url":"https://avatars3.githubusercontent.com/u/10679529?v=4","gravatar_id":"","url":"https://api.github.com/users/WaskiWabit","html_url":"https://github.com/WaskiWabit","followers_url":"https://api.github.com/users/WaskiWabit/followers","following_url":"https://api.github.com/users/WaskiWabit/following{/other_user}","gists_url":"https://api.github.com/users/WaskiWabit/gists{/gist_id}","starred_url":"https://api.github.com/users/WaskiWabit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/WaskiWabit/subscriptions","organizations_url":"https://api.github.com/users/WaskiWabit/orgs","repos_url":"https://api.github.com/users/WaskiWabit/repos","events_url":"https://api.github.com/users/WaskiWabit/events{/privacy}","received_events_url":"https://api.github.com/users/WaskiWabit/received_events","type":"User","site_admin":false},"created_at":"2018-09-14T19:46:58Z","updated_at":"2018-09-14T19:46:58Z","author_association":"NONE","body":"Thank you very much @LukeTowers  for taking the time to help me out with this issue. I know you are a busy man. Much appreciated!"}}
{"actor":{"display_login":"WaskiWabit"}}