pinned posts

pull/5884/head
Felipe Mateus 3 weeks ago
parent 4fab7d6968
commit cce4c41d97
No known key found for this signature in database
GPG Key ID: 94D494618F214123

@ -4426,4 +4426,53 @@ class ApiV1Controller extends Controller
})
);
}
/**
* GET /api/v2/statuses/{id}/pin
*/
public function statusPin(Request $request, $id) {
abort_if(! $request->user(), 403);
$status = Status::findOrFail($id);
$user = $request->user();
$res = [
'status' => false,
'message' => ''
];
if($status->profile_id == $user->profile_id){
if(StatusService::markPin($status->id)){
$res['status'] = true;
} else {
$res['message'] = 'Limit pin reached';
}
return $this->json($res)->setStatusCode(200);
}
return $this->json("")->setStatusCode(400);
}
/**
* GET /api/v2/statuses/{id}/unpin
*/
public function statusUnpin(Request $request, $id) {
abort_if(! $request->user(), 403);
$status = Status::findOrFail($id);
$user = $request->user();
if($status->profile_id == $user->profile_id){
StatusService::unmarkPin($status->id);
$res = [
'status' => true,
'message' => ''
];
return $this->json($res)->setStatusCode(200);
}
return $this->json("")->setStatusCode(200);
}
}

@ -725,6 +725,7 @@ class PublicApiController extends Controller
->where('id', $dir, $id)
->whereIn('scope', $visibility)
->limit($limit)
->orderBy('pinned_order')
->orderByDesc('id')
->get()
->map(function ($s) use ($user) {

@ -11,6 +11,8 @@ use League\Fractal\Serializer\ArraySerializer;
class StatusService
{
const CACHE_KEY = 'pf:services:status:v1.1:';
const MAX_PINNED = 3;
public static function key($id, $publicOnly = true)
{
@ -198,4 +200,46 @@ class StatusService
{
return InstanceService::totalLocalStatuses();
}
public static function isPinned($id)
{
$status = Status::find($id);
return $status && $status->whereNotNull("pinned_order")->count() > 0;
}
public static function totalPins($pid)
{
return Status::whereProfileId($pid)->whereNotNull("pinned_order")->count();
}
public static function markPin($id)
{
$status = Status::find($id);
if (self::isPinned($id)) {
return true;
}
$totalPins = self::totalPins($status->profile_id);
if ($totalPins >= self::MAX_PINNED) {
return false;
}
$status->pinned_order = $totalPins + 1;
$status->save();
self::refresh($id);
return true;
}
public static function unmarkPin($id)
{
$status = Status::find($id);
$status->pinned_order = null;
$status->save();
self::refresh($id);
return true;
}
}

@ -69,6 +69,7 @@ class StatusStatelessTransformer extends Fractal\TransformerAbstract
'tags' => StatusHashtagService::statusTags($status->id),
'poll' => $poll,
'edited_at' => $status->edited_at ? str_replace('+00:00', 'Z', $status->edited_at->format(DATE_RFC3339_EXTENDED)) : null,
'pinned' => (bool) $status->pinned_order,
];
}
}

@ -71,6 +71,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
'poll' => $poll,
'bookmarked' => BookmarkService::get($pid, $status->id),
'edited_at' => $status->edited_at ? str_replace('+00:00', 'Z', $status->edited_at->format(DATE_RFC3339_EXTENDED)) : null,
'pinned' => (bool) $status->pinned_order,
];
}
}

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('statuses', function (Blueprint $table) {
$table->integer('pinned_order')->nullable()->default(null);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
Schema::table('statuses', function (Blueprint $table) {
$table->dropColumn('pinned_order');
});
}
};

