Continue changes to allow uploads to be "pending" so a decision can be made to either upload or skip them (and ultimately, edit as well).

This commit is contained in:
2021-11-06 22:56:27 +10:30
parent e1f18b104f
commit 42fb7a2003
8 changed files with 233 additions and 68 deletions

View File

@@ -160,7 +160,6 @@
{{ end }}
{{ define "js" }}
<script src="//unpkg.com/alpinejs" defer></script>
<script>
function configuration() {
return {

View File

@@ -1,45 +1,129 @@
{{ define "content" }}
<main role="main" class="inner DAU">
<main role="main" x-data="uploads()" x-init="get_uploads();" class="inner DAU">
<h1 class="DAU-heading">Uploads</h1>
<p class="lead">Discord-auto-upload uploads</p>
<h2>Pending uploads</h2>
<table class="table table-condensed table-dark">
<thead>
<tr><th>uploaded</th><th>dt</th><th>thumb</th></tr>
<tr>
<th>filename</th>
<th>actions</th>
</tr>
</thead>
<tbody id="uploads">
<tbody>
<template x-for="ul in pending">
<tr>
<td x-text="ul.original_file"></td>
<td>
<button @click="start_upload(ul.id)" type="button" class="btn btn-primary">upload</button>
<button @click="skip_upload(ul.id)" type="button" class="btn btn-primary">reject</button>
</td>
</tr>
</template>
</tbody>
</table>
<h2>Current uploads</h2>
<table class="table table-condensed table-dark">
<thead>
<tr>
<th>filename</th>
<th>actions</th>
</tr>
</thead>
<tbody>
<template x-for="ul in uploads">
<tr>
<td x-text="ul.original_file"></td>
<td>
<button @click="start_upload(ul.id)" type="button" class="btn btn-primary">upload</button>
</td>
</tr>
</template>
</tbody>
</table>
<h2>Completed uploads</h2>
<table class="table table-condensed table-dark">
<thead>
<tr>
<th>filename</th>
<th>state</th>
</tr>
</thead>
<tbody>
<template x-for="ul in finished">
<tr>
<td x-text="ul.original_file"></td>
<td x-text="ul.state"></td>
</tr>
</template>
</tbody>
</table>
</main>
{{ end }}
{{ define "js" }}
<script>
$(document).ready(function() {
get_uploads();
});
function get_uploads() {
$.ajax({ method: 'get', url: '/rest/uploads'})
.done(function(data) {
console.log(data);
$('#uploads').empty();
if (! data) { return }
data.forEach(i => {
// {uploaded: true, uploaded_at: "2021-06-08T21:59:52.855936+09:30", url: "https://cdn.discordapp.com/attachments/849615269706203171/851800197046468628/dau736004285.png", width: 640, height: 640}
console.log(i);
row = $('<tr>');
row.append($('<td>').text(i.uploaded ? 'yes' : 'no'));
row.append($('<td>').text(i.uploaded_at));
row.append($('<td>').html($('<img>', { width : i.width/10, height : i.height/10, src : i.url })));
$('#uploads').prepend(row);
});
});
}
function uploads() {
return {
pending: [], uploads: [], finished: [],
start_upload(id) {
console.log(id);
fetch('/rest/upload/'+id+'/start', {method: 'POST'})
.then(response => response.json()) // convert to json
.then(json => {
console.log(json);
})
},
skip_upload(id) {
console.log(id);
fetch('/rest/upload/'+id+'/skip', {method: 'POST'})
.then(response => response.json()) // convert to json
.then(json => {
console.log(json);
})
},
get_uploads() {
fetch('/rest/uploads')
.then(response => response.json()) // convert to json
.then(json => {
this.pending = [];
this.uploads = [];
this.finished = [];
json.forEach(ul => {
if (ul.state == 'Pending') {
this.pending.push(ul);
}
else if (ul.state == 'Complete' || ul.state == 'Failed' || ul.state == 'Skipped') {
this.finished.push(ul)
}
else {
this.uploads.push(ul);
}
});
this.config = json;
console.log(json);
let self = this;
setTimeout(function() { self.get_uploads(); } , 1000);
})
},
}
}
</script>
{{ end }}

View File

@@ -10,7 +10,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
<script src="//unpkg.com/alpinejs" defer></script>
<style>
.bd-placeholder-img {

View File

@@ -10,8 +10,11 @@ import (
"mime"
"net/http"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/gorilla/mux"
"github.com/tardisx/discord-auto-upload/config"
daulog "github.com/tardisx/discord-auto-upload/log"
"github.com/tardisx/discord-auto-upload/upload"
@@ -23,6 +26,19 @@ type WebService struct {
Uploader *upload.Uploader
}
type ErrorResponse struct {
Error string `json:"error"`
}
type StartUploadRequest struct {
Id int32 `json:"id"`
}
type StartUploadResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
}
//go:embed data
var webFS embed.FS
@@ -43,6 +59,7 @@ func (ws *WebService) getStatic(w http.ResponseWriter, r *http.Request) {
extension := filepath.Ext(string(path))
if extension == ".html" { // html file
t, err := template.ParseFS(webFS, "data/wrapper.tmpl", "data/"+path)
if err != nil {
daulog.SendLog(fmt.Sprintf("when fetching: %s got: %s", path, err), daulog.LogTypeError)
@@ -109,33 +126,23 @@ func (ws *WebService) getLogs(w http.ResponseWriter, r *http.Request) {
func (ws *WebService) handleConfig(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
type ErrorResponse struct {
Error string `json:"error"`
}
newConfig := config.ConfigV2{}
defer r.Body.Close()
b, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(400)
w.Write([]byte("bad body"))
returnJSONError(w, "could not read body?")
return
}
err = json.Unmarshal(b, &newConfig)
if err != nil {
w.WriteHeader(400)
j, _ := json.Marshal(ErrorResponse{Error: "badly formed JSON"})
w.Write(j)
returnJSONError(w, "badly formed JSON")
return
}
ws.Config.Config = &newConfig
err = ws.Config.Save()
if err != nil {
w.WriteHeader(400)
j, _ := json.Marshal(ErrorResponse{Error: err.Error()})
w.Write(j)
returnJSONError(w, err.Error())
return
}
// config has changed, so tell the world
@@ -155,27 +162,92 @@ func (ws *WebService) getUploads(w http.ResponseWriter, r *http.Request) {
text, err := json.Marshal(ups)
if err != nil {
daulog.SendLog(fmt.Sprintf("err: %v", err), daulog.LogTypeError)
w.Write([]byte("could not marshall uploads?"))
return
// not sure how this would happen, so we probably want to find out the hard way
panic(err)
}
w.Write([]byte(text))
}
func (ws *WebService) modifyUpload(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.Method == "POST" {
vars := mux.Vars(r)
change := vars["change"]
id, err := strconv.ParseInt(vars["id"], 10, 32)
if err != nil {
returnJSONError(w, "bad id")
return
}
for _, anUpload := range ws.Uploader.Uploads {
if anUpload.Id == int32(id) {
if anUpload.State == upload.StatePending {
if change == "start" {
anUpload.State = upload.StateQueued
res := StartUploadResponse{Success: true, Message: "upload queued"}
resString, _ := json.Marshal(res)
w.Write(resString)
return
} else if change == "skip" {
anUpload.State = upload.StateSkipped
res := StartUploadResponse{Success: true, Message: "upload skipped"}
resString, _ := json.Marshal(res)
w.Write(resString)
return
} else {
returnJSONError(w, "bad change type")
return
}
}
}
}
res := StartUploadResponse{Success: false, Message: "upload does not exist, or already queued"}
resString, _ := json.Marshal(res)
w.WriteHeader(400)
w.Write(resString)
return
}
returnJSONError(w, "bad request")
return
}
func (ws *WebService) StartWebServer() {
http.HandleFunc("/", ws.getStatic)
r := mux.NewRouter()
http.HandleFunc("/rest/logs", ws.getLogs)
http.HandleFunc("/rest/uploads", ws.getUploads)
http.HandleFunc("/rest/config", ws.handleConfig)
r.HandleFunc("/rest/logs", ws.getLogs)
r.HandleFunc("/rest/uploads", ws.getUploads)
r.HandleFunc("/rest/upload/{id:[0-9]+}/{change}", ws.modifyUpload)
r.HandleFunc("/rest/config", ws.handleConfig)
r.PathPrefix("/").HandlerFunc(ws.getStatic)
go func() {
listen := fmt.Sprintf(":%d", ws.Config.Config.Port)
log.Printf("Starting web server on http://localhost%s", listen)
err := http.ListenAndServe(listen, nil) // set listen port
if err != nil {
log.Fatal("ListenAndServe: ", err)
srv := &http.Server{
Handler: r,
Addr: listen,
// Good practice: enforce timeouts for servers you create!
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
}()
}
func returnJSONError(w http.ResponseWriter, errMessage string) {
w.WriteHeader(400)
errJSON := ErrorResponse{
Error: errMessage,
}
errString, _ := json.Marshal(errJSON)
w.Write(errString)
}