瀏覽代碼

Add hashtag administration

Daniel Supernault 2 年之前
父節點
當前提交
8487231177

+ 102 - 0
app/Http/Controllers/Admin/AdminHashtagsController.php

@@ -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 [];
+    }
+
+}

+ 3 - 6
app/Http/Controllers/AdminController.php

@@ -12,6 +12,7 @@ use App\{
 	Profile,
 	Profile,
 	Report,
 	Report,
 	Status,
 	Status,
+	StatusHashtag,
 	Story,
 	Story,
 	User
 	User
 };
 };
@@ -22,6 +23,7 @@ use Illuminate\Support\Facades\Redis;
 use App\Http\Controllers\Admin\{
 use App\Http\Controllers\Admin\{
 	AdminDirectoryController,
 	AdminDirectoryController,
 	AdminDiscoverController,
 	AdminDiscoverController,
+	AdminHashtagsController,
 	AdminInstanceController,
 	AdminInstanceController,
 	AdminReportController,
 	AdminReportController,
 	// AdminGroupsController,
 	// AdminGroupsController,
@@ -43,6 +45,7 @@ class AdminController extends Controller
 	use AdminReportController, 
 	use AdminReportController, 
 	AdminDirectoryController,
 	AdminDirectoryController,
 	AdminDiscoverController,
 	AdminDiscoverController,
+	AdminHashtagsController,
 	// AdminGroupsController,
 	// AdminGroupsController,
 	AdminMediaController, 
 	AdminMediaController, 
 	AdminSettingsController, 
 	AdminSettingsController, 
@@ -201,12 +204,6 @@ class AdminController extends Controller
 		return view('admin.apps.home', compact('apps'));
 		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)
 	public function messagesHome(Request $request)
 	{
 	{
 		$messages = Contact::orderByDesc('id')->paginate(10);
 		$messages = Contact::orderByDesc('id')->paginate(10);

+ 2 - 27
app/Http/Controllers/DiscoverController.php

@@ -24,6 +24,7 @@ use App\Services\ReblogService;
 use App\Services\StatusHashtagService;
 use App\Services\StatusHashtagService;
 use App\Services\SnowflakeService;
 use App\Services\SnowflakeService;
 use App\Services\StatusService;
 use App\Services\StatusService;
+use App\Services\TrendingHashtagService;
 use App\Services\UserFilterService;
 use App\Services\UserFilterService;
 
 
 class DiscoverController extends Controller
 class DiscoverController extends Controller
@@ -181,33 +182,7 @@ class DiscoverController extends Controller
 	{
 	{
 		abort_if(!$request->user(), 403);
 		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;
 		return $res;
 	}
 	}
 
 

+ 2 - 9
app/Services/SearchApiV2Service.php

@@ -96,16 +96,9 @@ class SearchApiV2Service
 			$query = substr($rawQuery, 1) . '%';
 			$query = substr($rawQuery, 1) . '%';
 		}
 		}
 		$banned = InstanceService::getBannedDomains();
 		$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)
 			->where('username', 'like', $query)
-			->orderBy('domain')
 			->orderByDesc('profiles.followers_count')
 			->orderByDesc('profiles.followers_count')
-			->orderByDesc('followers.created_at')
 			->offset($offset)
 			->offset($offset)
 			->limit($limit)
 			->limit($limit)
 			->get()
 			->get()
@@ -131,7 +124,7 @@ class SearchApiV2Service
 		$limit = $this->query->input('limit') ?? 20;
 		$limit = $this->query->input('limit') ?? 20;
 		$offset = $this->query->input('offset') ?? 0;
 		$offset = $this->query->input('offset') ?? 0;
 		$query = '%' . $this->query->input('q') . '%';
 		$query = '%' . $this->query->input('q') . '%';
-		return Hashtag::whereIsBanned(false)
+		return Hashtag::where('can_search', true)
 			->where('name', 'like', $query)
 			->where('name', 'like', $query)
 			->offset($offset)
 			->offset($offset)
 			->limit($limit)
 			->limit($limit)

二進制
public/css/admin.css


二進制
public/js/admin.js


二進制
public/js/vendor.js


+ 5 - 5
public/js/vendor.js.LICENSE.txt

@@ -49,7 +49,7 @@
  */
  */
 
 
 /*!
 /*!
- * Pusher JavaScript Library v7.5.0
+ * Pusher JavaScript Library v7.6.0
  * https://pusher.com/
  * https://pusher.com/
  *
  *
  * Copyright 2020, Pusher
  * Copyright 2020, Pusher
@@ -65,14 +65,14 @@
  */
  */
 
 
 /*!
 /*!
- * Sizzle CSS Selector Engine v2.3.6
+ * Sizzle CSS Selector Engine v2.3.8
  * https://sizzlejs.com/
  * https://sizzlejs.com/
  *
  *
  * Copyright JS Foundation and other contributors
  * Copyright JS Foundation and other contributors
  * Released under the MIT license
  * Released under the MIT license
  * https://js.foundation/
  * 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/
  * https://jquery.com/
  *
  *
  * Includes Sizzle.js
  * Includes Sizzle.js
@@ -92,7 +92,7 @@
  * Released under the MIT license
  * Released under the MIT license
  * https://jquery.org/license
  * https://jquery.org/license
  *
  *
- * Date: 2022-08-26T17:52Z
+ * Date: 2022-12-13T14:56Z
  */
  */
 
 
 /*!
 /*!

二進制
public/mix-manifest.json


+ 10 - 0
resources/assets/js/admin.js

@@ -20,3 +20,13 @@ Chart.defaults.global.defaultFontFamily = "-apple-system,BlinkMacSystemFont,Sego
 Array.from(document.querySelectorAll('.pagination .page-link'))
 Array.from(document.querySelectorAll('.pagination .page-link'))
 .filter(el => el.textContent === '« Previous' || el.textContent === 'Next »')
 .filter(el => el.textContent === '« Previous' || el.textContent === 'Next »')
 .forEach(el => el.textContent = (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
+);

+ 8 - 38
resources/views/admin/hashtags/home.blade.php

@@ -1,43 +1,13 @@
 @extends('admin.partial.template-full')
 @extends('admin.partial.template-full')
 
 
 @section('section')
 @section('section')
-<div class="title">
-	<h3 class="font-weight-bold d-inline-block">Hashtags</h3>
 </div>
 </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
 @endsection
+
+@push('scripts')
+<script type="text/javascript">
+    new Vue({ el: '#panel'});
+</script>
+@endpush
+

+ 5 - 0
routes/web.php

@@ -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/save', 'AdminController@directorySaveTestimonial');
 		Route::post('directory/testimonial/delete', 'AdminController@directoryDeleteTestimonial');
 		Route::post('directory/testimonial/delete', 'AdminController@directoryDeleteTestimonial');
 		Route::post('directory/testimonial/update', 'AdminController@directoryUpdateTestimonial');
 		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');
 	});
 	});
 });
 });