implemented pinned posts
This commit is contained in:
parent
f67907176f
commit
1bf6eb7d94
@ -148,4 +148,23 @@ class ActionsPost
|
|||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function pin_post (Actor $actor, Note $note)
|
||||||
|
{
|
||||||
|
$client = new Client ();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$response = $client->post ($actor->outbox, [
|
||||||
|
"json" => [
|
||||||
|
"type" => "Pin",
|
||||||
|
"object" => $note->note_id,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
catch (\Exception $e)
|
||||||
|
{
|
||||||
|
return ["error" => "Could not connect to server: " . $e->getMessage ()];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,15 @@ use App\Models\User;
|
|||||||
use App\Models\Actor;
|
use App\Models\Actor;
|
||||||
use App\Models\Activity;
|
use App\Models\Activity;
|
||||||
use App\Models\Follow;
|
use App\Models\Follow;
|
||||||
|
use App\Models\Note;
|
||||||
|
use App\Models\ProfilePin;
|
||||||
|
|
||||||
|
use App\Types\TypeOrderedCollection;
|
||||||
|
use App\Types\TypeNote;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
use App\Types\TypeOrderedCollection;
|
|
||||||
|
|
||||||
class APActorController extends Controller
|
class APActorController extends Controller
|
||||||
{
|
{
|
||||||
public function user (User $user)
|
public function user (User $user)
|
||||||
@ -31,7 +34,7 @@ class APActorController extends Controller
|
|||||||
$followers = Actor::whereIn ("id", $follower_ids->pluck ("actor")->toArray ());
|
$followers = Actor::whereIn ("id", $follower_ids->pluck ("actor")->toArray ());
|
||||||
|
|
||||||
$ordered_collection = new TypeOrderedCollection ();
|
$ordered_collection = new TypeOrderedCollection ();
|
||||||
$ordered_collection->collection = $followers->get ()->pluck ("actor")->toArray ();
|
$ordered_collection->collection = $followers->get ()->pluck ("actor_id")->toArray ();
|
||||||
$ordered_collection->url = route ("ap.followers", $user->name);
|
$ordered_collection->url = route ("ap.followers", $user->name);
|
||||||
$ordered_collection->page_size = 10;
|
$ordered_collection->page_size = 10;
|
||||||
|
|
||||||
@ -49,7 +52,7 @@ class APActorController extends Controller
|
|||||||
$following = Actor::whereIn ("id", $following_ids->pluck ("object")->toArray ());
|
$following = Actor::whereIn ("id", $following_ids->pluck ("object")->toArray ());
|
||||||
|
|
||||||
$ordered_collection = new TypeOrderedCollection ();
|
$ordered_collection = new TypeOrderedCollection ();
|
||||||
$ordered_collection->collection = $following->get ()->pluck ("object")->toArray ();
|
$ordered_collection->collection = $following->get ()->pluck ("actor_id")->toArray ();
|
||||||
$ordered_collection->url = route ("ap.following", $user->name);
|
$ordered_collection->url = route ("ap.following", $user->name);
|
||||||
$ordered_collection->page_size = 10;
|
$ordered_collection->page_size = 10;
|
||||||
|
|
||||||
@ -60,4 +63,28 @@ class APActorController extends Controller
|
|||||||
|
|
||||||
return response ()->json ($ordered_collection->build_response_main ())->header ("Content-Type", "application/activity+json");
|
return response ()->json ($ordered_collection->build_response_main ())->header ("Content-Type", "application/activity+json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function featured (User $user)
|
||||||
|
{
|
||||||
|
$featured_ids = ProfilePin::where ("actor_id", $user->actor->id)->pluck ("note_id")->toArray ();
|
||||||
|
$notes = Note::whereIn ("id", $featured_ids)->get ();
|
||||||
|
|
||||||
|
$collection = [];
|
||||||
|
foreach ($notes as $note)
|
||||||
|
{
|
||||||
|
$collection[] = TypeNote::build_response ($note);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ordered_collection = new TypeOrderedCollection ();
|
||||||
|
$ordered_collection->collection = $collection;
|
||||||
|
$ordered_collection->url = route ("ap.featured", $user->name);
|
||||||
|
$ordered_collection->page_size = 10;
|
||||||
|
|
||||||
|
if (request ()->has ("page")) {
|
||||||
|
$page = request ()->input ("page");
|
||||||
|
return response ()->json ($ordered_collection->build_response_for_page ($page))->header ("Content-Type", "application/activity+json");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response ()->json ($ordered_collection->build_response_main ())->header ("Content-Type", "application/activity+json");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ use App\Types\TypeActivity;
|
|||||||
use App\Types\TypeNote;
|
use App\Types\TypeNote;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\ProfilePin;
|
||||||
|
|
||||||
class APInstanceInboxController extends Controller
|
class APInstanceInboxController extends Controller
|
||||||
{
|
{
|
||||||
@ -32,6 +33,14 @@ class APInstanceInboxController extends Controller
|
|||||||
return $this->handle_announce ($activity);
|
return $this->handle_announce ($activity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "Add":
|
||||||
|
return $this->handle_add ($activity);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Remove":
|
||||||
|
return $this->handle_remove ($activity);
|
||||||
|
break;
|
||||||
|
|
||||||
case "Undo":
|
case "Undo":
|
||||||
return $this->handle_undo ($activity);
|
return $this->handle_undo ($activity);
|
||||||
break;
|
break;
|
||||||
@ -87,6 +96,50 @@ class APInstanceInboxController extends Controller
|
|||||||
return response ()->json (["status" => "ok"]);
|
return response ()->json (["status" => "ok"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function handle_add ($activity)
|
||||||
|
{
|
||||||
|
$actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]);
|
||||||
|
if (!$actor)
|
||||||
|
return response ()->json (["status" => "error"]);
|
||||||
|
|
||||||
|
if ($activity["target"] != $actor->featured)
|
||||||
|
// For now we only support adding notes to the featured actor
|
||||||
|
return response ()->json (["error" => "not implemented"], 501);
|
||||||
|
|
||||||
|
$note = TypeNote::note_exists ($activity ["object"]);
|
||||||
|
if (!$note)
|
||||||
|
$note = TypeNote::obtain_external ($activity ["object"]);
|
||||||
|
|
||||||
|
$pin_exists = ProfilePin::where ("actor_id", $actor->id)->where ("note_id", $note->id)->first ();
|
||||||
|
if ($pin_exists)
|
||||||
|
return response ()->json (["status" => "ok"]);
|
||||||
|
|
||||||
|
ProfilePin::create ([
|
||||||
|
"actor_id" => $actor->id,
|
||||||
|
"note_id" => $note->id
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response ()->json (["status" => "ok"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle_remove ($activity)
|
||||||
|
{
|
||||||
|
$actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]);
|
||||||
|
if (!$actor)
|
||||||
|
return response ()->json (["status" => "error"]);
|
||||||
|
|
||||||
|
if ($activity ["target"] != $actor->featured)
|
||||||
|
// For now we only support removing notes from the featured actor
|
||||||
|
return response ()->json (["error" => "not implemented"], 501);
|
||||||
|
|
||||||
|
$note = TypeNote::note_exists ($activity ["object"]);
|
||||||
|
$pin_exists = ProfilePin::where ("actor_id", $actor->id)->where ("note_id", $note->id)->first ();
|
||||||
|
if (!$pin_exists)
|
||||||
|
return response ()->json (["status" => "ok"]);
|
||||||
|
|
||||||
|
$pin_exists->delete ();
|
||||||
|
}
|
||||||
|
|
||||||
public function handle_undo ($activity)
|
public function handle_undo ($activity)
|
||||||
{
|
{
|
||||||
return response ()->json (ActionsActivity::activity_undo($activity));
|
return response ()->json (ActionsActivity::activity_undo($activity));
|
||||||
@ -130,11 +183,11 @@ class APInstanceInboxController extends Controller
|
|||||||
|
|
||||||
public function handle_update ($activity)
|
public function handle_update ($activity)
|
||||||
{
|
{
|
||||||
if (TypeActivity::activity_exists ($activity ["id"]))
|
if (!TypeActivity::activity_exists ($activity ["id"]))
|
||||||
return response ()->json (["status" => "ok"]);
|
{
|
||||||
|
$activity ["activity_id"] = $activity ["id"];
|
||||||
$activity ["activity_id"] = $activity ["id"];
|
$new_activity = Activity::create ($activity);
|
||||||
$new_activity = Activity::create ($activity);
|
}
|
||||||
|
|
||||||
$object = $activity ["object"];
|
$object = $activity ["object"];
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ use Illuminate\Http\Request;
|
|||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\ProfilePin;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class APOutboxController extends Controller
|
class APOutboxController extends Controller
|
||||||
@ -60,6 +61,10 @@ class APOutboxController extends Controller
|
|||||||
return $this->handle_boost ($user, $request->get ("object"));
|
return $this->handle_boost ($user, $request->get ("object"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "Pin":
|
||||||
|
return $this->handle_pin ($user, $request->get ("object"));
|
||||||
|
break;
|
||||||
|
|
||||||
case "Post":
|
case "Post":
|
||||||
return $this->handle_post ($user, $request);
|
return $this->handle_post ($user, $request);
|
||||||
break;
|
break;
|
||||||
@ -295,6 +300,46 @@ class APOutboxController extends Controller
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function handle_pin (User $user, $object)
|
||||||
|
{
|
||||||
|
$object = Note::where ("note_id", $object)->first ();
|
||||||
|
if (!$object)
|
||||||
|
return response ()->json ([ "error" => "object not found" ], 404);
|
||||||
|
|
||||||
|
$actor = $user->actor ()->first ();
|
||||||
|
$already_pinned = $object->is_pinned ($actor);
|
||||||
|
if ($already_pinned)
|
||||||
|
{
|
||||||
|
$pin_activity = $already_pinned->activity;
|
||||||
|
$remove_activity = TypeActivity::craft_remove ($actor, $object->note_id, $actor->featured);
|
||||||
|
|
||||||
|
$response = TypeActivity::post_to_instances ($remove_activity, $actor);
|
||||||
|
|
||||||
|
$pin_exists = ProfilePin::where ("note_id", $object->id)
|
||||||
|
->where ("actor_id", $actor->id)
|
||||||
|
->first ();
|
||||||
|
if ($pin_exists)
|
||||||
|
$pin_exists->delete ();
|
||||||
|
|
||||||
|
return [
|
||||||
|
"success" => "unpinned"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$pin_activity = TypeActivity::craft_add ($actor, $object->note_id, $actor->featured);
|
||||||
|
$pin = ProfilePin::create ([
|
||||||
|
"activity_id" => $pin_activity->id,
|
||||||
|
"actor_id" => $actor->id,
|
||||||
|
"note_id" => $object->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = TypeActivity::post_to_instances ($pin_activity, $actor);
|
||||||
|
|
||||||
|
return [
|
||||||
|
"success" => "pinned"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function handle_post (User $user, $request)
|
public function handle_post (User $user, $request)
|
||||||
{
|
{
|
||||||
$actor = $user->actor ()->first ();
|
$actor = $user->actor ()->first ();
|
||||||
|
@ -96,6 +96,19 @@ class PostController extends Controller
|
|||||||
return back ()->with ("success", "Post boosted successfully.");
|
return back ()->with ("success", "Post boosted successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function pin (Note $note)
|
||||||
|
{
|
||||||
|
if (!auth ()->check ())
|
||||||
|
return back ()->with ("error", "You need to be logged in to pin a post.");
|
||||||
|
|
||||||
|
$user = auth ()->user ();
|
||||||
|
$actor = $user->actor ()->first ();
|
||||||
|
|
||||||
|
$response = ActionsPost::pin_post ($actor, $note);
|
||||||
|
|
||||||
|
return back ()->with ("success", "Post pinned successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
public function delete (Note $note)
|
public function delete (Note $note)
|
||||||
{
|
{
|
||||||
$actor = auth ()->user ()->actor ()->first ();
|
$actor = auth ()->user ()->actor ()->first ();
|
||||||
|
@ -25,6 +25,8 @@ class Actor extends Model
|
|||||||
"followers",
|
"followers",
|
||||||
|
|
||||||
"liked",
|
"liked",
|
||||||
|
"featured",
|
||||||
|
"featured_tags",
|
||||||
|
|
||||||
"inbox",
|
"inbox",
|
||||||
"outbox",
|
"outbox",
|
||||||
@ -55,6 +57,12 @@ class Actor extends Model
|
|||||||
return $this->belongsTo (User::class);
|
return $this->belongsTo (User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_pinned_posts ()
|
||||||
|
{
|
||||||
|
$pinned = $this->hasMany (ProfilePin::class, "actor_id")->orderBy ("created_at", "desc")->get ();
|
||||||
|
return Note::whereIn ("id", $pinned->pluck ("note_id"))->get ();
|
||||||
|
}
|
||||||
|
|
||||||
public function get_posts ()
|
public function get_posts ()
|
||||||
{
|
{
|
||||||
$posts = $this->hasMany (Note::class, "actor_id")->orderBy ("created_at", "desc")->get ();
|
$posts = $this->hasMany (Note::class, "actor_id")->orderBy ("created_at", "desc")->get ();
|
||||||
|
@ -61,4 +61,9 @@ class Note extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasMany (NoteAttachment::class);
|
return $this->hasMany (NoteAttachment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function is_pinned (Actor $actor)
|
||||||
|
{
|
||||||
|
return ProfilePin::where ("actor_id", $actor->id)->where ("note_id", $this->id)->first ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
14
app/Models/ProfilePin.php
Normal file
14
app/Models/ProfilePin.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ProfilePin extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
"activity_id",
|
||||||
|
"note_id",
|
||||||
|
"actor_id"
|
||||||
|
];
|
||||||
|
}
|
@ -145,6 +145,32 @@ class TypeActivity {
|
|||||||
return $announce_activity;
|
return $announce_activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function craft_add (Actor $actor, $object, $target)
|
||||||
|
{
|
||||||
|
$add_activity = new Activity ();
|
||||||
|
$add_activity->activity_id = env ("APP_URL") . "/activity/" . uniqid ();
|
||||||
|
$add_activity->type = "Add";
|
||||||
|
$add_activity->actor = $actor->actor_id;
|
||||||
|
$add_activity->object = $object;
|
||||||
|
$add_activity->target = $target;
|
||||||
|
$add_activity->save ();
|
||||||
|
|
||||||
|
return $add_activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function craft_remove (Actor $actor, $object, $target)
|
||||||
|
{
|
||||||
|
$remove_activity = new Activity ();
|
||||||
|
$remove_activity->activity_id = env ("APP_URL") . "/activity/" . uniqid ();
|
||||||
|
$remove_activity->type = "Remove";
|
||||||
|
$remove_activity->actor = $actor->actor_id;
|
||||||
|
$remove_activity->object = $object;
|
||||||
|
$remove_activity->target = $target;
|
||||||
|
$remove_activity->save ();
|
||||||
|
|
||||||
|
return $remove_activity;
|
||||||
|
}
|
||||||
|
|
||||||
public static function get_private_key (Actor $actor)
|
public static function get_private_key (Actor $actor)
|
||||||
{
|
{
|
||||||
return openssl_get_privatekey ($actor->private_key);
|
return openssl_get_privatekey ($actor->private_key);
|
||||||
@ -217,6 +243,9 @@ class TypeActivity {
|
|||||||
|
|
||||||
public static function post_to_instances (Activity $activity, Actor $source)
|
public static function post_to_instances (Activity $activity, Actor $source)
|
||||||
{
|
{
|
||||||
|
Log::info ("posting activity to instances");
|
||||||
|
Log::info (json_encode (TypeActivity::craft_response ($activity)));
|
||||||
|
|
||||||
$instances = Instance::all ();
|
$instances = Instance::all ();
|
||||||
foreach ($instances as $instance)
|
foreach ($instances as $instance)
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,7 @@ namespace App\Types;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Actor;
|
use App\Models\Actor;
|
||||||
use App\Models\Instance;
|
use App\Models\Instance;
|
||||||
|
use App\Models\ProfilePin;
|
||||||
|
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@ -43,6 +44,8 @@ class TypeActor {
|
|||||||
"followers" => $app_url . "/ap/v1/user/" . $user->name . "/followers",
|
"followers" => $app_url . "/ap/v1/user/" . $user->name . "/followers",
|
||||||
|
|
||||||
"liked" => $app_url . "/ap/v1/user/" . $user->name . "/liked",
|
"liked" => $app_url . "/ap/v1/user/" . $user->name . "/liked",
|
||||||
|
"featured" => $app_url . "/ap/v1/user/" . $user->name . "/collections/featured",
|
||||||
|
"featured_tags" => $app_url . "/ap/v1/user/" . $user->name . "/collections/featured/tags",
|
||||||
|
|
||||||
"inbox" => $app_url . "/ap/v1/user/" . $user->name . "/inbox",
|
"inbox" => $app_url . "/ap/v1/user/" . $user->name . "/inbox",
|
||||||
"outbox" => $app_url . "/ap/v1/user/" . $user->name . "/outbox",
|
"outbox" => $app_url . "/ap/v1/user/" . $user->name . "/outbox",
|
||||||
@ -63,7 +66,17 @@ class TypeActor {
|
|||||||
$response = [
|
$response = [
|
||||||
"@context" => [
|
"@context" => [
|
||||||
"https://www.w3.org/ns/activitystreams",
|
"https://www.w3.org/ns/activitystreams",
|
||||||
"https://w3id.org/security/v1"
|
"https://w3id.org/security/v1",
|
||||||
|
[
|
||||||
|
"featured" => [
|
||||||
|
"@id" => "http://joinmastodon.org/ns#featured",
|
||||||
|
"@type" => "@id"
|
||||||
|
],
|
||||||
|
"featuredTags" => [
|
||||||
|
"@id" => "http://joinmastodon.org/ns#featuredTags",
|
||||||
|
"@type" => "@id"
|
||||||
|
]
|
||||||
|
]
|
||||||
],
|
],
|
||||||
"id" => $actor->actor_id,
|
"id" => $actor->actor_id,
|
||||||
"type" => $actor->type,
|
"type" => $actor->type,
|
||||||
@ -72,6 +85,8 @@ class TypeActor {
|
|||||||
"followers" => $actor->followers,
|
"followers" => $actor->followers,
|
||||||
|
|
||||||
"liked" => $actor->liked,
|
"liked" => $actor->liked,
|
||||||
|
"featured" => $actor->featured,
|
||||||
|
"featuredTags" => $actor->featured_tags,
|
||||||
|
|
||||||
"inbox" => $actor->inbox,
|
"inbox" => $actor->inbox,
|
||||||
"outbox" => $actor->outbox,
|
"outbox" => $actor->outbox,
|
||||||
@ -163,6 +178,8 @@ class TypeActor {
|
|||||||
$actor->followers = $request['followers'] ?? '';
|
$actor->followers = $request['followers'] ?? '';
|
||||||
|
|
||||||
$actor->liked = $request['liked'] ?? '';
|
$actor->liked = $request['liked'] ?? '';
|
||||||
|
$actor->featured = $request['featured'] ?? '';
|
||||||
|
$actor->featured_tags = $request['featuredTags'] ?? '';
|
||||||
|
|
||||||
$actor->inbox = $request['inbox'] ?? '';
|
$actor->inbox = $request['inbox'] ?? '';
|
||||||
$actor->outbox = $request['outbox'] ?? '';
|
$actor->outbox = $request['outbox'] ?? '';
|
||||||
@ -188,6 +205,27 @@ class TypeActor {
|
|||||||
$instance->save ();
|
$instance->save ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$featured_items = TypeActor::actor_process_featured ($actor);
|
||||||
|
ProfilePin::where ("actor_id", $actor->id)->delete ();
|
||||||
|
|
||||||
|
foreach ($featured_items as $item)
|
||||||
|
{
|
||||||
|
if ($item ["type"] == "Note")
|
||||||
|
{
|
||||||
|
$note = TypeNote::note_exists ($item ["id"]);
|
||||||
|
if (!$note)
|
||||||
|
$note = TypeNote::obtain_external ($item ["id"]);
|
||||||
|
|
||||||
|
if (!$note)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ProfilePin::create ([
|
||||||
|
"actor_id" => $actor->id,
|
||||||
|
"note_id" => $note->id
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $actor;
|
return $actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,4 +355,83 @@ class TypeActor {
|
|||||||
return null;
|
return null;
|
||||||
return $actor;
|
return $actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function actor_process_featured (Actor $actor)
|
||||||
|
{
|
||||||
|
$pinned = [];
|
||||||
|
|
||||||
|
if (!$actor->featured)
|
||||||
|
return $pinned;
|
||||||
|
|
||||||
|
return TypeActor::actor_process_ordered_collection ($actor->featured);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function actor_process_ordered_collection ($collection_link)
|
||||||
|
{
|
||||||
|
$items = [];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$client = new Client ();
|
||||||
|
$response = $client->get ($collection_link, [
|
||||||
|
"headers" => [
|
||||||
|
"Accept" => "application/json"
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$collection = json_decode ($response->getBody ()->getContents (), true);
|
||||||
|
|
||||||
|
if (isset ($collection ["first"]) && isset ($collection ["last"]))
|
||||||
|
{
|
||||||
|
$first = $collection["first"];
|
||||||
|
$last = $collection["last"];
|
||||||
|
|
||||||
|
$current_url = $first;
|
||||||
|
$current_page = 1;
|
||||||
|
do {
|
||||||
|
$items = array_merge ($items, TypeActor::actor_processed_order_collection_page ($current_url));
|
||||||
|
|
||||||
|
$current_page++;
|
||||||
|
$current_url = $collection_link . "?page=" . $current_page;
|
||||||
|
} while ($current_url != $last);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $collection["orderedItems"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (\Exception $e)
|
||||||
|
{
|
||||||
|
Log::error ("TypeActor::actor_process_ordered_collection: " . $e->getMessage ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function actor_processed_order_collection_page ($page_link)
|
||||||
|
{
|
||||||
|
$items = [];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$client = new Client ();
|
||||||
|
$response = $client->get ($page_link, [
|
||||||
|
"headers" => [
|
||||||
|
"Accept" => "application/json"
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$collection = json_decode ($response->getBody ()->getContents (), true);
|
||||||
|
foreach ($collection["orderedItems"] as $item)
|
||||||
|
{
|
||||||
|
$items[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (\Exception $e)
|
||||||
|
{
|
||||||
|
Log::error ("TypeActor::actor_processed_order_collection_page: " . $e->getMessage ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,11 @@ class TypeNote
|
|||||||
$note->in_reply_to = $parent->note_id;
|
$note->in_reply_to = $parent->note_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset ($request ["replies"]))
|
||||||
|
{
|
||||||
|
// TODO: Handle replies
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function create_from_request ($request, Activity $activity, Actor $actor)
|
public static function create_from_request ($request, Activity $activity, Actor $actor)
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('actors', function (Blueprint $table) {
|
||||||
|
$table->string ("featured")->nullable ();
|
||||||
|
$table->string ("featured_tags")->nullable ();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('actors', function (Blueprint $table) {
|
||||||
|
$table->dropColumn ("featured");
|
||||||
|
$table->dropColumn ("featured_tags");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('profile_pins', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId ("activity_id")->nullable ()->constrained ()->onDelete ("cascade");
|
||||||
|
$table->foreignId ("note_id")->constrained ()->onDelete ("cascade");
|
||||||
|
$table->foreignId ("actor_id")->constrained ()->onDelete ("cascade");
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('profile_pins');
|
||||||
|
}
|
||||||
|
};
|
@ -40,6 +40,7 @@
|
|||||||
<div class="col right">
|
<div class="col right">
|
||||||
<h1 class="title">{{ $actor->name }}'s Post</h1>
|
<h1 class="title">{{ $actor->name }}'s Post</h1>
|
||||||
@if (auth ()->check () && auth ()->user ()->is ($actor->user))
|
@if (auth ()->check () && auth ()->user ()->is ($actor->user))
|
||||||
|
<div class="buttons" style="display: flex; gap: 5px;">
|
||||||
<form action="#" method="POST">
|
<form action="#" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
@method("DELETE")
|
@method("DELETE")
|
||||||
@ -48,6 +49,12 @@
|
|||||||
</a>
|
</a>
|
||||||
<button type="submit">Delete</button>
|
<button type="submit">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<form action="{{ route ('posts.pin', [ 'note' => $note ]) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<button type="submit">{{ $note->is_pinned ($actor) ? "Unpin" : "Pin" }}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if ($note->in_reply_to)
|
@if ($note->in_reply_to)
|
||||||
|
@ -320,6 +320,19 @@
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
@if ($actor->get_pinned_posts ()->count () > 0)
|
||||||
|
<table class="comments-table" cellspacing="0" cellpadding="3" bordercollor="#ffffff" border="1">
|
||||||
|
<tbody>
|
||||||
|
<p><b>Pinned</b></p>
|
||||||
|
@foreach ($actor->get_pinned_posts () as $post)
|
||||||
|
<x-comment_block :post="$post" />
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
@endif
|
||||||
|
|
||||||
<table class="comments-table" cellspacing="0" cellpadding="3" bordercollor="#ffffff" border="1">
|
<table class="comments-table" cellspacing="0" cellpadding="3" bordercollor="#ffffff" border="1">
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach ($actor->get_posts () as $post)
|
@foreach ($actor->get_posts () as $post)
|
||||||
|
@ -23,6 +23,7 @@ Route::prefix ("/ap/v1")->group (function () {
|
|||||||
Route::post ("/user/{user:name}/outbox", [ APOutboxController::class, "outbox" ])->name ("ap.outbox");
|
Route::post ("/user/{user:name}/outbox", [ APOutboxController::class, "outbox" ])->name ("ap.outbox");
|
||||||
Route::get ("/user/{user:name}/followers", [ APActorController::class, "followers" ])->name ("ap.followers");
|
Route::get ("/user/{user:name}/followers", [ APActorController::class, "followers" ])->name ("ap.followers");
|
||||||
Route::get ("/user/{user:name}/following", [ APActorController::class, "following" ])->name ("ap.following");
|
Route::get ("/user/{user:name}/following", [ APActorController::class, "following" ])->name ("ap.following");
|
||||||
|
Route::get ("/user/{user:name}/collections/featured", [ APActorController::class, "featured" ])->name ("ap.featured");
|
||||||
Route::get ("/user/{user:name}", [ APActorController::class, "user" ])->name ("ap.user");
|
Route::get ("/user/{user:name}", [ APActorController::class, "user" ])->name ("ap.user");
|
||||||
|
|
||||||
// notes
|
// notes
|
||||||
|
@ -34,6 +34,7 @@ Route::middleware ("update_online")->group (function () {
|
|||||||
Route::post ("/post/{note}/edit", [ PostController::class, "update" ])->middleware ("auth");
|
Route::post ("/post/{note}/edit", [ PostController::class, "update" ])->middleware ("auth");
|
||||||
Route::post ("/post/{note}/like", [ PostController::class, "like" ])->name ("posts.like")->middleware ("auth");
|
Route::post ("/post/{note}/like", [ PostController::class, "like" ])->name ("posts.like")->middleware ("auth");
|
||||||
Route::post ("/post/{note}/boost", [ PostController::class, "boost" ])->name ("posts.boost")->middleware ("auth");
|
Route::post ("/post/{note}/boost", [ PostController::class, "boost" ])->name ("posts.boost")->middleware ("auth");
|
||||||
|
Route::post ("/post/{note}/pin", [ PostController::class, "pin" ])->name ("posts.pin")->middleware ("auth");
|
||||||
Route::get ("/post/{note}", [ PostController::class, "show" ])->name ("posts.show");
|
Route::get ("/post/{note}", [ PostController::class, "show" ])->name ("posts.show");
|
||||||
Route::delete ("/post/{note}", [ PostController::class, "delete" ])->name ("posts.delete")->middleware ("auth");
|
Route::delete ("/post/{note}", [ PostController::class, "delete" ])->name ("posts.delete")->middleware ("auth");
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user