diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php index 16bba82b..f1a63d0e 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php @@ -13,6 +13,7 @@ **/ use App\Http\Utils\BooleanCellFormatter; use App\Http\Utils\EpochCellFormatter; +use App\Http\Utils\MultipartFormDataCleaner; use Exception; use Illuminate\Http\Request as LaravelRequest; use Illuminate\Support\Facades\Input; @@ -1358,4 +1359,56 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController } } + /** + * @param LaravelRequest $request + * @param $summit_id + */ + public function importEventData(LaravelRequest $request, $summit_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $payload = $request->all(); + + $rules = [ + 'file' => 'required', + 'send_speaker_email' => 'required|boolean', + ]; + + $payload = MultipartFormDataCleaner::cleanBool('send_speaker_email', $payload); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $ex = new ValidationException; + $ex->setMessages($validation->messages()->toArray()); + throw $ex; + } + + $file = $request->file('file'); + + $this->service->importEventData($summit, $file, $payload); + + return $this->ok(); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + } \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index 471d032a..c84685f2 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -256,7 +256,12 @@ Route::group([ Route::group(array('prefix' => 'events'), function () { Route::get('',[ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitEventsApiController@getEvents']); - Route::get('csv',[ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitEventsApiController@getEventsCSV']); + + + Route::group(['prefix' => 'csv'], function () { + Route::get('',[ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitEventsApiController@getEventsCSV']); + Route::post('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitEventsApiController@importEventData']); + }); // bulk actions Route::delete('/publish', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitEventsApiController@unPublishEvents']); Route::put('/publish', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitEventsApiController@updateAndPublishEvents']); diff --git a/app/Jobs/Emails/PresentationSubmissions/ImportEventSpeakerEmail.php b/app/Jobs/Emails/PresentationSubmissions/ImportEventSpeakerEmail.php new file mode 100644 index 00000000..19df4084 --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/ImportEventSpeakerEmail.php @@ -0,0 +1,94 @@ +getSummit(); + $creator = $presentation->getCreator(); + $selection_plan = $presentation->getSelectionPlan(); + + $speaker_management_base_url = Config::get('cfp.base_url'); + $idp_base_url = Config::get('idp.base_url'); + $support_email = $summit->getSupportEmail(); + $support_email = !empty($support_email) ? $support_email: Config::get("cfp.support_email", null); + + if(empty($speaker_management_base_url)) + throw new \InvalidArgumentException('cfp.base_url is null.'); + + if(empty($idp_base_url)) + throw new \InvalidArgumentException('idp.base_url is null.'); + + if(empty($support_email)) + throw new \InvalidArgumentException('cfp.support_email is null.'); + + $payload = []; + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['creator_full_name'] = is_null($creator) ? '' : $creator->getFullName(); + $payload['creator_email'] = is_null($creator) ? '': $creator->getEmail(); + $payload['presentation_name'] = $presentation->getTitle(); + $payload['presentation_start_date'] = $presentation->getStartDateNice(); + $payload['presentation_end_date'] = $presentation->getEndDateNice(); + $payload['presentation_location'] = $presentation->getLocationName(); + + $payload['selection_plan_name'] = is_null($selection_plan) ? '': $selection_plan->getName(); + $payload['presentation_edit_link'] = $presentation->getEditLink(); + $payload['summit_date'] = $summit->getMonthYear(); + $payload['until_date'] =is_null($selection_plan) ? '' : $selection_plan->getSubmissionEndDate()->format('d F, Y'); + $payload['selection_process_link'] = sprintf("%s/app/%s", $speaker_management_base_url, $summit->getRawSlug()); + $payload['speaker_management_link'] = sprintf("%s/app/%s", $speaker_management_base_url, $summit->getRawSlug()); + $payload['bio_edit_link'] = sprintf("%s/app/%s/profile", $speaker_management_base_url, $summit->getRawSlug()); + if(!empty($setPasswordLink)){ + $payload['bio_edit_link'] = $setPasswordLink; + } + $payload['reset_password_link'] = sprintf("%s/auth/password/reset", $idp_base_url); + $payload['support_email'] = $support_email; + $payload['speaker_full_name'] = $speaker->getFullName(' '); + if(empty($payload['speaker_full_name'])){ + $payload['speaker_full_name'] = $speaker->getEmail(); + } + $payload['speaker_email'] = $speaker->getEmail(); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['speaker_email']); + } +} \ No newline at end of file diff --git a/app/Jobs/ProcessEventDataImport.php b/app/Jobs/ProcessEventDataImport.php new file mode 100644 index 00000000..a5f19d09 --- /dev/null +++ b/app/Jobs/ProcessEventDataImport.php @@ -0,0 +1,80 @@ +summit_id = $summit_id; + $this->filename = $filename; + $this->send_speaker_email = boolval($payload['send_speaker_email']); + } + + /** + * @param ISummitService $service + */ + public function handle + ( + ISummitService $service + ) + { + try { + Log::debug(sprintf("ProcessEventDataImport::handle summit %s filename %s send_speaker_email %s", $this->summit_id, $this->filename, $this->send_speaker_email)); + $service->processEventData($this->summit_id, $this->filename, $this->send_speaker_email); + } catch (ValidationException $ex) { + Log::warning($ex); + } catch (\Exception $ex) { + Log::error($ex); + } + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/SummitEvent.php b/app/Models/Foundation/Summit/Events/SummitEvent.php index 9fdf3e9d..d3a22036 100644 --- a/app/Models/Foundation/Summit/Events/SummitEvent.php +++ b/app/Models/Foundation/Summit/Events/SummitEvent.php @@ -648,17 +648,6 @@ class SummitEvent extends SilverstripeBaseModel if ($end_date < $start_date) throw new ValidationException('start datetime must be greather or equal than end datetime!'); - if (!$summit->isEventInsideSummitDuration($this)) - throw new ValidationException - ( - sprintf - ( - 'start/end datetime must be between summit start/end datetime! (%s - %s)', - $summit->getLocalBeginDate()->format('Y-m-d H:i:s'), - $summit->getLocalEndDate()->format('Y-m-d H:i:s') - ) - ); - $this->published = true; $this->published_date = new DateTime(); } diff --git a/app/Models/Foundation/Summit/Repositories/ISpeakerRepository.php b/app/Models/Foundation/Summit/Repositories/ISpeakerRepository.php index 10728fb0..09ba524c 100644 --- a/app/Models/Foundation/Summit/Repositories/ISpeakerRepository.php +++ b/app/Models/Foundation/Summit/Repositories/ISpeakerRepository.php @@ -52,4 +52,10 @@ interface ISpeakerRepository extends IBaseRepository * @return PresentationSpeaker|null */ public function getByFullName(string $fullname):?PresentationSpeaker; + + /** + * @param string $email + * @return PresentationSpeaker|null + */ + public function getByEmail(string $email):?PresentationSpeaker; } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Speakers/PresentationSpeaker.php b/app/Models/Foundation/Summit/Speakers/PresentationSpeaker.php index 49791529..4780d92c 100644 --- a/app/Models/Foundation/Summit/Speakers/PresentationSpeaker.php +++ b/app/Models/Foundation/Summit/Speakers/PresentationSpeaker.php @@ -147,7 +147,7 @@ class PresentationSpeaker extends SilverstripeBaseModel private $promo_codes; /** - * @ORM\ManyToMany(targetEntity="models\summit\Presentation", mappedBy="speakers") + * @ORM\ManyToMany(targetEntity="models\summit\Presentation", mappedBy="speakers", cascade={"persist"}) * @var Presentation[] */ private $presentations; @@ -1092,12 +1092,13 @@ class PresentationSpeaker extends SilverstripeBaseModel } /** + * @param string $separator * @return string */ - public function getFullName(){ + public function getFullName(string $separator=', '){ $fullname = $this->first_name; if(!empty($this->last_name)){ - if(!empty($fullname)) $fullname .= ', '; + if(!empty($fullname)) $fullname .= $separator; $fullname .= $this->last_name; } return $fullname; diff --git a/app/Models/Foundation/Summit/Summit.php b/app/Models/Foundation/Summit/Summit.php index b24c2ebf..90b6cd27 100644 --- a/app/Models/Foundation/Summit/Summit.php +++ b/app/Models/Foundation/Summit/Summit.php @@ -1125,6 +1125,18 @@ class Summit extends SilverstripeBaseModel return $event === false ? null : $event; } + /** + * @param int $id + * @return SummitEvent|null + */ + public function getEventById(int $id):?SummitEvent{ + + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', $id)); + $event = $this->events->matching($criteria)->first(); + return $event === false ? null : $event; + } + /** * @param SummitEvent $event */ diff --git a/app/Repositories/Summit/DoctrineSpeakerRepository.php b/app/Repositories/Summit/DoctrineSpeakerRepository.php index b4f59c2f..0eae38e1 100644 --- a/app/Repositories/Summit/DoctrineSpeakerRepository.php +++ b/app/Repositories/Summit/DoctrineSpeakerRepository.php @@ -759,6 +759,27 @@ SQL; ->getOneOrNullResult(); } + /** + * @param string $email + * @return PresentationSpeaker|null + */ + public function getByEmail(string $email):?PresentationSpeaker + { + return $this->getEntityManager() + ->createQueryBuilder() + ->select("s") + ->from(PresentationSpeaker::class, "s") + ->leftJoin("s.member", "m") + ->leftJoin("s.registration_request", "r") + ->where("m.email = :email1 or r.email = :email2") + ->setParameter("email1", trim($email)) + ->setParameter("email2", trim($email)) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } + + /** * @param string $fullname * @return PresentationSpeaker|null diff --git a/app/Services/Model/ISpeakerService.php b/app/Services/Model/ISpeakerService.php index e964e8c8..ee3b9b1c 100644 --- a/app/Services/Model/ISpeakerService.php +++ b/app/Services/Model/ISpeakerService.php @@ -38,10 +38,11 @@ interface ISpeakerService /** * @param array $data * @param null|Member $creator + * @param bool $send_email * @return PresentationSpeaker * @throws ValidationException */ - public function addSpeaker(array $data, ?Member $creator = null); + public function addSpeaker(array $data, ?Member $creator = null, $send_email = true); /** * @param Summit $summit diff --git a/app/Services/Model/ISummitService.php b/app/Services/Model/ISummitService.php index 80033a3f..6149dcd6 100644 --- a/app/Services/Model/ISummitService.php +++ b/app/Services/Model/ISummitService.php @@ -498,4 +498,20 @@ interface ISummitService * @throws EntityNotFoundException */ public function advanceSummit(int $summit_id, int $days, bool $negative = false, $check_summit_ends = true):void; + + /** + * @param Summit $summit + * @param UploadedFile $csv_file + * @param array $payload + */ + public function importEventData(Summit $summit, UploadedFile $csv_file, array $payload):void; + + /** + * @param int $summit_id + * @param string $filename + * @param bool $send_speaker_email + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function processEventData(int $summit_id, string $filename, bool $send_speaker_email):void; } \ No newline at end of file diff --git a/app/Services/Model/Imp/MemberService.php b/app/Services/Model/Imp/MemberService.php index 509c9d1c..e877a045 100644 --- a/app/Services/Model/Imp/MemberService.php +++ b/app/Services/Model/Imp/MemberService.php @@ -29,6 +29,7 @@ use models\main\IOrganizationRepository; use models\main\Member; use DateTime; use models\main\Organization; +use models\summit\ISpeakerRegistrationRequestRepository; /** * Class MemberService @@ -71,6 +72,11 @@ final class MemberService */ private $external_user_api; + /** + * @var ISpeakerRegistrationRequestRepository + */ + private $speaker_registration_request_repository; + /** * MemberService constructor. * @param IMemberRepository $member_repository @@ -79,6 +85,7 @@ final class MemberService * @param IGroupRepository $group_repository * @param ICacheService $cache_service * @param IExternalUserApi $external_user_api + * @param ISpeakerRegistrationRequestRepository $speaker_registration_request_repository * @param ITransactionService $tx_service */ public function __construct @@ -89,6 +96,7 @@ final class MemberService IGroupRepository $group_repository, ICacheService $cache_service, IExternalUserApi $external_user_api, + ISpeakerRegistrationRequestRepository $speaker_registration_request_repository, ITransactionService $tx_service ) { @@ -99,6 +107,7 @@ final class MemberService $this->group_repository = $group_repository; $this->cache_service = $cache_service; $this->external_user_api = $external_user_api; + $this->speaker_registration_request_repository = $speaker_registration_request_repository; } /** @@ -319,6 +328,18 @@ final class MemberService } $this->synchronizeGroups($member, $user_data['groups']); + // check speaker registration request by email and no member set + Log::debug(sprintf("MemberService::registerExternalUserById trying to get former registration request by email %s", $email)); + $request = $this->speaker_registration_request_repository->getByEmail($email); + if(!is_null($request)){ + Log::debug(sprintf("MemberService::registerExternalUserById got former registration request by email %s", $email)); + $speaker = $request->getSpeaker(); + if(!is_null($speaker)) + if(!$speaker->hasMember()) { + Log::debug(sprintf("MemberService::registerExternalUserById setting current member to speaker %s", $speaker->getId())); + $speaker->setMember($member); + } + } if($is_new) Event::fire(new NewMember($member->getId())); diff --git a/app/Services/Model/Imp/SpeakerService.php b/app/Services/Model/Imp/SpeakerService.php index ddcc95b6..b4d4d8d5 100644 --- a/app/Services/Model/Imp/SpeakerService.php +++ b/app/Services/Model/Imp/SpeakerService.php @@ -163,13 +163,14 @@ final class SpeakerService /** * @param array $data * @param null|Member $creator + * @param bool $send_email * @return PresentationSpeaker * @throws ValidationException */ - public function addSpeaker(array $data, ?Member $creator = null) + public function addSpeaker(array $data, ?Member $creator = null, $send_email = true) { - return $this->tx_service->transaction(function () use ($data, $creator) { + return $this->tx_service->transaction(function () use ($data, $creator, $send_email) { $member_id = intval($data['member_id'] ?? 0); @@ -251,7 +252,7 @@ final class SpeakerService $this->speaker_repository->add($this->updateSpeakerRelations($speaker, $data)); // only send the email if we dont have a former registration request - if(is_null($formerRegistrationRequest)) + if(is_null($formerRegistrationRequest) && $send_email) SpeakerCreationEmail::dispatch($speaker); if(!is_null($formerRegistrationRequest)){ diff --git a/app/Services/Model/Imp/SummitService.php b/app/Services/Model/Imp/SummitService.php index 7c31c324..86d14c55 100644 --- a/app/Services/Model/Imp/SummitService.php +++ b/app/Services/Model/Imp/SummitService.php @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - +use League\Csv\Reader; use App\Events\MyFavoritesAdd; use App\Events\MyFavoritesRemove; use App\Events\MyScheduleAdd; @@ -21,7 +21,9 @@ use App\Events\RSVPUpdated; use App\Events\SummitDeleted; use App\Events\SummitUpdated; use App\Http\Utils\IFileUploader; +use App\Jobs\Emails\PresentationSubmissions\ImportEventSpeakerEmail; use App\Jobs\Emails\Schedule\ShareEventEmail; +use App\Jobs\ProcessEventDataImport; use App\Models\Foundation\Summit\Factories\SummitEventFeedbackFactory; use App\Models\Foundation\Summit\Factories\SummitFactory; use App\Models\Foundation\Summit\Factories\SummitRSVPFactory; @@ -30,11 +32,15 @@ use App\Models\Utils\IntervalParser; use App\Permissions\IPermissionsManager; use App\Services\Model\AbstractService; use App\Services\Model\IFolderService; +use App\Services\Model\IMemberService; +use App\Services\Utils\CSVReader; use CalDAVClient\Facade\Utils\ICalTimeZoneBuilder; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use GuzzleHttp\Exception\ClientException; use Illuminate\Http\UploadedFile; +use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Storage; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; use models\main\File; @@ -60,6 +66,7 @@ use models\summit\ISummitEntityEventRepository; use models\summit\ISummitEventRepository; use models\summit\ISummitRepository; use models\summit\Presentation; +use models\summit\PresentationSpeaker; use models\summit\PresentationType; use models\summit\RSVP; use models\summit\Summit; @@ -190,6 +197,16 @@ final class SummitService extends AbstractService implements ISummitService */ private $resource_server_context; + /** + * @var ISpeakerService ISpeakerService + */ + private $speaker_service; + + /** + * @var IMemberService + */ + private $member_service; + /** * SummitService constructor. * @param ISummitRepository $summit_repository @@ -210,6 +227,8 @@ final class SummitService extends AbstractService implements ISummitService * @param IPermissionsManager $permissions_manager * @param IFileUploader $file_uploader * @param IResourceServerContext $resource_server_context + * @param ISpeakerService $speaker_service + * @param IMemberService $member_service * @param ITransactionService $tx_service */ public function __construct @@ -232,6 +251,8 @@ final class SummitService extends AbstractService implements ISummitService IPermissionsManager $permissions_manager, IFileUploader $file_uploader, IResourceServerContext $resource_server_context, + ISpeakerService $speaker_service, + IMemberService $member_service, ITransactionService $tx_service ) { @@ -254,6 +275,8 @@ final class SummitService extends AbstractService implements ISummitService $this->permissions_manager = $permissions_manager; $this->file_uploader = $file_uploader; $this->resource_server_context = $resource_server_context; + $this->speaker_service = $speaker_service; + $this->member_service = $member_service; } /** @@ -632,19 +655,6 @@ final class SummitService extends AbstractService implements ISummitService // set local time from UTC $event->setStartDate($start_datetime); $event->setEndDate($end_datetime); - - if (!$summit->isEventInsideSummitDuration($event)) - throw new ValidationException - ( - sprintf - ( - "event start/end (%s - %s) does not match with summit start/end (%s - %s)", - $event->getLocalStartDate()->format('Y-m-d H:i:s'), - $event->getLocalEndDate()->format('Y-m-d H:i:s'), - $summit->getLocalBeginDate()->format('Y-m-d H:i:s'), - $summit->getLocalEndDate()->format('Y-m-d H:i:s') - ) - ); } return $event; @@ -2121,7 +2131,7 @@ final class SummitService extends AbstractService implements ISummitService { return $this->tx_service->transaction(function () use ($summit_id, $file, $max_file_size) { - $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'svg','jfif']; + $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'svg', 'jfif']; $summit = $this->summit_repository->getById($summit_id); @@ -2591,19 +2601,19 @@ final class SummitService extends AbstractService implements ISummitService * @param bool $check_summit_ends * @throws Exception */ - public function advanceSummit(int $summit_id, int $days, bool $negative = false, $check_summit_ends = true):void + public function advanceSummit(int $summit_id, int $days, bool $negative = false, $check_summit_ends = true): void { $interval = new DateInterval(sprintf("P%sD", $days)); Log::debug(sprintf("SummitService::advanceSummit summit_id %s days %s negative %s check_summit_ends %s", $summit_id, $days, $negative, $check_summit_ends)); - $events_ids = $this->tx_service->transaction(function () use ($summit_id, $interval, $negative, $check_summit_ends) { + $events_ids = $this->tx_service->transaction(function () use ($summit_id, $interval, $negative, $check_summit_ends) { $summit = $this->summit_repository->getByIdExclusiveLock($summit_id); - if(is_null($summit) || !$summit instanceof Summit) + if (is_null($summit) || !$summit instanceof Summit) throw new EntityNotFoundException("Summit not found"); - if($check_summit_ends && !$summit->isEnded()) { + if ($check_summit_ends && !$summit->isEnded()) { Log::debug(sprintf("SummitService::advanceSummit summit %s has not ended !.", $summit_id)); return []; } @@ -2614,10 +2624,9 @@ final class SummitService extends AbstractService implements ISummitService if (!is_null($summitBeginDate)) { Log::debug(sprintf("SummitService::advanceSummit Current Summit begin date for summit %s is %s", $summit_id, $summitBeginDate->format("Ymd His"))); - if($negative){ + if ($negative) { $summit->setRawBeginDate(clone $summitBeginDate->sub($interval)); - } - else { + } else { $summit->setRawBeginDate(clone $summitBeginDate->add($interval)); } Log::debug(sprintf("SummitService::advanceSummit New Summit begin date for summit %s is %s", $summit_id, $summit->getBeginDate()->format("Ymd His"))); @@ -2625,10 +2634,9 @@ final class SummitService extends AbstractService implements ISummitService if (!is_null($summitEndDate)) { Log::debug(sprintf("SummitService::advanceSummit Current Summit end date for summit %s is %s", $summit_id, $summitEndDate->format("Ymd His"))); - if($negative) { + if ($negative) { $summit->setRawEndDate(clone $summitEndDate->sub($interval)); - } - else{ + } else { $summit->setRawEndDate(clone $summitEndDate->add($interval)); } Log::debug(sprintf("SummitService::advanceSummit New Summit end date for summit %s is %s", $summit_id, $summit->getEndDate()->format("Ymd His"))); @@ -2639,18 +2647,17 @@ final class SummitService extends AbstractService implements ISummitService $summitRegistrationBeginDate = $summit->getRegistrationBeginDate(); $summitRegistrationEndDate = $summit->getRegistrationEndDate(); - if(!is_null($summitRegistrationBeginDate)){ + if (!is_null($summitRegistrationBeginDate)) { Log::debug(sprintf("SummitService::advanceSummit Current Summit registration begin date for summit %s is %s", $summit_id, $summitRegistrationBeginDate->format("Ymd His"))); - if($negative) { + if ($negative) { $summit->setRawRegistrationBeginDate(clone $summitRegistrationBeginDate->add($interval)); - } - else { + } else { $summit->setRawRegistrationBeginDate(clone $summitRegistrationBeginDate->sub($interval)); } Log::debug(sprintf("SummitService::advanceSummit New Summit registration begin date for summit %s is %s", $summit_id, $summit->getRegistrationBeginDate()->format("Ymd His"))); } - if(!is_null($summitRegistrationEndDate)){ + if (!is_null($summitRegistrationEndDate)) { Log::debug(sprintf("SummitService::advanceSummit Current Summit registration end date for summit %s is %s", $summit_id, $summitRegistrationEndDate->format("Ymd His"))); $summit->setRawRegistrationEndDate(clone $summitRegistrationEndDate->add($interval)); Log::debug(sprintf("SummitService::advanceSummit New Summit registration end date for summit %s is %s", $summit_id, $summit->getRegistrationEndDate()->format("Ymd His"))); @@ -2659,51 +2666,46 @@ final class SummitService extends AbstractService implements ISummitService // random dates $summitReassignTicketTillDate = $summit->getReassignTicketTillDate(); - if(!is_null($summitReassignTicketTillDate)){ - if($negative){ + if (!is_null($summitReassignTicketTillDate)) { + if ($negative) { $summit->setRawReassignTicketTillDate(clone $summitReassignTicketTillDate->sub($interval)); - } - else { + } else { $summit->setRawReassignTicketTillDate(clone $summitReassignTicketTillDate->add($interval)); } } $summitStartShowingVenuesDate = $summit->getStartShowingVenuesDate(); - if(!is_null($summitStartShowingVenuesDate)){ - if($negative){ + if (!is_null($summitStartShowingVenuesDate)) { + if ($negative) { $summit->setRawStartShowingVenuesDate(clone $summitStartShowingVenuesDate->sub($interval)); - } - else { + } else { $summit->setRawStartShowingVenuesDate(clone $summitStartShowingVenuesDate->add($interval)); } } $summitScheduleDefaultStartDate = $summit->getScheduleDefaultStartDate(); - if(!is_null($summitScheduleDefaultStartDate)){ - if($negative){ + if (!is_null($summitScheduleDefaultStartDate)) { + if ($negative) { $summit->setRawScheduleDefaultStartDate(clone $summitScheduleDefaultStartDate->sub($interval)); - } - else { + } else { $summit->setRawScheduleDefaultStartDate(clone $summitScheduleDefaultStartDate->add($interval)); } } $summitBeginAllowBookingDate = $summit->getBeginAllowBookingDate(); - if(!is_null($summitBeginAllowBookingDate)){ - if($negative) { + if (!is_null($summitBeginAllowBookingDate)) { + if ($negative) { $summit->setRawBeginAllowBookingDate(clone $summitBeginAllowBookingDate->sub($interval)); - } - else{ + } else { $summit->setRawBeginAllowBookingDate(clone $summitBeginAllowBookingDate->add($interval)); } } $summitEndAllowBookingDate = $summit->getEndAllowBookingDate(); - if(!is_null($summitEndAllowBookingDate)){ - if($negative) { + if (!is_null($summitEndAllowBookingDate)) { + if ($negative) { $summit->setRawEndAllowBookingDate(clone $summitEndAllowBookingDate->sub($interval)); - } - else{ + } else { $summit->setRawEndAllowBookingDate(clone $summitEndAllowBookingDate->add($interval)); } @@ -2711,37 +2713,35 @@ final class SummitService extends AbstractService implements ISummitService // schedule $event_ids = []; - foreach($summit->getPublishedEvents() as $event){ - if(!$event instanceof SummitEvent) continue; + foreach ($summit->getPublishedEvents() as $event) { + if (!$event instanceof SummitEvent) continue; $event_ids[] = $event->getId(); } return $event_ids; }); - foreach ($events_ids as $event_id){ - $this->tx_service->transaction(function() use($summit_id, $event_id, $interval, $negative){ + foreach ($events_ids as $event_id) { + $this->tx_service->transaction(function () use ($summit_id, $event_id, $interval, $negative) { $event = $this->event_repository->getByIdExclusiveLock($event_id); $eventBeginDate = $event->getStartDate(); $eventEndDate = $event->getEndDate(); - if(is_null($eventBeginDate) || is_null($eventEndDate)){ + if (is_null($eventBeginDate) || is_null($eventEndDate)) { Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s ( has not set dates but is published!), skipping it", $summit_id, $event->getId())); return; } Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s current start date %s", $summit_id, $event->getId(), $eventBeginDate->format("Ymd His"))); - if($negative){ + if ($negative) { $event->setRawStartDate(clone $eventBeginDate->sub($interval)); - } - else { + } else { $event->setRawStartDate(clone $eventBeginDate->add($interval)); } Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s new start date %s", $summit_id, $event->getId(), $event->getStartDate()->format("Ymd His"))); Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s current end date %s", $summit_id, $event->getId(), $eventEndDate->format("Ymd His"))); - if($negative) { + if ($negative) { $event->setRawEndDate(clone $eventEndDate->sub($interval)); - } - else{ + } else { $event->setRawEndDate(clone $eventEndDate->add($interval)); } Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s new end date %s", $summit_id, $event->getId(), $event->getEndDate()->format("Ymd His"))); @@ -2749,4 +2749,362 @@ final class SummitService extends AbstractService implements ISummitService }); } } + + /** + * @param Summit $summit + * @param UploadedFile $csv_file + * @param array $payload + * @throws ValidationException + */ + public function importEventData(Summit $summit, UploadedFile $csv_file, array $payload): void + { + + Log::debug(sprintf("SummitService::importEventData - summit %s", $summit->getId())); + + $allowed_extensions = ['txt']; + + if (!in_array($csv_file->extension(), $allowed_extensions)) { + throw new ValidationException("file does not has a valid extension ('csv')."); + } + + $real_path = $csv_file->getRealPath(); + $filename = pathinfo($real_path); + $filename = $filename['filename'] ?? sprintf("file%s", time()); + $basename = sprintf("%s_%s.csv", $filename, time()); + $filename = $csv_file->storeAs(sprintf("%s/events_imports", sys_get_temp_dir()), $basename); + $csv_data = \Illuminate\Support\Facades\File::get($real_path); + if (empty($csv_data)) + throw new ValidationException("file content is empty!"); + + $csv = Reader::createFromString($csv_data); + $csv->setHeaderOffset(0); + + $header = $csv->getHeader(); //returns the CSV header record + + // check needed columns (headers names) + /* + columns ( min) + * title + * abstract + * type_id (int) or type (string type name) + * track_id (int) or track ( string track name) + */ + + // validate format with col names + if (!in_array("title", $header)) + throw new ValidationException('title column missing'); + + if (!in_array("abstract", $header)) + throw new ValidationException('abstract column missing'); + + $type_data_present = in_array("type_id", $header)|| + in_array("type", $header); + + if (!$type_data_present) { + throw new ValidationException('type_id / type column missing'); + } + + $track_present = in_array("track_id", $header)|| + in_array("track", $header); + + if (!$track_present) { + throw new ValidationException('track_id / track column missing'); + } + + ProcessEventDataImport::dispatch($summit->getId(), $filename, $payload); + } + + /** + * @param int $summit_id + * @param string $filename + * @param bool $send_speaker_email + * @throws ValidationException + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function processEventData(int $summit_id, string $filename, bool $send_speaker_email): void + { + Log::debug(sprintf("SummitService::processEventData summit %s filename %s", $summit_id, $filename)); + + if (!Storage::disk('local')->exists($filename)) { + throw new ValidationException(sprintf("file %s does not exists.", $filename)); + } + + $csv_data = Storage::disk('local')->get($filename); + + $summit = $this->tx_service->transaction(function () use ($summit_id) { + $summit = $this->summit_repository->getById($summit_id); + if (is_null($summit) || !$summit instanceof Summit) + throw new EntityNotFoundException(sprintf("summit %s does not exists.", $summit_id)); + return $summit; + }); + + $csv = Reader::createFromString($csv_data); + $csv->setHeaderOffset(0); + + $header = $csv->getHeader(); //returns the CSV header record + $records = $csv->getRecords(); + + foreach ($records as $idx => $row) { + $event = $this->tx_service->transaction(function () use ($summit, $row) { + + Log::debug(sprintf("SummitService::processEventData processing row %s", json_encode($row))); + + $title = trim($row['title']); + $abstract = trim($row['abstract']); + // event type + $event_type = null; + if (isset($row['type_id'])) + $event_type = $summit->getEventType(intval($row['type_id'])); + if (isset($row['type'])) + $event_type = $summit->getEventTypeByType($row['type']); + + if (is_null($event_type)) + throw new EntityNotFoundException("event type not found."); + + // track + $track = null; + if (isset($row['track_id'])) + $track = $summit->getPresentationCategory(intval($row['track_id'])); + if (isset($row['track'])) + $track = $summit->getPresentationCategoryByTitle($row['track']); + + if (is_null($track)) + throw new EntityNotFoundException("track not found."); + + $event = null; + if(isset($row['id']) && !empty($row['id'])){ + Log::debug(sprintf("SummitService::processEventData trying to get event %s", $row['id'])); + $event = $summit->getEventById(intval($row['id'])); + } + if(is_null($event)) + $event = SummitEventFactory::build($event_type, $summit); + + // main data + + $event->setTitle(html_entity_decode($title)); + $event->setAbstract(html_entity_decode($abstract)); + if (isset($row['social_summary'])) + $event->setSocialSummary($row['social_summary']); + + if (isset($row['allow_feedback'])) + $event->setAllowFeedBack(boolval($row['allow_feedback'])); + + $event->setType($event_type); + $event->setCategory($track); + + if(isset($row['location']) && !empty($row['location'])){ + $location = $summit->getLocation(intval($row['location'])); + if(is_null($location)) + $location = $summit->getLocationByName(trim($row['location'])); + if(is_null($location)) + throw new EntityNotFoundException("location not found."); + + $event->setLocation($location); + } + if (isset($row['start_date']) && !empty($row['start_date']) && isset($row['end_date']) && !empty($row['end_date'])){ + Log::debug + ( + sprintf + ( + "SummitService::processEventData publishing event start_date %s end_date %s", + $row['start_date'], + $row['end_date'] + ) + ); + $start_date = DateTime::createFromFormat('Y-m-d H:i:s', $row['start_date'], $summit->getTimeZone()); + $end_date = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_date'], $summit->getTimeZone()); + + // set local time from UTC + $event->setStartDate($start_date); + $event->setEndDate($end_date); + } + + // tags + + if (isset($row['tags'])) { + $tags = explode('|', $row['tags']); + $event->clearTags(); + foreach ($tags as $val) { + $tag = $this->tag_repository->getByTag($val); + if ($tag == null) { + Log::debug(sprintf("SummitService::processEventData creating tag %s", $val)); + $tag = new Tag($val); + } + $event->addTag($tag); + } + } + + // sponsors + + $sponsors = ($event_type->isUseSponsors() && isset($row['sponsors'])) ? + $row['sponsors'] : ''; + $sponsors = explode('|', $sponsors); + if ($event_type->isAreSponsorsMandatory() && count($sponsors) == 0) { + throw new ValidationException('sponsors are mandatory!'); + } + + if (isset($row['sponsors'])) { + $event->clearSponsors(); + foreach ($sponsors as $sponsor_name) { + $sponsor = $this->company_repository->getByName(trim($sponsor_name)); + if (is_null($sponsor)) throw new EntityNotFoundException(sprintf('sponsor %s', $sponsor_name)); + $event->addSponsor($sponsor); + } + } + + if ($event instanceof Presentation) { + + if (isset($row['to_record'])) + $event->setToRecord(boolval($row['to_record'])); + + if (isset($row['attendees_expected_learnt'])) + $event->setAttendeesExpectedLearnt($row['attendees_expected_learnt']); + + if (isset($row['level'])) + $event->setLevel($row['level']); + + if (isset($row['problem_addressed'])) + $event->setProblemAddressed($row['problem_addressed']); + + // speakers + + if ($event_type instanceof PresentationType && $event_type->isUseSpeakers()) { + + $speakers = isset($row['speakers']) ? + $row['speakers'] : ''; + $speakers = explode('|', $speakers); + + $speakers_names = []; + if(isset($row["speakers_names"])){ + $speakers_names = isset($row['speakers_names']) ? + $row['speakers_names'] : ''; + $speakers_names = explode('|', $speakers_names); + } + if(count($speakers_names) == 0 ){ + $speakers_names = $speakers; + } + + if(count($speakers_names) != count($speakers)) + throw new ValidationException("count of speakers and speakers_name should match."); + + if ($event_type->isAreSpeakersMandatory() && count($speakers) == 0) { + throw new ValidationException('speakers are mandatory!'); + } + + if (count($speakers) > 0) { + $event->clearSpeakers(); + foreach ($speakers as $idx => $speaker_email) { + $speaker_full_name = $speakers_names[$idx]; + $speaker_full_name_comps = explode(" ", $speaker_full_name, 2); + $speaker_first_name = trim($speaker_full_name_comps[0]); + $speaker_last_name = null; + if(count($speaker_full_name_comps) > 1){ + $speaker_last_name = trim($speaker_full_name_comps[1]); + } + if(empty($speaker_last_name)) + $speaker_last_name = $speaker_first_name; + Log::debug(sprintf("SummitService::processEventData processing speaker email %s speaker fullname %s", $speaker_email, $speaker_full_name)); + $speaker = $this->speaker_repository->getByEmail(trim($speaker_email)); + if (is_null($speaker)) { + Log::debug(sprintf("SummitService::processEventData speaker %s fname %s lname %s does not exists", $speaker_email, $speaker_first_name, $speaker_last_name)); + $speaker = $this->speaker_service->addSpeaker([ + 'first_name' => $speaker_first_name, + 'last_name' => $speaker_last_name, + 'email' => $speaker_email + ], null, false); + } + + $event->addSpeaker($speaker); + } + } + } + + // moderator + + if ($event_type instanceof PresentationType && $event_type->isUseModerator()) { + $moderator_email = isset($row['moderator']) ? trim($row['moderator']) : null; + + if ($event_type->isModeratorMandatory() && empty($moderator_email)) { + throw new ValidationException('moderator is mandatory!'); + } + Log::debug(sprintf("SummitService::processEventData processing moderator %s", $moderator_email)); + $moderator = $this->speaker_repository->getByEmail($moderator_email); + if (is_null($moderator)) { + Log::debug(sprintf("SummitService::processEventData moderator %s does not exists", $moderator_email)); + $moderator = $this->speaker_service->addSpeaker(['email' => $moderator_email], null, false); + } + + $event->setModerator($moderator); + } + + // selection plan + + if (isset($row['selection_plan'])) { + $selection_plan = $summit->getSelectionPlanByName($row['selection_plan']); + if (!is_null($selection_plan)) { + Log::debug(sprintf("SummitService::processEventData processing selection plan %s", $row['selection_plan'])); + $track = $event->getCategory(); + if (!$selection_plan->hasTrack($track)) { + throw new ValidationException(sprintf("Track %s (%s) does not belongs to Selection Plan %s (%s)", $track->getTitle(), $track->getId(), $selection_plan->getName(), $selection_plan->getId())); + } + $event->setSelectionPlan($selection_plan); + } + } + } + + if (isset($row['is_published'])) { + $is_published = boolval($row['is_published']); + if ($is_published) { + if (!isset($row['start_date'])) throw new ValidationException("start_date is required."); + if (!isset($row['end_date'])) throw new ValidationException("end_date is required."); + if(!$event->isPublished()) + $event->publish(); + } + else{ + $event->unPublish(); + } + } + + $summit->addEvent($event); + + return $event; + }); + + if($send_speaker_email && $event instanceof Presentation){ + foreach($event->getSpeakers() as $speaker) + $this->tx_service->transaction(function () use ($speaker, $event) { + $setPasswordLink = null; + if($speaker instanceof PresentationSpeaker) { + if(!$speaker->hasMember()) { + Log::debug(sprintf("SummitService::processEventData speaker %s has not member set, checking at idp", $speaker->getEmail())); + $user = $this->member_service->checkExternalUser($speaker->getEmail()); + if(is_null($user)){ + + // user does not exist at idp so we need to generate a registration request + // and create the magic links to complete the registration request + Log::debug(sprintf("SummitService::processEventData speaker %s user not found at idp, creating registration request", $speaker->getEmail())); + $userRegistrationRequest = $this->member_service->emitRegistrationRequest + ( + $speaker->getEmail(), + $speaker->getFirstName(), + $speaker->getLastName() + ); + + $setPasswordLink = $userRegistrationRequest['set_password_link']; + $speaker_management_base_url = Config::get('cfp.base_url'); + + $setPasswordLink = sprintf( + "%s?client_id=%s&redirect_uri=%s", + $setPasswordLink, + Config::get("cfp.client_id"), + sprintf("%s/app/profile", $speaker_management_base_url) + ); + } + } + } + ImportEventSpeakerEmail::dispatch($event, $speaker, $setPasswordLink); + }); + } + } + } } \ No newline at end of file diff --git a/app/Services/Utils/CSVReader.php b/app/Services/Utils/CSVReader.php index d199b29a..d709a7b0 100644 --- a/app/Services/Utils/CSVReader.php +++ b/app/Services/Utils/CSVReader.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use Illuminate\Support\Facades\Log; use Iterator; /** * Class CSVReader @@ -45,12 +47,16 @@ final class CSVReader implements Iterator { */ public static function buildFrom(string $content):CSVReader { + Log::debug(sprintf("CSVReader::buildFrom content %s", $content)); $data = str_getcsv($content,"\n" ); + Log::debug(sprintf("CSVReader::buildFrom data %s", json_encode($data))); $idx = 0; - $header = []; + $header = []; + $lines = []; foreach($data as $row) { $row = str_getcsv($row, ","); + Log::debug(sprintf("CSVReader::buildFrom row %s", json_encode($row))); ++$idx; if($idx === 1) { diff --git a/composer.json b/composer.json index ee66ac9b..6c98653f 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "laravel-doctrine/orm": "1.4.*", "laravel/framework": "5.6.*", "laravel/tinker": "^1.0", + "league/csv": "^9.6", "league/oauth2-client": "^2.4", "php-amqplib/php-amqplib": "^2.11", "php-opencloud/openstack": "dev-master", diff --git a/composer.lock b/composer.lock index 664e40b0..7896978d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "dd60518aeb8ca6000e03c1ac89053208", + "content-hash": "a441f3fcf95ec732067dc7b61c451a5b", "packages": [ { "name": "bacon/bacon-qr-code", @@ -2576,6 +2576,78 @@ ], "time": "2019-08-07T15:10:45+00:00" }, + { + "name": "league/csv", + "version": "9.6.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/csv.git", + "reference": "634322df4aed210fdfbb7c94e434dc860da733d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/634322df4aed210fdfbb7c94e434dc860da733d9", + "reference": "634322df4aed210fdfbb7c94e434dc860da733d9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": "^7.2.5" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12.0", + "phpstan/phpstan-phpunit": "^0.12.0", + "phpstan/phpstan-strict-rules": "^0.12.0", + "phpunit/phpunit": "^8.5" + }, + "suggest": { + "ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes", + "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Csv\\": "src" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://github.com/nyamsprod/", + "role": "Developer" + } + ], + "description": "CSV data manipulation made easy in PHP", + "homepage": "http://csv.thephpleague.com", + "keywords": [ + "convert", + "csv", + "export", + "filter", + "import", + "read", + "transform", + "write" + ], + "time": "2020-09-05T08:40:12+00:00" + }, { "name": "league/flysystem", "version": "1.0.69", @@ -3322,12 +3394,12 @@ "version": "v1.0.4", "source": { "type": "git", - "url": "https://github.com/nrk/predis.git", + "url": "https://github.com/predis/predis.git", "reference": "9ead747663bb1b1ae017dfa0d152aca87792b42f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nrk/predis/zipball/9ead747663bb1b1ae017dfa0d152aca87792b42f", + "url": "https://api.github.com/repos/predis/predis/zipball/9ead747663bb1b1ae017dfa0d152aca87792b42f", "reference": "9ead747663bb1b1ae017dfa0d152aca87792b42f", "shasum": "" }, diff --git a/config/cfp.php b/config/cfp.php index 833fd31c..24ef205d 100644 --- a/config/cfp.php +++ b/config/cfp.php @@ -15,4 +15,5 @@ return [ 'base_url' => env('CFP_APP_BASE_URL', null), 'support_email' => env('CFP_SUPPORT_EMAIL', null), + 'client_id' => env('CFP_OAUTH2_CLIENT_ID', null), ]; \ No newline at end of file diff --git a/database/migrations/model/Version20200924203451.php b/database/migrations/model/Version20200924203451.php new file mode 100644 index 00000000..be38da11 --- /dev/null +++ b/database/migrations/model/Version20200924203451.php @@ -0,0 +1,66 @@ +getRepository(SummitEmailFlowType::class); + $flow = $repository->findOneBy([ + "name" => "Presentation Submissions" + ]); + + SummitEmailFlowTypeSeeder::createEventsTypes( + [ + [ + 'name' => ImportEventSpeakerEmail::EVENT_NAME, + 'slug' => ImportEventSpeakerEmail::EVENT_SLUG, + 'default_email_template' => ImportEventSpeakerEmail::DEFAULT_TEMPLATE + ] + ], + $flow + ); + + $em->persist($flow); + $em->flush(); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200924210244.php b/database/migrations/model/Version20200924210244.php new file mode 100644 index 00000000..c6976adf --- /dev/null +++ b/database/migrations/model/Version20200924210244.php @@ -0,0 +1,47 @@ +getRepository(Summit::class); + $summits = $repository->findAll(); + foreach($summits as $summit){ + $summit->seedDefaultEmailFlowEvents(); + $em->persist($summit); + } + $em->flush(); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index 3e8fc886..c99e0341 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -2256,7 +2256,7 @@ class ApiEndpointsSeeder extends Seeder IGroup::SummitAdministrators, ] ), - array( + [ 'name' => 'get-events-csv', 'route' => '/api/v1/summits/{id}/events/csv', 'http_method' => 'GET', @@ -2269,8 +2269,22 @@ class ApiEndpointsSeeder extends Seeder IGroup::Administrators, IGroup::SummitAdministrators, ] - ), - array( + ], + [ + 'name' => 'import-events-csv', + 'route' => '/api/v1/summits/{id}/events/csv', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteEventData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ 'name' => 'get-published-events', 'route' => '/api/v1/summits/{id}/events/published', 'http_method' => 'GET', @@ -2278,8 +2292,8 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadSummitData, $current_realm), sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], - ), - array( + ], + [ 'name' => 'get-published-events-tags', 'route' => '/api/v1/summits/{id}/events/all/published/tags', 'http_method' => 'GET', @@ -2287,8 +2301,8 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadSummitData, $current_realm), sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], - ), - array( + ], + [ 'name' => 'get-schedule-empty-spots', 'route' => '/api/v1/summits/{id}/events/published/empty-spots', 'http_method' => 'GET', @@ -2296,8 +2310,8 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadSummitData, $current_realm), sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], - ), - array( + ], + [ 'name' => 'get-unpublished-events', 'route' => '/api/v1/summits/{id}/events/unpublished', 'http_method' => 'GET', @@ -2305,8 +2319,8 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadSummitData, $current_realm), sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], - ), - array( + ], + [ 'name' => 'get-all-events', 'route' => '/api/v1/summits/events', 'http_method' => 'GET', @@ -2314,8 +2328,8 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadSummitData, $current_realm), sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], - ), - array( + ], + [ 'name' => 'get-all-published-events', 'route' => '/api/v1/summits/events/published', 'http_method' => 'GET', @@ -2323,7 +2337,7 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadSummitData, $current_realm), sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], - ), + ], [ 'name' => 'get-event', 'route' => '/api/v1/summits/{id}/events/{event_id}', diff --git a/database/seeds/SummitEmailFlowTypeSeeder.php b/database/seeds/SummitEmailFlowTypeSeeder.php index 683adcdb..fda19673 100644 --- a/database/seeds/SummitEmailFlowTypeSeeder.php +++ b/database/seeds/SummitEmailFlowTypeSeeder.php @@ -56,6 +56,7 @@ use App\Jobs\Emails\PresentationSubmissions\SelectionProcess\PresentationSpeaker use App\Jobs\Emails\PresentationSubmissions\SelectionProcess\PresentationSpeakerSelectionProcessAlternateOnlyEmail; use App\Jobs\Emails\PresentationSubmissions\SelectionProcess\PresentationSpeakerSelectionProcessAlternateRejectedEmail; use App\Jobs\Emails\PresentationSubmissions\SelectionProcess\PresentationSpeakerSelectionProcessRejectedEmail; +use App\Jobs\Emails\PresentationSubmissions\ImportEventSpeakerEmail; /** * Class SummitEmailFlowTypeSeeder */ @@ -277,6 +278,11 @@ final class SummitEmailFlowTypeSeeder extends Seeder 'slug' => PresentationSpeakerSelectionProcessRejectedEmail::EVENT_SLUG, 'default_email_template' => PresentationSpeakerSelectionProcessRejectedEmail::DEFAULT_TEMPLATE ], + [ + 'name' => ImportEventSpeakerEmail::EVENT_NAME, + 'slug' => ImportEventSpeakerEmail::EVENT_SLUG, + 'default_email_template' => ImportEventSpeakerEmail::DEFAULT_TEMPLATE + ], ], $flow); @@ -288,7 +294,7 @@ final class SummitEmailFlowTypeSeeder extends Seeder * @param array $payload * @param SummitEmailFlowType $flow */ - static private function createEventsTypes(array $payload , SummitEmailFlowType $flow){ + static public function createEventsTypes(array $payload , SummitEmailFlowType $flow){ foreach($payload as $definition){ $event_type = new SummitEmailEventFlowType(); $event_type->setName($definition['name']); diff --git a/tests/InsertSummitTestData.php b/tests/InsertSummitTestData.php index 82342f47..ffaae3fe 100644 --- a/tests/InsertSummitTestData.php +++ b/tests/InsertSummitTestData.php @@ -86,6 +86,16 @@ trait InsertSummitTestData $presentation_type = new PresentationType(); $presentation_type->setType('TEST PRESENTATION TYPE'); + $presentation_type->setMinSpeakers(1); + $presentation_type->setMaxSpeakers(3); + $presentation_type->setMinModerators(0); + $presentation_type->setMaxModerators(0); + $presentation_type->setUseSpeakers(true); + $presentation_type->setShouldBeAvailableOnCfp(true); + $presentation_type->setAreSpeakersMandatory(false); + $presentation_type->setUseModerator(false); + $presentation_type->setIsModeratorMandatory(false); + self::$summit->addEventType($presentation_type); self::$summit2 = new Summit(); @@ -103,6 +113,7 @@ trait InsertSummitTestData self::$summit2->setName("TEST SUMMIT2"); self::$mainVenue = new SummitVenue(); + self::$mainVenue->setName("TEST VENUE"); self::$mainVenue->setIsMain(true); self::$summit->addLocation(self::$mainVenue); diff --git a/tests/OAuth2SummitApiTest.php b/tests/OAuth2SummitApiTest.php index 4115eb35..7a96098c 100644 --- a/tests/OAuth2SummitApiTest.php +++ b/tests/OAuth2SummitApiTest.php @@ -31,7 +31,7 @@ final class OAuth2SummitApiTest extends ProtectedApiTest public function tearDown() { - self::clearTestData(); + // self::clearTestData(); Mockery::close(); } @@ -1619,4 +1619,50 @@ final class OAuth2SummitApiTest extends ProtectedApiTest return intval($video_id); } + public function testImportEventData(){ +/* $csv_content = << self::$summit->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "POST", + "OAuth2SummitEventsApiController@importEventData", + $params, + [ + 'send_speaker_email' => true, + ], + [], + [ + 'file' => $file, + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + } } \ No newline at end of file