kopia lustrzana https://github.com/pixelfed/pixelfed
pinned posts
rodzic
4fab7d6968
commit
cce4c41d97
|
@ -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() {
|
||||
|
|
Ładowanie…
Reference in New Issue