aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorwinter2024-12-17 23:05:43 +0000
committerwinter2024-12-17 23:05:43 +0000
commit6f844ff40d936fb6591c2469dd9ff922bc4e575f (patch)
tree007dc0372c2c999bdcf6ea1ba80f6eb93a161a7f
parent801778a295df2b026391483faa390cf87e68b1ad (diff)
implement interactions
-rw-r--r--Digitigrade/Model/FetchableModel.php7
-rw-r--r--Digitigrade/Model/Interaction.php62
-rw-r--r--Digitigrade/Model/InteractionKind.php8
-rw-r--r--Digitigrade/Model/Note.php4
-rw-r--r--migrations/20241217_221952_create_interaction.php27
-rw-r--r--routes/interaction.php16
-rw-r--r--routes/push.php3
7 files changed, 125 insertions, 2 deletions
diff --git a/Digitigrade/Model/FetchableModel.php b/Digitigrade/Model/FetchableModel.php
index 33e1151..1120823 100644
--- a/Digitigrade/Model/FetchableModel.php
+++ b/Digitigrade/Model/FetchableModel.php
@@ -13,7 +13,7 @@ abstract class FetchableModel extends Model implements RemoteFetchable {
self::$mapper->bStrictObjectTypeChecking = false;
}
- protected static function createFromJson(\stdClass $data, bool $autoSave): static {
+ protected static function createFromJson(\stdClass $data, bool $autoSave, ?string $uri = null): static {
// default everything nullable to null
$obj = new static();
$reflProps = (new \ReflectionClass(static::class))->getProperties();
@@ -62,9 +62,12 @@ abstract class FetchableModel extends Model implements RemoteFetchable {
if ($data === null)
return null;
- $obj = static::createFromJson($data, $autoSave);
+ $obj = static::createFromJson($data, $autoSave, $uri);
$obj->finaliseAfterFetch($uri);
+ if (!$obj->validate()) {
+ return null; // and don't save
+ }
if ($autoSave) {
$obj->save();
$obj->finaliseAfterSave();
diff --git a/Digitigrade/Model/Interaction.php b/Digitigrade/Model/Interaction.php
new file mode 100644
index 0000000..bf0745e
--- /dev/null
+++ b/Digitigrade/Model/Interaction.php
@@ -0,0 +1,62 @@
+<?php
+namespace Digitigrade\Model;
+
+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]);
+ }
+
+ public function jsonSerialize(): array {
+ 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' => []
+ ];
+ }
+} \ No newline at end of file
diff --git a/Digitigrade/Model/InteractionKind.php b/Digitigrade/Model/InteractionKind.php
new file mode 100644
index 0000000..2fd09c9
--- /dev/null
+++ b/Digitigrade/Model/InteractionKind.php
@@ -0,0 +1,8 @@
+<?php
+namespace Digitigrade\Model;
+
+enum InteractionKind: string {
+ case LIKE = 'like';
+ case DISLIKE = 'dislike';
+ case RESHARE = 'reshare';
+} \ No newline at end of file
diff --git a/Digitigrade/Model/Note.php b/Digitigrade/Model/Note.php
index dd66c85..0117a3c 100644
--- a/Digitigrade/Model/Note.php
+++ b/Digitigrade/Model/Note.php
@@ -105,6 +105,10 @@ class Note extends PushableModel {
return self::findAllWhere('author = ?', [$author->id]);
}
+ public function getInteractions(): array {
+ return Interaction::findAllWithTarget($this);
+ }
+
public function jsonSerialize(): array {
return [
'type' => 'note',
diff --git a/migrations/20241217_221952_create_interaction.php b/migrations/20241217_221952_create_interaction.php
new file mode 100644
index 0000000..6559b6c
--- /dev/null
+++ b/migrations/20241217_221952_create_interaction.php
@@ -0,0 +1,27 @@
+<?php
+
+use \Digitigrade\Db\Migrator;
+
+Migrator::getInstance()->register(20241217_221952, function (PDO $db) {
+ // interaction table!
+ $db->exec(<<<END
+ CREATE TYPE interaction_kind AS ENUM (
+ 'like', 'dislike', 'reshare'
+ );
+ CREATE TABLE interaction (
+ id bigserial primary key,
+ uri text unique not null,
+ created timestamp with time zone not null,
+ modified timestamp with time zone,
+ author bigint not null references actor,
+ kind interaction_kind not null,
+ target bigint not null references note
+ );
+ CREATE TABLE interaction_extension (
+ interaction_id bigint not null references interaction,
+ uri text not null,
+ data jsonb not null,
+ unique(interaction_id, uri)
+ );
+ END);
+});
diff --git a/routes/interaction.php b/routes/interaction.php
new file mode 100644
index 0000000..c50dec2
--- /dev/null
+++ b/routes/interaction.php
@@ -0,0 +1,16 @@
+<?php
+
+use Digitigrade\HttpResponseStatus\NotFound;
+use Digitigrade\Model\Interaction;
+use Digitigrade\Router;
+
+Router::getInstance()->mount('/interaction/:id', function (array $args) {
+ $interaction = Interaction::find($args['id']);
+ if ($interaction == null) {
+ throw new NotFound("i don't know that interaction");
+ }
+ if (!$interaction->author->isLocal) {
+ throw new NotFound("i don't want to tell you about non-local interactions!");
+ }
+ json_response($interaction);
+}); \ No newline at end of file
diff --git a/routes/push.php b/routes/push.php
index 6712fb4..6fc8229 100644
--- a/routes/push.php
+++ b/routes/push.php
@@ -5,6 +5,7 @@ use Digitigrade\HttpResponseStatus\Forbidden;
use Digitigrade\HttpResponseStatus\Unauthorized;
use Digitigrade\Model\Actor;
use Digitigrade\Model\Instance;
+use Digitigrade\Model\Interaction;
use Digitigrade\Model\Note;
use Digitigrade\Router;
@@ -41,6 +42,8 @@ Router::getInstance()->mount('/push', function (array $args) {
Note::importFromReceivedObject($obj);
break;
case 'interaction':
+ Interaction::importFromReceivedObject($obj);
+ break;
case 'extension':
case 'tombstone':
throw new \RuntimeException('object type not yet implemented :(');