mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-25 15:55:22 +00:00
Add hashtag administration
This commit is contained in:
parent
f9341d0197
commit
8487231177
12 changed files with 137 additions and 85 deletions
102
app/Http/Controllers/Admin/AdminHashtagsController.php
Normal file
102
app/Http/Controllers/Admin/AdminHashtagsController.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use Cache;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Hashtag;
|
||||
use App\StatusHashtag;
|
||||
use App\Http\Resources\AdminHashtag;
|
||||
use App\Services\TrendingHashtagService;
|
||||
|
||||
trait AdminHashtagsController
|
||||
{
|
||||
public function hashtagsHome(Request $request)
|
||||
{
|
||||
return view('admin.hashtags.home');
|
||||
}
|
||||
|
||||
public function hashtagsApi(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'action' => 'sometimes|in:banned,nsfw',
|
||||
'sort' => 'sometimes|in:id,name,cached_count,can_search,can_trend,is_banned,is_nsfw',
|
||||
'dir' => 'sometimes|in:asc,desc'
|
||||
]);
|
||||
$action = $request->input('action');
|
||||
$query = $request->input('q');
|
||||
$sort = $request->input('sort');
|
||||
$order = $request->input('dir');
|
||||
|
||||
$hashtags = Hashtag::when($query, function($q, $query) {
|
||||
return $q->where('name', 'like', $query . '%');
|
||||
})
|
||||
->when($sort, function($q, $sort) use($order) {
|
||||
return $q->orderBy($sort, $order);
|
||||
}, function($q) {
|
||||
return $q->orderByDesc('id');
|
||||
})
|
||||
->when($action, function($q, $action) {
|
||||
if($action === 'banned') {
|
||||
return $q->whereIsBanned(true);
|
||||
} else if ($action === 'nsfw') {
|
||||
return $q->whereIsNsfw(true);
|
||||
}
|
||||
})
|
||||
->cursorPaginate(10)
|
||||
->withQueryString();
|
||||
|
||||
return AdminHashtag::collection($hashtags);
|
||||
}
|
||||
|
||||
public function hashtagsStats(Request $request)
|
||||
{
|
||||
$stats = [
|
||||
'total_unique' => Hashtag::count(),
|
||||
'total_posts' => StatusHashtag::count(),
|
||||
'added_14_days' => Hashtag::where('created_at', '>', now()->subDays(14))->count(),
|
||||
'total_banned' => Hashtag::whereIsBanned(true)->count(),
|
||||
'total_nsfw' => Hashtag::whereIsNsfw(true)->count()
|
||||
];
|
||||
|
||||
return response()->json($stats);
|
||||
}
|
||||
|
||||
public function hashtagsGet(Request $request)
|
||||
{
|
||||
return new AdminHashtag(Hashtag::findOrFail($request->input('id')));
|
||||
}
|
||||
|
||||
public function hashtagsUpdate(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'id' => 'required',
|
||||
'name' => 'required',
|
||||
'slug' => 'required',
|
||||
'can_search' => 'required:boolean',
|
||||
'can_trend' => 'required:boolean',
|
||||
'is_nsfw' => 'required:boolean',
|
||||
'is_banned' => 'required:boolean'
|
||||
]);
|
||||
|
||||
$hashtag = Hashtag::whereSlug($request->input('slug'))->findOrFail($request->input('id'));
|
||||
$canTrendPrev = $hashtag->can_trend == null ? true : $hashtag->can_trend;
|
||||
$hashtag->is_banned = $request->input('is_banned');
|
||||
$hashtag->is_nsfw = $request->input('is_nsfw');
|
||||
$hashtag->can_search = $hashtag->is_banned ? false : $request->input('can_search');
|
||||
$hashtag->can_trend = $hashtag->is_banned ? false : $request->input('can_trend');
|
||||
$hashtag->save();
|
||||
|
||||
TrendingHashtagService::refresh();
|
||||
|
||||
return new AdminHashtag($hashtag);
|
||||
}
|
||||
|
||||
public function hashtagsClearTrendingCache(Request $request)
|
||||
{
|
||||
TrendingHashtagService::refresh();
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,7 @@ use App\{
|
|||
Profile,
|
||||
Report,
|
||||
Status,
|
||||
StatusHashtag,
|
||||
Story,
|
||||
User
|
||||
};
|
||||
|
@ -22,6 +23,7 @@ use Illuminate\Support\Facades\Redis;
|
|||
use App\Http\Controllers\Admin\{
|
||||
AdminDirectoryController,
|
||||
AdminDiscoverController,
|
||||
AdminHashtagsController,
|
||||
AdminInstanceController,
|
||||
AdminReportController,
|
||||
// AdminGroupsController,
|
||||
|
@ -43,6 +45,7 @@ class AdminController extends Controller
|
|||
use AdminReportController,
|
||||
AdminDirectoryController,
|
||||
AdminDiscoverController,
|
||||
AdminHashtagsController,
|
||||
// AdminGroupsController,
|
||||
AdminMediaController,
|
||||
AdminSettingsController,
|
||||
|
@ -201,12 +204,6 @@ class AdminController extends Controller
|
|||
return view('admin.apps.home', compact('apps'));
|
||||
}
|
||||
|
||||
public function hashtagsHome(Request $request)
|
||||
{
|
||||
$hashtags = Hashtag::orderByDesc('id')->paginate(10);
|
||||
return view('admin.hashtags.home', compact('hashtags'));
|
||||
}
|
||||
|
||||
public function messagesHome(Request $request)
|
||||
{
|
||||
$messages = Contact::orderByDesc('id')->paginate(10);
|
||||
|
|
|
@ -24,6 +24,7 @@ use App\Services\ReblogService;
|
|||
use App\Services\StatusHashtagService;
|
||||
use App\Services\SnowflakeService;
|
||||
use App\Services\StatusService;
|
||||
use App\Services\TrendingHashtagService;
|
||||
use App\Services\UserFilterService;
|
||||
|
||||
class DiscoverController extends Controller
|
||||
|
@ -181,33 +182,7 @@ class DiscoverController extends Controller
|
|||
{
|
||||
abort_if(!$request->user(), 403);
|
||||
|
||||
$res = Cache::remember('api:discover:v1.1:trending:hashtags', 43200, function() {
|
||||
$minId = StatusHashtag::where('created_at', '>', now()->subDays(14))->first();
|
||||
if(!$minId) {
|
||||
return [];
|
||||
}
|
||||
return StatusHashtag::select('hashtag_id', \DB::raw('count(*) as total'))
|
||||
->where('id', '>', $minId->id)
|
||||
->groupBy('hashtag_id')
|
||||
->orderBy('total','desc')
|
||||
->take(20)
|
||||
->get()
|
||||
->map(function($h) {
|
||||
$hashtag = Hashtag::find($h->hashtag_id);
|
||||
if(!$hashtag) {
|
||||
return;
|
||||
}
|
||||
return [
|
||||
'id' => $h->hashtag_id,
|
||||
'total' => $h->total,
|
||||
'name' => '#'.$hashtag->name,
|
||||
'hashtag' => $hashtag->name,
|
||||
'url' => $hashtag->url()
|
||||
];
|
||||
})
|
||||
->filter()
|
||||
->values();
|
||||
});
|
||||
$res = TrendingHashtagService::getTrending();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,16 +96,9 @@ class SearchApiV2Service
|
|||
$query = substr($rawQuery, 1) . '%';
|
||||
}
|
||||
$banned = InstanceService::getBannedDomains();
|
||||
$results = Profile::select('profiles.*', 'followers.profile_id', 'followers.created_at')
|
||||
->whereNull('status')
|
||||
->leftJoin('followers', function($join) use($user) {
|
||||
return $join->on('profiles.id', '=', 'followers.following_id')
|
||||
->where('followers.profile_id', $user->profile_id);
|
||||
})
|
||||
$results = Profile::select('username', 'id', 'followers_count', 'domain')
|
||||
->where('username', 'like', $query)
|
||||
->orderBy('domain')
|
||||
->orderByDesc('profiles.followers_count')
|
||||
->orderByDesc('followers.created_at')
|
||||
->offset($offset)
|
||||
->limit($limit)
|
||||
->get()
|
||||
|
@ -131,7 +124,7 @@ class SearchApiV2Service
|
|||
$limit = $this->query->input('limit') ?? 20;
|
||||
$offset = $this->query->input('offset') ?? 0;
|
||||
$query = '%' . $this->query->input('q') . '%';
|
||||
return Hashtag::whereIsBanned(false)
|
||||
return Hashtag::where('can_search', true)
|
||||
->where('name', 'like', $query)
|
||||
->offset($offset)
|
||||
->limit($limit)
|
||||
|
|
BIN
public/css/admin.css
vendored
BIN
public/css/admin.css
vendored
Binary file not shown.
BIN
public/js/admin.js
vendored
BIN
public/js/admin.js
vendored
Binary file not shown.
BIN
public/js/vendor.js
vendored
BIN
public/js/vendor.js
vendored
Binary file not shown.
|
@ -49,7 +49,7 @@
|
|||
*/
|
||||
|
||||
/*!
|
||||
* Pusher JavaScript Library v7.5.0
|
||||
* Pusher JavaScript Library v7.6.0
|
||||
* https://pusher.com/
|
||||
*
|
||||
* Copyright 2020, Pusher
|
||||
|
@ -65,14 +65,14 @@
|
|||
*/
|
||||
|
||||
/*!
|
||||
* Sizzle CSS Selector Engine v2.3.6
|
||||
* Sizzle CSS Selector Engine v2.3.8
|
||||
* https://sizzlejs.com/
|
||||
*
|
||||
* Copyright JS Foundation and other contributors
|
||||
* Released under the MIT license
|
||||
* https://js.foundation/
|
||||
*
|
||||
* Date: 2021-02-16
|
||||
* Date: 2022-11-16
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -82,7 +82,7 @@
|
|||
*/
|
||||
|
||||
/*!
|
||||
* jQuery JavaScript Library v3.6.1
|
||||
* jQuery JavaScript Library v3.6.2
|
||||
* https://jquery.com/
|
||||
*
|
||||
* Includes Sizzle.js
|
||||
|
@ -92,7 +92,7 @@
|
|||
* Released under the MIT license
|
||||
* https://jquery.org/license
|
||||
*
|
||||
* Date: 2022-08-26T17:52Z
|
||||
* Date: 2022-12-13T14:56Z
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
Binary file not shown.
10
resources/assets/js/admin.js
vendored
10
resources/assets/js/admin.js
vendored
|
@ -20,3 +20,13 @@ Chart.defaults.global.defaultFontFamily = "-apple-system,BlinkMacSystemFont,Sego
|
|||
Array.from(document.querySelectorAll('.pagination .page-link'))
|
||||
.filter(el => el.textContent === '« Previous' || el.textContent === 'Next »')
|
||||
.forEach(el => el.textContent = (el.textContent === 'Next »' ? '›' :'‹'));
|
||||
|
||||
Vue.component(
|
||||
'admin-directory',
|
||||
require('./../components/admin/AdminDirectory.vue').default
|
||||
);
|
||||
|
||||
Vue.component(
|
||||
'hashtag-component',
|
||||
require('./../components/admin/AdminHashtags.vue').default
|
||||
);
|
||||
|
|
|
@ -1,43 +1,13 @@
|
|||
@extends('admin.partial.template-full')
|
||||
|
||||
@section('section')
|
||||
<div class="title">
|
||||
<h3 class="font-weight-bold d-inline-block">Hashtags</h3>
|
||||
</div>
|
||||
<hr>
|
||||
<table class="table table-responsive">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th scope="col" width="10%">#</th>
|
||||
<th scope="col" width="30%">Hashtag</th>
|
||||
<th scope="col" width="15%">Status Count</th>
|
||||
<th scope="col" width="10%">NSFW</th>
|
||||
<th scope="col" width="10%">Banned</th>
|
||||
<th scope="col" width="15%">Created</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($hashtags as $tag)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/i/admin/apps/show/{{$tag->id}}" class="btn btn-sm btn-outline-primary">
|
||||
{{$tag->id}}
|
||||
</a>
|
||||
</td>
|
||||
<td class="font-weight-bold">{{$tag->name}}</td>
|
||||
<td class="font-weight-bold text-center">
|
||||
<a href="{{$tag->url()}}">
|
||||
{{$tag->posts()->count()}}
|
||||
</a>
|
||||
</td>
|
||||
<td class="font-weight-bold">{{$tag->is_nsfw ? 'true' : 'false'}}</td>
|
||||
<td class="font-weight-bold">{{$tag->is_banned ? 'true' : 'false'}}</td>
|
||||
<td class="font-weight-bold">{{$tag->created_at->diffForHumans()}}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-center mt-5 small">
|
||||
{{$hashtags->links()}}
|
||||
</div>
|
||||
<hashtag-component />
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
new Vue({ el: '#panel'});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
|
|
@ -108,6 +108,11 @@ Route::domain(config('pixelfed.domain.admin'))->prefix('i/admin')->group(functio
|
|||
Route::post('directory/testimonial/save', 'AdminController@directorySaveTestimonial');
|
||||
Route::post('directory/testimonial/delete', 'AdminController@directoryDeleteTestimonial');
|
||||
Route::post('directory/testimonial/update', 'AdminController@directoryUpdateTestimonial');
|
||||
Route::get('hashtags/stats', 'AdminController@hashtagsStats');
|
||||
Route::get('hashtags/query', 'AdminController@hashtagsApi');
|
||||
Route::get('hashtags/get', 'AdminController@hashtagsGet');
|
||||
Route::post('hashtags/update', 'AdminController@hashtagsUpdate');
|
||||
Route::post('hashtags/clear-trending-cache', 'AdminController@hashtagsClearTrendingCache');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue