Merge pull request #4363 from pixelfed/staging

Staging
pull/4394/head
daniel 3 years ago committed by GitHub
commit 03e7e24b6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,6 +2,12 @@
## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.6...dev) ## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.6...dev)
### API Changes
- Added [/api/v1/followed_tags](https://docs.joinmastodon.org/methods/followed_tags/) api endpoint ([175a8486](https://github.com/pixelfed/pixelfed/commit/175a8486))
- Added [/api/v1/tags/:id/follow](https://docs.joinmastodon.org/methods/tags/#follow) and [/api/v1/tags/:id/unfollow](https://docs.joinmastodon.org/methods/tags/#unfollow) api endpoints ([4d997bb9](https://github.com/pixelfed/pixelfed/commit/4d997bb9))
- Added [/api/v1/tags/:id](https://docs.joinmastodon.org/methods/tags/) api endpoint ([521b3b4c](https://github.com/pixelfed/pixelfed/commit/521b3b4c))
- Added `only_media` support to /api/v1/timelines/tag/:id api endpoint ([b5fe956a](https://github.com/pixelfed/pixelfed/commit/b5fe956a))
### Added ### Added
- Added store remote media on S3 config setting, disabled by default ([51768083](https://github.com/pixelfed/pixelfed/commit/51768083)) - Added store remote media on S3 config setting, disabled by default ([51768083](https://github.com/pixelfed/pixelfed/commit/51768083))
@ -14,6 +20,14 @@
- Update instance config, enable config cache by default ([970f77b0](https://github.com/pixelfed/pixelfed/commit/970f77b0)) - Update instance config, enable config cache by default ([970f77b0](https://github.com/pixelfed/pixelfed/commit/970f77b0))
- Update Admin Dashboard, allow admins to designate an admin account for the landing page and instance api endpoint ([6ea2bdc7](https://github.com/pixelfed/pixelfed/commit/6ea2bdc7)) - Update Admin Dashboard, allow admins to designate an admin account for the landing page and instance api endpoint ([6ea2bdc7](https://github.com/pixelfed/pixelfed/commit/6ea2bdc7))
- Update config, enable oauth by default ([6a2e9e8f](https://github.com/pixelfed/pixelfed/commit/6a2e9e8f)) - Update config, enable oauth by default ([6a2e9e8f](https://github.com/pixelfed/pixelfed/commit/6a2e9e8f))
- Update StatusService, fix missing account condition ([f48daab3](https://github.com/pixelfed/pixelfed/commit/f48daab3))
- Update ProfileService, add softFail param ([6bc20a37](https://github.com/pixelfed/pixelfed/commit/6bc20a37))
- Update MediaTagService, fix ProfileService to soft fail on missing or deleted accounts ([df444851](https://github.com/pixelfed/pixelfed/commit/df444851))
- Update LikeService, improve likedBy logic to soft fail on missing or deleted accounts ([91ba1398](https://github.com/pixelfed/pixelfed/commit/91ba1398))
- Update StatusTransformers, fix ProfileService to soft fail on missing or deleted accounts ([43d3aa2b](https://github.com/pixelfed/pixelfed/commit/43d3aa2b))
- Update ApiV1Controller, fix hashtag timeline ([fc1a385c](https://github.com/pixelfed/pixelfed/commit/fc1a385c))
- Update settings view, add fallback avatar ([1a83c585](https://github.com/pixelfed/pixelfed/commit/1a83c585))
- Update HashtagFollow model, add MAX_LIMIT of 250 tags per account ([ed352141](https://github.com/pixelfed/pixelfed/commit/ed352141))
- ([](https://github.com/pixelfed/pixelfed/commit/)) - ([](https://github.com/pixelfed/pixelfed/commit/))
## [v0.11.6 (2023-05-03)](https://github.com/pixelfed/pixelfed/compare/v0.11.5...v0.11.6) ## [v0.11.6 (2023-05-03)](https://github.com/pixelfed/pixelfed/compare/v0.11.5...v0.11.6)

@ -12,6 +12,8 @@ class HashtagFollow extends Model
'hashtag_id' 'hashtag_id'
]; ];
const MAX_LIMIT = 250;
public function hashtag() public function hashtag()
{ {
return $this->belongsTo(Hashtag::class); return $this->belongsTo(Hashtag::class);

@ -19,6 +19,7 @@ use App\{
Follower, Follower,
FollowRequest, FollowRequest,
Hashtag, Hashtag,
HashtagFollow,
Instance, Instance,
Like, Like,
Media, Media,
@ -69,6 +70,7 @@ use App\Services\{
BouncerService, BouncerService,
CollectionService, CollectionService,
FollowerService, FollowerService,
HashtagService,
InstanceService, InstanceService,
LikeService, LikeService,
NetworkTimelineService, NetworkTimelineService,
@ -99,6 +101,7 @@ use App\Jobs\FollowPipeline\FollowRejectPipeline;
use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\RateLimiter;
use Purify; use Purify;
use Carbon\Carbon; use Carbon\Carbon;
use App\Http\Resources\MastoApi\FollowedTagResource;
class ApiV1Controller extends Controller class ApiV1Controller extends Controller
{ {
@ -3245,7 +3248,9 @@ class ApiV1Controller extends Controller
'page' => 'nullable|integer|max:40', 'page' => 'nullable|integer|max:40',
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX, 'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX, 'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
'limit' => 'nullable|integer|max:100' 'limit' => 'nullable|integer|max:100',
'only_media' => 'sometimes|boolean',
'_pe' => 'sometimes'
]); ]);
if(config('database.default') === 'pgsql') { if(config('database.default') === 'pgsql') {
@ -3269,6 +3274,18 @@ class ApiV1Controller extends Controller
$min = $request->input('min_id'); $min = $request->input('min_id');
$max = $request->input('max_id'); $max = $request->input('max_id');
$limit = $request->input('limit', 20); $limit = $request->input('limit', 20);
$onlyMedia = $request->input('only_media', true);
$pe = $request->has(self::PF_API_ENTITY_KEY);
if($min || $max) {
$minMax = SnowflakeService::byDate(now()->subMonths(6));
if($min && intval($min) < $minMax) {
return [];
}
if($max && intval($max) < $minMax) {
return [];
}
}
if(!$min && !$max) { if(!$min && !$max) {
$id = 1; $id = 1;
@ -3281,15 +3298,19 @@ class ApiV1Controller extends Controller
$res = StatusHashtag::whereHashtagId($tag->id) $res = StatusHashtag::whereHashtagId($tag->id)
->whereStatusVisibility('public') ->whereStatusVisibility('public')
->where('status_id', $dir, $id) ->where('status_id', $dir, $id)
->latest() ->orderBy('status_id', 'desc')
->limit($limit) ->limit($limit)
->pluck('status_id') ->pluck('status_id')
->map(function ($i) { ->map(function ($i) use($pe) {
if($i) { return $pe ? StatusService::get($i) : StatusService::getMastodon($i);
return StatusService::getMastodon($i);
}
}) })
->filter(function($i) { ->filter(function($i) use($onlyMedia) {
if(!$i) {
return false;
}
if($onlyMedia && !isset($i['media_attachments']) || !count($i['media_attachments'])) {
return false;
}
return $i && isset($i['account']); return $i && isset($i['account']);
}) })
->values() ->values()
@ -3636,7 +3657,7 @@ class ApiV1Controller extends Controller
return $this->json(StatusService::getState($status->id, $pid)); return $this->json(StatusService::getState($status->id, $pid));
} }
/** /**
* GET /api/v1.1/discover/accounts/popular * GET /api/v1.1/discover/accounts/popular
* *
* *
@ -3794,4 +3815,181 @@ class ApiV1Controller extends Controller
return $this->json([]); return $this->json([]);
} }
/**
* GET /api/v1/followed_tags
*
*
* @return array
*/
public function getFollowedTags(Request $request)
{
abort_if(!$request->user(), 403);
if(config('pixelfed.bouncer.cloud_ips.ban_api')) {
abort_if(BouncerService::checkIp($request->ip()), 404);
}
$account = AccountService::get($request->user()->profile_id);
$this->validate($request, [
'cursor' => 'sometimes',
'limit' => 'sometimes|integer|min:1|max:200'
]);
$limit = $request->input('limit', 100);
$res = HashtagFollow::whereProfileId($account['id'])
->orderByDesc('id')
->cursorPaginate($limit)->withQueryString();
$pagination = false;
$prevPage = $res->nextPageUrl();
$nextPage = $res->previousPageUrl();
if($nextPage && $prevPage) {
$pagination = '<' . $nextPage . '>; rel="next", <' . $prevPage . '>; rel="prev"';
} else if($nextPage && !$prevPage) {
$pagination = '<' . $nextPage . '>; rel="next"';
} else if(!$nextPage && $prevPage) {
$pagination = '<' . $prevPage . '>; rel="prev"';
}
if($pagination) {
return response()->json(FollowedTagResource::collection($res)->collection)
->header('Link', $pagination);
}
return response()->json(FollowedTagResource::collection($res)->collection);
}
/**
* POST /api/v1/tags/:id/follow
*
*
* @return object
*/
public function followHashtag(Request $request, $id)
{
abort_if(!$request->user(), 403);
if(config('pixelfed.bouncer.cloud_ips.ban_api')) {
abort_if(BouncerService::checkIp($request->ip()), 404);
}
$pid = $request->user()->profile_id;
$account = AccountService::get($pid);
$operator = config('database.default') == 'pgsql' ? 'ilike' : 'like';
$tag = Hashtag::where('name', $operator, $id)
->orWhere('slug', $operator, $id)
->first();
abort_if(!$tag, 422, 'Unknown hashtag');
abort_if(
HashtagFollow::whereProfileId($pid)->count() >= HashtagFollow::MAX_LIMIT,
422,
'You cannot follow more than ' . HashtagFollow::MAX_LIMIT . ' hashtags.'
);
$follows = HashtagFollow::updateOrCreate(
[
'profile_id' => $account['id'],
'hashtag_id' => $tag->id
],
[
'user_id' => $request->user()->id
]
);
HashtagService::follow($pid, $tag->id);
return response()->json(FollowedTagResource::make($follows)->toArray($request));
}
/**
* POST /api/v1/tags/:id/unfollow
*
*
* @return object
*/
public function unfollowHashtag(Request $request, $id)
{
abort_if(!$request->user(), 403);
if(config('pixelfed.bouncer.cloud_ips.ban_api')) {
abort_if(BouncerService::checkIp($request->ip()), 404);
}
$pid = $request->user()->profile_id;
$account = AccountService::get($pid);
$operator = config('database.default') == 'pgsql' ? 'ilike' : 'like';
$tag = Hashtag::where('name', $operator, $id)
->orWhere('slug', $operator, $id)
->first();
abort_if(!$tag, 422, 'Unknown hashtag');
$follows = HashtagFollow::whereProfileId($pid)
->whereHashtagId($tag->id)
->first();
if(!$follows) {
return [
'name' => $tag->name,
'url' => config('app.url') . '/i/web/hashtag/' . $tag->slug,
'history' => [],
'following' => false
];
}
if($follows) {
HashtagService::unfollow($pid, $tag->id);
$follows->delete();
}
$res = FollowedTagResource::make($follows)->toArray($request);
$res['following'] = false;
return response()->json($res);
}
/**
* GET /api/v1/tags/:id
*
*
* @return object
*/
public function getHashtag(Request $request, $id)
{
abort_if(!$request->user(), 403);
if(config('pixelfed.bouncer.cloud_ips.ban_api')) {
abort_if(BouncerService::checkIp($request->ip()), 404);
}
$pid = $request->user()->profile_id;
$account = AccountService::get($pid);
$operator = config('database.default') == 'pgsql' ? 'ilike' : 'like';
$tag = Hashtag::where('name', $operator, $id)
->orWhere('slug', $operator, $id)
->first();
if(!$tag) {
return [
'name' => $id,
'url' => config('app.url') . '/i/web/hashtag/' . $id,
'history' => [],
'following' => false
];
}
$res = [
'name' => $tag->name,
'url' => config('app.url') . '/i/web/hashtag/' . $tag->slug,
'history' => [],
'following' => HashtagService::isFollowing($pid, $tag->id)
];
if($request->has(self::PF_API_ENTITY_KEY)) {
$res['count'] = HashtagService::count($tag->id);
}
return $this->json($res);
}
} }

@ -0,0 +1,33 @@
<?php
namespace App\Http\Resources\MastoApi;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\JsonResponse;
use Cache;
use App\Services\HashtagService;
class FollowedTagResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
$tag = HashtagService::get($this->hashtag_id);
if(!$tag || !isset($tag['name'])) {
return [];
}
return [
'name' => $tag['name'],
'url' => config('app.url') . '/i/web/hashtag/' . $tag['slug'],
'history' => [],
'following' => true,
];
}
}

@ -28,8 +28,8 @@ class HashtagService {
public static function count($id) public static function count($id)
{ {
return Cache::remember('services:hashtag:count:by_id:' . $id, 3600, function() use($id) { return Cache::remember('services:hashtag:public-count:by_id:' . $id, 86400, function() use($id) {
return StatusHashtag::whereHashtagId($id)->count(); return StatusHashtag::whereHashtagId($id)->whereStatusVisibility('public')->count();
}); });
} }
@ -64,4 +64,9 @@ class HashtagService {
{ {
return Redis::zrem(self::FOLLOW_KEY . $pid, $hid); return Redis::zrem(self::FOLLOW_KEY . $pid, $hid);
} }
public static function following($pid, $start = 0, $limit = 10)
{
return Redis::zrevrange(self::FOLLOW_KEY . $pid, $start, $limit);
}
} }

@ -85,7 +85,10 @@ class LikeService {
return $empty; return $empty;
} }
$id = $like->profile_id; $id = $like->profile_id;
$profile = ProfileService::get($id); $profile = ProfileService::get($id, true);
if(!$profile) {
return [];
}
$profileUrl = "/i/web/profile/{$profile['id']}"; $profileUrl = "/i/web/profile/{$profile['id']}";
$res = [ $res = [
'id' => (string) $profile['id'], 'id' => (string) $profile['id'],

@ -57,7 +57,7 @@ class MediaTagService
protected function idToUsername($id) protected function idToUsername($id)
{ {
$profile = ProfileService::get($id); $profile = ProfileService::get($id, true);
if(!$profile) { if(!$profile) {
return 'unavailable'; return 'unavailable';

@ -4,9 +4,9 @@ namespace App\Services;
class ProfileService class ProfileService
{ {
public static function get($id) public static function get($id, $softFail = false)
{ {
return AccountService::get($id); return AccountService::get($id, $softFail);
} }
public static function del($id) public static function del($id)

@ -47,6 +47,10 @@ class StatusService
return null; return null;
} }
if(!isset($status['account'])) {
return null;
}
$status['replies_count'] = $status['reply_count']; $status['replies_count'] = $status['reply_count'];
if(config('exp.emc') == false) { if(config('exp.emc') == false) {

@ -42,7 +42,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
'card' => null, 'card' => null,
'poll' => null, 'poll' => null,
'media_attachments' => MediaService::get($status->id), 'media_attachments' => MediaService::get($status->id),
'account' => ProfileService::get($status->profile_id), 'account' => ProfileService::get($status->profile_id, true),
'tags' => StatusHashtagService::statusTags($status->id), 'tags' => StatusHashtagService::statusTags($status->id),
]; ];
} }

@ -66,7 +66,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
'label' => StatusLabelService::get($status), 'label' => StatusLabelService::get($status),
'liked_by' => LikeService::likedBy($status), 'liked_by' => LikeService::likedBy($status),
'media_attachments' => MediaService::get($status->id), 'media_attachments' => MediaService::get($status->id),
'account' => ProfileService::get($status->profile_id), 'account' => ProfileService::get($status->profile_id, true),
'tags' => StatusHashtagService::statusTags($status->id), 'tags' => StatusHashtagService::statusTags($status->id),
'poll' => $poll, 'poll' => $poll,
'bookmarked' => BookmarkService::get($pid, $status->id), 'bookmarked' => BookmarkService::get($pid, $status->id),

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

@ -1 +1 @@
(()=>{"use strict";var e,r,a,t={},n={};function o(e){var r=n[e];if(void 0!==r)return r.exports;var a=n[e]={id:e,loaded:!1,exports:{}};return t[e].call(a.exports,a,a.exports,o),a.loaded=!0,a.exports}o.m=t,e=[],o.O=(r,a,t,n)=>{if(!a){var d=1/0;for(l=0;l<e.length;l++){for(var[a,t,n]=e[l],c=!0,i=0;i<a.length;i++)(!1&n||d>=n)&&Object.keys(o.O).every((e=>o.O[e](a[i])))?a.splice(i--,1):(c=!1,n<d&&(d=n));if(c){e.splice(l--,1);var s=t();void 0!==s&&(r=s)}}return r}n=n||0;for(var l=e.length;l>0&&e[l-1][2]>n;l--)e[l]=e[l-1];e[l]=[a,t,n]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var a in r)o.o(r,a)&&!o.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:r[a]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,a)=>(o.f[a](e,r),r)),[])),o.u=e=>"js/"+{1084:"profile~followers.bundle",1983:"kb.bundle",2470:"home.chunk",2521:"about.bundle",2530:"discover~myhashtags.chunk",2586:"compose.chunk",2732:"dms~message.chunk",3351:"discover~settings.chunk",3365:"dms.chunk",3623:"discover~findfriends.chunk",4028:"error404.bundle",4509:"static~privacy.bundle",4958:"discover.chunk",4965:"discover~memories.chunk",5865:"post.chunk",6053:"notifications.chunk",6869:"profile.chunk",7004:"help.bundle",7019:"discover~hashtag.bundle",8021:"contact.bundle",8250:"i18n.bundle",8517:"daci.chunk",8600:"changelog.bundle",8625:"profile~following.bundle",8900:"discover~serverfeed.chunk",9144:"static~tos.bundle"}[e]+"."+{1084:"fe353e697fb7660b",1983:"f6ebdaac1fd552ca",2470:"25bd77760873ee83",2521:"44a18841089fdde3",2530:"089b7465b2359979",2586:"c413851da244ae3f",2732:"1cfdf19c4525eafa",3351:"5757ad3940569422",3365:"91ab72a8dcd1a8a8",3623:"1aabfedaab1849ba",4028:"5075813f1b00e10d",4509:"24c230550b6938b2",4958:"4f1b3ea93df06670",4965:"70b04c7698c2172b",5865:"881f8b0a9934e053",6053:"1a834e4a7bdbf21a",6869:"0f947cc09af5c8c3",7004:"7c1195b63e04d568",7019:"76807a8ff71bd205",8021:"d6c1d467c11796b1",8250:"9b9bf1b64e2aa1c1",8517:"3f13ec9fc49e9d2b",8600:"7f58a5ccc6659eb2",8625:"c406db7b14d07d36",8900:"ff59ca12d08bb810",9144:"65caad6c0546d8c9"}[e]+".js",o.miniCssF=e=>({138:"css/spa",703:"css/admin",1242:"css/appdark",6170:"css/app",8737:"css/portfolio",9994:"css/landing"}[e]+".css"),o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},a="pixelfed:",o.l=(e,t,n,d)=>{if(r[e])r[e].push(t);else{var c,i;if(void 0!==n)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var u=s[l];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==a+n){c=u;break}}c||(i=!0,(c=document.createElement("script")).charset="utf-8",c.timeout=120,o.nc&&c.setAttribute("nonce",o.nc),c.setAttribute("data-webpack",a+n),c.src=e),r[e]=[t];var f=(a,t)=>{c.onerror=c.onload=null,clearTimeout(b);var n=r[e];if(delete r[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),a)return a(t)},b=setTimeout(f.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=f.bind(null,c.onerror),c.onload=f.bind(null,c.onload),i&&document.head.appendChild(c)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),o.p="/",(()=>{var e={8929:0,1242:0,6170:0,8737:0,703:0,9994:0,138:0};o.f.j=(r,a)=>{var t=o.o(e,r)?e[r]:void 0;if(0!==t)if(t)a.push(t[2]);else if(/^(1242|138|6170|703|8737|8929|9994)$/.test(r))e[r]=0;else{var n=new Promise(((a,n)=>t=e[r]=[a,n]));a.push(t[2]=n);var d=o.p+o.u(r),c=new Error;o.l(d,(a=>{if(o.o(e,r)&&(0!==(t=e[r])&&(e[r]=void 0),t)){var n=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;c.message="Loading chunk "+r+" failed.\n("+n+": "+d+")",c.name="ChunkLoadError",c.type=n,c.request=d,t[1](c)}}),"chunk-"+r,r)}},o.O.j=r=>0===e[r];var r=(r,a)=>{var t,n,[d,c,i]=a,s=0;if(d.some((r=>0!==e[r]))){for(t in c)o.o(c,t)&&(o.m[t]=c[t]);if(i)var l=i(o)}for(r&&r(a);s<d.length;s++)n=d[s],o.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return o.O(l)},a=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];a.forEach(r.bind(null,0)),a.push=r.bind(null,a.push.bind(a))})(),o.nc=void 0})(); (()=>{"use strict";var e,r,a,t={},n={};function o(e){var r=n[e];if(void 0!==r)return r.exports;var a=n[e]={id:e,loaded:!1,exports:{}};return t[e].call(a.exports,a,a.exports,o),a.loaded=!0,a.exports}o.m=t,e=[],o.O=(r,a,t,n)=>{if(!a){var d=1/0;for(l=0;l<e.length;l++){for(var[a,t,n]=e[l],c=!0,i=0;i<a.length;i++)(!1&n||d>=n)&&Object.keys(o.O).every((e=>o.O[e](a[i])))?a.splice(i--,1):(c=!1,n<d&&(d=n));if(c){e.splice(l--,1);var s=t();void 0!==s&&(r=s)}}return r}n=n||0;for(var l=e.length;l>0&&e[l-1][2]>n;l--)e[l]=e[l-1];e[l]=[a,t,n]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var a in r)o.o(r,a)&&!o.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:r[a]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,a)=>(o.f[a](e,r),r)),[])),o.u=e=>"js/"+{1084:"profile~followers.bundle",1983:"kb.bundle",2470:"home.chunk",2521:"about.bundle",2530:"discover~myhashtags.chunk",2586:"compose.chunk",2732:"dms~message.chunk",3351:"discover~settings.chunk",3365:"dms.chunk",3623:"discover~findfriends.chunk",4028:"error404.bundle",4509:"static~privacy.bundle",4958:"discover.chunk",4965:"discover~memories.chunk",5865:"post.chunk",6053:"notifications.chunk",6869:"profile.chunk",7004:"help.bundle",7019:"discover~hashtag.bundle",8021:"contact.bundle",8250:"i18n.bundle",8517:"daci.chunk",8600:"changelog.bundle",8625:"profile~following.bundle",8900:"discover~serverfeed.chunk",9144:"static~tos.bundle"}[e]+"."+{1084:"fe353e697fb7660b",1983:"f6ebdaac1fd552ca",2470:"25bd77760873ee83",2521:"44a18841089fdde3",2530:"089b7465b2359979",2586:"c413851da244ae3f",2732:"1cfdf19c4525eafa",3351:"5757ad3940569422",3365:"91ab72a8dcd1a8a8",3623:"1aabfedaab1849ba",4028:"5075813f1b00e10d",4509:"24c230550b6938b2",4958:"4f1b3ea93df06670",4965:"70b04c7698c2172b",5865:"881f8b0a9934e053",6053:"1a834e4a7bdbf21a",6869:"0f947cc09af5c8c3",7004:"7c1195b63e04d568",7019:"279c3460159d3af7",8021:"d6c1d467c11796b1",8250:"9b9bf1b64e2aa1c1",8517:"3f13ec9fc49e9d2b",8600:"7f58a5ccc6659eb2",8625:"c406db7b14d07d36",8900:"ff59ca12d08bb810",9144:"65caad6c0546d8c9"}[e]+".js",o.miniCssF=e=>({138:"css/spa",703:"css/admin",1242:"css/appdark",6170:"css/app",8737:"css/portfolio",9994:"css/landing"}[e]+".css"),o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},a="pixelfed:",o.l=(e,t,n,d)=>{if(r[e])r[e].push(t);else{var c,i;if(void 0!==n)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var u=s[l];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==a+n){c=u;break}}c||(i=!0,(c=document.createElement("script")).charset="utf-8",c.timeout=120,o.nc&&c.setAttribute("nonce",o.nc),c.setAttribute("data-webpack",a+n),c.src=e),r[e]=[t];var f=(a,t)=>{c.onerror=c.onload=null,clearTimeout(b);var n=r[e];if(delete r[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),a)return a(t)},b=setTimeout(f.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=f.bind(null,c.onerror),c.onload=f.bind(null,c.onload),i&&document.head.appendChild(c)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),o.p="/",(()=>{var e={8929:0,1242:0,6170:0,8737:0,703:0,9994:0,138:0};o.f.j=(r,a)=>{var t=o.o(e,r)?e[r]:void 0;if(0!==t)if(t)a.push(t[2]);else if(/^(1242|138|6170|703|8737|8929|9994)$/.test(r))e[r]=0;else{var n=new Promise(((a,n)=>t=e[r]=[a,n]));a.push(t[2]=n);var d=o.p+o.u(r),c=new Error;o.l(d,(a=>{if(o.o(e,r)&&(0!==(t=e[r])&&(e[r]=void 0),t)){var n=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;c.message="Loading chunk "+r+" failed.\n("+n+": "+d+")",c.name="ChunkLoadError",c.type=n,c.request=d,t[1](c)}}),"chunk-"+r,r)}},o.O.j=r=>0===e[r];var r=(r,a)=>{var t,n,[d,c,i]=a,s=0;if(d.some((r=>0!==e[r]))){for(t in c)o.o(c,t)&&(o.m[t]=c[t]);if(i)var l=i(o)}for(r&&r(a);s<d.length;s++)n=d[s],o.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return o.O(l)},a=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];a.forEach(r.bind(null,0)),a.push=r.bind(null,a.push.bind(a))})(),o.nc=void 0})();

2
public/js/spa.js vendored

File diff suppressed because one or more lines are too long

@ -1,3 +1 @@
/*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */ /*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */

@ -18,13 +18,13 @@
"/js/direct.js": "/js/direct.js?id=5816111700ad8f8a89c932485f3a1e47", "/js/direct.js": "/js/direct.js?id=5816111700ad8f8a89c932485f3a1e47",
"/js/admin.js": "/js/admin.js?id=840e3b76bda57a29784bb2988e856cd8", "/js/admin.js": "/js/admin.js?id=840e3b76bda57a29784bb2988e856cd8",
"/js/live-player.js": "/js/live-player.js?id=c987b3cd69e432f1b3d52da2901ed305", "/js/live-player.js": "/js/live-player.js?id=c987b3cd69e432f1b3d52da2901ed305",
"/js/spa.js": "/js/spa.js?id=ec07738df5a6bd2ccccbc6edf0027927", "/js/spa.js": "/js/spa.js?id=7ecabb487fd27999e701d4f27132e3ac",
"/js/stories.js": "/js/stories.js?id=4db94699502e85543192865879bece7d", "/js/stories.js": "/js/stories.js?id=4db94699502e85543192865879bece7d",
"/js/portfolio.js": "/js/portfolio.js?id=646ebcbb4cab1dc0942dde3f8126940d", "/js/portfolio.js": "/js/portfolio.js?id=646ebcbb4cab1dc0942dde3f8126940d",
"/js/installer.js": "/js/installer.js?id=cd240ae970947b76ac49032ba95e0922", "/js/installer.js": "/js/installer.js?id=cd240ae970947b76ac49032ba95e0922",
"/js/admin_invite.js": "/js/admin_invite.js?id=307a53250701e3b12164af9495e88447", "/js/admin_invite.js": "/js/admin_invite.js?id=307a53250701e3b12164af9495e88447",
"/js/landing.js": "/js/landing.js?id=7e3ab65813c4bf28182f5bdf0825774c", "/js/landing.js": "/js/landing.js?id=7e3ab65813c4bf28182f5bdf0825774c",
"/js/manifest.js": "/js/manifest.js?id=20f6595aff2c900e268765e348ce70e2", "/js/manifest.js": "/js/manifest.js?id=476d005bfafee68d739307577f42f5c2",
"/js/home.chunk.25bd77760873ee83.js": "/js/home.chunk.25bd77760873ee83.js?id=2c68326604072a767c6eb345bbb89bb8", "/js/home.chunk.25bd77760873ee83.js": "/js/home.chunk.25bd77760873ee83.js?id=2c68326604072a767c6eb345bbb89bb8",
"/js/compose.chunk.c413851da244ae3f.js": "/js/compose.chunk.c413851da244ae3f.js?id=6389b021170bc21b58fc5bc28920f9af", "/js/compose.chunk.c413851da244ae3f.js": "/js/compose.chunk.c413851da244ae3f.js?id=6389b021170bc21b58fc5bc28920f9af",
"/js/post.chunk.881f8b0a9934e053.js": "/js/post.chunk.881f8b0a9934e053.js?id=89108b6e10ed316dc2d17ae28ea61262", "/js/post.chunk.881f8b0a9934e053.js": "/js/post.chunk.881f8b0a9934e053.js?id=89108b6e10ed316dc2d17ae28ea61262",
@ -41,7 +41,7 @@
"/js/dms~message.chunk.1cfdf19c4525eafa.js": "/js/dms~message.chunk.1cfdf19c4525eafa.js?id=bd3b4b71f23988bdfaf09ed817219cb9", "/js/dms~message.chunk.1cfdf19c4525eafa.js": "/js/dms~message.chunk.1cfdf19c4525eafa.js?id=bd3b4b71f23988bdfaf09ed817219cb9",
"/js/profile~followers.bundle.fe353e697fb7660b.js": "/js/profile~followers.bundle.fe353e697fb7660b.js?id=dc50b57aa36b027c3f5a81efe9525bf2", "/js/profile~followers.bundle.fe353e697fb7660b.js": "/js/profile~followers.bundle.fe353e697fb7660b.js?id=dc50b57aa36b027c3f5a81efe9525bf2",
"/js/profile~following.bundle.c406db7b14d07d36.js": "/js/profile~following.bundle.c406db7b14d07d36.js?id=b9088a98eeb05f06e241d398ffad5fbd", "/js/profile~following.bundle.c406db7b14d07d36.js": "/js/profile~following.bundle.c406db7b14d07d36.js?id=b9088a98eeb05f06e241d398ffad5fbd",
"/js/discover~hashtag.bundle.76807a8ff71bd205.js": "/js/discover~hashtag.bundle.76807a8ff71bd205.js?id=be75e076f14d258c1c581abc07f40af3", "/js/discover~hashtag.bundle.279c3460159d3af7.js": "/js/discover~hashtag.bundle.279c3460159d3af7.js?id=a13b7c78b2de89468a0d0a176919dd3f",
"/js/error404.bundle.5075813f1b00e10d.js": "/js/error404.bundle.5075813f1b00e10d.js?id=a5c557f4d707537aa3f023a0786dfeba", "/js/error404.bundle.5075813f1b00e10d.js": "/js/error404.bundle.5075813f1b00e10d.js?id=a5c557f4d707537aa3f023a0786dfeba",
"/js/help.bundle.7c1195b63e04d568.js": "/js/help.bundle.7c1195b63e04d568.js?id=5de97a307e5f3c6f1079fe57ff6f8294", "/js/help.bundle.7c1195b63e04d568.js": "/js/help.bundle.7c1195b63e04d568.js?id=5de97a307e5f3c6f1079fe57ff6f8294",
"/js/kb.bundle.f6ebdaac1fd552ca.js": "/js/kb.bundle.f6ebdaac1fd552ca.js?id=d1d8c0f2c80a50471e4df88c0bd4ca0d", "/js/kb.bundle.f6ebdaac1fd552ca.js": "/js/kb.bundle.f6ebdaac1fd552ca.js?id=d1d8c0f2c80a50471e4df88c0bd4ca0d",
@ -56,6 +56,6 @@
"/css/portfolio.css": "/css/portfolio.css?id=d98e354f173c6a8b729626384dceaa90", "/css/portfolio.css": "/css/portfolio.css?id=d98e354f173c6a8b729626384dceaa90",
"/css/admin.css": "/css/admin.css?id=619b6c6613a24e232048856e72110862", "/css/admin.css": "/css/admin.css?id=619b6c6613a24e232048856e72110862",
"/css/landing.css": "/css/landing.css?id=b3df014b08177b3e7a4eae8fbe132708", "/css/landing.css": "/css/landing.css?id=b3df014b08177b3e7a4eae8fbe132708",
"/css/spa.css": "/css/spa.css?id=602c4f74ce800b7bf45a8d8a4d8cb6e5", "/css/spa.css": "/css/spa.css?id=6f1bfa8ad59f9d3e8f7a16827057a7a9",
"/js/vendor.js": "/js/vendor.js?id=985cea6d09ed0f4c43ee3646a991ac84" "/js/vendor.js": "/js/vendor.js?id=985cea6d09ed0f4c43ee3646a991ac84"
} }

@ -8,7 +8,7 @@
<hr> <hr>
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-3"> <div class="col-sm-3">
<img src="{{Auth::user()->profile->avatarUrl()}}" width="38px" height="38px" class="rounded-circle float-right"> <img src="{{Auth::user()->profile->avatarUrl()}}" width="38px" height="38px" class="rounded-circle float-right" draggable="false" onerror="this.src='/storage/avatars/default.jpg?v=0';this.onerror=null;">
</div> </div>
<div class="col-sm-9"> <div class="col-sm-9">
<p class="lead font-weight-bold mb-0">{{Auth::user()->username}}</p> <p class="lead font-weight-bold mb-0">{{Auth::user()->username}}</p>

@ -89,6 +89,11 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
Route::get('announcements', 'Api\ApiV1Controller@getAnnouncements')->middleware($middleware); Route::get('announcements', 'Api\ApiV1Controller@getAnnouncements')->middleware($middleware);
Route::get('markers', 'Api\ApiV1Controller@getMarkers')->middleware($middleware); Route::get('markers', 'Api\ApiV1Controller@getMarkers')->middleware($middleware);
Route::post('markers', 'Api\ApiV1Controller@setMarkers')->middleware($middleware); Route::post('markers', 'Api\ApiV1Controller@setMarkers')->middleware($middleware);
Route::get('followed_tags', 'Api\ApiV1Controller@getFollowedTags')->middleware($middleware);
Route::post('tags/{id}/follow', 'Api\ApiV1Controller@followHashtag')->middleware($middleware);
Route::post('tags/{id}/unfollow', 'Api\ApiV1Controller@unfollowHashtag')->middleware($middleware);
Route::get('tags/{id}', 'Api\ApiV1Controller@getHashtag')->middleware($middleware);
}); });
Route::group(['prefix' => 'v2'], function() use($middleware) { Route::group(['prefix' => 'v2'], function() use($middleware) {

@ -407,6 +407,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('web/username/{id}', 'SpaController@usernameRedirect'); Route::get('web/username/{id}', 'SpaController@usernameRedirect');
Route::get('web/post/{id}', 'SpaController@webPost'); Route::get('web/post/{id}', 'SpaController@webPost');
Route::get('web/profile/{id}', 'SpaController@webProfile'); Route::get('web/profile/{id}', 'SpaController@webProfile');
Route::get('web/{q}', 'SpaController@index')->where('q', '.*'); Route::get('web/{q}', 'SpaController@index')->where('q', '.*');
Route::get('web', 'SpaController@index'); Route::get('web', 'SpaController@index');
}); });

Loading…
Cancel
Save