aboutsummaryrefslogtreecommitdiffhomepage
path: root/Digitigrade/Model/Interaction.php
blob: c24d8cc2bb761df8404abd61342257103fc38b5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<?php
namespace Digitigrade\Model;

use Digitigrade\Timeline\HomeTimelineItem;
use Digitigrade\Timeline\ReasonReshared;
use Digitigrade\Timeline\TimelineItem;

class Interaction extends PushableModel {
    public ?int $id;
    public string $uri;
    public \DateTimeImmutable $created;
    public ?\DateTimeImmutable $modified;
    public Actor $author;
    public InteractionKind $kind;
    public Note $target;
    public array $extensions = [];

    public static function create(Actor $author, InteractionKind $kind, Note $target) {
        $inter = new self();
        $inter->uri = "UNKNOWN";
        $inter->created = new \DateTimeImmutable();
        $inter->author = $author;
        $inter->kind = $kind;
        $inter->target = $target;

        $inter->save();
        $inter->uri = path_to_uri("/interaction/$inter->id");
        $inter->save();

        return $inter;
    }

    protected function getUpdateWhereClause(\PDO $db): ?string {
        if (self::findWhere('uri = ?', [$this->uri]) != null)
            return 'uri = ' . $db->quote($this->uri);
        if (self::findWhere('id = ?', [$this->id]) != null)
            return "id = $this->id";
        return null;
    }

    protected function validate(): bool {
        // author has to be from the same instance as the interaction itself
        return hostname_from_uri($this->author->uri) == hostname_from_uri($this->uri);
    }

    public static function findAllWithAuthor(Actor $author): array {
        return self::findAllWhere('author = ?', [$author->id]);
    }

    public static function findAllWithTarget(Note $target): array {
        return self::findAllWhere('target = ?', [$target->id]);
    }

    protected function getRelevantServers(): array {
        $instances = array_map(
            fn(Actor $actor) => $actor->isLocal ? null : $actor->findHomeInstance(),
            $this->author->findFollowers()
        );
        if (!$this->target->author->isLocal)
            $instances[] = $this->target->author->findHomeInstance();
        return array_unique($instances);
    }

    public function processTimelineAdditions() {
        // basically, if this is a reshare, we need to put a home timeline item
        // for all followers who can see the shared note
        if ($this->kind != InteractionKind::RESHARE)
            return;
        $reason = new ReasonReshared($this->author);
        $item = new TimelineItem($this->target, $reason);

        foreach ($this->author->findFollowers() as $actor) {
            if (!$actor->isLocal)
                return;
            $user = UserAccount::findByLinkedActor($actor);
            if (!$this->target->isViewableBy($user))
                return;

            HomeTimelineItem::fromTimelineItem($item, $user)->save();
        }
    }

    public function jsonSerialize(): array {
        if ($this->deleted) {
            return [
                'type' => 'tombstone',
                'self' => path_to_uri("/interaction/$this->id"),
                'previousType' => 'interaction'
            ];
        }
        return [
            'type' => 'interaction',
            'self' => path_to_uri("/interaction/$this->id"),
            'created' => $this->created->format('c'),
            'modified' => $this->modified?->format('c'),
            'author' => $this->author->uri,
            'kind' => $this->kind->value,
            'target' => $this->target->uri,
            //'extensions' => []
        ];
    }
}