mirror of
https://github.com/YunoHost-Apps/pixelfed_ynh.git
synced 2024-09-03 20:06:04 +02:00
Merge pull request #1461 from pixelfed/frontend-ui-refactor
ActivityPub improvements (Announce + Like)
This commit is contained in:
commit
d316a647c3
17 changed files with 156 additions and 137 deletions
|
@ -56,7 +56,7 @@ class SearchController extends Controller
|
||||||
]
|
]
|
||||||
]];
|
]];
|
||||||
} else if ($type == 'Note') {
|
} else if ($type == 'Note') {
|
||||||
$item = Helpers::statusFirstOrFetch($tag, false);
|
$item = Helpers::statusFetch($tag);
|
||||||
$tokens['posts'] = [[
|
$tokens['posts'] = [[
|
||||||
'count' => 0,
|
'count' => 0,
|
||||||
'url' => $item->url(),
|
'url' => $item->url(),
|
||||||
|
|
|
@ -30,11 +30,12 @@ class StatusController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$status = Status::whereProfileId($user->id)
|
$status = Status::whereProfileId($user->id)
|
||||||
|
->whereNull('reblog_of_id')
|
||||||
->whereNotIn('visibility',['draft','direct'])
|
->whereNotIn('visibility',['draft','direct'])
|
||||||
->findOrFail($id);
|
->findOrFail($id);
|
||||||
|
|
||||||
if($status->uri) {
|
if($status->uri || $status->url) {
|
||||||
$url = $status->uri;
|
$url = $status->uri ?? $status->url;
|
||||||
if(ends_with($url, '/activity')) {
|
if(ends_with($url, '/activity')) {
|
||||||
$url = str_replace('/activity', '', $url);
|
$url = str_replace('/activity', '', $url);
|
||||||
}
|
}
|
||||||
|
@ -102,109 +103,6 @@ class StatusController extends Controller
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
||||||
$this->authCheck();
|
|
||||||
$user = Auth::user();
|
|
||||||
|
|
||||||
$size = Media::whereUserId($user->id)->sum('size') / 1000;
|
|
||||||
$limit = (int) config('pixelfed.max_account_size');
|
|
||||||
if ($size >= $limit) {
|
|
||||||
return redirect()->back()->with('error', 'You have exceeded your storage limit. Please click <a href="#">here</a> for more info.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->validate($request, [
|
|
||||||
'photo.*' => 'required|mimetypes:' . config('pixelfed.media_types').'|max:' . config('pixelfed.max_photo_size'),
|
|
||||||
'caption' => 'nullable|string|max:'.config('pixelfed.max_caption_length'),
|
|
||||||
'cw' => 'nullable|string',
|
|
||||||
'filter_class' => 'nullable|alpha_dash|max:30',
|
|
||||||
'filter_name' => 'nullable|string',
|
|
||||||
'visibility' => 'required|string|min:5|max:10',
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (count($request->file('photo')) > config('pixelfed.max_album_length')) {
|
|
||||||
return redirect()->back()->with('error', 'Too many files, max limit per post: '.config('pixelfed.max_album_length'));
|
|
||||||
}
|
|
||||||
$cw = $request->filled('cw') && $request->cw == 'on' ? true : false;
|
|
||||||
$monthHash = hash('sha1', date('Y').date('m'));
|
|
||||||
$userHash = hash('sha1', $user->id.(string) $user->created_at);
|
|
||||||
$profile = $user->profile;
|
|
||||||
$visibility = $this->validateVisibility($request->visibility);
|
|
||||||
|
|
||||||
$cw = $profile->cw == true ? true : $cw;
|
|
||||||
$visibility = $profile->unlisted == true && $visibility == 'public' ? 'unlisted' : $visibility;
|
|
||||||
|
|
||||||
if(config('costar.enabled') == true) {
|
|
||||||
$blockedKeywords = config('costar.keyword.block');
|
|
||||||
if($blockedKeywords !== null) {
|
|
||||||
$keywords = config('costar.keyword.block');
|
|
||||||
foreach($keywords as $kw) {
|
|
||||||
if(Str::contains($request->caption, $kw) == true) {
|
|
||||||
abort(400, 'Invalid object');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$status = new Status();
|
|
||||||
$status->profile_id = $profile->id;
|
|
||||||
$status->caption = strip_tags($request->caption);
|
|
||||||
$status->is_nsfw = $cw;
|
|
||||||
|
|
||||||
// TODO: remove deprecated visibility in favor of scope
|
|
||||||
$status->visibility = $visibility;
|
|
||||||
$status->scope = $visibility;
|
|
||||||
|
|
||||||
$status->save();
|
|
||||||
|
|
||||||
$photos = $request->file('photo');
|
|
||||||
$order = 1;
|
|
||||||
$mimes = [];
|
|
||||||
$medias = 0;
|
|
||||||
|
|
||||||
foreach ($photos as $k => $v) {
|
|
||||||
|
|
||||||
$allowedMimes = explode(',', config('pixelfed.media_types'));
|
|
||||||
if(in_array($v->getMimeType(), $allowedMimes) == false) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$filter_class = $request->input('filter_class');
|
|
||||||
$filter_name = $request->input('filter_name');
|
|
||||||
|
|
||||||
$storagePath = "public/m/{$monthHash}/{$userHash}";
|
|
||||||
$path = $v->store($storagePath);
|
|
||||||
$hash = \hash_file('sha256', $v);
|
|
||||||
$media = new Media();
|
|
||||||
$media->status_id = $status->id;
|
|
||||||
$media->profile_id = $profile->id;
|
|
||||||
$media->user_id = $user->id;
|
|
||||||
$media->media_path = $path;
|
|
||||||
$media->original_sha256 = $hash;
|
|
||||||
$media->size = $v->getSize();
|
|
||||||
$media->mime = $v->getMimeType();
|
|
||||||
|
|
||||||
$media->filter_class = in_array($filter_class, Filter::classes()) ? $filter_class : null;
|
|
||||||
$media->filter_name = in_array($filter_name, Filter::names()) ? $filter_name : null;
|
|
||||||
$media->order = $order;
|
|
||||||
$media->save();
|
|
||||||
array_push($mimes, $media->mime);
|
|
||||||
ImageOptimize::dispatch($media);
|
|
||||||
$order++;
|
|
||||||
$medias++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($medias == 0) {
|
|
||||||
$status->delete();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$status->type = (new self)::mimeTypeCheck($mimes);
|
|
||||||
$status->save();
|
|
||||||
|
|
||||||
Cache::forget('profile:status_count:'.$profile->id);
|
|
||||||
NewStatusPipeline::dispatch($status);
|
|
||||||
|
|
||||||
// TODO: Send to subscribers
|
|
||||||
|
|
||||||
return redirect($status->url());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Request $request)
|
public function delete(Request $request)
|
||||||
|
@ -238,7 +136,9 @@ class StatusController extends Controller
|
||||||
|
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$profile = $user->profile;
|
$profile = $user->profile;
|
||||||
$status = Status::withCount('shares')->findOrFail($request->input('item'));
|
$status = Status::withCount('shares')
|
||||||
|
->whereIn('scope', ['public', 'unlisted'])
|
||||||
|
->findOrFail($request->input('item'));
|
||||||
|
|
||||||
$count = $status->shares_count;
|
$count = $status->shares_count;
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,17 @@
|
||||||
|
|
||||||
namespace App\Jobs\LikePipeline;
|
namespace App\Jobs\LikePipeline;
|
||||||
|
|
||||||
use App\Like;
|
use Cache, Log, Redis;
|
||||||
use App\Notification;
|
use App\{Like, Notification};
|
||||||
use Cache;
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Log;
|
use App\Util\ActivityPub\Helpers;
|
||||||
use Redis;
|
use League\Fractal;
|
||||||
|
use League\Fractal\Serializer\ArraySerializer;
|
||||||
|
use App\Transformer\ActivityPub\Verb\Like as LikeTransformer;
|
||||||
|
|
||||||
class LikePipeline implements ShouldQueue
|
class LikePipeline implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
@ -48,11 +49,15 @@ class LikePipeline implements ShouldQueue
|
||||||
$status = $this->like->status;
|
$status = $this->like->status;
|
||||||
$actor = $this->like->actor;
|
$actor = $this->like->actor;
|
||||||
|
|
||||||
if (!$status || $status->url !== null) {
|
if (!$status) {
|
||||||
// Ignore notifications to remote statuses, or deleted statuses
|
// Ignore notifications to deleted statuses
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($status->url && $actor->domain == null) {
|
||||||
|
return $this->remoteLikeDeliver();
|
||||||
|
}
|
||||||
|
|
||||||
$exists = Notification::whereProfileId($status->profile_id)
|
$exists = Notification::whereProfileId($status->profile_id)
|
||||||
->whereActorId($actor->id)
|
->whereActorId($actor->id)
|
||||||
->whereAction('like')
|
->whereAction('like')
|
||||||
|
@ -78,4 +83,20 @@ class LikePipeline implements ShouldQueue
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function remoteLikeDeliver()
|
||||||
|
{
|
||||||
|
$like = $this->like;
|
||||||
|
$status = $this->like->status;
|
||||||
|
$actor = $this->like->actor;
|
||||||
|
|
||||||
|
$fractal = new Fractal\Manager();
|
||||||
|
$fractal->setSerializer(new ArraySerializer());
|
||||||
|
$resource = new Fractal\Resource\Item($like, new LikeTransformer());
|
||||||
|
$activity = $fractal->createData($resource)->toArray();
|
||||||
|
|
||||||
|
$url = $status->profile->sharedInbox ?? $status->profile->inbox_url;
|
||||||
|
|
||||||
|
Helpers::sendSignedObject($actor, $url, $activity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use League\Fractal;
|
||||||
|
use League\Fractal\Serializer\ArraySerializer;
|
||||||
|
use App\Transformer\ActivityPub\Verb\Announce;
|
||||||
|
use GuzzleHttp\{Pool, Client, Promise};
|
||||||
|
use App\Util\ActivityPub\HttpSignature;
|
||||||
|
|
||||||
class SharePipeline implements ShouldQueue
|
class SharePipeline implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
@ -60,6 +65,8 @@ class SharePipeline implements ShouldQueue
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->remoteAnnounceDeliver();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$notification = new Notification;
|
$notification = new Notification;
|
||||||
$notification->profile_id = $target->id;
|
$notification->profile_id = $target->id;
|
||||||
|
@ -78,4 +85,56 @@ class SharePipeline implements ShouldQueue
|
||||||
Log::error($e);
|
Log::error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function remoteAnnounceDeliver()
|
||||||
|
{
|
||||||
|
$status = $this->status;
|
||||||
|
$profile = $status->profile;
|
||||||
|
|
||||||
|
$fractal = new Fractal\Manager();
|
||||||
|
$fractal->setSerializer(new ArraySerializer());
|
||||||
|
$resource = new Fractal\Resource\Item($status, new Announce());
|
||||||
|
$activity = $fractal->createData($resource)->toArray();
|
||||||
|
|
||||||
|
$audience = $status->profile->getAudienceInbox();
|
||||||
|
|
||||||
|
if(empty($audience) || $status->scope != 'public') {
|
||||||
|
// Return on profiles with no remote followers
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = json_encode($activity);
|
||||||
|
|
||||||
|
$client = new Client([
|
||||||
|
'timeout' => config('federation.activitypub.delivery.timeout')
|
||||||
|
]);
|
||||||
|
|
||||||
|
$requests = function($audience) use ($client, $activity, $profile, $payload) {
|
||||||
|
foreach($audience as $url) {
|
||||||
|
$headers = HttpSignature::sign($profile, $url, $activity);
|
||||||
|
yield function() use ($client, $url, $headers, $payload) {
|
||||||
|
return $client->postAsync($url, [
|
||||||
|
'curl' => [
|
||||||
|
CURLOPT_HTTPHEADER => $headers,
|
||||||
|
CURLOPT_POSTFIELDS => $payload,
|
||||||
|
CURLOPT_HEADER => true
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$pool = new Pool($client, $requests($audience), [
|
||||||
|
'concurrency' => config('federation.activitypub.delivery.concurrency'),
|
||||||
|
'fulfilled' => function ($response, $index) {
|
||||||
|
},
|
||||||
|
'rejected' => function ($reason, $index) {
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
$promise = $pool->promise();
|
||||||
|
|
||||||
|
$promise->wait();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ class StatusActivityPubDeliver implements ShouldQueue
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$status = $this->status;
|
$status = $this->status;
|
||||||
|
$profile = $status->profile;
|
||||||
|
|
||||||
if($status->local == false || $status->url || $status->uri) {
|
if($status->local == false || $status->url || $status->uri) {
|
||||||
return;
|
return;
|
||||||
|
@ -56,12 +57,11 @@ class StatusActivityPubDeliver implements ShouldQueue
|
||||||
|
|
||||||
$audience = $status->profile->getAudienceInbox();
|
$audience = $status->profile->getAudienceInbox();
|
||||||
|
|
||||||
if(empty($audience) || $status->visibility != 'public') {
|
if(empty($audience) || $status->scope != 'public') {
|
||||||
// Return on profiles with no remote followers
|
// Return on profiles with no remote followers
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$profile = $status->profile;
|
|
||||||
|
|
||||||
$fractal = new Fractal\Manager();
|
$fractal = new Fractal\Manager();
|
||||||
$fractal->setSerializer(new ArraySerializer());
|
$fractal->setSerializer(new ArraySerializer());
|
||||||
|
|
|
@ -11,9 +11,16 @@ class Announce extends Fractal\TransformerAbstract
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||||
|
'id' => $status->permalink(),
|
||||||
'type' => 'Announce',
|
'type' => 'Announce',
|
||||||
'actor' => $status->profile->permalink(),
|
'actor' => $status->profile->permalink(),
|
||||||
'object' => $status->parent()->url()
|
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||||
|
'cc' => [
|
||||||
|
$status->profile->permalink(),
|
||||||
|
$status->profile->follower_url ?? $status->profile->permalink('/followers')
|
||||||
|
],
|
||||||
|
'published' => $status->created_at->format(DATE_ISO8601),
|
||||||
|
'object' => $status->parent()->url(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,6 +11,7 @@ class Like extends Fractal\TransformerAbstract
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||||
|
'id' => $like->actor->permalink('#likes/'.$like->id),
|
||||||
'type' => 'Like',
|
'type' => 'Like',
|
||||||
'actor' => $like->actor->permalink(),
|
'actor' => $like->actor->permalink(),
|
||||||
'object' => $like->status->url()
|
'object' => $like->status->url()
|
||||||
|
|
|
@ -34,7 +34,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
|
||||||
'muted' => null,
|
'muted' => null,
|
||||||
'sensitive' => (bool) $status->is_nsfw,
|
'sensitive' => (bool) $status->is_nsfw,
|
||||||
'spoiler_text' => $status->cw_summary,
|
'spoiler_text' => $status->cw_summary,
|
||||||
'visibility' => $status->visibility,
|
'visibility' => $status->visibility ?? $status->scope,
|
||||||
'application' => [
|
'application' => [
|
||||||
'name' => 'web',
|
'name' => 'web',
|
||||||
'website' => null
|
'website' => null
|
||||||
|
|
|
@ -206,7 +206,7 @@ class Helpers {
|
||||||
return self::fetchFromUrl($url);
|
return self::fetchFromUrl($url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function statusFirstOrFetch($url, $replyTo = true)
|
public static function statusFirstOrFetch($url, $replyTo = false)
|
||||||
{
|
{
|
||||||
$url = self::validateUrl($url);
|
$url = self::validateUrl($url);
|
||||||
if($url == false) {
|
if($url == false) {
|
||||||
|
@ -337,6 +337,11 @@ class Helpers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function statusFetch($url)
|
||||||
|
{
|
||||||
|
return self::statusFirstOrFetch($url);
|
||||||
|
}
|
||||||
|
|
||||||
public static function importNoteAttachment($data, Status $status)
|
public static function importNoteAttachment($data, Status $status)
|
||||||
{
|
{
|
||||||
if(self::verifyAttachments($data) == false) {
|
if(self::verifyAttachments($data) == false) {
|
||||||
|
@ -435,6 +440,11 @@ class Helpers {
|
||||||
return $profile;
|
return $profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function profileFetch($url)
|
||||||
|
{
|
||||||
|
return self::profileFirstOrNew($url);
|
||||||
|
}
|
||||||
|
|
||||||
public static function sendSignedObject($senderProfile, $url, $body)
|
public static function sendSignedObject($senderProfile, $url, $body)
|
||||||
{
|
{
|
||||||
abort_if(!self::validateUrl($url), 400);
|
abort_if(!self::validateUrl($url), 400);
|
||||||
|
|
|
@ -151,7 +151,7 @@ class Inbox
|
||||||
if(Status::whereUrl($url)->exists()) {
|
if(Status::whereUrl($url)->exists()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Helpers::statusFirstOrFetch($url, false);
|
Helpers::statusFetch($url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,21 +205,27 @@ class Inbox
|
||||||
{
|
{
|
||||||
$actor = $this->actorFirstOrCreate($this->payload['actor']);
|
$actor = $this->actorFirstOrCreate($this->payload['actor']);
|
||||||
$activity = $this->payload['object'];
|
$activity = $this->payload['object'];
|
||||||
|
|
||||||
if(!$actor || $actor->domain == null) {
|
if(!$actor || $actor->domain == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Helpers::validateLocalUrl($activity) == false) {
|
if(Helpers::validateLocalUrl($activity) == false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$parent = Helpers::statusFirstOrFetch($activity, true);
|
|
||||||
if(!$parent) {
|
$parent = Helpers::statusFetch($activity);
|
||||||
|
|
||||||
|
if(empty($parent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$status = Status::firstOrCreate([
|
$status = Status::firstOrCreate([
|
||||||
'profile_id' => $actor->id,
|
'profile_id' => $actor->id,
|
||||||
'reblog_of_id' => $parent->id,
|
'reblog_of_id' => $parent->id,
|
||||||
'type' => 'reply'
|
'type' => 'share'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Notification::firstOrCreate([
|
Notification::firstOrCreate([
|
||||||
'profile_id' => $parent->profile->id,
|
'profile_id' => $parent->profile->id,
|
||||||
'actor_id' => $actor->id,
|
'actor_id' => $actor->id,
|
||||||
|
@ -229,6 +235,7 @@ class Inbox
|
||||||
'item_id' => $parent->id,
|
'item_id' => $parent->id,
|
||||||
'item_type' => 'App\Status'
|
'item_type' => 'App\Status'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$parent->reblogs_count = $parent->shares()->count();
|
$parent->reblogs_count = $parent->shares()->count();
|
||||||
$parent->save();
|
$parent->save();
|
||||||
}
|
}
|
||||||
|
@ -316,6 +323,20 @@ class Inbox
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Announce':
|
case 'Announce':
|
||||||
|
abort_if(!Helpers::validateLocalUrl($obj), 400);
|
||||||
|
$status = Helpers::statusFetch($obj);
|
||||||
|
if(!$status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Status::whereProfileId($profile->id)
|
||||||
|
->whereReblogOfId($status->id)
|
||||||
|
->forceDelete();
|
||||||
|
Notification::whereProfileId($status->profile->id)
|
||||||
|
->whereActorId($profile->id)
|
||||||
|
->whereAction('share')
|
||||||
|
->whereItemId($status->reblog_of_id)
|
||||||
|
->whereItemType('App\Status')
|
||||||
|
->forceDelete();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Block':
|
case 'Block':
|
||||||
|
@ -347,6 +368,6 @@ class Inbox
|
||||||
->forceDelete();
|
->forceDelete();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
public/js/profile.js
vendored
2
public/js/profile.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/status.js
vendored
2
public/js/status.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/timeline.js
vendored
2
public/js/timeline.js
vendored
File diff suppressed because one or more lines are too long
|
@ -14,10 +14,10 @@
|
||||||
"/js/discover.js": "/js/discover.js?id=772fbc6c176aaa9039ec",
|
"/js/discover.js": "/js/discover.js?id=772fbc6c176aaa9039ec",
|
||||||
"/js/loops.js": "/js/loops.js?id=a2291e15b8b246621b07",
|
"/js/loops.js": "/js/loops.js?id=a2291e15b8b246621b07",
|
||||||
"/js/mode-dot.js": "/js/mode-dot.js?id=3c67c8f827dc52536a4b",
|
"/js/mode-dot.js": "/js/mode-dot.js?id=3c67c8f827dc52536a4b",
|
||||||
"/js/profile.js": "/js/profile.js?id=fe87d1e6d75323c9f7d9",
|
"/js/profile.js": "/js/profile.js?id=c45f4c00d9e3c9aac7c9",
|
||||||
"/js/quill.js": "/js/quill.js?id=d2e82cff48024d45384a",
|
"/js/quill.js": "/js/quill.js?id=d2e82cff48024d45384a",
|
||||||
"/js/search.js": "/js/search.js?id=38a3a6a07e3b37a1e444",
|
"/js/search.js": "/js/search.js?id=38a3a6a07e3b37a1e444",
|
||||||
"/js/status.js": "/js/status.js?id=8333e903aaf01fc6436d",
|
"/js/status.js": "/js/status.js?id=28de331daaf3447a3d3f",
|
||||||
"/js/theme-monokai.js": "/js/theme-monokai.js?id=1f7b44b76af99c0b4e38",
|
"/js/theme-monokai.js": "/js/theme-monokai.js?id=1f7b44b76af99c0b4e38",
|
||||||
"/js/timeline.js": "/js/timeline.js?id=3b2c69ca0262332e6542"
|
"/js/timeline.js": "/js/timeline.js?id=52af49a558f589d1b569"
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,14 +179,14 @@
|
||||||
<div class="reactions my-1">
|
<div class="reactions my-1">
|
||||||
<h3 v-bind:class="[reactions.liked ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus"></h3>
|
<h3 v-bind:class="[reactions.liked ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus"></h3>
|
||||||
<h3 v-if="!status.comments_disabled" class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="replyFocus(status)"></h3>
|
<h3 v-if="!status.comments_disabled" class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="replyFocus(status)"></h3>
|
||||||
<h3 v-bind:class="[reactions.shared ? 'far fa-share-square pr-3 m-0 text-primary cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn cursor-pointer']" title="Share" v-on:click="shareStatus"></h3>
|
<h3 v-if="status.visibility == 'public'" v-bind:class="[reactions.shared ? 'far fa-share-square pr-3 m-0 text-primary cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn cursor-pointer']" title="Share" v-on:click="shareStatus"></h3>
|
||||||
<h3 v-bind:class="[reactions.bookmarked ? 'fas fa-bookmark text-warning m-0 float-right cursor-pointer' : 'far fa-bookmark m-0 float-right cursor-pointer']" title="Bookmark" v-on:click="bookmarkStatus"></h3>
|
<h3 v-if="status.visibility == 'public'" v-bind:class="[reactions.bookmarked ? 'fas fa-bookmark text-warning m-0 float-right cursor-pointer' : 'far fa-bookmark m-0 float-right cursor-pointer']" title="Bookmark" v-on:click="bookmarkStatus"></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="reaction-counts font-weight-bold mb-0">
|
<div class="reaction-counts font-weight-bold mb-0">
|
||||||
<span style="cursor:pointer;" v-on:click="likesModal">
|
<span style="cursor:pointer;" v-on:click="likesModal">
|
||||||
<span class="like-count">{{status.favourites_count || 0}}</span> likes
|
<span class="like-count">{{status.favourites_count || 0}}</span> likes
|
||||||
</span>
|
</span>
|
||||||
<span class="float-right" style="cursor:pointer;" v-on:click="sharesModal">
|
<span v-if="status.visibility == 'public'" class="float-right" style="cursor:pointer;" v-on:click="sharesModal">
|
||||||
<span class="share-count pl-4">{{status.reblogs_count || 0}}</span> shares
|
<span class="share-count pl-4">{{status.reblogs_count || 0}}</span> shares
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -268,13 +268,13 @@
|
||||||
<div class="reactions py-2">
|
<div class="reactions py-2">
|
||||||
<h3 v-bind:class="[reactions.liked ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus"></h3>
|
<h3 v-bind:class="[reactions.liked ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus"></h3>
|
||||||
<h3 v-if="!status.comments_disabled" class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="replyFocus(status)"></h3>
|
<h3 v-if="!status.comments_disabled" class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="replyFocus(status)"></h3>
|
||||||
<h3 v-bind:class="[reactions.shared ? 'far fa-share-square pr-3 m-0 text-primary float-right cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn float-right cursor-pointer']" title="Share" v-on:click="shareStatus"></h3>
|
<h3 v-if="status.visibility == 'public'" v-bind:class="[reactions.shared ? 'far fa-share-square pr-3 m-0 text-primary float-right cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn float-right cursor-pointer']" title="Share" v-on:click="shareStatus"></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="reaction-counts font-weight-bold mb-0">
|
<div class="reaction-counts font-weight-bold mb-0">
|
||||||
<span style="cursor:pointer;" v-on:click="likesModal">
|
<span style="cursor:pointer;" v-on:click="likesModal">
|
||||||
<span class="like-count">{{status.favourites_count || 0}}</span> likes
|
<span class="like-count">{{status.favourites_count || 0}}</span> likes
|
||||||
</span>
|
</span>
|
||||||
<span class="float-right" style="cursor:pointer;" v-on:click="sharesModal">
|
<span v-if="status.visibility == 'public'" class="float-right" style="cursor:pointer;" v-on:click="sharesModal">
|
||||||
<span class="share-count pl-4">{{status.reblogs_count || 0}}</span> shares
|
<span class="share-count pl-4">{{status.reblogs_count || 0}}</span> shares
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -242,7 +242,7 @@
|
||||||
<div class="reactions my-1" v-if="user.hasOwnProperty('id')">
|
<div class="reactions my-1" v-if="user.hasOwnProperty('id')">
|
||||||
<h3 v-bind:class="[status.favourited ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus(status, $event)"></h3>
|
<h3 v-bind:class="[status.favourited ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus(status, $event)"></h3>
|
||||||
<h3 class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
|
<h3 class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
|
||||||
<h3 v-bind:class="[status.reblogged ? 'far fa-share-square pr-3 m-0 text-primary cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"></h3>
|
<h3 v-if="status.visibility == 'public'" v-bind:class="[status.reblogged ? 'far fa-share-square pr-3 m-0 text-primary cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"></h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="likes font-weight-bold">
|
<div class="likes font-weight-bold">
|
||||||
|
|
|
@ -117,7 +117,7 @@
|
||||||
<div v-if="!modes.distractionFree" class="reactions my-1">
|
<div v-if="!modes.distractionFree" class="reactions my-1">
|
||||||
<h3 v-bind:class="[status.favourited ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus(status, $event)"></h3>
|
<h3 v-bind:class="[status.favourited ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus(status, $event)"></h3>
|
||||||
<h3 v-if="!status.comments_disabled" class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
|
<h3 v-if="!status.comments_disabled" class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
|
||||||
<h3 v-bind:class="[status.reblogged ? 'far fa-share-square pr-3 m-0 text-primary cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"></h3>
|
<h3 v-if="status.visibility == 'public'" v-bind:class="[status.reblogged ? 'far fa-share-square pr-3 m-0 text-primary cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"></h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="likes font-weight-bold" v-if="expLc(status) == true && !modes.distractionFree">
|
<div class="likes font-weight-bold" v-if="expLc(status) == true && !modes.distractionFree">
|
||||||
|
|
Loading…
Add table
Reference in a new issue