From 8e67f5ae90e9f9b1ec1ca3a92cd6ee4a2ea267d9 Mon Sep 17 00:00:00 2001 From: Sebastian Marcet Date: Thu, 27 Jul 2017 00:33:37 -0300 Subject: [PATCH] External Calendar Sync Allows to synchronize member summit schedule with an enternal calendar provider: * Outlook * iCloud * Google the solution is composed of 2 services * member actions processor ( process actions like: create calendar, add event, remove event, remove calendar) * admin actions processsor ( process actions like: update event, delete event, update location, delete location) Change-Id: Ib8681bd2ea3b66b114fb676b4fa25fc15c65b46c --- .env.example | 8 +- Libs/Utils/IEncryptionService.php | 21 + ...inActionsCalendarSyncProcessingCommand.php | 77 + app/Console/Commands/Inspire.php | 33 - ...erActionsCalendarSyncProcessingCommand.php | 83 + app/Console/Kernel.php | 24 +- app/ModelSerializers/OwnMemberSerializer.php | 1 - .../SummitEventSerializer.php | 2 +- app/Models/Foundation/Main/Affiliation.php | 2 +- .../Main/ChatTeams/ChatTeamInvitation.php | 2 +- .../Main/ChatTeams/ChatTeamMember.php | 4 +- .../ChatTeamPushNotificationMessage.php | 2 +- app/Models/Foundation/Main/Member.php | 420 ++-- .../Main/PushNotificationMessage.php | 102 +- .../Foundation/Main/SummitMemberFavorite.php | 4 +- .../Foundation/Main/SummitMemberSchedule.php | 51 +- .../Summit/Attendees/SummitAttendee.php | 16 +- .../Summit/Attendees/SummitAttendeeTicket.php | 2 +- .../Summit/CalendarSync/CalendarSyncInfo.php | 186 ++ .../CalendarSync/CalendarSyncInfoCalDav.php | 150 ++ .../CalendarSync/CalendarSyncInfoOAuth2.php | 74 + .../CalendarSync/ScheduleCalendarSyncInfo.php | 280 +++ .../AbstractCalendarSyncWorkRequest.php | 110 + ...minScheduleSummitActionSyncWorkRequest.php | 49 + .../AdminSummitEventActionSyncWorkRequest.php | 52 + ...minSummitLocationActionSyncWorkRequest.php | 48 + ...darScheduleSummitActionSyncWorkRequest.php | 99 + ...entScheduleSummitActionSyncWorkRequest.php | 56 + ...berScheduleSummitActionSyncWorkRequest.php | 77 + .../Materials/PresentationMaterial.php | 2 +- .../Events/Presentations/Presentation.php | 4 +- .../Presentations/PresentationSpeaker.php | 1 + .../Foundation/Summit/Events/SummitEvent.php | 9 +- .../Locations/SummitGeoLocatedLocation.php | 149 +- .../Summit/Locations/SummitLocationImage.php | 4 +- ...tractCalendarSyncWorkRequestRepository.php | 49 + .../ICalendarSyncInfoRepository.php | 24 + .../IScheduleCalendarSyncInfoRepository.php | 39 + app/Models/Foundation/Summit/Summit.php | 33 +- app/Models/Foundation/Summit/SummitOwned.php | 2 +- .../ResourceServer/AccessTokenService.php | 32 +- app/Models/ResourceServer/Api.php | 2 +- app/Models/ResourceServer/ApiEndpoint.php | 2 +- app/Models/ResourceServer/ApiScope.php | 2 +- app/Repositories/RepositoriesProvider.php | 17 + ...tractCalendarSyncWorkRequestRepository.php | 149 ++ .../DoctrineCalendarSyncInfoRepository.php | 27 + ...rineScheduleCalendarSyncInfoRepository.php | 110 + .../DoctrineSummitNotificationRepository.php | 3 +- .../AbstractCalendarSyncRemoteFacade.php | 42 + .../CalendarSyncRemoteFacadeFactory.php | 56 + .../Exceptions/RateLimitExceededException.php | 23 + .../GoogleCalendarSyncRemoteFacade.php | 322 +++ .../ICalendarSyncRemoteFacade.php | 60 + .../ICloudCalendarSyncRemoteFacade.php | 325 +++ .../OutlookCalendarSyncRemoteFacade.php | 299 +++ app/Services/Apis/EventbriteAPI.php | 67 +- app/Services/Apis/FireBaseGCMApi.php | 10 +- .../AdminActionsCalendarSyncPreProcessor.php | 67 + ...inActionsCalendarSyncProcessingService.php | 166 ++ .../Model/AdminScheduleWorkQueueManager.php | 152 ++ ...inActionsCalendarSyncProcessingService.php | 26 + .../ICalendarSyncWorkRequestPreProcessor.php | 25 + .../ICalendarSyncWorkRequestQueueManager.php | 49 + ...erActionsCalendarSyncProcessingService.php | 27 + .../MemberActionsCalendarSyncPreProcessor.php | 79 + ...erActionsCalendarSyncProcessingService.php | 236 +++ .../Model/MemberScheduleWorkQueueManager.php | 212 ++ ...entActionSyncWorkRequestDeleteStrategy.php | 71 + ...entActionSyncWorkRequestUpdateStrategy.php | 71 + ...ionActionSyncWorkRequestDeleteStrategy.php | 71 + ...ionActionSyncWorkRequestUpdateStrategy.php | 72 + ...WorkRequestPreProcessorStrategyFactory.php | 126 ++ ...darSyncWorkRequestPreProcessorStrategy.php | 28 + ...WorkRequestPreProcessorStrategyFactory.php | 30 + ...SummitActionSyncWorkRequestAddStrategy.php | 36 + ...mitActionSyncWorkRequestDeleteStrategy.php | 99 + ...SummitActionSyncWorkRequestAddStrategy.php | 84 + ...mitActionSyncWorkRequestDeleteStrategy.php | 83 + ...mitActionSyncWorkRequestUpdateStrategy.php | 74 + app/Services/Model/SummitService.php | 106 +- app/Services/ServicesProvider.php | 60 + app/Services/Utils/EncryptionService.php | 48 + app/Services/Utils/Facades/Encryption.php | 27 + composer.json | 14 +- composer.lock | 1806 ++++++++++++----- config/app.php | 1 + config/apple_api.php | 17 + config/doctrine.php | 4 +- config/google_api.php | 19 + config/server.php | 2 + ...minActionsCalendarSyncPreProcessorTest.php | 170 ++ ...berActionsCalendarSyncPreProcessorTest.php | 308 +++ tests/OAuth2SummitApiTest.php | 53 +- tests/ProtectedApiTest.php | 2 +- 95 files changed, 7431 insertions(+), 989 deletions(-) create mode 100644 Libs/Utils/IEncryptionService.php create mode 100644 app/Console/Commands/AdminActionsCalendarSyncProcessingCommand.php delete mode 100644 app/Console/Commands/Inspire.php create mode 100644 app/Console/Commands/MemberActionsCalendarSyncProcessingCommand.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfo.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfoCalDav.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfoOAuth2.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/ScheduleCalendarSyncInfo.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/WorkQueue/AbstractCalendarSyncWorkRequest.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminScheduleSummitActionSyncWorkRequest.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminSummitEventActionSyncWorkRequest.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminSummitLocationActionSyncWorkRequest.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberCalendarScheduleSummitActionSyncWorkRequest.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberEventScheduleSummitActionSyncWorkRequest.php create mode 100644 app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberScheduleSummitActionSyncWorkRequest.php create mode 100644 app/Models/Foundation/Summit/Repositories/IAbstractCalendarSyncWorkRequestRepository.php create mode 100644 app/Models/Foundation/Summit/Repositories/ICalendarSyncInfoRepository.php create mode 100644 app/Models/Foundation/Summit/Repositories/IScheduleCalendarSyncInfoRepository.php create mode 100644 app/Repositories/Summit/Doctrine/DoctrineAbstractCalendarSyncWorkRequestRepository.php create mode 100644 app/Repositories/Summit/Doctrine/DoctrineCalendarSyncInfoRepository.php create mode 100644 app/Repositories/Summit/Doctrine/DoctrineScheduleCalendarSyncInfoRepository.php create mode 100644 app/Services/Apis/CalendarSync/AbstractCalendarSyncRemoteFacade.php create mode 100644 app/Services/Apis/CalendarSync/CalendarSyncRemoteFacadeFactory.php create mode 100644 app/Services/Apis/CalendarSync/Exceptions/RateLimitExceededException.php create mode 100644 app/Services/Apis/CalendarSync/GoogleCalendarSyncRemoteFacade.php create mode 100644 app/Services/Apis/CalendarSync/ICalendarSyncRemoteFacade.php create mode 100644 app/Services/Apis/CalendarSync/ICloudCalendarSyncRemoteFacade.php create mode 100644 app/Services/Apis/CalendarSync/OutlookCalendarSyncRemoteFacade.php create mode 100644 app/Services/Model/AdminActionsCalendarSyncPreProcessor.php create mode 100644 app/Services/Model/AdminActionsCalendarSyncProcessingService.php create mode 100644 app/Services/Model/AdminScheduleWorkQueueManager.php create mode 100644 app/Services/Model/IAdminActionsCalendarSyncProcessingService.php create mode 100644 app/Services/Model/ICalendarSyncWorkRequestPreProcessor.php create mode 100644 app/Services/Model/ICalendarSyncWorkRequestQueueManager.php create mode 100644 app/Services/Model/IMemberActionsCalendarSyncProcessingService.php create mode 100644 app/Services/Model/MemberActionsCalendarSyncPreProcessor.php create mode 100644 app/Services/Model/MemberActionsCalendarSyncProcessingService.php create mode 100644 app/Services/Model/MemberScheduleWorkQueueManager.php create mode 100644 app/Services/Model/Strategies/AdminActions/AdminSummitEventActionSyncWorkRequestDeleteStrategy.php create mode 100644 app/Services/Model/Strategies/AdminActions/AdminSummitEventActionSyncWorkRequestUpdateStrategy.php create mode 100644 app/Services/Model/Strategies/AdminActions/AdminSummitLocationActionSyncWorkRequestDeleteStrategy.php create mode 100644 app/Services/Model/Strategies/AdminActions/AdminSummitLocationActionSyncWorkRequestUpdateStrategy.php create mode 100644 app/Services/Model/Strategies/CalendarSyncWorkRequestPreProcessorStrategyFactory.php create mode 100644 app/Services/Model/Strategies/ICalendarSyncWorkRequestPreProcessorStrategy.php create mode 100644 app/Services/Model/Strategies/ICalendarSyncWorkRequestPreProcessorStrategyFactory.php create mode 100644 app/Services/Model/Strategies/MemberActions/MemberCalendarScheduleSummitActionSyncWorkRequestAddStrategy.php create mode 100644 app/Services/Model/Strategies/MemberActions/MemberCalendarScheduleSummitActionSyncWorkRequestDeleteStrategy.php create mode 100644 app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestAddStrategy.php create mode 100644 app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestDeleteStrategy.php create mode 100644 app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestUpdateStrategy.php create mode 100644 app/Services/Utils/EncryptionService.php create mode 100644 app/Services/Utils/Facades/Encryption.php create mode 100644 config/apple_api.php create mode 100644 config/google_api.php create mode 100644 tests/AdminActionsCalendarSyncPreProcessorTest.php create mode 100644 tests/MemberActionsCalendarSyncPreProcessorTest.php diff --git a/.env.example b/.env.example index 392a7d4d..56bc6d33 100644 --- a/.env.example +++ b/.env.example @@ -55,4 +55,10 @@ LOG_EMAIL_TO=smarcet@gmail.com LOG_EMAIL_FROM=smarcet@gmail.com LOG_LEVEL=info -EVENTBRITE_OAUTH2_PERSONAL_TOKEN= \ No newline at end of file +EVENTBRITE_OAUTH2_PERSONAL_TOKEN= +SS_ENCRYPT_KEY= +SS_ENCRYPT_CYPHER=AES-256-CBC + +GOOGLE_CLIENT_ID="" +GOOGLE_CLIENT_SECRET="" +GOOGLE_SCOPES="" diff --git a/Libs/Utils/IEncryptionService.php b/Libs/Utils/IEncryptionService.php new file mode 100644 index 00000000..c9c61212 --- /dev/null +++ b/Libs/Utils/IEncryptionService.php @@ -0,0 +1,21 @@ +service = $service; + } + + /** + * The console command name. + * + * @var string + */ + protected $name = 'summit:admin-schedule-action-process'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Process Admin External Schedule Sync Actions'; + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'summit:admin-schedule-action-process {batch_size?}'; + + public function handle() + { + $batch_size = $this->argument('batch_size'); + if(empty($batch_size)) + $batch_size = PHP_INT_MAX; + + $start = time(); + + $this->info(sprintf("processing batch size of %s", $batch_size)); + + + $res = $this->service->processActions($batch_size); + + $end = time(); + $delta = $end - $start; + $this->info(sprintf("execution call %s seconds - processed entries %s", $delta, $res)); + + } +} \ No newline at end of file diff --git a/app/Console/Commands/Inspire.php b/app/Console/Commands/Inspire.php deleted file mode 100644 index db9ab854..00000000 --- a/app/Console/Commands/Inspire.php +++ /dev/null @@ -1,33 +0,0 @@ -comment(PHP_EOL.Inspiring::quote().PHP_EOL); - } -} diff --git a/app/Console/Commands/MemberActionsCalendarSyncProcessingCommand.php b/app/Console/Commands/MemberActionsCalendarSyncProcessingCommand.php new file mode 100644 index 00000000..ad8a6257 --- /dev/null +++ b/app/Console/Commands/MemberActionsCalendarSyncProcessingCommand.php @@ -0,0 +1,83 @@ +service = $service; + } + + /** + * The console command name. + * + * @var string + */ + protected $name = 'summit:member-schedule-action-process'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Process Member External Schedule Sync Actions'; + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'summit:member-schedule-action-process {provider} {batch_size?}'; + + public function handle() + { + $batch_size = $this->argument('batch_size'); + $provider = $this->argument('provider'); + if(!CalendarSyncInfo::isValidProvider($provider)){ + $this->error("provider param is not valid , valid values are [Google, Outlook, iCloud]"); + return false; + } + if(empty($batch_size)) + $batch_size = 1000; + + $start = time(); + + $this->info(sprintf("processing provider %s - batch size of %s", $provider, $batch_size)); + + + $res = $this->service->processActions($provider, $batch_size); + + $end = time(); + $delta = $end - $start; + $this->info(sprintf("execution call %s seconds - processed entries %s", $delta, $res)); + } +} \ No newline at end of file diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 55e25f52..3cfafbde 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -4,6 +4,7 @@ namespace App\Console; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; +use models\summit\CalendarSync\CalendarSyncInfo; class Kernel extends ConsoleKernel { @@ -14,6 +15,8 @@ class Kernel extends ConsoleKernel */ protected $commands = [ \App\Console\Commands\SummitJsonGenerator::class, + \App\Console\Commands\MemberActionsCalendarSyncProcessingCommand::class, + \App\Console\Commands\AdminActionsCalendarSyncProcessingCommand::class, \App\Console\Commands\ChatTeamMessagesSender::class, ]; @@ -28,12 +31,23 @@ class Kernel extends ConsoleKernel //Current $schedule->command('summit:json-generator')->everyTenMinutes()->withoutOverlapping(); //Austin - $schedule->command('summit:json-generator 6')->everyTenMinutes()->withoutOverlapping(); + $schedule->command('summit:json-generator',[6])->everyTenMinutes()->withoutOverlapping(); //BCN - $schedule->command('summit:json-generator 7')->everyTenMinutes()->withoutOverlapping(); + $schedule->command('summit:json-generator', [7])->everyTenMinutes()->withoutOverlapping(); //Boston - $schedule->command('summit:json-generator 22')->everyTenMinutes()->withoutOverlapping(); - // teams messages - $schedule->command('teams:message-sender 100')->everyMinute()->withoutOverlapping(); + $schedule->command('summit:json-generator', [22])->everyTenMinutes()->withoutOverlapping(); + + // Calendar Sync Jobs + + // Admin Actions + $schedule->command('summit:admin-schedule-action-process')->withoutOverlapping(); + // Member Actions + // Google Calendar + $schedule->command('summit:member-schedule-action-process', [CalendarSyncInfo::ProviderGoogle, 1000])->withoutOverlapping(); + // Outlook + $schedule->command('summit:member-schedule-action-process', [CalendarSyncInfo::ProviderOutlook, 1000])->withoutOverlapping(); + // iCloud + $schedule->command('summit:member-schedule-action-process', [CalendarSyncInfo::ProvideriCloud, 1000])->withoutOverlapping(); + } } diff --git a/app/ModelSerializers/OwnMemberSerializer.php b/app/ModelSerializers/OwnMemberSerializer.php index 4d12e4f9..a8cee5f4 100644 --- a/app/ModelSerializers/OwnMemberSerializer.php +++ b/app/ModelSerializers/OwnMemberSerializer.php @@ -91,7 +91,6 @@ final class OwnMemberSerializer extends AbstractMemberSerializer $values['favorite_summit_events'] = $res; } - if(in_array('schedule_summit_events', $relations) && !is_null($summit)){ $schedule = []; diff --git a/app/ModelSerializers/SummitEventSerializer.php b/app/ModelSerializers/SummitEventSerializer.php index af3bdb74..d365b462 100644 --- a/app/ModelSerializers/SummitEventSerializer.php +++ b/app/ModelSerializers/SummitEventSerializer.php @@ -36,7 +36,7 @@ class SummitEventSerializer extends SilverStripeSerializer 'Published' => 'is_published:json_boolean', 'HeadCount' => 'head_count:json_int', 'RSVPLink' => 'rsvp_link:json_string', - 'IssExternalRSVP' => 'rsvp_external:json_boolean', + 'IsExternalRSVP' => 'rsvp_external:json_boolean', 'CategoryId' => 'track_id:json_int', ); diff --git a/app/Models/Foundation/Main/Affiliation.php b/app/Models/Foundation/Main/Affiliation.php index 9a21ea12..1c85d3fa 100644 --- a/app/Models/Foundation/Main/Affiliation.php +++ b/app/Models/Foundation/Main/Affiliation.php @@ -42,7 +42,7 @@ class Affiliation extends SilverstripeBaseModel private $is_current; /** - * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="affiliations") * @ORM\JoinColumn(name="MemberID", referencedColumnName="ID") * @var Member */ diff --git a/app/Models/Foundation/Main/ChatTeams/ChatTeamInvitation.php b/app/Models/Foundation/Main/ChatTeams/ChatTeamInvitation.php index 7c0168b6..deb92809 100644 --- a/app/Models/Foundation/Main/ChatTeams/ChatTeamInvitation.php +++ b/app/Models/Foundation/Main/ChatTeams/ChatTeamInvitation.php @@ -195,7 +195,7 @@ class ChatTeamInvitation extends SilverstripeBaseModel } /** - * @ORM\ManyToOne(targetEntity="models\main\ChatTeam") + * @ORM\ManyToOne(targetEntity="models\main\ChatTeam", inversedBy="invitations") * @ORM\JoinColumn(name="TeamID", referencedColumnName="ID") * @var ChatTeam */ diff --git a/app/Models/Foundation/Main/ChatTeams/ChatTeamMember.php b/app/Models/Foundation/Main/ChatTeams/ChatTeamMember.php index 61b0336f..1aadb6ec 100644 --- a/app/Models/Foundation/Main/ChatTeams/ChatTeamMember.php +++ b/app/Models/Foundation/Main/ChatTeams/ChatTeamMember.php @@ -123,14 +123,14 @@ class ChatTeamMember } /** - * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="team_memberships") * @ORM\JoinColumn(name="MemberID", referencedColumnName="ID") * @var Member */ private $member; /** - * @ORM\ManyToOne(targetEntity="models\main\ChatTeam") + * @ORM\ManyToOne(targetEntity="models\main\ChatTeam", inversedBy="members") * @ORM\JoinColumn(name="ChatTeamID", referencedColumnName="ID") * @var ChatTeam */ diff --git a/app/Models/Foundation/Main/ChatTeams/ChatTeamPushNotificationMessage.php b/app/Models/Foundation/Main/ChatTeams/ChatTeamPushNotificationMessage.php index bc875f92..a46aad06 100644 --- a/app/Models/Foundation/Main/ChatTeams/ChatTeamPushNotificationMessage.php +++ b/app/Models/Foundation/Main/ChatTeams/ChatTeamPushNotificationMessage.php @@ -51,7 +51,7 @@ class ChatTeamPushNotificationMessage extends PushNotificationMessage $this->team = $team; } /** - * @ORM\ManyToOne(targetEntity="models\main\ChatTeam") + * @ORM\ManyToOne(targetEntity="models\main\ChatTeam", inversedBy="messages") * @ORM\JoinColumn(name="ChatTeamID", referencedColumnName="ID") * @var ChatTeam */ diff --git a/app/Models/Foundation/Main/Member.php b/app/Models/Foundation/Main/Member.php index 36406ff2..b4e2703e 100644 --- a/app/Models/Foundation/Main/Member.php +++ b/app/Models/Foundation/Main/Member.php @@ -19,6 +19,8 @@ use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; use Doctrine\ORM\Query\ResultSetMappingBuilder; use models\exceptions\ValidationException; +use models\summit\CalendarSync\CalendarSyncInfo; +use models\summit\CalendarSync\ScheduleCalendarSyncInfo; use models\summit\RSVP; use models\summit\Summit; use models\summit\SummitEvent; @@ -35,20 +37,114 @@ use Doctrine\ORM\Mapping AS ORM; */ class Member extends SilverstripeBaseModel { + /** - * Member constructor. + * @ORM\Column(name="FirstName", type="string") + * @var string */ - public function __construct() - { - parent::__construct(); - $this->feedback = new ArrayCollection(); - $this->groups = new ArrayCollection(); - $this->affiliations = new ArrayCollection(); - $this->team_memberships = new ArrayCollection(); - $this->favorites = new ArrayCollection(); - $this->schedule = new ArrayCollection(); - $this->rsvp = new ArrayCollection(); - } + private $first_name; + + /** + * @ORM\Column(name="Bio", type="string") + * @var string + */ + private $bio; + + /** + * @ORM\Column(name="Surname", type="string") + * @var string + */ + private $last_name; + + /** + * @ORM\OneToMany(targetEntity="models\summit\SummitEventFeedback", mappedBy="owner", cascade={"persist"}) + * @var SummitEventFeedback[] + */ + private $feedback; + + /** + * @ORM\OneToMany(targetEntity="Affiliation", mappedBy="owner", cascade={"persist"}) + */ + private $affiliations; + + /** + * @ORM\Column(name="Active", type="boolean") + * @var bool + */ + private $active; + + /** + * @ORM\Column(name="LinkedInProfile", type="string") + * @var string + */ + private $linked_in_profile; + + /** + * @ORM\Column(name="IRCHandle", type="string") + * @var string + */ + private $irc_handle; + + /** + * @ORM\Column(name="TwitterName", type="string") + * @var string + */ + private $twitter_handle; + + /** + * @ORM\Column(name="Gender", type="string") + * @var string + */ + private $gender; + + /** + * @ORM\Column(name="Country", type="string") + * @var string + */ + private $country; + + /** + * @ORM\Column(name="Email", type="string") + * @var string + */ + private $email; + + /** + * @ORM\Column(name="SecondEmail", type="string") + * @var string + */ + private $second_email; + + /** + * @ORM\Column(name="ThirdEmail", type="string") + * @var string + */ + private $third_email; + + /** + * @ORM\Column(name="EmailVerified", type="boolean") + * @var bool + */ + private $email_verified; + + /** + * @ORM\Column(name="EmailVerifiedDate", type="datetime") + * @var \DateTime + */ + private $email_verified_date; + + /** + * @ORM\ManyToOne(targetEntity="models\main\File") + * @ORM\JoinColumn(name="PhotoID", referencedColumnName="ID") + * @var File + */ + private $photo; + + /** + * @ORM\Column(name="State", type="string") + * @var string + */ + private $state; /** * @ORM\OneToMany(targetEntity="SummitMemberSchedule", mappedBy="member", cascade={"persist"}, orphanRemoval=true) @@ -56,11 +152,62 @@ class Member extends SilverstripeBaseModel */ private $schedule; + /** + * @ORM\OneToMany(targetEntity="models\summit\CalendarSync\ScheduleCalendarSyncInfo", mappedBy="member", cascade={"persist"}, orphanRemoval=true) + * @var ScheduleCalendarSyncInfo[] + */ + private $schedule_sync_info; + + /** + * @ORM\OneToMany(targetEntity="models\summit\CalendarSync\CalendarSyncInfo", mappedBy="owner", cascade={"persist"}, orphanRemoval=true) + * @var CalendarSyncInfo[] + */ + private $calendars_sync; + /** * @ORM\OneToMany(targetEntity="models\summit\RSVP", mappedBy="owner", cascade={"persist"}) * @var RSVP[] */ - protected $rsvp; + private $rsvp; + + /** + * @ORM\ManyToMany(targetEntity="models\main\Group", inversedBy="members") + * @ORM\JoinTable(name="Group_Members", + * joinColumns={@ORM\JoinColumn(name="MemberID", referencedColumnName="ID")}, + * inverseJoinColumns={@ORM\JoinColumn(name="GroupID", referencedColumnName="ID")} + * ) + * @var Group[] + */ + private $groups; + + /** + * @ORM\OneToMany(targetEntity="ChatTeamMember", mappedBy="member", cascade={"persist"}, orphanRemoval=true) + * @var ChatTeamMember[] + */ + private $team_memberships; + + /** + * @ORM\OneToMany(targetEntity="SummitMemberFavorite", mappedBy="member", cascade={"persist"}, orphanRemoval=true) + * @var SummitMemberFavorite[] + */ + private $favorites; + + /** + * Member constructor. + */ + public function __construct() + { + parent::__construct(); + $this->feedback = new ArrayCollection(); + $this->groups = new ArrayCollection(); + $this->affiliations = new ArrayCollection(); + $this->team_memberships = new ArrayCollection(); + $this->favorites = new ArrayCollection(); + $this->schedule = new ArrayCollection(); + $this->rsvp = new ArrayCollection(); + $this->calendars_sync = new ArrayCollection(); + $this->schedule_sync_info = new ArrayCollection(); + } /** * @return Affiliation[] @@ -130,23 +277,6 @@ class Member extends SilverstripeBaseModel $this->groups = $groups; } - /** - * @ORM\ManyToMany(targetEntity="models\main\Group", inversedBy="members") - * @ORM\JoinTable(name="Group_Members", - * joinColumns={@ORM\JoinColumn(name="MemberID", referencedColumnName="ID")}, - * inverseJoinColumns={@ORM\JoinColumn(name="GroupID", referencedColumnName="ID")} - * ) - * @var Group[] - */ - private $groups; - - - /** - * @ORM\OneToMany(targetEntity="ChatTeamMember", mappedBy="member", cascade={"persist"}, orphanRemoval=true) - * @var ChatTeamMember[] - */ - private $team_memberships; - /** * @return SummitEvent[] */ @@ -155,7 +285,6 @@ class Member extends SilverstripeBaseModel return $this->favorites; } - /** * @param SummitMemberFavorite[] $favorites */ @@ -164,12 +293,6 @@ class Member extends SilverstripeBaseModel $this->favorites = $favorites; } - /** - * @ORM\OneToMany(targetEntity="SummitMemberFavorite", mappedBy="member", cascade={"persist"}, orphanRemoval=true) - * @var SummitMemberFavorite[] - */ - private $favorites; - /** * @return string */ @@ -202,31 +325,6 @@ class Member extends SilverstripeBaseModel return $this->twitter_handle; } - /** - * @ORM\ManyToOne(targetEntity="models\main\File") - * @ORM\JoinColumn(name="PhotoID", referencedColumnName="ID") - * @var File - */ - private $photo; - - /** - * @ORM\Column(name="FirstName", type="string") - * @var string - */ - private $first_name; - - /** - * @ORM\Column(name="Bio", type="string") - * @var string - */ - private $bio; - - /** - * @ORM\Column(name="State", type="string") - * @var string - */ - private $state; - /** * @return string */ @@ -291,42 +389,6 @@ class Member extends SilverstripeBaseModel $this->third_email = $third_email; } - /** - * @ORM\Column(name="Country", type="string") - * @var string - */ - private $country; - - /** - * @ORM\Column(name="Email", type="string") - * @var string - */ - private $email; - - /** - * @ORM\Column(name="SecondEmail", type="string") - * @var string - */ - private $second_email; - - /** - * @ORM\Column(name="ThirdEmail", type="string") - * @var string - */ - private $third_email; - - /** - * @ORM\Column(name="EmailVerified", type="boolean") - * @var bool - */ - private $email_verified; - - /** - * @ORM\Column(name="EmailVerifiedDate", type="datetime") - * @var \DateTime - */ - private $email_verified_date; - /** * @return string */ @@ -407,36 +469,6 @@ class Member extends SilverstripeBaseModel $this->active = $active; } - /** - * @ORM\Column(name="Active", type="boolean") - * @var bool - */ - private $active; - - /** - * @ORM\Column(name="LinkedInProfile", type="string") - * @var string - */ - private $linked_in_profile; - - /** - * @ORM\Column(name="IRCHandle", type="string") - * @var string - */ - private $irc_handle; - - /** - * @ORM\Column(name="TwitterName", type="string") - * @var string - */ - private $twitter_handle; - - /** - * @ORM\Column(name="Gender", type="string") - * @var string - */ - private $gender; - /** * @return string */ @@ -461,24 +493,6 @@ class Member extends SilverstripeBaseModel return $this->first_name; } - /** - * @ORM\Column(name="Surname", type="string") - * @var string - */ - private $last_name; - - /** - * @ORM\OneToMany(targetEntity="models\summit\SummitEventFeedback", mappedBy="owner", cascade={"persist"}) - * @var SummitEventFeedback[] - */ - private $feedback; - - - /** - * @ORM\OneToMany(targetEntity="Affiliation", mappedBy="owner", cascade={"persist"}) - */ - private $affiliations; - /** * @return File */ @@ -606,19 +620,9 @@ class Member extends SilverstripeBaseModel */ public function isOnFavorite(SummitEvent $event) { - $sql = <<prepareRawSQL($sql); - $stmt->execute([ - 'member_id' => $this->getId(), - 'event_id' => $event->getId() - ]); - $res = $stmt->fetchAll(\PDO::FETCH_COLUMN); - return count($res) > 0 ? intval($res[0]) > 0 : false; + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('event', $event)); + return $this->favorites->matching($criteria)->count() > 0; } /** @@ -634,7 +638,7 @@ SQL; ( sprintf('Event %s does not belongs to member %s favorite.', $event->getId(), $this->getId()) ); - $this->schedule->removeElement($favorite); + $this->favorites->removeElement($favorite); $favorite->clearOwner(); } @@ -686,6 +690,14 @@ SQL; $this->schedule->add($schedule); } + /** + * @param ScheduleCalendarSyncInfo $sync_info + */ + public function add2ScheduleSyncInfo(ScheduleCalendarSyncInfo $sync_info){ + $sync_info->setMember($this); + $this->schedule_sync_info->add($sync_info); + } + public function removeFromSchedule(SummitEvent $event) { $schedule = $this->getScheduleByEvent($event); @@ -699,25 +711,33 @@ SQL; $schedule->clearOwner(); } + public function removeFromScheduleSyncInfo(ScheduleCalendarSyncInfo $sync_info){ + $this->schedule_sync_info->removeElement($sync_info); + $sync_info->clearOwner(); + } + + /** + * @param CalendarSyncInfo $calendar_sync_info + * @param SummitEvent $event + * @return bool + */ + public function isEventSynchronized(CalendarSyncInfo $calendar_sync_info, SummitEvent $event){ + + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('summit_event', $event)); + $criteria->andWhere(Criteria::expr()->eq('calendar_sync_info', $calendar_sync_info)); + return $this->schedule_sync_info->matching($criteria)->count() > 0; + } + /** * @param SummitEvent $event * @return bool */ public function isOnSchedule(SummitEvent $event) { - $sql = <<prepareRawSQL($sql); - $stmt->execute([ - 'member_id' => $this->getId(), - 'event_id' => $event->getId() - ]); - $res = $stmt->fetchAll(\PDO::FETCH_COLUMN); - return count($res) > 0 ? intval($res[0]) > 0 : false; + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('event', $event)); + return $this->schedule->matching($criteria)->count() > 0; } /** @@ -746,6 +766,27 @@ SQL; } } + /** + * @param SummitEvent $event + * @param CalendarSyncInfo $calendar_sync_info + * @return ScheduleCalendarSyncInfo|null + */ + public function getScheduleSyncInfoByEvent(SummitEvent $event, CalendarSyncInfo $calendar_sync_info){ + try { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('summit_event', $event)); + $criteria->andWhere(Criteria::expr()->eq('calendar_sync_info', $calendar_sync_info)); + return $this->schedule_sync_info->matching($criteria)->first(); + } + catch(NoResultException $ex1){ + return null; + } + catch(NonUniqueResultException $ex2){ + // should never happen + return null; + } + } + /** * @param SummitEvent $event * @return SummitMemberFavorite|null @@ -771,12 +812,6 @@ SQL; } } - /** - * @return SummitMemberSchedule[] - */ - public function getSchedule(){ - return $this->schedule; - } /** * @param Summit $summit * @return int[] @@ -851,4 +886,31 @@ SQL; ->setParameter('summit_id', $summit->getId()) ->getResult(); } + + /** + * @param Summit $summit + * @return CalendarSyncInfo[] + */ + public function getSyncInfoBy(Summit $summit){ + $res = $this->calendars_sync->filter(function($entity) use($summit){ + return $entity->getSummit()->getIdentifier() == $summit->getIdentifier() && !$entity->isRevoked(); + }); + return count($res) > 0 ? $res[0] : null; + } + + /** + * @param Summit $summit + * @return bool + */ + public function hasSyncInfoFor(Summit $summit){ + return !is_null($this->getSyncInfoBy($summit)); + } + + /** + * @param CalendarSyncInfo $calendar_sync_info + */ + public function removeFromCalendarSyncInfo(CalendarSyncInfo $calendar_sync_info){ + $this->calendars_sync->removeElement($calendar_sync_info); + $calendar_sync_info->clearOwner(); + } } \ No newline at end of file diff --git a/app/Models/Foundation/Main/PushNotificationMessage.php b/app/Models/Foundation/Main/PushNotificationMessage.php index b8e1b533..43c54e8b 100644 --- a/app/Models/Foundation/Main/PushNotificationMessage.php +++ b/app/Models/Foundation/Main/PushNotificationMessage.php @@ -26,6 +26,9 @@ use models\utils\SilverstripeBaseModel; */ class PushNotificationMessage extends SilverstripeBaseModel { + const PlatformMobile = 'MOBILE'; + const PlatformWeb = 'WEB'; + public function __construct() { parent::__construct(); @@ -38,22 +41,6 @@ class PushNotificationMessage extends SilverstripeBaseModel */ protected $message; - /** - * @return string - */ - public function getPriority() - { - return $this->priority; - } - - /** - * @param string $priority - */ - public function setPriority($priority) - { - $this->priority = $priority; - } - /** * @ORM\Column(name="Priority", type="string") * @var string @@ -72,6 +59,18 @@ class PushNotificationMessage extends SilverstripeBaseModel */ protected $is_sent; + /** + * @ORM\Column(name="Approved", type="boolean") + * @var bool + */ + protected $approved; + + /** + * @ORM\Column(name="Platform", type="string") + * @var bool + */ + protected $platform; + /** * @ORM\ManyToOne(targetEntity="models\main\Member") * @ORM\JoinColumn(name="OwnerID", referencedColumnName="ID") @@ -79,6 +78,13 @@ class PushNotificationMessage extends SilverstripeBaseModel */ protected $owner; + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="ApprovedByID", referencedColumnName="ID") + * @var Member + */ + protected $approved_by; + /** * @return int */ @@ -180,4 +186,68 @@ class PushNotificationMessage extends SilverstripeBaseModel $this->owner = $owner; } + /** + * @return string + */ + public function getPriority() + { + return $this->priority; + } + + /** + * @param string $priority + */ + public function setPriority($priority) + { + $this->priority = $priority; + } + + /** + * @return bool + */ + public function isApproved() + { + return $this->approved; + } + + /** + * @param bool $approved + */ + public function setApproved($approved) + { + $this->approved = $approved; + } + + /** + * @return bool + */ + public function isPlatform() + { + return $this->platform; + } + + /** + * @param bool $platform + */ + public function setPlatform($platform) + { + $this->platform = $platform; + } + + /** + * @return Member + */ + public function getApprovedBy() + { + return $this->approved_by; + } + + /** + * @param Member $approved_by + */ + public function setApprovedBy($approved_by) + { + $this->approved_by = $approved_by; + } + } \ No newline at end of file diff --git a/app/Models/Foundation/Main/SummitMemberFavorite.php b/app/Models/Foundation/Main/SummitMemberFavorite.php index 06452ece..e759dc3a 100644 --- a/app/Models/Foundation/Main/SummitMemberFavorite.php +++ b/app/Models/Foundation/Main/SummitMemberFavorite.php @@ -22,7 +22,7 @@ use models\utils\IEntity; * Class SummitMemberSchedule * @package models\main */ -class SummitMemberFavorite +final class SummitMemberFavorite { /** * @ORM\Id @@ -86,7 +86,7 @@ class SummitMemberFavorite } /** - * @ORM\ManyToOne(targetEntity="Member", inversedBy="schedule") + * @ORM\ManyToOne(targetEntity="Member", inversedBy="favorites") * @ORM\JoinColumn(name="MemberID", referencedColumnName="ID", nullable=true ) * @var Member */ diff --git a/app/Models/Foundation/Main/SummitMemberSchedule.php b/app/Models/Foundation/Main/SummitMemberSchedule.php index f19ee36a..cb39bdac 100644 --- a/app/Models/Foundation/Main/SummitMemberSchedule.php +++ b/app/Models/Foundation/Main/SummitMemberSchedule.php @@ -22,8 +22,12 @@ use models\utils\IEntity; * Class SummitMemberSchedule * @package models\main */ -class SummitMemberSchedule implements IEntity +final class SummitMemberSchedule implements IEntity { + public function __construct() + { + } + /** * @ORM\Id * @ORM\GeneratedValue @@ -31,6 +35,28 @@ class SummitMemberSchedule implements IEntity */ private $id; + /** + * @ORM\ManyToOne(targetEntity="Member", inversedBy="schedule") + * @ORM\JoinColumn(name="MemberID", referencedColumnName="ID", nullable=true ) + * @var Member + */ + private $member; + + /** + * @ORM\ManyToOne(targetEntity="models\summit\SummitEvent") + * @ORM\JoinColumn(name="SummitEventID", referencedColumnName="ID") + * @var SummitEvent + */ + private $event; + + /** + * @return int + */ + public function getIdentifier() + { + return $this->id; + } + /** * @return int */ @@ -76,27 +102,4 @@ class SummitMemberSchedule implements IEntity { $this->event = $event; } - - /** - * @return int - */ - public function getIdentifier() - { - return $this->id; - } - - /** - * @ORM\ManyToOne(targetEntity="Member", inversedBy="schedule") - * @ORM\JoinColumn(name="MemberID", referencedColumnName="ID", nullable=true ) - * @var Member - */ - private $member; - - /** - * @ORM\ManyToOne(targetEntity="models\summit\SummitEvent") - * @ORM\JoinColumn(name="SummitEventID", referencedColumnName="ID") - * @var SummitEvent - */ - private $event; - } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Attendees/SummitAttendee.php b/app/Models/Foundation/Summit/Attendees/SummitAttendee.php index 1a7e691b..28127dc2 100644 --- a/app/Models/Foundation/Summit/Attendees/SummitAttendee.php +++ b/app/Models/Foundation/Summit/Attendees/SummitAttendee.php @@ -49,6 +49,13 @@ class SummitAttendee extends SilverstripeBaseModel */ private $summit_hall_checked_in_date; + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="MemberID", referencedColumnName="ID") + * @var Member + */ + private $member; + /** * @return \DateTime */ @@ -79,13 +86,6 @@ class SummitAttendee extends SilverstripeBaseModel $this->share_contact_info = $share_contact_info; } - /** - * @ORM\ManyToOne(targetEntity="models\main\Member") - * @ORM\JoinColumn(name="MemberID", referencedColumnName="ID") - * @var Member - */ - private $member; - /** * @return int */ @@ -106,7 +106,7 @@ class SummitAttendee extends SilverstripeBaseModel } /** - * @ORM\OneToMany(targetEntity="SummitAttendeeTicket", mappedBy="owner", cascade={"persist"}) + * @ORM\OneToMany(targetEntity="SummitAttendeeTicket", mappedBy="owner", cascade={"persist"}, orphanRemoval=true) * @var SummitAttendeeTicket[] */ private $tickets; diff --git a/app/Models/Foundation/Summit/Attendees/SummitAttendeeTicket.php b/app/Models/Foundation/Summit/Attendees/SummitAttendeeTicket.php index 078f7753..fbb4e8d9 100644 --- a/app/Models/Foundation/Summit/Attendees/SummitAttendeeTicket.php +++ b/app/Models/Foundation/Summit/Attendees/SummitAttendeeTicket.php @@ -170,7 +170,7 @@ class SummitAttendeeTicket extends SilverstripeBaseModel private $ticket_type; /** - * @ORM\ManyToOne(targetEntity="SummitAttendee") + * @ORM\ManyToOne(targetEntity="SummitAttendee", inversedBy="tickets") * @ORM\JoinColumn(name="OwnerID", referencedColumnName="ID") * @var SummitAttendee */ diff --git a/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfo.php b/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfo.php new file mode 100644 index 00000000..e0f5246c --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfo.php @@ -0,0 +1,186 @@ +synchronized_events = new ArrayCollection(); + } + + /** + * @ORM\Column(name="Provider", type="string") + * @var string + */ + protected $provider; + + /** + * @ORM\Column(name="CalendarExternalId", type="string") + * @var string + */ + protected $external_id; + + /** + * @ORM\Column(name="ETag", type="string") + * @var string + */ + protected $etag; + + /** + * @ORM\Column(name="Revoked", type="boolean") + * @var bool + */ + protected $revoked; + + use SummitOwned; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="calendars_sync") + * @ORM\JoinColumn(name="OwnerID", referencedColumnName="ID") + * @var Member + */ + protected $owner; + + /** + * @ORM\OneToMany(targetEntity="ScheduleCalendarSyncInfo", mappedBy="calendar_sync_info", cascade={"persist"}, orphanRemoval=true) + * @var ScheduleCalendarSyncInfo[] + */ + protected $synchronized_events; + + /** + * @return string + */ + public function getProvider() + { + return $this->provider; + } + + /** + * @param string $provider + */ + public function setProvider($provider) + { + $this->provider = $provider; + } + + /** + * @return string + */ + public function getExternalId() + { + return $this->external_id; + } + + /** + * @param string $external_id + */ + public function setExternalId($external_id) + { + $this->external_id = $external_id; + } + + /** + * @return string + */ + public function getEtag() + { + return $this->etag; + } + + /** + * @param string $etag + */ + public function setEtag($etag) + { + $this->etag = $etag; + } + + /** + * @return Member + */ + public function getOwner() + { + return $this->owner; + } + + /** + * @param Member $owner + */ + public function setOwner($owner) + { + $this->owner = $owner; + } + + /** + * @return ScheduleCalendarSyncInfo[] + */ + public function getSynchronizedEvents() + { + return $this->synchronized_events; + } + + /** + * @return bool + */ + public function isRevoked() + { + return $this->revoked; + } + + /** + * @param bool $revoked + */ + public function setRevoked($revoked) + { + $this->revoked = $revoked; + } + + public function clearOwner(){ + $this->owner = null; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfoCalDav.php b/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfoCalDav.php new file mode 100644 index 00000000..f51265bc --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfoCalDav.php @@ -0,0 +1,150 @@ +user_name; + } + + /** + * @param string $user_name + */ + public function setUserName($user_name) + { + $this->user_name = $user_name; + } + + /** + * @return string + */ + public function getUserPassword() + { + return Encryption::decrypt($this->user_password); + } + + /** + * @param string $user_password + */ + public function setUserPassword($user_password) + { + $this->user_password = Encryption::encrypt($user_password); + } + + /** + * @return string + */ + public function getUserPrincipalUrl() + { + return $this->user_principal_url; + } + + /** + * @param string $user_principal_url + */ + public function setUserPrincipalUrl($user_principal_url) + { + $this->user_principal_url = $user_principal_url; + } + + /** + * @return string + */ + public function getServer(){ + $result = parse_url($this->user_principal_url); + return $result['scheme']."://".$result['host']; + } + + /** + * @return string + */ + public function getCalendarUrl(){ + return $this->external_id; + } + + /** + * @return string + */ + public function getCalendarDisplayName() + { + return $this->calendar_display_name; + } + + /** + * @param string $calendar_display_name + */ + public function setCalendarDisplayName($calendar_display_name) + { + $this->calendar_display_name = $calendar_display_name; + } + + /** + * @return string + */ + public function getCalendarSyncToken() + { + return $this->calendar_sync_token; + } + + /** + * @param string $calendar_sync_token + */ + public function setCalendarSyncToken($calendar_sync_token) + { + $this->calendar_sync_token = $calendar_sync_token; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfoOAuth2.php b/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfoOAuth2.php new file mode 100644 index 00000000..d6361819 --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/CalendarSyncInfoOAuth2.php @@ -0,0 +1,74 @@ +access_token); + return json_decode($access_token, true); + } + + /** + * @param string $access_token + */ + public function setAccessToken($access_token) + { + $this->access_token = Encryption::encrypt + ( + json_encode($access_token) + ); + } + + /** + * @return string + */ + public function getRefreshToken() + { + return Encryption::decrypt($this->refresh_token); + } + + /** + * @param string $refresh_token + */ + public function setRefreshToken($refresh_token) + { + $this->refresh_token = Encryption::encrypt($refresh_token); + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/ScheduleCalendarSyncInfo.php b/app/Models/Foundation/Summit/CalendarSync/ScheduleCalendarSyncInfo.php new file mode 100644 index 00000000..9fcd8e31 --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/ScheduleCalendarSyncInfo.php @@ -0,0 +1,280 @@ +id; + } + + /** + * @return Member + */ + public function getMember() + { + return $this->member; + } + + /** + * @param Member $member + */ + public function setMember($member) + { + $this->member = $member; + } + + + public function clearOwner(){ + $this->member = null; + $this->event = null; + } + + /** + * @return SummitEvent + */ + public function getSummitEvent() + { + return $this->summit_event; + } + + /** + * @param SummitEvent $event + */ + public function setSummitEvent($event) + { + $this->summit_event = $event; + } + + /** + * @return \DateTime + */ + public function getCreated() + { + return $this->created; + } + + /** + * @param \DateTime $created + */ + public function setCreated($created) + { + $this->created = $created; + } + + /** + * @return \DateTime + */ + public function getLastEdited() + { + return $this->last_edited; + } + + /** + * @param \DateTime $last_edited + */ + public function setLastEdited($last_edited) + { + $this->last_edited = $last_edited; + } + + /** + * @return string + */ + public function getExternalId() + { + return $this->external_id; + } + + /** + * @param string $external_id + */ + public function setExternalId($external_id) + { + $this->external_id = $external_id; + } + + /** + * @return string + */ + public function getEtag() + { + return $this->etag; + } + + /** + * @param string $etag + */ + public function setEtag($etag) + { + $this->etag = $etag; + } + + /** + * @return string + */ + public function getExternalUrl() + { + return $this->external_url; + } + + /** + * @param string $external_url + */ + public function setExternalUrl($external_url) + { + $this->external_url = $external_url; + } + + /** + * @return CalendarSyncInfo + */ + public function getCalendarSyncInfo() + { + return $this->calendar_sync_info; + } + + /** + * @param CalendarSyncInfo $calendar_sync_info + */ + public function setCalendarSyncInfo($calendar_sync_info) + { + $this->calendar_sync_info = $calendar_sync_info; + } + + /** + * @return mixed + */ + public function getLocation() + { + return $this->location; + } + + /** + * @param mixed $location + */ + public function setLocation($location) + { + $this->location = $location; + } + + /** + * @return string + */ + public function getVCard() + { + return $this->vcard; + } + + /** + * @param string $vcard + */ + public function setVCard($vcard) + { + $this->vcard = $vcard; + } + + /** + * @return string + */ + public function toJson(){ + return json_encode([ + 'external_id' => $this->external_id, + 'etag' => $this->etag, + 'external_url' => $this->external_url, + 'vcard' => $this->vcard, + ]); + } + + /** + * @param string $str_json + * @return ScheduleCalendarSyncInfo + */ + public static function buildFromJson($str_json){ + $res = json_decode($str_json, true); + $o = new ScheduleCalendarSyncInfo(); + $o->setExternalId($res['external_id']); + $o->setEtag($res['etag']); + $o->setExternalUrl($res['external_url']); + $o->setVCard($res['vcard']); + return $o; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AbstractCalendarSyncWorkRequest.php b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AbstractCalendarSyncWorkRequest.php new file mode 100644 index 00000000..fcf8fa66 --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AbstractCalendarSyncWorkRequest.php @@ -0,0 +1,110 @@ +is_processed = false; + } + + /** + * @ORM\Column(name="Type", type="string") + * @var string + */ + protected $type; + + /** + * @ORM\Column(name="IsProcessed", type="boolean", options={"default":"0"}) + * @var bool + */ + protected $is_processed; + + /** + * @ORM\Column(name="ProcessedDate", type="datetime") + * @var \DateTime + */ + protected $processed_date; + + + /** + * @return mixed + */ + public function getType() + { + return $this->type; + } + + /** + * @param mixed $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return bool + */ + public function IsProcessed() + { + return $this->is_processed; + } + + /** + * @param bool $is_processed + */ + public function setIsProcessed($is_processed) + { + $this->is_processed = $is_processed; + } + + /** + * @return \DateTime + */ + public function getProcessedDate() + { + return $this->processed_date; + } + + /** + * @param \DateTime $processed_date + */ + public function setProcessedDate($processed_date) + { + $this->processed_date = $processed_date; + } + + + public function markProcessed(){ + $this->is_processed = true; + $this->processed_date = new \DateTime('now', new \DateTimeZone(SilverstripeBaseModel::DefaultTimeZone)); + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminScheduleSummitActionSyncWorkRequest.php b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminScheduleSummitActionSyncWorkRequest.php new file mode 100644 index 00000000..794adff0 --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminScheduleSummitActionSyncWorkRequest.php @@ -0,0 +1,49 @@ +created_by; + } + + /** + * @param Member $created_by + */ + public function setCreatedBy($created_by) + { + $this->created_by = $created_by; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminSummitEventActionSyncWorkRequest.php b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminSummitEventActionSyncWorkRequest.php new file mode 100644 index 00000000..23983ef7 --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminSummitEventActionSyncWorkRequest.php @@ -0,0 +1,52 @@ +summit_event; + } + + /** + * @param SummitEvent $summit_event + */ + public function setSummitEvent($summit_event) + { + $this->summit_event = $summit_event; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminSummitLocationActionSyncWorkRequest.php b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminSummitLocationActionSyncWorkRequest.php new file mode 100644 index 00000000..eab1e4d5 --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/AdminSummitLocationActionSyncWorkRequest.php @@ -0,0 +1,48 @@ +location; + } + + /** + * @param SummitAbstractLocation $location + */ + public function setLocation($location) + { + $this->location = $location; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberCalendarScheduleSummitActionSyncWorkRequest.php b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberCalendarScheduleSummitActionSyncWorkRequest.php new file mode 100644 index 00000000..7a6911a7 --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberCalendarScheduleSummitActionSyncWorkRequest.php @@ -0,0 +1,99 @@ +calendar_id; + } + + /** + * @param string $calendar_id + */ + public function setCalendarId($calendar_id) + { + $this->calendar_id = $calendar_id; + } + + /** + * @return string + */ + public function getCalendarName() + { + return $this->calendar_name; + } + + /** + * @param string $calendar_name + */ + public function setCalendarName($calendar_name) + { + $this->calendar_name = $calendar_name; + } + + /** + * @return string + */ + public function getCalendarDescription() + { + return $this->calendar_description; + } + + /** + * @param string $calendar_description + */ + public function setCalendarDescription($calendar_description) + { + $this->calendar_description = $calendar_description; + } + + /** + * @return string + */ + public function getSubType(){ + return self::SubType; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberEventScheduleSummitActionSyncWorkRequest.php b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberEventScheduleSummitActionSyncWorkRequest.php new file mode 100644 index 00000000..f273fd9c --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberEventScheduleSummitActionSyncWorkRequest.php @@ -0,0 +1,56 @@ +summit_event; + } + + /** + * @param SummitEvent $summit_event + */ + public function setSummitEvent($summit_event) + { + $this->summit_event = $summit_event; + } + + /** + * @return string + */ + public function getSubType(){ + return self::SubType; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberScheduleSummitActionSyncWorkRequest.php b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberScheduleSummitActionSyncWorkRequest.php new file mode 100644 index 00000000..83bf97ec --- /dev/null +++ b/app/Models/Foundation/Summit/CalendarSync/WorkQueue/MemberScheduleSummitActionSyncWorkRequest.php @@ -0,0 +1,77 @@ +owner; + } + + /** + * @param Member $owner + */ + public function setOwner($owner) + { + $this->owner = $owner; + } + + /** + * @return CalendarSyncInfo + */ + public function getCalendarSyncInfo() + { + return $this->calendar_sync_info; + } + + /** + * @param CalendarSyncInfo $calendar_sync_info + */ + public function setCalendarSyncInfo($calendar_sync_info) + { + $this->calendar_sync_info = $calendar_sync_info; + } + + public function getSubType(){ + return null; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMaterial.php b/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMaterial.php index b952ca09..cf04bd01 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMaterial.php +++ b/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMaterial.php @@ -38,7 +38,7 @@ abstract class PresentationMaterial extends SilverstripeBaseModel } /** - * @ORM\ManyToOne(targetEntity="models\summit\Presentation", inversedBy="materil") + * @ORM\ManyToOne(targetEntity="models\summit\Presentation", inversedBy="materials") * @ORM\JoinColumn(name="PresentationID", referencedColumnName="ID") * @var Presentation */ diff --git a/app/Models/Foundation/Summit/Events/Presentations/Presentation.php b/app/Models/Foundation/Summit/Events/Presentations/Presentation.php index bf8639b4..084afb68 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/Presentation.php +++ b/app/Models/Foundation/Summit/Events/Presentations/Presentation.php @@ -26,7 +26,7 @@ class Presentation extends SummitEvent { /** - * @ORM\OneToMany(targetEntity="models\summit\PresentationMaterial", mappedBy="presentation", cascade={"persist"}) + * @ORM\OneToMany(targetEntity="models\summit\PresentationMaterial", mappedBy="presentation", cascade={"persist"}, orphanRemoval=true) * @var PresentationMaterial[] */ private $materials; @@ -293,7 +293,7 @@ class Presentation extends SummitEvent } /** - * @ORM\ManyToOne(targetEntity="PresentationSpeaker") + * @ORM\ManyToOne(targetEntity="PresentationSpeaker", inversedBy="moderated_presentations") * @ORM\JoinColumn(name="ModeratorID", referencedColumnName="ID") * @var PresentationSpeaker */ diff --git a/app/Models/Foundation/Summit/Events/Presentations/PresentationSpeaker.php b/app/Models/Foundation/Summit/Events/Presentations/PresentationSpeaker.php index 22a27e38..1e4dcc37 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/PresentationSpeaker.php +++ b/app/Models/Foundation/Summit/Events/Presentations/PresentationSpeaker.php @@ -170,6 +170,7 @@ class PresentationSpeaker extends SilverstripeBaseModel /** * @ORM\OneToMany(targetEntity="Presentation", mappedBy="moderator", cascade={"persist"}) + * @var Presentation[] */ private $moderated_presentations; diff --git a/app/Models/Foundation/Summit/Events/SummitEvent.php b/app/Models/Foundation/Summit/Events/SummitEvent.php index 93b64222..ceb96f30 100644 --- a/app/Models/Foundation/Summit/Events/SummitEvent.php +++ b/app/Models/Foundation/Summit/Events/SummitEvent.php @@ -265,10 +265,17 @@ class SummitEvent extends SilverstripeBaseModel /** * @return bool */ - public function getIssExternalRSVP(){ + public function isExternalRSVP(){ return !empty($this->rsvp_link) && $this->rsvp_template_id == 0; } + /** + * @return bool + */ + public function getIsExternalRSVP(){ + return $this->isExternalRSVP(); + } + public function getSlug(){ $slugify = new Slugify(); return $slugify->slugify($this->title); diff --git a/app/Models/Foundation/Summit/Locations/SummitGeoLocatedLocation.php b/app/Models/Foundation/Summit/Locations/SummitGeoLocatedLocation.php index e3acedc0..cd000cec 100644 --- a/app/Models/Foundation/Summit/Locations/SummitGeoLocatedLocation.php +++ b/app/Models/Foundation/Summit/Locations/SummitGeoLocatedLocation.php @@ -37,6 +37,95 @@ class SummitGeoLocatedLocation extends SummitAbstractLocation */ protected $address1; + /** + * @ORM\Column(name="Address2", type="string") + */ + protected $address2; + + /** + * @ORM\Column(name="ZipCode", type="string") + */ + protected $zip_code; + + /** + * @ORM\Column(name="City", type="string") + */ + protected $city; + + /** + * @ORM\Column(name="State", type="string") + */ + protected $state; + + /** + * @ORM\Column(name="Country", type="string") + */ + protected $country; + + /** + * @ORM\Column(name="WebSiteUrl", type="string") + */ + protected $website_url; + + /** + * @ORM\Column(name="Lng", type="string") + */ + protected $lng; + + /** + * @ORM\Column(name="Lat", type="string") + */ + protected $lat; + + /** + * @ORM\Column(name="DisplayOnSite", type="boolean") + */ + protected $display_on_site; + + /** + * @ORM\Column(name="DetailsPage", type="boolean") + */ + protected $details_page; + + /** + * @ORM\Column(name="LocationMessage", type="string") + */ + protected $location_message; + + /** + * @ORM\OneToMany(targetEntity="models\summit\SummitLocationImage", mappedBy="location", cascade={"persist"}, orphanRemoval=true) + * @var SummitLocationImage[] + */ + protected $images; + + + /** + * @param SummitVenueRoom|null $room + * @return string + */ + public function getFullAddress(SummitVenueRoom $room = null){ + $full_location = $this->getName().', '; + if(!is_null($room)){ + $floor = $room->getFloor(); + if(!is_null($floor)){ + $full_location .= $floor->getName().', '; + } + $full_location .= $room->getName().', '; + } + if(!empty($this->getAddress1())) + $full_location .= $this->getAddress1().', '; + if(!empty($this->getAddress2())) + $full_location .= $this->getAddress2().', '; + if(!empty($this->getCity())) + $full_location .= $this->getCity().', '; + if(!empty($this->getState())) + $full_location .= $this->getState().', '; + if(!empty($this->getZipCode())) + $full_location .= $this->getZipCode().', '; + if(!empty($this->getCountry)) + $full_location .= $this->getCountry().', '; + return rtrim($full_location, ', '); + } /** * @return mixed */ @@ -229,66 +318,6 @@ class SummitGeoLocatedLocation extends SummitAbstractLocation $this->location_message = $location_message; } - /** - * @ORM\Column(name="Address2", type="string") - */ - protected $address2; - - /** - * @ORM\Column(name="ZipCode", type="string") - */ - protected $zip_code; - - /** - * @ORM\Column(name="City", type="string") - */ - protected $city; - - /** - * @ORM\Column(name="State", type="string") - */ - protected $state; - - /** - * @ORM\Column(name="Country", type="string") - */ - protected $country; - - /** - * @ORM\Column(name="WebSiteUrl", type="string") - */ - protected $website_url; - - /** - * @ORM\Column(name="Lng", type="string") - */ - protected $lng; - - /** - * @ORM\Column(name="Lat", type="string") - */ - protected $lat; - - /** - * @ORM\Column(name="DisplayOnSite", type="boolean") - */ - protected $display_on_site; - - /** - * @ORM\Column(name="DetailsPage", type="boolean") - */ - protected $details_page; - - /** - * @ORM\Column(name="LocationMessage", type="string") - */ - protected $location_message; - - /** - * @ORM\OneToMany(targetEntity="models\summit\SummitLocationImage", mappedBy="location", cascade={"persist"}) - * @var SummitLocationImage[] - */ - protected $images; public function __construct() { diff --git a/app/Models/Foundation/Summit/Locations/SummitLocationImage.php b/app/Models/Foundation/Summit/Locations/SummitLocationImage.php index 4dabee72..1cec7866 100644 --- a/app/Models/Foundation/Summit/Locations/SummitLocationImage.php +++ b/app/Models/Foundation/Summit/Locations/SummitLocationImage.php @@ -159,9 +159,9 @@ class SummitLocationImage extends SilverstripeBaseModel protected $picture; /** - * @ORM\ManyToOne(targetEntity="models\summit\SummitAbstractLocation") + * @ORM\ManyToOne(targetEntity="models\summit\SummitGeoLocatedLocation", inversedBy="images") * @ORM\JoinColumn(name="LocationID", referencedColumnName="ID") - * @var SummitAbstractLocation + * @var SummitGeoLocatedLocation */ protected $location; diff --git a/app/Models/Foundation/Summit/Repositories/IAbstractCalendarSyncWorkRequestRepository.php b/app/Models/Foundation/Summit/Repositories/IAbstractCalendarSyncWorkRequestRepository.php new file mode 100644 index 00000000..5954c677 --- /dev/null +++ b/app/Models/Foundation/Summit/Repositories/IAbstractCalendarSyncWorkRequestRepository.php @@ -0,0 +1,49 @@ +time_zone_id; - if(empty($time_zone_id)) return $value; - $time_zone_list = timezone_identifiers_list(); + $summit_time_zone = $this->getTimeZone(); - if(isset($time_zone_list[$time_zone_id]) && !empty($value)) + if(!is_null($summit_time_zone) && !empty($value)) { $utc_timezone = new DateTimeZone("UTC"); - $time_zone_name = $time_zone_list[$time_zone_id]; - $summit_time_zone = new DateTimeZone($time_zone_name); $timestamp = $value->format('Y-m-d H:i:s'); $local_date = new DateTime($timestamp, $summit_time_zone); return $local_date->setTimezone($utc_timezone); @@ -380,6 +377,19 @@ class Summit extends SilverstripeBaseModel return null; } + /** + * @return DateTimeZone|null + */ + public function getTimeZone(){ + $time_zone_id = $this->time_zone_id; + if(empty($time_zone_id)) return null; + $time_zone_list = timezone_identifiers_list(); + if(isset($time_zone_list[$time_zone_id])){ + $time_zone_name = $time_zone_list[$time_zone_id]; + return new DateTimeZone($time_zone_name); + } + return null; + } /** * @param DateTime $value * @return null|DateTime @@ -992,4 +1002,13 @@ SQL; return $builder->getQuery()->getResult(); } + /** + * @return string + */ + public function getSlug(){ + $res = "openstack-".$this->name.'-'; + $res .= $this->begin_date->format('Y').'-summit'; + $res = strtolower( preg_replace('/[^a-zA-Z0-9\-]/', '',$res)); + return $res; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/SummitOwned.php b/app/Models/Foundation/Summit/SummitOwned.php index 7aa800dc..f40e439e 100644 --- a/app/Models/Foundation/Summit/SummitOwned.php +++ b/app/Models/Foundation/Summit/SummitOwned.php @@ -21,7 +21,7 @@ use Doctrine\ORM\Mapping AS ORM; trait SummitOwned { /** - * @ORM\ManyToOne(targetEntity="Summit", cascade={"persist"}) + * @ORM\ManyToOne(targetEntity="models\summit\Summit") * @ORM\JoinColumn(name="SummitID", referencedColumnName="ID") * @var Summit */ diff --git a/app/Models/ResourceServer/AccessTokenService.php b/app/Models/ResourceServer/AccessTokenService.php index b34426f0..2597f10c 100644 --- a/app/Models/ResourceServer/AccessTokenService.php +++ b/app/Models/ResourceServer/AccessTokenService.php @@ -181,38 +181,42 @@ final class AccessTokenService implements IAccessTokenService if (empty($auth_server_url)) { throw new ConfigurationException('app.openstackid_base_url param is missing!'); } - - $response = $client->post( - $auth_server_url . '/oauth2/token/introspection', + // http://docs.guzzlephp.org/en/stable/request-options.html + $response = $client->request('POST', + "{$auth_server_url}/oauth2/token/introspection", [ - 'body' => ['token' => $token_value], - 'headers' => ['Authorization' => " Basic " . base64_encode($client_id . ':' . $client_secret)] + 'form_params' => ['token' => $token_value], + 'auth' => [$client_id, $client_secret], + 'timeout' => 120, + 'http_errors' => true ] ); - $content_type = $response->getHeader('content-type'); + $content_type = $response->getHeaderLine('content-type'); if(!str_contains($content_type, 'application/json')) { // invalid content type throw new \Exception($response->getBody()); } - $token_info = $response->json(); + $token_info = json_decode($response->getBody()->getContents(), true); return $token_info; } - catch (RequestException $ex) - { + catch (RequestException $ex) { + Log::warning($ex->getMessage()); - $response = $ex->getResponse(); + $response = $ex->getResponse(); + if(is_null($response)) throw new OAuth2InvalidIntrospectionResponse(sprintf('http code %s', $ex->getCode())); - $content_type = $response->getHeader('content-type'); + $content_type = $response->getHeaderLine('content-type'); $is_json = str_contains($content_type, 'application/json'); - $body = ($is_json) ? $response->json(): $response->getBody(); + $body = $response->getBody()->getContents(); + $body = $is_json ? json_decode($body, true): $body; + $code = $response->getStatusCode(); - $code = $response->getStatusCode(); if ($code === 400 && $is_json && isset($body['error']) && ( $body['error'] === OAuth2Protocol::OAuth2Protocol_Error_InvalidToken || @@ -227,7 +231,7 @@ final class AccessTokenService implements IAccessTokenService $this->cache_service->setSingleValue(md5($token_value).'.revoked', md5($token_value)); throw new InvalidGrantTypeException(OAuth2Protocol::OAuth2Protocol_Error_InvalidToken); } - throw new OAuth2InvalidIntrospectionResponse(sprintf('http code %s - body %s', $ex->getCode(), $response->getBody())); + throw new OAuth2InvalidIntrospectionResponse(sprintf('http code %s - body %s', $ex->getCode(), $body)); } } } \ No newline at end of file diff --git a/app/Models/ResourceServer/Api.php b/app/Models/ResourceServer/Api.php index fedbb65f..503f4098 100644 --- a/app/Models/ResourceServer/Api.php +++ b/app/Models/ResourceServer/Api.php @@ -26,7 +26,7 @@ class Api extends ResourceServerEntity implements IApi { /** - * @ORM\OneToMany(targetEntity="ApiScope", mappedBy="api", cascade={"persist"}) + * @ORM\OneToMany(targetEntity="ApiScope", mappedBy="api", cascade={"persist"}, orphanRemoval=true) */ private $scopes; diff --git a/app/Models/ResourceServer/ApiEndpoint.php b/app/Models/ResourceServer/ApiEndpoint.php index 35ff0d88..78d12da4 100644 --- a/app/Models/ResourceServer/ApiEndpoint.php +++ b/app/Models/ResourceServer/ApiEndpoint.php @@ -171,7 +171,7 @@ class ApiEndpoint extends ResourceServerEntity implements IApiEndpoint $this->http_method = $http_method; } /** - * @ORM\ManyToOne(targetEntity="Api", cascade={"persist"}) + * @ORM\ManyToOne(targetEntity="Api", cascade={"persist"}, inversedBy="endpoints") * @ORM\JoinColumn(name="api_id", referencedColumnName="id") * @var Api */ diff --git a/app/Models/ResourceServer/ApiScope.php b/app/Models/ResourceServer/ApiScope.php index 2dc93ce6..d46ee765 100644 --- a/app/Models/ResourceServer/ApiScope.php +++ b/app/Models/ResourceServer/ApiScope.php @@ -40,7 +40,7 @@ class ApiScope extends ResourceServerEntity implements IApiScope } /** - * @ORM\ManyToOne(targetEntity="Api", cascade={"persist"}) + * @ORM\ManyToOne(targetEntity="Api", inversedBy="scopes") * @ORM\JoinColumn(name="api_id", referencedColumnName="id") * @var Api */ diff --git a/app/Repositories/RepositoriesProvider.php b/app/Repositories/RepositoriesProvider.php index 4d84e080..bf7a5129 100644 --- a/app/Repositories/RepositoriesProvider.php +++ b/app/Repositories/RepositoriesProvider.php @@ -139,5 +139,22 @@ final class RepositoriesProvider extends ServiceProvider return EntityManager::getRepository(\models\summit\RSVP::class); }); + App::singleton( + 'models\summit\IAbstractCalendarSyncWorkRequestRepository', + function(){ + return EntityManager::getRepository(\models\summit\CalendarSync\WorkQueue\AbstractCalendarSyncWorkRequest::class); + }); + + App::singleton( + 'models\summit\ICalendarSyncInfoRepository', + function(){ + return EntityManager::getRepository(\models\summit\CalendarSync\CalendarSyncInfo::class); + }); + + App::singleton( + 'models\summit\IScheduleCalendarSyncInfoRepository', + function(){ + return EntityManager::getRepository(\models\summit\CalendarSync\ScheduleCalendarSyncInfo::class); + }); } } \ No newline at end of file diff --git a/app/Repositories/Summit/Doctrine/DoctrineAbstractCalendarSyncWorkRequestRepository.php b/app/Repositories/Summit/Doctrine/DoctrineAbstractCalendarSyncWorkRequestRepository.php new file mode 100644 index 00000000..10e65814 --- /dev/null +++ b/app/Repositories/Summit/Doctrine/DoctrineAbstractCalendarSyncWorkRequestRepository.php @@ -0,0 +1,149 @@ +getEntityManager() + ->createQueryBuilder() + ->select("r") + ->from(MemberEventScheduleSummitActionSyncWorkRequest::class, "r") + ->join('r.summit_event', 'e', Join::WITH, " e.id = :event_id") + ->join('r.owner', 'o', Join::WITH, " o.id = :member_id") + ->join('r.calendar_sync_info', 'si', Join::WITH, " si.id = :calendar_sync_info_id"); + if(!empty($type)){ + $query = $query + ->where('r.type = :type') + ->setParameter('type', $type)->getQuery(); + } + + $query + ->setParameter('event_id', $event->getId()) + ->setParameter('member_id', $member->getId()) + ->setParameter('calendar_sync_info_id', $calendar_sync_info->getId()); + + return $query->getSingleResult(); + } + + /** + * @param string $provider + * @param PagingInfo $paging_info + * @return PagingResponse + */ + public function getUnprocessedMemberScheduleWorkRequestActionByPage($provider = 'ALL', PagingInfo $paging_info){ + + log::debug(sprintf("DoctrineAbstractCalendarSyncWorkRequestRepository::getUnprocessedMemberScheduleWorkRequestActionByPage: provider %s",$provider)); + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("r") + ->from(MemberScheduleSummitActionSyncWorkRequest::class, "r") + ->where('(r.type = :type_add or r.type = :type_remove or r.type = :type_update) and r.is_processed = 0') + ->orderBy('r.id', 'ASC') + ->setParameter('type_add',AbstractCalendarSyncWorkRequest::TypeAdd ) + ->setParameter('type_update',AbstractCalendarSyncWorkRequest::TypeUpdate ) + ->setParameter('type_remove',AbstractCalendarSyncWorkRequest::TypeRemove); + + if(CalendarSyncInfo::isValidProvider($provider)){ + log::debug(sprintf("provider %s is valid",$provider)); + $query = $query + ->join('r.calendar_sync_info', 'si', Join::WITH, " si.provider = :provider") + ->setParameter('provider', $provider); + } + $query = $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $paginator = new Paginator($query, $fetchJoinCollection = true); + $total = $paginator->count(); + $data = []; + + foreach($paginator as $entity) + $data[] = $entity; + + return new PagingResponse + ( + $total, + $paging_info->getPerPage(), + $paging_info->getCurrentPage(), + $paging_info->getLastPage($total), + $data + ); + } + + /** + * @param PagingInfo $paging_info + * @return PagingResponse + */ + public function getUnprocessedAdminScheduleWorkRequestActionByPage(PagingInfo $paging_info){ + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("r") + ->from(AdminScheduleSummitActionSyncWorkRequest::class, "r") + ->where('(r.type = :type_add or r.type = :type_remove or r.type = :type_update) and r.is_processed = 0') + ->orderBy('r.id', 'ASC') + ->setParameter('type_add',AbstractCalendarSyncWorkRequest::TypeAdd ) + ->setParameter('type_update',AbstractCalendarSyncWorkRequest::TypeUpdate ) + ->setParameter('type_remove',AbstractCalendarSyncWorkRequest::TypeRemove); + + $query= $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $paginator = new Paginator($query, $fetchJoinCollection = true); + $total = $paginator->count(); + $data = []; + + foreach($paginator as $entity) + $data[] = $entity; + + return new PagingResponse + ( + $total, + $paging_info->getPerPage(), + $paging_info->getCurrentPage(), + $paging_info->getLastPage($total), + $data + ); + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/Doctrine/DoctrineCalendarSyncInfoRepository.php b/app/Repositories/Summit/Doctrine/DoctrineCalendarSyncInfoRepository.php new file mode 100644 index 00000000..d9d0024f --- /dev/null +++ b/app/Repositories/Summit/Doctrine/DoctrineCalendarSyncInfoRepository.php @@ -0,0 +1,27 @@ +getEntityManager() + ->createQueryBuilder() + ->select("si") + ->from(ScheduleCalendarSyncInfo::class, "si") + ->join('si.summit_event', 'e', Join::WITH, " e.id = :event_id") + ->join('si.calendar_sync_info', 'ci', Join::WITH, " ci.revoked = :credential_status") + ->orderBy('si.id', 'ASC') + ->setParameter('event_id', $summit_event->getId()) + ->setParameter('credential_status',false); + + $query= $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $paginator = new Paginator($query, $fetchJoinCollection = true); + $total = $paginator->count(); + $data = []; + + foreach($paginator as $entity) + $data[] = $entity; + + return new PagingResponse + ( + $total, + $paging_info->getPerPage(), + $paging_info->getCurrentPage(), + $paging_info->getLastPage($total), + $data + ); + } + + /** + * @param SummitAbstractLocation $location + * @param PagingInfo $paging_info + * @return PagingResponse + */ + public function getAllBySummitLocation(SummitAbstractLocation $location, PagingInfo $paging_info) + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("si") + ->from(ScheduleCalendarSyncInfo::class, "si") + ->join('si.location', 'l', Join::WITH, " l.id = :location_id") + ->join('si.calendar_sync_info', 'ci', Join::WITH, " ci.revoked = :crendential_status") + ->orderBy('si.id', 'ASC') + ->setParameter('location_id', $location->getId()) + ->setParameter('crendential_status',false); + + $query= $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $paginator = new Paginator($query, $fetchJoinCollection = true); + $total = $paginator->count(); + $data = []; + + foreach($paginator as $entity) + $data[] = $entity; + + return new PagingResponse + ( + $total, + $paging_info->getPerPage(), + $paging_info->getCurrentPage(), + $paging_info->getLastPage($total), + $data + ); + } + +} \ No newline at end of file diff --git a/app/Repositories/Summit/Doctrine/DoctrineSummitNotificationRepository.php b/app/Repositories/Summit/Doctrine/DoctrineSummitNotificationRepository.php index 07e446e2..4714268e 100644 --- a/app/Repositories/Summit/Doctrine/DoctrineSummitNotificationRepository.php +++ b/app/Repositories/Summit/Doctrine/DoctrineSummitNotificationRepository.php @@ -17,6 +17,7 @@ use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Tools\Pagination\Paginator; use models\summit\ISummitNotificationRepository; use models\summit\Summit; +use models\summit\SummitPushNotification; use repositories\SilverStripeDoctrineRepository; use utils\Filter; use utils\Order; @@ -44,7 +45,7 @@ final class DoctrineSummitNotificationRepository { $query = $this->getEntityManager()->createQueryBuilder() ->select("n") - ->from(\models\summit\SummitPushNotification::class, "n") + ->from(SummitPushNotification::class, "n") ->leftJoin('n.summit_event', 'e') ->join('n.summit', 's', Join::WITH, " s.id = :summit_id") ->setParameter('summit_id', $summit->getId()); diff --git a/app/Services/Apis/CalendarSync/AbstractCalendarSyncRemoteFacade.php b/app/Services/Apis/CalendarSync/AbstractCalendarSyncRemoteFacade.php new file mode 100644 index 00000000..fd203daa --- /dev/null +++ b/app/Services/Apis/CalendarSync/AbstractCalendarSyncRemoteFacade.php @@ -0,0 +1,42 @@ +sync_calendar_info = $sync_calendar_info; + } + + /** + * @return mixed + */ + abstract public function getSleepInterval(); +} \ No newline at end of file diff --git a/app/Services/Apis/CalendarSync/CalendarSyncRemoteFacadeFactory.php b/app/Services/Apis/CalendarSync/CalendarSyncRemoteFacadeFactory.php new file mode 100644 index 00000000..b151c780 --- /dev/null +++ b/app/Services/Apis/CalendarSync/CalendarSyncRemoteFacadeFactory.php @@ -0,0 +1,56 @@ +getProvider()){ + case CalendarSyncInfo::ProviderGoogle: + return new GoogleCalendarSyncRemoteFacade($sync_calendar_info); + break; + case CalendarSyncInfo::ProvideriCloud: + return new ICloudCalendarSyncRemoteFacade($sync_calendar_info); + break; + case CalendarSyncInfo::ProviderOutlook: + return new OutlookCalendarSyncRemoteFacade($sync_calendar_info); + break; + } + return null; + } +} \ No newline at end of file diff --git a/app/Services/Apis/CalendarSync/Exceptions/RateLimitExceededException.php b/app/Services/Apis/CalendarSync/Exceptions/RateLimitExceededException.php new file mode 100644 index 00000000..e763f6c7 --- /dev/null +++ b/app/Services/Apis/CalendarSync/Exceptions/RateLimitExceededException.php @@ -0,0 +1,23 @@ +client = new \Google_Client(); + $this->client->setClientId(Config::get("google_api.google_client_id")); + $this->client->setClientSecret(Config::get("google_api.google_client_secret")); + //$this->client->setRedirectUri(Config::get("google_api.google_redirect_url")); + $this->client->setScopes(explode(',', Config::get("google_api.google_scopes"))); + $this->client->setApprovalPrompt('force'); + $this->client->setAccessType('offline'); + $this->client->setAccessToken($sync_calendar_info->getAccessToken()); + $this->checkAccessToken(); + } + + private function checkAccessToken(){ + if($this->client->isAccessTokenExpired()) + { + $creds = $this->client->fetchAccessTokenWithRefreshToken($this->sync_calendar_info->getRefreshToken()); + $access_token = isset($creds['access_token']) ? $creds['access_token'] : null; + $refresh_token = isset($creds['refresh_token']) ? $creds['refresh_token'] : null; + + if(!empty($access_token)) { + $this->sync_calendar_info->setAccessToken($creds); + } + + if(!empty($refresh_token)) + $this->sync_calendar_info->setRefreshToken($refresh_token); + } + } + + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @throws RateLimitExceededException + * @throws Google_Service_Exception + * @return ScheduleCalendarSyncInfo + */ + public function addEvent(MemberEventScheduleSummitActionSyncWorkRequest $request) + { + try { + $this->checkAccessToken(); + $service = new Google_Service_Calendar($this->client); + $summit_event = $request->getSummitEvent(); + $vo = $this->buildEventVO($summit_event); + $calendar_id = $this->sync_calendar_info->getExternalId(); + $created_event = $service->events->insert($calendar_id, $vo); + + // new schedule sync info + $sync_info = new ScheduleCalendarSyncInfo(); + // primitives + $sync_info->setEtag($created_event->getEtag()); + $sync_info->setExternalId($created_event->getId()); + $sync_info->setExternalUrl($created_event->getHtmlLink()); + // relationships + $sync_info->setSummitEvent($summit_event); + $sync_info->setCalendarSyncInfo($this->sync_calendar_info); + $sync_info->setLocation($summit_event->getLocation()); + return $sync_info; + } + catch(Google_Service_Exception $ex1){ + Log::warning($ex1); + if($ex1->getCode() == 403) + throw new RateLimitExceededException($ex1->getMessage(), $ex1->getCode()); + throw $ex1; + } + catch (Exception $ex){ + Log::error($ex); + return null; + } + } + + /** + * @param SummitEvent $summit_event + * @param bool $update + * @return Google_Service_Calendar_Event + */ + private function buildEventVO(SummitEvent $summit_event, $update = false){ + $vo = new Google_Service_Calendar_Event(); + $title = $summit_event->getTitle(); + if($update) $title = "{$title} [UPDATED]"; + $vo->setSummary($title); + $vo->setDescription($summit_event->getAbstract()); + + $location = null; + + if($summit_event->hasLocation()){ + $venue = $summit_event->getLocation(); + $room = null; + if($venue instanceof SummitVenueRoom){ + $room = $venue; + $venue = $venue->getVenue(); + } + if($venue instanceof SummitGeoLocatedLocation) { + $location = $venue->getFullAddress($room); + } + } + + if(!empty($location)) + $vo->setLocation($location); + + // dates + + $time_zone = $summit_event->getSummit()->getTimeZone()->getName(); + $start = new Google_Service_Calendar_EventDateTime(); + $start->setDateTime($summit_event->getLocalStartDate()->format(DateTime::RFC3339)); + $start->setTimeZone($time_zone); + $vo->setStart($start); + + $end = new Google_Service_Calendar_EventDateTime(); + $end->setDateTime($summit_event->getLocalEndDate()->format(DateTime::RFC3339)); + $end->setTimeZone($time_zone); + $vo->setEnd($end); + + return $vo; + } + + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @param ScheduleCalendarSyncInfo $schedule_sync_info + * @throws RateLimitExceededException + * @throws Google_Service_Exception + * @return bool + */ + public function deleteEvent + ( + MemberEventScheduleSummitActionSyncWorkRequest $request, + ScheduleCalendarSyncInfo $schedule_sync_info + ) + { + try{ + $this->checkAccessToken(); + $service = new Google_Service_Calendar($this->client); + $calendar_id = $this->sync_calendar_info->getExternalId(); + $res = $service->events->delete($calendar_id, $schedule_sync_info->getExternalId()); + if(!$res instanceof Response) return false; + return $res->getStatusCode() == 204; + } + catch(Google_Service_Exception $ex1){ + Log::warning($ex1); + if($ex1->getCode() == 404) return false; + if($ex1->getCode() == 403) + throw new RateLimitExceededException($ex1->getMessage(), $ex1->getCode()); + throw $ex1; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @param ScheduleCalendarSyncInfo $schedule_sync_info + * @throws RateLimitExceededException + * @throws Google_Service_Exception + * @return bool + */ + public function updateEvent + ( + MemberEventScheduleSummitActionSyncWorkRequest $request, + ScheduleCalendarSyncInfo $schedule_sync_info + ) + { + try{ + $this->checkAccessToken(); + $service = new Google_Service_Calendar($this->client); + $summit_event = $request->getSummitEvent(); + $vo = $this->buildEventVO($summit_event, true); + $calendar_id = $this->sync_calendar_info->getExternalId(); + + $updated_event = $service->events->update($calendar_id, $schedule_sync_info->getExternalId(), $vo); + // primitives + $schedule_sync_info->setEtag($updated_event->getEtag()); + // relationships + $schedule_sync_info->setLocation($summit_event->getLocation()); + + return true; + } + catch(Google_Service_Exception $ex1){ + Log::warning($ex1); + if($ex1->getCode() == 403) + throw new RateLimitExceededException($ex1->getMessage(), $ex1->getCode()); + throw $ex1; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberCalendarScheduleSummitActionSyncWorkRequest $request + * @param CalendarSyncInfo $calendar_sync_info + * @throws RateLimitExceededException + * @throws Google_Service_Exception + * @return bool + */ + public function createCalendar + ( + MemberCalendarScheduleSummitActionSyncWorkRequest $request, + CalendarSyncInfo $calendar_sync_info + ) + { + try { + $this->checkAccessToken(); + $service = new Google_Service_Calendar($this->client); + $google_calendar = new Google_Service_Calendar_Calendar($this->client); + $google_calendar->setSummary($request->getCalendarName()); + $google_calendar->setDescription($request->getCalendarDescription()); + $google_calendar->setTimeZone($calendar_sync_info->getSummit()->getTimeZone()->getName()); + $created_calendar = $service->calendars->insert($google_calendar); + $calendar_id = $created_calendar->getId(); + Log::info(sprintf("GoogleCalendarSyncRemoteFacade::createCalendar: calendarId %s", $calendar_id)); + $this->sync_calendar_info->setExternalId($calendar_id); + $this->sync_calendar_info->setEtag($created_calendar->getEtag()); + return true; + } + catch(Google_Service_Exception $ex1){ + Log::warning($ex1); + if($ex1->getCode() == 403) + throw new RateLimitExceededException($ex1->getMessage(), $ex1->getCode()); + throw $ex1; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberCalendarScheduleSummitActionSyncWorkRequest $request + * @param CalendarSyncInfo $calendar_sync_info + * @throws RateLimitExceededException + * @throws Google_Service_Exception + * @return bool + */ + public function deleteCalendar + ( + MemberCalendarScheduleSummitActionSyncWorkRequest $request, + CalendarSyncInfo $calendar_sync_info + ) + { + try { + $this->checkAccessToken(); + $service = new Google_Service_Calendar($this->client); + Log::info(sprintf("GoogleCalendarSyncRemoteFacade::deleteCalendar: calendarId %s", $calendar_sync_info->getExternalId())); + $res = $service->calendars->delete($calendar_sync_info->getExternalId()); + if(!$res instanceof Response) return false; + return $res->getStatusCode() == 204; + } + catch(Google_Service_Exception $ex1){ + Log::warning($ex1); + if($ex1->getCode() == 404) return false; + if($ex1->getCode() == 403) + throw new RateLimitExceededException($ex1->getMessage(), $ex1->getCode()); + throw $ex1; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @return mixed + */ + public function getSleepInterval() + { + return 500; + } +} \ No newline at end of file diff --git a/app/Services/Apis/CalendarSync/ICalendarSyncRemoteFacade.php b/app/Services/Apis/CalendarSync/ICalendarSyncRemoteFacade.php new file mode 100644 index 00000000..26bd6e3a --- /dev/null +++ b/app/Services/Apis/CalendarSync/ICalendarSyncRemoteFacade.php @@ -0,0 +1,60 @@ +client = new CalDavClient( + $this->sync_calendar_info->getServer(), + $this->sync_calendar_info->getUserName(), + $this->sync_calendar_info->getUserPassword() + ); + } + + /** + * @param $prod_id + * @param SummitEvent $summit_event + * @param bool $update + * @return EventRequestVO + */ + private function buildEventVO($prod_id, SummitEvent $summit_event, $update = false){ + $location_name = null; + $location_title = null; + $location_lat = null; + $location_lng = null; + + if($summit_event->hasLocation()){ + $venue = $summit_event->getLocation(); + $room = null; + if($venue instanceof SummitVenueRoom){ + $room = $venue; + $venue = $venue->getVenue(); + } + $location_full_name = $venue->getName(); + if(!is_null($room)){ + if($room->hasFloor()){ + $location_full_name .= ' - '.$room->getFloor()->getName(); + } + $location_full_name .= ' - '.$room->getName(); + } + + $location_name = $location_full_name; + $location_title = $location_full_name; + if($venue instanceof SummitGeoLocatedLocation) { + $location_lat = $venue->getLat(); + $location_lng = $venue->getLng(); + } + } + + $title = $summit_event->getTitle(); + if($update) $title = "{$title} [UPDATED]"; + return new EventRequestVO( + $prod_id, + $title, + $summit_event->getAbstract(), + $summit_event->getSocialSummary(), + $summit_event->getLocalStartDate(), + $summit_event->getLocalEndDate(), + $summit_event->getSummit()->getTimeZone(), + $location_name, + $location_title, + $location_lat, + $location_lng + ); + } + + /** + * @param string $calendar_url + * @param string $event_url + * @return array + */ + private function getEventInfo($calendar_url, $event_url){ + $etag = null; + $vcard = null; + + try { + + $relative_resource_url = parse_url($event_url, PHP_URL_PATH); + + $events_response = $this->client->getEventsBy + ( + $calendar_url, [ + $relative_resource_url + ]); + + if ($events_response->isSuccessFull() && count($events_response->getResponses()) > 0) { + $etag = $events_response->getResponses()[0]->getETag(); + $vcard = $events_response->getResponses()[0]->getVCard(); + } + } + catch (\Exception $ex){ + + } + return [$etag, $vcard]; + } + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @return ScheduleCalendarSyncInfo + */ + public function addEvent(MemberEventScheduleSummitActionSyncWorkRequest $request) + { + try { + $summit_event = $request->getSummitEvent(); + $calendar_url = $this->sync_calendar_info->getCalendarUrl(); + $vo = $this->buildEventVO($this->sync_calendar_info->getCalendarDisplayName(), $summit_event); + $res = $this->client->createEvent( + $calendar_url, + $vo + ); + + $etag = $res->getETag(); + $vcard = ""; + + if (empty($etag)) { + list($etag, $vcard) = $this->getEventInfo($calendar_url, $res->getResourceUrl()); + } + + $sync_info = new ScheduleCalendarSyncInfo(); + // primitives + $sync_info->setEtag($etag); + $sync_info->setExternalId($res->getUid()); + $sync_info->setExternalUrl($res->getResourceUrl()); + $sync_info->setVCard($vcard); + // relationships + $sync_info->setSummitEvent($summit_event); + $sync_info->setCalendarSyncInfo($this->sync_calendar_info); + $sync_info->setLocation($summit_event->getLocation()); + + return $sync_info; + } + catch (Exception $ex){ + Log::error($ex); + return null; + } + } + + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @param ScheduleCalendarSyncInfo $schedule_sync_info + * @return bool + */ + public function updateEvent + ( + MemberEventScheduleSummitActionSyncWorkRequest $request, + ScheduleCalendarSyncInfo $schedule_sync_info + ) + { + try { + $summit_event = $request->getSummitEvent(); + $calendar_url = $this->sync_calendar_info->getCalendarUrl(); + $vo = $this->buildEventVO($this->sync_calendar_info->getCalendarDisplayName(), $summit_event, true); + $vo->setUID($schedule_sync_info->getExternalId()); + $res = $this->client->updateEvent( + $calendar_url, + $vo, + $schedule_sync_info->getEtag() + ); + + $etag = $res->getETag(); + $vcard = ""; + + if (empty($etag)) { + list($etag, $vcard) = $this->getEventInfo($calendar_url, $res->getResourceUrl()); + } + + // primitives + $schedule_sync_info->setEtag($etag); + $schedule_sync_info->setVCard($vcard); + // relationships + $schedule_sync_info->setLocation($summit_event->getLocation()); + return true; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @param ScheduleCalendarSyncInfo $schedule_sync_info + * @return bool + */ + public function deleteEvent(MemberEventScheduleSummitActionSyncWorkRequest $request, ScheduleCalendarSyncInfo $schedule_sync_info) + { + try{ + if(empty($schedule_sync_info->getEtag())) return false; + $res = $this->client->deleteEvent + ( + $this->sync_calendar_info->getCalendarUrl(), + $schedule_sync_info->getExternalId(), + $schedule_sync_info->getEtag() + ); + + return $res->isSuccessFull(); + return true; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberCalendarScheduleSummitActionSyncWorkRequest $request + * @param CalendarSyncInfo $calendar_sync_info + * @return bool + */ + public function createCalendar(MemberCalendarScheduleSummitActionSyncWorkRequest $request, CalendarSyncInfo $calendar_sync_info) + { + try{ + try { + // get calendar home url + $user_ppal_url = $this->sync_calendar_info->getUserPrincipalUrl(); + $res = $this->client->getCalendarHome + ( + $user_ppal_url + ); + $calendar_home = $res->getCalendarHomeSetUrl(); + $real_server = $res->getRealCalDAVHost(); + + // make calendar + $summit = $this->sync_calendar_info->getSummit(); + $calendar_url = $this->client->createCalendar($calendar_home, + new MakeCalendarRequestVO( + $request->getCalendarId(), + $request->getCalendarName(), + $request->getCalendarDescription(), + $summit->getTimeZone() + ) + ); + $calendar_url = rtrim($calendar_url, '/') . '/'; + } + catch(ForbiddenException $ex){ + // calendar already exists + $calendar_url = $calendar_home.'/'.$request->getCalendarId().'/'; + } + + $this->sync_calendar_info->setUserPrincipalUrl + ( + str_replace + ( + Config::get("apple_api.base_caldav_server"), + $real_server, + $user_ppal_url + ) + ); + + $this->sync_calendar_info->setCalendarDisplayName($request->getCalendarName()); + $this->sync_calendar_info->setExternalId($calendar_url); + + $res = $this->client->getCalendar($calendar_url); + $this->sync_calendar_info->setCalendarSyncToken($res->getSyncToken()); + return true; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberCalendarScheduleSummitActionSyncWorkRequest $request + * @param CalendarSyncInfo $calendar_sync_info + * @return bool + */ + public function deleteCalendar(MemberCalendarScheduleSummitActionSyncWorkRequest $request, CalendarSyncInfo $calendar_sync_info) + { + try { + $this->client->deleteCalendar($this->sync_calendar_info->getExternalId()); + return true; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @return mixed + */ + public function getSleepInterval() + { + return 500; + } +} \ No newline at end of file diff --git a/app/Services/Apis/CalendarSync/OutlookCalendarSyncRemoteFacade.php b/app/Services/Apis/CalendarSync/OutlookCalendarSyncRemoteFacade.php new file mode 100644 index 00000000..8dde0515 --- /dev/null +++ b/app/Services/Apis/CalendarSync/OutlookCalendarSyncRemoteFacade.php @@ -0,0 +1,299 @@ +client = new OutlookRestClient(); + $this->client->setAccessToken($sync_calendar_info->getAccessToken()); + $this->client->setTokenCallback(function($access_token){ + + $this->sync_calendar_info->setAccessToken($access_token); + + if(isset($access_token['refresh_token'])) + $this->sync_calendar_info->setRefreshToken($access_token['refresh_token']); + }); + + } + + + /** + * @param SummitEvent $summit_event + * @param bool $update + * @return EventVO + */ + private function buildEventVO(SummitEvent $summit_event, $update = false){ + + try { + $location_name = null; + $location_title = null; + $location_lat = null; + $location_lng = null; + $location_street = null; + $location_city = null; + $location_state = null; + $location_country = null; + $location_postal_code = null; + + if ($summit_event->hasLocation()) { + $venue = $summit_event->getLocation(); + $room = null; + if ($venue instanceof SummitVenueRoom) { + $room = $venue; + $venue = $venue->getVenue(); + } + $location_full_name = $venue->getName(); + if (!is_null($room)) { + if ($room->hasFloor()) { + $location_full_name .= ', ' . $room->getFloor()->getName(); + } + $location_full_name .= ', ' . $room->getName(); + } + + $location_name = $location_full_name; + $location_title = $location_full_name; + if ($venue instanceof SummitGeoLocatedLocation) { + $location_lat = $venue->getLat(); + $location_lng = $venue->getLng(); + $location_street = $venue->getAddress1(); + $location_city = $venue->getCity(); + $location_state = $venue->getState(); + $location_country = $venue->getCountry(); + $location_postal_code = $venue->getZipCode(); + } + } + $title = $summit_event->getTitle(); + if($update) $title = "{$title} [UPDATED]"; + return new EventVO( + $title, + $summit_event->getAbstract(), + $summit_event->getLocalStartDate(), + $summit_event->getLocalEndDate(), + $summit_event->getSummit()->getTimeZone(), + new LocationVO + ( + $location_name, + new AddressVO + ( + $location_street, + $location_city, + $location_state, + $location_country, + $location_postal_code + ), + $location_lat, + $location_lng + ) + ); + } + catch (Exception $ex){ + Log::error($ex); + return null; + } + } + + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @return ScheduleCalendarSyncInfo + */ + public function addEvent(MemberEventScheduleSummitActionSyncWorkRequest $request) + { + try { + $summit_event = $request->getSummitEvent(); + $vo = $this->buildEventVO($summit_event); + if(is_null($vo)) throw new LogicException(); + $calendar_id = $this->sync_calendar_info->getExternalId(); + $created_event = $this->client->createEvent($calendar_id, $vo); + // new schedule sync info + $sync_info = new ScheduleCalendarSyncInfo(); + // primitives + $sync_info->setEtag($created_event->getEtag()); + $sync_info->setExternalId($created_event->getId()); + $sync_info->setExternalUrl($created_event->getDataId()); + // relationships + $sync_info->setSummitEvent($summit_event); + $sync_info->setCalendarSyncInfo($this->sync_calendar_info); + $sync_info->setLocation($summit_event->getLocation()); + return $sync_info; + } + catch (Exception $ex){ + Log::error($ex); + return null; + } + } + + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @param ScheduleCalendarSyncInfo $schedule_sync_info + * @return bool + */ + public function deleteEvent + ( + MemberEventScheduleSummitActionSyncWorkRequest $request, + ScheduleCalendarSyncInfo $schedule_sync_info + ) + { + try { + $res = $this->client->deleteEvent($schedule_sync_info->getExternalId()); + return !($res instanceof ErrorResponse); + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberEventScheduleSummitActionSyncWorkRequest $request + * @param ScheduleCalendarSyncInfo $schedule_sync_info + * @return bool + */ + public function updateEvent + ( + MemberEventScheduleSummitActionSyncWorkRequest $request, + ScheduleCalendarSyncInfo $schedule_sync_info + ) + { + try { + $summit_event = $request->getSummitEvent(); + $vo = $this->buildEventVO($summit_event, true); + if(is_null($vo)) throw new LogicException(); + $event_id = $schedule_sync_info->getExternalId(); + $updated_event = $this->client->updateEvent($event_id, $vo); + // primitives + $schedule_sync_info->setEtag($updated_event->getEtag()); + // relationships + $schedule_sync_info->setLocation($summit_event->getLocation()); + return true; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberCalendarScheduleSummitActionSyncWorkRequest $request + * @param CalendarSyncInfo $calendar_sync_info + * @return bool + */ + public function createCalendar + ( + MemberCalendarScheduleSummitActionSyncWorkRequest $request, + CalendarSyncInfo $calendar_sync_info + ) + { + try { + $res = $this->client->createCalendar(new CalendarVO + ( + $request->getCalendarName() + )); + + if ($res instanceof CalendarResponse) { + + $this->sync_calendar_info->setExternalId($res->getId()); + $this->sync_calendar_info->setEtag($res->getChangeKey()); + return true; + } + + return false; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param MemberCalendarScheduleSummitActionSyncWorkRequest $request + * @param CalendarSyncInfo $calendar_sync_info + * @return bool + */ + public function deleteCalendar + ( + MemberCalendarScheduleSummitActionSyncWorkRequest $request, + CalendarSyncInfo $calendar_sync_info + ) + { + try { + do { + $res = $this->client->deleteCalendar($calendar_sync_info->getExternalId()); + $deleted = is_bool($res) ? $res : false; + if ($res instanceof ErrorResponse) { + if($res->getErrorCode() == "ErrorItemNotFound"){$delete = true; break;} + // @see https://stackoverflow.com/questions/31923669/office-365-unified-api-error-when-deleting-a-calendar + // @see https://stackoverflow.com/questions/44597230/office365-calendar-rest-api-cannot-delete-calendars + // change name ... + $this->client->updateCalendar($calendar_sync_info->getExternalId(), new CalendarVO( + md5(uniqid(mt_rand(), true)) + )); + } + + } while (!$deleted); + return $deleted; + } + catch (Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @return mixed + */ + public function getSleepInterval() + { + return 500; + } +} \ No newline at end of file diff --git a/app/Services/Apis/EventbriteAPI.php b/app/Services/Apis/EventbriteAPI.php index e16a2542..df06ac90 100644 --- a/app/Services/Apis/EventbriteAPI.php +++ b/app/Services/Apis/EventbriteAPI.php @@ -1,7 +1,4 @@ - $this->auth_info['token'] - ); + $client = new Client(); - foreach($params as $param => $value) - { - $query[$param] = $value; - } - - $response = $client->get($api_url, array + $query = array ( - 'query' => $query - ) - ); + 'token' => $this->auth_info['token'] + ); - if($response->getStatusCode() !== 200) throw new Exception('invalid status code!'); - $content_type = $response->getHeader('content-type'); - if(empty($content_type)) throw new Exception('invalid content type!'); - if($content_type !== 'application/json') throw new Exception('invalid content type!'); + foreach ($params as $param => $value) { + $query[$param] = $value; + } - $json = $response->getBody()->getContents(); - return json_decode($json, true); + $response = $client->get($api_url, array + ( + 'query' => $query + ) + ); + if ($response->getStatusCode() !== 200) + throw new Exception('invalid status code!'); + $content_type = $response->getHeaderLine('content-type'); + if (empty($content_type)) + throw new Exception('invalid content type!'); + if ($content_type !== 'application/json') + throw new Exception('invalid content type!'); + + $json = $response->getBody()->getContents(); + return json_decode($json, true); + } + catch(RequestException $ex){ + Log::warning($ex->getMessage()); + throw $ex; + } } /** @@ -73,7 +88,7 @@ final class EventbriteAPI implements IEventbriteAPI public function getOrder($order_id) { $order_id = intval($order_id); - $url = sprintf('%s/orders/%s', self::BaseUrl, $order_id); + $url = sprintf('%s/orders/%s', self::BaseUrl, $order_id); return $this->getEntity($url, array('expand' => 'attendees')); } } \ No newline at end of file diff --git a/app/Services/Apis/FireBaseGCMApi.php b/app/Services/Apis/FireBaseGCMApi.php index d50ede45..694aafe3 100644 --- a/app/Services/Apis/FireBaseGCMApi.php +++ b/app/Services/Apis/FireBaseGCMApi.php @@ -12,8 +12,11 @@ * limitations under the License. **/ use GuzzleHttp\Client; +use GuzzleHttp\Exception\ClientException; use models\main\PushNotificationMessagePriority; use Illuminate\Support\Facades\Log; +use Exception; + /** * Class FireBaseGCMApi * @package services\apis @@ -56,20 +59,19 @@ final class FireBaseGCMApi implements IPushNotificationApi $response = $client->post($endpoint, [ 'headers' => [ 'Authorization' => sprintf('key=%s', $this->api_server_key), - 'Content-Type' => 'application/json' ], - 'body' => json_encode($message) + 'json' => $message ]); if ($response->getStatusCode() !== 200) $res = $res && false; } return $res; } - catch (\GuzzleHttp\Exception\ClientException $ex1){ + catch (ClientException $ex1){ Log::error($ex1->getMessage()); return false; } - catch(\Exception $ex){ + catch(Exception $ex){ Log::error($ex->getMessage()); return false; } diff --git a/app/Services/Model/AdminActionsCalendarSyncPreProcessor.php b/app/Services/Model/AdminActionsCalendarSyncPreProcessor.php new file mode 100644 index 00000000..cf25a811 --- /dev/null +++ b/app/Services/Model/AdminActionsCalendarSyncPreProcessor.php @@ -0,0 +1,67 @@ +queue_manager = $queue_manager; + $this->strategy_factory = $strategy_factory; + } + + /** + * @param array $requests + * @return array + */ + public function preProcessActions(array $requests) + { + foreach ($requests as $request){ + $strategy = $this->strategy_factory->build($this->queue_manager, $request); + if(is_null($strategy)) continue; + $request = $strategy->process($request); + if(!is_null($request)) + $this->queue_manager->registerRequest($request); + } + + return $this->queue_manager->getPurgedRequests(); + } +} \ No newline at end of file diff --git a/app/Services/Model/AdminActionsCalendarSyncProcessingService.php b/app/Services/Model/AdminActionsCalendarSyncProcessingService.php new file mode 100644 index 00000000..3c23640f --- /dev/null +++ b/app/Services/Model/AdminActionsCalendarSyncProcessingService.php @@ -0,0 +1,166 @@ +work_request_repository = $work_request_repository; + $this->calendar_sync_repository = $calendar_sync_repository; + $this->schedule_sync_repository = $schedule_sync_repository; + $this->preprocessor_requests = $preprocessor_requests; + $this->tx_manager = $tx_manager; + } + + /** + * @param int $batch_size + * @return int + */ + public function processActions($batch_size = PHP_INT_MAX) + { + return $this->tx_manager->transaction(function() use($batch_size){ + $count = 0; + + $res = $this->work_request_repository->getUnprocessedAdminScheduleWorkRequestActionByPage + ( + new PagingInfo(1, $batch_size) + ); + + foreach ($this->preprocessor_requests->preProcessActions($res->getItems()) as $request){ + + try { + if (!$request instanceof AdminScheduleSummitActionSyncWorkRequest) continue; + + if($request instanceof AdminSummitEventActionSyncWorkRequest){ + + $page = 1; + $summit_event = $request->getSummitEvent(); + + do{ + $page_response = $this->schedule_sync_repository->getAllBySummitEvent($summit_event, new PagingInfo($page, 1000)); + $has_more = count($page_response->getItems()) > 0; + if(!$has_more) continue; + foreach ($page_response->getItems() as $schedule_event){ + if(!$schedule_event instanceof ScheduleCalendarSyncInfo) continue; + $work_request = new MemberEventScheduleSummitActionSyncWorkRequest(); + $work_request->setType($request->getType()); + $work_request->setCalendarSyncInfo($schedule_event->getCalendarSyncInfo()); + $work_request->setOwner($schedule_event->getMember()); + $work_request->setSummitEvent($summit_event); + $this->work_request_repository->add($work_request); + } + $page++; + + }while($has_more); + } + + if($request instanceof AdminSummitLocationActionSyncWorkRequest){ + $location = $request->getLocation(); + $page = 1; + + do{ + $page_response = $this->schedule_sync_repository->getAllBySummitLocation($location, new PagingInfo($page, 1000)); + $has_more = count($page_response->getItems()) > 0; + if(!$has_more) continue; + foreach ($page_response->getItems() as $schedule_event){ + if(!$schedule_event instanceof ScheduleCalendarSyncInfo) continue; + $work_request = new MemberEventScheduleSummitActionSyncWorkRequest(); + // always is update no matter what + $work_request->setType(AbstractCalendarSyncWorkRequest::TypeUpdate); + $work_request->setCalendarSyncInfo($schedule_event->getCalendarSyncInfo()); + $work_request->setOwner($schedule_event->getMember()); + $work_request->setSummitEvent($summit_event); + $this->work_request_repository->add($work_request); + } + $page++; + + }while($has_more); + } + + $request->markProcessed(); + $count++; + } + catch(DBALException $ex1){ + echo 'DBALException !!'.PHP_EOL; + Log::error($ex1); + } + catch(Exception $ex6){ + echo 'Exception !!'.PHP_EOL; + Log::error($ex6); + } + } + return $count; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/AdminScheduleWorkQueueManager.php b/app/Services/Model/AdminScheduleWorkQueueManager.php new file mode 100644 index 00000000..e302f941 --- /dev/null +++ b/app/Services/Model/AdminScheduleWorkQueueManager.php @@ -0,0 +1,152 @@ +getSummitEvent()->getId(); + } + if($request instanceof AdminSummitLocationActionSyncWorkRequest){ + $location_id = $request->getLocation()->getId(); + } + return $this->generateKey($request->getType(), $event_id, $location_id); + } + + /** + * @param string $type + * @param int $event_id + * @param int $location_id + * @return string + */ + private function generateKey($type, $event_id = null, $location_id = null){ + $sub_type = !is_null($event_id) ? AdminSummitEventActionSyncWorkRequest::SubType : AdminSummitLocationActionSyncWorkRequest::SubType; + $id = !is_null($event_id) ? $event_id : $location_id; + $key = "{$sub_type}_{$type}_{$id}"; + return $key; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return bool + */ + public function registerRequest(AbstractCalendarSyncWorkRequest $request){ + $key = $this->getKey($request); + if(isset($this->registered_requests[$key])) return false; + $this->registered_requests[$key] = $request; + return true; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return bool + */ + public function removeRequest(AbstractCalendarSyncWorkRequest $request){ + $key = $this->getKey($request); + if(isset($this->registered_requests[$key])){ + unset($this->registered_requests[$key]); + return true; + } + return false; + } + + /** + * @param int $event_id + * @param string $type + * @return AdminSummitEventActionSyncWorkRequest[] + */ + public function getSummitEventRequestFor($event_id, $type = null){ + $types = [ + AbstractCalendarSyncWorkRequest::TypeAdd, + AbstractCalendarSyncWorkRequest::TypeRemove, + AbstractCalendarSyncWorkRequest::TypeUpdate, + ]; + + if(!empty($type)) $types = [$type]; + $list = []; + foreach ($types as $t){ + $key = $this->generateKey($t, $event_id); + if(isset($this->registered_requests[$key])){ + $list[] = $this->registered_requests[$key]; + } + } + return $list; + } + + /** + * @param int $location_id + * @param string $type + * @return AdminSummitLocationActionSyncWorkRequest[] + */ + public function getSummitLocationRequestFor($location_id, $type = null){ + $types = [ + AbstractCalendarSyncWorkRequest::TypeAdd, + AbstractCalendarSyncWorkRequest::TypeRemove, + AbstractCalendarSyncWorkRequest::TypeUpdate, + ]; + + if(!empty($type)) $types = [$type]; + $list = []; + foreach ($types as $t){ + $key = $this->generateKey($t, null, $location_id); + if(isset($this->registered_requests[$key])){ + $list[] = $this->registered_requests[$key]; + } + } + return $list; + } + /** + * @return array + */ + public function getPurgedRequests(){ + return array_values($this->registered_requests); + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return bool + */ + public function registerRequestForDelete(AbstractCalendarSyncWorkRequest $request) + { + // TODO: Implement registerRequestForDelete() method. + } + + /** + * @return array + */ + public function getRequestsToDelete() + { + // TODO: Implement getRequestsToDelete() method. + } +} \ No newline at end of file diff --git a/app/Services/Model/IAdminActionsCalendarSyncProcessingService.php b/app/Services/Model/IAdminActionsCalendarSyncProcessingService.php new file mode 100644 index 00000000..94c38340 --- /dev/null +++ b/app/Services/Model/IAdminActionsCalendarSyncProcessingService.php @@ -0,0 +1,26 @@ +queue_manager = $queue_manager; + $this->work_request_repository = $work_request_repository; + $this->strategy_factory = $strategy_factory; + } + + /** + * @param MemberScheduleSummitActionSyncWorkRequest[] $requests + * @return MemberScheduleSummitActionSyncWorkRequest[] + */ + function preProcessActions(array $requests){ + + foreach ($requests as $request){ + $strategy = $this->strategy_factory->build($this->queue_manager, $request); + if(is_null($strategy)) continue; + $request = $strategy->process($request); + if(!is_null($request)) + $this->queue_manager->registerRequest($request); + } + + foreach($this->queue_manager->getRequestsToDelete() as $request_2_delete){ + $this->work_request_repository->delete($request_2_delete); + } + return $this->queue_manager->getPurgedRequests(); + } +} \ No newline at end of file diff --git a/app/Services/Model/MemberActionsCalendarSyncProcessingService.php b/app/Services/Model/MemberActionsCalendarSyncProcessingService.php new file mode 100644 index 00000000..be99fc93 --- /dev/null +++ b/app/Services/Model/MemberActionsCalendarSyncProcessingService.php @@ -0,0 +1,236 @@ +work_request_repository = $work_request_repository; + $this->calendar_sync_repository = $calendar_sync_repository; + $this->preprocessor_requests = $preprocessor_requests; + $this->tx_manager = $tx_manager; + } + + + /** + * @param string $provider + * @param int $batch_size + * @return int + */ + public function processActions($provider = 'ALL', $batch_size = 1000) + { + return $this->tx_manager->transaction(function() use($provider, $batch_size){ + $count = 0; + + $res = $this->work_request_repository->getUnprocessedMemberScheduleWorkRequestActionByPage + ( + $provider, + new PagingInfo(1, $batch_size) + ); + $requests = $this->preprocessor_requests->preProcessActions($res->getItems()); + log::info(sprintf("provider %s got %s request to process ...", $provider, count($requests))); + + foreach ($requests as $request){ + try { + log::debug(sprintf("iteration # %s", $count+1)); + if (!$request instanceof MemberScheduleSummitActionSyncWorkRequest) continue; + $calendar_sync_info = $request->getCalendarSyncInfo(); + $remote_facade = CalendarSyncRemoteFacadeFactory::getInstance()->build($calendar_sync_info); + if (is_null($remote_facade)) continue; + $member = $request->getOwner(); + $request_type = $request->getType(); + $request_sub_type = $request->getSubType(); + + log::info(sprintf + ( + "%s - processing work request %s - sub type %s - type %s - member %s - credential id %s -revoked credentials %s", + $provider, + $request->getIdentifier(), + $request_sub_type, + $request_type, + $member->getIdentifier(), + $calendar_sync_info->getId(), + $calendar_sync_info->isRevoked()? 1:0 + )); + + switch ($request_sub_type) { + + case MemberEventScheduleSummitActionSyncWorkRequest::SubType: { + $summit_event = $request->getSummitEvent(); + log::info(sprintf + ( + "%s - processing work request %s - sub type %s - type %s - event id %s - member %s - credential id %s -revoked credentials %s", + $provider, + $request->getIdentifier(), + $request_sub_type, + $request_type, + $summit_event->getIdentifier(), + $member->getIdentifier(), + $calendar_sync_info->getId(), + $calendar_sync_info->isRevoked()? 1:0 + )); + + switch ($request_type) { + case AbstractCalendarSyncWorkRequest::TypeAdd: + if ($calendar_sync_info->isRevoked()){ + Log::warning(sprintf("EVENT ADD : event id %s - member id %s could not be added on external calendar bc credential are revoked!", $summit_event->getId(), $member->getId())); + continue; + } + if($member->isEventSynchronized($calendar_sync_info, $summit_event)){ + Log::warning(sprintf("EVENT ADD : event id %s - member id %s already synchronized", $summit_event->getId(), $member->getId())); + continue; + } + $schedule_sync_info = $remote_facade->addEvent($request); + if(is_null($schedule_sync_info)){ + Log::warning(sprintf("EVENT ADD : event id %s - member id %s could not be added on external calendar", $summit_event->getId(), $member->getId())); + continue; + } + $member->add2ScheduleSyncInfo($schedule_sync_info); + break; + case AbstractCalendarSyncWorkRequest::TypeUpdate: + if($calendar_sync_info->isRevoked()) continue; + $sync_info = $member->getScheduleSyncInfoByEvent($summit_event, $calendar_sync_info); + $is_scheduled = $member->isOnSchedule($summit_event); + if(is_null($sync_info)) continue; + if(!$is_scheduled) { + $member->removeFromScheduleSyncInfo($sync_info); + continue; + } + $remote_facade->updateEvent($request, $sync_info); + break; + case AbstractCalendarSyncWorkRequest::TypeRemove: + if($calendar_sync_info->isRevoked()) continue; + $schedule_sync_info = $member->getScheduleSyncInfoByEvent($summit_event, $calendar_sync_info); + if(is_null($schedule_sync_info)){ + Log::warning(sprintf("EVENT REMOVE : event id %s - member id %s could not be removed, schedule synch info is null", $summit_event->getId(), $member->getId())); + continue; + } + $remote_facade->deleteEvent($request, $schedule_sync_info); + $member->removeFromScheduleSyncInfo($schedule_sync_info); + break; + } + } + break; + case MemberCalendarScheduleSummitActionSyncWorkRequest::SubType: { + switch ($request_type) { + case AbstractCalendarSyncWorkRequest::TypeAdd: + if($calendar_sync_info->isRevoked()){ + Log::warning(sprintf("CALENDAR ADD : calendar sync info id %s, member id %s is revoked!", $calendar_sync_info->getId(), $member->getId())); + continue; + } + $remote_facade->createCalendar($request, $calendar_sync_info); + break; + case AbstractCalendarSyncWorkRequest::TypeRemove: + $remote_facade->deleteCalendar($request, $calendar_sync_info); + $member->removeFromCalendarSyncInfo($calendar_sync_info); + break; + } + } + break; + } + + $request->markProcessed(); + $count++; + usleep($remote_facade->getSleepInterval()); + } + catch(ForbiddenException $ex1){ + // cant create calendar (CAL DAV)... + echo 'ForbiddenException !!'.PHP_EOL; + Log::warning($ex1); + } + catch(UserUnAuthorizedException $ex2){ + echo 'UserUnAuthorizedException !!'.PHP_EOL; + Log::warning($ex2); + } + catch(NotFoundResourceException $ex3){ + echo 'NotFoundResourceException !!'.PHP_EOL; + Log::error($ex3); + } + catch(ServerErrorException $ex4){ + echo 'ServerErrorException !!'.PHP_EOL; + Log::error($ex4); + } + catch (RateLimitExceededException $ex5){ + Log::critical($ex5); + break; + } + catch(Exception $ex6){ + echo 'Exception !!'.PHP_EOL; + Log::error($ex6); + } + } + + return $count; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/MemberScheduleWorkQueueManager.php b/app/Services/Model/MemberScheduleWorkQueueManager.php new file mode 100644 index 00000000..1d9437bc --- /dev/null +++ b/app/Services/Model/MemberScheduleWorkQueueManager.php @@ -0,0 +1,212 @@ +getSummitEvent()->getId(); + } + if(empty($type)) $type = $request->getType(); + return $this->generateKey($type, $request->getCalendarSyncInfo()->getId(), $event_id); + } + + /** + * @param string $type + * @param int $calendar_id + * @param null|int $event_id + * @return string + */ + private function generateKey($type, $calendar_id, $event_id = null){ + $sub_type = is_null($event_id) ? MemberCalendarScheduleSummitActionSyncWorkRequest::SubType : MemberEventScheduleSummitActionSyncWorkRequest::SubType; + $key = "{$sub_type}_{$type}_{$calendar_id}"; + if(!is_null($event_id)){ + $key .= "_{$event_id}"; + } + return $key; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return bool + */ + public function registerRequest(AbstractCalendarSyncWorkRequest $request){ + $key = $this->getKey($request); + if(isset($this->registered_requests[$key])) return false; + $this->registered_requests[$key] = $request; + // register request per member calendar + if($request instanceof MemberEventScheduleSummitActionSyncWorkRequest) { + $calendar_info_id = $request->getCalendarSyncInfo()->getId(); + if (!isset($this->calendars_events[$calendar_info_id])) + $this->calendars_events[$calendar_info_id] = []; + $this->calendars_events[$calendar_info_id][] = $request; + } + + return true; + } + + /** + * @param int $calendar_info_id + * @return MemberEventScheduleSummitActionSyncWorkRequest[] + */ + public function getPendingEventsForCalendar($calendar_info_id){ + if (isset($this->calendars_events[$calendar_info_id])){ + return $this->calendars_events[$calendar_info_id]; + } + return []; + } + + /** + * @param int $calendar_info_id + * @return bool + */ + public function clearPendingEventsForCalendar($calendar_info_id){ + if (isset($this->calendars_events[$calendar_info_id])){ + unset($this->calendars_events[$calendar_info_id]); + return true; + } + return false; + } + + /** + * @param int $calendar_id + * @param int $event_id + * @param string $type + * @return MemberEventScheduleSummitActionSyncWorkRequest[] + */ + public function getSummitEventRequestFor($calendar_id, $event_id, $type = null){ + $types = [ + AbstractCalendarSyncWorkRequest::TypeAdd, + AbstractCalendarSyncWorkRequest::TypeRemove, + AbstractCalendarSyncWorkRequest::TypeUpdate, + ]; + + if(!empty($type)) $types = [$type]; + $list = []; + foreach ($types as $t){ + $key = $this->generateKey($t, $calendar_id, $event_id); + if(isset($this->registered_requests[$key]) && !isset($this->registered_requests_2_delete[$key]) ){ + $list[] = $this->registered_requests[$key]; + } + } + return $list; + } + + /** + * @param int $calendar_id + * @param string $type + * @return MemberCalendarScheduleSummitActionSyncWorkRequest|null + */ + public function getCalendarRequestFor($calendar_id, $type){ + $key = $this->generateKey($type, $calendar_id); + return isset($this->registered_requests[$key]) ? $this->registered_requests[$key] : null; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return bool + */ + public function removeRequest(AbstractCalendarSyncWorkRequest $request){ + $key = $this->getKey($request); + if(isset($this->registered_requests[$key])){ + unset($this->registered_requests[$key]); + if($request instanceof MemberEventScheduleSummitActionSyncWorkRequest) { + $calendar_info_id = $request->getCalendarSyncInfo()->getId(); + if (isset($this->calendars_events[$calendar_info_id])) { + // remove from calendar events + $key = array_search($request, $this->calendars_events[$calendar_info_id]); + if($key!==false){ + unset($this->calendars_events[$calendar_info_id][$key]); + if(isset($this->calendars_events[$calendar_info_id])){ + unset($this->calendars_events[$calendar_info_id]); + } + } + } + } + return true; + } + return false; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return bool + */ + public function registerRequestForDelete(AbstractCalendarSyncWorkRequest $request){ + $key = $this->getKey($request); + if(isset($this->registered_requests_2_delete[$key])) return false; + $this->registerRequest($request); + $this->registered_requests_2_delete[$key] = $request; + return true; + } + + /** + * @return array + */ + public function getPurgedRequests(){ + $list = []; + foreach($this->registered_requests as $key => $request){ + if(isset($this->registered_requests_2_delete[$key])) continue; + $list[] = $request; + }; + return $list; + } + + /** + * @return array + */ + public function getRequestsToDelete(){ + return array_values($this->registered_requests_2_delete); + } + + /** + * @param MemberScheduleSummitActionSyncWorkRequest $request + * @param string|null $type + * @return bool + */ + public function unRegisterRequestForDelete(MemberScheduleSummitActionSyncWorkRequest $request , $type = null){ + $key = $this->getKey($request, $type); + if(!isset($this->registered_requests_2_delete[$key])) return false; + unset($this->registered_requests_2_delete[$key]); + return true; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/AdminActions/AdminSummitEventActionSyncWorkRequestDeleteStrategy.php b/app/Services/Model/Strategies/AdminActions/AdminSummitEventActionSyncWorkRequestDeleteStrategy.php new file mode 100644 index 00000000..0fc65a3a --- /dev/null +++ b/app/Services/Model/Strategies/AdminActions/AdminSummitEventActionSyncWorkRequestDeleteStrategy.php @@ -0,0 +1,71 @@ +queue_manager = $queue_manager; + $this->work_request_repository = $work_request_repository; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return AbstractCalendarSyncWorkRequest|null + */ + public function process(AbstractCalendarSyncWorkRequest $request) + { + if(!$request instanceof AdminSummitEventActionSyncWorkRequest) return null; + $summit_event = $request->getSummitEvent(); + $pending_requests = $this->queue_manager->getSummitEventRequestFor($summit_event->getId()); + if(count($pending_requests) > 0 ){ + // delete all former and pending ... + foreach ($pending_requests as $pending_request) { + if($this->queue_manager->removeRequest($pending_request)) + $this->work_request_repository->delete($pending_request); + } + } + return $request; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/AdminActions/AdminSummitEventActionSyncWorkRequestUpdateStrategy.php b/app/Services/Model/Strategies/AdminActions/AdminSummitEventActionSyncWorkRequestUpdateStrategy.php new file mode 100644 index 00000000..d9300beb --- /dev/null +++ b/app/Services/Model/Strategies/AdminActions/AdminSummitEventActionSyncWorkRequestUpdateStrategy.php @@ -0,0 +1,71 @@ +queue_manager = $queue_manager; + $this->work_request_repository = $work_request_repository; + } + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return AbstractCalendarSyncWorkRequest|null + */ + public function process(AbstractCalendarSyncWorkRequest $request) + { + if(!$request instanceof AdminSummitEventActionSyncWorkRequest) return null; + $summit_event = $request->getSummitEvent(); + $pending_requests = $this->queue_manager->getSummitEventRequestFor($summit_event->getId()); + if(count($pending_requests) > 0 ){ + // delete all former and pending ... + foreach ($pending_requests as $pending_request) { + if( $this->queue_manager->removeRequest($pending_request)) + $this->work_request_repository->delete($pending_request); + } + } + return $request; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/AdminActions/AdminSummitLocationActionSyncWorkRequestDeleteStrategy.php b/app/Services/Model/Strategies/AdminActions/AdminSummitLocationActionSyncWorkRequestDeleteStrategy.php new file mode 100644 index 00000000..0d2b56c3 --- /dev/null +++ b/app/Services/Model/Strategies/AdminActions/AdminSummitLocationActionSyncWorkRequestDeleteStrategy.php @@ -0,0 +1,71 @@ +queue_manager = $queue_manager; + $this->work_request_repository = $work_request_repository; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return AbstractCalendarSyncWorkRequest|null + */ + public function process(AbstractCalendarSyncWorkRequest $request) + { + if(!$request instanceof AdminSummitLocationActionSyncWorkRequest) return null; + $location = $request->getLocation(); + $pending_requests = $this->queue_manager->getSummitLocationRequestFor($location->getId()); + if(count($pending_requests) > 0 ){ + // delete all former and pending ... + foreach ($pending_requests as $pending_request) { + if($this->queue_manager->removeRequest($pending_request)) + $this->work_request_repository->delete($pending_request); + } + } + return $request; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/AdminActions/AdminSummitLocationActionSyncWorkRequestUpdateStrategy.php b/app/Services/Model/Strategies/AdminActions/AdminSummitLocationActionSyncWorkRequestUpdateStrategy.php new file mode 100644 index 00000000..4eb3c1c2 --- /dev/null +++ b/app/Services/Model/Strategies/AdminActions/AdminSummitLocationActionSyncWorkRequestUpdateStrategy.php @@ -0,0 +1,72 @@ +queue_manager = $queue_manager; + $this->work_request_repository = $work_request_repository; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return AbstractCalendarSyncWorkRequest|null + */ + public function process(AbstractCalendarSyncWorkRequest $request) + { + if(!$request instanceof AdminSummitLocationActionSyncWorkRequest) return null; + $location = $request->getLocation(); + $pending_requests = $this->queue_manager->getSummitLocationRequestFor($location->getId()); + if(count($pending_requests) > 0 ){ + // delete all former and pending ... + foreach ($pending_requests as $pending_request) { + if($this->queue_manager->removeRequest($pending_request)) + $this->work_request_repository->delete($pending_request); + } + } + return $request; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/CalendarSyncWorkRequestPreProcessorStrategyFactory.php b/app/Services/Model/Strategies/CalendarSyncWorkRequestPreProcessorStrategyFactory.php new file mode 100644 index 00000000..ff7c5586 --- /dev/null +++ b/app/Services/Model/Strategies/CalendarSyncWorkRequestPreProcessorStrategyFactory.php @@ -0,0 +1,126 @@ +work_request_repository = $work_request_repository; + $this->calendar_sync_repository = $calendar_sync_repository; + } + + /** + * @param ICalendarSyncWorkRequestQueueManager $queue_manager + * @param AbstractCalendarSyncWorkRequest $request + * @return ICalendarSyncWorkRequestPreProcessorStrategy|null + */ + public function build(ICalendarSyncWorkRequestQueueManager $queue_manager, AbstractCalendarSyncWorkRequest $request){ + if($request instanceof MemberEventScheduleSummitActionSyncWorkRequest) { + switch ($request->getType()) { + case AbstractCalendarSyncWorkRequest::TypeRemove: + return new MemberEventScheduleSummitActionSyncWorkRequestDeleteStrategy($queue_manager, $this->work_request_repository); + case AbstractCalendarSyncWorkRequest::TypeAdd: + return new MemberEventScheduleSummitActionSyncWorkRequestAddStrategy($queue_manager, $this->work_request_repository); + + case AbstractCalendarSyncWorkRequest::TypeUpdate: + return new MemberEventScheduleSummitActionSyncWorkRequestUpdateStrategy($queue_manager, $this->work_request_repository); + } + } + if($request instanceof MemberCalendarScheduleSummitActionSyncWorkRequest){ + switch ($request->getType()) { + case AbstractCalendarSyncWorkRequest::TypeRemove: + return new MemberCalendarScheduleSummitActionSyncWorkRequestDeleteStrategy + ( + $queue_manager, + $this->work_request_repository, + $this->calendar_sync_repository + ); + + case AbstractCalendarSyncWorkRequest::TypeAdd: + return new MemberCalendarScheduleSummitActionSyncWorkRequestAddStrategy(); + } + } + if($request instanceof AdminSummitEventActionSyncWorkRequest){ + switch ($request->getType()) { + case AbstractCalendarSyncWorkRequest::TypeRemove: + return new AdminSummitEventActionSyncWorkRequestDeleteStrategy( + $queue_manager, + $this->work_request_repository + ); + case AbstractCalendarSyncWorkRequest::TypeUpdate: + return new AdminSummitEventActionSyncWorkRequestUpdateStrategy( + $queue_manager, + $this->work_request_repository + ); + } + } + if($request instanceof AdminSummitLocationActionSyncWorkRequest){ + switch ($request->getType()) { + case AbstractCalendarSyncWorkRequest::TypeRemove: + return new AdminSummitLocationActionSyncWorkRequestDeleteStrategy( + $queue_manager, + $this->work_request_repository + ); + case AbstractCalendarSyncWorkRequest::TypeUpdate: + return new AdminSummitLocationActionSyncWorkRequestUpdateStrategy( + $queue_manager, + $this->work_request_repository + ); + } + } + + return null; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/ICalendarSyncWorkRequestPreProcessorStrategy.php b/app/Services/Model/Strategies/ICalendarSyncWorkRequestPreProcessorStrategy.php new file mode 100644 index 00000000..306fb4c4 --- /dev/null +++ b/app/Services/Model/Strategies/ICalendarSyncWorkRequestPreProcessorStrategy.php @@ -0,0 +1,28 @@ +queue_manager = $queue_manager; + $this->work_request_repository = $work_request_repository; + $this->calendar_sync_repository = $calendar_sync_repository; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return AbstractCalendarSyncWorkRequest|null + */ + public function process(AbstractCalendarSyncWorkRequest $request) + { + if(! $request instanceof MemberCalendarScheduleSummitActionSyncWorkRequest) return null; + $calendar_sync_info = $request->getCalendarSyncInfo(); + //check if we have pending make calendar on this round ... + $pending_calendar_create_request = $this->queue_manager->getCalendarRequestFor($calendar_sync_info->getId(), AbstractCalendarSyncWorkRequest::TypeAdd); + $calendar_created = true; + if(!is_null($pending_calendar_create_request)){ + if($this->queue_manager->removeRequest($pending_calendar_create_request)) + $this->work_request_repository->delete($pending_calendar_create_request); + $calendar_created = false; + } + // delete all pending work ( calendar and events) + $pending_requests = $this->queue_manager->getPendingEventsForCalendar($calendar_sync_info->getId()); + if(count($pending_requests) > 0 ) { + foreach($pending_requests as $pending_request) { + if($this->queue_manager->removeRequest($pending_request)) + $this->work_request_repository->delete($pending_request); + } + } + + if(!$calendar_created){ + // delete the current request ( delete calendar, we never created it ) + $this->work_request_repository->delete($request); + $this->queue_manager->clearPendingEventsForCalendar($calendar_sync_info->getId()); + // delete revoked credentials; + $this->calendar_sync_repository->delete($calendar_sync_info); + return null; + } + + return $request; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestAddStrategy.php b/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestAddStrategy.php new file mode 100644 index 00000000..8540c1a6 --- /dev/null +++ b/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestAddStrategy.php @@ -0,0 +1,84 @@ +work_queue_manager = $work_queue_manager; + $this->work_request_repository = $work_request_repository; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return AbstractCalendarSyncWorkRequest|null + */ + public function process(AbstractCalendarSyncWorkRequest $request) + { + if(!$request instanceof MemberEventScheduleSummitActionSyncWorkRequest) return null; + $summit_event = $request->getSummitEvent(); + $calendar_sync_info = $request->getCalendarSyncInfo(); + // check if there is a former add, disregard and omit + $pending_requests = $this->work_queue_manager->getSummitEventRequestFor($calendar_sync_info->getId(), $summit_event->getId()); + if(count($pending_requests) > 0 ) { + foreach ($pending_requests as $pending_request) { + if($request->getType() == AbstractCalendarSyncWorkRequest::TypeUpdate) + { + $this->work_queue_manager->registerRequestForDelete($request); + continue; + } + if($this->work_queue_manager->removeRequest($pending_request)) + $this->work_request_repository->delete($pending_request); + } + // if the event is not already synchronized disregard add + if($request->getOwner()->isEventSynchronized($calendar_sync_info, $summit_event)) { + $this->work_queue_manager->unRegisterRequestForDelete($request, AbstractCalendarSyncWorkRequest::TypeUpdate); + $this->work_request_repository->delete($request); + return null; + } + } + return $request; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestDeleteStrategy.php b/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestDeleteStrategy.php new file mode 100644 index 00000000..8c09e734 --- /dev/null +++ b/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestDeleteStrategy.php @@ -0,0 +1,83 @@ +queue_manager = $queue_manager; + $this->work_request_repository = $work_request_repository; + } + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return AbstractCalendarSyncWorkRequest|null + */ + public function process(AbstractCalendarSyncWorkRequest $request) + { + if(!$request instanceof MemberEventScheduleSummitActionSyncWorkRequest) return null; + $summit_event = $request->getSummitEvent(); + $calendar_sync_info = $request->getCalendarSyncInfo(); + // check if there is a former add, disregard and omit + $pending_requests = $this->queue_manager->getSummitEventRequestFor($calendar_sync_info->getId(), $summit_event->getId()); + if(count($pending_requests) > 0 ) { + foreach ($pending_requests as $pending_request) { + if($request->getType() == AbstractCalendarSyncWorkRequest::TypeUpdate) + { + $this->queue_manager->registerRequestForDelete($request); + continue; + } + if($this->queue_manager->removeRequest($pending_request)) + $this->work_request_repository->delete($pending_request); + } + // if the event is not already synchronized disregard delete + if(!$request->getOwner()->isEventSynchronized($calendar_sync_info, $summit_event)) { + $this->work_request_repository->delete($request); + return null; + } + } + return $request; + } +} \ No newline at end of file diff --git a/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestUpdateStrategy.php b/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestUpdateStrategy.php new file mode 100644 index 00000000..2b92c12f --- /dev/null +++ b/app/Services/Model/Strategies/MemberActions/MemberEventScheduleSummitActionSyncWorkRequestUpdateStrategy.php @@ -0,0 +1,74 @@ +queue_manager = $queue_manager; + $this->work_request_repository = $work_request_repository; + } + + + /** + * @param AbstractCalendarSyncWorkRequest $request + * @return AbstractCalendarSyncWorkRequest|null + */ + public function process(AbstractCalendarSyncWorkRequest $request) + { + if(!$request instanceof MemberEventScheduleSummitActionSyncWorkRequest) return null; + $summit_event = $request->getSummitEvent(); + $calendar_sync_info = $request->getCalendarSyncInfo(); + // check if there is a former ones, disregard and omit + $pending_requests = $this->queue_manager->getSummitEventRequestFor($calendar_sync_info->getId(), $summit_event->getId()); + if(count($pending_requests) > 0 || !$request->getOwner()->isEventSynchronized($calendar_sync_info, $summit_event)) { + //$this->work_request_repository->delete($request); + $this->queue_manager->registerRequestForDelete($request); + return null; + } + return $request; + } +} \ No newline at end of file diff --git a/app/Services/Model/SummitService.php b/app/Services/Model/SummitService.php index 5f3f3303..5c775e79 100644 --- a/app/Services/Model/SummitService.php +++ b/app/Services/Model/SummitService.php @@ -28,7 +28,11 @@ use Models\foundation\summit\EntityEvents\EntityEventTypeFactory; use Models\foundation\summit\EntityEvents\SummitEntityEventProcessContext; use models\main\Member; use models\main\Tag; +use models\summit\CalendarSync\WorkQueue\AbstractCalendarSyncWorkRequest; +use models\summit\CalendarSync\WorkQueue\MemberEventScheduleSummitActionSyncWorkRequest; +use models\summit\CalendarSync\WorkQueue\MemberScheduleSummitEventCalendarSyncWorkRequest; use models\summit\ConfirmationExternalOrderRequest; +use models\summit\IAbstractCalendarSyncWorkRequestRepository; use models\summit\IRSVPRepository; use models\summit\ISpeakerRepository; use models\summit\ISummitAttendeeRepository; @@ -108,6 +112,11 @@ final class SummitService implements ISummitService */ private $rsvp_repository; + /** + * @var IAbstractCalendarSyncWorkRequestRepository + */ + private $calendar_sync_work_request_repository; + /** * SummitService constructor. * @param ISummitEventRepository $event_repository @@ -118,6 +127,7 @@ final class SummitService implements ISummitService * @param IMemberRepository $member_repository * @param ITagRepository $tag_repository * @param IRSVPRepository $rsvp_repository, + * @param IAbstractCalendarSyncWorkRequestRepository $calendar_sync_work_request_repository * @param IEventbriteAPI $eventbrite_api * @param ITransactionService $tx_service */ @@ -131,20 +141,22 @@ final class SummitService implements ISummitService IMemberRepository $member_repository, ITagRepository $tag_repository, IRSVPRepository $rsvp_repository, + IAbstractCalendarSyncWorkRequestRepository $calendar_sync_work_request_repository, IEventbriteAPI $eventbrite_api, ITransactionService $tx_service ) { - $this->event_repository = $event_repository; - $this->speaker_repository = $speaker_repository; - $this->entity_events_repository = $entity_events_repository; - $this->ticket_repository = $ticket_repository; - $this->member_repository = $member_repository; - $this->attendee_repository = $attendee_repository; - $this->tag_repository = $tag_repository; - $this->rsvp_repository = $rsvp_repository; - $this->eventbrite_api = $eventbrite_api; - $this->tx_service = $tx_service; + $this->event_repository = $event_repository; + $this->speaker_repository = $speaker_repository; + $this->entity_events_repository = $entity_events_repository; + $this->ticket_repository = $ticket_repository; + $this->member_repository = $member_repository; + $this->attendee_repository = $attendee_repository; + $this->tag_repository = $tag_repository; + $this->rsvp_repository = $rsvp_repository; + $this->calendar_sync_work_request_repository = $calendar_sync_work_request_repository; + $this->eventbrite_api = $eventbrite_api; + $this->tx_service = $tx_service; } /** @@ -160,6 +172,7 @@ final class SummitService implements ISummitService { try { $this->tx_service->transaction(function () use ($summit, $member, $event_id, $check_rsvp) { + $event = $summit->getScheduleEvent($event_id); if (is_null($event)) { throw new EntityNotFoundException('event not found on summit!'); @@ -167,10 +180,21 @@ final class SummitService implements ISummitService if(!Summit::allowToSee($event, $member)) throw new EntityNotFoundException('event not found on summit!'); - if($check_rsvp && $event->hasRSVP() && !$event->getIssExternalRSVP()) + if($check_rsvp && $event->hasRSVP() && !$event->isExternalRSVP()) throw new ValidationException("event has rsvp set on it!"); $member->add2Schedule($event); + + if($member->hasSyncInfoFor($summit)) { + $sync_info = $member->getSyncInfoBy($summit); + $request = new MemberEventScheduleSummitActionSyncWorkRequest(); + $request->setType(AbstractCalendarSyncWorkRequest::TypeAdd); + $request->setSummitEvent($event); + $request->setOwner($member); + $request->setCalendarSyncInfo($sync_info); + $this->calendar_sync_work_request_repository->add($request); + } + }); Event::fire(new MyScheduleAdd($member ,$summit, $event_id)); } @@ -182,6 +206,40 @@ final class SummitService implements ISummitService } } + /** + * @param Summit $summit + * @param Member $member + * @param int $event_id + * @param boolean $check_rsvp + * @return void + * @throws \Exception + */ + public function removeEventFromMemberSchedule(Summit $summit, Member $member, $event_id, $check_rsvp = true) + { + $this->tx_service->transaction(function () use ($summit, $member, $event_id, $check_rsvp) { + $event = $summit->getScheduleEvent($event_id); + if (is_null($event)) + throw new EntityNotFoundException('event not found on summit!'); + + if($check_rsvp && $event->hasRSVP() && !$event->isExternalRSVP()) + throw new ValidationException("event has rsvp set on it!"); + + $member->removeFromSchedule($event); + + if($member->hasSyncInfoFor($summit)) { + $sync_info = $member->getSyncInfoBy($summit); + $request = new MemberEventScheduleSummitActionSyncWorkRequest(); + $request->setType(AbstractCalendarSyncWorkRequest::TypeRemove); + $request->setSummitEvent($event); + $request->setOwner($member); + $request->setCalendarSyncInfo($sync_info); + $this->calendar_sync_work_request_repository->add($request); + } + }); + + Event::fire(new MyScheduleRemove($member,$summit, $event_id)); + } + /** * @param Summit $summit * @param Member $member @@ -200,6 +258,7 @@ final class SummitService implements ISummitService throw new EntityNotFoundException('event not found on summit!'); $member->addFavoriteSummitEvent($event); }); + Event::fire(new MyFavoritesAdd($member, $summit, $event_id)); } catch (UniqueConstraintViolationException $ex){ @@ -210,31 +269,6 @@ final class SummitService implements ISummitService } } - - /** - * @param Summit $summit - * @param Member $member - * @param int $event_id - * @param boolean $check_rsvp - * @return void - * @throws \Exception - */ - public function removeEventFromMemberSchedule(Summit $summit, Member $member, $event_id, $check_rsvp = true) - { - $this->tx_service->transaction(function () use ($summit, $member, $event_id, $check_rsvp) { - $event = $summit->getScheduleEvent($event_id); - if (is_null($event)) - throw new EntityNotFoundException('event not found on summit!'); - - if($check_rsvp && $event->hasRSVP() && !$event->getIssExternalRSVP()) - throw new ValidationException("event has rsvp set on it!"); - - $member->removeFromSchedule($event); - }); - - Event::fire(new MyScheduleRemove($member,$summit, $event_id)); - } - /** * @param Summit $summit * @param Member $member diff --git a/app/Services/ServicesProvider.php b/app/Services/ServicesProvider.php index 84626e78..c102041f 100644 --- a/app/Services/ServicesProvider.php +++ b/app/Services/ServicesProvider.php @@ -31,20 +31,80 @@ class ServicesProvider extends ServiceProvider public function register() { App::singleton('libs\utils\ICacheService', 'services\utils\RedisCacheService'); + App::singleton(\libs\utils\ITransactionService::class, function(){ return new \services\utils\DoctrineTransactionService('ss'); }); + + App::singleton(\libs\utils\IEncryptionService::class, function(){ + return new \services\utils\EncryptionService( + Config::get("server.ss_encrypt_key", ''), + Config::get("server.ss_encrypt_cypher", '') + ); + }); + + // setting facade + $this->app['encryption'] = App::share(function ($app) { + return new \services\utils\EncryptionService( + Config::get("server.ss_encrypt_key", ''), + Config::get("server.ss_encrypt_cypher", '') + ); + }); + App::singleton('services\model\ISummitService', 'services\model\SummitService'); + App::singleton('services\model\IPresentationService', 'services\model\PresentationService'); + App::singleton('services\model\IChatTeamService', 'services\model\ChatTeamService'); + App::singleton('services\apis\IEventbriteAPI', function(){ $api = new EventbriteAPI(); $api->setCredentials(array('token' => Config::get("server.eventbrite_oauth2_personal_token", null))); return $api; }); + App::singleton('services\apis\IPushNotificationApi', function(){ $api = new FireBaseGCMApi(Config::get("server.firebase_gcm_server_key", null)); return $api; }); + + // work request pre processors + + App::singleton + ( + 'App\Services\Model\Strategies\ICalendarSyncWorkRequestPreProcessorStrategyFactory', + 'App\Services\Model\Strategies\CalendarSyncWorkRequestPreProcessorStrategyFactory' + ); + + App::when('App\Services\Model\MemberActionsCalendarSyncPreProcessor') + ->needs('App\Services\Model\ICalendarSyncWorkRequestQueueManager') + ->give('App\Services\Model\MemberScheduleWorkQueueManager'); + + App::when('App\Services\Model\AdminActionsCalendarSyncPreProcessor') + ->needs('App\Services\Model\ICalendarSyncWorkRequestQueueManager') + ->give('App\Services\Model\AdminScheduleWorkQueueManager'); + + + // work request process services + + App::when('App\Services\Model\MemberActionsCalendarSyncProcessingService') + ->needs('App\Services\Model\ICalendarSyncWorkRequestPreProcessor') + ->give('App\Services\Model\MemberActionsCalendarSyncPreProcessor'); + + App::singleton + ( + 'App\Services\Model\IMemberActionsCalendarSyncProcessingService', + 'App\Services\Model\MemberActionsCalendarSyncProcessingService' + ); + + App::when('App\Services\Model\AdminActionsCalendarSyncProcessingService') + ->needs('App\Services\Model\ICalendarSyncWorkRequestPreProcessor') + ->give('App\Services\Model\AdminActionsCalendarSyncPreProcessor'); + + App::singleton + ( + 'App\Services\Model\IAdminActionsCalendarSyncProcessingService', + 'App\Services\Model\AdminActionsCalendarSyncProcessingService' + ); } } \ No newline at end of file diff --git a/app/Services/Utils/EncryptionService.php b/app/Services/Utils/EncryptionService.php new file mode 100644 index 00000000..08815cfc --- /dev/null +++ b/app/Services/Utils/EncryptionService.php @@ -0,0 +1,48 @@ +enc = new Encrypter($key, $cipher); + } + + public function encrypt($value) + { + return $this->enc->encrypt($value); + } + + public function decrypt($payload) + { + return $this->enc->decrypt($payload); + } +} \ No newline at end of file diff --git a/app/Services/Utils/Facades/Encryption.php b/app/Services/Utils/Facades/Encryption.php new file mode 100644 index 00000000..b3c21920 --- /dev/null +++ b/app/Services/Utils/Facades/Encryption.php @@ -0,0 +1,27 @@ +=5.5.9", "laravel/framework": "5.2.*", "predis/predis": "1.0.1", - "guzzlehttp/guzzle": "5.3.0", "ezyang/htmlpurifier": "4.7.0", "glenscott/url-normalizer" : "^1.4", "laravel-doctrine/orm":"1.2.*", "laravel-doctrine/extensions": "1.0.*", - "cocur/slugify": "^2.3" + "cocur/slugify": "^2.3", + "guzzlehttp/guzzle": "^6.3", + "google/apiclient": "^2.2", + "smarcet/caldavclient": "dev-master", + "smarcet/outlook-rest-client": "dev-master" }, "require-dev": { "fzaninotto/faker": "~1.4", - "mockery/mockery": "0.9.*", "phpunit/phpunit": "~4.0", "symfony/css-selector": "2.8.*|3.0.*", - "symfony/dom-crawler": "2.8.*|3.0.*" + "symfony/dom-crawler": "2.8.*|3.0.*", + "mockery/mockery": "^0.9.9" }, "autoload": { "classmap": [ @@ -59,5 +62,6 @@ }, "config": { "preferred-install": "dist" - } + }, + "minimum-stability":"dev" } diff --git a/composer.lock b/composer.lock index 4f1bf164..74ab53bb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,25 +4,24 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "e41e836704d7fe67318a85269f74bdca", - "content-hash": "2ebc91262281a96a723b834b6736996d", + "content-hash": "5e516218aea07f2829d27b116c1d5fe4", "packages": [ { "name": "classpreloader/classpreloader", - "version": "3.0.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/ClassPreloader/ClassPreloader.git", - "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a" + "reference": "53f7fe1962abd34d94c7d0dcd6482e8ec1434eed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/9b10b913c2bdf90c3d2e0d726b454fb7f77c552a", - "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a", + "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/53f7fe1962abd34d94c7d0dcd6482e8ec1434eed", + "reference": "53f7fe1962abd34d94c7d0dcd6482e8ec1434eed", "shasum": "" }, "require": { - "nikic/php-parser": "^1.0|^2.0", + "nikic/php-parser": "^1.0|^2.0|^3.0", "php": ">=5.5.9" }, "require-dev": { @@ -31,7 +30,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -59,20 +58,20 @@ "class", "preload" ], - "time": "2015-11-09 22:51:51" + "time": "2017-06-23T13:23:36+00:00" }, { "name": "cocur/slugify", - "version": "v2.3", + "version": "2.5.x-dev", "source": { "type": "git", "url": "https://github.com/cocur/slugify.git", - "reference": "57a00e06a382928e350cc7bbb13b19f1b8f4e73a" + "reference": "e8167e9a3236044afebd6e8ab13ebeb3ec9ca145" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cocur/slugify/zipball/57a00e06a382928e350cc7bbb13b19f1b8f4e73a", - "reference": "57a00e06a382928e350cc7bbb13b19f1b8f4e73a", + "url": "https://api.github.com/repos/cocur/slugify/zipball/e8167e9a3236044afebd6e8ab13ebeb3ec9ca145", + "reference": "e8167e9a3236044afebd6e8ab13ebeb3ec9ca145", "shasum": "" }, "require": { @@ -92,7 +91,7 @@ "symfony/config": "~2.4|~3.0", "symfony/dependency-injection": "~2.4|~3.0", "symfony/http-kernel": "~2.4|~3.0", - "twig/twig": "~1.12", + "twig/twig": "~1.26|~2.0", "zendframework/zend-modulemanager": "~2.2", "zendframework/zend-servicemanager": "~2.2", "zendframework/zend-view": "~2.2" @@ -123,7 +122,7 @@ "slug", "slugify" ], - "time": "2016-08-09 20:10:17" + "time": "2017-03-23T21:52:55+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -156,20 +155,20 @@ "MIT" ], "description": "implementation of xdg base directory specification for php", - "time": "2014-10-24 07:27:01" + "time": "2014-10-24T07:27:01+00:00" }, { "name": "doctrine/annotations", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "30e07cf03edc3cd3ef579d0dd4dd8c58250799a5" + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/30e07cf03edc3cd3ef579d0dd4dd8c58250799a5", - "reference": "30e07cf03edc3cd3ef579d0dd4dd8c58250799a5", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", "shasum": "" }, "require": { @@ -178,7 +177,7 @@ }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^5.6.1" + "phpunit/phpunit": "^5.7" }, "type": "library", "extra": { @@ -224,20 +223,20 @@ "docblock", "parser" ], - "time": "2016-10-24 11:45:47" + "time": "2017-02-24T16:22:25+00:00" }, { "name": "doctrine/cache", - "version": "v1.6.1", + "version": "1.6.x-dev", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3" + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/b6f544a20f4807e81f7044d31e679ccbb1866dc3", - "reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3", + "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", "shasum": "" }, "require": { @@ -294,32 +293,33 @@ "cache", "caching" ], - "time": "2016-10-29 11:16:17" + "time": "2017-07-22T12:49:21+00:00" }, { "name": "doctrine/collections", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a" + "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a", - "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba", + "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^5.6 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "doctrine/coding-standard": "~0.1@dev", + "phpunit/phpunit": "^5.7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -360,20 +360,20 @@ "collections", "iterator" ], - "time": "2015-04-14 22:21:58" + "time": "2017-01-03T10:49:41+00:00" }, { "name": "doctrine/common", - "version": "v2.6.1", + "version": "2.7.x-dev", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "a579557bc689580c19fee4e27487a67fe60defc0" + "reference": "df88fc88463a60f228a8233acf3fa8664897229c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0", - "reference": "a579557bc689580c19fee4e27487a67fe60defc0", + "url": "https://api.github.com/repos/doctrine/common/zipball/df88fc88463a60f228a8233acf3fa8664897229c", + "reference": "df88fc88463a60f228a8233acf3fa8664897229c", "shasum": "" }, "require": { @@ -382,10 +382,10 @@ "doctrine/collections": "1.*", "doctrine/inflector": "1.*", "doctrine/lexer": "1.*", - "php": "~5.5|~7.0" + "php": "~5.6|~7.0" }, "require-dev": { - "phpunit/phpunit": "~4.8|~5.0" + "phpunit/phpunit": "^5.4.6" }, "type": "library", "extra": { @@ -433,24 +433,24 @@ "persistence", "spl" ], - "time": "2015-12-25 13:18:31" + "time": "2017-07-22T08:35:55+00:00" }, { "name": "doctrine/dbal", - "version": "v2.5.5", + "version": "2.5.x-dev", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9" + "reference": "9315e61c4c525167fbcc963c38ef136f691c99e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", - "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/9315e61c4c525167fbcc963c38ef136f691c99e9", + "reference": "9315e61c4c525167fbcc963c38ef136f691c99e9", "shasum": "" }, "require": { - "doctrine/common": ">=2.4,<2.7-dev", + "doctrine/common": ">=2.4,<2.8-dev", "php": ">=5.3.2" }, "require-dev": { @@ -504,11 +504,11 @@ "persistence", "queryobject" ], - "time": "2016-09-09 19:13:33" + "time": "2017-07-22T20:45:23+00:00" }, { "name": "doctrine/inflector", - "version": "v1.1.0", + "version": "1.1.x-dev", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", @@ -571,11 +571,11 @@ "singularize", "string" ], - "time": "2015-11-06 14:35:42" + "time": "2015-11-06T14:35:42+00:00" }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.0.x-dev", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", @@ -625,20 +625,20 @@ "constructor", "instantiate" ], - "time": "2015-06-14 21:17:01" + "time": "2015-06-14T21:17:01+00:00" }, { "name": "doctrine/lexer", - "version": "v1.0.1", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + "reference": "cc709ba91eee09540091ad5a5f2616727662e41b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/cc709ba91eee09540091ad5a5f2616727662e41b", + "reference": "cc709ba91eee09540091ad5a5f2616727662e41b", "shasum": "" }, "require": { @@ -651,8 +651,8 @@ } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" } }, "notification-url": "https://packagist.org/downloads/", @@ -679,27 +679,27 @@ "lexer", "parser" ], - "time": "2014-09-09 13:34:57" + "time": "2017-07-24T09:37:08+00:00" }, { "name": "doctrine/orm", - "version": "v2.5.5", + "version": "2.5.x-dev", "source": { "type": "git", "url": "https://github.com/doctrine/doctrine2.git", - "reference": "73e4be7c7b3ba26f96b781a40b33feba4dfa6d45" + "reference": "d27a9fce7a01476cc3fba5c564558ee4ec0c64f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/73e4be7c7b3ba26f96b781a40b33feba4dfa6d45", - "reference": "73e4be7c7b3ba26f96b781a40b33feba4dfa6d45", + "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/d27a9fce7a01476cc3fba5c564558ee4ec0c64f1", + "reference": "d27a9fce7a01476cc3fba5c564558ee4ec0c64f1", "shasum": "" }, "require": { "doctrine/cache": "~1.4", "doctrine/collections": "~1.2", - "doctrine/common": ">=2.5-dev,<2.7-dev", - "doctrine/dbal": ">=2.5-dev,<2.6-dev", + "doctrine/common": ">=2.5-dev,<2.9-dev", + "doctrine/dbal": ">=2.5-dev,<2.7-dev", "doctrine/instantiator": "~1.0.1", "ext-pdo": "*", "php": ">=5.4", @@ -755,7 +755,60 @@ "database", "orm" ], - "time": "2016-09-10 18:51:13" + "time": "2017-07-25T03:02:26+00:00" + }, + { + "name": "eluceo/ical", + "version": "0.11.x-dev", + "source": { + "type": "git", + "url": "https://github.com/markuspoerschke/iCal.git", + "reference": "739a4e8622fa75fc77d76718300dae6805d09ff0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/markuspoerschke/iCal/zipball/739a4e8622fa75fc77d76718300dae6805d09ff0", + "reference": "739a4e8622fa75fc77d76718300dae6805d09ff0", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "type": "library", + "autoload": { + "psr-0": { + "Eluceo\\iCal": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maciej Łebkowski", + "email": "m.lebkowski@gmail.com", + "role": "Contributor" + }, + { + "name": "Markus Poerschke", + "email": "markus@eluceo.de", + "role": "Developer" + } + ], + "description": "The eluceo/iCal package offers a abstraction layer for creating iCalendars. You can easily create iCal files by using PHP object instead of typing your *.ics file by hand. The output will follow RFC 2445 as best as possible.", + "homepage": "https://github.com/markuspoerschke/iCal", + "keywords": [ + "calendar", + "iCalendar", + "ical", + "ics", + "php calendar" + ], + "time": "2017-04-25 08:33:00" }, { "name": "ezyang/htmlpurifier", @@ -799,7 +852,53 @@ "keywords": [ "html" ], - "time": "2015-08-05 01:03:42" + "time": "2015-08-05T01:03:42+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v5.0.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/9984a4d3a32ae7673d6971ea00bae9d0a1abba0e", + "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": " 4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "time": "2017-06-27T22:17:23+00:00" }, { "name": "glenscott/url-normalizer", @@ -836,38 +935,189 @@ } ], "description": "Syntax based normalization of URL's", - "time": "2015-06-11 16:06:02" + "time": "2015-06-11T16:06:02+00:00" }, { - "name": "guzzlehttp/guzzle", - "version": "5.3.0", + "name": "google/apiclient", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "f3c8c22471cb55475105c14769644a49c3262b93" + "url": "https://github.com/google/google-api-php-client.git", + "reference": "9bef2490ed545c9deac78b12efa38ec01527d5f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f3c8c22471cb55475105c14769644a49c3262b93", - "reference": "f3c8c22471cb55475105c14769644a49c3262b93", + "url": "https://api.github.com/repos/google/google-api-php-client/zipball/9bef2490ed545c9deac78b12efa38ec01527d5f3", + "reference": "9bef2490ed545c9deac78b12efa38ec01527d5f3", "shasum": "" }, "require": { - "guzzlehttp/ringphp": "^1.1", - "php": ">=5.4.0" + "firebase/php-jwt": "~2.0|~3.0|~4.0|~5.0", + "google/apiclient-services": "~0.13", + "google/auth": "^1.0", + "guzzlehttp/guzzle": "~5.3.1|~6.0", + "guzzlehttp/psr7": "^1.2", + "monolog/monolog": "^1.17", + "php": ">=5.4", + "phpseclib/phpseclib": "~0.3.10|~2.0" }, "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.0", - "psr/log": "^1.0" + "cache/filesystem-adapter": "^0.3.2", + "phpunit/phpunit": "~4", + "squizlabs/php_codesniffer": "~2.3", + "symfony/css-selector": "~2.1", + "symfony/dom-crawler": "~2.1" + }, + "suggest": { + "cache/filesystem-adapter": "For caching certs and tokens (using Google_Client::setCache)" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "2.x-dev" } }, "autoload": { + "psr-0": { + "Google_": "src/" + }, + "classmap": [ + "src/Google/Service/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "time": "2017-07-12 19:40:33" + }, + { + "name": "google/apiclient-services", + "version": "v0.17", + "source": { + "type": "git", + "url": "https://github.com/google/google-api-php-client-services.git", + "reference": "04d29c4b679249bd0ed62e5891203478072c8a09" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/google/google-api-php-client-services/zipball/04d29c4b679249bd0ed62e5891203478072c8a09", + "reference": "04d29c4b679249bd0ed62e5891203478072c8a09", + "shasum": "" + }, + "require": { + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "autoload": { + "psr-0": { + "Google_Service_": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "time": "2017-07-30T00:20:54+00:00" + }, + { + "name": "google/auth", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/google/google-auth-library-php.git", + "reference": "db8e3022a308cb0e988026d38e67b91a42b41622" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/google/google-auth-library-php/zipball/db8e3022a308cb0e988026d38e67b91a42b41622", + "reference": "db8e3022a308cb0e988026d38e67b91a42b41622", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "~2.0|~3.0|~4.0|~5.0", + "guzzlehttp/guzzle": "~5.3.1|~6.0", + "guzzlehttp/psr7": "~1.2", + "php": ">=5.4", + "psr/cache": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^1.11", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ], + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "http://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "time": "2017-07-31T16:34:40+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0 || ^5.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], "psr-4": { "GuzzleHttp\\": "src/" } @@ -883,7 +1133,7 @@ "homepage": "https://github.com/mtdowling" } ], - "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "description": "Guzzle is a PHP HTTP client library", "homepage": "http://guzzlephp.org/", "keywords": [ "client", @@ -894,44 +1144,41 @@ "rest", "web service" ], - "time": "2015-05-20 03:47:55" + "time": "2017-06-22T18:50:49+00:00" }, { - "name": "guzzlehttp/ringphp", - "version": "1.1.0", + "name": "guzzlehttp/promises", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/guzzle/RingPHP.git", - "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b" + "url": "https://github.com/guzzle/promises.git", + "reference": "09e549f5534380c68761260a71f847644d8f65aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", - "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "url": "https://api.github.com/repos/guzzle/promises/zipball/09e549f5534380c68761260a71f847644d8f65aa", + "reference": "09e549f5534380c68761260a71f847644d8f65aa", "shasum": "" }, "require": { - "guzzlehttp/streams": "~3.0", - "php": ">=5.4.0", - "react/promise": "~2.0" + "php": ">=5.5.0" }, "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "~4.0" - }, - "suggest": { - "ext-curl": "Guzzle will use specific adapters if cURL is present" + "phpunit/phpunit": "^4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.4-dev" } }, "autoload": { "psr-4": { - "GuzzleHttp\\Ring\\": "src/" - } + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -944,71 +1191,140 @@ "homepage": "https://github.com/mtdowling" } ], - "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", - "time": "2015-05-20 03:37:09" - }, - { - "name": "guzzlehttp/streams", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/streams.git", - "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", - "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Stream\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Provides a simple abstraction over streams of data", - "homepage": "http://guzzlephp.org/", + "description": "Guzzle promises library", "keywords": [ - "Guzzle", - "stream" + "promise" ], - "time": "2014-10-12 19:18:40" + "time": "2017-05-20T23:14:18+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "811b676fbab9c99e359885032e5ebc70e442f5b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/811b676fbab9c99e359885032e5ebc70e442f5b8", + "reference": "811b676fbab9c99e359885032e5ebc70e442f5b8", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-07-17T09:11:21+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "1.2.x-dev", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "b72949ccf2f640e7de66ff7dd92d83f577ce782e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b72949ccf2f640e7de66ff7dd92d83f577ce782e", + "reference": "b72949ccf2f640e7de66ff7dd92d83f577ce782e", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "1.3.3", + "phpunit/phpunit": "~4.0", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ], + "files": [ + "hamcrest/Hamcrest.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "time": "2016-01-19T12:08:55+00:00" }, { "name": "ircmaxell/password-compat", - "version": "v1.0.4", + "version": "1.0.x-dev", "source": { "type": "git", "url": "https://github.com/ircmaxell/password_compat.git", - "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" + "reference": "9b99377557a33a4129c9194e60a97a685fab21e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", - "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", + "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/9b99377557a33a4129c9194e60a97a685fab21e0", + "reference": "9b99377557a33a4129c9194e60a97a685fab21e0", "shasum": "" }, "require-dev": { @@ -1037,7 +1353,7 @@ "hashing", "password" ], - "time": "2014-11-20 16:49:30" + "time": "2014-11-20T19:18:42+00:00" }, { "name": "jakub-onderka/php-console-color", @@ -1080,7 +1396,7 @@ "homepage": "http://www.acci.cz" } ], - "time": "2014-04-08 15:00:19" + "time": "2014-04-08T15:00:19+00:00" }, { "name": "jakub-onderka/php-console-highlighter", @@ -1124,24 +1440,24 @@ "homepage": "http://www.acci.cz/" } ], - "time": "2015-04-20 18:58:01" + "time": "2015-04-20T18:58:01+00:00" }, { "name": "jeremeamia/SuperClosure", - "version": "2.2.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/jeremeamia/super_closure.git", - "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938" + "reference": "f57f48cb328552f6af7c4ad61f51b35a4237b546" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/29a88be2a4846d27c1613aed0c9071dfad7b5938", - "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938", + "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/f57f48cb328552f6af7c4ad61f51b35a4237b546", + "reference": "f57f48cb328552f6af7c4ad61f51b35a4237b546", "shasum": "" }, "require": { - "nikic/php-parser": "^1.2|^2.0", + "nikic/php-parser": "^1.2|^2.0|^3.0", "php": ">=5.4", "symfony/polyfill-php56": "^1.0" }, @@ -1151,7 +1467,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -1182,20 +1498,20 @@ "serialize", "tokenizer" ], - "time": "2015-12-05 17:17:57" + "time": "2017-06-23T22:47:24+00:00" }, { "name": "laravel-doctrine/extensions", - "version": "1.0.10", + "version": "1.0.x-dev", "source": { "type": "git", "url": "https://github.com/laravel-doctrine/extensions.git", - "reference": "dc11146308b14da194106fda1641bb3bc282d317" + "reference": "d9c8b64a8c9e6e3ef9334c9f3d548cac01b1c2a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel-doctrine/extensions/zipball/dc11146308b14da194106fda1641bb3bc282d317", - "reference": "dc11146308b14da194106fda1641bb3bc282d317", + "url": "https://api.github.com/repos/laravel-doctrine/extensions/zipball/d9c8b64a8c9e6e3ef9334c9f3d548cac01b1c2a2", + "reference": "d9c8b64a8c9e6e3ef9334c9f3d548cac01b1c2a2", "shasum": "" }, "require": { @@ -1204,7 +1520,7 @@ "illuminate/contracts": "~5.1", "illuminate/http": "~5.1", "illuminate/support": "~5.1", - "laravel-doctrine/orm": "1.0.*|1.1.*|1.2.*", + "laravel-doctrine/orm": "~1.0", "php": ">=5.5.9" }, "require-dev": { @@ -1243,20 +1559,20 @@ "laravel", "orm" ], - "time": "2016-09-01 16:38:57" + "time": "2017-07-21T17:01:03+00:00" }, { "name": "laravel-doctrine/orm", - "version": "1.2.8", + "version": "1.2.x-dev", "source": { "type": "git", "url": "https://github.com/laravel-doctrine/orm.git", - "reference": "9b32992e4672cf0ac597035e99e72c4ebd63a80e" + "reference": "6a92c3458e82aa659d7bf066dfa15e7bbc3447d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel-doctrine/orm/zipball/9b32992e4672cf0ac597035e99e72c4ebd63a80e", - "reference": "9b32992e4672cf0ac597035e99e72c4ebd63a80e", + "url": "https://api.github.com/repos/laravel-doctrine/orm/zipball/6a92c3458e82aa659d7bf066dfa15e7bbc3447d5", + "reference": "6a92c3458e82aa659d7bf066dfa15e7bbc3447d5", "shasum": "" }, "require": { @@ -1266,6 +1582,7 @@ "illuminate/container": "5.2.*|5.3.*", "illuminate/contracts": "5.2.*|5.3.*", "illuminate/pagination": "5.2.*|5.3.*", + "illuminate/routing": "5.2.*|5.3.*", "illuminate/support": "5.2.*|5.3.*", "illuminate/validation": "5.2.*|5.3.*", "illuminate/view": "5.2.*|5.3.*", @@ -1316,20 +1633,20 @@ "laravel", "orm" ], - "time": "2016-09-25 18:05:32" + "time": "2017-04-12T12:45:15+00:00" }, { "name": "laravel/framework", - "version": "v5.2.45", + "version": "5.2.x-dev", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "2a79f920d5584ec6df7cf996d922a742d11095d1" + "reference": "c6d7def0182f37645585f19e4852a8ce3889b28f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/2a79f920d5584ec6df7cf996d922a742d11095d1", - "reference": "2a79f920d5584ec6df7cf996d922a742d11095d1", + "url": "https://api.github.com/repos/laravel/framework/zipball/c6d7def0182f37645585f19e4852a8ce3889b28f", + "reference": "c6d7def0182f37645585f19e4852a8ce3889b28f", "shasum": "" }, "require": { @@ -1446,20 +1763,20 @@ "framework", "laravel" ], - "time": "2016-08-26 11:44:52" + "time": "2017-03-25T17:57:22+00:00" }, { "name": "league/flysystem", - "version": "1.0.32", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab" + "reference": "988626314a28f34e682f374162b67deb855af2d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1b5c4a0031697f46e779a9d1b309c2e1b24daeab", - "reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/988626314a28f34e682f374162b67deb855af2d1", + "reference": "988626314a28f34e682f374162b67deb855af2d1", "shasum": "" }, "require": { @@ -1480,13 +1797,13 @@ "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", - "league/flysystem-copy": "Allows you to use Copy.com storage", - "league/flysystem-dropbox": "Allows you to use Dropbox storage", "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", "league/flysystem-webdav": "Allows you to use WebDAV storage", - "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter" + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" }, "type": "library", "extra": { @@ -1529,20 +1846,152 @@ "sftp", "storage" ], - "time": "2016-10-19 20:38:46" + "time": "2017-07-29T19:03:34+00:00" }, { - "name": "monolog/monolog", - "version": "1.21.0", + "name": "league/oauth2-client", + "version": "2.2.1", "source": { "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952" + "url": "https://github.com/thephpleague/oauth2-client.git", + "reference": "313250eab923e673a5c0c8f463f443ee79f4383f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952", - "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952", + "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/313250eab923e673a5c0c8f463f443ee79f4383f", + "reference": "313250eab923e673a5c0c8f463f443ee79f4383f", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "paragonie/random_compat": "^1|^2", + "php": ">=5.6.0" + }, + "require-dev": { + "eloquent/liberator": "^2.0", + "eloquent/phony": "^0.14.1", + "jakub-onderka/php-parallel-lint": "~0.9", + "phpunit/phpunit": "^5.0", + "squizlabs/php_codesniffer": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\OAuth2\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Bilbie", + "email": "hello@alexbilbie.com", + "homepage": "http://www.alexbilbie.com", + "role": "Developer" + }, + { + "name": "Woody Gilk", + "homepage": "https://github.com/shadowhand", + "role": "Contributor" + } + ], + "description": "OAuth 2.0 Client Library", + "keywords": [ + "Authentication", + "SSO", + "authorization", + "identity", + "idp", + "oauth", + "oauth2", + "single sign on" + ], + "time": "2017-04-25T14:43:14+00:00" + }, + { + "name": "mockery/mockery", + "version": "0.9.x-dev", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "80ac8060487db317c133ee00154f0862bd4d4ec7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/80ac8060487db317c133ee00154f0862bd4d4ec7", + "reference": "80ac8060487db317c133ee00154f0862bd4d4ec7", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "~1.1", + "lib-pcre": ">=7.0", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.9.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mockery": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Padraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "http://davedevelopment.co.uk" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", + "homepage": "http://github.com/padraic/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "time": "2017-06-07T08:41:50+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", "shasum": "" }, "require": { @@ -1553,7 +2002,7 @@ "psr/log-implementation": "1.0.0" }, "require-dev": { - "aws/aws-sdk-php": "^2.4.9", + "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", "jakub-onderka/php-parallel-lint": "0.9", @@ -1563,7 +2012,7 @@ "phpunit/phpunit-mock-objects": "2.3.0", "ruflin/elastica": ">=0.90 <3.0", "sentry/sentry": "^0.13", - "swiftmailer/swiftmailer": "~5.3" + "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", @@ -1607,20 +2056,20 @@ "logging", "psr-3" ], - "time": "2016-07-29 03:23:52" + "time": "2017-06-19T01:22:40+00:00" }, { "name": "mtdowling/cron-expression", - "version": "v1.1.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/mtdowling/cron-expression.git", - "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5" + "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5", - "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5", + "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/9504fa9ea681b586028adaaa0877db4aecf32bad", + "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad", "shasum": "" }, "require": { @@ -1631,8 +2080,8 @@ }, "type": "library", "autoload": { - "psr-0": { - "Cron": "src/" + "psr-4": { + "Cron\\": "src/Cron/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1651,30 +2100,36 @@ "cron", "schedule" ], - "time": "2016-01-26 21:23:30" + "time": "2017-01-23T04:29:33+00:00" }, { "name": "nesbot/carbon", - "version": "1.21.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7" + "reference": "926aee5ab38c2868816aa760f862a85ad01cb61a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7b08ec6f75791e130012f206e3f7b0e76e18e3d7", - "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/926aee5ab38c2868816aa760f862a85ad01cb61a", + "reference": "926aee5ab38c2868816aa760f862a85ad01cb61a", "shasum": "" }, "require": { "php": ">=5.3.0", - "symfony/translation": "~2.6|~3.0" + "symfony/translation": "~2.6 || ~3.0" }, "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" + "friendsofphp/php-cs-fixer": "~2", + "phpunit/phpunit": "~4.0 || ~5.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.23-dev" + } + }, "autoload": { "psr-4": { "Carbon\\": "src/Carbon/" @@ -1698,11 +2153,11 @@ "datetime", "time" ], - "time": "2015-11-04 20:07:17" + "time": "2017-02-06T22:02:47+00:00" }, { "name": "nikic/php-parser", - "version": "v2.1.1", + "version": "2.x-dev", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", @@ -1749,20 +2204,20 @@ "parser", "php" ], - "time": "2016-09-16 12:04:44" + "time": "2016-09-16T12:04:44+00:00" }, { "name": "paragonie/random_compat", - "version": "v1.4.1", + "version": "v1.x-dev", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "c7e26a21ba357863de030f0b9e701c7d04593774" + "reference": "965cdeb01fdcab7653253aa81d40441d261f1e66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774", - "reference": "c7e26a21ba357863de030f0b9e701c7d04593774", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/965cdeb01fdcab7653253aa81d40441d261f1e66", + "reference": "965cdeb01fdcab7653253aa81d40441d261f1e66", "shasum": "" }, "require": { @@ -1797,7 +2252,99 @@ "pseudorandom", "random" ], - "time": "2016-03-18 20:34:03" + "time": "2017-03-13T16:22:52+00:00" + }, + { + "name": "phpseclib/phpseclib", + "version": "2.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "f68a85e99bfa80c21e335c5108d2ee9b5b6862ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/f68a85e99bfa80c21e335c5108d2ee9b5b6862ab", + "reference": "f68a85e99bfa80c21e335c5108d2ee9b5b6862ab", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "~4.0", + "sami/sami": "~2.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "time": "2017-07-30 21:19:23" }, { "name": "predis/predis", @@ -1847,11 +2394,107 @@ "predis", "redis" ], - "time": "2015-01-02 12:51:34" + "time": "2015-01-02T12:51:34+00:00" + }, + { + "name": "psr/cache", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "78c5a01ddbf11cf731f1338a4f5aba23b14d5b47" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/78c5a01ddbf11cf731f1338a4f5aba23b14d5b47", + "reference": "78c5a01ddbf11cf731f1338a4f5aba23b14d5b47", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-10-13 14:48:10" + }, + { + "name": "psr/http-message", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" }, { "name": "psr/log", - "version": "1.0.2", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", @@ -1894,7 +2537,7 @@ "psr", "psr-3" ], - "time": "2016-10-10 12:19:37" + "time": "2016-10-10T12:19:37+00:00" }, { "name": "psy/psysh", @@ -1966,71 +2609,238 @@ "interactive", "shell" ], - "time": "2016-03-09 05:03:14" + "time": "2016-03-09T05:03:14+00:00" }, { - "name": "react/promise", - "version": "v2.4.1", + "name": "sabre/uri", + "version": "1.x-dev", "source": { "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "8025426794f1944de806618671d4fa476dc7626f" + "url": "https://github.com/fruux/sabre-uri.git", + "reference": "ada354d83579565949d80b2e15593c2371225e61" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/8025426794f1944de806618671d4fa476dc7626f", - "reference": "8025426794f1944de806618671d4fa476dc7626f", + "url": "https://api.github.com/repos/fruux/sabre-uri/zipball/ada354d83579565949d80b2e15593c2371225e61", + "reference": "ada354d83579565949d80b2e15593c2371225e61", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=5.4.7" + }, + "require-dev": { + "phpunit/phpunit": ">=4.0,<6.0", + "sabre/cs": "~1.0.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Sabre\\Uri\\": "lib/" } }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "Functions for making sense out of URIs.", + "homepage": "http://sabre.io/uri/", + "keywords": [ + "rfc3986", + "uri", + "url" + ], + "time": "2017-02-20 19:59:28" + }, + { + "name": "sabre/xml", + "version": "1.5.x-dev", + "source": { + "type": "git", + "url": "https://github.com/fruux/sabre-xml.git", + "reference": "59b20e5bbace9912607481634f97d05a776ffca7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruux/sabre-xml/zipball/59b20e5bbace9912607481634f97d05a776ffca7", + "reference": "59b20e5bbace9912607481634f97d05a776ffca7", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "lib-libxml": ">=2.6.20", + "php": ">=5.5.5", + "sabre/uri": ">=1.0,<3.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*", + "sabre/cs": "~1.0.0" + }, + "type": "library", "autoload": { "psr-4": { - "React\\Promise\\": "src/" + "Sabre\\Xml\\": "lib/" }, "files": [ - "src/functions_include.php" + "lib/Deserializer/functions.php", + "lib/Serializer/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + }, + { + "name": "Markus Staab", + "email": "markus.staab@redaxo.de", + "role": "Developer" + } + ], + "description": "sabre/xml is an XML library that you may not hate.", + "homepage": "https://sabre.io/xml/", + "keywords": [ + "XMLReader", + "XMLWriter", + "dom", + "xml" + ], + "time": "2016-10-09 22:57:52" + }, + { + "name": "smarcet/caldavclient", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/smarcet/CalDAVClient.git", + "reference": "b5f5252e966d7ca90cb836de71804d0d0974507a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/smarcet/CalDAVClient/zipball/b5f5252e966d7ca90cb836de71804d0d0974507a", + "reference": "b5f5252e966d7ca90cb836de71804d0d0974507a", + "shasum": "" + }, + "require": { + "eluceo/ical": "^0.11.3", + "guzzlehttp/guzzle": "^6.3", + "sabre/xml": "^1.5" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "CalDAVClient\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com" + "name": "Sebastian Marcet", + "email": "smarcet@gmail.com" } ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "time": "2016-05-03 17:50:52" + "description": "CALDAV Client for PHP", + "homepage": "https://github.com/smarcet", + "keywords": [ + "CalDAV", + "calendar", + "icloud", + "synchronization" + ], + "time": "2017-07-31T13:22:07+00:00" }, { - "name": "swiftmailer/swiftmailer", - "version": "v5.4.3", + "name": "smarcet/outlook-rest-client", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153" + "url": "https://github.com/smarcet/OutlookRestClient.git", + "reference": "28ddb3effb6af7e3bb7cba7e8edfc58e1b2f73dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", - "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", + "url": "https://api.github.com/repos/smarcet/OutlookRestClient/zipball/28ddb3effb6af7e3bb7cba7e8edfc58e1b2f73dd", + "reference": "28ddb3effb6af7e3bb7cba7e8edfc58e1b2f73dd", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.3", + "league/oauth2-client": "^2.2", + "php": ">=5.6", + "vlucas/phpdotenv": "^2.4@dev" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "OutlookRestClient\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Marcet", + "email": "smarcet@gmail.com" + } + ], + "description": "Outlook REST Api Client", + "keywords": [ + "REST API", + "calendar", + "outlook", + "synchronization" + ], + "time": "2017-08-05 01:36:59" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "5.x-dev", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "e0ec3fd79fec8f86857c6f1b0ab6a3b69a1ebb15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/e0ec3fd79fec8f86857c6f1b0ab6a3b69a1ebb15", + "reference": "e0ec3fd79fec8f86857c6f1b0ab6a3b69a1ebb15", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "mockery/mockery": "~0.9.1" + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.2" }, "type": "library", "extra": { @@ -2063,11 +2873,11 @@ "mail", "mailer" ], - "time": "2016-07-08 11:51:25" + "time": "2017-08-02T17:03:33+00:00" }, { "name": "symfony/console", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/console.git", @@ -2123,11 +2933,11 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:22:48" + "time": "2016-07-30T07:22:48+00:00" }, { "name": "symfony/debug", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", @@ -2180,31 +2990,34 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:22:48" + "time": "2016-07-30T07:22:48+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.1.7", + "version": "3.4.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc" + "reference": "cd8b015f859e6b60933324db00067c2f060b4d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/28b0832b2553ffb80cabef6a7a812ff1e670c0bc", - "reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/cd8b015f859e6b60933324db00067c2f060b4d18", + "reference": "cd8b015f859e6b60933324db00067c2f060b4d18", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/dependency-injection": "<3.3" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/dependency-injection": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0" + "symfony/config": "~2.8|~3.0|~4.0", + "symfony/dependency-injection": "~3.3|~4.0", + "symfony/expression-language": "~2.8|~3.0|~4.0", + "symfony/stopwatch": "~2.8|~3.0|~4.0" }, "suggest": { "symfony/dependency-injection": "", @@ -2213,7 +3026,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -2240,11 +3053,11 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-10-13 06:28:43" + "time": "2017-08-03T09:34:20+00:00" }, { "name": "symfony/finder", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -2289,11 +3102,11 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:40:00" + "time": "2016-06-29T05:40:00+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", @@ -2342,20 +3155,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2016-07-17 13:54:30" + "time": "2016-07-17T13:54:30+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "d97ba4425e36e79c794e7d14ff36f00f081b37b3" + "reference": "03ac7bbc8fccbf002e0bea88dbe09262b29dc2a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/d97ba4425e36e79c794e7d14ff36f00f081b37b3", - "reference": "d97ba4425e36e79c794e7d14ff36f00f081b37b3", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/03ac7bbc8fccbf002e0bea88dbe09262b29dc2a9", + "reference": "03ac7bbc8fccbf002e0bea88dbe09262b29dc2a9", "shasum": "" }, "require": { @@ -2424,20 +3237,20 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2016-07-30 09:10:37" + "time": "2016-07-30T09:29:03+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.3.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" + "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7c8fae0ac1d216eb54349e6a8baa57d515fe8803", + "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803", "shasum": "" }, "require": { @@ -2449,7 +3262,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -2483,20 +3296,20 @@ "portable", "shim" ], - "time": "2016-11-14 01:06:16" + "time": "2017-06-14T15:44:48+00:00" }, { "name": "symfony/polyfill-php55", - "version": "v1.3.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php55.git", - "reference": "03e3f0350bca2220e3623a0e340eef194405fc67" + "reference": "29b1381d66f16e0581aab0b9f678ccf073288f68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/03e3f0350bca2220e3623a0e340eef194405fc67", - "reference": "03e3f0350bca2220e3623a0e340eef194405fc67", + "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/29b1381d66f16e0581aab0b9f678ccf073288f68", + "reference": "29b1381d66f16e0581aab0b9f678ccf073288f68", "shasum": "" }, "require": { @@ -2506,7 +3319,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -2539,20 +3352,20 @@ "portable", "shim" ], - "time": "2016-11-14 01:06:16" + "time": "2017-06-14T15:44:48+00:00" }, { "name": "symfony/polyfill-php56", - "version": "v1.3.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c" + "reference": "e85ebdef569b84e8709864e1a290c40f156b30ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/1dd42b9b89556f18092f3d1ada22cb05ac85383c", - "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/e85ebdef569b84e8709864e1a290c40f156b30ca", + "reference": "e85ebdef569b84e8709864e1a290c40f156b30ca", "shasum": "" }, "require": { @@ -2562,7 +3375,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -2595,20 +3408,20 @@ "portable", "shim" ], - "time": "2016-11-14 01:06:16" + "time": "2017-06-14T15:44:48+00:00" }, { "name": "symfony/polyfill-util", - "version": "v1.3.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-util.git", - "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb" + "reference": "5d2fc887042ffa5617c28d362f0f114a4c6048bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/746bce0fca664ac0a575e465f65c6643faddf7fb", - "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/5d2fc887042ffa5617c28d362f0f114a4c6048bf", + "reference": "5d2fc887042ffa5617c28d362f0f114a4c6048bf", "shasum": "" }, "require": { @@ -2617,7 +3430,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -2647,11 +3460,11 @@ "polyfill", "shim" ], - "time": "2016-11-14 01:06:16" + "time": "2017-06-14T15:44:48+00:00" }, { "name": "symfony/process", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -2696,11 +3509,11 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-07-28 11:13:34" + "time": "2016-07-28T11:13:34+00:00" }, { "name": "symfony/routing", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", @@ -2771,20 +3584,20 @@ "uri", "url" ], - "time": "2016-06-29 05:40:00" + "time": "2016-06-29T05:40:00+00:00" }, { "name": "symfony/serializer", - "version": "v2.8.14", + "version": "2.8.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "df9a4f82143668c2f775cc85e1972044c9e93d4d" + "reference": "ff6bd03c458a6007b05a2c4c4199cbc3417bf074" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/df9a4f82143668c2f775cc85e1972044c9e93d4d", - "reference": "df9a4f82143668c2f775cc85e1972044c9e93d4d", + "url": "https://api.github.com/repos/symfony/serializer/zipball/ff6bd03c458a6007b05a2c4c4199cbc3417bf074", + "reference": "ff6bd03c458a6007b05a2c4c4199cbc3417bf074", "shasum": "" }, "require": { @@ -2796,7 +3609,7 @@ "doctrine/cache": "~1.0", "symfony/config": "~2.2|~3.0.0", "symfony/property-access": "~2.3|~3.0.0", - "symfony/yaml": "~2.0,>=2.0.5|~3.0.0" + "symfony/yaml": "^2.0.5|~3.0.0" }, "suggest": { "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", @@ -2835,11 +3648,11 @@ ], "description": "Symfony Serializer Component", "homepage": "https://symfony.com", - "time": "2016-11-03 07:52:58" + "time": "2017-07-03T14:09:54+00:00" }, { "name": "symfony/translation", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", @@ -2899,11 +3712,11 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:22:48" + "time": "2016-07-30T07:22:48+00:00" }, { "name": "symfony/var-dumper", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", @@ -2962,20 +3775,20 @@ "debug", "dump" ], - "time": "2016-07-26 08:03:56" + "time": "2016-07-26T08:03:56+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.4.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" + "reference": "7ac2c1cef304f5bd5a8d40750fbcbdd49333b9e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", - "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/7ac2c1cef304f5bd5a8d40750fbcbdd49333b9e5", + "reference": "7ac2c1cef304f5bd5a8d40750fbcbdd49333b9e5", "shasum": "" }, "require": { @@ -3012,35 +3825,37 @@ "env", "environment" ], - "time": "2016-09-01 10:05:43" + "time": "2017-02-03T22:05:04+00:00" } ], "packages-dev": [ { "name": "fzaninotto/faker", - "version": "v1.6.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/fzaninotto/Faker.git", - "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" + "reference": "cb3bcad7dcb36b2db6d4d2c98144ffe800ba0feb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", - "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/cb3bcad7dcb36b2db6d4d2c98144ffe800ba0feb", + "reference": "cb3bcad7dcb36b2db6d4d2c98144ffe800ba0feb", "shasum": "" }, "require": { - "php": "^5.3.3|^7.0" + "php": "^5.3.3 || ^7.0" }, "require-dev": { "ext-intl": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.5" + "phpunit/phpunit": "^4.0 || ^5.0", + "squizlabs/php_codesniffer": "^1.5" }, "type": "library", "extra": { - "branch-alias": [] + "branch-alias": { + "dev-master": "1.7-dev" + } }, "autoload": { "psr-4": { @@ -3062,130 +3877,20 @@ "faker", "fixtures" ], - "time": "2016-04-29 12:21:54" - }, - { - "name": "hamcrest/hamcrest-php", - "version": "v1.2.2", - "source": { - "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c", - "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" - }, - "require-dev": { - "phpunit/php-file-iterator": "1.3.3", - "satooshi/php-coveralls": "dev-master" - }, - "type": "library", - "autoload": { - "classmap": [ - "hamcrest" - ], - "files": [ - "hamcrest/Hamcrest.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD" - ], - "description": "This is the PHP port of Hamcrest Matchers", - "keywords": [ - "test" - ], - "time": "2015-05-11 14:41:42" - }, - { - "name": "mockery/mockery", - "version": "0.9.6", - "source": { - "type": "git", - "url": "https://github.com/padraic/mockery.git", - "reference": "65d4ca18e15cb02eeb1e5336f884e46b9b905be0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/padraic/mockery/zipball/65d4ca18e15cb02eeb1e5336f884e46b9b905be0", - "reference": "65d4ca18e15cb02eeb1e5336f884e46b9b905be0", - "shasum": "" - }, - "require": { - "hamcrest/hamcrest-php": "~1.1", - "lib-pcre": ">=7.0", - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.9.x-dev" - } - }, - "autoload": { - "psr-0": { - "Mockery": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" - }, - { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" - } - ], - "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", - "homepage": "http://github.com/padraic/mockery", - "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" - ], - "time": "2016-09-30 12:09:40" + "time": "2017-08-03T09:15:57+00:00" }, { "name": "phpdocumentor/reflection-common", - "version": "1.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + "reference": "a046af61c36e9162372f205de091a1cab7340f1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/a046af61c36e9162372f205de091a1cab7340f1c", + "reference": "a046af61c36e9162372f205de091a1cab7340f1c", "shasum": "" }, "require": { @@ -3226,26 +3931,26 @@ "reflection", "static analysis" ], - "time": "2015-12-27 11:43:31" + "time": "2017-04-30T11:58:12+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "3.1.1", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" + "reference": "183824db76118b9dddffc7e522b91fa175f75119" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/183824db76118b9dddffc7e522b91fa175f75119", + "reference": "183824db76118b9dddffc7e522b91fa175f75119", "shasum": "" }, "require": { "php": ">=5.5", "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", + "phpdocumentor/type-resolver": "^0.3.0", "webmozart/assert": "^1.0" }, "require-dev": { @@ -3271,24 +3976,24 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-09-30 07:12:33" + "time": "2017-08-04T20:55:59+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.2", + "version": "0.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fb3933512008d8162b3cdf9e18dba9309b7c3773", + "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773", "shasum": "" }, "require": { - "php": ">=5.5", + "php": "^5.5 || ^7.0", "phpdocumentor/reflection-common": "^1.0" }, "require-dev": { @@ -3318,36 +4023,37 @@ "email": "me@mikevanriel.com" } ], - "time": "2016-06-10 07:14:17" + "time": "2017-06-03T08:32:36+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.6.1", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + "reference": "420d44c5534bbf269e85e6213446e8284d53c6c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/420d44c5534bbf269e85e6213446e8284d53c6c7", + "reference": "420d44c5534bbf269e85e6213446e8284d53c6c7", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0" + "sebastian/comparator": "^1.1|^2.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { - "phpspec/phpspec": "^2.0" + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8 || ^5.6.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -3380,11 +4086,11 @@ "spy", "stub" ], - "time": "2016-06-07 08:13:47" + "time": "2017-07-19T07:44:25+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "2.2.4", + "version": "2.2.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", @@ -3442,20 +4148,20 @@ "testing", "xunit" ], - "time": "2015-10-06 15:47:00" + "time": "2015-10-06T15:47:00+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.1", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", "shasum": "" }, "require": { @@ -3489,7 +4195,7 @@ "filesystem", "iterator" ], - "time": "2015-06-21 13:08:43" + "time": "2016-10-03T07:40:28+00:00" }, { "name": "phpunit/php-text-template", @@ -3530,29 +4236,34 @@ "keywords": [ "template" ], - "time": "2015-06-21 13:50:34" + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", - "version": "1.0.8", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + "reference": "d107f347d368dd8a384601398280c7c608390ab7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/d107f347d368dd8a384601398280c7c608390ab7", + "reference": "d107f347d368dd8a384601398280c7c608390ab7", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4|~5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -3574,20 +4285,20 @@ "keywords": [ "timer" ], - "time": "2016-05-12 18:03:57" + "time": "2017-03-07T15:42:04+00:00" }, { "name": "phpunit/php-token-stream", - "version": "1.4.9", + "version": "1.4.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b" + "reference": "958103f327daef5dd0bb328dec53e0a9e43cfaf7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b", - "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/958103f327daef5dd0bb328dec53e0a9e43cfaf7", + "reference": "958103f327daef5dd0bb328dec53e0a9e43cfaf7", "shasum": "" }, "require": { @@ -3623,20 +4334,20 @@ "keywords": [ "tokenizer" ], - "time": "2016-11-15 14:06:22" + "time": "2017-03-07T08:21:50+00:00" }, { "name": "phpunit/phpunit", - "version": "4.8.29", + "version": "4.8.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f19d481b468b76a7fb55eb2b772ed487e484891e" + "reference": "18e5f52e8412d23e739f7d8744e177039860e800" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f19d481b468b76a7fb55eb2b772ed487e484891e", - "reference": "f19d481b468b76a7fb55eb2b772ed487e484891e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/18e5f52e8412d23e739f7d8744e177039860e800", + "reference": "18e5f52e8412d23e739f7d8744e177039860e800", "shasum": "" }, "require": { @@ -3695,11 +4406,11 @@ "testing", "xunit" ], - "time": "2016-11-20 10:35:28" + "time": "2017-06-23T12:44:27+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", + "version": "2.3.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", @@ -3751,20 +4462,20 @@ "mock", "xunit" ], - "time": "2015-10-02 06:51:40" + "time": "2015-10-02T06:51:40+00:00" }, { "name": "sebastian/comparator", - "version": "1.2.2", + "version": "1.2.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f" + "reference": "18a5d97c25f408f48acaf6d1b9f4079314c5996a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f", - "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/18a5d97c25f408f48acaf6d1b9f4079314c5996a", + "reference": "18a5d97c25f408f48acaf6d1b9f4079314c5996a", "shasum": "" }, "require": { @@ -3815,27 +4526,27 @@ "compare", "equality" ], - "time": "2016-11-19 09:18:40" + "time": "2017-03-07T10:34:43+00:00" }, { "name": "sebastian/diff", - "version": "1.4.1", + "version": "1.4.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", "extra": { @@ -3867,27 +4578,27 @@ "keywords": [ "diff" ], - "time": "2015-12-08 07:14:41" + "time": "2017-05-22T07:24:03+00:00" }, { "name": "sebastian/environment", - "version": "1.3.8", + "version": "1.3.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + "reference": "67f55699c2810ff0f2cc47478bbdeda8567e68ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/67f55699c2810ff0f2cc47478bbdeda8567e68ee", + "reference": "67f55699c2810ff0f2cc47478bbdeda8567e68ee", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", "extra": { @@ -3917,34 +4628,34 @@ "environment", "hhvm" ], - "time": "2016-08-18 05:49:44" + "time": "2017-02-28T08:18:59+00:00" }, { "name": "sebastian/exporter", - "version": "1.2.2", + "version": "1.2.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + "reference": "dcd43bcc0fd3551bd2ede0081882d549bb78225d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/dcd43bcc0fd3551bd2ede0081882d549bb78225d", + "reference": "dcd43bcc0fd3551bd2ede0081882d549bb78225d", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" + "php": "^5.3.3 || ^7.0", + "sebastian/recursion-context": "^1.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -3984,27 +4695,27 @@ "export", "exporter" ], - "time": "2016-06-17 09:04:28" + "time": "2017-02-26T13:09:30+00:00" }, { "name": "sebastian/global-state", - "version": "1.1.1", + "version": "1.1.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + "reference": "cea85a84b00f2795341ebbbca4fa396347f2494e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/cea85a84b00f2795341ebbbca4fa396347f2494e", + "reference": "cea85a84b00f2795341ebbbca4fa396347f2494e", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "phpunit/phpunit": "~4.2|~5.0" }, "suggest": { "ext-uopz": "*" @@ -4035,20 +4746,20 @@ "keywords": [ "global state" ], - "time": "2015-10-12 03:26:01" + "time": "2017-02-23T14:11:06+00:00" }, { "name": "sebastian/recursion-context", - "version": "1.0.2", + "version": "1.0.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", "shasum": "" }, "require": { @@ -4088,7 +4799,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-11-11 19:50:13" + "time": "2016-10-03T07:41:43+00:00" }, { "name": "sebastian/version", @@ -4123,11 +4834,11 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21 13:59:46" + "time": "2015-06-21T13:59:46+00:00" }, { "name": "symfony/css-selector", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", @@ -4176,11 +4887,11 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:40:00" + "time": "2016-06-29T05:40:00+00:00" }, { "name": "symfony/dom-crawler", - "version": "v3.0.9", + "version": "3.0.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", @@ -4232,29 +4943,35 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:22:48" + "time": "2016-07-30T07:22:48+00:00" }, { "name": "symfony/yaml", - "version": "v3.1.7", + "version": "3.4.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "9da375317228e54f4ea1b013b30fa47417e84943" + "reference": "1395ddba6f65bf46cdf1d80d59223cbab8ff3ccc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/9da375317228e54f4ea1b013b30fa47417e84943", - "reference": "9da375317228e54f4ea1b013b30fa47417e84943", + "url": "https://api.github.com/repos/symfony/yaml/zipball/1395ddba6f65bf46cdf1d80d59223cbab8ff3ccc", + "reference": "1395ddba6f65bf46cdf1d80d59223cbab8ff3ccc", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^5.5.9|>=7.0.8" + }, + "require-dev": { + "symfony/console": "~2.8|~3.0|~4.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -4281,24 +4998,24 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-11-18 21:05:29" + "time": "2017-08-04T13:29:48+00:00" }, { "name": "webmozart/assert", - "version": "1.1.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "bb2d123231c095735130cc8f6d31385a44c7b308" + "reference": "4a8bf11547e139e77b651365113fc12850c43d9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308", - "reference": "bb2d123231c095735130cc8f6d31385a44c7b308", + "url": "https://api.github.com/repos/webmozart/assert/zipball/4a8bf11547e139e77b651365113fc12850c43d9a", + "reference": "4a8bf11547e139e77b651365113fc12850c43d9a", "shasum": "" }, "require": { - "php": "^5.3.3|^7.0" + "php": "^5.3.3 || ^7.0" }, "require-dev": { "phpunit/phpunit": "^4.6", @@ -4307,7 +5024,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -4331,12 +5048,15 @@ "check", "validate" ], - "time": "2016-08-09 15:02:57" + "time": "2016-11-23T20:04:41+00:00" } ], "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], + "minimum-stability": "dev", + "stability-flags": { + "smarcet/caldavclient": 20, + "smarcet/outlook-rest-client": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/config/app.php b/config/app.php index 36ad7fa2..a12b083c 100644 --- a/config/app.php +++ b/config/app.php @@ -212,6 +212,7 @@ return [ 'EntityManager' => LaravelDoctrine\ORM\Facades\EntityManager::class, 'Registry' => LaravelDoctrine\ORM\Facades\Registry::class, 'Doctrine' => LaravelDoctrine\ORM\Facades\Doctrine::class, + 'Encryption' => services\utils\Facades\Encryption::class, ], ]; diff --git a/config/apple_api.php b/config/apple_api.php new file mode 100644 index 00000000..3c5c459c --- /dev/null +++ b/config/apple_api.php @@ -0,0 +1,17 @@ + env('APPLE_CALDAV_BASE_SERVER', "p01-caldav.icloud.com"), +]; \ No newline at end of file diff --git a/config/doctrine.php b/config/doctrine.php index a3fa488b..72142a53 100644 --- a/config/doctrine.php +++ b/config/doctrine.php @@ -74,7 +74,7 @@ return [ |-------------------------------------------------------------------------- */ 'mapping_types' => [ - //'enum' => 'string' + 'enum' => 'string' ] ], 'ss' => [ @@ -130,7 +130,7 @@ return [ |-------------------------------------------------------------------------- */ 'mapping_types' => [ - //'enum' => 'string' + 'enum' => 'string' ] ] ], diff --git a/config/google_api.php b/config/google_api.php new file mode 100644 index 00000000..a32d297f --- /dev/null +++ b/config/google_api.php @@ -0,0 +1,19 @@ + env('GOOGLE_CLIENT_ID', null), + 'google_client_secret' => env('GOOGLE_CLIENT_SECRET', null), + 'google_scopes' => env('GOOGLE_SCOPES', null), +]; \ No newline at end of file diff --git a/config/server.php b/config/server.php index 141d70a9..bd433525 100644 --- a/config/server.php +++ b/config/server.php @@ -22,4 +22,6 @@ return array 'response_cache_lifetime' => env('API_RESPONSE_CACHE_LIFETIME', 300), 'eventbrite_oauth2_personal_token' => env('EVENTBRITE_OAUTH2_PERSONAL_TOKEN', ''), 'firebase_gcm_server_key' => env('FIREBASE_GCM_SERVER_KEY', ''), + 'ss_encrypt_key' => env('SS_ENCRYPT_KEY', ''), + 'ss_encrypt_cypher' => env('SS_ENCRYPT_CYPHER', ''), ); \ No newline at end of file diff --git a/tests/AdminActionsCalendarSyncPreProcessorTest.php b/tests/AdminActionsCalendarSyncPreProcessorTest.php new file mode 100644 index 00000000..97ff0c8e --- /dev/null +++ b/tests/AdminActionsCalendarSyncPreProcessorTest.php @@ -0,0 +1,170 @@ +shouldIgnoreMissing(); + $app->instance(IAbstractCalendarSyncWorkRequestRepository::class, $repo_mock); + + $repo_mock = Mockery::mock(ICalendarSyncInfoRepository::class)->shouldIgnoreMissing(); + $app->instance(ICalendarSyncInfoRepository::class, $repo_mock); + return $app; + } + + public function testUpdateFourthSameEvent(){ + $preprocessor = App::make('App\Services\Model\AdminActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $mock_update_request = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $mock_update_request1 = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request1->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request1->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $mock_update_request2 = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request2->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request2->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $mock_update_request3 = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request3->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request3->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $purged_requests = $preprocessor->preProcessActions([ + $mock_update_request, + $mock_update_request1, + $mock_update_request2, + $mock_update_request3 + ]); + + $this->assertTrue(count($purged_requests) == 1); + } + + public function testUpdateFourthTimesDeleteSameEvent(){ + $preprocessor = App::make('App\Services\Model\AdminActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $mock_update_request = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $mock_update_request1 = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request1->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request1->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $mock_update_request2 = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request2->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request2->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $mock_update_request3 = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request3->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request3->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $mock_delete_request = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_delete_request->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_delete_request->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeRemove); + + $purged_requests = $preprocessor->preProcessActions([ + $mock_update_request, + $mock_update_request1, + $mock_delete_request, + $mock_update_request2, + $mock_update_request3 + ]); + + $this->assertTrue(count($purged_requests) == 1); + $this->assertTrue($purged_requests[0]->getType() == AbstractCalendarSyncWorkRequest::TypeUpdate); + } + + public function testDeleteUpdateSameEvent(){ + $preprocessor = App::make('App\Services\Model\AdminActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $mock_delete_request = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_delete_request->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_delete_request->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeRemove); + + $mock_update_request = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $purged_requests = $preprocessor->preProcessActions([ + $mock_delete_request, + $mock_update_request + ]); + + $this->assertTrue(count($purged_requests) == 1); + $this->assertTrue($purged_requests[0]->getType() == AbstractCalendarSyncWorkRequest::TypeUpdate); + } + + + public function testUpdateDeleteSameEvent(){ + + $preprocessor = App::make('App\Services\Model\AdminActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $mock_delete_request = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_delete_request->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_delete_request->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeRemove); + + $mock_update_request = Mockery::mock(AdminSummitEventActionSyncWorkRequest::class); + $mock_update_request->shouldReceive('getSummitEvent')->andReturn($summit_event); + $mock_update_request->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + + $purged_requests = $preprocessor->preProcessActions([ + $mock_update_request, + $mock_delete_request, + ]); + + $this->assertTrue(count($purged_requests) == 1); + $this->assertTrue($purged_requests[0]->getType() == AbstractCalendarSyncWorkRequest::TypeRemove); + } + +} \ No newline at end of file diff --git a/tests/MemberActionsCalendarSyncPreProcessorTest.php b/tests/MemberActionsCalendarSyncPreProcessorTest.php new file mode 100644 index 00000000..f30b0b5f --- /dev/null +++ b/tests/MemberActionsCalendarSyncPreProcessorTest.php @@ -0,0 +1,308 @@ +shouldIgnoreMissing(); + $app->instance(IAbstractCalendarSyncWorkRequestRepository::class, $repo_mock); + + $repo_mock = Mockery::mock(ICalendarSyncInfoRepository::class)->shouldIgnoreMissing(); + $app->instance(ICalendarSyncInfoRepository::class, $repo_mock); + return $app; + } + + public function testSynchronizedRemoveUpdateAdd(){ + + $preprocessor = App::make('App\Services\Model\MemberActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $member_mock = Mockery::mock(Member::class); + $member_mock->shouldReceive("isEventSynchronized")->andReturn(true); + + $calendar_sync_info = Mockery::mock(CalendarSyncInfo::class); + $calendar_sync_info->shouldReceive("getId")->andReturn(1); + + $request_delete_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_delete_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_delete_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeRemove); + $request_delete_mock->shouldReceive("getOwner")->andReturn($member_mock); + $request_delete_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + + $request_update_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_update_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_update_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + $request_update_mock->shouldReceive("getOwner")->andReturn($member_mock); + $request_update_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + + $request_add_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_add_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_add_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeAdd); + $request_add_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + $request_add_mock->shouldReceive("getOwner")->andReturn($member_mock); + + + // preconditions event id 1 is already synchronized with user external calendar + // we pass over the time this work load + // delete , update, add + // bc event is already synchronized, the purged actions should only emmit an update + $purged_requests = $preprocessor->preProcessActions([ + $request_delete_mock, + $request_update_mock, + $request_add_mock + ]); + + $this->assertTrue(count($purged_requests) == 1); + + $this->assertTrue($purged_requests[0]->getType() == AbstractCalendarSyncWorkRequest::TypeUpdate); + } + + public function testSynchronizedRemoveAdd(){ + + $preprocessor = App::make('App\Services\Model\MemberActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $member_mock = Mockery::mock(Member::class); + $member_mock->shouldReceive("isEventSynchronized")->andReturn(true); + + $calendar_sync_info = Mockery::mock(CalendarSyncInfo::class); + $calendar_sync_info->shouldReceive("getId")->andReturn(1); + + $request_delete_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_delete_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_delete_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeRemove); + $request_delete_mock->shouldReceive("getOwner")->andReturn($member_mock); + $request_delete_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + + $request_add_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_add_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_add_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeAdd); + $request_add_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + $request_add_mock->shouldReceive("getOwner")->andReturn($member_mock); + + + // preconditions event id 1 is already synchronized with user external calendar + // we pass over the time this work load + // delete , add + // bc event is already synchronized, the purged actions should only emmit zero elements ( no action) + $purged_requests = $preprocessor->preProcessActions([ + $request_delete_mock, + $request_add_mock + ]); + + $this->assertTrue(count($purged_requests) == 0); + } + + public function testSynchronizedRemoveUpdate(){ + + $preprocessor = App::make('App\Services\Model\MemberActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $member_mock = Mockery::mock(Member::class); + $member_mock->shouldReceive("isEventSynchronized")->andReturn(true); + + $calendar_sync_info = Mockery::mock(CalendarSyncInfo::class); + $calendar_sync_info->shouldReceive("getId")->andReturn(1); + + $request_delete_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_delete_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_delete_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeRemove); + $request_delete_mock->shouldReceive("getOwner")->andReturn($member_mock); + $request_delete_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + + $request_update_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_update_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_update_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + $request_update_mock->shouldReceive("getOwner")->andReturn($member_mock); + $request_update_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + + + // preconditions event id 1 is already synchronized with user external calendar + // we pass over the time this work load + // delete, update + // bc event is already synchronized, the purged actions should only emmit an delete + $purged_requests = $preprocessor->preProcessActions([ + $request_delete_mock, + $request_update_mock, + ]); + + $this->assertTrue(count($purged_requests) == 1); + + $this->assertTrue($purged_requests[0]->getType() == AbstractCalendarSyncWorkRequest::TypeRemove); + } + + public function testSynchronizedUpdateRemove(){ + + $preprocessor = App::make('App\Services\Model\MemberActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $member_mock = Mockery::mock(Member::class); + $member_mock->shouldReceive("isEventSynchronized")->andReturn(true); + + $calendar_sync_info = Mockery::mock(CalendarSyncInfo::class); + $calendar_sync_info->shouldReceive("getId")->andReturn(1); + + $request_delete_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_delete_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_delete_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeRemove); + $request_delete_mock->shouldReceive("getOwner")->andReturn($member_mock); + $request_delete_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + + $request_update_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_update_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_update_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeUpdate); + $request_update_mock->shouldReceive("getOwner")->andReturn($member_mock); + $request_update_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + + + // preconditions event id 1 is already synchronized with user external calendar + // we pass over the time this work load + // update, delete + // bc event is already synchronized, the purged actions should only emmit an delete + $purged_requests = $preprocessor->preProcessActions([ + $request_update_mock, + $request_delete_mock, + ]); + + $this->assertTrue(count($purged_requests) == 1); + + $this->assertTrue($purged_requests[0]->getType() == AbstractCalendarSyncWorkRequest::TypeRemove); + } + + public function testUnSynchronizedAddRemoveAdd(){ + + $preprocessor = App::make('App\Services\Model\MemberActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $member_mock = Mockery::mock(Member::class); + $member_mock->shouldReceive("isEventSynchronized")->andReturn(false); + + $calendar_sync_info = Mockery::mock(CalendarSyncInfo::class); + $calendar_sync_info->shouldReceive("getId")->andReturn(1); + + + $request_add_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_add_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_add_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeAdd); + $request_add_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + $request_add_mock->shouldReceive("getOwner")->andReturn($member_mock); + + + $request_delete_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_delete_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_delete_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeRemove); + $request_delete_mock->shouldReceive("getOwner")->andReturn($member_mock); + $request_delete_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + + $request_add_mock2 = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_add_mock2->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_add_mock2->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeAdd); + $request_add_mock2->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + $request_add_mock2->shouldReceive("getOwner")->andReturn($member_mock); + + + // preconditions event id 1 is not synchronized + // we pass over the time this work load + // add , delete, add + // bc event is already synchronized, the purged actions should only emmit 1 element : add + $purged_requests = $preprocessor->preProcessActions([ + $request_add_mock, + $request_delete_mock, + $request_add_mock2 + ]); + + $this->assertTrue(count($purged_requests) == 1); + $this->assertTrue($purged_requests[0]->getType() == AbstractCalendarSyncWorkRequest::TypeAdd); + } + + public function testUnSynchronizedAddAdd(){ + + $preprocessor = App::make('App\Services\Model\MemberActionsCalendarSyncPreProcessor'); + + $summit_event = Mockery::mock(SummitEvent::class); + $summit_event->shouldReceive('getId')->andReturn(1); + + $member_mock = Mockery::mock(Member::class); + $member_mock->shouldReceive("isEventSynchronized")->andReturn(false); + + $calendar_sync_info = Mockery::mock(CalendarSyncInfo::class); + $calendar_sync_info->shouldReceive("getId")->andReturn(1); + + + $request_add_mock = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_add_mock->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_add_mock->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeAdd); + $request_add_mock->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + $request_add_mock->shouldReceive("getOwner")->andReturn($member_mock); + + $request_add_mock2 = Mockery::mock(MemberEventScheduleSummitActionSyncWorkRequest::class); + $request_add_mock2->shouldReceive('getSummitEvent')->andReturn($summit_event); + $request_add_mock2->shouldReceive('getType')->andReturn(AbstractCalendarSyncWorkRequest::TypeAdd); + $request_add_mock2->shouldReceive("getCalendarSyncInfo")->andReturn($calendar_sync_info); + $request_add_mock2->shouldReceive("getOwner")->andReturn($member_mock); + + + // preconditions event id 1 is not synchronized + // we pass over the time this work load + // add , delete, add + // bc event is already synchronized, the purged actions should only emmit 1 element : add + $purged_requests = $preprocessor->preProcessActions([ + $request_add_mock, + $request_add_mock2 + ]); + + $this->assertTrue(count($purged_requests) == 1); + $this->assertTrue($purged_requests[0]->getType() == AbstractCalendarSyncWorkRequest::TypeAdd); + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitApiTest.php b/tests/OAuth2SummitApiTest.php index d4e6c400..209157a5 100644 --- a/tests/OAuth2SummitApiTest.php +++ b/tests/OAuth2SummitApiTest.php @@ -266,7 +266,6 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertTrue(!is_null($attendee)); } - public function testCurrentSummitMyAttendeeAddToSchedule($event_id = 18845, $summit_id = 22) { $params = array @@ -290,7 +289,6 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertResponseStatus(201); } - public function testCurrentSummitMyAttendeeScheduleUnset($event_id = 18845, $summit_id = 22) { //$this->testCurrentSummitMyAttendeeAddToSchedule($event_id, $summit_id); @@ -2148,7 +2146,7 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertTrue(!is_null($events)); } - public function testAdd2Favorite($summit_id = 7, $event_id = 14964){ + public function testAdd2Favorite($summit_id = 22, $event_id = 18719){ $params = array ( 'id' => $summit_id, @@ -2170,7 +2168,7 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertResponseStatus(201); } - public function testRemoveFromFavorites($summit_id = 7, $event_id = 14964){ + public function testRemoveFromFavorites($summit_id = 22, $event_id = 18719){ $params = array ( @@ -2271,6 +2269,53 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertTrue(!is_null($favorites)); } + public function testCurrentSummitMemberAddToSchedule($event_id = 18845, $summit_id = 22) + { + $params = array + ( + 'id' => $summit_id, + 'member_id' => 'me', + 'event_id' => $event_id + ); + + $headers = array("HTTP_Authorization" => " Bearer " . $this->access_token); + $response = $this->action( + "POST", + "OAuth2SummitMembersApiController@addEventToMemberSchedule", + $params, + array(), + array(), + array(), + $headers + ); + $content = $response->getContent(); + $this->assertResponseStatus(201); + } + + public function testCurrentSummitMemberScheduleUnset($event_id = 18845, $summit_id = 22) + { + $this->testCurrentSummitMemberAddToSchedule($event_id, $summit_id); + $params = array + ( + 'id' => $summit_id, + 'member_id' => 'me', + 'event_id' => $event_id + ); + + $headers = array("HTTP_Authorization" => " Bearer " . $this->access_token); + $response = $this->action( + "DELETE", + "OAuth2SummitMembersApiController@removeEventFromMemberSchedule", + $params, + array(), + array(), + array(), + $headers + ); + $content = $response->getContent(); + $this->assertResponseStatus(204); + } + public function testCurrentSummitMyMemberScheduleUnRSVP($event_id = 18639, $summit_id = 22) { //$this->testCurrentSummitMyAttendeeAddToSchedule($event_id, $summit_id); diff --git a/tests/ProtectedApiTest.php b/tests/ProtectedApiTest.php index e5f44f20..a9d25e55 100644 --- a/tests/ProtectedApiTest.php +++ b/tests/ProtectedApiTest.php @@ -57,7 +57,7 @@ class AccessTokenServiceStub implements IAccessTokenService $url . '/me/summits/events/favorites/delete', ); - return AccessToken::createFromParams('123456789', implode(' ', $scopes), '1', $realm, '1','13867', 3600, 'WEB_APPLICATION', '', ''); + return AccessToken::createFromParams('123456789', implode(' ', $scopes), '1', $realm, '1','11624', 3600, 'WEB_APPLICATION', '', ''); } }