(control) GUI for atags export

This commit is contained in:
Viktor Lofgren 2023-10-31 17:55:47 +01:00
parent 23f2068e33
commit c77a5b7cb6
7 changed files with 98 additions and 5 deletions

View File

@ -86,6 +86,13 @@ public class ExecutorClient extends AbstractDynamicClient {
.blockingSubscribe(); .blockingSubscribe();
} }
public void exportAtags(Context ctx, int node, String fid) {
post(ctx, node, "/export/atags?fid="+fid, "").blockingSubscribe();
}
public void exportData(Context ctx, int node) {
post(ctx, node, "/export/data", "").blockingSubscribe();
}
public void restoreBackup(Context context, int node, String fid) { public void restoreBackup(Context context, int node, String fid) {
post(context, node, "/backup/" + fid + "/restore", "").blockingSubscribe(); post(context, node, "/backup/" + fid + "/restore", "").blockingSubscribe();
} }

View File

@ -12,6 +12,9 @@ public record FileStorageWithActions(FileStorage storage) {
public boolean isCrawlable() { public boolean isCrawlable() {
return storage.type() == FileStorageType.CRAWL_SPEC; return storage.type() == FileStorageType.CRAWL_SPEC;
} }
public boolean isAtagsExportable() {
return storage.type() == FileStorageType.CRAWL_DATA;
}
public boolean isRecrawlable() { public boolean isRecrawlable() {
return storage.type() == FileStorageType.CRAWL_DATA; return storage.type() == FileStorageType.CRAWL_DATA;
} }

View File

@ -111,11 +111,26 @@ public class ControlNodeService {
Spark.post("/public/nodes/:id/storage/backup-restore/:fid", this::triggerRestoreBackup, Spark.post("/public/nodes/:id/storage/backup-restore/:fid", this::triggerRestoreBackup,
redirectControl.renderRedirectAcknowledgement("Restoring", "..") redirectControl.renderRedirectAcknowledgement("Restoring", "..")
); );
Spark.post("/public/nodes/:id/actions/export-data", this::exportData,
redirectControl.renderRedirectAcknowledgement("Exporting", "../storage/exports")
);
Spark.post("/public/nodes/:id/storage/:fid/export-atags", this::exportAtags,
redirectControl.renderRedirectAcknowledgement("Exporting", "../../storage/exports")
);
Spark.post("/public/nodes/:id/fsms/:fsm/start", this::startFsm); Spark.post("/public/nodes/:id/fsms/:fsm/start", this::startFsm);
Spark.post("/public/nodes/:id/fsms/:fsm/stop", this::stopFsm); Spark.post("/public/nodes/:id/fsms/:fsm/stop", this::stopFsm);
} }
private Object exportData(Request req, Response rsp) {
executorClient.exportData(Context.fromRequest(req), Integer.parseInt(req.params("id")));
return "";
}
private Object exportAtags(Request req, Response rsp) {
executorClient.exportAtags(Context.fromRequest(req), Integer.parseInt(req.params("id")), req.params("fid"));
return "";
}
public Object startFsm(Request req, Response rsp) throws Exception { public Object startFsm(Request req, Response rsp) throws Exception {
executorClient.startFsm(Context.fromRequest(req), Integer.parseInt(req.params("id")), req.params("fsm").toUpperCase()); executorClient.startFsm(Context.fromRequest(req), Integer.parseInt(req.params("id")), req.params("fsm").toUpperCase());

View File

@ -288,6 +288,34 @@
</form> </form>
</div> </div>
</div> </div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapseExportData"
aria-expanded="false"
aria-controls="collapseExportData">
Export Database Data
</button>
</h2>
<div id="collapseExportData" class="accordion-collapse collapse p-3" data-bs-parent="#accordionActions">
This will export database data: Domains, blacklist and domain links.
<form method="post" action="actions/export-data" onsubmit="return confirm('Confirm export')">
<div class="my-3 py-3">
<div class="row">
<div class="col">
<button type="submit" class="btn btn-primary">Export</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div> </div>
</div> </div>

View File

@ -67,6 +67,14 @@
</tr> </tr>
</form> </form>
{{/if}} {{/if}}
{{#if isAtagsExportable}}
<form method="post" action="/nodes/{{node.id}}/storage/{{storage.id}}/export-atags" onsubmit="return confirm('Confirm export of anchor tags from {{storage.path}}')">
<tr>
<td>Export anchor tags from this crawl data</td>
<td><button class="btn btn-secondary" type="submit">Export</button></td>
</tr>
</form>
{{/if}}
{{#if isRestorable}} {{#if isRestorable}}
<form method="post" action="/nodes/{{node.id}}/storage/backup-restore/{{storage.id}}" onsubmit="return confirm('Confirm restoring backup {{storage.path}}')"> <form method="post" action="/nodes/{{node.id}}/storage/backup-restore/{{storage.id}}" onsubmit="return confirm('Confirm restoring backup {{storage.path}}')">
<tr> <tr>

View File

@ -8,10 +8,7 @@ import nu.marginalia.actor.ExecutorActorControlService;
import nu.marginalia.actor.state.ActorStateInstance; import nu.marginalia.actor.state.ActorStateInstance;
import nu.marginalia.executor.model.ActorRunState; import nu.marginalia.executor.model.ActorRunState;
import nu.marginalia.executor.model.ActorRunStates; import nu.marginalia.executor.model.ActorRunStates;
import nu.marginalia.executor.svc.BackupService; import nu.marginalia.executor.svc.*;
import nu.marginalia.executor.svc.ProcessingService;
import nu.marginalia.executor.svc.SideloadService;
import nu.marginalia.executor.svc.TransferService;
import nu.marginalia.service.server.BaseServiceParams; import nu.marginalia.service.server.BaseServiceParams;
import nu.marginalia.service.server.Service; import nu.marginalia.service.server.Service;
import nu.marginalia.service.server.mq.MqNotification; import nu.marginalia.service.server.mq.MqNotification;
@ -44,6 +41,7 @@ public class ExecutorSvc extends Service {
ProcessingService processingService, ProcessingService processingService,
SideloadService sideloadService, SideloadService sideloadService,
BackupService backupService, BackupService backupService,
ExportService exportService,
FileStorageService fileStorageService, FileStorageService fileStorageService,
Gson gson, Gson gson,
TransferService transferService, TransferService transferService,
@ -72,6 +70,9 @@ public class ExecutorSvc extends Service {
Spark.post("/sideload/stackexchange", sideloadService::sideloadStackexchange); Spark.post("/sideload/stackexchange", sideloadService::sideloadStackexchange);
Spark.post("/sideload/encyclopedia", sideloadService::sideloadEncyclopedia); Spark.post("/sideload/encyclopedia", sideloadService::sideloadEncyclopedia);
Spark.post("/export/atags", exportService::exportAtags);
Spark.post("/export/data", exportService::exportData);
Spark.post("/backup/:fid/restore", backupService::restore); Spark.post("/backup/:fid/restore", backupService::restore);
Spark.get("/storage/:fid", transferService::listFiles, gson::toJson); Spark.get("/storage/:fid", transferService::listFiles, gson::toJson);

View File

@ -0,0 +1,31 @@
package nu.marginalia.executor.svc;
import com.google.inject.Inject;
import nu.marginalia.actor.ExecutorActor;
import nu.marginalia.actor.ExecutorActorControlService;
import nu.marginalia.actor.task.ConvertActor;
import nu.marginalia.actor.task.ExportAtagsActor;
import nu.marginalia.actor.task.ExportDataActor;
import nu.marginalia.storage.model.FileStorageId;
import spark.Request;
import spark.Response;
public class ExportService {
private final ExecutorActorControlService actorControlService;
@Inject
public ExportService(ExecutorActorControlService actorControlService) {
this.actorControlService = actorControlService;
}
public Object exportData(Request request, Response response) throws Exception {
actorControlService.startFrom(ExecutorActor.EXPORT_DATA, new ExportDataActor.Export());
return "";
}
public Object exportAtags(Request request, Response response) throws Exception {
actorControlService.startFrom(ExecutorActor.EXPORT_ATAGS, new ExportAtagsActor.Export(FileStorageId.parse(request.queryParams("fid"))));
return "";
}
}