now posts can be updated
This commit is contained in:
parent
fdb9d09f0d
commit
031b805e5b
@ -52,3 +52,6 @@ Notice that the styles were taken from [AnySpace](https://anyspace.3to.moe/about
|
|||||||
- [ ] Others
|
- [ ] Others
|
||||||
- [ ] Music
|
- [ ] Music
|
||||||
- [ ] Announcements
|
- [ ] Announcements
|
||||||
|
|
||||||
|
- [ ] Fixes
|
||||||
|
- [ ] Fix that weird json encoding in the object field of an activity
|
||||||
|
@ -18,11 +18,8 @@ use Intervention\Image\Drivers\Gd\Driver;
|
|||||||
|
|
||||||
class ActionsPost
|
class ActionsPost
|
||||||
{
|
{
|
||||||
public static function post_new ($request)
|
public static function process_content_and_attachments ($request)
|
||||||
{
|
{
|
||||||
if (!auth ()->check ())
|
|
||||||
return ["error" => "You must be logged in to post."];
|
|
||||||
|
|
||||||
$processed_content = Str::markdown ($request->get ("content"));
|
$processed_content = Str::markdown ($request->get ("content"));
|
||||||
$attachments = [];
|
$attachments = [];
|
||||||
|
|
||||||
@ -42,6 +39,36 @@ class ActionsPost
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
"summary" => $request->summary,
|
||||||
|
"content" => $processed_content,
|
||||||
|
"attachments" => $attachments,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function create_attachment (Note $note, $url)
|
||||||
|
{
|
||||||
|
$attachment = new NoteAttachment ();
|
||||||
|
$attachment->note_id = $note->id;
|
||||||
|
$attachment->url = $url;
|
||||||
|
$attachment->save ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function create_attachments (Note $note, $attachments)
|
||||||
|
{
|
||||||
|
foreach ($attachments as $attachment)
|
||||||
|
{
|
||||||
|
ActionsPost::create_attachment ($note, $attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function post_new ($request)
|
||||||
|
{
|
||||||
|
if (!auth ()->check ())
|
||||||
|
return ["error" => "You must be logged in to post."];
|
||||||
|
|
||||||
|
$processed = ActionsPost::process_content_and_attachments ($request);
|
||||||
|
|
||||||
$actor = auth ()->user ()->actor ()->first ();
|
$actor = auth ()->user ()->actor ()->first ();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -49,8 +76,9 @@ class ActionsPost
|
|||||||
$response = $client->post ($actor->outbox, [
|
$response = $client->post ($actor->outbox, [
|
||||||
"json" => [
|
"json" => [
|
||||||
"type" => "Post",
|
"type" => "Post",
|
||||||
"content" => $processed_content,
|
"summary" => $processed ["summary"],
|
||||||
"attachments" => $attachments,
|
"content" => $processed ["content"],
|
||||||
|
"attachments" => $processed ["attachments"],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@ class APInboxController extends Controller
|
|||||||
$request = request ();
|
$request = request ();
|
||||||
$type = $request->get ("type");
|
$type = $request->get ("type");
|
||||||
|
|
||||||
|
Log::info ("APInboxController@index");
|
||||||
|
Log::info (json_encode ($request->all ()));
|
||||||
|
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case "Follow":
|
case "Follow":
|
||||||
$this->handle_follow ($user, $request->all ());
|
$this->handle_follow ($user, $request->all ());
|
||||||
@ -29,9 +32,6 @@ class APInboxController extends Controller
|
|||||||
$this->handle_undo ($user, $request->all ());
|
$this->handle_undo ($user, $request->all ());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::info ("APInboxController@index");
|
|
||||||
Log::info (json_encode ($request->all ()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handle_follow (User $user, $activity)
|
private function handle_follow (User $user, $activity)
|
||||||
|
@ -21,6 +21,9 @@ class APInstanceInboxController extends Controller
|
|||||||
$activity = request ()->all ();
|
$activity = request ()->all ();
|
||||||
$activity_type = $activity['type'];
|
$activity_type = $activity['type'];
|
||||||
|
|
||||||
|
Log::info ("APInstanceInboxController:inbox");
|
||||||
|
Log::info ($activity);
|
||||||
|
|
||||||
switch ($activity_type)
|
switch ($activity_type)
|
||||||
{
|
{
|
||||||
case "Create":
|
case "Create":
|
||||||
@ -41,9 +44,6 @@ class APInstanceInboxController extends Controller
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::info ("APInstanceInboxController:inbox");
|
|
||||||
Log::info ($activity);
|
|
||||||
|
|
||||||
return response ()->json (["status" => "ok"]);
|
return response ()->json (["status" => "ok"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +69,9 @@ class APInstanceInboxController extends Controller
|
|||||||
|
|
||||||
public function handle_delete ($activity)
|
public function handle_delete ($activity)
|
||||||
{
|
{
|
||||||
|
if (!is_array ($activity ["object"]))
|
||||||
|
return response ()->json (["error" => "not implemented"]);
|
||||||
|
|
||||||
// we suppose that we are deleting a note
|
// we suppose that we are deleting a note
|
||||||
$note = TypeNote::note_exists ($activity ["object"]["id"]);
|
$note = TypeNote::note_exists ($activity ["object"]["id"]);
|
||||||
if (!$note)
|
if (!$note)
|
||||||
|
@ -2,20 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\AP;
|
namespace App\Http\Controllers\AP;
|
||||||
|
|
||||||
|
use App\Models\Note;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Actor;
|
use App\Models\Actor;
|
||||||
|
use App\Types\TypeNote;
|
||||||
use App\Models\Activity;
|
use App\Models\Activity;
|
||||||
use App\Models\Instance;
|
use App\Models\Instance;
|
||||||
use App\Models\Note;
|
|
||||||
use App\Models\NoteAttachment;
|
|
||||||
|
|
||||||
use App\Types\TypeActivity;
|
|
||||||
use App\Types\TypeActor;
|
use App\Types\TypeActor;
|
||||||
use App\Types\TypeNote;
|
use App\Types\TypeActivity;
|
||||||
|
use App\Actions\ActionsPost;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use App\Models\NoteAttachment;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class APOutboxController extends Controller
|
class APOutboxController extends Controller
|
||||||
{
|
{
|
||||||
@ -28,6 +31,10 @@ class APOutboxController extends Controller
|
|||||||
return $this->handle_update_profile ($user);
|
return $this->handle_update_profile ($user);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "UpdateNote":
|
||||||
|
return $this->handle_update_note ($user, $request);
|
||||||
|
break;
|
||||||
|
|
||||||
case "Follow":
|
case "Follow":
|
||||||
return $this->handle_follow ($user, $request->get ("object"));
|
return $this->handle_follow ($user, $request->get ("object"));
|
||||||
break;
|
break;
|
||||||
@ -56,13 +63,75 @@ class APOutboxController extends Controller
|
|||||||
$instances = Instance::all ();
|
$instances = Instance::all ();
|
||||||
foreach ($instances as $instance)
|
foreach ($instances as $instance)
|
||||||
{
|
{
|
||||||
$response = TypeActivity::post_activity ($update_activity, $actor, $instance->inbox);
|
$response = TypeActivity::post_activity ($update_activity, $actor, $instance->inbox, true);
|
||||||
if ($response->getStatusCode () < 200 || $response->getStatusCode () >= 300)
|
if ($response->getStatusCode () < 200 || $response->getStatusCode () >= 300)
|
||||||
continue;
|
{
|
||||||
|
Log::info ("failed to post activity to " . $instance->inbox);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return response ()->json ("success", 200);
|
return response ()->json ("success", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function handle_update_note (User $user, $request)
|
||||||
|
{
|
||||||
|
$actor = $user->actor ()->first ();
|
||||||
|
|
||||||
|
// first check if there are new attachments
|
||||||
|
if ($request ["attachments"])
|
||||||
|
{
|
||||||
|
// TODO: Keep old attachments
|
||||||
|
$attachments = NoteAttachment::where ("note_id", $request ["note"])->get ();
|
||||||
|
foreach ($attachments as $attachment)
|
||||||
|
{
|
||||||
|
$processed_url = parse_url ($attachment->url);
|
||||||
|
$processed_path = $processed_url["path"];
|
||||||
|
|
||||||
|
$processed_path = str_replace ("/storage", "", $processed_path);
|
||||||
|
if (Storage::disk ("public")->exists ($processed_path))
|
||||||
|
{
|
||||||
|
Storage::disk ("public")->delete ($processed_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log::error ("Attachment not found: " . $attachment->url . " " . $processed_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment->delete ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$note = Note::where ("id", $request ["note"])->first ();
|
||||||
|
if (!$note)
|
||||||
|
return response ()->json ([ "error" => "note not found" ], 404);
|
||||||
|
|
||||||
|
$note_actor = $note->get_actor ()->first ();
|
||||||
|
if ($actor != $note_actor)
|
||||||
|
return response ()->json ([ "error" => "not allowed" ], 403);
|
||||||
|
|
||||||
|
$note->summary = $request ["summary"];
|
||||||
|
$note->content = $request ["content"];
|
||||||
|
$note->save ();
|
||||||
|
|
||||||
|
if ($request ["attachments"])
|
||||||
|
{
|
||||||
|
ActionsPost::create_attachments ($note, $request ["attachments"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$note_response = TypeNote::build_response ($note);
|
||||||
|
$update_activity = TypeActivity::craft_update ($actor, $note_response);
|
||||||
|
$instances = Instance::all ();
|
||||||
|
foreach ($instances as $instance)
|
||||||
|
{
|
||||||
|
$response = TypeActivity::post_activity ($update_activity, $actor, $instance->inbox, true);
|
||||||
|
if ($response->getStatusCode () < 200 || $response->getStatusCode () >= 300)
|
||||||
|
{
|
||||||
|
Log::info ("failed to post activity to " . $instance->inbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response ()->json ("success", 200);
|
||||||
|
}
|
||||||
|
|
||||||
public function handle_follow (User $user, string $object)
|
public function handle_follow (User $user, string $object)
|
||||||
{
|
{
|
||||||
$object_actor = Actor::where ("actor_id", $object)->first ();
|
$object_actor = Actor::where ("actor_id", $object)->first ();
|
||||||
@ -124,13 +193,7 @@ class APOutboxController extends Controller
|
|||||||
|
|
||||||
if (isset ($request ["attachments"]))
|
if (isset ($request ["attachments"]))
|
||||||
{
|
{
|
||||||
foreach ($request ["attachments"] as $attachment)
|
ActionsPost::create_attachments ($note, $request ["attachments"]);
|
||||||
{
|
|
||||||
$attachment_note = NoteAttachment::create ([
|
|
||||||
"note_id" => $note->id,
|
|
||||||
"url" => $attachment
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$create_activity = TypeActivity::craft_create ($actor, $note);
|
$create_activity = TypeActivity::craft_create ($actor, $note);
|
||||||
|
@ -4,8 +4,14 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Models\Note;
|
use App\Models\Note;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use App\Actions\ActionsPost;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use App\Models\NoteAttachment;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class PostController extends Controller
|
class PostController extends Controller
|
||||||
{
|
{
|
||||||
public function show (Note $note)
|
public function show (Note $note)
|
||||||
@ -14,4 +20,53 @@ class PostController extends Controller
|
|||||||
|
|
||||||
return view ("posts.show", compact ("note", "actor"));
|
return view ("posts.show", compact ("note", "actor"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function edit (Note $note)
|
||||||
|
{
|
||||||
|
$actor = $note->get_actor ()->first ();
|
||||||
|
$note_user = $actor->user ()->first ();
|
||||||
|
if (!auth()->user ()->is ($note_user)) {
|
||||||
|
return back ()->with ("error", "You are not allowed to edit this post.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return view ("posts.edit", compact ("note", "actor"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update (Note $note, Request $request)
|
||||||
|
{
|
||||||
|
$actor = auth ()->user ()->actor ()->first ();
|
||||||
|
$note_user = $actor->user ()->first ();
|
||||||
|
if (!auth ()->user ()->is ($note_user)) {
|
||||||
|
return back ()->with ("error", "You are not allowed to edit this post.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$incoming_fields = $request->validate ([
|
||||||
|
"summary" => "nullable|string",
|
||||||
|
"content" => "required|string",
|
||||||
|
"files" => "nullable|array",
|
||||||
|
"files.*" => "image"
|
||||||
|
]);
|
||||||
|
|
||||||
|
$processed = ActionsPost::process_content_and_attachments ($request);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$client = new Client ();
|
||||||
|
$client->request ("POST", $note->get_actor ()->first ()->outbox, [
|
||||||
|
"json" => [
|
||||||
|
"type" => "UpdateNote",
|
||||||
|
"note" => $note->id,
|
||||||
|
"summary" => $processed["summary"],
|
||||||
|
"content" => $processed["content"],
|
||||||
|
"attachments" => $processed["attachments"]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect ()->route ("posts.show", $note)->with ("success", "Post updated successfully.");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return back ()->with ("error", "An error occurred while updating the post.");
|
||||||
|
|
||||||
|
Log::error ("An error occurred while updating the post.");
|
||||||
|
Log::error ($e->getMessage ());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ class UserActionController extends Controller
|
|||||||
public function post_new (Request $request)
|
public function post_new (Request $request)
|
||||||
{
|
{
|
||||||
$request->validate ([
|
$request->validate ([
|
||||||
|
"summary" => "nullable|string",
|
||||||
"content" => "required",
|
"content" => "required",
|
||||||
"files.*" => "mimes:jpeg,png,jpg,gif,webm|max:4096"
|
"files.*" => "mimes:jpeg,png,jpg,gif,webm|max:4096"
|
||||||
]);
|
]);
|
||||||
|
@ -18,6 +18,7 @@ class TypeActivity {
|
|||||||
"type" => $activity->type,
|
"type" => $activity->type,
|
||||||
"actor" => $activity->actor,
|
"actor" => $activity->actor,
|
||||||
"object" => $activity->object,
|
"object" => $activity->object,
|
||||||
|
"published" => $activity->created_at,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($activity->target)
|
if ($activity->target)
|
||||||
@ -100,6 +101,18 @@ class TypeActivity {
|
|||||||
return $create_activity;
|
return $create_activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function get_private_key (Actor $actor)
|
||||||
|
{
|
||||||
|
return openssl_get_privatekey ($actor->private_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function sign ($data, $key)
|
||||||
|
{
|
||||||
|
openssl_sign ($data, $signature, $key, OPENSSL_ALGO_SHA256);
|
||||||
|
|
||||||
|
return $signature;
|
||||||
|
}
|
||||||
|
|
||||||
public static function craft_signed_headers ($activity, Actor $source, $target)
|
public static function craft_signed_headers ($activity, Actor $source, $target)
|
||||||
{
|
{
|
||||||
if (!$source->user)
|
if (!$source->user)
|
||||||
@ -110,7 +123,7 @@ class TypeActivity {
|
|||||||
|
|
||||||
$key_id = $source->actor_id . "#main-key";
|
$key_id = $source->actor_id . "#main-key";
|
||||||
|
|
||||||
$signer = openssl_get_privatekey ($source->private_key);
|
$signer = TypeActivity::get_private_key ($source);
|
||||||
|
|
||||||
$date = gmdate ("D, d M Y H:i:s \G\M\T");
|
$date = gmdate ("D, d M Y H:i:s \G\M\T");
|
||||||
|
|
||||||
@ -125,6 +138,12 @@ class TypeActivity {
|
|||||||
else
|
else
|
||||||
$url = parse_url ($target);
|
$url = parse_url ($target);
|
||||||
|
|
||||||
|
if (!$url ["path"] || !$url ["host"])
|
||||||
|
{
|
||||||
|
Log::error ("Target not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$string_to_sign = "(request-target): post ". $url["path"] . "\nhost: " . $url["host"] . "\ndate: " . $date . "\ndigest: SHA-256=" . $digest;
|
$string_to_sign = "(request-target): post ". $url["path"] . "\nhost: " . $url["host"] . "\ndate: " . $date . "\ndigest: SHA-256=" . $digest;
|
||||||
|
|
||||||
openssl_sign ($string_to_sign, $signature, $signer, OPENSSL_ALGO_SHA256);
|
openssl_sign ($string_to_sign, $signature, $signer, OPENSSL_ALGO_SHA256);
|
||||||
@ -139,16 +158,47 @@ class TypeActivity {
|
|||||||
"Signature" => $signature_header,
|
"Signature" => $signature_header,
|
||||||
"Content-Type" => "application/activity+json",
|
"Content-Type" => "application/activity+json",
|
||||||
"Accept" => "application/activity+json",
|
"Accept" => "application/activity+json",
|
||||||
|
"B64" => $signature_b64
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function post_activity (Activity $activity, Actor $source, $target)
|
public static function post_activity (Activity $activity, Actor $source, $target, $should_sign = false)
|
||||||
{
|
{
|
||||||
$crafted_activity = TypeActivity::craft_response ($activity);
|
$crafted_activity = TypeActivity::craft_response ($activity);
|
||||||
|
|
||||||
|
if ($should_sign)
|
||||||
|
{
|
||||||
|
$crafted_activity["to"] = [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
];
|
||||||
|
|
||||||
|
$crafted_activity["cc"] = [
|
||||||
|
$source->following
|
||||||
|
];
|
||||||
|
|
||||||
|
$key = TypeActivity::get_private_key ($source);
|
||||||
|
$activity_json = json_encode ($crafted_activity, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION);
|
||||||
|
$signature = TypeActivity::sign ($activity_json, $key);
|
||||||
|
|
||||||
|
$crafted_activity ["signature"] = [
|
||||||
|
"type" => "RsaSignature2017",
|
||||||
|
"creator" => $source->actor_id . "#main-key",
|
||||||
|
"created" => gmdate ("Y-m-d\TH:i:s\Z"),
|
||||||
|
"signatureValue" => base64_encode ($signature)
|
||||||
|
];
|
||||||
|
|
||||||
|
$activity_json = json_encode ($crafted_activity, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION);
|
||||||
|
}
|
||||||
|
|
||||||
$activity_json = json_encode ($crafted_activity, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION);
|
$activity_json = json_encode ($crafted_activity, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION);
|
||||||
$activity_json = mb_convert_encoding ($activity_json, "UTF-8");
|
$activity_json = mb_convert_encoding ($activity_json, "UTF-8");
|
||||||
|
|
||||||
$headers = TypeActivity::craft_signed_headers ($activity_json, $source, $target);
|
$headers = TypeActivity::craft_signed_headers ($activity_json, $source, $target);
|
||||||
|
if (!$headers)
|
||||||
|
{
|
||||||
|
Log::error ("Failed to craft headers");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$target_inbox = null;
|
$target_inbox = null;
|
||||||
@ -171,7 +221,13 @@ class TypeActivity {
|
|||||||
}
|
}
|
||||||
catch (RequestException $e)
|
catch (RequestException $e)
|
||||||
{
|
{
|
||||||
Log::error ($e->getMessage ());
|
$response = $e->getResponse ();
|
||||||
|
if ($response)
|
||||||
|
{
|
||||||
|
Log::error ("Failed to post activity: " . $response->getBody ());
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::error ("Failed to post activity: " . $e->getMessage ());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +232,7 @@ class TypeActor {
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
// TODO: check if we got a 404
|
||||||
return json_encode (["error" => "Actor not found"]);
|
return json_encode (["error" => "Actor not found"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ class TypeNote
|
|||||||
"summary" => $note->summary,
|
"summary" => $note->summary,
|
||||||
"inReplyTo" => $note->in_reply_to,
|
"inReplyTo" => $note->in_reply_to,
|
||||||
"published" => $note->created_at,
|
"published" => $note->created_at,
|
||||||
|
"updated" => $note->updated_at,
|
||||||
"url" => $note->url,
|
"url" => $note->url,
|
||||||
"attributedTo" => $note->attributedTo,
|
"attributedTo" => $note->attributedTo,
|
||||||
"to" => [
|
"to" => [
|
||||||
@ -50,16 +51,19 @@ class TypeNote
|
|||||||
// TODO: url should be route ('posts.show', $note->id)
|
// TODO: url should be route ('posts.show', $note->id)
|
||||||
$note = Note::create ([
|
$note = Note::create ([
|
||||||
"actor_id" => $actor->id,
|
"actor_id" => $actor->id,
|
||||||
|
"summary" => $request ["summary"],
|
||||||
"note_id" => env ("APP_URL") . "/ap/v1/note/" . uniqid (),
|
"note_id" => env ("APP_URL") . "/ap/v1/note/" . uniqid (),
|
||||||
"in_reply_to" => $request ["inReplyTo"] ?? null,
|
"in_reply_to" => $request ["inReplyTo"] ?? null,
|
||||||
"type" => "Note",
|
"type" => "Note",
|
||||||
"summary" => $request ["summary"] ?? null,
|
"summary" => $request ["summary"] ?? null,
|
||||||
"url" => "TODO",
|
|
||||||
"attributedTo" => $actor->actor_id,
|
"attributedTo" => $actor->actor_id,
|
||||||
"content" => $request ["content"] ?? null,
|
"content" => $request ["content"] ?? null,
|
||||||
"tag" => $request ["tag"] ?? null
|
"tag" => $request ["tag"] ?? null
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$note->url = route ('posts.show', $note->id);
|
||||||
|
$note->save ();
|
||||||
|
|
||||||
return $note;
|
return $note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
"guzzlehttp/guzzle": "^7.9",
|
"guzzlehttp/guzzle": "^7.9",
|
||||||
"intervention/image": "^3.10",
|
"intervention/image": "^3.10",
|
||||||
"laravel/framework": "^11.31",
|
"laravel/framework": "^11.31",
|
||||||
"laravel/tinker": "^2.9"
|
"laravel/tinker": "^2.9",
|
||||||
|
"league/html-to-markdown": "^5.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.23",
|
"fakerphp/faker": "^1.23",
|
||||||
|
91
composer.lock
generated
91
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "067a260457c754c554a61fce0e741b0f",
|
"content-hash": "628d31471da81db14ba13b073eaa09e0",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
@ -1920,6 +1920,95 @@
|
|||||||
},
|
},
|
||||||
"time": "2024-08-09T21:24:39+00:00"
|
"time": "2024-08-09T21:24:39+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "league/html-to-markdown",
|
||||||
|
"version": "5.1.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||||
|
"reference": "0b4066eede55c48f38bcee4fb8f0aa85654390fd"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/0b4066eede55c48f38bcee4fb8f0aa85654390fd",
|
||||||
|
"reference": "0b4066eede55c48f38bcee4fb8f0aa85654390fd",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-xml": "*",
|
||||||
|
"php": "^7.2.5 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mikehaertl/php-shellcommand": "^1.1.0",
|
||||||
|
"phpstan/phpstan": "^1.8.8",
|
||||||
|
"phpunit/phpunit": "^8.5 || ^9.2",
|
||||||
|
"scrutinizer/ocular": "^1.6",
|
||||||
|
"unleashedtech/php-coding-standard": "^2.7 || ^3.0",
|
||||||
|
"vimeo/psalm": "^4.22 || ^5.0"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/html-to-markdown"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.2-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\HTMLToMarkdown\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Colin O'Dell",
|
||||||
|
"email": "colinodell@gmail.com",
|
||||||
|
"homepage": "https://www.colinodell.com",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nick Cernis",
|
||||||
|
"email": "nick@cern.is",
|
||||||
|
"homepage": "http://modernnerd.net",
|
||||||
|
"role": "Original Author"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An HTML-to-markdown conversion helper for PHP",
|
||||||
|
"homepage": "https://github.com/thephpleague/html-to-markdown",
|
||||||
|
"keywords": [
|
||||||
|
"html",
|
||||||
|
"markdown"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/thephpleague/html-to-markdown/issues",
|
||||||
|
"source": "https://github.com/thephpleague/html-to-markdown/tree/5.1.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.colinodell.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.paypal.me/colinpodell/10.00",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/colinodell",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/league/html-to-markdown",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-07-12T21:21:09+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "league/mime-type-detection",
|
"name": "league/mime-type-detection",
|
||||||
"version": "1.16.0",
|
"version": "1.16.0",
|
||||||
|
@ -45,7 +45,7 @@ else
|
|||||||
<a href="{{ route ('posts.show', [ 'note' => $post ]) }}">
|
<a href="{{ route ('posts.show', [ 'note' => $post ]) }}">
|
||||||
<button type="button">View</button>
|
<button type="button">View</button>
|
||||||
</a>
|
</a>
|
||||||
@if ($actor->user && auth ()->check () && auth ()->user ()->is ($actor->user))
|
{{-- @if ($actor->user && auth ()->check () && auth ()->user ()->is ($actor->user))
|
||||||
<form action="#" method="POST" style="display: inline">
|
<form action="#" method="POST" style="display: inline">
|
||||||
@csrf
|
@csrf
|
||||||
<a href="#">
|
<a href="#">
|
||||||
@ -55,6 +55,6 @@ else
|
|||||||
</a>
|
</a>
|
||||||
<input type="submit" value="Delete">
|
<input type="submit" value="Delete">
|
||||||
</form>
|
</form>
|
||||||
@endif
|
@endif --}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
42
resources/views/posts/edit.blade.php
Normal file
42
resources/views/posts/edit.blade.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
@extends ("partials.layout")
|
||||||
|
|
||||||
|
@section ("title", "Edit Post")
|
||||||
|
|
||||||
|
@php
|
||||||
|
use League\HTMLToMarkdown\HtmlConverter;
|
||||||
|
$converter = new HtmlConverter ();
|
||||||
|
$markdown = $converter->convert ($note->content);
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
@section ("content")
|
||||||
|
<div class="row edit-blog-entry">
|
||||||
|
<div class="col w-20 left">
|
||||||
|
<div class="edit-info">
|
||||||
|
<p>Edit your post</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col right">
|
||||||
|
<h1>Edit Post</h1>
|
||||||
|
<p>
|
||||||
|
<a href="{{ route ('posts.show', ['note' => $note ]) }}">← View post</a>
|
||||||
|
</p>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
|
<input type="text" name="summary" placeholder="Summary" value="{{ old ('summary', $note->summary) }}">
|
||||||
|
<br>
|
||||||
|
<textarea name="content" id="content">{{ old ('content', $markdown) }}</textarea>
|
||||||
|
<br>
|
||||||
|
<input type="file" name="files[]" accept="image/*" multiple>
|
||||||
|
|
||||||
|
<div class="publish">
|
||||||
|
<button type="submit" name="submit">
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
@ -42,14 +42,21 @@
|
|||||||
@if (auth ()->check () && auth ()->user ()->is ($actor->user))
|
@if (auth ()->check () && auth ()->user ()->is ($actor->user))
|
||||||
<form action="#" method="POST">
|
<form action="#" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
<a href="#">
|
<a href="{{ route ('posts.edit', [ 'note' => $note ]) }}">
|
||||||
<button type="button">Edit</button>
|
<button type="button">Edit</button>
|
||||||
</a>
|
</a>
|
||||||
<button type="submit">Delete</button>
|
<button type="submit">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
@endif
|
@endif
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
<div class="heading">
|
||||||
|
<h4>{{ $note->summary }}</h4>
|
||||||
|
</div>
|
||||||
{!! $note->content !!}
|
{!! $note->content !!}
|
||||||
|
|
||||||
|
@foreach ($note->attachments as $attachment)
|
||||||
|
<img loading="lazy" src="{{ $attachment->url }}" width="250">
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
@ -277,6 +277,8 @@
|
|||||||
@if (auth ()->user () && auth ()->user ()->is ($user))
|
@if (auth ()->user () && auth ()->user ()->is ($user))
|
||||||
<form action="{{ route ('user.post.new') }}" method="post" enctype="multipart/form-data">
|
<form action="{{ route ('user.post.new') }}" method="post" enctype="multipart/form-data">
|
||||||
@csrf
|
@csrf
|
||||||
|
<input type="text" name="summary" placeholder="Title" size="60">
|
||||||
|
<br>
|
||||||
<textarea name="content" placeholder="What's on your mind?" cols="60" rows="5"></textarea>
|
<textarea name="content" placeholder="What's on your mind?" cols="60" rows="5"></textarea>
|
||||||
<input type="file" name="files[]" accept="image/*" multiple>
|
<input type="file" name="files[]" accept="image/*" multiple>
|
||||||
<button type="submit">Post</button>
|
<button type="submit">Post</button>
|
||||||
|
@ -28,6 +28,8 @@ Route::post ("/user/edit", [ ProfileController::class, "update" ])->middleware (
|
|||||||
Route::get ("/user/{user_name}", [ ProfileController::class, "show" ])->name ("users.show");
|
Route::get ("/user/{user_name}", [ ProfileController::class, "show" ])->name ("users.show");
|
||||||
|
|
||||||
// posts routes
|
// posts routes
|
||||||
|
Route::get ("/post/{note}/edit", [ PostController::class, "edit" ])->name ("posts.edit")->middleware ("auth");
|
||||||
|
Route::post ("/post/{note}/edit", [ PostController::class, "update" ])->middleware ("auth");
|
||||||
Route::get ("/post/{note}", [ PostController::class, "show" ])->name ("posts.show");
|
Route::get ("/post/{note}", [ PostController::class, "show" ])->name ("posts.show");
|
||||||
|
|
||||||
// other routes
|
// other routes
|
||||||
|
Loading…
x
Reference in New Issue
Block a user