1
0
Fork 0

Merge pull request #4363 from pixelfed/staging

Staging
This commit is contained in:
daniel 2023-05-09 04:09:18 -06:00 committed by GitHub
commit 03e7e24b6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 290 additions and 27 deletions

View File

@ -2,6 +2,12 @@
## [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 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 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 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/))
## [v0.11.6 (2023-05-03)](https://github.com/pixelfed/pixelfed/compare/v0.11.5...v0.11.6)

View File

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

View File

@ -19,6 +19,7 @@ use App\{
Follower,
FollowRequest,
Hashtag,
HashtagFollow,
Instance,
Like,
Media,
@ -69,6 +70,7 @@ use App\Services\{
BouncerService,
CollectionService,
FollowerService,
HashtagService,
InstanceService,
LikeService,
NetworkTimelineService,
@ -99,6 +101,7 @@ use App\Jobs\FollowPipeline\FollowRejectPipeline;
use Illuminate\Support\Facades\RateLimiter;
use Purify;
use Carbon\Carbon;
use App\Http\Resources\MastoApi\FollowedTagResource;
class ApiV1Controller extends Controller
{
@ -3245,7 +3248,9 @@ class ApiV1Controller extends Controller
'page' => 'nullable|integer|max:40',
'min_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') {
@ -3269,6 +3274,18 @@ class ApiV1Controller extends Controller
$min = $request->input('min_id');
$max = $request->input('max_id');
$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) {
$id = 1;
@ -3281,15 +3298,19 @@ class ApiV1Controller extends Controller
$res = StatusHashtag::whereHashtagId($tag->id)
->whereStatusVisibility('public')
->where('status_id', $dir, $id)
->latest()
->orderBy('status_id', 'desc')
->limit($limit)
->pluck('status_id')
->map(function ($i) {
if($i) {
return StatusService::getMastodon($i);
}
->map(function ($i) use($pe) {
return $pe ? StatusService::get($i) : 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']);
})
->values()
@ -3636,7 +3657,7 @@ class ApiV1Controller extends Controller
return $this->json(StatusService::getState($status->id, $pid));
}
/**
/**
* GET /api/v1.1/discover/accounts/popular
*
*
@ -3794,4 +3815,181 @@ class ApiV1Controller extends Controller
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);
}
}

View File

@ -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,
];
}
}

View File

@ -28,8 +28,8 @@ class HashtagService {
public static function count($id)
{
return Cache::remember('services:hashtag:count:by_id:' . $id, 3600, function() use($id) {
return StatusHashtag::whereHashtagId($id)->count();
return Cache::remember('services:hashtag:public-count:by_id:' . $id, 86400, function() use($id) {
return StatusHashtag::whereHashtagId($id)->whereStatusVisibility('public')->count();
});
}
@ -64,4 +64,9 @@ class HashtagService {
{
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);
}
}

View File

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

View File

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

View File

@ -4,9 +4,9 @@ namespace App\Services;
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)

View File

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

View File

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

View File

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

2
public/css/spa.css vendored

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

View File

@ -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

View File

@ -1,3 +1 @@
/*! @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 */

View File

@ -18,13 +18,13 @@
"/js/direct.js": "/js/direct.js?id=5816111700ad8f8a89c932485f3a1e47",
"/js/admin.js": "/js/admin.js?id=840e3b76bda57a29784bb2988e856cd8",
"/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/portfolio.js": "/js/portfolio.js?id=646ebcbb4cab1dc0942dde3f8126940d",
"/js/installer.js": "/js/installer.js?id=cd240ae970947b76ac49032ba95e0922",
"/js/admin_invite.js": "/js/admin_invite.js?id=307a53250701e3b12164af9495e88447",
"/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/compose.chunk.c413851da244ae3f.js": "/js/compose.chunk.c413851da244ae3f.js?id=6389b021170bc21b58fc5bc28920f9af",
"/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/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/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/help.bundle.7c1195b63e04d568.js": "/js/help.bundle.7c1195b63e04d568.js?id=5de97a307e5f3c6f1079fe57ff6f8294",
"/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/admin.css": "/css/admin.css?id=619b6c6613a24e232048856e72110862",
"/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"
}

View File

@ -8,7 +8,7 @@
<hr>
<div class="form-group row">
<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 class="col-sm-9">
<p class="lead font-weight-bold mb-0">{{Auth::user()->username}}</p>

View File

@ -89,6 +89,11 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
Route::get('announcements', 'Api\ApiV1Controller@getAnnouncements')->middleware($middleware);
Route::get('markers', 'Api\ApiV1Controller@getMarkers')->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) {

View File

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