Notes/main.go

789 lines
18 KiB
Go
Raw Normal View History

2023-06-15 07:24:23 +02:00
package main
import (
2024-01-05 20:00:02 +01:00
// External
"git.gibonuddevalla.se/go/webservice"
"git.gibonuddevalla.se/go/wrappederror"
2024-01-05 20:00:02 +01:00
// Internal
"git.gibonuddevalla.se/go/webservice/session"
"notes/notification"
2024-01-05 20:00:02 +01:00
2023-06-15 07:24:23 +02:00
// Standard
2023-06-21 23:52:21 +02:00
"crypto/md5"
2023-12-28 07:47:23 +01:00
"embed"
2023-06-21 23:52:21 +02:00
"encoding/hex"
"encoding/json"
2023-06-15 07:24:23 +02:00
"flag"
"fmt"
2023-06-21 23:52:21 +02:00
"io"
2023-12-28 09:09:56 +01:00
"log/slog"
2023-06-15 07:24:23 +02:00
"net/http"
"os"
2023-12-28 07:47:23 +01:00
"path/filepath"
2023-06-22 06:52:27 +02:00
"strconv"
2023-12-28 07:47:23 +01:00
"strings"
2024-03-28 21:49:48 +01:00
"time"
2023-06-15 07:24:23 +02:00
)
2023-12-28 07:47:23 +01:00
const LISTEN_HOST = "0.0.0.0"
2023-06-15 07:24:23 +02:00
var (
2023-12-28 08:08:59 +01:00
flagPort int
flagVersion bool
flagCreateUser bool
2024-01-05 20:00:02 +01:00
flagCheckLocal bool
2023-12-28 08:08:59 +01:00
flagConfig string
2023-12-28 07:47:23 +01:00
service *webservice.Service
connectionManager ConnectionManager
notificationManager notification.Manager
static http.Handler
config Config
logger *slog.Logger
schedulers map[int]Schedule
VERSION string
2023-12-28 07:47:23 +01:00
//go:embed version sql/*
2024-01-05 20:00:02 +01:00
embeddedSQL embed.FS
//go:embed static
staticFS embed.FS
2023-06-15 07:24:23 +02:00
)
func sqlProvider(dbname string, version int) (sql []byte, found bool) { // {{{
2024-01-05 20:00:02 +01:00
var err error
sql, err = embeddedSQL.ReadFile(fmt.Sprintf("sql/%05d.sql", version))
if err != nil {
return
}
found = true
return
} // }}}
func logCallback(e WrappedError.Error) { // {{{
now := time.Now()
out := struct {
Year int
Month int
Day int
Time string
2024-04-05 08:59:59 +02:00
Error error
}{now.Year(), int(now.Month()), now.Day(), now.Format("15:04:05"), e}
j, _ := json.Marshal(out)
file, err := os.OpenFile("/tmp/notes.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
logger.Error("log", "error", err)
return
}
file.Write(j)
file.Write([]byte("\n"))
file.Close()
} // }}}
2024-01-05 20:00:02 +01:00
2023-12-28 07:47:23 +01:00
func init() { // {{{
2024-01-05 20:00:02 +01:00
version, _ := embeddedSQL.ReadFile("version")
2023-12-28 07:47:23 +01:00
VERSION = strings.TrimSpace(string(version))
2023-06-15 07:24:23 +02:00
2023-12-28 09:09:56 +01:00
opt := slog.HandlerOptions{}
2024-01-07 16:20:21 +01:00
opt.Level = slog.LevelDebug
2023-12-28 09:09:56 +01:00
logger = slog.New(slog.NewJSONHandler(os.Stdout, &opt))
2024-03-28 21:49:48 +01:00
schedulers = make(map[int]Schedule, 512)
2023-12-28 07:47:23 +01:00
configFilename := os.Getenv("HOME") + "/.config/notes.yaml"
flag.IntVar(&flagPort, "port", 1371, "TCP port to listen on")
flag.BoolVar(&flagVersion, "version", false, "Shows Notes version and exists")
2023-12-28 08:08:59 +01:00
flag.BoolVar(&flagCreateUser, "createuser", false, "Create a user and exit")
2024-01-05 20:00:02 +01:00
flag.BoolVar(&flagCheckLocal, "checklocal", false, "Check for local static file before embedded")
2023-12-28 07:47:23 +01:00
flag.StringVar(&flagConfig, "config", configFilename, "Filename of configuration file")
2023-06-15 07:24:23 +02:00
flag.Parse()
2023-12-28 07:47:23 +01:00
} // }}}
func main() { // {{{
WrappedError.Init()
WrappedError.SetLogCallback(logCallback)
2023-06-15 07:24:23 +02:00
var err error
2023-07-22 09:57:02 +02:00
if flagVersion {
fmt.Printf("%s\n", VERSION)
os.Exit(0)
}
2023-12-28 09:09:56 +01:00
logger.Info("application", "version", VERSION)
2023-06-15 07:24:23 +02:00
2024-01-09 17:19:54 +01:00
config, err = ConfigRead(flagConfig)
if err != nil {
logger.Error("application", "error", err)
os.Exit(1)
}
2024-01-07 16:20:21 +01:00
service, err = webservice.New(flagConfig, VERSION, logger)
2023-06-15 07:24:23 +02:00
if err != nil {
2024-01-05 20:00:02 +01:00
logger.Error("application", "error", err)
2023-06-18 22:05:10 +02:00
os.Exit(1)
}
2024-01-05 20:00:02 +01:00
service.SetDatabase(sqlProvider)
service.SetStaticDirectory("static", true)
service.SetStaticFS(staticFS, "static")
service.Register("/node/upload", true, true, nodeUpload)
service.Register("/node/tree", true, true, nodeTree)
service.Register("/node/retrieve", true, true, nodeRetrieve)
service.Register("/node/create", true, true, nodeCreate)
service.Register("/node/update", true, true, nodeUpdate)
service.Register("/node/rename", true, true, nodeRename)
service.Register("/node/delete", true, true, nodeDelete)
service.Register("/node/download", true, true, nodeDownload)
service.Register("/node/search", true, true, nodeSearch)
service.Register("/node/checklist_group/add", true, true, nodeChecklistGroupAdd)
service.Register("/node/checklist_group/item_add", true, true, nodeChecklistGroupItemAdd)
service.Register("/node/checklist_group/label", true, true, nodeChecklistGroupLabel)
service.Register("/node/checklist_group/delete", true, true, nodeChecklistGroupDelete)
service.Register("/node/checklist_item/state", true, true, nodeChecklistItemState)
service.Register("/node/checklist_item/label", true, true, nodeChecklistItemLabel)
service.Register("/node/checklist_item/delete", true, true, nodeChecklistItemDelete)
2024-01-13 10:01:10 +01:00
service.Register("/node/checklist_item/move", true, true, nodeChecklistItemMove)
2024-01-05 20:00:02 +01:00
service.Register("/key/retrieve", true, true, keyRetrieve)
service.Register("/key/create", true, true, keyCreate)
service.Register("/key/counter", true, true, keyCounter)
service.Register("/notification/ack", false, false, notificationAcknowledge)
2024-04-03 17:37:32 +02:00
service.Register("/schedule/list", true, true, scheduleList)
2024-01-05 20:00:02 +01:00
service.Register("/", false, false, service.StaticHandler)
2023-06-18 22:05:10 +02:00
2023-12-28 08:08:59 +01:00
if flagCreateUser {
2024-01-05 20:00:02 +01:00
service.CreateUserPrompt()
2023-12-28 08:08:59 +01:00
os.Exit(0)
}
2024-03-28 21:49:48 +01:00
go scheduleHandler()
if err = service.InitDatabaseConnection(); err != nil {
logger.Error("application", "error", err)
os.Exit(1)
}
err = InitNotificationManager()
if err != nil {
logger.Error("application", "error", err)
os.Exit(1)
}
2024-01-05 20:00:02 +01:00
err = service.Start()
if err != nil {
logger.Error("webserver", "error", err)
os.Exit(1)
}
2023-12-28 07:47:23 +01:00
} // }}}
2023-07-20 10:47:49 +02:00
2024-01-05 20:00:02 +01:00
func nodeTree(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2024-01-05 21:14:55 +01:00
logger.Info("webserver", "request", "/node/tree")
var err error
2023-12-28 07:47:23 +01:00
req := struct{ StartNodeID int }{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-01-05 20:00:02 +01:00
nodes, err := NodeTree(sess.UserID, req.StartNodeID)
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
2023-12-28 07:47:23 +01:00
"OK": true,
"Nodes": nodes,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeRetrieve(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
logger.Info("webserver", "request", "/node/retrieve")
2024-01-05 21:14:55 +01:00
var err error
2023-06-15 07:24:23 +02:00
2023-12-28 07:47:23 +01:00
req := struct{ ID int }{}
2023-06-17 09:11:14 +02:00
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
2023-06-15 07:24:23 +02:00
return
}
2024-01-05 20:00:02 +01:00
node, err := RetrieveNode(sess.UserID, req.ID)
2023-06-15 07:24:23 +02:00
if err != nil {
2023-06-17 09:11:14 +02:00
responseError(w, err)
2023-06-15 07:24:23 +02:00
return
}
2023-06-17 09:11:14 +02:00
responseData(w, map[string]interface{}{
2023-12-28 07:47:23 +01:00
"OK": true,
2023-06-17 09:11:14 +02:00
"Node": node,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeCreate(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/node/create")
2023-06-18 20:13:35 +02:00
var err error
req := struct {
2023-12-28 07:47:23 +01:00
Name string
2023-06-18 20:13:35 +02:00
ParentID int
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-01-05 20:00:02 +01:00
node, err := CreateNode(sess.UserID, req.ParentID, req.Name)
2023-06-18 20:13:35 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
2023-12-28 07:47:23 +01:00
"OK": true,
2023-06-18 20:13:35 +02:00
"Node": node,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeUpdate(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/node/update")
2023-06-18 20:13:35 +02:00
var err error
req := struct {
2023-12-28 07:47:23 +01:00
NodeID int
Content string
2023-07-12 22:35:38 +02:00
CryptoKeyID int
2024-01-09 16:28:40 +01:00
Markdown bool
2024-03-30 09:46:48 +01:00
TimeOffset int
2023-06-18 20:13:35 +02:00
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-03-30 09:46:48 +01:00
err = UpdateNode(sess.UserID, req.NodeID, req.TimeOffset, req.Content, req.CryptoKeyID, req.Markdown)
2023-06-18 20:13:35 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeRename(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-06-18 22:05:10 +02:00
var err error
2024-01-05 20:00:02 +01:00
logger.Info("webserver", "request", "/node/rename")
2023-06-18 22:05:10 +02:00
req := struct {
NodeID int
2023-12-28 07:47:23 +01:00
Name string
2023-06-18 22:05:10 +02:00
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-01-05 20:00:02 +01:00
err = RenameNode(sess.UserID, req.NodeID, req.Name)
2023-06-18 22:05:10 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeDelete(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-06-18 22:05:10 +02:00
var err error
2024-01-05 20:00:02 +01:00
logger.Info("webserver", "request", "/node/delete")
2023-06-18 22:05:10 +02:00
req := struct {
NodeID int
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-01-05 20:00:02 +01:00
err = DeleteNode(sess.UserID, req.NodeID)
2023-06-18 22:05:10 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeUpload(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/node/upload")
2023-06-21 23:52:21 +02:00
var err error
// Parse our multipart form, 10 << 20 specifies a maximum
// upload of 10 MB files.
2023-06-22 06:52:27 +02:00
r.Body = http.MaxBytesReader(w, r.Body, 128<<20+512)
r.ParseMultipartForm(128 << 20)
2023-06-21 23:52:21 +02:00
// FormFile returns the first file for the given key `myFile`
// it also returns the FileHeader so we can get the Filename,
// the Header and the size of the file
file, handler, err := r.FormFile("file")
if err != nil {
responseError(w, err)
return
}
defer file.Close()
2023-06-22 06:52:27 +02:00
// Read metadata of file for database, and also file contents
// for MD5, which is used to store the file on disk.
2023-06-21 23:52:21 +02:00
fileBytes, err := io.ReadAll(file)
if err != nil {
responseError(w, err)
return
}
md5sumBytes := md5.Sum(fileBytes)
md5sum := hex.EncodeToString(md5sumBytes[:])
2023-06-22 06:52:27 +02:00
var nodeID int
if nodeID, err = strconv.Atoi(r.PostFormValue("NodeID")); err != nil {
responseError(w, err)
return
}
2023-06-21 23:52:21 +02:00
nodeFile := File{
2023-12-28 07:47:23 +01:00
NodeID: nodeID,
2023-06-21 23:52:21 +02:00
Filename: handler.Filename,
2023-12-28 07:47:23 +01:00
Size: handler.Size,
MIME: handler.Header.Get("Content-Type"),
MD5: md5sum,
2023-06-21 23:52:21 +02:00
}
2024-01-05 20:00:02 +01:00
if err = AddFile(sess.UserID, &nodeFile); err != nil {
2023-06-21 23:52:21 +02:00
responseError(w, err)
return
}
2023-06-22 06:52:27 +02:00
// Files are stored in a directory structure composed of
// the first three characters in the md5sum, which is statistically
// distributed by design, making sure there aren't too many files in
// a single directory.
2023-06-21 23:52:21 +02:00
path := filepath.Join(
config.Application.Directories.Upload,
md5sum[0:1],
md5sum[1:2],
md5sum[2:3],
)
if err = os.MkdirAll(path, 0755); err != nil {
responseError(w, err)
return
}
path = filepath.Join(
config.Application.Directories.Upload,
md5sum[0:1],
md5sum[1:2],
md5sum[2:3],
md5sum,
)
if err = os.WriteFile(path, fileBytes, 0644); err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
2023-12-28 07:47:23 +01:00
"OK": true,
2023-06-22 06:52:27 +02:00
"File": nodeFile,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeDownload(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/node/download")
2023-06-22 16:48:31 +02:00
var err error
var files []File
req := struct {
NodeID int
FileID int
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-01-05 20:00:02 +01:00
files, err = Files(sess.UserID, req.NodeID, req.FileID)
2023-06-22 16:48:31 +02:00
if err != nil {
responseError(w, err)
return
}
if len(files) != 1 {
responseError(w, fmt.Errorf("File not found"))
return
}
2023-12-28 07:47:23 +01:00
2023-06-22 16:48:31 +02:00
var file *os.File
fname := filepath.Join(
config.Application.Directories.Upload,
files[0].MD5[0:1],
files[0].MD5[1:2],
files[0].MD5[2:3],
files[0].MD5,
)
file, err = os.Open(fname)
if err != nil {
responseError(w, err)
return
}
var finfo os.FileInfo
finfo, err = file.Stat()
if err != nil {
responseError(w, err)
return
}
2023-06-22 17:42:34 +02:00
w.Header().Add("Content-Type", files[0].MIME)
2023-06-27 14:44:36 +02:00
w.Header().Add("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, files[0].Filename))
2023-06-22 17:42:34 +02:00
w.Header().Add("Content-Length", strconv.Itoa(int(finfo.Size())))
2023-06-22 16:48:31 +02:00
read := 1
var buf []byte
for read > 0 {
buf = make([]byte, 65536)
read, err = file.Read(buf)
if read > 0 {
w.Write(buf[0:read])
}
}
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeFiles(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/node/files")
2023-06-22 06:52:27 +02:00
var err error
var files []File
req := struct {
NodeID int
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-01-05 20:00:02 +01:00
files, err = Files(sess.UserID, req.NodeID, 0)
2023-06-22 06:52:27 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
2023-12-28 07:47:23 +01:00
"OK": true,
2023-06-22 06:52:27 +02:00
"Files": files,
2023-06-21 23:52:21 +02:00
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func nodeSearch(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/node/search")
2023-07-19 10:00:36 +02:00
var err error
var nodes []Node
req := struct {
Search string
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-01-05 20:00:02 +01:00
nodes, err = SearchNodes(sess.UserID, req.Search)
2023-07-19 10:00:36 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
2023-12-28 07:47:23 +01:00
"OK": true,
2023-07-19 10:00:36 +02:00
"Nodes": nodes,
})
2023-12-28 07:47:23 +01:00
} // }}}
func nodeChecklistGroupAdd(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
var err error
req := struct {
NodeID int
Label string
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
var group ChecklistGroup
group, err = ChecklistGroupAdd(sess.UserID, req.NodeID, req.Label)
if err != nil {
responseError(w, err)
return
}
group.Items = []ChecklistItem{}
responseData(w, map[string]interface{}{
"OK": true,
"Group": group,
})
} // }}}
func nodeChecklistGroupItemAdd(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
var err error
req := struct {
ChecklistGroupID int
Label string
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
var item ChecklistItem
item, err = ChecklistGroupItemAdd(sess.UserID, req.ChecklistGroupID, req.Label)
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
"Item": item,
})
} // }}}
func nodeChecklistGroupLabel(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
var err error
req := struct {
ChecklistGroupID int
Label string
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
var item ChecklistItem
item, err = ChecklistGroupLabel(sess.UserID, req.ChecklistGroupID, req.Label)
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
"Item": item,
})
} // }}}
func nodeChecklistGroupDelete(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
var err error
req := struct {
ChecklistGroupID int
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
err = ChecklistGroupDelete(sess.UserID, req.ChecklistGroupID)
if err != nil {
logger.Error("checklist", "error", err)
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
func nodeChecklistItemState(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
var err error
req := struct {
ChecklistItemID int
State bool
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
err = ChecklistItemState(sess.UserID, req.ChecklistItemID, req.State)
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
func nodeChecklistItemLabel(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
var err error
req := struct {
ChecklistItemID int
Label string
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
err = ChecklistItemLabel(sess.UserID, req.ChecklistItemID, req.Label)
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
func nodeChecklistItemDelete(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
var err error
req := struct {
ChecklistItemID int
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
err = ChecklistItemDelete(sess.UserID, req.ChecklistItemID)
if err != nil {
logger.Error("checklist", "error", err)
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
2024-01-13 10:01:10 +01:00
func nodeChecklistItemMove(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
var err error
req := struct {
ChecklistItemID int
AfterItemID int
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
err = ChecklistItemMove(sess.UserID, req.ChecklistItemID, req.AfterItemID)
if err != nil {
logger.Error("checklist", "error", err)
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
2023-06-15 07:24:23 +02:00
2024-01-05 20:00:02 +01:00
func keyRetrieve(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/key/retrieve")
2023-07-01 20:33:26 +02:00
var err error
2024-01-05 20:00:02 +01:00
keys, err := Keys(sess.UserID)
2023-07-01 20:33:26 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
2023-12-28 07:47:23 +01:00
"OK": true,
2023-07-01 20:33:26 +02:00
"Keys": keys,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func keyCreate(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/key/create")
2023-07-12 22:35:38 +02:00
var err error
req := struct {
Description string
2023-12-28 07:47:23 +01:00
Key string
2023-07-12 22:35:38 +02:00
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
}
2024-01-05 20:00:02 +01:00
key, err := KeyCreate(sess.UserID, req.Description, req.Key)
2023-07-12 22:35:38 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
2023-12-28 07:47:23 +01:00
"OK": true,
2023-07-12 22:35:38 +02:00
"Key": key,
})
2023-12-28 07:47:23 +01:00
} // }}}
2024-01-05 20:00:02 +01:00
func keyCounter(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
2023-12-28 09:09:56 +01:00
logger.Info("webserver", "request", "/key/counter")
2023-07-12 22:35:38 +02:00
var err error
2024-01-05 20:00:02 +01:00
counter, err := KeyCounter()
2023-07-12 22:35:38 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
// Javascript uses int32, thus getting a string counter for Javascript BigInt to parse.
"Counter": strconv.FormatInt(counter, 10),
})
2023-12-28 07:47:23 +01:00
} // }}}
2023-07-01 20:33:26 +02:00
func notificationAcknowledge(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
logger.Info("webserver", "request", "/notification/ack")
var err error
2024-03-30 17:58:51 +01:00
w.Header().Add("Access-Control-Allow-Origin", "*")
err = AcknowledgeNotification(r.URL.Query().Get("uuid"))
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
2024-04-03 17:37:32 +02:00
func scheduleList(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
logger.Info("webserver", "request", "/schedule/list")
var err error
w.Header().Add("Access-Control-Allow-Origin", "*")
2024-04-17 18:43:24 +02:00
request := struct {
NodeID int
}{}
body, _ := io.ReadAll(r.Body)
if len(body) > 0 {
err = json.Unmarshal(body, &request)
if err != nil {
responseError(w, err)
return
}
}
2024-04-03 17:37:32 +02:00
var schedules []Schedule
2024-04-17 18:43:24 +02:00
schedules, err = FutureSchedules(sess.UserID, request.NodeID)
2024-04-03 17:37:32 +02:00
if err != nil {
responseError(w, err)
return
}
responseData(w, map[string]interface{}{
"OK": true,
"ScheduleEvents": schedules,
})
} // }}}
2024-03-30 17:58:51 +01:00
2023-06-15 07:24:23 +02:00
// vim: foldmethod=marker