@ -112,6 +112,21 @@
@click.prevent="unarchivePost(status)">
{{ $t('menu.unarchive') }}
</a>
<a
v-if="status && profile.id == status.account.id && !status.pinned"
class="list-group-item menu-option text-danger"
href="#"
@click.prevent="pinPost(status)">
{{ $t('menu.pin') }}
</a>
<a
v-if="status && profile.id == status.account.id && status.pinned"
class="list-group-item menu-option text-danger"
href="#"
@click.prevent="unpinPost(status)">
{{ $t('menu.unpin') }}
</a>
<a
v-if="config.ab.pue && status && profile.id == status.account.id && status.visibility !== 'archived'"
@ -976,6 +991,40 @@
}
})
},
pinPost(status) {
if(window.confirm(this.$t('menu.pinPostConfirm')) == false) {
return;
}
axios.post('/api/v2/statuses/' + status.id + '/pin')
.then(res => {
const data = res.data;
if(data.status){
swal('Success', "Post was pinned successfully!" , 'success');
}else {
swal('Error', data.message, 'error');
}
this.closeModals();
});
},
unpinPost(status) {
if(window.confirm(this.$t('menu.unpinPostConfirm')) == false) {
return;
}
axios.post('/api/v2/statuses/' + status.id + '/unpin')
.then(res => {
const data = res.data;
if(data.status){
swal('Success', "Post was unpinned successfully!" , 'success');
}else {
swal('Error', data.message, 'error');
}
this.closeModals();
});
},
}
}
</script>

@ -181,6 +181,9 @@
<span class="badge badge-light timestamp-overlay-badge">
{{ timeago(s.created_at) }}
</span>
<span v-if="s.pinned" class="badge badge-light pinned-overlay-badge">
<i class="fa fa-tag" aria-hidden="true"></i>
</span>
</a>
</div>
@ -219,6 +222,10 @@
<span class="badge badge-light timestamp-overlay-badge">
{{ timeago(s.created_at) }}
</span>
<span v-if="s.pinned" class="badge badge-light pinned-overlay-badge">
<i class="fa fa-tag" aria-hidden="true"></i>
</span>
</a>
<a v-else-if="s.sensitive" class="card info-overlay card-md-border-0" :href="statusUrl(s)">
@ -246,6 +253,9 @@
<span class="badge badge-light timestamp-overlay-badge">
{{ timeago(s.created_at) }}
</span>
<span v-if="s.pinned" class="badge badge-light pinned-overlay-badge">
<i class="fa fa-tag" aria-hidden="true"></i>
</span>
</a>
</div>
@ -1071,6 +1081,7 @@
});
});
},
}
}
</script>
@ -1126,6 +1137,14 @@
opacity: 0.6;
}
.pinned-overlay-badge {
position: absolute;
top: 10px;
left: 10px;
color: var(--dark);
font-size: 120%;
}
.profile-nav-btns {
margin-right: 1rem;

@ -129,10 +129,10 @@ return [
'emptyPosts' => 'We can\'t seem to find any posts',
],
'menu' => [
'viewPost' => 'View Post',
'viewProfile' => 'View Profile',
'moderationTools' => 'Moderation Tools',
'menu' => [
'viewPost' => 'View Post',
'viewProfile' => 'View Profile',
'moderationTools' => 'Moderation Tools',
'report' => 'Report',
'archive' => 'Archive',
'unarchive' => 'Unarchive',
@ -176,6 +176,10 @@ return [
'deletePostConfirm' => 'Are you sure you want to delete this post?',
'archivePostConfirm' => 'Are you sure you want to archive this post?',
'unarchivePostConfirm' => 'Are you sure you want to unarchive this post?',
'pin' => "Pin",
'unpin' => "Unpin",
'pinPostConfirm' => 'Are you sure you want to pin this post?',
'unpinPostConfirm' => 'Are you sure you want to unpin this post?'
],
'story' => [

@ -176,6 +176,10 @@ return [
'deletePostConfirm' => 'Tem a certeza que pretende apagar esta publicação?',
'archivePostConfirm' => 'Tem a certeza que pretende arquivar esta publicação?',
'unarchivePostConfirm' => 'Tem a certeza que pretende desarquivar este post?',
'pin' => "Fixar",
'unpin' => "Desfixar",
"pinPostConfirm" => "Tem certeza de que deseja fixar esta publicação?",
"unpinPostConfirm" => "Tem certeza de que deseja desafixar esta publicação?"
],
'story' => [

@ -58,6 +58,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('discover/tag', 'DiscoverController@getHashtags');
Route::get('statuses/{id}/replies', 'Api\ApiV1Controller@statusReplies');
Route::get('statuses/{id}/state', 'Api\ApiV1Controller@statusState');
Route::post('statuses/{id}/pin', 'Api\ApiV1Controller@statusPin');
Route::post('statuses/{id}/unpin', 'Api\ApiV1Controller@statusUnpin');
});
Route::group(['prefix' => 'pixelfed'], function() {

Loading…
Cancel
Save