Compare commits
2 Commits
08dbeda80a
...
f5e9a0faec
Author | SHA1 | Date | |
---|---|---|---|
f5e9a0faec | |||
bc19b0a70f |
@ -103,7 +103,7 @@ Parity features
|
||||
* [ ] set a working directory for item actions
|
||||
* [ ] crontab integration
|
||||
* [ ] source batching
|
||||
* [ ] add item from web
|
||||
* [x] add item from web
|
||||
* [ ] Nix build
|
||||
* [ ] NixOS module
|
||||
* [ ] NixOS vm demo
|
||||
|
@ -81,14 +81,9 @@ func actionExecute(
|
||||
|
||||
db := openAndMigrateDb()
|
||||
|
||||
state, err := core.GetState(db, source)
|
||||
state, envs, argv, postProcess, err := core.GetSourceActionInputs(db, source, action)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to load state for %s: %v", source, err)
|
||||
}
|
||||
|
||||
envs, err := core.GetEnvs(db, source)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to get envs for %s: %v", source, err)
|
||||
log.Fatalf("error: failed to load data for %s: %v", source, err)
|
||||
}
|
||||
|
||||
item, err := core.GetItem(db, source, itemId)
|
||||
@ -104,16 +99,6 @@ func actionExecute(
|
||||
}
|
||||
}
|
||||
|
||||
argv, err := core.GetArgvForAction(db, source, action)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to get action: %v", err)
|
||||
}
|
||||
|
||||
postProcess, err := core.GetSourcePostProcessor(db, source)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to get source post-processor: %v", err)
|
||||
}
|
||||
|
||||
newItem, newState, err := core.ExecuteItemAction(item, argv, envs, state, time.Minute, postProcess)
|
||||
if err != nil {
|
||||
log.Fatalf("error executing %s: %v", action, err)
|
||||
|
@ -43,24 +43,9 @@ func sourceFetch(source string, format string, dryRun bool) {
|
||||
|
||||
db := openAndMigrateDb()
|
||||
|
||||
state, err := core.GetState(db, source)
|
||||
state, envs, argv, postProcess, err := core.GetSourceActionInputs(db, source, "fetch")
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to load state for %s: %v", source, err)
|
||||
}
|
||||
|
||||
envs, err := core.GetEnvs(db, source)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to get envs for %s: %v", source, err)
|
||||
}
|
||||
|
||||
argv, err := core.GetArgvForAction(db, source, "fetch")
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to get fetch action: %v", err)
|
||||
}
|
||||
|
||||
postProcess, err := core.GetSourcePostProcessor(db, source)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to get source post-processor: %v", err)
|
||||
log.Fatalf("error: failed to load data for %s: %v", source, err)
|
||||
}
|
||||
|
||||
items, newState, err := core.Execute(source, argv, envs, state, "", time.Minute, postProcess)
|
||||
|
@ -114,6 +114,39 @@ func GetSourcePostProcessor(db DB, source string) (func(item Item) Item, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetSourceActionInputs(
|
||||
db DB,
|
||||
source string,
|
||||
action string,
|
||||
) (
|
||||
state []byte,
|
||||
envs []string,
|
||||
argv []string,
|
||||
postProcess func(Item) Item,
|
||||
err error,
|
||||
) {
|
||||
state, err = GetState(db, source)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("failed to load state for %s: %v", source, err)
|
||||
}
|
||||
|
||||
envs, err = GetEnvs(db, source)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("failed to get envs for %s: %v", source, err)
|
||||
}
|
||||
|
||||
argv, err = GetArgvForAction(db, source, action)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("failed to get %s action for %s: %v", action, source, err)
|
||||
}
|
||||
|
||||
postProcess, err = GetSourcePostProcessor(db, source)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("failed to get %s post-processor: %v", source, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Given the results of a fetch, add new items, update existing items, and delete expired items.
|
||||
//
|
||||
// Returns the number of new and deleted items on success.
|
||||
|
@ -42,4 +42,36 @@
|
||||
{{ end }}
|
||||
</details>
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<details open>
|
||||
<summary><span class="feed-controls">Add item</span></summary>
|
||||
<form action="/item" method="post">
|
||||
<p>
|
||||
<input type="text" name="title" class="wide" placeholder="Title">
|
||||
</p>
|
||||
<p>
|
||||
<input type="url" name="link" class="wide" placeholder="Link">
|
||||
</p>
|
||||
<p>
|
||||
<textarea name="body" class="wide" placeholder="Body"></textarea>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ttl">TTL:</label>
|
||||
<input type="datetime-local" name="ttl">
|
||||
</p>
|
||||
<p>
|
||||
<label for="ttd">TTD:</label>
|
||||
<input type="datetime-local" name="ttd">
|
||||
</p>
|
||||
<p>
|
||||
<label for="tts">TTS:</label>
|
||||
<input type="datetime-local" name="tts">
|
||||
</p>
|
||||
<p>
|
||||
<input type="submit" value="Add">
|
||||
</p>
|
||||
</form>
|
||||
</details>
|
||||
</article>
|
||||
{{- end }}
|
||||
|
@ -133,7 +133,6 @@ var item = load("itemPage.html", "item.html")
|
||||
|
||||
type ItemData struct {
|
||||
Item core.Item
|
||||
Open bool
|
||||
}
|
||||
|
||||
func Item(writer io.Writer, data ItemData) {
|
||||
|
@ -71,6 +71,7 @@ summary:focus {
|
||||
.wide {
|
||||
width: 100%;
|
||||
resize: vertical;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.fade > * {
|
||||
opacity: 0.2;
|
||||
|
@ -1,5 +1,11 @@
|
||||
{{ define "title" }}{{ if .Item.Title }}{{ .Item.Title }}{{ else }}{{ .Item.Source }}/{{ .Item.Id }}{{ end }} - Intake [{{ .Item.Source }}]{{ end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
<article class="center">
|
||||
<span class="feed-controls">
|
||||
<a href="/">Home</a>
|
||||
</span>
|
||||
</article>
|
||||
|
||||
{{ template "item" .Item }}
|
||||
{{- end }}
|
||||
|
90
web/item.go
90
web/item.go
@ -1,6 +1,8 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -69,14 +71,9 @@ func (env *Env) doAction(writer http.ResponseWriter, req *http.Request) {
|
||||
id := req.PathValue("id")
|
||||
action := req.PathValue("action")
|
||||
|
||||
state, err := core.GetState(env.db, source)
|
||||
state, envs, argv, postProcess, err := core.GetSourceActionInputs(env.db, source, action)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to load state for %s: %v", source, err)
|
||||
}
|
||||
|
||||
envs, err := core.GetEnvs(env.db, source)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to get envs for %s: %v", source, err)
|
||||
http.Error(writer, fmt.Sprintf("error: failed to load data for %s: %v", source, err), 500)
|
||||
}
|
||||
|
||||
item, err := core.GetItem(env.db, source, id)
|
||||
@ -90,17 +87,6 @@ func (env *Env) doAction(writer http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
argv, err := core.GetArgvForAction(env.db, source, action)
|
||||
if err != nil {
|
||||
http.Error(writer, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
postProcess, err := core.GetSourcePostProcessor(env.db, source)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to get source post-processor: %v", err)
|
||||
}
|
||||
|
||||
newItem, newState, err := core.ExecuteItemAction(item, argv, envs, state, time.Minute, postProcess)
|
||||
if err != nil {
|
||||
http.Error(writer, err.Error(), 500)
|
||||
@ -151,3 +137,71 @@ func (env *Env) massDeactivate(writer http.ResponseWriter, req *http.Request) {
|
||||
writer.Header()["HX-Refresh"] = []string{"true"}
|
||||
http.Error(writer, "ok", http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (env *Env) addItem(writer http.ResponseWriter, req *http.Request) {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
log.Printf("error parsing form data: %v", err)
|
||||
http.Error(writer, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
exists, err := core.SourceExists(env.db, "default")
|
||||
if err != nil {
|
||||
http.Error(writer, fmt.Sprintf("error: failed to check for source: %v", err), 500)
|
||||
return
|
||||
}
|
||||
if !exists {
|
||||
if err := core.AddSource(env.db, "default"); err != nil {
|
||||
http.Error(writer, fmt.Sprintf("error: failed to add source: %v", err), 500)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
bytes := make([]byte, 16)
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
http.Error(writer, fmt.Sprintf("error: failed to generate id: %v", err), 500)
|
||||
}
|
||||
id := hex.EncodeToString(bytes)
|
||||
|
||||
title := req.PostForm.Get("title")
|
||||
link := req.PostForm.Get("link")
|
||||
body := req.PostForm.Get("body")
|
||||
|
||||
item := core.Item{
|
||||
Source: "default",
|
||||
Id: id,
|
||||
Title: title,
|
||||
Link: link,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
if ttl := req.PostForm.Get("ttl"); ttl != "" {
|
||||
ttl, _ := time.Parse("2006-01-02T15:04", ttl)
|
||||
item.Ttl = int(ttl.Unix() - now)
|
||||
}
|
||||
if ttd := req.PostForm.Get("ttd"); ttd != "" {
|
||||
ttd, _ := time.Parse("2006-01-02T15:04", ttd)
|
||||
item.Ttd = int(ttd.Unix() - now)
|
||||
}
|
||||
if tts := req.PostForm.Get("tts"); tts != "" {
|
||||
tts, _ := time.Parse("2006-01-02T15:04", tts)
|
||||
item.Tts = int(tts.Unix() - now)
|
||||
}
|
||||
|
||||
if err := core.AddItems(env.db, []core.Item{item}); err != nil {
|
||||
http.Error(writer, fmt.Sprintf("error: failed to add item: %s", err), 500)
|
||||
return
|
||||
}
|
||||
|
||||
item, err = core.GetItem(env.db, "default", id)
|
||||
if err != nil {
|
||||
http.Error(writer, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
data := html.ItemData{
|
||||
Item: item,
|
||||
}
|
||||
html.Item(writer, data)
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ func RunServer(db core.DB, addr string, port string) {
|
||||
handleFunc("GET /source/{source}", env.getSource, env.authed, logged)
|
||||
handleFunc("POST /source/{source}/fetch", env.fetchSource, env.authed, logged)
|
||||
handleFunc("GET /channel/{channel}", env.getChannel, env.authed, logged)
|
||||
handleFunc("POST /item", env.addItem, env.authed, logged)
|
||||
handleFunc("GET /item/{source}/{id}", env.getItem, env.authed, logged)
|
||||
handleFunc("DELETE /item/{source}/{id}", env.deleteItem, env.authed, logged)
|
||||
handleFunc("POST /item/{source}/{id}/action/{action}", env.doAction, env.authed, logged)
|
||||
|
@ -49,27 +49,9 @@ func (env *Env) fetchSource(writer http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
state, err := core.GetState(env.db, source)
|
||||
state, envs, argv, postProcess, err := core.GetSourceActionInputs(env.db, source, "fetch")
|
||||
if err != nil {
|
||||
http.Error(writer, fmt.Sprintf("error: failed to get state: %v", err.Error()), 500)
|
||||
return
|
||||
}
|
||||
|
||||
envs, err := core.GetEnvs(env.db, source)
|
||||
if err != nil {
|
||||
http.Error(writer, fmt.Sprintf("error: failed to get envs: %v", err.Error()), 500)
|
||||
return
|
||||
}
|
||||
|
||||
argv, err := core.GetArgvForAction(env.db, source, "fetch")
|
||||
if err != nil {
|
||||
http.Error(writer, fmt.Sprintf("error: failed to get fetch argv: %v", err.Error()), 500)
|
||||
return
|
||||
}
|
||||
|
||||
postProcess, err := core.GetSourcePostProcessor(env.db, source)
|
||||
if err != nil {
|
||||
http.Error(writer, fmt.Sprintf("error: failed to get post-processor: %v", err.Error()), 500)
|
||||
http.Error(writer, fmt.Sprintf("error: failed to get data for %s: %v", source, err.Error()), 500)
|
||||
return
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user