added note visibility

This commit is contained in:
Ghostie 2025-01-12 15:10:44 -05:00
parent daa8b3eaeb
commit 518586b6ab
11 changed files with 130 additions and 16 deletions

View File

@ -2,7 +2,7 @@
- [-] Activitypub - [-] Activitypub
- [x] Accounts - [x] Accounts
- [-] Posts - [x] Posts
- [x] Local posts should be federated - [x] Local posts should be federated
- [x] Local posts should be deleted - [x] Local posts should be deleted
- [x] Remote posts should be fetched - [x] Remote posts should be fetched
@ -18,10 +18,10 @@
- [x] Tags - [x] Tags
- [x] Mentions - [x] Mentions
- [x] Local mentions - [x] Local mentions
- [ ] Private post - [x] Private post
- [x] Pinned Posts - [x] Pinned Posts
- [x] Nodeinfo - [x] Nodeinfo
- [ ] Notifications - [x] Notifications
- [-] Social features - [-] Social features
- [x] Profile - [x] Profile

View File

@ -125,6 +125,7 @@ class ActionsPost
"summary" => $processed ["summary"], "summary" => $processed ["summary"],
"content" => $processed ["content"], "content" => $processed ["content"],
"attachments" => $processed ["attachments"], "attachments" => $processed ["attachments"],
"visibility" => $request ["visibility"],
"inReplyTo" => $processed ["inReplyTo"] ?? null, "inReplyTo" => $processed ["inReplyTo"] ?? null,
"tags" => $processed ["tags"] ?? null, "tags" => $processed ["tags"] ?? null,
"mentions" => $processed ["mentions"] ?? null "mentions" => $processed ["mentions"] ?? null

View File

@ -370,6 +370,7 @@ class APOutboxController extends Controller
} }
} }
$mentions = [];
if (isset ($request ["mentions"])) if (isset ($request ["mentions"]))
{ {
foreach ($request ["mentions"] as $mention) foreach ($request ["mentions"] as $mention)
@ -387,9 +388,37 @@ class APOutboxController extends Controller
"note_id" => $note->id, "note_id" => $note->id,
"actor_id" => $object->id "actor_id" => $object->id
]); ]);
$mentions[] = $object->actor_id;
} }
} }
if ($request ["visibility"] == "public")
{
$note->to = [
"https://www.w3.org/ns/activitystreams#Public"
];
$note->cc = [
$actor->followers
];
}
else if ($request ["visibility"] == "followers")
{
// TODO: Boosting should be disabled
$note->to = [
$actor->followers
];
$note->cc = [];
}
else if ($request ["visibility"] == "private")
{
// TODO: Boosting should be disabled
$note->to = $mentions;
}
$note->visibility = $request ["visibility"];
$note->save ();
$create_activity = TypeActivity::craft_create ($actor, $note); $create_activity = TypeActivity::craft_create ($actor, $note);
$create_activity->to = $note->to; $create_activity->to = $note->to;

View File

@ -21,6 +21,8 @@ class PostController extends Controller
if (!$actor) if (!$actor)
return redirect ()->back (); return redirect ()->back ();
if (!$note->can_view ())
return redirect ()->back ()->with ("error", "You are not allowed to view this post.");
return view ("posts.show", compact ("note", "actor")); return view ("posts.show", compact ("note", "actor"));
} }

View File

@ -32,7 +32,8 @@ class UserActionController extends Controller
$request->validate ([ $request->validate ([
"summary" => "nullable|string", "summary" => "nullable|string",
"content" => "required", "content" => "required",
"files.*" => "max:4096" "files.*" => "max:4096",
"visibility" => "required|in:public,private,followers",
]); ]);
$response = ActionsPost::post_new ($request); $response = ActionsPost::post_new ($request);

View File

@ -11,6 +11,6 @@ class Hashtag extends Model
]; ];
public function get_notes () { public function get_notes () {
return $this->belongsToMany(Note::class, 'note_hashtag'); return $this->belongsToMany(Note::class, 'note_hashtag')->orderBy('created_at', 'desc');
} }
} }

View File

