Sending to nextcloud groups#810
Conversation
| $container->registerAlias('ErrorMiddleware', ErrorMiddleware::class); | ||
| $container->registerMiddleWare('ErrorMiddleware'); | ||
|
|
||
| $container->registerService('OCA\Mail\Service\GroupsIntegration', function($c) { |
There was a problem hiding this comment.
I don't think you have to register this here. The DI container should be able to resolve this class automatically.
There was a problem hiding this comment.
How should the container know which AbstractGroupServices GroupsIntegration should be constructed with?
There was a problem hiding this comment.
See below. Use an interface instead of this abstract class and register the implementation as alias of the interface here (see other services in this file).
There was a problem hiding this comment.
Please use $container->registerAlias(IGroupService::class, NextcloudGroupService::class); instead
|
|
||
| public function findMatches($term) { | ||
| $recipientsFromContacts = $this->contactsIntegration->getMatchingRecipient($term); | ||
| $recipientGroups = $this->groupsIntegration->getMatchingGroups($term); |
There was a problem hiding this comment.
I'd prefer to have this logic moved to a service class, maybe even introduce a facade for that. But that's a minor enhancement - this can be done later on 😉
|
|
||
| namespace OCA\Mail\Service\Group; | ||
|
|
||
| abstract class AbstractGroupService { |
There was a problem hiding this comment.
Looks like an interface would be the better choice here.
|
|
||
| return array_map( | ||
| function($g) { | ||
| return [ |
There was a problem hiding this comment.
Looks like a good candidate to implement PHP's JsonSerializable interface for this.
There was a problem hiding this comment.
I ported this pattern from Contacts\IManager::search. It's just returning key/value pairs. Where would JsonSerializable fit in?
There was a problem hiding this comment.
Nvm, just realized that $g is some data structure from the Nextcloud server, so nothing we can change. In that case that's fine 👍
| $users = $this->groupManager->get($groupId)->getUsers(); | ||
| return array_map( | ||
| function($user) { | ||
| return [ |
| */ | ||
| private $groupServices = []; | ||
|
|
||
| public function __construct(AbstractGroupService ...$groupServices) { |
There was a problem hiding this comment.
For simplicity, I'd recommend to only inject a single group service (there's only one so far). You don't have to use the concrete impl here but use the interface (as proposed above) and register the impl as alias for the interface in Application.
There was a problem hiding this comment.
I designed this so it will be extensible for Contacts groups.
But I could reserve this feature for later when Contacts groups integration will be ready.
| /** | ||
| * The services to get groups from | ||
| * | ||
| * @var IGroupService[] |
There was a problem hiding this comment.
Does this interface really exist?
There was a problem hiding this comment.
It did :-)
Missed to update the docs here.
But AbstractGroupService should become IGroupService again anyways.
| protected function setUp() { | ||
| parent::setUp(); | ||
|
|
||
| $this->groupService1 = $this->getMockBuilder(NextcloudGroupService::class) |
There was a problem hiding this comment.
use $this->createMock(...::class);.
| * | ||
| * @return string | ||
| */ | ||
| abstract public function getNamespace(); |
There was a problem hiding this comment.
Do we really need these namespaces? This kinda looks like an unnecessary generalization.
There was a problem hiding this comment.
Yes, I think so. There are two reasons:
- When
GroupIntegrationonce would be extended for Contacts groups, we need a means to tell apart whether it's a Nextcloud or a Contacts group, since both applications can have equally named groups. Eg. nextcloud:mygroup vs. contacts:mygroup. - We need to distinguish nextcloud groups from single recipients, since Nextcloud groups could look like email addresses. Eg. nextcloud:group@domain.com vs. group@domain.com ...
| $this->appName = 'mail'; | ||
| $this->request = $this->createMock(IRequest::class); | ||
| $this->accountService = $this->createMock(AccountService::class); | ||
| $this->groupsIntegration = new GroupsIntegration(); |
There was a problem hiding this comment.
use a mock instead please
| $container->registerAlias('ErrorMiddleware', ErrorMiddleware::class); | ||
| $container->registerMiddleWare('ErrorMiddleware'); | ||
|
|
||
| $container->registerService('OCA\Mail\Service\GroupsIntegration', function($c) { |
There was a problem hiding this comment.
Please use $container->registerAlias(IGroupService::class, NextcloudGroupService::class); instead
| protected function setUp() { | ||
| parent::setUp(); | ||
|
|
||
| $this->groupsManager = $this->createMock('OCP\IGroupManager'); |
There was a problem hiding this comment.
use the ::class notation
|
|
||
| public function getUsers($groupId) { | ||
| if(!$this->groupManager->groupExists($groupId)) { | ||
| throw new \Exception("$groupId ({$this->getNamespace()}) does not exist"); |
There was a problem hiding this comment.
throw a OCA\Mail\Exception\ServiceException instead
| */ | ||
| public function servicePrefix(IGroupService $gs) { | ||
| if(empty($gs->getNamespace())) { | ||
| throw new \Exception('GroupService has no namespace'); |
There was a problem hiding this comment.
use ServiceException instead
| $this->contactsIntegration = $this->getMockBuilder('\OCA\Mail\Service\ContactsIntegration') | ||
| ->disableOriginalConstructor() | ||
| ->getMock(); | ||
| $this->groupsIntegration = $this->getMockBuilder('\OCA\Mail\Service\GroupsIntegration') |
There was a problem hiding this comment.
->createMock and the ::class notation
| } | ||
|
|
||
| public function testGetUsersWrong() { | ||
| $this->expectException(\Exception::class); |
There was a problem hiding this comment.
needs update to ServiceException
| */ | ||
| private $groupServices = []; | ||
|
|
||
| public function __construct(IGroupService ...$groupServices) { |
There was a problem hiding this comment.
I'd prefer to simply inject a single instance as long as we have only a single implementation. Other implementations can be injected later.
| } | ||
|
|
||
| public function testExpandEmpty() { | ||
| $this->expectException(\Exception::class); |
| } | ||
|
|
||
| public function testExpandWrong2() { | ||
| $this->expectException(\Exception::class); |
ChristophWurst
left a comment
There was a problem hiding this comment.
👍 @myrho thanks a lot! I'll try to take over and integrate this PR next week
|
|
||
| } | ||
|
|
||
| ?> |
92ab7e7 to
539966a
Compare
2d2c7b6 to
1aa8a4d
Compare
ChristophWurst
left a comment
There was a problem hiding this comment.
Squashed the commits, rebased onto current master and fixed some coding style issues. Code looks good and manual tests confirmed that the feature works as expected. There are a few edge cases that are not handled well (like groups that have no members with email addresses set - horde will throw an exception because there is no recipient).
@myrho that can be fixed in follow-up pull requests. Thanks a lot for your work on this
Should be addressed before merging. |
ChristophWurst
left a comment
There was a problem hiding this comment.
Scrutinizer is happy now 😉
|
cc @nextcloud/mail for review. Would be great to have a second person testing/reviewing this new feature |
ain't nobody got time for that. Merging. |
|
I am confused. Please see my comment in #41 |
This PR overrides #800.
Fixes #41