diff --git a/app/Http/Controllers/Api/BaseApiController.php b/app/Http/Controllers/Api/BaseApiController.php index 61c8b9e8b..ad717dfe6 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 d21b8eaba..fb4cdcde9 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 440effd86..637dde844 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 d7ab96480..fa12c9392 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 5ce51eb89..417692855 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 5dc6599ee..4176a3101 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 4ac5c6be2..8ab38fc6f 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 d5afa1b60..16d537c97 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 131a1959c..ca1b4be2d 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 a77f1ee82..8545e1add 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 7f21d6449..6c173a69e 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 3998e2e55..28802d7b0 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=$("