Merge pull request #2744 from pixelfed/staging

Staging
pull/2751/head
daniel 4 years ago committed by GitHub
commit 2e2078a2fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -75,6 +75,7 @@
- Updated StoryController, fix cache crop bug. ([c2f8faae](https://github.com/pixelfed/pixelfed/commit/c2f8faae))
- Updated StoryController, optimize photo size by resizing to 9:16 aspect. ([e66ed9a2](https://github.com/pixelfed/pixelfed/commit/e66ed9a2))
- Updated StoryCompose crop logic. ([2ead622c](https://github.com/pixelfed/pixelfed/commit/2ead622c))
- Updated StatusController, allow license edits without 24 hour limit. ([c799a01a](https://github.com/pixelfed/pixelfed/commit/c799a01a))
- ([](https://github.com/pixelfed/pixelfed/commit/))
## [v0.10.10 (2021-01-28)](https://github.com/pixelfed/pixelfed/compare/v0.10.9...v0.10.10)

@ -21,422 +21,398 @@ use App\Util\Media\Filter;
use Illuminate\Support\Str;
use App\Services\HashidService;
use App\Services\StatusService;
use App\Util\Media\License;
class StatusController extends Controller
{
public function show(Request $request, $username, int $id)
{
$user = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
if($user->status != null) {
return ProfileController::accountCheck($user);
}
$status = Status::whereProfileId($user->id)
->whereNull('reblog_of_id')
->whereIn('scope', ['public','unlisted', 'private'])
->findOrFail($id);
if($status->uri || $status->url) {
$url = $status->uri ?? $status->url;
if(ends_with($url, '/activity')) {
$url = str_replace('/activity', '', $url);
}
return redirect($url);
}
if($status->visibility == 'private' || $user->is_private) {
if(!Auth::check()) {
abort(404);
}
$pid = Auth::user()->profile;
if($user->followedBy($pid) == false && $user->id !== $pid->id && Auth::user()->is_admin == false) {
abort(404);
}
}
if($status->type == 'archived') {
if(Auth::user()->profile_id !== $status->profile_id) {
abort(404);
}
}
if($request->user() && $request->user()->profile_id != $status->profile_id) {
StatusView::firstOrCreate([
'status_id' => $status->id,
'status_profile_id' => $status->profile_id,
'profile_id' => $request->user()->profile_id
]);
}
if ($request->wantsJson() && config('federation.activitypub.enabled')) {
return $this->showActivityPub($request, $status);
}
$template = $status->in_reply_to_id ? 'status.reply' : 'status.show';
// $template = $status->type === 'video' &&
// $request->has('video_beta') &&
// $request->video_beta == 1 &&
// $request->user() ?
// 'status.show_video' : 'status.show';
return view($template, compact('user', 'status'));
}
public function shortcodeRedirect(Request $request, $id)
{
abort_if(strlen($id) < 5, 404);
if(!Auth::check()) {
return redirect('/login?next='.urlencode('/' . $request->path()));
}
$id = HashidService::decode($id);
$status = Status::find($id);
if(!$status) {
return redirect('/404');
}
return redirect($status->url());
}
public function showId(int $id)
{
abort(404);
$status = Status::whereNull('reblog_of_id')
->whereIn('scope', ['public', 'unlisted'])
->findOrFail($id);
return redirect($status->url());
}
public function showEmbed(Request $request, $username, int $id)
{
$profile = Profile::whereNull(['domain','status'])
->whereIsPrivate(false)
->whereUsername($username)
->first();
if(!$profile) {
$content = view('status.embed-removed');
return response($content)->header('X-Frame-Options', 'ALLOWALL');
}
$status = Status::whereProfileId($profile->id)
->whereNull('uri')
->whereScope('public')
->whereIsNsfw(false)
->whereIn('type', ['photo', 'video','photo:album'])
->find($id);
if(!$status) {
$content = view('status.embed-removed');
return response($content)->header('X-Frame-Options', 'ALLOWALL');
}
$showLikes = $request->filled('likes') && $request->likes == true;
$showCaption = $request->filled('caption') && $request->caption !== false;
$layout = $request->filled('layout') && $request->layout == 'compact' ? 'compact' : 'full';
$content = view('status.embed', compact('status', 'showLikes', 'showCaption', 'layout'));
return response($content)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
}
public function showObject(Request $request, $username, int $id)
{
$user = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
if($user->status != null) {
return ProfileController::accountCheck($user);
}
$status = Status::whereProfileId($user->id)
->whereNotIn('visibility',['draft','direct'])
->findOrFail($id);
abort_if($status->uri, 404);
if($status->visibility == 'private' || $user->is_private) {
if(!Auth::check()) {
abort(403);
}
$pid = Auth::user()->profile;
if($user->followedBy($pid) == false && $user->id !== $pid->id) {
abort(403);
}
}
return $this->showActivityPub($request, $status);
}
public function compose()
{
$this->authCheck();
return view('status.compose');
}
public function store(Request $request)
{
return;
}
public function delete(Request $request)
{
$this->authCheck();
$this->validate($request, [
'item' => 'required|integer|min:1',
]);
$status = Status::findOrFail($request->input('item'));
$user = Auth::user();
if($status->profile_id != $user->profile->id &&
$user->is_admin == true &&
$status->uri == null
) {
$media = $status->media;
$ai = new AccountInterstitial;
$ai->user_id = $status->profile->user_id;
$ai->type = 'post.removed';
$ai->view = 'account.moderation.post.removed';
$ai->item_type = 'App\Status';
$ai->item_id = $status->id;
$ai->has_media = (bool) $media->count();
$ai->blurhash = $media->count() ? $media->first()->blurhash : null;
$ai->meta = json_encode([
'caption' => $status->caption,
'created_at' => $status->created_at,
'type' => $status->type,
'url' => $status->url(),
'is_nsfw' => $status->is_nsfw,
'scope' => $status->scope,
'reblog' => $status->reblog_of_id,
'likes_count' => $status->likes_count,
'reblogs_count' => $status->reblogs_count,
]);
$ai->save();
$u = $status->profile->user;
$u->has_interstitial = true;
$u->save();
}
Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
Cache::forget('profile:status_count:' . $status->profile_id);
Cache::forget('profile:embed:' . $status->profile_id);
StatusService::del($status->id);
if ($status->profile_id == $user->profile->id || $user->is_admin == true) {
Cache::forget('profile:status_count:'.$status->profile_id);
StatusDelete::dispatch($status);
}
if($request->wantsJson()) {
return response()->json(['Status successfully deleted.']);
} else {
return redirect($user->url());
}
}
public function storeShare(Request $request)
{
$this->authCheck();
$this->validate($request, [
'item' => 'required|integer|min:1',
]);
$user = Auth::user();
$profile = $user->profile;
$status = Status::withCount('shares')
->whereIn('scope', ['public', 'unlisted'])
->findOrFail($request->input('item'));
$count = $status->shares()->count();
$exists = Status::whereProfileId(Auth::user()->profile->id)
->whereReblogOfId($status->id)
->count();
if ($exists !== 0) {
$shares = Status::whereProfileId(Auth::user()->profile->id)
->whereReblogOfId($status->id)
->get();
foreach ($shares as $share) {
$share->delete();
$count--;
}
} else {
$share = new Status();
$share->profile_id = $profile->id;
$share->reblog_of_id = $status->id;
$share->in_reply_to_profile_id = $status->profile_id;
$share->save();
$count++;
SharePipeline::dispatch($share);
}
if($count >= 0) {
$status->reblogs_count = $count;
$status->save();
}
Cache::forget('status:'.$status->id.':sharedby:userid:'.$user->id);
StatusService::del($status->id);
if ($request->ajax()) {
$response = ['code' => 200, 'msg' => 'Share saved', 'count' => $count];
} else {
$response = redirect($status->url());
}
return $response;
}
public function showActivityPub(Request $request, $status)
{
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Item($status, new Note());
$res = $fractal->createData($resource)->toArray();
return response()->json($res['data'], 200, ['Content-Type' => 'application/activity+json'], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function edit(Request $request, $username, $id)
{
$this->authCheck();
$user = Auth::user()->profile;
$status = Status::whereProfileId($user->id)
->with(['media'])
->where('created_at', '>', now()->subHours(24))
->findOrFail($id);
return view('status.edit', compact('user', 'status'));
}
public function editStore(Request $request, $username, $id)
{
$this->authCheck();
$user = Auth::user()->profile;
$status = Status::whereProfileId($user->id)
->with(['media'])
->where('created_at', '>', now()->subHours(24))
->findOrFail($id);
$this->validate($request, [
'id' => 'required|integer|min:1',
'caption' => 'nullable',
'filter' => 'nullable|alpha_dash|max:30',
]);
$id = $request->input('id');
$caption = $request->input('caption');
$filter = $request->input('filter');
$media = Media::whereProfileId($user->id)
->whereStatusId($status->id)
->findOrFail($id);
$changed = false;
if ($media->caption != $caption) {
$media->caption = $caption;
$changed = true;
}
if ($media->filter_class != $filter && in_array($filter, Filter::classes())) {
$media->filter_class = $filter;
$changed = true;
}
if ($changed === true) {
$media->save();
Cache::forget('status:transformer:media:attachments:'.$media->status_id);
}
return response()->json([], 200);
}
protected function authCheck()
{
if (Auth::check() == false) {
abort(403);
}
}
protected function validateVisibility($visibility)
{
$allowed = ['public', 'unlisted', 'private'];
return in_array($visibility, $allowed) ? $visibility : 'public';
}
public static function mimeTypeCheck($mimes)
{
$allowed = explode(',', config('pixelfed.media_types'));
$count = count($mimes);
$photos = 0;
$videos = 0;
foreach($mimes as $mime) {
if(in_array($mime, $allowed) == false && $mime !== 'video/mp4') {
continue;
}
if(str_contains($mime, 'image/')) {
$photos++;
}
if(str_contains($mime, 'video/')) {
$videos++;
}
}
if($photos == 1 && $videos == 0) {
return 'photo';
}
if($videos == 1 && $photos == 0) {
return 'video';
}
if($photos > 1 && $videos == 0) {
return 'photo:album';
}
if($videos > 1 && $photos == 0) {
return 'video:album';
}
if($photos >= 1 && $videos >= 1) {
return 'photo:video:album';
}
}
public function toggleVisibility(Request $request) {
$this->authCheck();
$this->validate($request, [
'item' => 'required|string|min:1|max:20',
'disableComments' => 'required|boolean'
]);
$user = Auth::user();
$id = $request->input('item');
$state = $request->input('disableComments');
$status = Status::findOrFail($id);
if($status->profile_id != $user->profile->id && $user->is_admin == false) {
abort(403);
}
$status->comments_disabled = $status->comments_disabled == true ? false : true;
$status->save();
return response()->json([200]);
}
public function storeView(Request $request)
{
abort_if(!$request->user(), 403);
$this->validate($request, [
'status_id' => 'required|integer|exists:statuses,id',
'profile_id' => 'required|integer|exists:profiles,id'
]);
$sid = (int) $request->input('status_id');
$pid = (int) $request->input('profile_id');
StatusView::firstOrCreate([
'status_id' => $sid,
'status_profile_id' => $pid,
'profile_id' => $request->user()->profile_id
]);
return response()->json(1);
}
public function show(Request $request, $username, int $id)
{
$user = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
if($user->status != null) {
return ProfileController::accountCheck($user);
}
$status = Status::whereProfileId($user->id)
->whereNull('reblog_of_id')
->whereIn('scope', ['public','unlisted', 'private'])
->findOrFail($id);
if($status->uri || $status->url) {
$url = $status->uri ?? $status->url;
if(ends_with($url, '/activity')) {
$url = str_replace('/activity', '', $url);
}
return redirect($url);
}
if($status->visibility == 'private' || $user->is_private) {
if(!Auth::check()) {
abort(404);
}
$pid = Auth::user()->profile;
if($user->followedBy($pid) == false && $user->id !== $pid->id && Auth::user()->is_admin == false) {
abort(404);
}
}
if($status->type == 'archived') {
if(Auth::user()->profile_id !== $status->profile_id) {
abort(404);
}
}
if($request->user() && $request->user()->profile_id != $status->profile_id) {
StatusView::firstOrCreate([
'status_id' => $status->id,
'status_profile_id' => $status->profile_id,
'profile_id' => $request->user()->profile_id
]);
}
if ($request->wantsJson() && config('federation.activitypub.enabled')) {
return $this->showActivityPub($request, $status);
}
$template = $status->in_reply_to_id ? 'status.reply' : 'status.show';
return view($template, compact('user', 'status'));
}
public function shortcodeRedirect(Request $request, $id)
{
abort_if(strlen($id) < 5, 404);
if(!Auth::check()) {
return redirect('/login?next='.urlencode('/' . $request->path()));
}
$id = HashidService::decode($id);
$status = Status::find($id);
if(!$status) {
return redirect('/404');
}
return redirect($status->url());
}
public function showId(int $id)
{
abort(404);
$status = Status::whereNull('reblog_of_id')
->whereIn('scope', ['public', 'unlisted'])
->findOrFail($id);
return redirect($status->url());
}
public function showEmbed(Request $request, $username, int $id)
{
$profile = Profile::whereNull(['domain','status'])
->whereIsPrivate(false)
->whereUsername($username)
->first();
if(!$profile) {
$content = view('status.embed-removed');
return response($content)->header('X-Frame-Options', 'ALLOWALL');
}
$status = Status::whereProfileId($profile->id)
->whereNull('uri')
->whereScope('public')
->whereIsNsfw(false)
->whereIn('type', ['photo', 'video','photo:album'])
->find($id);
if(!$status) {
$content = view('status.embed-removed');
return response($content)->header('X-Frame-Options', 'ALLOWALL');
}
$showLikes = $request->filled('likes') && $request->likes == true;
$showCaption = $request->filled('caption') && $request->caption !== false;
$layout = $request->filled('layout') && $request->layout == 'compact' ? 'compact' : 'full';
$content = view('status.embed', compact('status', 'showLikes', 'showCaption', 'layout'));
return response($content)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
}
public function showObject(Request $request, $username, int $id)
{
$user = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
if($user->status != null) {
return ProfileController::accountCheck($user);
}
$status = Status::whereProfileId($user->id)
->whereNotIn('visibility',['draft','direct'])
->findOrFail($id);
abort_if($status->uri, 404);
if($status->visibility == 'private' || $user->is_private) {
if(!Auth::check()) {
abort(403);
}
$pid = Auth::user()->profile;
if($user->followedBy($pid) == false && $user->id !== $pid->id) {
abort(403);
}
}
return $this->showActivityPub($request, $status);
}
public function compose()
{
$this->authCheck();
return view('status.compose');
}
public function store(Request $request)
{
return;
}
public function delete(Request $request)
{
$this->authCheck();
$this->validate($request, [
'item' => 'required|integer|min:1',
]);
$status = Status::findOrFail($request->input('item'));
$user = Auth::user();
if($status->profile_id != $user->profile->id &&
$user->is_admin == true &&
$status->uri == null
) {
$media = $status->media;
$ai = new AccountInterstitial;
$ai->user_id = $status->profile->user_id;
$ai->type = 'post.removed';
$ai->view = 'account.moderation.post.removed';
$ai->item_type = 'App\Status';
$ai->item_id = $status->id;
$ai->has_media = (bool) $media->count();
$ai->blurhash = $media->count() ? $media->first()->blurhash : null;
$ai->meta = json_encode([
'caption' => $status->caption,
'created_at' => $status->created_at,
'type' => $status->type,
'url' => $status->url(),
'is_nsfw' => $status->is_nsfw,
'scope' => $status->scope,
'reblog' => $status->reblog_of_id,
'likes_count' => $status->likes_count,
'reblogs_count' => $status->reblogs_count,
]);
$ai->save();
$u = $status->profile->user;
$u->has_interstitial = true;
$u->save();
}
Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
Cache::forget('profile:status_count:' . $status->profile_id);
Cache::forget('profile:embed:' . $status->profile_id);
StatusService::del($status->id);
if ($status->profile_id == $user->profile->id || $user->is_admin == true) {
Cache::forget('profile:status_count:'.$status->profile_id);
StatusDelete::dispatch($status);
}
if($request->wantsJson()) {
return response()->json(['Status successfully deleted.']);
} else {
return redirect($user->url());
}
}
public function storeShare(Request $request)
{
$this->authCheck();
$this->validate($request, [
'item' => 'required|integer|min:1',
]);
$user = Auth::user();
$profile = $user->profile;
$status = Status::withCount('shares')
->whereIn('scope', ['public', 'unlisted'])
->findOrFail($request->input('item'));
$count = $status->shares()->count();
$exists = Status::whereProfileId(Auth::user()->profile->id)
->whereReblogOfId($status->id)
->count();
if ($exists !== 0) {
$shares = Status::whereProfileId(Auth::user()->profile->id)
->whereReblogOfId($status->id)
->get();
foreach ($shares as $share) {
$share->delete();
$count--;
}
} else {
$share = new Status();
$share->profile_id = $profile->id;
$share->reblog_of_id = $status->id;
$share->in_reply_to_profile_id = $status->profile_id;
$share->save();
$count++;
SharePipeline::dispatch($share);
}
if($count >= 0) {
$status->reblogs_count = $count;
$status->save();
}
Cache::forget('status:'.$status->id.':sharedby:userid:'.$user->id);
StatusService::del($status->id);
if ($request->ajax()) {
$response = ['code' => 200, 'msg' => 'Share saved', 'count' => $count];
} else {
$response = redirect($status->url());
}
return $response;
}
public function showActivityPub(Request $request, $status)
{
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Item($status, new Note());
$res = $fractal->createData($resource)->toArray();
return response()->json($res['data'], 200, ['Content-Type' => 'application/activity+json'], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function edit(Request $request, $username, $id)
{
$this->authCheck();
$user = Auth::user()->profile;
$status = Status::whereProfileId($user->id)
->with(['media'])
->findOrFail($id);
$licenses = License::get();
return view('status.edit', compact('user', 'status', 'licenses'));
}
public function editStore(Request $request, $username, $id)
{
$this->authCheck();
$user = Auth::user()->profile;
$status = Status::whereProfileId($user->id)
->with(['media'])
->findOrFail($id);
$this->validate($request, [
'license' => 'nullable|integer|min:1|max:16',
]);
$licenseId = $request->input('license');
$status->media->each(function($media) use($licenseId) {
$media->license = $licenseId;
$media->save();
Cache::forget('status:transformer:media:attachments:'.$media->status_id);
});
return redirect($status->url());
}
protected function authCheck()
{
if (Auth::check() == false) {
abort(403);
}
}
protected function validateVisibility($visibility)
{
$allowed = ['public', 'unlisted', 'private'];
return in_array($visibility, $allowed) ? $visibility : 'public';
}
public static function mimeTypeCheck($mimes)
{
$allowed = explode(',', config('pixelfed.media_types'));
$count = count($mimes);
$photos = 0;
$videos = 0;
foreach($mimes as $mime) {
if(in_array($mime, $allowed) == false && $mime !== 'video/mp4') {
continue;
}
if(str_contains($mime, 'image/')) {
$photos++;
}
if(str_contains($mime, 'video/')) {
$videos++;
}
}
if($photos == 1 && $videos == 0) {
return 'photo';
}
if($videos == 1 && $photos == 0) {
return 'video';
}
if($photos > 1 && $videos == 0) {
return 'photo:album';
}
if($videos > 1 && $photos == 0) {
return 'video:album';
}
if($photos >= 1 && $videos >= 1) {
return 'photo:video:album';
}
}
public function toggleVisibility(Request $request) {
$this->authCheck();
$this->validate($request, [
'item' => 'required|string|min:1|max:20',
'disableComments' => 'required|boolean'
]);
$user = Auth::user();
$id = $request->input('item');
$state = $request->input('disableComments');
$status = Status::findOrFail($id);
if($status->profile_id != $user->profile->id && $user->is_admin == false) {
abort(403);
}
$status->comments_disabled = $status->comments_disabled == true ? false : true;
$status->save();
return response()->json([200]);
}
public function storeView(Request $request)
{
abort_if(!$request->user(), 403);
$this->validate($request, [
'status_id' => 'required|integer|exists:statuses,id',
'profile_id' => 'required|integer|exists:profiles,id'
]);
$sid = (int) $request->input('status_id');
$pid = (int) $request->input('profile_id');
StatusView::firstOrCreate([
'status_id' => $sid,
'status_profile_id' => $pid,
'profile_id' => $request->user()->profile_id
]);
return response()->json(1);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -15,12 +15,12 @@
"/js/compose-classic.js": "/js/compose-classic.js?id=ee4ad4759a55261c429c",
"/js/developers.js": "/js/developers.js?id=f8efa9cb9101d403d6c2",
"/js/direct.js": "/js/direct.js?id=3f9e2504bf670d3d7961",
"/js/discover.js": "/js/discover.js?id=b954935be21c33a6bafa",
"/js/hashtag.js": "/js/hashtag.js?id=656b11ab6b4d1dd489ae",
"/js/discover.js": "/js/discover.js?id=22389e6a69fe8bdf3701",
"/js/hashtag.js": "/js/hashtag.js?id=f2f0ba62a694ed192f32",
"/js/loops.js": "/js/loops.js?id=4ae79e81965c4fd1ae66",
"/js/mode-dot.js": "/js/mode-dot.js?id=d54ad862baf30ee756f8",
"/js/network-timeline.js": "/js/network-timeline.js?id=c153107849c4485772d0",
"/js/profile.js": "/js/profile.js?id=4ebaa85964697a2fac1a",
"/js/profile.js": "/js/profile.js?id=252340ccd8ecc9c35e15",
"/js/profile-directory.js": "/js/profile-directory.js?id=886f17ad7ab4b2e08019",
"/js/quill.js": "/js/quill.js?id=866b31b9b9540305751d",
"/js/rempos.js": "/js/rempos.js?id=26c37eace801046187bf",

@ -54,10 +54,6 @@
<span v-if="s.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
<div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold">
<span>
<span class="far fa-heart fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{formatCount(s.favourites_count)}}</span>
</span>
<span>
<span class="far fa-comment fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{formatCount(s.reply_count)}}</span>
@ -119,10 +115,6 @@
<span v-if="s.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
<div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold">
<span>
<span class="far fa-heart fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{formatCount(s.favourites_count)}}</span>
</span>
<span>
<span class="far fa-comment fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{formatCount(s.reply_count)}}</span>

@ -48,9 +48,6 @@
<div v-else class="square-content" :style="'background-image: url('+tag.status.media_attachments[0].preview_url+')'"></div>
<div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold">
<span class="pr-4">
<span class="far fa-heart fa-lg pr-1"></span> {{tag.status.like_count}}
</span>
<span>
<span class="fas fa-retweet fa-lg pr-1"></span> {{tag.status.share_count}}
</span>
@ -92,9 +89,6 @@
<span v-if="tag.status.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
<div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold">
<span class="pr-4">
<span class="far fa-heart fa-lg pr-1"></span> {{tag.status.favourites_count}}
</span>
<span>
<span class="far fa-comment fa-lg pr-1"></span> {{tag.status.reply_count}}
</span>

@ -212,10 +212,6 @@
<span v-if="s.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
<div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold">
<span>
<span class="far fa-heart fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{formatCount(s.favourites_count)}}</span>
</span>
<span>
<span class="far fa-comment fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{formatCount(s.reply_count)}}</span>
@ -260,10 +256,6 @@
</div>
<div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold">
<span>
<span class="far fa-heart fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{s.favourites_count}}</span>
</span>
<span>
<span class="fas fa-retweet fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{s.reblogs_count}}</span>

@ -5,99 +5,27 @@
<div class="container">
<div class="col-12 col-md-8 offset-md-2 pt-4">
<div class="card">
<div class="card shadow-none border">
<div class="card-header bg-white font-weight-bold d-flex justify-content-between align-items-center">
<span>Edit Status</span>
<a class="btn btn-outline-primary btn-sm font-weight-bold" href="{{$status->url()}}">Back to post</a>
</div>
<div class="card-body">
@csrf
<div class="form-group mb-0">
<label class="font-weight-bold text-muted small">CW/NSFW</label>
<div class="switch switch-sm">
<input type="checkbox" class="switch" id="cw-switch" name="cw" {{$status->is_nsfw==true?'checked=""':''}} disabled="">
<label for="cw-switch" class="small font-weight-bold">(Default off)</label>
<form method="post">
@csrf
<div class="form-group">
<label class="font-weight-bold text-muted small">License</label>
<select class="form-control" name="license">
@foreach($licenses as $license)
<option value="{{$license['id']}}" {{$status->firstMedia()->license == $license['id'] ? 'selected' : ''}}>{{$license['title']}}</option>
@endforeach
</select>
</div>
</div>
<hr>
<button class="btn btn-primary btn-block font-weight-bold">Save</button>
</form>
</div>
</div>
<div class="accordion" id="accordionWrapper">
@foreach($status->media()->orderBy('order')->get() as $media)
<div class="card mt-4 media-card">
<div class="card-header bg-white font-weight-bold" data-toggle="collapse" href="#collapseMedia{{$loop->iteration}}">
Media #{{$media->order + 1}}
<span class="float-right">
<span class="badge badge-primary">
{{$media->mime}}
</span>
</span>
</div>
<div class="collapse {{$loop->iteration==1?'show':''}}" id="collapseMedia{{$loop->iteration}}" data-parent="#accordionWrapper">
<div class="card-body p-0">
<form method="post" enctype="multipart/form-data" class="media-form">
@csrf
<input type="hidden" name="media_id" value="{{$media->id}}">
<div class="filter-wrapper {{$media->filter_class}}" data-filter="{{$media->filter_class}}">
<img class="img-fluid" src="{{$media->url()}}" width="100%">
</div>
<div class="p-3">
<div class="form-group">
<label class="font-weight-bold text-muted small">Description</label>
<input class="form-control" name="media_caption" value="{{$media->caption}}" placeholder="Add a descriptive caption for screenreaders" autocomplete="off">
</div>
@if($media->activityVerb() == 'Image')
<div class="form-group form-filters" data-filter="{{$media->filter_class}}">
<label for="filterSelectDropdown" class="font-weight-bold text-muted small">Select Filter</label>
<select class="form-control filter-dropdown" name="media_filter"><option value="" selected="">No Filter</option><option value="filter-1977">1977</option><option value="filter-aden">Aden</option><option value="filter-amaro">Amaro</option><option value="filter-ashby">Ashby</option><option value="filter-brannan">Brannan</option><option value="filter-brooklyn">Brooklyn</option><option value="filter-charmes">Charmes</option><option value="filter-clarendon">Clarendon</option><option value="filter-crema">Crema</option><option value="filter-dogpatch">Dogpatch</option><option value="filter-earlybird">Earlybird</option><option value="filter-gingham">Gingham</option><option value="filter-ginza">Ginza</option><option value="filter-hefe">Hefe</option><option value="filter-helena">Helena</option><option value="filter-hudson">Hudson</option><option value="filter-inkwell">Inkwell</option><option value="filter-kelvin">Kelvin</option><option value="filter-juno">Kuno</option><option value="filter-lark">Lark</option><option value="filter-lofi">Lo-Fi</option><option value="filter-ludwig">Ludwig</option><option value="filter-maven">Maven</option><option value="filter-mayfair">Mayfair</option><option value="filter-moon">Moon</option><option value="filter-nashville">Nashville</option><option value="filter-perpetua">Perpetua</option><option value="filter-poprocket">Poprocket</option><option value="filter-reyes">Reyes</option><option value="filter-rise">Rise</option><option value="filter-sierra">Sierra</option><option value="filter-skyline">Skyline</option><option value="filter-slumber">Slumber</option><option value="filter-stinson">Stinson</option><option value="filter-sutro">Sutro</option><option value="filter-toaster">Toaster</option><option value="filter-valencia">Valencia</option><option value="filter-vesper">Vesper</option><option value="filter-walden">Walden</option><option value="filter-willow">Willow</option><option value="filter-xpro-ii">X-Pro II</option></select>
</div>
@endif
<hr>
<div class="form-group d-flex justify-content-between align-items-center mb-0">
<p class="text-muted font-weight-bold mb-0 small">Last Updated: {{$media->updated_at->diffForHumans()}}</p>
<button type="submit" class="btn btn-primary btn-sm font-weight-bold px-4">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
@endsection
@push('scripts')
<script type="text/javascript">
$(document).ready(function() {
App.boot();
$('.form-filters').each(function(i,d) {
let el = $(d);
let filter = el.data('filter');
if(filter) {
var opt = el.find('option[value='+filter+']')[0];
$(opt).attr('selected','');
}
});
$('.media-form').on('submit', function(e){
e.preventDefault();
let el = $(this);
let id = el.find('input[name=media_id]').val();
let caption = el.find('input[name=media_caption]').val();
let filter = el.find('.filter-dropdown option:selected').val();
axios.post(window.location.href, {
'id': id,
'caption': caption,
'filter': filter
}).then((res) => {
window.location.href = '{{$status->url()}}';
}).catch((err) => {
swal('Something went wrong', 'An error occurred, please try again later', 'error');
});
});
});
</script>
@endpush

@ -190,7 +190,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('loops', 'DiscoverController@loopsApi');
Route::post('loops/watch', 'DiscoverController@loopWatch');
Route::get('discover/tag', 'DiscoverController@getHashtags');
Route::post('status/compose', 'InternalApiController@composePost')->middleware('throttle:maxPostsPerHour,60')->middleware('throttle:maxPostsPerDay,1440');
Route::post('status/compose', 'InternalApiController@composePost');
Route::get('discover/posts/trending', 'DiscoverController@trendingApi');
Route::get('discover/posts/hashtags', 'DiscoverController@trendingHashtags');
Route::get('discover/posts/places', 'DiscoverController@trendingPlaces');
@ -202,7 +202,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::group(['prefix' => 'local'], function () {
// Route::post('status/compose', 'InternalApiController@composePost')->middleware('throttle:maxPostsPerHour,60')->middleware('throttle:maxPostsPerDay,1440');
Route::get('exp/rec', 'ApiController@userRecommendations');
Route::post('discover/tag/subscribe', 'HashtagFollowController@store')->middleware('throttle:maxHashtagFollowsPerHour,60')->middleware('throttle:maxHashtagFollowsPerDay,1440');
Route::post('discover/tag/subscribe', 'HashtagFollowController@store');
Route::get('discover/tag/list', 'HashtagFollowController@getTags');
// Route::get('profile/sponsor/{id}', 'ProfileSponsorController@get');
Route::get('bookmarks', 'InternalApiController@bookmarks');
@ -211,8 +211,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::delete('collection/item', 'CollectionController@deleteId');
Route::get('collection/{id}', 'CollectionController@get');
Route::post('collection/{id}', 'CollectionController@store');
Route::delete('collection/{id}', 'CollectionController@delete')->middleware('throttle:maxCollectionsPerHour,60')->middleware('throttle:maxCollectionsPerDay,1440')->middleware('throttle:maxCollectionsPerMonth,43800');
Route::post('collection/{id}/publish', 'CollectionController@publish')->middleware('throttle:maxCollectionsPerHour,60')->middleware('throttle:maxCollectionsPerDay,1440')->middleware('throttle:maxCollectionsPerMonth,43800');
Route::delete('collection/{id}', 'CollectionController@delete');
Route::post('collection/{id}/publish', 'CollectionController@publish');
Route::get('profile/collections/{id}', 'CollectionController@getUserCollections');
Route::get('compose/location/search', 'ApiController@composeLocationSearch');
@ -223,11 +223,11 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
});
Route::group(['prefix' => 'stories'], function () {
Route::get('v0/recent', 'StoryController@apiV1Recent');
Route::post('v0/add', 'StoryController@apiV1Add')->middleware('throttle:maxStoriesPerDay,1440');
Route::post('v0/add', 'StoryController@apiV1Add');
Route::get('v0/fetch/{id}', 'StoryController@apiV1Fetch');
Route::get('v0/profile/{id}', 'StoryController@apiV1Profile');
Route::get('v0/exists/{id}', 'StoryController@apiV1Exists');
Route::delete('v0/delete/{id}', 'StoryController@apiV1Delete')->middleware('throttle:maxStoryDeletePerDay,1440');
Route::delete('v0/delete/{id}', 'StoryController@apiV1Delete');
Route::get('v0/me', 'StoryController@apiV1Me');
Route::get('v0/item/{id}', 'StoryController@apiV1Item');
Route::post('v0/crop', 'StoryController@cropPhoto');
@ -244,14 +244,14 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::group(['prefix' => 'i'], function () {
Route::redirect('/', '/');
Route::get('compose', 'StatusController@compose')->name('compose');
Route::post('comment', 'CommentController@store')->middleware('throttle:maxCommentsPerDay,1440');
Route::post('comment', 'CommentController@store');
Route::post('delete', 'StatusController@delete');
Route::post('mute', 'AccountController@mute');
Route::post('unmute', 'AccountController@unmute');
Route::post('block', 'AccountController@block');
Route::post('unblock', 'AccountController@unblock');
Route::post('like', 'LikeController@store')->middleware('throttle:maxLikesPerDay,1440');
Route::post('share', 'StatusController@storeShare')->middleware('throttle:maxSharesPerHour,60')->middleware('throttle:maxSharesPerDay,1440');
Route::post('like', 'LikeController@store');
Route::post('share', 'StatusController@storeShare');
Route::post('follow', 'FollowerController@store');
Route::post('bookmark', 'BookmarkController@store');
Route::get('lang/{locale}', 'SiteController@changeLocale');
@ -347,7 +347,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('privacy/blocked-users', 'SettingsController@blockedUsers')->name('settings.privacy.blocked-users');
Route::post('privacy/blocked-users', 'SettingsController@blockedUsersUpdate');
Route::get('privacy/blocked-instances', 'SettingsController@blockedInstances')->name('settings.privacy.blocked-instances');
Route::post('privacy/blocked-instances', 'SettingsController@blockedInstanceStore')->middleware('throttle:maxInstanceBansPerDay,1440');
Route::post('privacy/blocked-instances', 'SettingsController@blockedInstanceStore');
Route::post('privacy/blocked-instances/unblock', 'SettingsController@blockedInstanceUnblock')->name('settings.privacy.blocked-instances.unblock');
Route::get('privacy/blocked-keywords', 'SettingsController@blockedKeywords')->name('settings.privacy.blocked-keywords');
Route::post('privacy/account', 'SettingsController@privateAccountOptions')->name('settings.privacy.account');
@ -489,7 +489,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('p/{username}/{id}/c', 'CommentController@showAll');
Route::get('p/{username}/{id}/embed', 'StatusController@showEmbed');
Route::get('p/{username}/{id}/edit', 'StatusController@edit');
Route::post('p/{username}/{id}/edit', 'StatusController@editStore')->middleware('throttle:maxPostEditsPerHour,60')->middleware('throttle:maxPostEditsPerDay,1440');
Route::post('p/{username}/{id}/edit', 'StatusController@editStore');
Route::get('p/{username}/{id}.json', 'StatusController@showObject');
Route::get('p/{username}/{id}', 'StatusController@show');
Route::get('{username}/embed', 'ProfileController@embed');

Loading…
Cancel
Save