Fixed error on file upload when folder does not exists

Change-Id: Ic3e503178115f8f6939ae4850d3a240e2f4dda64
This commit is contained in:
Sebastian Marcet 2018-03-13 19:41:30 -03:00
parent 6abd51f8dc
commit 23a16de81d
11 changed files with 230 additions and 37 deletions

View File

@ -12,12 +12,12 @@
* limitations under the License.
**/
use App\Events\FileCreated;
use App\Services\Model\IFolderService;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Storage;
use models\main\File;
use models\main\IFolderRepository;
/**
* Class FileUploader
* @package App\Http\Utils
@ -25,12 +25,16 @@ use models\main\IFolderRepository;
final class FileUploader
{
/**
* @var IFolderRepository
* @var IFolderService
*/
private $folder_repository;
private $folder_service;
public function __construct(IFolderRepository $folder_repository){
$this->folder_repository = $folder_repository;
/**
* FileUploader constructor.
* @param IFolderService $folder_service
*/
public function __construct(IFolderService $folder_service){
$this->folder_service = $folder_service;
}
/**
@ -42,7 +46,8 @@ final class FileUploader
public function build(UploadedFile $file, $folder_name, $is_image = false){
$attachment = new File();
$local_path = Storage::putFileAs(sprintf('/public/%s', $folder_name), $file, $file->getClientOriginalName());
$folder = $this->folder_repository->getFolderByName($folder_name);
$folder = $this->folder_service->findOrMake($folder_name);
$attachment->setParent($folder);
$attachment->setName($file->getClientOriginalName());
$attachment->setFilename(sprintf("assets/%s/%s",$folder_name, $file->getClientOriginalName()));

View File

@ -181,10 +181,16 @@ class File extends SilverstripeBaseModel
public function __construct()
{
parent::__construct();
$this->class_name = 'File';
$this->class_name = 'File';
$this->show_in_search = true;
}
public function setImage(){
$this->class_name = 'Image';
}
public function setFolder(){
$this->class_name = 'Folder';
}
}

View File

@ -23,4 +23,18 @@ interface IFolderRepository extends IBaseRepository
* @return File
*/
public function getFolderByName($folder_name);
/**
* @param string $file_name
* @return File
*/
public function getFolderByFileName($file_name);
/**
* @param string $folder_name
* @param File $parent
* @return File
*/
public function getFolderByNameAndParent($folder_name, File $parent);
}

View File

@ -45,6 +45,27 @@ SQL;
return $native_query->getOneOrNullResult();
}
/**
* @param string $file_name
* @return File
*/
public function getFolderByFileName($file_name)
{
$query = <<<SQL
select * from File where ClassName = 'Folder' AND
FileName = :file_name
SQL;
// build rsm here
$rsm = new ResultSetMappingBuilder($this->_em);
$rsm->addRootEntityFromClassMetadata(\models\main\File::class, 'f');
$native_query = $this->_em->createNativeQuery($query, $rsm);
$native_query->setParameter("file_name", $file_name);
return $native_query->getOneOrNullResult();
}
/**
* @return string
*/
@ -52,4 +73,26 @@ SQL;
{
return File::class;
}
/**
* @param string $folder_name
* @param File $parent
* @return File
*/
public function getFolderByNameAndParent($folder_name, File $parent)
{
$query = <<<SQL
select * from File where ClassName = 'Folder' AND
Name = :folder_name and ParentID = :parent_id
SQL;
// build rsm here
$rsm = new ResultSetMappingBuilder($this->_em);
$rsm->addRootEntityFromClassMetadata(\models\main\File::class, 'f');
$native_query = $this->_em->createNativeQuery($query, $rsm);
$native_query->setParameter("folder_name", $folder_name);
$native_query->setParameter("parent_id", $parent->getId());
return $native_query->getOneOrNullResult();
}
}

View File

