1
0
Fork 0

Merge pull request #1989 from pixelfed/staging

Bug fixes
This commit is contained in:
daniel 2020-02-09 19:54:41 -07:00 committed by GitHub
commit a87c236c00
21 changed files with 548 additions and 90 deletions

View File

@ -10,6 +10,8 @@
- Updated RateLimit, add max post edits per hour and day ([51fbfcdc](https://github.com/pixelfed/pixelfed/commit/51fbfcdc))
- Updated Timeline.vue, move announcements from sidebar to top of timeline ([228f5044](https://github.com/pixelfed/pixelfed/commit/228f5044))
- Updated lexer autolinker and extractor, add support for mentioned usernames containing dashes, periods and underscore characters ([f911c96d](https://github.com/pixelfed/pixelfed/commit/f911c96d))
- Updated Story apis, move FE to v0 and add v1 for oauth clients ([92654fab](https://github.com/pixelfed/pixelfed/commit/92654fab))
- Updated robots.txt ([25101901](https://github.com/pixelfed/pixelfed/commit/25101901))
## [v0.10.8 (2020-01-29)](https://github.com/pixelfed/pixelfed/compare/v0.10.7...v0.10.8)
### Added

View File

@ -44,6 +44,47 @@ class StoryGC extends Command
* @return mixed
*/
public function handle()
{
$this->directoryScan();
$this->deleteViews();
$this->deleteStories();
}
protected function directoryScan()
{
$day = now()->day;
if($day !== 3) {
return;
}
$monthHash = substr(hash('sha1', date('Y').date('m')), 0, 12);
$t1 = Storage::directories('public/_esm.t1');
$t2 = Storage::directories('public/_esm.t2');
$dirs = array_merge($t1, $t2);
foreach($dirs as $dir) {
$hash = last(explode('/', $dir));
if($hash != $monthHash) {
$this->info('Found directory to delete: ' . $dir);
$this->deleteDirectory($dir);
}
}
}
protected function deleteDirectory($path)
{
Storage::deleteDirectory($path);
}
protected function deleteViews()
{
StoryView::where('created_at', '<', now()->subDays(2))->delete();
}
protected function deleteStories()
{
$stories = Story::where('expires_at', '<', now())->take(50)->get();

View File

@ -44,7 +44,10 @@ use App\Jobs\VideoPipeline\{
VideoPostProcess,
VideoThumbnail
};
use App\Services\NotificationService;
use App\Services\{
NotificationService,
SearchApiV2Service
};
class ApiV1Controller extends Controller
{
@ -367,15 +370,15 @@ class ApiV1Controller extends Controller
$user = $request->user();
$target = Profile::where('id', '!=', $user->id)
$target = Profile::where('id', '!=', $user->profile_id)
->whereNull('status')
->findOrFail($item);
->findOrFail($id);
$private = (bool) $target->is_private;
$remote = (bool) $target->domain;
$blocked = UserFilter::whereUserId($target->id)
->whereFilterType('block')
->whereFilterableId($user->id)
->whereFilterableId($user->profile_id)
->whereFilterableType('App\Profile')
->exists();
@ -383,7 +386,7 @@ class ApiV1Controller extends Controller
abort(400, 'You cannot follow this user.');
}
$isFollowing = Follower::whereProfileId($user->id)
$isFollowing = Follower::whereProfileId($user->profile_id)
->whereFollowingId($target->id)
->exists();
@ -396,42 +399,42 @@ class ApiV1Controller extends Controller
}
// Rate limits, max 7500 followers per account
if($user->following()->count() >= Follower::MAX_FOLLOWING) {
if($user->profile->following()->count() >= Follower::MAX_FOLLOWING) {
abort(400, 'You cannot follow more than ' . Follower::MAX_FOLLOWING . ' accounts');
}
// Rate limits, follow 30 accounts per hour max
if($user->following()->where('followers.created_at', '>', now()->subHour())->count() >= Follower::FOLLOW_PER_HOUR) {
if($user->profile->following()->where('followers.created_at', '>', now()->subHour())->count() >= Follower::FOLLOW_PER_HOUR) {
abort(400, 'You can only follow ' . Follower::FOLLOW_PER_HOUR . ' users per hour');
}
if($private == true) {
$follow = FollowRequest::firstOrCreate([
'follower_id' => $user->id,
'follower_id' => $user->profile_id,
'following_id' => $target->id
]);
if($remote == true && config('federation.activitypub.remoteFollow') == true) {
(new FollowerController())->sendFollow($user, $target);
(new FollowerController())->sendFollow($user->profile, $target);
}
} else {
$follower = new Follower();
$follower->profile_id = $user->id;
$follower->profile_id = $user->profile_id;
$follower->following_id = $target->id;
$follower->save();
if($remote == true && config('federation.activitypub.remoteFollow') == true) {
(new FollowerController())->sendFollow($user, $target);
(new FollowerController())->sendFollow($user->profile, $target);
}
FollowPipeline::dispatch($follower);
}
Cache::forget('profile:following:'.$target->id);
Cache::forget('profile:followers:'.$target->id);
Cache::forget('profile:following:'.$user->id);
Cache::forget('profile:followers:'.$user->id);
Cache::forget('api:local:exp:rec:'.$user->id);
Cache::forget('profile:following:'.$user->profile_id);
Cache::forget('profile:followers:'.$user->profile_id);
Cache::forget('api:local:exp:rec:'.$user->profile_id);
Cache::forget('user:account:id:'.$target->user_id);
Cache::forget('user:account:id:'.$user->user_id);
Cache::forget('user:account:id:'.$user->id);
$resource = new Fractal\Resource\Item($target, new RelationshipTransformer());
$res = $this->fractal->createData($resource)->toArray();
@ -452,14 +455,14 @@ class ApiV1Controller extends Controller
$user = $request->user();
$target = Profile::where('id', '!=', $user->id)
$target = Profile::where('id', '!=', $user->profile_id)
->whereNull('status')
->findOrFail($item);
->findOrFail($id);
$private = (bool) $target->is_private;
$remote = (bool) $target->domain;
$isFollowing = Follower::whereProfileId($user->id)
$isFollowing = Follower::whereProfileId($user->profile_id)
->whereFollowingId($target->id)
->exists();
@ -471,29 +474,29 @@ class ApiV1Controller extends Controller
}
// Rate limits, follow 30 accounts per hour max
if($user->following()->where('followers.updated_at', '>', now()->subHour())->count() >= Follower::FOLLOW_PER_HOUR) {
if($user->profile->following()->where('followers.updated_at', '>', now()->subHour())->count() >= Follower::FOLLOW_PER_HOUR) {
abort(400, 'You can only follow or unfollow ' . Follower::FOLLOW_PER_HOUR . ' users per hour');
}
FollowRequest::whereFollowerId($user->id)
FollowRequest::whereFollowerId($user->profile_id)
->whereFollowingId($target->id)
->delete();
Follower::whereProfileId($user->id)
Follower::whereProfileId($user->profile_id)
->whereFollowingId($target->id)
->delete();
if($remote == true && config('federation.activitypub.remoteFollow') == true) {
(new FollowerController())->sendUndoFollow($user, $target);
(new FollowerController())->sendUndoFollow($user->profile, $target);
}
Cache::forget('profile:following:'.$target->id);
Cache::forget('profile:followers:'.$target->id);
Cache::forget('profile:following:'.$user->id);
Cache::forget('profile:followers:'.$user->id);
Cache::forget('api:local:exp:rec:'.$user->id);
Cache::forget('profile:following:'.$user->profile_id);
Cache::forget('profile:followers:'.$user->profile_id);
Cache::forget('api:local:exp:rec:'.$user->profile_id);
Cache::forget('user:account:id:'.$target->user_id);
Cache::forget('user:account:id:'.$user->user_id);
Cache::forget('user:account:id:'.$user->id);
$resource = new Fractal\Resource\Item($target, new RelationshipTransformer());
$res = $this->fractal->createData($resource)->toArray();
@ -1164,34 +1167,43 @@ class ApiV1Controller extends Controller
public function accountNotifications(Request $request)
{
abort_if(!$request->user(), 403);
$this->validate($request, [
'page' => 'nullable|integer|min:1|max:10',
'limit' => 'nullable|integer|min:1|max:80',
'max_id' => 'nullable|integer|min:1',
'min_id' => 'nullable|integer|min:0',
'min_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
'max_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
'since_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
]);
$pid = $request->user()->profile_id;
$limit = $request->input('limit') ?? 20;
$limit = $request->input('limit', 20);
$timeago = now()->subMonths(6);
$since = $request->input('since_id');
$min = $request->input('min_id');
$max = $request->input('max_id');
if($min || $max) {
$dir = $min ? '>' : '<';
$id = $min ?? $max;
$notifications = Notification::whereProfileId($pid)
->whereDate('created_at', '>', $timeago)
->where('id', $dir, $id)
->orderByDesc('created_at')
->limit($limit)
->get();
} else {
$notifications = Notification::whereProfileId($pid)
->whereDate('created_at', '>', $timeago)
->orderByDesc('created_at')
->simplePaginate($limit);
}
$resource = new Fractal\Resource\Collection($notifications, new NotificationTransformer());
$res = $this->fractal->createData($resource)->toArray();
abort_if(!$since && !$min && !$max, 400);
$dir = $since ? '>' : ($min ? '>=' : '<');
$id = $since ?? $min ?? $max;
$notifications = Notification::whereProfileId($pid)
->where('id', $dir, $id)
->whereDate('created_at', '>', $timeago)
->orderByDesc('id')
->limit($limit)
->get();
$resource = new Fractal\Resource\Collection(
$notifications,
new NotificationTransformer()
);
$res = $this->fractal
->createData($resource)
->toArray();
return response()->json($res);
}
@ -1696,4 +1708,30 @@ class ApiV1Controller extends Controller
$res = [];
return response()->json($res);
}
/**
* GET /api/v2/search
*
*
* @return array
*/
public function searchV2(Request $request)
{
abort_if(!$request->user(), 403);
$this->validate($request, [
'q' => 'required|string|min:1|max:80',
'account_id' => 'nullable|string',
'max_id' => 'nullable|string',
'min_id' => 'nullable|string',
'type' => 'nullable|in:accounts,hashtags,statuses',
'exclude_unreviewed' => 'nullable',
'resolve' => 'nullable',
'limit' => 'nullable|integer|max:40',
'offset' => 'nullable|integer',
'following' => 'nullable'
]);
return SearchApiV2Service::query($request);
}
}

View File

@ -16,12 +16,6 @@ use App\Services\FollowerService;
class StoryController extends Controller
{
public function construct()
{
$this->middleware('auth');
}
public function apiV1Add(Request $request)
{
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
@ -66,8 +60,8 @@ class StoryController extends Controller
protected function storePhoto($photo)
{
$monthHash = substr(hash('sha1', date('Y').date('m')), 0, 12);
$sid = Str::uuid();
$rid = Str::random(6).'.'.Str::random(9);
$sid = (string) Str::uuid();
$rid = Str::random(9).'.'.Str::random(9);
$mimes = explode(',', config('pixelfed.media_types'));
if(in_array($photo->getMimeType(), [
'image/jpeg',
@ -77,7 +71,7 @@ class StoryController extends Controller
return;
}
$storagePath = "public/_esm.t1/{$monthHash}/{$sid}/{$rid}";
$storagePath = "public/_esm.t2/{$monthHash}/{$sid}/{$rid}";
$path = $photo->store($storagePath);
$fpath = storage_path('app/' . $path);
$img = Intervention::make($fpath);
@ -175,6 +169,39 @@ class StoryController extends Controller
return response()->json($stories, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function apiV1Item(Request $request, $id)
{
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
$authed = $request->user()->profile;
$story = Story::with('profile')
->where('expires_at', '>', now())
->findOrFail($id);
$profile = $story->profile;
if($story->profile_id == $authed->id) {
$publicOnly = true;
} else {
$publicOnly = (bool) $profile->followedBy($authed);
}
abort_if(!$publicOnly, 403);
$res = [
'id' => (string) $story->id,
'type' => 'photo',
'length' => 3,
'src' => url(Storage::url($story->path)),
'preview' => null,
'link' => null,
'linkText' => null,
'time' => $story->created_at->format('U'),
'expires_at' => (int) $story->expires_at->format('U'),
'seen' => $story->seen()
];
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function apiV1Profile(Request $request, $id)
{
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
@ -232,24 +259,33 @@ class StoryController extends Controller
$this->validate($request, [
'id' => 'required|integer|min:1|exists:stories',
]);
$id = $request->input('id');
$authed = $request->user()->profile;
$story = Story::with('profile')
->where('expires_at', '>', now())
->orderByDesc('expires_at')
->findOrFail($id);
$profile = $story->profile;
if($story->profile_id == $authed->id) {
$publicOnly = true;
} else {
$publicOnly = (bool) $profile->followedBy($authed);
}
abort_if(!$publicOnly, 403);
StoryView::firstOrCreate([
'story_id' => $request->input('id'),
'profile_id' => $request->user()->profile_id
'story_id' => $id,
'profile_id' => $authed->id
]);
return ['code' => 200];
}
public function compose(Request $request)
{
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
return view('stories.compose');
}
public function apiV1Exists(Request $request, $id)
{
abort_if(!config('instance.stories.enabled'), 404);
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
$res = (bool) Story::whereProfileId($id)
->where('expires_at', '>', now())
@ -258,8 +294,54 @@ class StoryController extends Controller
return response()->json($res);
}
public function apiV1Me(Request $request)
{
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
$profile = $request->user()->profile;
$stories = Story::whereProfileId($profile->id)
->orderBy('expires_at')
->where('expires_at', '>', now())
->get()
->map(function($s, $k) {
return [
'id' => $s->id,
'type' => 'photo',
'length' => 3,
'src' => url(Storage::url($s->path)),
'preview' => null,
'link' => null,
'linkText' => null,
'time' => $s->created_at->format('U'),
'expires_at' => (int) $s->expires_at->format('U'),
'seen' => true
];
})->toArray();
$ts = count($stories) ? last($stories)['time'] : null;
$res = [
'id' => (string) $profile->id,
'photo' => $profile->avatarUrl(),
'name' => $profile->username,
'link' => $profile->url(),
'lastUpdated' => $ts,
'seen' => true,
'items' => $stories
];
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function compose(Request $request)
{
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
return view('stories.compose');
}
public function iRedirect(Request $request)
{
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
$user = $request->user();
abort_if(!$user, 404);
$username = $user->username;

View File

@ -0,0 +1,234 @@
<?php
namespace App\Services;
use Cache;
use Illuminate\Support\Facades\Redis;
use App\{Hashtag, Profile, Status};
use App\Transformer\Api\AccountTransformer;
use App\Transformer\Api\StatusTransformer;
use League\Fractal;
use League\Fractal\Serializer\ArraySerializer;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use App\Util\ActivityPub\Helpers;
use Illuminate\Support\Str;
class SearchApiV2Service
{
private $query;
public static function query($query)
{
return (new self)->run($query);
}
protected function run($query)
{
$this->query = $query;
if($query->has('resolve') &&
$query->resolve == true &&
Helpers::validateUrl(urldecode($query->input('q')))
) {
return $this->resolve();
}
if($query->has('type')) {
switch ($query->input('type')) {
case 'accounts':
return [
'accounts' => $this->accounts(),
'hashtags' => [],
'statuses' => []
];
break;
case 'hashtags':
return [
'accounts' => [],
'hashtags' => $this->hashtags(),
'statuses' => []
];
break;
case 'statuses':
return [
'accounts' => [],
'hashtags' => [],
'statuses' => $this->statuses()
];
break;
}
}
if($query->has('account_id')) {
return [
'accounts' => [],
'hashtags' => [],
'statuses' => $this->statusesById()
];
}
return [
'accounts' => $this->accounts(),
'hashtags' => $this->hashtags(),
'statuses' => $this->statuses()
];
}
protected function resolve()
{
$query = urldecode($this->query->input('q'));
if(Str::startsWith($query, '@') == true) {
return WebfingerService::lookup($this->query->input('q'));
} else if (Str::startsWith($query, 'https://') == true) {
return $this->resolveQuery();
}
}
protected function accounts()
{
$limit = $this->query->input('limit', 20);
$query = '%' . $this->query->input('q') . '%';
$results = Profile::whereNull('status')
->where('username', 'like', $query)
->when($this->query->input('offset') != null, function($q, $offset) {
return $q->offset($offset);
})
->limit($limit)
->get();
$fractal = new Fractal\Manager();
$fractal->setSerializer(new ArraySerializer());
$resource = new Fractal\Resource\Collection($results, new AccountTransformer());
return $fractal->createData($resource)->toArray();
}
protected function hashtags()
{
$limit = $this->query->input('limit', 20);
$query = '%' . $this->query->input('q') . '%';
return Hashtag::whereIsBanned(false)
->where('name', 'like', $query)
->when($this->query->input('offset') != null, function($q, $offset) {
return $q->offset($offset);
})
->limit($limit)
->get()
->map(function($tag) {
return [
'name' => $tag->name,
'url' => $tag->url(),
'history' => []
];
});
}
protected function statuses()
{
$limit = $this->query->input('limit', 20);
$query = '%' . $this->query->input('q') . '%';
$results = Status::where('caption', 'like', $query)
->whereScope('public')
->when($this->query->input('offset') != null, function($q, $offset) {
return $q->offset($offset);
})
->limit($limit)
->orderByDesc('created_at')
->get();
$fractal = new Fractal\Manager();
$fractal->setSerializer(new ArraySerializer());
$resource = new Fractal\Resource\Collection($results, new StatusTransformer());
return $fractal->createData($resource)->toArray();
}
protected function statusesById()
{
$accountId = $this->query->input('account_id');
$limit = $this->query->input('limit', 20);
$query = '%' . $this->query->input('q') . '%';
$results = Status::where('caption', 'like', $query)
->whereProfileId($accountId)
->when($this->query->input('offset') != null, function($q, $offset) {
return $q->offset($offset);
})
->limit($limit)
->get();
$fractal = new Fractal\Manager();
$fractal->setSerializer(new ArraySerializer());
$resource = new Fractal\Resource\Collection($results, new StatusTransformer());
return $fractal->createData($resource)->toArray();
}
protected function resolveQuery()
{
$query = urldecode($this->query->input('q'));
if(Helpers::validateLocalUrl($query)) {
if(Str::contains($query, '/p/')) {
return $this->resolveLocalStatus();
} else {
return $this->resolveLocalProfile();
}
} else {
return [
'accounts' => [],
'hashtags' => [],
'statuses' => []
];
}
}
protected function resolveLocalStatus()
{
$query = urldecode($this->query->input('q'));
$query = last(explode('/', $query));
$status = Status::whereNull('uri')
->whereScope('public')
->find($query);
if(!$status) {
return [
'accounts' => [],
'hashtags' => [],
'statuses' => []
];
}
$fractal = new Fractal\Manager();
$fractal->setSerializer(new ArraySerializer());
$resource = new Fractal\Resource\Item($status, new StatusTransformer());
return [
'accounts' => [],
'hashtags' => [],
'statuses' => $fractal->createData($resource)->toArray()
];
}
protected function resolveLocalProfile()
{
$query = urldecode($this->query->input('q'));
$query = last(explode('/', $query));
$profile = Profile::whereNull('status')
->whereNull('domain')
->whereUsername($query)
->first();
if(!$profile) {
return [
'accounts' => [],
'hashtags' => [],
'statuses' => []
];
}
$fractal = new Fractal\Manager();
$fractal->setSerializer(new ArraySerializer());
$resource = new Fractal\Resource\Item($profile, new AccountTransformer());
return [
'accounts' => $fractal->createData($resource)->toArray(),
'hashtags' => [],
'statuses' => []
];
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Services;
use Cache;
use Illuminate\Support\Facades\Redis;
use App\Util\Webfinger\WebfingerUrl;
use Zttp\Zttp;
use App\Util\ActivityPub\Helpers;
use App\Transformer\Api\AccountTransformer;
use League\Fractal;
use League\Fractal\Serializer\ArraySerializer;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
class WebfingerService
{
public static function lookup($query)
{
return (new self)->run($query);
}
protected function run($query)
{
$url = WebfingerUrl::generateWebfingerUrl($query);
if(!Helpers::validateUrl($url)) {
return [];
}
$res = Zttp::get($url);
$webfinger = $res->json();
if(!isset($webfinger['links'])) {
return [];
}
$profile = Helpers::profileFetch($webfinger['links'][0]['href']);
$fractal = new Fractal\Manager();
$fractal->setSerializer(new ArraySerializer());
$resource = new Fractal\Resource\Item($profile, new AccountTransformer());
$res = $fractal->createData($resource)->toArray();
return $res;
}
}

File diff suppressed because one or more lines are too long

2
public/js/status.js 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

@ -4,9 +4,9 @@
"/js/ace.js": "/js/ace.js?id=a575b37c2085b5003666",
"/js/activity.js": "/js/activity.js?id=028cbbe598f925bb3414",
"/js/app.js": "/js/app.js?id=360dc653e947aa970981",
"/css/app.css": "/css/app.css?id=293968cda6f2d640178a",
"/css/app.css": "/css/app.css?id=d5460a8e4a191926137e",
"/css/appdark.css": "/css/appdark.css?id=cc58358d958b0496f87e",
"/css/landing.css": "/css/landing.css?id=9af4c611557edf0f7e31",
"/css/landing.css": "/css/landing.css?id=fc8a5523ec7670d4a9bc",
"/css/quill.css": "/css/quill.css?id=e3741782d15a3031f785",
"/js/collectioncompose.js": "/js/collectioncompose.js?id=3fd79944492361ec7347",
"/js/collections.js": "/js/collections.js?id=38be4150f3d2ebb15f50",
@ -18,12 +18,12 @@
"/js/hashtag.js": "/js/hashtag.js?id=e6b41cab117cb03c7d2a",
"/js/loops.js": "/js/loops.js?id=ac610897b12207c829b9",
"/js/mode-dot.js": "/js/mode-dot.js?id=1225a9aac7a93d5d232f",
"/js/profile.js": "/js/profile.js?id=2370d5629003b30a605f",
"/js/profile.js": "/js/profile.js?id=4fd453802d18d4b7593d",
"/js/profile-directory.js": "/js/profile-directory.js?id=7160b00d9beda164f1bc",
"/js/quill.js": "/js/quill.js?id=9b15ab0ae830e7293390",
"/js/search.js": "/js/search.js?id=22e8bccee621e57963d9",
"/js/status.js": "/js/status.js?id=c0058d6c5fecb0bc96c0",
"/js/story-compose.js": "/js/story-compose.js?id=0a2ac08ac4dbc66b105f",
"/js/status.js": "/js/status.js?id=14240dabd093541f39b5",
"/js/story-compose.js": "/js/story-compose.js?id=d0e4923e743ace0f5144",
"/js/theme-monokai.js": "/js/theme-monokai.js?id=39b089458f249e8717ad",
"/js/timeline.js": "/js/timeline.js?id=0548db240e700b82806f"
"/js/timeline.js": "/js/timeline.js?id=cf2d4040b15130537379"
}

View File

@ -1,2 +1,4 @@
User-agent: *
Disallow:
Disallow: /discover/places/
Disallow: /stories/
Disallow: /i/

View File

@ -680,6 +680,7 @@ export default {
let self = this;
self.status = response.data.status;
self.user = response.data.user;
window._sharedData.curUser = self.user;
self.media = self.status.media_attachments;
self.reactions = response.data.reactions;
self.likes = response.data.likes;

View File

@ -642,7 +642,7 @@
axios.get('/api/pixelfed/v1/accounts/verify_credentials').then(res => {
this.user = res.data;
if(res.data.id == this.profileId || this.relationship.following == true) {
axios.get('/api/stories/v1/exists/' + this.profileId)
axios.get('/api/stories/v0/exists/' + this.profileId)
.then(res => {
this.hasStory = res.data == true;
})

View File

@ -177,7 +177,7 @@
mounted() {
this.mediaWatcher();
axios.get('/api/stories/v1/fetch/' + this.profileId)
axios.get('/api/stories/v0/fetch/' + this.profileId)
.then(res => this.stories = res.data);
},
@ -226,7 +226,7 @@
}
};
axios.post('/api/stories/v1/add', form, xhrConfig)
axios.post('/api/stories/v0/add', form, xhrConfig)
.then(function(e) {
self.uploadProgress = 100;
self.uploading = false;
@ -264,7 +264,7 @@
return;
}
axios.delete('/api/stories/v1/delete/' + story.id)
axios.delete('/api/stories/v0/delete/' + story.id)
.then(res => {
this.stories.splice(index, 1);
if(this.stories.length == 0) {

View File

@ -30,7 +30,7 @@
methods: {
fetchStories() {
axios.get('/api/stories/v1/recent')
axios.get('/api/stories/v0/recent')
.then(res => {
let data = res.data;
let stories = new Zuck('storyContainer', {
@ -57,7 +57,7 @@
});
data.forEach(d => {
let url = '/api/stories/v1/fetch/' + d.pid;
let url = '/api/stories/v0/fetch/' + d.pid;
axios.get(url)
.then(res => {
res.data.forEach(item => {

View File

@ -36,7 +36,7 @@
methods: {
fetchStories() {
axios.get('/api/stories/v1/profile/' + this.pid)
axios.get('/api/stories/v0/profile/' + this.pid)
.then(res => {
let data = res.data;
if(data.length == 0) {

View File

@ -1424,7 +1424,7 @@
},
hasStory() {
axios.get('/api/stories/v1/exists/'+this.profile.id)
axios.get('/api/stories/v0/exists/'+this.profile.id)
.then(res => {
this.userStory = res.data;
})

View File

@ -21,3 +21,5 @@ $white: white;
$theme-colors: (
'primary': #08d
);
$card-cap-bg: $white;

View File

@ -67,4 +67,18 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
Route::get('timelines/public', 'Api\ApiV1Controller@timelinePublic');
Route::get('timelines/tag/{hashtag}', 'Api\ApiV1Controller@timelineHashtag')->middleware($middleware);
});
Route::group(['prefix' => 'stories'], function () use($middleware) {
Route::get('v1/me', 'StoryController@apiV1Me');
Route::get('v1/recent', 'StoryController@apiV1Recent');
Route::post('v1/add', 'StoryController@apiV1Add')->middleware(array_merge($middleware, ['throttle:maxStoriesPerDay,1440']));
Route::get('v1/item/{id}', 'StoryController@apiV1Item');
Route::get('v1/fetch/{id}', 'StoryController@apiV1Fetch');
Route::get('v1/profile/{id}', 'StoryController@apiV1Profile');
Route::get('v1/exists/{id}', 'StoryController@apiV1Exists');
Route::delete('v1/delete/{id}', 'StoryController@apiV1Delete')->middleware(array_merge($middleware, ['throttle:maxStoryDeletePerDay,1440']));
Route::post('v1/viewed', 'StoryController@apiV1Viewed');
});
Route::group(['prefix' => 'v2'], function() use($middleware) {
Route::get('search', 'Api\ApiV1Controller@searchV2')->middleware($middleware);
});
});

View File

@ -179,12 +179,14 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::post('moderate', 'Api\AdminApiController@moderate');
});
Route::group(['prefix' => 'stories'], function () {
Route::get('v1/recent', 'StoryController@apiV1Recent');
Route::post('v1/add', 'StoryController@apiV1Add')->middleware('throttle:maxStoriesPerDay,1440');
Route::get('v1/fetch/{id}', 'StoryController@apiV1Fetch');
Route::get('v1/profile/{id}', 'StoryController@apiV1Profile');
Route::get('v1/exists/{id}', 'StoryController@apiV1Exists');
Route::delete('v1/delete/{id}', 'StoryController@apiV1Delete')->middleware('throttle:maxStoryDeletePerDay,1440');
Route::get('v0/recent', 'StoryController@apiV1Recent');
Route::post('v0/add', 'StoryController@apiV1Add')->middleware('throttle:maxStoriesPerDay,1440');
Route::get('v0/fetch/{id}', 'StoryController@apiV1Fetch');
Route::get('v0/profile/{id}', 'StoryController@apiV1Profile');
Route::get('v0/exists/{id}', 'StoryController@apiV1Exists');
Route::delete('v0/delete/{id}', 'StoryController@apiV1Delete')->middleware('throttle:maxStoryDeletePerDay,1440');
Route::get('v0/me', 'StoryController@apiV1Me');
Route::get('v0/item/{id}', 'StoryController@apiV1Item');
});
});