diff --git a/app/Http/Controllers/Api/BaseApiController.php b/app/Http/Controllers/Api/BaseApiController.php index 61c8b9e8..ad717dfe 100644 --- a/app/Http/Controllers/Api/BaseApiController.php +++ b/app/Http/Controllers/Api/BaseApiController.php @@ -8,6 +8,7 @@ use App\Http\Controllers\{ AvatarController }; use Auth, Cache, URL; +use Carbon\Carbon; use App\{ Avatar, Notification, @@ -47,7 +48,22 @@ class BaseApiController extends Controller $resource = new Fractal\Resource\Item($notification, new NotificationTransformer()); $res = $this->fractal->createData($resource)->toArray(); - return response()->json($res, 200, [], JSON_PRETTY_PRINT); + return response()->json($res); + } + + public function notifications(Request $request) + { + $pid = Auth::user()->profile->id; + $timeago = Carbon::now()->subMonths(6); + $notifications = Notification::with('actor') + ->whereProfileId($pid) + ->whereDate('created_at', '>', $timeago) + ->orderBy('created_at','desc') + ->paginate(10); + $resource = new Fractal\Resource\Collection($notifications, new NotificationTransformer()); + $res = $this->fractal->createData($resource)->toArray(); + + return response()->json($res); } public function accounts(Request $request, $id) @@ -56,7 +72,7 @@ class BaseApiController extends Controller $resource = new Fractal\Resource\Item($profile, new AccountTransformer()); $res = $this->fractal->createData($resource)->toArray(); - return response()->json($res, 200, [], JSON_PRETTY_PRINT); + return response()->json($res); } public function accountFollowers(Request $request, $id) @@ -66,7 +82,7 @@ class BaseApiController extends Controller $resource = new Fractal\Resource\Collection($followers, new AccountTransformer()); $res = $this->fractal->createData($resource)->toArray(); - return response()->json($res, 200, [], JSON_PRETTY_PRINT); + return response()->json($res); } public function accountFollowing(Request $request, $id) @@ -76,7 +92,7 @@ class BaseApiController extends Controller $resource = new Fractal\Resource\Collection($following, new AccountTransformer()); $res = $this->fractal->createData($resource)->toArray(); - return response()->json($res, 200, [], JSON_PRETTY_PRINT); + return response()->json($res); } public function accountStatuses(Request $request, $id) @@ -92,7 +108,7 @@ class BaseApiController extends Controller $resource = new Fractal\Resource\Collection($statuses, new StatusTransformer()); $res = $this->fractal->createData($resource)->toArray(); - return response()->json($res, 200, [], JSON_PRETTY_PRINT); + return response()->json($res); } public function followSuggestions(Request $request) @@ -140,13 +156,13 @@ class BaseApiController extends Controller ]); } - public function showTempMedia(Request $request, $profileId, $mediaId) + public function showTempMedia(Request $request, int $profileId, $mediaId) { if (!$request->hasValidSignature()) { abort(401); } $profile = Auth::user()->profile; - if($profile->id !== (int) $profileId) { + if($profile->id !== $profileId) { abort(403); } $media = Media::whereProfileId($profile->id)->findOrFail($mediaId); @@ -240,4 +256,13 @@ class BaseApiController extends Controller return response()->json($res); } + + public function verifyCredentials(Request $request) + { + $profile = Auth::user()->profile; + $resource = new Fractal\Resource\Item($profile, new AccountTransformer()); + $res = $this->fractal->createData($resource)->toArray(); + + return response()->json($res); + } } diff --git a/app/Http/Controllers/InternalApiController.php b/app/Http/Controllers/InternalApiController.php index d21b8eab..fb4cdcde 100644 --- a/app/Http/Controllers/InternalApiController.php +++ b/app/Http/Controllers/InternalApiController.php @@ -94,37 +94,6 @@ class InternalApiController extends Controller return $status->url(); } - public function notifications(Request $request) - { - $this->validate($request, [ - 'page' => 'nullable|min:1|max:3', - ]); - - $profile = Auth::user()->profile; - $timeago = Carbon::now()->subMonths(6); - $notifications = Notification::with('actor') - ->whereProfileId($profile->id) - ->whereDate('created_at', '>', $timeago) - ->orderBy('id', 'desc') - ->simplePaginate(30); - $notifications = $notifications->map(function($k, $v) { - return [ - 'id' => $k->id, - 'action' => $k->action, - 'message' => $k->message, - 'rendered' => $k->rendered, - 'actor' => [ - 'avatar' => $k->actor->avatarUrl(), - 'username' => $k->actor->username, - 'url' => $k->actor->url(), - ], - 'url' => $k->item->url(), - 'read_at' => $k->read_at, - ]; - }); - return response()->json($notifications, 200, [], JSON_PRETTY_PRINT); - } - // deprecated public function discover(Request $request) { @@ -288,4 +257,19 @@ class InternalApiController extends Controller return; } + + public function statusReplies(Request $request, int $id) + { + $parent = Status::findOrFail($id); + + $children = Status::whereInReplyToId($parent->id) + ->orderBy('created_at', 'desc') + ->take(3) + ->get(); + + $resource = new Fractal\Resource\Collection($children, new StatusTransformer()); + $res = $this->fractal->createData($resource)->toArray(); + + return response()->json($res); + } } diff --git a/app/Http/Controllers/PublicApiController.php b/app/Http/Controllers/PublicApiController.php index 440effd8..637dde84 100644 --- a/app/Http/Controllers/PublicApiController.php +++ b/app/Http/Controllers/PublicApiController.php @@ -12,6 +12,7 @@ use App\{ Profile, StatusHashtag, Status, + UserFilter }; use Auth,Cache; use Carbon\Carbon; @@ -194,4 +195,127 @@ class PublicApiController extends Controller break; } } + + public function publicTimelineApi(Request $request) + { + if(!Auth::check()) { + return abort(403); + } + + $this->validate($request,[ + 'page' => 'nullable|integer|max:40', + 'min_id' => 'nullable|integer', + 'max_id' => 'nullable|integer', + 'limit' => 'nullable|integer|max:20' + ]); + + $page = $request->input('page'); + $min = $request->input('min_id'); + $max = $request->input('max_id'); + $limit = $request->input('limit') ?? 10; + + // TODO: Use redis for timelines + // $timeline = Timeline::build()->local(); + $pid = Auth::user()->profile->id; + + $private = Profile::whereIsPrivate(true)->where('id', '!=', $pid)->pluck('id'); + $filters = UserFilter::whereUserId($pid) + ->whereFilterableType('App\Profile') + ->whereIn('filter_type', ['mute', 'block']) + ->pluck('filterable_id')->toArray(); + $filtered = array_merge($private->toArray(), $filters); + + if($min || $max) { + $dir = $min ? '>' : '<'; + $id = $min ?? $max; + $timeline = Status::whereHas('media') + ->where('id', $dir, $id) + ->whereNotIn('profile_id', $filtered) + ->whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereVisibility('public') + ->withCount(['comments', 'likes']) + ->orderBy('created_at', 'desc') + ->limit($limit) + ->get(); + } else { + $timeline = Status::whereHas('media') + ->whereNotIn('profile_id', $filtered) + ->whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereVisibility('public') + ->withCount(['comments', 'likes']) + ->orderBy('created_at', 'desc') + ->simplePaginate($limit); + } + + $fractal = new Fractal\Resource\Collection($timeline, new StatusTransformer()); + $res = $this->fractal->createData($fractal)->toArray(); + return response()->json($res); + + } + + public function homeTimelineApi(Request $request) + { + if(!Auth::check()) { + return abort(403); + } + + $this->validate($request,[ + 'page' => 'nullable|integer|max:40', + 'min_id' => 'nullable|integer', + 'max_id' => 'nullable|integer', + 'limit' => 'nullable|integer|max:20' + ]); + + $page = $request->input('page'); + $min = $request->input('min_id'); + $max = $request->input('max_id'); + $limit = $request->input('limit') ?? 10; + + // TODO: Use redis for timelines + // $timeline = Timeline::build()->local(); + $pid = Auth::user()->profile->id; + + $following = Follower::whereProfileId($pid)->pluck('following_id'); + $following->push($pid)->toArray(); + + $private = Profile::whereIsPrivate(true)->where('id', '!=', $pid)->pluck('id'); + $filters = UserFilter::whereUserId($pid) + ->whereFilterableType('App\Profile') + ->whereIn('filter_type', ['mute', 'block']) + ->pluck('filterable_id')->toArray(); + $filtered = array_merge($private->toArray(), $filters); + + if($min || $max) { + $dir = $min ? '>' : '<'; + $id = $min ?? $max; + $timeline = Status::whereHas('media') + ->where('id', $dir, $id) + ->whereIn('profile_id', $following) + ->whereNotIn('profile_id', $filtered) + ->whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereVisibility('public') + ->withCount(['comments', 'likes']) + ->orderBy('created_at', 'desc') + ->limit($limit) + ->get(); + } else { + $timeline = Status::whereHas('media') + ->whereIn('profile_id', $following) + ->whereNotIn('profile_id', $filtered) + ->whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereVisibility('public') + ->withCount(['comments', 'likes']) + ->orderBy('created_at', 'desc') + ->simplePaginate($limit); + } + + $fractal = new Fractal\Resource\Collection($timeline, new StatusTransformer()); + $res = $this->fractal->createData($fractal)->toArray(); + return response()->json($res); + + } } diff --git a/app/Http/Controllers/SiteController.php b/app/Http/Controllers/SiteController.php index d7ab9648..fa12c939 100644 --- a/app/Http/Controllers/SiteController.php +++ b/app/Http/Controllers/SiteController.php @@ -31,28 +31,7 @@ class SiteController extends Controller public function homeTimeline() { - $pid = Auth::user()->profile->id; - // TODO: Use redis for timelines - - $following = Follower::whereProfileId($pid)->pluck('following_id'); - $following->push($pid)->toArray(); - - $filtered = UserFilter::whereUserId($pid) - ->whereFilterableType('App\Profile') - ->whereIn('filter_type', ['mute', 'block']) - ->pluck('filterable_id')->toArray(); - - $timeline = Status::whereIn('profile_id', $following) - ->whereNotIn('profile_id', $filtered) - ->whereHas('media') - ->whereVisibility('public') - ->orderBy('created_at', 'desc') - ->withCount(['comments', 'likes', 'shares']) - ->simplePaginate(20); - - $type = 'personal'; - - return view('timeline.template', compact('timeline', 'type')); + return view('timeline.home'); } public function changeLocale(Request $request, $locale) diff --git a/app/Http/Controllers/TimelineController.php b/app/Http/Controllers/TimelineController.php index 5ce51eb8..41769285 100644 --- a/app/Http/Controllers/TimelineController.php +++ b/app/Http/Controllers/TimelineController.php @@ -20,30 +20,6 @@ class TimelineController extends Controller public function local(Request $request) { - $this->validate($request,[ - 'page' => 'nullable|integer|max:20' - ]); - // TODO: Use redis for timelines - // $timeline = Timeline::build()->local(); - $pid = Auth::user()->profile->id; - - $private = Profile::whereIsPrivate(true)->where('id', '!=', $pid)->pluck('id'); - $filters = UserFilter::whereUserId($pid) - ->whereFilterableType('App\Profile') - ->whereIn('filter_type', ['mute', 'block']) - ->pluck('filterable_id')->toArray(); - $filtered = array_merge($private->toArray(), $filters); - - $timeline = Status::whereHas('media') - ->whereNotIn('profile_id', $filtered) - ->whereNull('in_reply_to_id') - ->whereNull('reblog_of_id') - ->whereVisibility('public') - ->withCount(['comments', 'likes']) - ->orderBy('created_at', 'desc') - ->simplePaginate(10); - $type = 'local'; - - return view('timeline.template', compact('timeline', 'type')); + return view('timeline.local'); } } diff --git a/app/Profile.php b/app/Profile.php index 5dc6599e..4176a310 100644 --- a/app/Profile.php +++ b/app/Profile.php @@ -156,6 +156,7 @@ class Profile extends Model public function statusCount() { return $this->statuses() + ->getQuery() ->whereHas('media') ->whereNull('in_reply_to_id') ->whereNull('reblog_of_id') diff --git a/app/Transformer/Api/MediaTransformer.php b/app/Transformer/Api/MediaTransformer.php index 4ac5c6be..8ab38fc6 100644 --- a/app/Transformer/Api/MediaTransformer.php +++ b/app/Transformer/Api/MediaTransformer.php @@ -23,6 +23,7 @@ class MediaTransformer extends Fractal\TransformerAbstract 'orientation' => $media->orientation, 'filter_name' => $media->filter_name, 'filter_class' => $media->filter_class, + 'mime' => $media->mime, ]; } } diff --git a/app/Transformer/Api/NotificationTransformer.php b/app/Transformer/Api/NotificationTransformer.php index d5afa1b6..16d537c9 100644 --- a/app/Transformer/Api/NotificationTransformer.php +++ b/app/Transformer/Api/NotificationTransformer.php @@ -45,6 +45,7 @@ class NotificationTransformer extends Fractal\TransformerAbstract 'mention' => 'mention', 'reblog' => 'share', 'like' => 'favourite', + 'comment' => 'comment', ]; return $verbs[$verb]; } diff --git a/config/pixelfed.php b/config/pixelfed.php index 131a1959..ca1b4be2 100644 --- a/config/pixelfed.php +++ b/config/pixelfed.php @@ -23,7 +23,7 @@ return [ | This value is the version of your PixelFed instance. | */ - 'version' => '0.4.3', + 'version' => '0.5.0', /* |-------------------------------------------------------------------------- diff --git a/package-lock.json b/package-lock.json index a77f1ee8..8545e1ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2571,6 +2571,11 @@ "assert-plus": "^1.0.0" } }, + "date-fns": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", + "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==" + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -11372,6 +11377,14 @@ "integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==", "dev": true }, + "vue-timeago": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/vue-timeago/-/vue-timeago-5.0.0.tgz", + "integrity": "sha512-C+EqTlfHE9nO6FOQIS6q5trAZ0WIgNz/eydTvsanPRsLVV1xqNiZirTG71d9nl/LjfNETwaktnBlgP8adCc37A==", + "requires": { + "date-fns": "^1.29.0" + } + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", diff --git a/package.json b/package.json index 7f21d644..6c173a69 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "filesize": "^3.6.1", "infinite-scroll": "^3.0.4", "laravel-echo": "^1.4.0", + "opencollective": "^1.0.3", "opencollective-postinstall": "^2.0.1", "plyr": "^3.4.7", "pusher-js": "^4.2.2", @@ -34,10 +35,10 @@ "twitter-text": "^2.0.5", "vue-infinite-loading": "^2.4.3", "vue-loading-overlay": "^3.1.0", - "opencollective": "^1.0.3" + "vue-timeago": "^5.0.0" }, "collective": { "type": "opencollective", "url": "https://opencollective.com/pixelfed-528" } -} \ No newline at end of file +} diff --git a/public/js/components.js b/public/js/components.js index 3998e2e5..28802d7b 100644 --- a/public/js/components.js +++ b/public/js/components.js @@ -1 +1 @@ -!function(t){var e={};function n(i){if(e[i])return e[i].exports;var r=e[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:i})},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/",n(n.s=2)}({"/7en":function(t,e,n){var i,r;"undefined"!=typeof window&&window,void 0===(r="function"==typeof(i=function(){"use strict";function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var n=this._events=this._events||{},i=n[t]=n[t]||[];return-1==i.indexOf(e)&&i.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var n=this._onceEvents=this._onceEvents||{};return(n[t]=n[t]||{})[e]=!0,this}},e.off=function(t,e){var n=this._events&&this._events[t];if(n&&n.length){var i=n.indexOf(e);return-1!=i&&n.splice(i,1),this}},e.emitEvent=function(t,e){var n=this._events&&this._events[t];if(n&&n.length){n=n.slice(0),e=e||[];for(var i=this._onceEvents&&this._onceEvents[t],r=0;r1&&($(".section-explore .loader").hide(),$(".section-explore .row.d-none").removeClass("d-none"))})}}}},"1/oy":function(t,e,n){var i=n("eAYY");"string"==typeof i&&(i=[[t.i,i,""]]);var r={transform:void 0};n("MTIv")(i,r);i.locals&&(t.exports=i.locals)},"162o":function(t,e,n){(function(t){var i=void 0!==t&&t||"undefined"!=typeof self&&self||window,r=Function.prototype.apply;function o(t,e){this._id=t,this._clearFn=e}e.setTimeout=function(){return new o(r.call(setTimeout,i,arguments),clearTimeout)},e.setInterval=function(){return new o(r.call(setInterval,i,arguments),clearInterval)},e.clearTimeout=e.clearInterval=function(t){t&&t.close()},o.prototype.unref=o.prototype.ref=function(){},o.prototype.close=function(){this._clearFn.call(i,this._id)},e.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},e.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},e._unrefActive=e.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},n("mypn"),e.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==t&&t.setImmediate||this&&this.setImmediate,e.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==t&&t.clearImmediate||this&&this.clearImmediate}).call(e,n("DuR2"))},"1MO9":function(t,e,n){(t.exports=n("FZ+f")(!1)).push([t.i,"input.form-control[type=color],input.form-control[type=range]{height:2.25rem}input.form-control.form-control-sm[type=color],input.form-control.form-control-sm[type=range]{height:1.9375rem}input.form-control.form-control-lg[type=color],input.form-control.form-control-lg[type=range]{height:3rem}input.form-control[type=color]{padding:.25rem}input.form-control.form-control-sm[type=color]{padding:.125rem}",""])},2:function(t,e,n){t.exports=n("Tkmu")},"20cu":function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default={data:function(){return{tokens:[]}},ready:function(){this.prepareComponent()},mounted:function(){this.prepareComponent()},methods:{prepareComponent:function(){this.getTokens()},getTokens:function(){var t=this;axios.get("/oauth/tokens").then(function(e){t.tokens=e.data})},revoke:function(t){var e=this;axios.delete("/oauth/tokens/"+t.id).then(function(t){e.getTokens()})}}}},"2XjJ":function(t,e){t.exports={render:function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"container"},[n("section",{staticClass:"mb-5 section-explore"},[n("p",{staticClass:"lead text-muted font-weight-bold mb-0"},[t._v("Explore")]),t._v(" "),n("div",{staticClass:"profile-timeline"},[t._m(0),t._v(" "),n("div",{staticClass:"row d-none"},t._l(t.posts,function(t){return n("div",{staticClass:"col-4 p-0 p-sm-2 p-md-3"},[n("a",{staticClass:"card info-overlay card-md-border-0",attrs:{href:t.url}},[n("div",{staticClass:"square filter_class"},[n("div",{staticClass:"square-content",style:{"background-image":"url("+t.thumb+")"}})])])])}))])]),t._v(" "),t._m(1)])},staticRenderFns:[function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"loader text-center"},[e("div",{staticClass:"lds-ring"},[e("div"),e("div"),e("div"),e("div")])])},function(){var t=this.$createElement,e=this._self._c||t;return e("section",{staticClass:"mb-5"},[e("p",{staticClass:"lead text-center"},[this._v("To view more posts, check the "),e("a",{staticClass:"font-weight-bold",attrs:{href:"/"}},[this._v("home")]),this._v(" or "),e("a",{staticClass:"font-weight-bold",attrs:{href:"/timeline/public"}},[this._v("local")]),this._v(" timelines.")])])}]}},"3G5u":function(t,e){t.exports={render:function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("div",[n("div",{staticClass:"card card-default mb-4"},[n("div",{staticClass:"card-header font-weight-bold bg-white"},[n("div",{staticStyle:{display:"flex","justify-content":"space-between","align-items":"center"}},[n("span",[t._v("\n Personal Access Tokens\n ")]),t._v(" "),n("a",{staticClass:"action-link",attrs:{tabindex:"-1"},on:{click:t.showCreateTokenForm}},[t._v("\n Create New Token\n ")])])]),t._v(" "),n("div",{staticClass:"card-body"},[0===t.tokens.length?n("p",{staticClass:"mb-0"},[t._v("\n You have not created any personal access tokens.\n ")]):t._e(),t._v(" "),t.tokens.length>0?n("table",{staticClass:"table table-borderless mb-0"},[t._m(0),t._v(" "),n("tbody",t._l(t.tokens,function(e){return n("tr",[n("td",{staticStyle:{"vertical-align":"middle"}},[t._v("\n "+t._s(e.name)+"\n ")]),t._v(" "),n("td",{staticStyle:{"vertical-align":"middle"}},[n("a",{staticClass:"action-link text-danger",on:{click:function(n){t.revoke(e)}}},[t._v("\n Delete\n ")])])])}))]):t._e()])])]),t._v(" "),n("div",{staticClass:"modal fade",attrs:{id:"modal-create-token",tabindex:"-1",role:"dialog"}},[n("div",{staticClass:"modal-dialog"},[n("div",{staticClass:"modal-content"},[t._m(1),t._v(" "),n("div",{staticClass:"modal-body"},[t.form.errors.length>0?n("div",{staticClass:"alert alert-danger"},[t._m(2),t._v(" "),n("br"),t._v(" "),n("ul",t._l(t.form.errors,function(e){return n("li",[t._v("\n "+t._s(e)+"\n ")])}))]):t._e(),t._v(" "),n("form",{attrs:{role:"form"},on:{submit:function(e){return e.preventDefault(),t.store(e)}}},[n("div",{staticClass:"form-group row"},[n("label",{staticClass:"col-md-4 col-form-label"},[t._v("Name")]),t._v(" "),n("div",{staticClass:"col-md-6"},[n("input",{directives:[{name:"model",rawName:"v-model",value:t.form.name,expression:"form.name"}],staticClass:"form-control",attrs:{id:"create-token-name",type:"text",name:"name",autocomplete:"off"},domProps:{value:t.form.name},on:{input:function(e){e.target.composing||t.$set(t.form,"name",e.target.value)}}})])]),t._v(" "),t.scopes.length>0?n("div",{staticClass:"form-group row"},[n("label",{staticClass:"col-md-4 col-form-label"},[t._v("Scopes")]),t._v(" "),n("div",{staticClass:"col-md-6"},t._l(t.scopes,function(e){return n("div",[n("div",{staticClass:"checkbox"},[n("label",[n("input",{attrs:{type:"checkbox"},domProps:{checked:t.scopeIsAssigned(e.id)},on:{click:function(n){t.toggleScope(e.id)}}}),t._v("\n\n "+t._s(e.id)+"\n ")])])])}))]):t._e()])]),t._v(" "),n("div",{staticClass:"modal-footer"},[n("button",{staticClass:"btn btn-secondary font-weight-bold",attrs:{type:"button","data-dismiss":"modal"}},[t._v("Close")]),t._v(" "),n("button",{staticClass:"btn btn-primary font-weight-bold",attrs:{type:"button"},on:{click:t.store}},[t._v("\n Create\n ")])])])])]),t._v(" "),n("div",{staticClass:"modal fade",attrs:{id:"modal-access-token",tabindex:"-1",role:"dialog"}},[n("div",{staticClass:"modal-dialog"},[n("div",{staticClass:"modal-content"},[t._m(3),t._v(" "),n("div",{staticClass:"modal-body"},[n("p",[t._v("\n Here is your new personal access token. This is the only time it will be shown so don't lose it!\n You may now use this token to make API requests.\n ")]),t._v(" "),n("textarea",{staticClass:"form-control",attrs:{rows:"10"}},[t._v(t._s(t.accessToken))])]),t._v(" "),t._m(4)])])])])},staticRenderFns:[function(){var t=this.$createElement,e=this._self._c||t;return e("thead",[e("tr",[e("th",[this._v("Name")]),this._v(" "),e("th")])])},function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[this._v("\n Create Token\n ")]),this._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[this._v("×")])])},function(){var t=this.$createElement,e=this._self._c||t;return e("p",{staticClass:"mb-0"},[e("strong",[this._v("Whoops!")]),this._v(" Something went wrong!")])},function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[this._v("\n Personal Access Token\n ")]),this._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[this._v("×")])])},function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"modal-footer"},[e("button",{staticClass:"btn btn-secondary",attrs:{type:"button","data-dismiss":"modal"}},[this._v("Close")])])}]}},"3H+/":function(t,e,n){var i,r;!function(o,a){i=[n("/7en"),n("h803")],void 0===(r=function(t,e){return a(o,t,e)}.apply(e,i))||(t.exports=r)}(window,function(t,e,n){var i=t.jQuery,r={};function o(t,e){var a=n.getQueryElement(t);if(a){if((t=a).infiniteScrollGUID){var s=r[t.infiniteScrollGUID];return s.option(e),s}this.element=t,this.options=n.extend({},o.defaults),this.option(e),i&&(this.$element=i(this.element)),this.create()}else console.error("Bad element for InfiniteScroll: "+(a||t))}o.defaults={},o.create={},o.destroy={};var a=o.prototype;n.extend(a,e.prototype);var s=0;a.create=function(){var t=this.guid=++s;if(this.element.infiniteScrollGUID=t,r[t]=this,this.pageIndex=1,this.loadCount=0,this.updateGetPath(),this.getPath&&this.getPath())for(var e in this.updateGetAbsolutePath(),this.log("initialized",[this.element.className]),this.callOnInit(),o.create)o.create[e].call(this);else console.error("Disabling InfiniteScroll")},a.option=function(t){n.extend(this.options,t)},a.callOnInit=function(){var t=this.options.onInit;t&&t.call(this,this)},a.dispatchEvent=function(t,e,n){this.log(t,n);var r=e?[e].concat(n):n;if(this.emitEvent(t,r),i&&this.$element){var o=t+=".infiniteScroll";if(e){var a=i.Event(e);a.type=t,o=a}this.$element.trigger(o,n)}};var l={initialized:function(t){return"on "+t},request:function(t){return"URL: "+t},load:function(t,e){return(t.title||"")+". URL: "+e},error:function(t,e){return t+". URL: "+e},append:function(t,e,n){return n.length+" items. URL: "+e},last:function(t,e){return"URL: "+e},history:function(t,e){return"URL: "+e},pageIndex:function(t,e){return"current page determined to be: "+t+" from "+e}};a.log=function(t,e){if(this.options.debug){var n="[InfiniteScroll] "+t,i=l[t];i&&(n+=". "+i.apply(this,e)),console.log(n)}},a.updateMeasurements=function(){this.windowHeight=t.innerHeight;var e=this.element.getBoundingClientRect();this.top=e.top+t.pageYOffset},a.updateScroller=function(){var e=this.options.elementScroll;if(e){if(this.scroller=!0===e?this.element:n.getQueryElement(e),!this.scroller)throw"Unable to find elementScroll: "+e}else this.scroller=t},a.updateGetPath=function(){var t=this.options.path;if(t){var e=typeof t;if("function"!=e)"string"==e&&t.match("{{#}}")?this.updateGetPathTemplate(t):this.updateGetPathSelector(t);else this.getPath=t}else console.error("InfiniteScroll path option required. Set as: "+t)},a.updateGetPathTemplate=function(t){this.getPath=function(){var e=this.pageIndex+1;return t.replace("{{#}}",e)}.bind(this);var e=t.replace("{{#}}","(\\d\\d?\\d?)"),n=new RegExp(e),i=location.href.match(n);i&&(this.pageIndex=parseInt(i[1],10),this.log("pageIndex",[this.pageIndex,"template string"]))};var c=[/^(.*?\/?page\/?)(\d\d?\d?)(.*?$)/,/^(.*?\/?\?page=)(\d\d?\d?)(.*?$)/,/(.*?)(\d\d?\d?)(?!.*\d)(.*?$)/];return a.updateGetPathSelector=function(t){var e=document.querySelector(t);if(e){for(var n,i,r=e.getAttribute("href"),o=0;r&&o=0,this.isPrefilling?(this.log("prefill"),this.loadNextPage()):this.stopPrefill()},n.getPrefillDistance=function(){return this.options.elementScroll?this.scroller.clientHeight-this.scroller.scrollHeight:this.windowHeight-this.element.clientHeight},n.stopPrefill=function(){this.log("stopPrefill"),this.off("append",this.prefill)},e})},"99Qu":function(t,e,n){var i,r;!function(o,a){i=[n("3H+/"),n("h803")],void 0===(r=function(t,e){return a(o,t,e)}.apply(e,i))||(t.exports=r)}(window,function(t,e,n){var i=e.prototype;return e.defaults.scrollThreshold=400,e.create.scrollWatch=function(){this.pageScrollHandler=this.onPageScroll.bind(this),this.resizeHandler=this.onResize.bind(this);var t=this.options.scrollThreshold;(t||0===t)&&this.enableScrollWatch()},e.destroy.scrollWatch=function(){this.disableScrollWatch()},i.enableScrollWatch=function(){this.isScrollWatching||(this.isScrollWatching=!0,this.updateMeasurements(),this.updateScroller(),this.on("last",this.disableScrollWatch),this.bindScrollWatchEvents(!0))},i.disableScrollWatch=function(){this.isScrollWatching&&(this.bindScrollWatchEvents(!1),delete this.isScrollWatching)},i.bindScrollWatchEvents=function(e){var n=e?"addEventListener":"removeEventListener";this.scroller[n]("scroll",this.pageScrollHandler),t[n]("resize",this.resizeHandler)},i.onPageScroll=e.throttle(function(){this.getBottomDistance()<=this.options.scrollThreshold&&this.dispatchEvent("scrollThreshold")}),i.getBottomDistance=function(){return this.options.elementScroll?this.getElementBottomDistance():this.getWindowBottomDistance()},i.getWindowBottomDistance=function(){return this.top+this.element.clientHeight-(t.pageYOffset+this.windowHeight)},i.getElementBottomDistance=function(){return this.scroller.scrollHeight-(this.scroller.scrollTop+this.scroller.clientHeight)},i.onResize=function(){this.updateMeasurements()},n.debounceMethod(e,"onResize",150),e})},"A/e+":function(t,e,n){var i=n("VU/8")(n("5m3O"),n("ITff"),!1,function(t){n("SZtu")},"data-v-6c5fc404",null);t.exports=i.exports},BXHd:function(t,e){$(document).ready(function(){$(document).on("submit",".bookmark-form",function(t){t.preventDefault();var e=$(this).data("id");axios.post("/i/bookmark",{item:e})})})},"Bx+d":function(t,e,n){"use strict";function i(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e");i.addClass(e[0].filter_class);var r=$("");if(r.attr("src",e[0].url),r.attr("title",e[0].description),i.append(r),1==n.sensitive){var o=n.spoiler_text?n.spoiler_text:"CW / NSFW / Hidden Media",a=$("
").addClass("details-animated"),s=$(""),l=$("

").addClass("mb-0 lead font-weight-bold").text(o),c=$("

").addClass("font-weight-light").text("(click to show)");s.append(l,c),a.append(s,i),t.append(a)}else t.append(i)},video:function(t,e,n){var i=$("

");i.addClass("");var r=$("