@ -0,0 +1,91 @@
<?php namespace App\Services\Model;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use libs\utils\ITransactionService;
use models\main\File;
use models\main\IFolderRepository;
/**
* Class FolderService
* @package App\Services\Model
*/
final class FolderService implements IFolderService
{
/**
* @var IFolderRepository
*/
private $folder_repository;
/**
* @var ITransactionService
*/
private $tx_service;
/**
* FolderService constructor.
* @param IFolderRepository $folder_repository
* @param ITransactionService $tx_service
*/
public function __construct(IFolderRepository $folder_repository, ITransactionService $tx_service)
{
$this->folder_repository = $folder_repository;
$this->tx_service = $tx_service;
}
/**
* @param string $folder_name
* @return File
*/
public function findOrMake($folder_name)
{
return $this->tx_service->transaction(function() use($folder_name){
$folder = $this->folder_repository->getFolderByFileName($folder_name);
if(!is_null($folder)) return $folder;
// create it
$folder_path = preg_replace('/^\/?(.*)\/?$/', '$1', $folder_name);
$parts = explode("/", $folder_path);
$parent = null;
$item = null;
$file_name = null;
foreach($parts as $part) {
if(!$part) continue; // happens for paths with a trailing slash
if(!empty($file_name))
$file_name .= '/';
$file_name .= $part;
$item = is_null($parent) ?
$this->folder_repository->getFolderByName($part) :
$this->folder_repository->getFolderByNameAndParent($part, $parent);
if(!$item) {
$item = new File();
if(!is_null($parent)){
$item->setParent($parent);
}
else{
$file_name = 'assets/'.$file_name;
}
$item->setFolder();
$item->setName($part);
$item->setTitle($part);
$item->setFilename($file_name);
$this->folder_repository->add($item);
}
$parent = $item;
}
return $item;
});
}
}

View File

@ -0,0 +1,26 @@
<?php namespace App\Services\Model;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use models\main\File;
/**
* Interface IFolderService
* @package App\Services\Model
*/
interface IFolderService
{
/**
* @param $string $folder_name
* @return File
*/
public function findOrMake($folder_name);
}

View File

