diff --git a/app/Http/Utils/FileUploader.php b/app/Http/Utils/FileUploader.php index 28189369..53be2096 100644 --- a/app/Http/Utils/FileUploader.php +++ b/app/Http/Utils/FileUploader.php @@ -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())); diff --git a/app/Models/Foundation/Main/File.php b/app/Models/Foundation/Main/File.php index bc74a528..e2fe67c8 100644 --- a/app/Models/Foundation/Main/File.php +++ b/app/Models/Foundation/Main/File.php @@ -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'; + } + } \ No newline at end of file diff --git a/app/Models/Foundation/Main/Repositories/IFolderRepository.php b/app/Models/Foundation/Main/Repositories/IFolderRepository.php index c4e13bdc..0c726fba 100644 --- a/app/Models/Foundation/Main/Repositories/IFolderRepository.php +++ b/app/Models/Foundation/Main/Repositories/IFolderRepository.php @@ -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); + } \ No newline at end of file diff --git a/app/Repositories/Main/DoctrineFolderRepository.php b/app/Repositories/Main/DoctrineFolderRepository.php index 382279b8..18a23948 100644 --- a/app/Repositories/Main/DoctrineFolderRepository.php +++ b/app/Repositories/Main/DoctrineFolderRepository.php @@ -45,6 +45,27 @@ SQL; return $native_query->getOneOrNullResult(); } + /** + * @param string $file_name + * @return File + */ + public function getFolderByFileName($file_name) + { + + $query = <<_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 = <<_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(); + } } \ No newline at end of file diff --git a/app/Services/Model/FolderService.php b/app/Services/Model/FolderService.php new file mode 100644 index 00000000..1b98414b --- /dev/null +++ b/app/Services/Model/FolderService.php @@ -0,0 +1,91 @@ +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; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/IFolderService.php b/app/Services/Model/IFolderService.php new file mode 100644 index 00000000..7f07540d --- /dev/null +++ b/app/Services/Model/IFolderService.php @@ -0,0 +1,26 @@ +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); } diff --git a/app/Services/Model/SpeakerService.php b/app/Services/Model/SpeakerService.php index 4651034a..e95cd825 100644 --- a/app/Services/Model/SpeakerService.php +++ b/app/Services/Model/SpeakerService.php @@ -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); diff --git a/app/Services/Model/SummitService.php b/app/Services/Model/SummitService.php index bab9b29f..3e099c4c 100644 --- a/app/Services/Model/SummitService.php +++ b/app/Services/Model/SummitService.php @@ -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); diff --git a/app/Services/ServicesProvider.php b/app/Services/ServicesProvider.php index 389d392c..e14fcd00 100644 --- a/app/Services/ServicesProvider.php +++ b/app/Services/ServicesProvider.php @@ -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 ( diff --git a/tests/OAuth2SummitLocationsApiTest.php b/tests/OAuth2SummitLocationsApiTest.php index 16b443e8..560b3416 100644 --- a/tests/OAuth2SummitLocationsApiTest.php +++ b/tests/OAuth2SummitLocationsApiTest.php @@ -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 = [