(control) Administrative QOL improvement, GUI for banning spam

This commit is contained in:
Viktor Lofgren 2023-10-07 15:43:18 +02:00
parent 1b418d77ff
commit 49344d7ea8
5 changed files with 82 additions and 1 deletions

View File

@ -45,6 +45,7 @@ dependencies {
implementation libs.notnull
implementation libs.guice
implementation libs.zstd
implementation libs.rxjava
implementation libs.trove
implementation libs.spark

View File

@ -3,6 +3,7 @@ package nu.marginalia.control;
import com.google.gson.Gson;
import com.google.inject.Inject;
import gnu.trove.list.array.TIntArrayList;
import nu.marginalia.client.Context;
import nu.marginalia.client.ServiceMonitors;
import nu.marginalia.control.actor.Actor;
import nu.marginalia.control.model.*;
@ -10,9 +11,11 @@ import nu.marginalia.control.svc.*;
import nu.marginalia.db.storage.model.FileStorageId;
import nu.marginalia.db.storage.model.FileStorageType;
import nu.marginalia.model.EdgeDomain;
import nu.marginalia.model.EdgeUrl;
import nu.marginalia.model.gson.GsonFactory;
import nu.marginalia.renderer.RendererFactory;
import nu.marginalia.screenshot.ScreenshotService;
import nu.marginalia.search.client.SearchClient;
import nu.marginalia.service.server.*;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
@ -38,6 +41,7 @@ public class ControlService extends Service {
private final DomainComplaintService domainComplaintService;
private final ControlBlacklistService blacklistService;
private final RandomExplorationService randomExplorationService;
private final SearchClient searchClient;
private final ControlActorService controlActorService;
private final StaticResources staticResources;
private final MessageQueueService messageQueueService;
@ -59,7 +63,8 @@ public class ControlService extends Service {
ControlBlacklistService blacklistService,
ControlActionsService controlActionsService,
ScreenshotService screenshotService,
RandomExplorationService randomExplorationService
RandomExplorationService randomExplorationService,
SearchClient searchClient
) throws IOException {
super(params);
@ -70,6 +75,7 @@ public class ControlService extends Service {
this.domainComplaintService = domainComplaintService;
this.blacklistService = blacklistService;
this.randomExplorationService = randomExplorationService;
this.searchClient = searchClient;
var indexRenderer = rendererFactory.renderer("control/index");
var eventsRenderer = rendererFactory.renderer("control/events");
@ -96,6 +102,7 @@ public class ControlService extends Service {
var actionsViewRenderer = rendererFactory.renderer("control/actions");
var blacklistRenderer = rendererFactory.renderer("control/blacklist");
var searchToBanRenderer = rendererFactory.renderer("control/search-to-ban");
this.controlActorService = controlActorService;
@ -169,6 +176,9 @@ public class ControlService extends Service {
Spark.get("/public/blacklist", this::blacklistModel, blacklistRenderer::render);
Spark.post("/public/blacklist", this::updateBlacklist, redirectToBlacklist);
Spark.get("/public/search-to-ban", this::searchToBanModel, searchToBanRenderer::render);
Spark.post("/public/search-to-ban", this::searchToBanModel, searchToBanRenderer::render);
// API Keys
Spark.get("/public/api-keys", this::apiKeysModel, apiKeysRenderer::render);
@ -242,6 +252,37 @@ public class ControlService extends Service {
return Map.of("blacklist", blacklistService.lastNAdditions(100));
}
private Object searchToBanModel(Request request, Response response) {
String q = request.queryParams("q");
if (Objects.equals(request.requestMethod(), "POST")) {
request.params().forEach((k,v) -> System.out.println(k + " -- " + v));
List<String> bannedUrls = new ArrayList<>();
String query = request.queryParams("query");
for (var param : request.queryParams()) {
if ("query".equals(param)) {
continue;
}
EdgeUrl.parse(param).ifPresent(url ->
blacklistService.addToBlacklist(url.domain, query)
);
bannedUrls.add(param);
}
request.queryParams().forEach(System.out::println);
q = query;
}
if (q == null || q.isBlank()) {
return Map.of();
} else {
return searchClient
.query(Context.fromRequest(request), q, 200, 5)
.blockingFirst();
}
}
private Object updateBlacklist(Request request, Response response) {
var domain = new EdgeDomain(request.queryParams("domain"));
if ("add".equals(request.queryParams("act"))) {

View File

@ -4,6 +4,7 @@
<li>Manage</li>
<li><a href="/api-keys" title="Create or remove API keys">API Keys</a></li>
<li><a href="/blacklist" title="Add or remove website sanctions">Blacklist</a></li>
<li><a href="/search-to-ban" title="Search function for easy blacklisting">Blacklist Search</a></li>
<li><a href="/complaints" title="View and act on user complaints">Complaints</a></li>
<li><a href="/review-random-domains" title="Review random domains list">Random Exploration</a></li>
<li>System</li>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>Control Service</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/style.css" />
</head>
<body>
{{> control/partials/nav}}
<section>
<h1>Search to Ban</h1>
<form action="/search-to-ban">
<label for="q">Search Query</label><br>
<input type="text" value="{{query}}" name="q" id="q" /> <input type="submit" value="Search" />
</form>
{{#unless results}}
<p>This utility lets you use the search engine to find spammy results, and ban them
by using the checkbox next to the result. </p>
{{/unless}}
{{#if results}}
<hr>
<form action="/search-to-ban" method="post">
<input type="submit" value="Blacklist Selected Domains">
<input type="hidden" name="query" text="{{query}}" />
<table>
{{#each results}}
<tr><td><input type="checkbox" name="{{url}}"><td>{{title}}</td></tr>
<tr><td colspan="2"><a href="{{url}}>{{url}}</a></td></tr>
<tr><td colspan="2">{{description}}</td></tr>
<tr><td colspan="2">&nbsp;</td></tr>
{{/each}}
</table>
{{/if}}
</form>
</section>
</body>
</html>

View File

@ -48,6 +48,7 @@ public class SearchApiQueryService {
case "1" -> SearchProfile.MODERN;
case "2" -> SearchProfile.DEFAULT;
case "3" -> SearchProfile.CORPO_CLEAN;
case "5" -> SearchProfile.YOLO;
case "blogosphere" -> SearchProfile.BLOGOSPHERE;
default -> SearchProfile.CORPO_CLEAN;
};