@ -29,14 +29,12 @@ use App\Models\Foundation\Summit\Factories\SummitLocationBannerFactory;
use App\Models\Foundation\Summit\Factories\SummitLocationFactory;
use App\Models\Foundation\Summit\Factories\SummitLocationImageFactory;
use App\Models\Foundation\Summit\Factories\SummitVenueFloorFactory;
use App\Models\Foundation\Summit\Locations\Banners\ScheduledSummitLocationBanner;
use App\Models\Foundation\Summit\Locations\Banners\SummitLocationBanner;
use App\Models\Foundation\Summit\Repositories\ISummitLocationRepository;
use App\Services\Apis\GeoCodingApiException;
use App\Services\Apis\IGeoCodingAPI;
use App\Services\Model\Strategies\GeoLocation\GeoLocationStrategyFactory;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use libs\utils\ITransactionService;
@ -45,10 +43,7 @@ use models\exceptions\ValidationException;
use models\main\IFolderRepository;
use models\summit\Summit;
use models\summit\SummitAbstractLocation;
use models\summit\SummitAirport;
use models\summit\SummitExternalLocation;
use models\summit\SummitGeoLocatedLocation;
use models\summit\SummitHotel;
use models\summit\SummitLocationImage;
use models\summit\SummitVenue;
use models\summit\SummitVenueFloor;
@ -64,11 +59,6 @@ final class LocationService implements ILocationService
*/
private $location_repository;
/**
* @var IFolderRepository
*/
private $folder_repository;
/**
* @var ITransactionService
*/
@ -79,25 +69,30 @@ final class LocationService implements ILocationService
*/
private $geo_coding_api;
/**
* @var IFolderService
*/
private $folder_service;
/**
* LocationService constructor.
* @param ISummitLocationRepository $location_repository
* @param IFolderRepository $folder_repository
* @param IGeoCodingAPI $geo_coding_api
* @param IFolderService $folder_service
* @param ITransactionService $tx_service
*/
public function __construct
(
ISummitLocationRepository $location_repository,
IFolderRepository $folder_repository,
IGeoCodingAPI $geo_coding_api,
IFolderService $folder_service,
ITransactionService $tx_service
)
{
$this->location_repository = $location_repository;
$this->geo_coding_api = $geo_coding_api;
$this->folder_service = $folder_service;
$this->tx_service = $tx_service;
$this->folder_repository = $folder_repository;
}
/**
@ -1176,7 +1171,7 @@ final class LocationService implements ILocationService
);
}
$uploader = new FileUploader($this->folder_repository);
$uploader = new FileUploader($this->folder_service);
$pic = $uploader->build($file, sprintf('summits/%s/locations/%s/maps/', $location->getSummitId(), $location->getId()), true);
$map = SummitLocationImageFactory::buildMap($metadata);
$map->setPicture($pic);
@ -1280,7 +1275,7 @@ final class LocationService implements ILocationService
);
}
$uploader = new FileUploader($this->folder_repository);
$uploader = new FileUploader($this->folder_service);
$pic = $uploader->build($file, sprintf('summits/%s/locations/%s/maps/', $location->getSummitId(), $location->getId()), true);
$map->setPicture($pic);
}

View File

@ -13,6 +13,7 @@
**/
use App\Models\Foundation\Summit\Factories\PresentationSpeakerSummitAssistanceConfirmationRequestFactory;
use App\Models\Foundation\Summit\Repositories\IPresentationSpeakerSummitAssistanceConfirmationRequestRepository;
use App\Services\Model\IFolderService;
use Illuminate\Http\UploadedFile;
use libs\utils\ITransactionService;
use models\exceptions\EntityNotFoundException;
@ -20,7 +21,6 @@ use models\exceptions\ValidationException;
use models\main\EmailCreationRequest;
use models\main\File;
use models\main\IEmailCreationRequestRepository;
use models\main\IFolderRepository;
use models\main\IMemberRepository;
use models\main\MemberPromoCodeEmailCreationRequest;
use models\main\SpeakerCreationEmailCreationRequest;
@ -52,9 +52,9 @@ final class SpeakerService implements ISpeakerService
private $member_repository;
/**
* @var IFolderRepository
* @var IFolderService
*/
private $folder_repository;
private $folder_service;
/**
* @var ISpeakerRegistrationRequestRepository
@ -89,7 +89,7 @@ final class SpeakerService implements ISpeakerService
* @param ISpeakerRegistrationRequestRepository $speaker_registration_request_repository
* @param ISpeakerSummitRegistrationPromoCodeRepository $registration_code_repository
* @param IEmailCreationRequestRepository $email_creation_request_repository
* @param IFolderRepository $folder_repository
* @param IFolderService $folder_service
* @param IPresentationSpeakerSummitAssistanceConfirmationRequestRepository $speakers_assistance_repository
* @param ITransactionService $tx_service
*/
@ -100,14 +100,14 @@ final class SpeakerService implements ISpeakerService
ISpeakerRegistrationRequestRepository $speaker_registration_request_repository,
ISpeakerSummitRegistrationPromoCodeRepository $registration_code_repository,
IEmailCreationRequestRepository $email_creation_request_repository,
IFolderRepository $folder_repository,
IFolderService $folder_service,
IPresentationSpeakerSummitAssistanceConfirmationRequestRepository $speakers_assistance_repository,
ITransactionService $tx_service
)
{
$this->speaker_repository = $speaker_repository;
$this->member_repository = $member_repository;
$this->folder_repository = $folder_repository;
$this->folder_service = $folder_service;
$this->speaker_registration_request_repository = $speaker_registration_request_repository;
$this->registration_code_repository = $registration_code_repository;
$this->email_creation_request_repository = $email_creation_request_repository;
@ -397,7 +397,7 @@ final class SpeakerService implements ISpeakerService
throw new ValidationException(sprintf( "file exceeds max_file_size (%s MB).", ($max_file_size/1024)/1024));
}
$uploader = new FileUploader($this->folder_repository);
$uploader = new FileUploader($this->folder_service);
$photo = $uploader->build($file, 'profile-images', true);
$speaker->setPhoto($photo);

