From de39350aa50a5f98b0e163a2eb3feca349c06e4f Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Thu, 2 Jan 2025 23:23:18 +0100 Subject: [PATCH] Initial --- .gitignore | 2 + flake.lock | 63 +++++++++++++++++ flake.nix | 31 +++++++++ main.go | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 294 insertions(+) create mode 100644 .gitignore create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c5edab1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.envrc +.direnv/ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3f8c783 --- /dev/null +++ b/flake.lock @@ -0,0 +1,63 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1735471104, + "narHash": "sha256-0q9NGQySwDQc7RhAV2ukfnu7Gxa5/ybJ2ANT8DQrQrs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "88195a94f390381c6afcdaa933c2f6ff93959cb4", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "systems": "systems" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..2168cfe --- /dev/null +++ b/flake.nix @@ -0,0 +1,31 @@ +{ + inputs = { + nixpkgs.url = "nixpkgs/nixos-unstable"; + systems.url = "github:nix-systems/default"; + flake-utils = { + url = "github:numtide/flake-utils"; + inputs.systems.follows = "systems"; + }; + }; + + outputs = { nixpkgs, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + in with pkgs; rec { + devShell = pkgs.mkShell { + packages = with pkgs; [ + bashInteractive + git + go_1_23 + go-task + gopls + golangci-lint + golangci-lint-langserver + nodejs + tmux + ]; + }; + } + ); +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..aea6b48 --- /dev/null +++ b/main.go @@ -0,0 +1,198 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "time" +) + +func main() { + fmt.Println("##################### START #####################") + fmt.Println(" Docspell Consumedir Cleaner - v0.1 beta") + fmt.Println(" by jacob1123") + fmt.Println(" (based on work by totti4ever) ") + fmt.Println("#################################################") + fmt.Println() + + // Get password from rbw + cmd := exec.Command("rbw", "get", "Docspell") + password, err := cmd.Output() + if err != nil { + fmt.Println("Error getting password:", err) + os.Exit(0) + } + + // Login + loginCmd := exec.Command("dsc", "login", "--user", "jacob1123", "--password", strings.TrimSpace(string(password))) + if err := loginCmd.Run(); err != nil { + fmt.Println("Login failed:", err) + os.Exit(0) + } + + // Check for jq + if _, err := exec.LookPath("jq"); err != nil { + fmt.Println("please install 'jq'") + os.Exit(-4) + } + + dsUrl := "https://docs.javil.eu" + + if len(os.Args) != 3 { + fmt.Println("FATAL Exactly two parameters needed") + os.Exit(-3) + } + + dsConsumedir := strings.TrimRight(os.Args[1], "/") + dsArchivedir := strings.TrimRight(os.Args[2], "/") + + if dsConsumedir == "" || dsArchivedir == "" { + fmt.Println("FATAL Parameter missing") + fmt.Printf(" ds_consumedir: %s\n", dsConsumedir) + fmt.Printf(" ds_archivedir: %s\n", dsArchivedir) + os.Exit(-2) + } + + fmt.Println("Settings:") + uploadMissing := os.Getenv("DS_CC_UPLOAD_MISSING") == "true" + if uploadMissing { + fmt.Println(" - UPLOAD files? YES") + fmt.Println(" files not existing in Docspell will be uploaded and will be re-checked in the next run.") + } else { + fmt.Println(" - UPLOAD files? no") + fmt.Println(" files not existing in Docspell will NOT be uploaded and stay where they are.") + } + fmt.Println() + fmt.Println() + fmt.Println("Press 'ctrl+c' to cancel") + time.Sleep(time.Second) + fmt.Println() + fmt.Println() + + fmt.Printf("Scanning folder '%s'\n", dsConsumedir) + fmt.Println() + fmt.Println() + + err = filepath.Walk(dsConsumedir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + + fmt.Printf("Checking '%s'\n", path) + + // Check if file exists in Docspell + cmd := exec.Command("dsc", "-f", "json", "file-exists", path) + output, err := cmd.Output() + if err != nil { + fmt.Printf("ERROR %v\n", err) + return nil + } + + var fileExistsResponse []map[string]interface{} + if err := json.Unmarshal(output, &fileExistsResponse); err != nil { + fmt.Printf("ERROR parsing response: %v\n", err) + return nil + } + + if fileExistsResponse[0]["exists"].(bool) { + // File exists in Docspell + items := fileExistsResponse[0]["items"].([]interface{}) + item := items[0].(map[string]interface{}) + itemID := item["id"].(string) + itemName := item["name"].(string) + + // Get item details + cmd = exec.Command("dsc", "-f", "json", "item", "get", itemID) + output, err = cmd.Output() + if err != nil { + fmt.Printf("ERROR getting item details: %v\n", err) + return nil + } + + var itemDetails map[string]interface{} + if err := json.Unmarshal(output, &itemDetails); err != nil { + fmt.Printf("ERROR parsing item details: %v\n", err) + return nil + } + + folder := itemDetails["folder"].(map[string]interface{})["name"].(string) + extension := filepath.Ext(path)[1:] + + var corr string + if corrOrg, ok := itemDetails["corr_org"].(map[string]interface{}); ok && corrOrg["name"] != nil { + corr = corrOrg["name"].(string) + } else if corrPerson, ok := itemDetails["corr_person"].(map[string]interface{}); ok && corrPerson["name"] != nil { + corr = corrPerson["name"].(string) + } + + fmt.Printf("File already exists: '%s @ %s/app/item/%s'\n", itemName, dsUrl, itemID) + + state := item["state"].(string) + if state == "confirmed" { + itemDate := item["item_date"] + if itemDate == nil { + fmt.Println("... but has no date - not doing anything.") + } else { + timestamp := int64(itemDate.(float64)) / 1000 + date := time.Unix(timestamp, 0) + curDir := filepath.Join(dsArchivedir, folder, date.Format("2006/01")) + + if err := os.MkdirAll(curDir, 0755); err != nil { + fmt.Printf("ERROR creating directory: %v\n", err) + return nil + } + + newPath := filepath.Join(curDir, fmt.Sprintf("%s %s - %s.%s", + date.Format("20060102"), corr, itemName, extension)) + + if err := os.Rename(path, newPath); err != nil { + fmt.Printf("ERROR moving file: %v\n", err) + return nil + } + fmt.Printf("... moving to archive by date ('%s')\n", curDir) + } + } else { + fmt.Println("... but is not confirmed yet - not doing anything.") + } + } else { + fmt.Println("Files does not exist, yet") + if uploadMissing { + fmt.Print("...uploading file..") + cmd = exec.Command("dsc", "-f", "json", "upload", path) + output, err := cmd.Output() + if err != nil { + fmt.Printf("\nERROR uploading: %v\n", err) + return nil + } + + var uploadResult map[string]interface{} + if err := json.Unmarshal(output, &uploadResult); err != nil { + fmt.Printf("\nERROR parsing upload result: %v\n", err) + return nil + } + + if uploadResult["success"].(bool) { + fmt.Println(". done") + } else { + fmt.Printf("\nERROR %v\n", uploadResult) + } + } + } + + return nil + }) + + if err != nil { + fmt.Printf("Error walking directory: %v\n", err) + os.Exit(1) + } + + fmt.Println("################# DONE #################") + fmt.Println(time.Now().Format(time.RFC1123)) +}