Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add event organizer #260

Merged
merged 3 commits into from
Apr 26, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Event organizer

## [2.1.0] - 2021-04-21

### Fixed
Expand Down
135 changes: 62 additions & 73 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions examples/example1.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
use Eluceo\iCal\Domain\ValueObject\Alarm;
use Eluceo\iCal\Domain\ValueObject\Attachment;
use Eluceo\iCal\Domain\ValueObject\DateTime;
use Eluceo\iCal\Domain\ValueObject\EmailAddress;
use Eluceo\iCal\Domain\ValueObject\GeographicPosition;
use Eluceo\iCal\Domain\ValueObject\Location;
use Eluceo\iCal\Domain\ValueObject\Organizer;
use Eluceo\iCal\Domain\ValueObject\TimeSpan;
use Eluceo\iCal\Domain\ValueObject\Uri;
use Eluceo\iCal\Presentation\Factory\CalendarFactory;
Expand All @@ -31,6 +33,10 @@
$event
->setSummary('Christmas Eve')
->setDescription('Lorem Ipsum Dolor...')
->setOrganizer(new Organizer(
new EmailAddress('john.doe@example.com'),
'John Doe'
))
->setLocation(
(new Location('Neuschwansteinstraße 20, 87645 Schwangau', 'Schloss Neuschwanstein'))
->withGeographicPosition(new GeographicPosition(47.557579, 10.749704))
Expand Down
21 changes: 21 additions & 0 deletions src/Domain/Entity/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Eluceo\iCal\Domain\ValueObject\Attachment;
use Eluceo\iCal\Domain\ValueObject\Location;
use Eluceo\iCal\Domain\ValueObject\Occurrence;
use Eluceo\iCal\Domain\ValueObject\Organizer;
use Eluceo\iCal\Domain\ValueObject\Timestamp;
use Eluceo\iCal\Domain\ValueObject\UniqueIdentifier;

Expand All @@ -26,6 +27,7 @@ class Event
private ?string $description = null;
private ?Occurrence $occurrence = null;
private ?Location $location = null;
private ?Organizer $organizer = null;

/**
* @var array<Alarm>
Expand Down Expand Up @@ -150,6 +152,25 @@ public function hasLocation(): bool
return $this->location !== null;
}

public function getOrganizer(): Organizer
{
assert($this->organizer !== null);

return $this->organizer;
}

public function setOrganizer(?Organizer $organizer): self
{
$this->organizer = $organizer;

return $this;
}

public function hasOrganizer(): bool
{
return $this->organizer !== null;
}

/**
* @return Alarm[]
*/
Expand Down
38 changes: 38 additions & 0 deletions src/Domain/ValueObject/EmailAddress.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

/*
* This file is part of the eluceo/iCal package.
*
* (c) 2021 Markus Poerschke <markus@poerschke.nrw>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Eluceo\iCal\Domain\ValueObject;

use InvalidArgumentException;

final class EmailAddress
{
private string $emailAddress;

public function __construct(string $emailAddress)
{
if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("$emailAddress is no valid e-mail address");
}

$this->emailAddress = $emailAddress;
}

public function getEmailAddress(): string
{
return $this->emailAddress;
}

public function toUri(): Uri
{
return new Uri('mailto:' . urlencode($this->emailAddress));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outlook 2016 is having trouble with the encoded "@" character in the email address.

According to RFC standard, the mailto: doesn't require the url-encoding of that character. From the RFC 5545 3.8.4.3 (Organizer) section, see its examples, but it says "Value Type: CAL-ADDRESS" -> look for that in the RFC, find definition here -> says "the value must be a mailto URI, as defined by [RFC2368].", see its examples.

By RFC 2368's examples, it seems that it implies the "@" should remain unencoded. The solution then would mean parsing the email address, such as is seen in this related StackOverflow discussion on the topic: https://stackoverflow.com/questions/8940445/what-is-the-correct-way-to-escape-a-string-for-a-mailto-link

In our case, we're going to just look for %40 in the ORGANIZER property and convert it back to @, which will suffice.

}
}
83 changes: 83 additions & 0 deletions src/Domain/ValueObject/Organizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

/*
* This file is part of the eluceo/iCal package.
*
* (c) 2021 Markus Poerschke <markus@poerschke.nrw>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Eluceo\iCal\Domain\ValueObject;

final class Organizer
{
private EmailAddress $emailAddress;
private ?string $displayName;

/**
* The e-mail address of another user that is acting on behalf of the "Organizer".
*/
private ?EmailAddress $sentBy;

/**
* To specify reference to a directory entry associated wit the calendar user specified by the property.
*
* @see https://tools.ietf.org/html/rfc5545#section-3.2.6
*/
private ?Uri $directoryEntry;

public function __construct(
EmailAddress $emailAddress,
?string $displayName = null,
?Uri $directoryEntry = null,
?EmailAddress $sentBy = null
) {
$this->emailAddress = $emailAddress;
$this->displayName = $displayName;
$this->directoryEntry = $directoryEntry;
$this->sentBy = $sentBy;
}

public function getEmailAddress(): EmailAddress
{
return $this->emailAddress;
}

public function hasDisplayName(): bool
{
return $this->displayName !== null;
}

public function getDisplayName(): string
{
assert($this->displayName !== null);

return $this->displayName;
}

public function isSentInBehalfOf(): bool
{
return $this->sentBy !== null;
}

public function getSentBy(): EmailAddress
{
assert($this->sentBy !== null);

return $this->sentBy;
}

public function hasDirectoryEntry(): bool
{
return $this->directoryEntry !== null;
}

public function getDirectoryEntry(): Uri
{
assert($this->directoryEntry !== null);

return $this->directoryEntry;
}
}
24 changes: 24 additions & 0 deletions src/Presentation/Factory/EventFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Eluceo\iCal\Domain\ValueObject\Attachment;
use Eluceo\iCal\Domain\ValueObject\MultiDay;
use Eluceo\iCal\Domain\ValueObject\Occurrence;
use Eluceo\iCal\Domain\ValueObject\Organizer;
use Eluceo\iCal\Domain\ValueObject\SingleDay;
use Eluceo\iCal\Domain\ValueObject\TimeSpan;
use Eluceo\iCal\Presentation\Component;
Expand Down Expand Up @@ -91,6 +92,10 @@ protected function getProperties(Event $event): Generator
yield from $this->getLocationProperties($event);
}

if ($event->hasOrganizer()) {
yield $this->getOrganizerProperty($event->getOrganizer());
}

foreach ($event->getAttachments() as $attachment) {
yield from $this->getAttachmentProperties($attachment);
}
Expand Down Expand Up @@ -179,4 +184,23 @@ private function getAttachmentProperties(Attachment $attachment): Generator
);
}
}

private function getOrganizerProperty(Organizer $organizer): Property
{
$parameters = [];

if ($organizer->hasDisplayName()) {
$parameters[] = new Parameter('CN', new TextValue($organizer->getDisplayName()));
}

if ($organizer->hasDirectoryEntry()) {
$parameters[] = new Parameter('DIR', new UriValue($organizer->getDirectoryEntry()));
}

if ($organizer->isSentInBehalfOf()) {
$parameters[] = new Parameter('SENT-BY', new UriValue($organizer->getSentBy()->toUri()));
}

return new Property('ORGANIZER', new UriValue($organizer->getEmailAddress()->toUri()), $parameters);
}
}
Loading