Update FollowerController, remove deprecated /i/follow endpoint

This commit is contained in:
Daniel Supernault 2023-03-05 03:13:12 -07:00
parent 60fbf0e7d5
commit 4739d6146f
No known key found for this signature in database
GPG key ID: 0DEF1C662C9033F7
4 changed files with 63 additions and 144 deletions

View file

@ -23,109 +23,7 @@ class FollowerController extends Controller
public function store(Request $request) public function store(Request $request)
{ {
$this->validate($request, [ abort(422, 'Deprecated API Endpoint, use /api/v1/accounts/{id}/follow or /api/v1/accounts/{id}/unfollow instead.');
'item' => 'required|string',
'force' => 'nullable|boolean',
]);
$force = (bool) $request->input('force', true);
$item = (int) $request->input('item');
$url = $this->handleFollowRequest($item, $force);
if($request->wantsJson() == true) {
return response()->json(200);
} else {
return redirect($url);
}
}
protected function handleFollowRequest($item, $force)
{
$user = Auth::user()->profile;
$target = Profile::where('id', '!=', $user->id)->whereNull('status')->findOrFail($item);
$private = (bool) $target->is_private;
$remote = (bool) $target->domain;
$blocked = UserFilter::whereUserId($target->id)
->whereFilterType('block')
->whereFilterableId($user->id)
->whereFilterableType('App\Profile')
->exists();
if($blocked == true) {
abort(400, 'You cannot follow this user.');
}
$isFollowing = Follower::whereProfileId($user->id)->whereFollowingId($target->id)->exists();
if($private == true && $isFollowing == 0) {
if($user->following()->count() >= Follower::MAX_FOLLOWING) {
abort(400, 'You cannot follow more than ' . Follower::MAX_FOLLOWING . ' accounts');
}
if($user->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');
}
$follow = FollowRequest::firstOrCreate([
'follower_id' => $user->id,
'following_id' => $target->id
]);
if($remote == true && config('federation.activitypub.remoteFollow') == true) {
$this->sendFollow($user, $target);
}
FollowerService::add($user->id, $target->id);
} elseif ($private == false && $isFollowing == 0) {
if($user->following()->count() >= Follower::MAX_FOLLOWING) {
abort(400, 'You cannot follow more than ' . Follower::MAX_FOLLOWING . ' accounts');
}
if($user->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');
}
$follower = new Follower();
$follower->profile_id = $user->id;
$follower->following_id = $target->id;
$follower->save();
if($remote == true && config('federation.activitypub.remoteFollow') == true) {
$this->sendFollow($user, $target);
}
FollowerService::add($user->id, $target->id);
FollowPipeline::dispatch($follower);
} else {
if($force == true) {
$request = FollowRequest::whereFollowerId($user->id)->whereFollowingId($target->id)->exists();
$follower = Follower::whereProfileId($user->id)->whereFollowingId($target->id)->exists();
if($remote == true && $request && !$follower) {
$this->sendFollow($user, $target);
}
if($remote == true && $follower) {
$this->sendUndoFollow($user, $target);
}
Follower::whereProfileId($user->id)
->whereFollowingId($target->id)
->delete();
FollowerService::remove($user->id, $target->id);
}
}
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('user:account:id:'.$target->user_id);
Cache::forget('user:account:id:'.$user->user_id);
Cache::forget('px:profile:followers-v1.3:'.$user->id);
Cache::forget('px:profile:followers-v1.3:'.$target->id);
Cache::forget('px:profile:following-v1.3:'.$user->id);
Cache::forget('px:profile:following-v1.3:'.$target->id);
Cache::forget('profile:follower_count:'.$target->id);
Cache::forget('profile:follower_count:'.$user->id);
Cache::forget('profile:following_count:'.$target->id);
Cache::forget('profile:following_count:'.$user->id);
return $target->url();
} }
public function sendFollow($user, $target) public function sendFollow($user, $target)

View file

