diff --git a/app/Activity/Controllers/WatchController.php b/app/Activity/Controllers/WatchController.php new file mode 100644 index 000000000..f9e8a4e3d --- /dev/null +++ b/app/Activity/Controllers/WatchController.php @@ -0,0 +1,63 @@ +validate($request, [ + 'level' => ['required', 'string'], + ]); + + $watchable = $this->getValidatedModelFromRequest($request); + $newLevel = Watch::optionNameToLevel($requestData['level']); + + if ($newLevel < 0) { + // TODO - Delete + } else { + // TODO - Upsert + } + } + + /** + * @throws ValidationException + * @throws Exception + */ + protected function getValidatedModelFromRequest(Request $request): Entity + { + $modelInfo = $this->validate($request, [ + 'type' => ['required', 'string'], + 'id' => ['required', 'integer'], + ]); + + if (!class_exists($modelInfo['type'])) { + throw new Exception('Model not found'); + } + + /** @var Model $model */ + $model = new $modelInfo['type'](); + if (!$model instanceof Entity) { + throw new Exception('Model not an entity'); + } + + $modelInstance = $model->newQuery() + ->where('id', '=', $modelInfo['id']) + ->first(['id', 'name', 'owned_by']); + + $inaccessibleEntity = ($modelInstance instanceof Entity && !userCan('view', $modelInstance)); + if (is_null($modelInstance) || $inaccessibleEntity) { + throw new Exception('Model instance not found'); + } + + return $modelInstance; + } +} diff --git a/app/Activity/Models/Watch.php b/app/Activity/Models/Watch.php new file mode 100644 index 000000000..6e0e1f787 --- /dev/null +++ b/app/Activity/Models/Watch.php @@ -0,0 +1,52 @@ + -1, + 'ignore' => 0, + 'new' => 1, + 'updates' => 2, + 'comments' => 3, + ]; + + public function watchable() + { + $this->morphTo(); + } + + public function jointPermissions(): HasMany + { + return $this->hasMany(JointPermission::class, 'entity_id', 'watchable_id') + ->whereColumn('favourites.watchable_type', '=', 'joint_permissions.entity_type'); + } + + /** + * @return string[] + */ + public static function getAvailableOptionNames(): array + { + return array_keys(static::$levelByOption); + } + + public static function optionNameToLevel(string $option): int + { + return static::$levelByOption[$option] ?? -1; + } +} diff --git a/app/Users/UserWatchOptions.php b/app/Users/UserWatchOptions.php deleted file mode 100644 index a835bcfc7..000000000 --- a/app/Users/UserWatchOptions.php +++ /dev/null @@ -1,22 +0,0 @@ - -1, - 'ignore' => 0, - 'new' => 1, - 'updates' => 2, - 'comments' => 3, - ]; - - /** - * @return string[] - */ - public static function getAvailableOptionNames(): array - { - return array_keys(static::$levelByOption); - } -} diff --git a/database/migrations/2023_07_31_104430_create_watches_table.php b/database/migrations/2023_07_31_104430_create_watches_table.php new file mode 100644 index 000000000..e2a5c20d0 --- /dev/null +++ b/database/migrations/2023_07_31_104430_create_watches_table.php @@ -0,0 +1,37 @@ +increments('id'); + $table->integer('user_id')->index(); + $table->integer('watchable_id'); + $table->string('watchable_type', 100); + $table->tinyInteger('level', false, true)->index(); + $table->timestamps(); + + $table->index(['watchable_id', 'watchable_type'], 'watchable_index'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('watches'); + } +}; diff --git a/resources/views/entities/watch-controls.blade.php b/resources/views/entities/watch-controls.blade.php index b6b16a607..8d6bfed00 100644 --- a/resources/views/entities/watch-controls.blade.php +++ b/resources/views/entities/watch-controls.blade.php @@ -5,7 +5,7 @@