View File

@ -17,6 +17,7 @@ use App\Events\MyScheduleAdd;
use App\Events\MyScheduleRemove;
use App\Http\Utils\FileUploader;
use App\Models\Utils\IntervalParser;
use App\Services\Model\IFolderService;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Http\UploadedFile;
@ -25,7 +26,6 @@ use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\File;
use models\main\ICompanyRepository;
use models\main\IFolderRepository;
use models\main\IGroupRepository;
use models\main\IMemberRepository;
use models\main\ITagRepository;
@ -135,9 +135,9 @@ final class SummitService implements ISummitService
private $calendar_sync_work_request_repository;
/**
* @var IFolderRepository
* @var IFolderService
*/
private $folder_repository;
private $folder_service;
/**
* @var ICompanyRepository
@ -161,7 +161,7 @@ final class SummitService implements ISummitService
* @param IRSVPRepository $rsvp_repository
* @param IAbstractCalendarSyncWorkRequestRepository $calendar_sync_work_request_repository
* @param IEventbriteAPI $eventbrite_api
* @param IFolderRepository $folder_repository
* @param IFolderService $folder_service
* @param ICompanyRepository $company_repository
* @param IGroupRepository $group_repository,
* @param ITransactionService $tx_service
@ -178,7 +178,7 @@ final class SummitService implements ISummitService
IRSVPRepository $rsvp_repository,
IAbstractCalendarSyncWorkRequestRepository $calendar_sync_work_request_repository,
IEventbriteAPI $eventbrite_api,
IFolderRepository $folder_repository,
IFolderService $folder_service,
ICompanyRepository $company_repository,
IGroupRepository $group_repository,
ITransactionService $tx_service
@ -194,9 +194,9 @@ final class SummitService implements ISummitService
$this->rsvp_repository = $rsvp_repository;
$this->calendar_sync_work_request_repository = $calendar_sync_work_request_repository;
$this->eventbrite_api = $eventbrite_api;
$this->folder_repository = $folder_repository;
$this->folder_service = $folder_service;
$this->company_repository = $company_repository;
$this->group_repository = $group_repository;
$this->group_repository = $group_repository;
$this->tx_service = $tx_service;
}
@ -1230,7 +1230,7 @@ final class SummitService implements ISummitService
throw new ValidationException(sprintf( "file exceeds max_file_size (%s MB).", ($max_file_size/1024)/1024));
}
$uploader = new FileUploader($this->folder_repository);
$uploader = new FileUploader($this->folder_service);
$attachment = $uploader->build($file, 'summit-event-attachments', true);
$event->setAttachment($attachment);

View File

@ -14,7 +14,9 @@
use App\Services\Apis\GoogleGeoCodingAPI;
use App\Services\Apis\IGeoCodingAPI;
use App\Services\Model\AttendeeService;
use App\Services\Model\FolderService;
use App\Services\Model\IAttendeeService;
use App\Services\Model\IFolderService;
use App\Services\Model\ILocationService;
use App\Services\Model\IMemberService;
use App\Services\Model\ISummitEventTypeService;
@ -173,6 +175,12 @@ final class ServicesProvider extends ServiceProvider
LocationService::class
);
App::singleton
(
IFolderService::class,
FolderService::class
);
App::singleton(IGeoCodingAPI::class, function(){
return new GoogleGeoCodingAPI
(

View File

@ -17,6 +17,11 @@
*/
final class OAuth2SummitLocationsApiTest extends ProtectedApiTest
{
public function testGetFolder(){
$service = \Illuminate\Support\Facades\App::make(\App\Services\Model\IFolderService::class);
$folder = $service->findOrMake('summits/1/locations/292/maps');
}
public function testGetCurrentSummitLocations($summit_id = 23)
{
$params = [