@ -20,7 +20,8 @@ class Note extends Model
"content", "content",
"tag", "tag",
"to", "to",
"cc" "cc",
"visibility"
]; ];
protected $casts = [ protected $casts = [
@ -88,4 +89,34 @@ class Note extends Model
{ {
return ProfilePin::where ("actor_id", $actor->id)->where ("note_id", $this->id)->first (); return ProfilePin::where ("actor_id", $actor->id)->where ("note_id", $this->id)->first ();
} }
public function can_view (Actor $actor = null)
{
$final_actor = $actor;
$note_actor = $this->get_actor ()->first ();
if (!$final_actor && auth ()->check ())
{
$final_actor = auth ()->user ()->actor;
}
if ($this->visibility == "public")
{
return true;
}
else if ($this->visibility == "followers" && $final_actor)
{
return $final_actor->friends_with ($note_actor);
}
else if ($this->visibility == "private" && $final_actor)
{
if ($final_actor == $note_actor)
return true;
$mention_exists = NoteMention::where ("note_id", $this->id)->where ("actor_id", $final_actor->id)->first ();
if ($mention_exists)
return true;
}
return false;
}
} }

View File

@ -86,14 +86,6 @@ class TypeNote
"attributedTo" => $actor->actor_id, "attributedTo" => $actor->actor_id,
"content" => $request ["content"] ?? null, "content" => $request ["content"] ?? null,
"tag" => $request ["tag"] ?? null, "tag" => $request ["tag"] ?? null,
// TODO: This should change when I implement visibilities and private notes
"to" => [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc" => [
$actor->followers
]
]); ]);
$note->url = route ('posts.show', $note->id); $note->url = route ('posts.show', $note->id);
@ -107,6 +99,7 @@ class TypeNote
if ($activity) if ($activity)
$note->activity_id = $activity->id; $note->activity_id = $activity->id;
$note_actor = $actor;
if ($actor) if ($actor)
$note->actor_id = $actor->id; $note->actor_id = $actor->id;
else else
@ -122,6 +115,7 @@ class TypeNote
} }
$note->actor_id = $actor->id; $note->actor_id = $actor->id;
$note_actor = $actor;
} }
$note->note_id = $request["id"] ?? null; $note->note_id = $request["id"] ?? null;
@ -132,6 +126,8 @@ class TypeNote
$note->content = $request["content"] ?? null; $note->content = $request["content"] ?? null;
$note->tag = $request["tag"] ?? null; $note->tag = $request["tag"] ?? null;
$note->created_at = $request["published"] ?? null; $note->created_at = $request["published"] ?? null;
$note->to = $request["to"] ?? null;
$note->cc = $request["cc"] ?? null;
$attachments = $note->attachments ()->get (); $attachments = $note->attachments ()->get ();
foreach ($attachments as $attachment) foreach ($attachments as $attachment)
@ -238,6 +234,20 @@ class TypeNote
{ {
// TODO: Handle replies // TODO: Handle replies
} }
$note_to = $note->to;
if (in_array ("https://www.w3.org/ns/activitystreams#Public", $note_to))
{
$note->visibility = "public";
}
else if (in_array ($note_actor->followers, $note_to))
{
$note->visibility = "followers";
}
else
{
$note->visibility = "private";
}
} }
public static function create_from_request ($request, Activity $activity, Actor $actor) public static function create_from_request ($request, Activity $activity, Actor $actor)

View File

@ -0,0 +1,28 @@
<?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('notes', function (Blueprint $table) {
$table->string ("visibility")->default ("public");
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('notes', function (Blueprint $table) {
$table->dropColumn ("visibility");
});
}
};

View File

@ -21,6 +21,9 @@ if ($actor->user_id)
$actor_url = route ('users.show', [ 'user_name' => $actor->user->name ]); $actor_url = route ('users.show', [ 'user_name' => $actor->user->name ]);
else else
$actor_url = route ('users.show', [ 'user_name' => $actor->local_actor_id ]); $actor_url = route ('users.show', [ 'user_name' => $actor->local_actor_id ]);
if (!$display_post->can_view ())
return;
@endphp @endphp
<tr> <tr>

View File

@ -10,9 +10,18 @@
<br> <br>
<textarea name="content" placeholder="What's on your mind?" style="width: 100%"></textarea> <textarea name="content" placeholder="What's on your mind?" style="width: 100%"></textarea>
<input type="file" name="files[]" accept="image/*" multiple><br>
<button type="submit">Post</button>
<small>Markdown is supported</small> <small>Markdown is supported</small>
<br>
<input type="file" name="files[]" accept="image/*" multiple><br>
<p>
<b>Visibility:</b>
<select name="visibility">
<option value="public">Public</option>
<option value="followers">Friends only</option>
<option value="private">Mentioned Only</option>
</select>
</p>
<button type="submit">Post</button>
@error ("content") @error ("content")
<div class="error">{{ $message }}</div> <div class="error">{{ $message }}</div>