Add hashtag administration

pull/4021/head
Daniel Supernault 3 years ago
parent f9341d0197
commit 8487231177
No known key found for this signature in database
GPG Key ID: 0DEF1C662C9033F7

@ -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…
Cancel
Save