@ -122,12 +122,6 @@
</a> </a>
</div> --> </div> -->
<!-- <div v-else-if="n.type == 'follow' && n.relationship.following == false">
<a href="#" class="btn btn-primary py-0 font-weight-bold" @click.prevent="followProfile(n);">
Follow
</a>
</div> -->
<!-- <div v-else-if="n.status && n.status.parent && !n.status.parent.media_attachments && n.type == 'like' && n.relationship.following == false"> <!-- <div v-else-if="n.status && n.status.parent && !n.status.parent.media_attachments && n.type == 'like' && n.relationship.following == false">
<a href="#" class="btn btn-primary py-0 font-weight-bold"> <a href="#" class="btn btn-primary py-0 font-weight-bold">
Follow Follow
@ -290,24 +284,6 @@ export default {
return '/p/' + username + '/' + id; return '/p/' + username + '/' + id;
}, },
followProfile(n) {
let self = this;
let id = n.account.id;
axios.post('/i/follow', {
item: id
}).then(res => {
self.notifications.map(notification => {
if(notification.account.id === id) {
notification.relationship.following = true;
}
});
}).catch(err => {
if(err.response.data.message) {
swal('Error', err.response.data.message, 'error');
}
});
},
viewContext(n) { viewContext(n) {
switch(n.type) { switch(n.type) {
case 'follow': case 'follow':

View file

@ -131,14 +131,20 @@
break; break;
case 'unfollow': case 'unfollow':
axios.post('/i/follow', { axios.post('/api/v1/accounts/' + id + '/unfollow')
item: id .then(res => {
}).then(res => {
swal( swal(
'Unfollow Successful', 'Unfollow Successful',
'You have successfully unfollowed that user', 'You have successfully unfollowed that user',
'success' 'success'
); );
})
.catch(err => {
swal(
'Error',
'An error occured when attempting to unfollow this user',
'error'
);
}); });
break; break;

View file

@ -11,25 +11,35 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="text-center mt-n5 mb-4"> <div class="text-center mt-n5 mb-4">
<img class="rounded-circle p-1 border mt-n4 bg-white shadow" src="{{$profile->avatarUrl()}}" width="90px" height="90px;"> <img
class="rounded-circle p-1 border mt-n4 bg-white shadow"
src="{{$profile->avatarUrl()}}"
width="90"
height="90"
loading="lazy"
onerror="this.src='/storage/avatars/default.jpg?v=0';this.onerror=null;">
</div> </div>
<p class="text-center lead font-weight-bold mb-1">{{$profile->username}}</p> <p class="text-center lead font-weight-bold mb-1">{{$profile->username}}</p>
<p class="text-center text-muted small text-uppercase mb-4">{{$profile->followerCount()}} followers</p> <p class="text-center text-muted small text-uppercase mb-4">{{$profile->followerCount()}} followers</p>
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
@if($following == true) @if($following == true)
<form class="d-inline-block" action="/i/follow" method="post"> <button
@csrf id="unfollow"
<input type="hidden" name="item" value="{{(string)$profile->id}}"> type="button"
<input type="hidden" name="force" value="0"> class="btn btn-outline-secondary btn-sm py-1 px-4 text-uppercase font-weight-bold mr-3"
<button type="submit" class="btn btn-outline-secondary btn-sm py-1 px-4 text-uppercase font-weight-bold mr-3" style="font-weight: 500">Unfollow</button> style="font-weight: 500"
</form> onclick="unfollowProfile()">
Unfollow
</button>
@else @else
<form class="d-inline-block" action="/i/follow" method="post"> <button
@csrf id="follow"
<input type="hidden" name="item" value="{{(string)$profile->id}}"> type="button"
<input type="hidden" name="force" value="0"> class="btn btn-primary btn-sm py-1 px-4 text-uppercase font-weight-bold mr-3"
<button type="submit" class="btn btn-primary btn-sm py-1 px-4 text-uppercase font-weight-bold mr-3" style="font-weight: 500">Follow</button> style="font-weight: 500"
</form> onclick="followProfile()">
Follow
</button>
@endif @endif
<a class="btn btn-outline-primary btn-sm py-1 px-4 text-uppercase font-weight-bold" href="{{$profile->url()}}" style="font-weight: 500">View Profile</a> <a class="btn btn-outline-primary btn-sm py-1 px-4 text-uppercase font-weight-bold" href="{{$profile->url()}}" style="font-weight: 500">View Profile</a>
</div> </div>
@ -51,3 +61,32 @@
</div> </div>
</div> </div>
@endsection @endsection
@push('scripts')
<script type="text/javascript">
function followProfile() {
let btn = document.querySelector('#follow');
btn.setAttribute('disabled', 'disabled');
axios.post('/api/v1/accounts/{{$profile->id}}/follow')
.then(res => {
setTimeout(() => location.reload(), 1000);
})
.catch(err => {
location.href = '/login?next=' + encodeURI(location.href);
})
}
function unfollowProfile() {
let btn = document.querySelector('#unfollow');
btn.setAttribute('disabled', 'disabled');
axios.post('/api/v1/accounts/{{$profile->id}}/unfollow')
.then(res => {
setTimeout(() => location.reload(), 1000);
})
.catch(err => {
location.href = '/login?next=' + encodeURI(location.href);
})
}
</script>
@endpush