mirror of https://github.com/pixelfed/pixelfed.git
Add hashtag administration
This commit is contained in:
parent
f9341d0197
commit
8487231177
|
@ -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)
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"/js/profile-directory.js": "/js/profile-directory.js?id=62b575734ca1d8e8b780b5dbcde82680",
|
||||
"/js/story-compose.js": "/js/story-compose.js?id=9d606ec8de7ba57ed1402c531a3937ed",
|
||||
"/js/direct.js": "/js/direct.js?id=83f62237dcbdcd3c3b0dd97ebb8cf4aa",
|
||||
"/js/admin.js": "/js/admin.js?id=145e57a8fe4986cf8fce7378284e8c1f",
|
||||
"/js/admin.js": "/js/admin.js?id=09ff5d52a465c7c7e9e04209eeb76df6",
|
||||
"/js/rempro.js": "/js/rempro.js?id=61bb49ccfe70d28ed788750f9c6279b2",
|
||||
"/js/rempos.js": "/js/rempos.js?id=da10eddc2edd1d3a29d8ffcd75d239dc",
|
||||
"/js/live-player.js": "/js/live-player.js?id=674d2b72d4cf417d9d7a3953c55f37ca",
|
||||
|
@ -43,8 +43,8 @@
|
|||
"/css/appdark.css": "/css/appdark.css?id=de85ecce91d9ed7afa7714547eb1e26c",
|
||||
"/css/app.css": "/css/app.css?id=88a0a931d5b0e24b0d9355f548414768",
|
||||
"/css/portfolio.css": "/css/portfolio.css?id=db2c9929a56d83f9ff2aaf2161d29d36",
|
||||
"/css/admin.css": "/css/admin.css?id=c39d4fbc91a140c22cf5afe5d9faa827",
|
||||
"/css/admin.css": "/css/admin.css?id=619b6c6613a24e232048856e72110862",
|
||||
"/css/landing.css": "/css/landing.css?id=e852a642699916fc9ff8208d7e06daa8",
|
||||
"/css/spa.css": "/css/spa.css?id=602c4f74ce800b7bf45a8d8a4d8cb6e5",
|
||||
"/js/vendor.js": "/js/vendor.js?id=cedafb53a2de5dd37758d3009b4b21c1"
|
||||
"/js/vendor.js": "/js/vendor.js?id=be64338fb941b8e58b836490ef0e96be"
|
||||
}
|
||||
|
|
|
@ -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 New Issue