Completed
Pull Request — master (#200)
by Raffael
16:31
created

NewShareAdded::postSaveNodeAttributes()   D

Complexity

Conditions 18
Paths 16

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 0
Metric Value
dl 0
loc 46
ccs 0
cts 40
cp 0
rs 4.8666
c 0
b 0
f 0
cc 18
nc 16
nop 5
crap 342

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2018 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Balloon\App\Notification\Hook;
13
14
use Balloon\App\Notification\Notifier;
15
use Balloon\Async\Mail;
16
use Balloon\Filesystem\Node\Collection;
17
use Balloon\Filesystem\Node\NodeInterface;
18
use Balloon\Hook\AbstractHook;
19
use Balloon\Server;
20
use Balloon\Server\User;
21
use MongoDB\BSON\ObjectId;
22
use Psr\Log\LoggerInterface;
23
24
class NewShareAdded extends AbstractHook
25
{
26
    /**
27
     * Notifier.
28
     *
29
     * @var Notifier
30
     */
31
    protected $notifier;
32
33
    /**
34
     * Server.
35
     *
36
     * @var Server
37
     */
38
    protected $server;
39
40
    /**
41
     * Logger.
42
     *
43
     * @var LoggerInterface
44
     */
45
    protected $logger;
46
47
    /**
48
     * Constructor.
49
     */
50
    public function __construct(Notifier $notifier, Server $server, LoggerInterface $logger)
51
    {
52
        $this->notifier = $notifier;
53
        $this->server = $server;
54
        $this->logger = $logger;
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    public function postSaveNodeAttributes(NodeInterface $node, array $attributes, array $remove, ?string $recursion, bool $recursion_first): void
61
    {
62
        if (!($node instanceof Collection)) {
63
            return;
64
        }
65
66
        $fs = $node->getFilesystem();
0 ignored issues
show
Unused Code introduced by
$fs is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
67
        $raw = $node->getRawAttributes();
68
69
        if ($node->isReference()) {
70
            return;
71
        }
72
        if ($node->isShared() && isset($raw['acl']) && $raw['acl'] === $node->getAttributes()['acl']) {
73
            return;
74
        }
75
        if (!$node->isShared()) {
76
            return;
77
        }
78
79
        $receiver = [];
80
        foreach ($node->getAcl() as $rule) {
81
            if (isset($raw['acl']) && $this->hadRole($raw['acl'], $rule['role']->getId())) {
82
                continue;
83
            }
84
85
            if ('user' === $rule['type']) {
86
                if (!isset($receiver[(string) $rule['role']->getId()]) && $this->checkNotify($node, $rule['role'])) {
87
                    $receiver[(string) $rule['role']->getId()] = $rule['role'];
88
                }
89
            } elseif ('group' === $rule['type']) {
90
                foreach ($rule['role']->getResolvedMembers() as $user) {
91
                    if (!isset($receiver[(string) $user->getId()]) && $this->checkNotify($node, $user)) {
92
                        $receiver[(string) $user->getId()] = $user;
93
                    }
94
                }
95
            }
96
        }
97
98
        if (!empty($receiver)) {
99
            $message = $this->notifier->compose('new_share_added', [
100
                'node' => $node,
101
            ]);
102
103
            $this->notifier->notify($receiver, $this->server->getIdentity(), $message);
104
        }
105
    }
106
107
    /**
108
     * Check if had role before.
109
     */
110
    protected function hadRole(array $acl, ObjectId $id): bool
111
    {
112
        foreach ($acl as $rule) {
113
            if ($rule['id'] == $id) {
114
                return true;
115
            }
116
        }
117
118
        return false;
119
    }
120
121
    /**
122
     * Check if users needs a notification and checks if mail adress is available.
123
     */
124
    protected function checkNotify(NodeInterface $node, User $user): bool
125
    {
126
        if ($user->hasShare($node)) {
0 ignored issues
show
Compatibility introduced by
$node of type object<Balloon\Filesystem\Node\NodeInterface> is not a sub-type of object<Balloon\Filesystem\Node\Collection>. It seems like you assume a concrete implementation of the interface Balloon\Filesystem\Node\NodeInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
127
            $this->logger->debug('skip notifcation for share ['.$node->getId().'] user ['.$user->getId().'] already got it', [
128
                'category' => get_class($this),
129
            ]);
130
131
            return false;
132
        }
133
134
        return true;
135
    }
136
}
137