mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-25 15:55:22 +00:00
Update StoryController, add parental controls support
This commit is contained in:
parent
fe30cd25d1
commit
71c148c61e
2 changed files with 645 additions and 614 deletions
|
@ -29,306 +29,315 @@ use App\Jobs\StoryPipeline\StoryFanout;
|
||||||
use App\Jobs\StoryPipeline\StoryDelete;
|
use App\Jobs\StoryPipeline\StoryDelete;
|
||||||
use ImageOptimizer;
|
use ImageOptimizer;
|
||||||
use App\Models\Conversation;
|
use App\Models\Conversation;
|
||||||
|
use App\Services\UserRoleService;
|
||||||
|
|
||||||
class StoryComposeController extends Controller
|
class StoryComposeController extends Controller
|
||||||
{
|
{
|
||||||
public function apiV1Add(Request $request)
|
public function apiV1Add(Request $request)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'file' => function() {
|
'file' => function() {
|
||||||
return [
|
return [
|
||||||
'required',
|
'required',
|
||||||
'mimetypes:image/jpeg,image/png,video/mp4',
|
'mimetypes:image/jpeg,image/png,video/mp4',
|
||||||
'max:' . config_cache('pixelfed.max_photo_size'),
|
'max:' . config_cache('pixelfed.max_photo_size'),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
$count = Story::whereProfileId($user->profile_id)
|
||||||
|
->whereActive(true)
|
||||||
|
->where('expires_at', '>', now())
|
||||||
|
->count();
|
||||||
|
|
||||||
$count = Story::whereProfileId($user->profile_id)
|
if($count >= Story::MAX_PER_DAY) {
|
||||||
->whereActive(true)
|
abort(418, 'You have reached your limit for new Stories today.');
|
||||||
->where('expires_at', '>', now())
|
}
|
||||||
->count();
|
|
||||||
|
|
||||||
if($count >= Story::MAX_PER_DAY) {
|
$photo = $request->file('file');
|
||||||
abort(418, 'You have reached your limit for new Stories today.');
|
$path = $this->storePhoto($photo, $user);
|
||||||
}
|
|
||||||
|
|
||||||
$photo = $request->file('file');
|
$story = new Story();
|
||||||
$path = $this->storePhoto($photo, $user);
|
$story->duration = 3;
|
||||||
|
$story->profile_id = $user->profile_id;
|
||||||
|
$story->type = Str::endsWith($photo->getMimeType(), 'mp4') ? 'video' :'photo';
|
||||||
|
$story->mime = $photo->getMimeType();
|
||||||
|
$story->path = $path;
|
||||||
|
$story->local = true;
|
||||||
|
$story->size = $photo->getSize();
|
||||||
|
$story->bearcap_token = str_random(64);
|
||||||
|
$story->expires_at = now()->addMinutes(1440);
|
||||||
|
$story->save();
|
||||||
|
|
||||||
$story = new Story();
|
$url = $story->path;
|
||||||
$story->duration = 3;
|
|
||||||
$story->profile_id = $user->profile_id;
|
|
||||||
$story->type = Str::endsWith($photo->getMimeType(), 'mp4') ? 'video' :'photo';
|
|
||||||
$story->mime = $photo->getMimeType();
|
|
||||||
$story->path = $path;
|
|
||||||
$story->local = true;
|
|
||||||
$story->size = $photo->getSize();
|
|
||||||
$story->bearcap_token = str_random(64);
|
|
||||||
$story->expires_at = now()->addMinutes(1440);
|
|
||||||
$story->save();
|
|
||||||
|
|
||||||
$url = $story->path;
|
$res = [
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'Successfully added',
|
||||||
|
'media_id' => (string) $story->id,
|
||||||
|
'media_url' => url(Storage::url($url)) . '?v=' . time(),
|
||||||
|
'media_type' => $story->type
|
||||||
|
];
|
||||||
|
|
||||||
$res = [
|
if($story->type === 'video') {
|
||||||
'code' => 200,
|
$video = FFMpeg::open($path);
|
||||||
'msg' => 'Successfully added',
|
$duration = $video->getDurationInSeconds();
|
||||||
'media_id' => (string) $story->id,
|
$res['media_duration'] = $duration;
|
||||||
'media_url' => url(Storage::url($url)) . '?v=' . time(),
|
if($duration > 500) {
|
||||||
'media_type' => $story->type
|
Storage::delete($story->path);
|
||||||
];
|
$story->delete();
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Video duration cannot exceed 60 seconds'
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($story->type === 'video') {
|
return $res;
|
||||||
$video = FFMpeg::open($path);
|
}
|
||||||
$duration = $video->getDurationInSeconds();
|
|
||||||
$res['media_duration'] = $duration;
|
|
||||||
if($duration > 500) {
|
|
||||||
Storage::delete($story->path);
|
|
||||||
$story->delete();
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Video duration cannot exceed 60 seconds'
|
|
||||||
], 422);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $res;
|
protected function storePhoto($photo, $user)
|
||||||
}
|
{
|
||||||
|
$mimes = explode(',', config_cache('pixelfed.media_types'));
|
||||||
|
if(in_array($photo->getMimeType(), [
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'video/mp4'
|
||||||
|
]) == false) {
|
||||||
|
abort(400, 'Invalid media type');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
protected function storePhoto($photo, $user)
|
$storagePath = MediaPathService::story($user->profile);
|
||||||
{
|
$path = $photo->storePubliclyAs($storagePath, Str::random(random_int(2, 12)) . '_' . Str::random(random_int(32, 35)) . '_' . Str::random(random_int(1, 14)) . '.' . $photo->extension());
|
||||||
$mimes = explode(',', config_cache('pixelfed.media_types'));
|
if(in_array($photo->getMimeType(), ['image/jpeg','image/png'])) {
|
||||||
if(in_array($photo->getMimeType(), [
|
$fpath = storage_path('app/' . $path);
|
||||||
'image/jpeg',
|
$img = Intervention::make($fpath);
|
||||||
'image/png',
|
$img->orientate();
|
||||||
'video/mp4'
|
$img->save($fpath, config_cache('pixelfed.image_quality'));
|
||||||
]) == false) {
|
$img->destroy();
|
||||||
abort(400, 'Invalid media type');
|
}
|
||||||
return;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
$storagePath = MediaPathService::story($user->profile);
|
public function cropPhoto(Request $request)
|
||||||
$path = $photo->storePubliclyAs($storagePath, Str::random(random_int(2, 12)) . '_' . Str::random(random_int(32, 35)) . '_' . Str::random(random_int(1, 14)) . '.' . $photo->extension());
|
{
|
||||||
if(in_array($photo->getMimeType(), ['image/jpeg','image/png'])) {
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
$fpath = storage_path('app/' . $path);
|
|
||||||
$img = Intervention::make($fpath);
|
|
||||||
$img->orientate();
|
|
||||||
$img->save($fpath, config_cache('pixelfed.image_quality'));
|
|
||||||
$img->destroy();
|
|
||||||
}
|
|
||||||
return $path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cropPhoto(Request $request)
|
$this->validate($request, [
|
||||||
{
|
'media_id' => 'required|integer|min:1',
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
'width' => 'required',
|
||||||
|
'height' => 'required',
|
||||||
|
'x' => 'required',
|
||||||
|
'y' => 'required'
|
||||||
|
]);
|
||||||
|
|
||||||
$this->validate($request, [
|
$user = $request->user();
|
||||||
'media_id' => 'required|integer|min:1',
|
$id = $request->input('media_id');
|
||||||
'width' => 'required',
|
$width = round($request->input('width'));
|
||||||
'height' => 'required',
|
$height = round($request->input('height'));
|
||||||
'x' => 'required',
|
$x = round($request->input('x'));
|
||||||
'y' => 'required'
|
$y = round($request->input('y'));
|
||||||
]);
|
|
||||||
|
|
||||||
$user = $request->user();
|
$story = Story::whereProfileId($user->profile_id)->findOrFail($id);
|
||||||
$id = $request->input('media_id');
|
|
||||||
$width = round($request->input('width'));
|
|
||||||
$height = round($request->input('height'));
|
|
||||||
$x = round($request->input('x'));
|
|
||||||
$y = round($request->input('y'));
|
|
||||||
|
|
||||||
$story = Story::whereProfileId($user->profile_id)->findOrFail($id);
|
$path = storage_path('app/' . $story->path);
|
||||||
|
|
||||||
$path = storage_path('app/' . $story->path);
|
if(!is_file($path)) {
|
||||||
|
abort(400, 'Invalid or missing media.');
|
||||||
|
}
|
||||||
|
|
||||||
if(!is_file($path)) {
|
if($story->type === 'photo') {
|
||||||
abort(400, 'Invalid or missing media.');
|
$img = Intervention::make($path);
|
||||||
}
|
$img->crop($width, $height, $x, $y);
|
||||||
|
$img->resize(1080, 1920, function ($constraint) {
|
||||||
|
$constraint->aspectRatio();
|
||||||
|
});
|
||||||
|
$img->save($path, config_cache('pixelfed.image_quality'));
|
||||||
|
}
|
||||||
|
|
||||||
if($story->type === 'photo') {
|
return [
|
||||||
$img = Intervention::make($path);
|
'code' => 200,
|
||||||
$img->crop($width, $height, $x, $y);
|
'msg' => 'Successfully cropped',
|
||||||
$img->resize(1080, 1920, function ($constraint) {
|
];
|
||||||
$constraint->aspectRatio();
|
}
|
||||||
});
|
|
||||||
$img->save($path, config_cache('pixelfed.image_quality'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
public function publishStory(Request $request)
|
||||||
'code' => 200,
|
{
|
||||||
'msg' => 'Successfully cropped',
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function publishStory(Request $request)
|
$this->validate($request, [
|
||||||
{
|
'media_id' => 'required',
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
'duration' => 'required|integer|min:3|max:120',
|
||||||
|
'can_reply' => 'required|boolean',
|
||||||
|
'can_react' => 'required|boolean'
|
||||||
|
]);
|
||||||
|
|
||||||
$this->validate($request, [
|
$id = $request->input('media_id');
|
||||||
'media_id' => 'required',
|
$user = $request->user();
|
||||||
'duration' => 'required|integer|min:3|max:120',
|
abort_if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id), 403, 'Invalid permissions for this action');
|
||||||
'can_reply' => 'required|boolean',
|
$story = Story::whereProfileId($user->profile_id)
|
||||||
'can_react' => 'required|boolean'
|
->findOrFail($id);
|
||||||
]);
|
|
||||||
|
|
||||||
$id = $request->input('media_id');
|
$story->active = true;
|
||||||
$user = $request->user();
|
$story->duration = $request->input('duration', 10);
|
||||||
$story = Story::whereProfileId($user->profile_id)
|
$story->can_reply = $request->input('can_reply');
|
||||||
->findOrFail($id);
|
$story->can_react = $request->input('can_react');
|
||||||
|
$story->save();
|
||||||
|
|
||||||
$story->active = true;
|
StoryService::delLatest($story->profile_id);
|
||||||
$story->duration = $request->input('duration', 10);
|
StoryFanout::dispatch($story)->onQueue('story');
|
||||||
$story->can_reply = $request->input('can_reply');
|
StoryService::addRotateQueue($story->id);
|
||||||
$story->can_react = $request->input('can_react');
|
|
||||||
$story->save();
|
|
||||||
|
|
||||||
StoryService::delLatest($story->profile_id);
|
return [
|
||||||
StoryFanout::dispatch($story)->onQueue('story');
|
'code' => 200,
|
||||||
StoryService::addRotateQueue($story->id);
|
'msg' => 'Successfully published',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
public function apiV1Delete(Request $request, $id)
|
||||||
'code' => 200,
|
{
|
||||||
'msg' => 'Successfully published',
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function apiV1Delete(Request $request, $id)
|
$user = $request->user();
|
||||||
{
|
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
|
||||||
|
|
||||||
$user = $request->user();
|
$story = Story::whereProfileId($user->profile_id)
|
||||||
|
->findOrFail($id);
|
||||||
|
$story->active = false;
|
||||||
|
$story->save();
|
||||||
|
|
||||||
$story = Story::whereProfileId($user->profile_id)
|
StoryDelete::dispatch($story)->onQueue('story');
|
||||||
->findOrFail($id);
|
|
||||||
$story->active = false;
|
|
||||||
$story->save();
|
|
||||||
|
|
||||||
StoryDelete::dispatch($story)->onQueue('story');
|
return [
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'Successfully deleted'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
public function compose(Request $request)
|
||||||
'code' => 200,
|
{
|
||||||
'msg' => 'Successfully deleted'
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
];
|
$user = $request->user();
|
||||||
}
|
abort_if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
|
||||||
public function compose(Request $request)
|
return view('stories.compose');
|
||||||
{
|
}
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
|
||||||
|
|
||||||
return view('stories.compose');
|
public function createPoll(Request $request)
|
||||||
}
|
{
|
||||||
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
abort_if(!config_cache('instance.polls.enabled'), 404);
|
||||||
|
|
||||||
public function createPoll(Request $request)
|
return $request->all();
|
||||||
{
|
}
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
|
||||||
abort_if(!config_cache('instance.polls.enabled'), 404);
|
|
||||||
|
|
||||||
return $request->all();
|
public function publishStoryPoll(Request $request)
|
||||||
}
|
{
|
||||||
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
|
||||||
public function publishStoryPoll(Request $request)
|
$this->validate($request, [
|
||||||
{
|
'question' => 'required|string|min:6|max:140',
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
'options' => 'required|array|min:2|max:4',
|
||||||
|
'can_reply' => 'required|boolean',
|
||||||
|
'can_react' => 'required|boolean'
|
||||||
|
]);
|
||||||
|
|
||||||
$this->validate($request, [
|
$user = $request->user();
|
||||||
'question' => 'required|string|min:6|max:140',
|
abort_if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id), 403, 'Invalid permissions for this action');
|
||||||
'options' => 'required|array|min:2|max:4',
|
$pid = $request->user()->profile_id;
|
||||||
'can_reply' => 'required|boolean',
|
|
||||||
'can_react' => 'required|boolean'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$pid = $request->user()->profile_id;
|
$count = Story::whereProfileId($pid)
|
||||||
|
->whereActive(true)
|
||||||
|
->where('expires_at', '>', now())
|
||||||
|
->count();
|
||||||
|
|
||||||
$count = Story::whereProfileId($pid)
|
if($count >= Story::MAX_PER_DAY) {
|
||||||
->whereActive(true)
|
abort(418, 'You have reached your limit for new Stories today.');
|
||||||
->where('expires_at', '>', now())
|
}
|
||||||
->count();
|
|
||||||
|
|
||||||
if($count >= Story::MAX_PER_DAY) {
|
$story = new Story;
|
||||||
abort(418, 'You have reached your limit for new Stories today.');
|
$story->type = 'poll';
|
||||||
}
|
$story->story = json_encode([
|
||||||
|
'question' => $request->input('question'),
|
||||||
|
'options' => $request->input('options')
|
||||||
|
]);
|
||||||
|
$story->public = false;
|
||||||
|
$story->local = true;
|
||||||
|
$story->profile_id = $pid;
|
||||||
|
$story->expires_at = now()->addMinutes(1440);
|
||||||
|
$story->duration = 30;
|
||||||
|
$story->can_reply = false;
|
||||||
|
$story->can_react = false;
|
||||||
|
$story->save();
|
||||||
|
|
||||||
$story = new Story;
|
$poll = new Poll;
|
||||||
$story->type = 'poll';
|
$poll->story_id = $story->id;
|
||||||
$story->story = json_encode([
|
$poll->profile_id = $pid;
|
||||||
'question' => $request->input('question'),
|
$poll->poll_options = $request->input('options');
|
||||||
'options' => $request->input('options')
|
$poll->expires_at = $story->expires_at;
|
||||||
]);
|
$poll->cached_tallies = collect($poll->poll_options)->map(function($o) {
|
||||||
$story->public = false;
|
return 0;
|
||||||
$story->local = true;
|
})->toArray();
|
||||||
$story->profile_id = $pid;
|
$poll->save();
|
||||||
$story->expires_at = now()->addMinutes(1440);
|
|
||||||
$story->duration = 30;
|
|
||||||
$story->can_reply = false;
|
|
||||||
$story->can_react = false;
|
|
||||||
$story->save();
|
|
||||||
|
|
||||||
$poll = new Poll;
|
$story->active = true;
|
||||||
$poll->story_id = $story->id;
|
$story->save();
|
||||||
$poll->profile_id = $pid;
|
|
||||||
$poll->poll_options = $request->input('options');
|
|
||||||
$poll->expires_at = $story->expires_at;
|
|
||||||
$poll->cached_tallies = collect($poll->poll_options)->map(function($o) {
|
|
||||||
return 0;
|
|
||||||
})->toArray();
|
|
||||||
$poll->save();
|
|
||||||
|
|
||||||
$story->active = true;
|
StoryService::delLatest($story->profile_id);
|
||||||
$story->save();
|
|
||||||
|
|
||||||
StoryService::delLatest($story->profile_id);
|
return [
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'Successfully published',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
public function storyPollVote(Request $request)
|
||||||
'code' => 200,
|
{
|
||||||
'msg' => 'Successfully published',
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function storyPollVote(Request $request)
|
$this->validate($request, [
|
||||||
{
|
'sid' => 'required',
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
'ci' => 'required|integer|min:0|max:3'
|
||||||
|
]);
|
||||||
|
|
||||||
$this->validate($request, [
|
$pid = $request->user()->profile_id;
|
||||||
'sid' => 'required',
|
$ci = $request->input('ci');
|
||||||
'ci' => 'required|integer|min:0|max:3'
|
$story = Story::findOrFail($request->input('sid'));
|
||||||
]);
|
abort_if(!FollowerService::follows($pid, $story->profile_id), 403);
|
||||||
|
$poll = Poll::whereStoryId($story->id)->firstOrFail();
|
||||||
|
|
||||||
$pid = $request->user()->profile_id;
|
$vote = new PollVote;
|
||||||
$ci = $request->input('ci');
|
$vote->profile_id = $pid;
|
||||||
$story = Story::findOrFail($request->input('sid'));
|
$vote->poll_id = $poll->id;
|
||||||
abort_if(!FollowerService::follows($pid, $story->profile_id), 403);
|
$vote->story_id = $story->id;
|
||||||
$poll = Poll::whereStoryId($story->id)->firstOrFail();
|
$vote->status_id = null;
|
||||||
|
$vote->choice = $ci;
|
||||||
|
$vote->save();
|
||||||
|
|
||||||
$vote = new PollVote;
|
$poll->votes_count = $poll->votes_count + 1;
|
||||||
$vote->profile_id = $pid;
|
$poll->cached_tallies = collect($poll->getTallies())->map(function($tally, $key) use($ci) {
|
||||||
$vote->poll_id = $poll->id;
|
return $ci == $key ? $tally + 1 : $tally;
|
||||||
$vote->story_id = $story->id;
|
})->toArray();
|
||||||
$vote->status_id = null;
|
$poll->save();
|
||||||
$vote->choice = $ci;
|
|
||||||
$vote->save();
|
|
||||||
|
|
||||||
$poll->votes_count = $poll->votes_count + 1;
|
return 200;
|
||||||
$poll->cached_tallies = collect($poll->getTallies())->map(function($tally, $key) use($ci) {
|
}
|
||||||
return $ci == $key ? $tally + 1 : $tally;
|
|
||||||
})->toArray();
|
|
||||||
$poll->save();
|
|
||||||
|
|
||||||
return 200;
|
public function storeReport(Request $request)
|
||||||
}
|
{
|
||||||
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
|
||||||
public function storeReport(Request $request)
|
$this->validate($request, [
|
||||||
{
|
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
|
||||||
|
|
||||||
$this->validate($request, [
|
|
||||||
'type' => 'required|alpha_dash',
|
'type' => 'required|alpha_dash',
|
||||||
'id' => 'required|integer|min:1',
|
'id' => 'required|integer|min:1',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$sid = $request->input('id');
|
$sid = $request->input('id');
|
||||||
$type = $request->input('type');
|
$type = $request->input('type');
|
||||||
|
@ -355,17 +364,17 @@ class StoryComposeController extends Controller
|
||||||
abort_if(!FollowerService::follows($pid, $story->profile_id), 422, 'Cannot report a story from an account you do not follow');
|
abort_if(!FollowerService::follows($pid, $story->profile_id), 422, 'Cannot report a story from an account you do not follow');
|
||||||
|
|
||||||
if( Report::whereProfileId($pid)
|
if( Report::whereProfileId($pid)
|
||||||
->whereObjectType('App\Story')
|
->whereObjectType('App\Story')
|
||||||
->whereObjectId($story->id)
|
->whereObjectId($story->id)
|
||||||
->exists()
|
->exists()
|
||||||
) {
|
) {
|
||||||
return response()->json(['error' => [
|
return response()->json(['error' => [
|
||||||
'code' => 409,
|
'code' => 409,
|
||||||
'message' => 'Cannot report the same story again'
|
'message' => 'Cannot report the same story again'
|
||||||
]], 409);
|
]], 409);
|
||||||
}
|
}
|
||||||
|
|
||||||
$report = new Report;
|
$report = new Report;
|
||||||
$report->profile_id = $pid;
|
$report->profile_id = $pid;
|
||||||
$report->user_id = $request->user()->id;
|
$report->user_id = $request->user()->id;
|
||||||
$report->object_id = $story->id;
|
$report->object_id = $story->id;
|
||||||
|
@ -376,149 +385,151 @@ class StoryComposeController extends Controller
|
||||||
$report->save();
|
$report->save();
|
||||||
|
|
||||||
return [200];
|
return [200];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function react(Request $request)
|
public function react(Request $request)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'sid' => 'required',
|
'sid' => 'required',
|
||||||
'reaction' => 'required|string'
|
'reaction' => 'required|string'
|
||||||
]);
|
]);
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$text = $request->input('reaction');
|
$text = $request->input('reaction');
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
$story = Story::findOrFail($request->input('sid'));
|
||||||
|
|
||||||
$story = Story::findOrFail($request->input('sid'));
|
abort_if(!$story->can_react, 422);
|
||||||
|
abort_if(StoryService::reactCounter($story->id, $pid) >= 5, 422, 'You have already reacted to this story');
|
||||||
|
|
||||||
abort_if(!$story->can_react, 422);
|
$status = new Status;
|
||||||
abort_if(StoryService::reactCounter($story->id, $pid) >= 5, 422, 'You have already reacted to this story');
|
$status->profile_id = $pid;
|
||||||
|
$status->type = 'story:reaction';
|
||||||
|
$status->caption = $text;
|
||||||
|
$status->rendered = $text;
|
||||||
|
$status->scope = 'direct';
|
||||||
|
$status->visibility = 'direct';
|
||||||
|
$status->in_reply_to_profile_id = $story->profile_id;
|
||||||
|
$status->entities = json_encode([
|
||||||
|
'story_id' => $story->id,
|
||||||
|
'reaction' => $text
|
||||||
|
]);
|
||||||
|
$status->save();
|
||||||
|
|
||||||
$status = new Status;
|
$dm = new DirectMessage;
|
||||||
$status->profile_id = $pid;
|
$dm->to_id = $story->profile_id;
|
||||||
$status->type = 'story:reaction';
|
$dm->from_id = $pid;
|
||||||
$status->caption = $text;
|
$dm->type = 'story:react';
|
||||||
$status->rendered = $text;
|
$dm->status_id = $status->id;
|
||||||
$status->scope = 'direct';
|
$dm->meta = json_encode([
|
||||||
$status->visibility = 'direct';
|
'story_username' => $story->profile->username,
|
||||||
$status->in_reply_to_profile_id = $story->profile_id;
|
'story_actor_username' => $request->user()->username,
|
||||||
$status->entities = json_encode([
|
'story_id' => $story->id,
|
||||||
'story_id' => $story->id,
|
'story_media_url' => url(Storage::url($story->path)),
|
||||||
'reaction' => $text
|
'reaction' => $text
|
||||||
]);
|
]);
|
||||||
$status->save();
|
$dm->save();
|
||||||
|
|
||||||
$dm = new DirectMessage;
|
Conversation::updateOrInsert(
|
||||||
$dm->to_id = $story->profile_id;
|
[
|
||||||
$dm->from_id = $pid;
|
'to_id' => $story->profile_id,
|
||||||
$dm->type = 'story:react';
|
'from_id' => $pid
|
||||||
$dm->status_id = $status->id;
|
],
|
||||||
$dm->meta = json_encode([
|
[
|
||||||
'story_username' => $story->profile->username,
|
'type' => 'story:react',
|
||||||
'story_actor_username' => $request->user()->username,
|
'status_id' => $status->id,
|
||||||
'story_id' => $story->id,
|
'dm_id' => $dm->id,
|
||||||
'story_media_url' => url(Storage::url($story->path)),
|
'is_hidden' => false
|
||||||
'reaction' => $text
|
]
|
||||||
]);
|
);
|
||||||
$dm->save();
|
|
||||||
|
|
||||||
Conversation::updateOrInsert(
|
if($story->local) {
|
||||||
[
|
// generate notification
|
||||||
'to_id' => $story->profile_id,
|
$n = new Notification;
|
||||||
'from_id' => $pid
|
$n->profile_id = $dm->to_id;
|
||||||
],
|
$n->actor_id = $dm->from_id;
|
||||||
[
|
$n->item_id = $dm->id;
|
||||||
'type' => 'story:react',
|
$n->item_type = 'App\DirectMessage';
|
||||||
'status_id' => $status->id,
|
$n->action = 'story:react';
|
||||||
'dm_id' => $dm->id,
|
$n->save();
|
||||||
'is_hidden' => false
|
} else {
|
||||||
]
|
StoryReactionDeliver::dispatch($story, $status)->onQueue('story');
|
||||||
);
|
}
|
||||||
|
|
||||||
if($story->local) {
|
StoryService::reactIncrement($story->id, $pid);
|
||||||
// generate notification
|
|
||||||
$n = new Notification;
|
|
||||||
$n->profile_id = $dm->to_id;
|
|
||||||
$n->actor_id = $dm->from_id;
|
|
||||||
$n->item_id = $dm->id;
|
|
||||||
$n->item_type = 'App\DirectMessage';
|
|
||||||
$n->action = 'story:react';
|
|
||||||
$n->save();
|
|
||||||
} else {
|
|
||||||
StoryReactionDeliver::dispatch($story, $status)->onQueue('story');
|
|
||||||
}
|
|
||||||
|
|
||||||
StoryService::reactIncrement($story->id, $pid);
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
return 200;
|
public function comment(Request $request)
|
||||||
}
|
{
|
||||||
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
$this->validate($request, [
|
||||||
|
'sid' => 'required',
|
||||||
|
'caption' => 'required|string'
|
||||||
|
]);
|
||||||
|
$pid = $request->user()->profile_id;
|
||||||
|
$text = $request->input('caption');
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
$story = Story::findOrFail($request->input('sid'));
|
||||||
|
|
||||||
public function comment(Request $request)
|
abort_if(!$story->can_reply, 422);
|
||||||
{
|
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
|
||||||
$this->validate($request, [
|
|
||||||
'sid' => 'required',
|
|
||||||
'caption' => 'required|string'
|
|
||||||
]);
|
|
||||||
$pid = $request->user()->profile_id;
|
|
||||||
$text = $request->input('caption');
|
|
||||||
|
|
||||||
$story = Story::findOrFail($request->input('sid'));
|
$status = new Status;
|
||||||
|
$status->type = 'story:reply';
|
||||||
|
$status->profile_id = $pid;
|
||||||
|
$status->caption = $text;
|
||||||
|
$status->rendered = $text;
|
||||||
|
$status->scope = 'direct';
|
||||||
|
$status->visibility = 'direct';
|
||||||
|
$status->in_reply_to_profile_id = $story->profile_id;
|
||||||
|
$status->entities = json_encode([
|
||||||
|
'story_id' => $story->id
|
||||||
|
]);
|
||||||
|
$status->save();
|
||||||
|
|
||||||
abort_if(!$story->can_reply, 422);
|
$dm = new DirectMessage;
|
||||||
|
$dm->to_id = $story->profile_id;
|
||||||
|
$dm->from_id = $pid;
|
||||||
|
$dm->type = 'story:comment';
|
||||||
|
$dm->status_id = $status->id;
|
||||||
|
$dm->meta = json_encode([
|
||||||
|
'story_username' => $story->profile->username,
|
||||||
|
'story_actor_username' => $request->user()->username,
|
||||||
|
'story_id' => $story->id,
|
||||||
|
'story_media_url' => url(Storage::url($story->path)),
|
||||||
|
'caption' => $text
|
||||||
|
]);
|
||||||
|
$dm->save();
|
||||||
|
|
||||||
$status = new Status;
|
Conversation::updateOrInsert(
|
||||||
$status->type = 'story:reply';
|
[
|
||||||
$status->profile_id = $pid;
|
'to_id' => $story->profile_id,
|
||||||
$status->caption = $text;
|
'from_id' => $pid
|
||||||
$status->rendered = $text;
|
],
|
||||||
$status->scope = 'direct';
|
[
|
||||||
$status->visibility = 'direct';
|
'type' => 'story:comment',
|
||||||
$status->in_reply_to_profile_id = $story->profile_id;
|
'status_id' => $status->id,
|
||||||
$status->entities = json_encode([
|
'dm_id' => $dm->id,
|
||||||
'story_id' => $story->id
|
'is_hidden' => false
|
||||||
]);
|
]
|
||||||
$status->save();
|
);
|
||||||
|
|
||||||
$dm = new DirectMessage;
|
if($story->local) {
|
||||||
$dm->to_id = $story->profile_id;
|
// generate notification
|
||||||
$dm->from_id = $pid;
|
$n = new Notification;
|
||||||
$dm->type = 'story:comment';
|
$n->profile_id = $dm->to_id;
|
||||||
$dm->status_id = $status->id;
|
$n->actor_id = $dm->from_id;
|
||||||
$dm->meta = json_encode([
|
$n->item_id = $dm->id;
|
||||||
'story_username' => $story->profile->username,
|
$n->item_type = 'App\DirectMessage';
|
||||||
'story_actor_username' => $request->user()->username,
|
$n->action = 'story:comment';
|
||||||
'story_id' => $story->id,
|
$n->save();
|
||||||
'story_media_url' => url(Storage::url($story->path)),
|
} else {
|
||||||
'caption' => $text
|
StoryReplyDeliver::dispatch($story, $status)->onQueue('story');
|
||||||
]);
|
}
|
||||||
$dm->save();
|
|
||||||
|
|
||||||
Conversation::updateOrInsert(
|
return 200;
|
||||||
[
|
}
|
||||||
'to_id' => $story->profile_id,
|
|
||||||
'from_id' => $pid
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'type' => 'story:comment',
|
|
||||||
'status_id' => $status->id,
|
|
||||||
'dm_id' => $dm->id,
|
|
||||||
'is_hidden' => false
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
if($story->local) {
|
|
||||||
// generate notification
|
|
||||||
$n = new Notification;
|
|
||||||
$n->profile_id = $dm->to_id;
|
|
||||||
$n->actor_id = $dm->from_id;
|
|
||||||
$n->item_id = $dm->id;
|
|
||||||
$n->item_type = 'App\DirectMessage';
|
|
||||||
$n->action = 'story:comment';
|
|
||||||
$n->save();
|
|
||||||
} else {
|
|
||||||
StoryReplyDeliver::dispatch($story, $status)->onQueue('story');
|
|
||||||
}
|
|
||||||
|
|
||||||
return 200;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,288 +28,308 @@ use League\Fractal\Serializer\ArraySerializer;
|
||||||
use League\Fractal\Resource\Item;
|
use League\Fractal\Resource\Item;
|
||||||
use App\Transformer\ActivityPub\Verb\StoryVerb;
|
use App\Transformer\ActivityPub\Verb\StoryVerb;
|
||||||
use App\Jobs\StoryPipeline\StoryViewDeliver;
|
use App\Jobs\StoryPipeline\StoryViewDeliver;
|
||||||
|
use App\Services\UserRoleService;
|
||||||
|
|
||||||
class StoryController extends StoryComposeController
|
class StoryController extends StoryComposeController
|
||||||
{
|
{
|
||||||
public function recent(Request $request)
|
public function recent(Request $request)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
$pid = $request->user()->profile_id;
|
$user = $request->user();
|
||||||
|
if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$pid = $user->profile_id;
|
||||||
|
|
||||||
if(config('database.default') == 'pgsql') {
|
if(config('database.default') == 'pgsql') {
|
||||||
$s = Cache::remember('pf:stories:recent-by-id:' . $pid, 900, function() use($pid) {
|
$s = Cache::remember('pf:stories:recent-by-id:' . $pid, 900, function() use($pid) {
|
||||||
return Story::select('stories.*', 'followers.following_id')
|
return Story::select('stories.*', 'followers.following_id')
|
||||||
->leftJoin('followers', 'followers.following_id', 'stories.profile_id')
|
->leftJoin('followers', 'followers.following_id', 'stories.profile_id')
|
||||||
->where('followers.profile_id', $pid)
|
->where('followers.profile_id', $pid)
|
||||||
->where('stories.active', true)
|
->where('stories.active', true)
|
||||||
->get()
|
->get()
|
||||||
->map(function($s) {
|
->map(function($s) {
|
||||||
$r = new \StdClass;
|
$r = new \StdClass;
|
||||||
$r->id = $s->id;
|
$r->id = $s->id;
|
||||||
$r->profile_id = $s->profile_id;
|
$r->profile_id = $s->profile_id;
|
||||||
$r->type = $s->type;
|
$r->type = $s->type;
|
||||||
$r->path = $s->path;
|
$r->path = $s->path;
|
||||||
return $r;
|
return $r;
|
||||||
})
|
})
|
||||||
->unique('profile_id');
|
->unique('profile_id');
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$s = Cache::remember('pf:stories:recent-by-id:' . $pid, 900, function() use($pid) {
|
$s = Cache::remember('pf:stories:recent-by-id:' . $pid, 900, function() use($pid) {
|
||||||
return Story::select('stories.*', 'followers.following_id')
|
return Story::select('stories.*', 'followers.following_id')
|
||||||
->leftJoin('followers', 'followers.following_id', 'stories.profile_id')
|
->leftJoin('followers', 'followers.following_id', 'stories.profile_id')
|
||||||
->where('followers.profile_id', $pid)
|
->where('followers.profile_id', $pid)
|
||||||
->where('stories.active', true)
|
->where('stories.active', true)
|
||||||
->groupBy('followers.following_id')
|
->groupBy('followers.following_id')
|
||||||
->orderByDesc('id')
|
->orderByDesc('id')
|
||||||
->get();
|
->get();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$self = Cache::remember('pf:stories:recent-self:' . $pid, 21600, function() use($pid) {
|
$self = Cache::remember('pf:stories:recent-self:' . $pid, 21600, function() use($pid) {
|
||||||
return Story::whereProfileId($pid)
|
return Story::whereProfileId($pid)
|
||||||
->whereActive(true)
|
->whereActive(true)
|
||||||
->orderByDesc('id')
|
->orderByDesc('id')
|
||||||
->limit(1)
|
->limit(1)
|
||||||
->get()
|
->get()
|
||||||
->map(function($s) use($pid) {
|
->map(function($s) use($pid) {
|
||||||
$r = new \StdClass;
|
$r = new \StdClass;
|
||||||
$r->id = $s->id;
|
$r->id = $s->id;
|
||||||
$r->profile_id = $pid;
|
$r->profile_id = $pid;
|
||||||
$r->type = $s->type;
|
$r->type = $s->type;
|
||||||
$r->path = $s->path;
|
$r->path = $s->path;
|
||||||
return $r;
|
return $r;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if($self->count()) {
|
if($self->count()) {
|
||||||
$s->prepend($self->first());
|
$s->prepend($self->first());
|
||||||
}
|
}
|
||||||
|
|
||||||
$res = $s->map(function($s) use($pid) {
|
$res = $s->map(function($s) use($pid) {
|
||||||
$profile = AccountService::get($s->profile_id);
|
$profile = AccountService::get($s->profile_id);
|
||||||
$url = $profile['local'] ? url("/stories/{$profile['username']}") :
|
$url = $profile['local'] ? url("/stories/{$profile['username']}") :
|
||||||
url("/i/rs/{$profile['id']}");
|
url("/i/rs/{$profile['id']}");
|
||||||
return [
|
return [
|
||||||
'pid' => $profile['id'],
|
'pid' => $profile['id'],
|
||||||
'avatar' => $profile['avatar'],
|
'avatar' => $profile['avatar'],
|
||||||
'local' => $profile['local'],
|
'local' => $profile['local'],
|
||||||
'username' => $profile['acct'],
|
'username' => $profile['acct'],
|
||||||
'latest' => [
|
'latest' => [
|
||||||
'id' => $s->id,
|
'id' => $s->id,
|
||||||
'type' => $s->type,
|
'type' => $s->type,
|
||||||
'preview_url' => url(Storage::url($s->path))
|
'preview_url' => url(Storage::url($s->path))
|
||||||
],
|
],
|
||||||
'url' => $url,
|
'url' => $url,
|
||||||
'seen' => StoryService::hasSeen($pid, StoryService::latest($s->profile_id)),
|
'seen' => StoryService::hasSeen($pid, StoryService::latest($s->profile_id)),
|
||||||
'sid' => $s->id
|
'sid' => $s->id
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
->sortBy('seen')
|
->sortBy('seen')
|
||||||
->values();
|
->values();
|
||||||
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function profile(Request $request, $id)
|
public function profile(Request $request, $id)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
|
||||||
$authed = $request->user()->profile_id;
|
$user = $request->user();
|
||||||
$profile = Profile::findOrFail($id);
|
if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$authed = $user->profile_id;
|
||||||
|
$profile = Profile::findOrFail($id);
|
||||||
|
|
||||||
if($authed != $profile->id && !FollowerService::follows($authed, $profile->id)) {
|
if($authed != $profile->id && !FollowerService::follows($authed, $profile->id)) {
|
||||||
return abort([], 403);
|
return abort([], 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stories = Story::whereProfileId($profile->id)
|
$stories = Story::whereProfileId($profile->id)
|
||||||
->whereActive(true)
|
->whereActive(true)
|
||||||
->orderBy('expires_at')
|
->orderBy('expires_at')
|
||||||
->get()
|
->get()
|
||||||
->map(function($s, $k) use($authed) {
|
->map(function($s, $k) use($authed) {
|
||||||
$seen = StoryService::hasSeen($authed, $s->id);
|
$seen = StoryService::hasSeen($authed, $s->id);
|
||||||
$res = [
|
$res = [
|
||||||
'id' => (string) $s->id,
|
'id' => (string) $s->id,
|
||||||
'type' => $s->type,
|
'type' => $s->type,
|
||||||
'duration' => $s->duration,
|
'duration' => $s->duration,
|
||||||
'src' => url(Storage::url($s->path)),
|
'src' => url(Storage::url($s->path)),
|
||||||
'created_at' => $s->created_at->toAtomString(),
|
'created_at' => $s->created_at->toAtomString(),
|
||||||
'expires_at' => $s->expires_at->toAtomString(),
|
'expires_at' => $s->expires_at->toAtomString(),
|
||||||
'view_count' => ($authed == $s->profile_id) ? ($s->view_count ?? 0) : null,
|
'view_count' => ($authed == $s->profile_id) ? ($s->view_count ?? 0) : null,
|
||||||
'seen' => $seen,
|
'seen' => $seen,
|
||||||
'progress' => $seen ? 100 : 0,
|
'progress' => $seen ? 100 : 0,
|
||||||
'can_reply' => (bool) $s->can_reply,
|
'can_reply' => (bool) $s->can_reply,
|
||||||
'can_react' => (bool) $s->can_react
|
'can_react' => (bool) $s->can_react
|
||||||
];
|
];
|
||||||
|
|
||||||
if($s->type == 'poll') {
|
if($s->type == 'poll') {
|
||||||
$res['question'] = json_decode($s->story, true)['question'];
|
$res['question'] = json_decode($s->story, true)['question'];
|
||||||
$res['options'] = json_decode($s->story, true)['options'];
|
$res['options'] = json_decode($s->story, true)['options'];
|
||||||
$res['voted'] = PollService::votedStory($s->id, $authed);
|
$res['voted'] = PollService::votedStory($s->id, $authed);
|
||||||
if($res['voted']) {
|
if($res['voted']) {
|
||||||
$res['voted_index'] = PollService::storyChoice($s->id, $authed);
|
$res['voted_index'] = PollService::storyChoice($s->id, $authed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
})->toArray();
|
})->toArray();
|
||||||
if(count($stories) == 0) {
|
if(count($stories) == 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$cursor = count($stories) - 1;
|
$cursor = count($stories) - 1;
|
||||||
$stories = [[
|
$stories = [[
|
||||||
'id' => (string) $stories[$cursor]['id'],
|
'id' => (string) $stories[$cursor]['id'],
|
||||||
'nodes' => $stories,
|
'nodes' => $stories,
|
||||||
'account' => AccountService::get($profile->id),
|
'account' => AccountService::get($profile->id),
|
||||||
'pid' => (string) $profile->id
|
'pid' => (string) $profile->id
|
||||||
]];
|
]];
|
||||||
return response()->json($stories, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
return response()->json($stories, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function viewed(Request $request)
|
public function viewed(Request $request)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'id' => 'required|min:1',
|
'id' => 'required|min:1',
|
||||||
]);
|
]);
|
||||||
$id = $request->input('id');
|
$id = $request->input('id');
|
||||||
|
$user = $request->user();
|
||||||
|
if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$authed = $user->profile;
|
||||||
|
|
||||||
$authed = $request->user()->profile;
|
$story = Story::with('profile')
|
||||||
|
->findOrFail($id);
|
||||||
|
$exp = $story->expires_at;
|
||||||
|
|
||||||
$story = Story::with('profile')
|
$profile = $story->profile;
|
||||||
->findOrFail($id);
|
|
||||||
$exp = $story->expires_at;
|
|
||||||
|
|
||||||
$profile = $story->profile;
|
if($story->profile_id == $authed->id) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
if($story->profile_id == $authed->id) {
|
$publicOnly = (bool) $profile->followedBy($authed);
|
||||||
return [];
|
abort_if(!$publicOnly, 403);
|
||||||
}
|
|
||||||
|
|
||||||
$publicOnly = (bool) $profile->followedBy($authed);
|
$v = StoryView::firstOrCreate([
|
||||||
abort_if(!$publicOnly, 403);
|
'story_id' => $id,
|
||||||
|
'profile_id' => $authed->id
|
||||||
|
]);
|
||||||
|
|
||||||
$v = StoryView::firstOrCreate([
|
if($v->wasRecentlyCreated) {
|
||||||
'story_id' => $id,
|
Story::findOrFail($story->id)->increment('view_count');
|
||||||
'profile_id' => $authed->id
|
|
||||||
]);
|
|
||||||
|
|
||||||
if($v->wasRecentlyCreated) {
|
if($story->local == false) {
|
||||||
Story::findOrFail($story->id)->increment('view_count');
|
StoryViewDeliver::dispatch($story, $authed)->onQueue('story');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($story->local == false) {
|
Cache::forget('stories:recent:by_id:' . $authed->id);
|
||||||
StoryViewDeliver::dispatch($story, $authed)->onQueue('story');
|
StoryService::addSeen($authed->id, $story->id);
|
||||||
}
|
return ['code' => 200];
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache::forget('stories:recent:by_id:' . $authed->id);
|
public function exists(Request $request, $id)
|
||||||
StoryService::addSeen($authed->id, $story->id);
|
{
|
||||||
return ['code' => 200];
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
}
|
$user = $request->user();
|
||||||
|
if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id)) {
|
||||||
|
return response()->json(false);
|
||||||
|
}
|
||||||
|
return response()->json(Story::whereProfileId($id)
|
||||||
|
->whereActive(true)
|
||||||
|
->exists());
|
||||||
|
}
|
||||||
|
|
||||||
public function exists(Request $request, $id)
|
public function iRedirect(Request $request)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
|
||||||
return response()->json(Story::whereProfileId($id)
|
$user = $request->user();
|
||||||
->whereActive(true)
|
abort_if(!$user, 404);
|
||||||
->exists());
|
$username = $user->username;
|
||||||
}
|
return redirect("/stories/{$username}");
|
||||||
|
}
|
||||||
|
|
||||||
public function iRedirect(Request $request)
|
public function viewers(Request $request)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
|
||||||
$user = $request->user();
|
$this->validate($request, [
|
||||||
abort_if(!$user, 404);
|
'sid' => 'required|string'
|
||||||
$username = $user->username;
|
]);
|
||||||
return redirect("/stories/{$username}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function viewers(Request $request)
|
$user = $request->user();
|
||||||
{
|
if($user->has_roles && !UserRoleService::can('can-use-stories', $user->id)) {
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
return response()->json([]);
|
||||||
|
}
|
||||||
|
|
||||||
$this->validate($request, [
|
$pid = $request->user()->profile_id;
|
||||||
'sid' => 'required|string'
|
$sid = $request->input('sid');
|
||||||
]);
|
|
||||||
|
|
||||||
$pid = $request->user()->profile_id;
|
$story = Story::whereProfileId($pid)
|
||||||
$sid = $request->input('sid');
|
->whereActive(true)
|
||||||
|
->findOrFail($sid);
|
||||||
|
|
||||||
$story = Story::whereProfileId($pid)
|
$viewers = StoryView::whereStoryId($story->id)
|
||||||
->whereActive(true)
|
->latest()
|
||||||
->findOrFail($sid);
|
->simplePaginate(10)
|
||||||
|
->map(function($view) {
|
||||||
|
return AccountService::get($view->profile_id);
|
||||||
|
})
|
||||||
|
->values();
|
||||||
|
|
||||||
$viewers = StoryView::whereStoryId($story->id)
|
return response()->json($viewers, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||||
->latest()
|
}
|
||||||
->simplePaginate(10)
|
|
||||||
->map(function($view) {
|
|
||||||
return AccountService::get($view->profile_id);
|
|
||||||
})
|
|
||||||
->values();
|
|
||||||
|
|
||||||
return response()->json($viewers, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
public function remoteStory(Request $request, $id)
|
||||||
}
|
{
|
||||||
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
|
|
||||||
public function remoteStory(Request $request, $id)
|
$profile = Profile::findOrFail($id);
|
||||||
{
|
if($profile->user_id != null || $profile->domain == null) {
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
return redirect('/stories/' . $profile->username);
|
||||||
|
}
|
||||||
|
$pid = $profile->id;
|
||||||
|
return view('stories.show_remote', compact('pid'));
|
||||||
|
}
|
||||||
|
|
||||||
$profile = Profile::findOrFail($id);
|
public function pollResults(Request $request)
|
||||||
if($profile->user_id != null || $profile->domain == null) {
|
{
|
||||||
return redirect('/stories/' . $profile->username);
|
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
||||||
}
|
|
||||||
$pid = $profile->id;
|
|
||||||
return view('stories.show_remote', compact('pid'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function pollResults(Request $request)
|
$this->validate($request, [
|
||||||
{
|
'sid' => 'required|string'
|
||||||
abort_if(!config_cache('instance.stories.enabled') || !$request->user(), 404);
|
]);
|
||||||
|
|
||||||
$this->validate($request, [
|
$pid = $request->user()->profile_id;
|
||||||
'sid' => 'required|string'
|
$sid = $request->input('sid');
|
||||||
]);
|
|
||||||
|
|
||||||
$pid = $request->user()->profile_id;
|
$story = Story::whereProfileId($pid)
|
||||||
$sid = $request->input('sid');
|
->whereActive(true)
|
||||||
|
->findOrFail($sid);
|
||||||
|
|
||||||
$story = Story::whereProfileId($pid)
|
return PollService::storyResults($sid);
|
||||||
->whereActive(true)
|
}
|
||||||
->findOrFail($sid);
|
|
||||||
|
|
||||||
return PollService::storyResults($sid);
|
public function getActivityObject(Request $request, $username, $id)
|
||||||
}
|
{
|
||||||
|
abort_if(!config_cache('instance.stories.enabled'), 404);
|
||||||
|
|
||||||
public function getActivityObject(Request $request, $username, $id)
|
if(!$request->wantsJson()) {
|
||||||
{
|
return redirect('/stories/' . $username);
|
||||||
abort_if(!config_cache('instance.stories.enabled'), 404);
|
}
|
||||||
|
|
||||||
if(!$request->wantsJson()) {
|
abort_if(!$request->hasHeader('Authorization'), 404);
|
||||||
return redirect('/stories/' . $username);
|
|
||||||
}
|
|
||||||
|
|
||||||
abort_if(!$request->hasHeader('Authorization'), 404);
|
$profile = Profile::whereUsername($username)->whereNull('domain')->firstOrFail();
|
||||||
|
$story = Story::whereActive(true)->whereProfileId($profile->id)->findOrFail($id);
|
||||||
|
|
||||||
$profile = Profile::whereUsername($username)->whereNull('domain')->firstOrFail();
|
abort_if($story->bearcap_token == null, 404);
|
||||||
$story = Story::whereActive(true)->whereProfileId($profile->id)->findOrFail($id);
|
abort_if(now()->gt($story->expires_at), 404);
|
||||||
|
$token = substr($request->header('Authorization'), 7);
|
||||||
|
abort_if(hash_equals($story->bearcap_token, $token) === false, 404);
|
||||||
|
abort_if($story->created_at->lt(now()->subMinutes(20)), 404);
|
||||||
|
|
||||||
abort_if($story->bearcap_token == null, 404);
|
$fractal = new Manager();
|
||||||
abort_if(now()->gt($story->expires_at), 404);
|
$fractal->setSerializer(new ArraySerializer());
|
||||||
$token = substr($request->header('Authorization'), 7);
|
$resource = new Item($story, new StoryVerb());
|
||||||
abort_if(hash_equals($story->bearcap_token, $token) === false, 404);
|
$res = $fractal->createData($resource)->toArray();
|
||||||
abort_if($story->created_at->lt(now()->subMinutes(20)), 404);
|
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||||
|
}
|
||||||
|
|
||||||
$fractal = new Manager();
|
public function showSystemStory()
|
||||||
$fractal->setSerializer(new ArraySerializer());
|
{
|
||||||
$resource = new Item($story, new StoryVerb());
|
// return view('stories.system');
|
||||||
$res = $fractal->createData($resource)->toArray();
|
}
|
||||||
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function showSystemStory()
|
|
||||||
{
|
|
||||||
// return view('stories.system');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue