package cmd
import (
+ "fmt"
"github.com/spf13/cobra"
"os"
+ "os/exec"
+ Helper "scientia/lib"
)
/**
*/
var editCmd = &cobra.Command {
- Use: "edit",
- Short: "Modify an entry",
- Long: "Edit an existing entry.",
+ Use: "edit ID",
+ Short: "Modify an entry by its ID",
+ Long: "Edit an existing entry. Get the ID from the list command.",
Run: func(cmd *cobra.Command, args []string) {
- if len(args) == 0 {
+ var entryId string
+
+ if len(args) == 1 {
+ entryId = args[0]
+ } else {
cmd.Help()
os.Exit(0)
}
+
+ response := getEndpointRequest("?p=entry&id=" + entryId);
+
+ body := response.Data[0].Body
+ ident := response.Data[0].Ident
+
+ fh, err := os.CreateTemp("", ident)
+ Helper.ErrorCheck(err, "Can not create tmp file for editing.")
+ _, err = fmt.Fprintf(fh, body)
+
+ // default editor
+ var editor = "vim"
+
+ if e := os.Getenv("VISUAL"); e != "" {
+ editor = e
+ } else if e := os.Getenv("EDITOR"); e != "" {
+ editor = e
+ }
+
+ editCmd := exec.Command(editor, fh.Name())
+ editCmd.Stdin = os.Stdin
+ editCmd.Stdout = os.Stdout
+ editCmd.Stderr = os.Stderr
+ err = editCmd.Start()
+ Helper.ErrorCheck(err, "Can not open tmp file")
+
+ fmt.Println("Waiting for command to finish...")
+ err = editCmd.Wait()
+ Helper.ErrorCheck(err, "Command finished with error")
+ fmt.Println("Done.")
+
+ defer os.Remove(fh.Name())
+
},
}
+++ /dev/null
-package cmd
-
-import (
- "fmt"
- "github.com/spf13/cobra"
-)
-
-/**
- * scientia
- *
- * Copyright 2023 - 2024 Johannes Keßler
- *
- * https://www.bananas-playground.net/projekt/scientia/
- *
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
- *
- * You should have received a copy of the
- * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
- * along with this program. If not, see http://www.sun.com/cddl/cddl.html
- */
-
-
-// Subcommand of edit
-// to list all available entries
-
-var editListCmd = &cobra.Command {
- Use: "list",
- Short: "List all available entries",
- Long: "List all available entries",
- Run: func(cmd *cobra.Command, args []string) {
- listEntries()
- },
-}
-
-func init() {
- editCmd.AddCommand(editListCmd)
-}
-
-func listEntries() {
- if FlagVerbose {
- fmt.Println("Starting to request entries")
- }
-}
--- /dev/null
+package cmd
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/spf13/cobra"
+ "io"
+ "net/http"
+ Helper "scientia/lib"
+ "strings"
+)
+
+/**
+ * scientia
+ *
+ * Copyright 2023 - 2024 Johannes Keßler
+ *
+ * https://www.bananas-playground.net/projekt/scientia/
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ *
+ * You should have received a copy of the
+ * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+ * along with this program. If not, see http://www.sun.com/cddl/cddl.html
+ */
+
+
+// to list all available entries
+
+var listCmd = &cobra.Command {
+ Use: "list",
+ Short: "List all available entries",
+ Long: "List all available entries with its ID, date and content preview.",
+ Run: func(cmd *cobra.Command, args []string) {
+ listEntries()
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(listCmd)
+}
+
+func listEntries() {
+ response := getEndpointRequest("")
+
+ for _, entry := range response.Data {
+ leftOfDelimiter, _, _ := strings.Cut(entry.Body, "\n")
+ fmt.Println(entry.Ident, entry.Date, leftOfDelimiter)
+ }
+}
+
+
+func getEndpointRequest(params string) GetResponse {
+ if FlagVerbose {
+ fmt.Println("Starting to request get endpoint")
+ }
+
+ req, err := http.NewRequest(http.MethodGet, ScientiaConfig.Endpoint.Get + params, nil)
+ Helper.ErrorCheck(err, "Can not create http request")
+ // We need to set the content type from the writer, it includes necessary boundary as well
+ req.Header.Set("User-Agent", "scientiaAgent/1.0")
+ req.Header.Set("X-ASL", ScientiaConfig.Endpoint.Secret)
+
+ // Do the request
+ client := &http.Client{}
+ response, err := client.Do(req)
+ Helper.ErrorCheck(err, "GET request failed")
+
+ responseBody, err := io.ReadAll(response.Body)
+ Helper.ErrorCheck(err, "Can not read response body")
+
+ if FlagVerbose {
+ fmt.Println("Request done")
+ }
+ if FlagDebug {
+ fmt.Printf("DEBUG Response status code: %d\n", response.StatusCode)
+ fmt.Printf("DEBUG Response headers: %#v\n", response.Header)
+ fmt.Println("DEBUG Response body:\n", string(responseBody))
+ }
+
+ returnResponse := GetResponse{}
+ if response.StatusCode != 200 {
+ returnResponse = GetResponse {
+ Message: "Status not as expected.",
+ Status: response.StatusCode,
+ Data: []GetResponseEntry{}}
+ } else {
+ err := json.Unmarshal([]byte(responseBody), &returnResponse)
+ Helper.ErrorCheck(err, "Can not parse return json")
+ }
+
+ return returnResponse
+}
"github.com/adrg/xdg"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
- "log"
"os"
Helper "scientia/lib"
)
} `yaml:"endpoint"`
}
+// GetResponse struct for the get.php request
+type GetResponse struct {
+ Data []GetResponseEntry `json:"data"`
+ Status int `json:"status"`
+ Message string `json:"message"`
+}
+// GetResponseEntry struct is the entry itself
+type GetResponseEntry struct {
+ Ident string `json:"ident"`
+ Date string `json:"date"`
+ Body string `json:"body"`
+}
+
// The ScientiaConfig used globally
var ScientiaConfig ConfigStruct
Helper.ErrorCheck(err, "Can not decode config file")
if ScientiaConfig.Endpoint.Add == "" || ScientiaConfig.Endpoint.Get == "" || ScientiaConfig.Endpoint.Secret == "" {
- log.Fatal("Empty or outdated config?")
+ fmt.Println("WARNING Empty or outdated config?")
}
if FlagDebug {
-edit_list: list
edit_id: id
server: server
server.shape: cloud
-edit -> edit_list
edit -> edit_id
-edit_list <-> server
edit_id <-> server
# required libs
require_once('lib/summoner.class.php');
+
+# validate key
+if(!isset($_SERVER['HTTP_X_ASL']) || empty($_SERVER['HTTP_X_ASL']) || !isset(UPLOAD_SECRET[$_SERVER['HTTP_X_ASL']])) {
+ header('X-PROVIDED-BY: scientia');
+ http_response_code(400);
+ exit();
+}
+
+
+$_requestMode = "list";
+if(isset($_GET['p']) && !empty($_GET['p'])) {
+ $_requestMode = trim($_GET['p']);
+ $_requestMode = Summoner::validate($_requestMode,'nospace') ? $_requestMode : "list";
+}
+$_id = '';
+if(isset($_GET['id']) && Summoner::validate($_GET['id'], 'shortlink',4)) {
+ $_id = trim($_GET['id']);
+ $_view = 'entry';
+}
+
+# default response
+$contentType = 'Content-Type: application/json; charset=utf-8';
+$httpResponseCode = 200;
+$contentBody = array (
+ 'data' => array(),
+ 'message' => '',
+ 'status' => $httpResponseCode
+);
+
+## DB connection
+$DB = new mysqli(DB_HOST, DB_USERNAME,DB_PASSWORD, DB_NAME);
+if ($DB->connect_errno) exit('Can not connect to MySQL Server');
+$DB->set_charset("utf8mb4");
+$DB->query("SET collation_connection = 'utf8mb4_bin'");
+$driver = new mysqli_driver();
+$driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;
+
+require_once 'lib/entry.class.php';
+$Entry = new Entry($DB);
+
+switch($_requestMode) {
+ case "entry":
+ if(!empty($_id)) {
+ $contentBody['data'][] = $Entry->loadById($_id);
+ }
+ break;
+
+ case "list":
+ default:
+ $contentBody['data'] = $Entry->list();
+}
+
+## return
+header('X-PROVIDED-BY: scientia');
+header($contentType);
+http_response_code($httpResponseCode);
+echo json_encode($contentBody);
+$DB->close();
return $ret;
}
+ /**
+ * Load an entry by given $id.
+ * Used by get api
+ *
+ * @param string $id Id of the entry
+ * @return array
+ */
+ public function loadById(string $id): array {
+ $ret = array();
+
+ if(!empty($id)) {
+ $queryStr = "SELECT `ident`,`date`,`body`
+ FROM `".DB_PREFIX."_entry`
+ WHERE `ident` = '".$this->_DB->real_escape_string($id)."'";
+ if(QUERY_DEBUG) error_log("[QUERY] ".__METHOD__." query: ".var_export($queryStr,true));
+ try {
+ $query = $this->_DB->query($queryStr);
+ if($query !== false && $query->num_rows > 0) {
+ $ret = $query->fetch_assoc();
+ }
+ }
+ catch(Exception $e) {
+ error_log("[ERROR] ".__METHOD__." catch: ".$e->getMessage());
+ }
+ }
+
+ return $ret;
+ }
+
/**
* Update an entry by given $id and $data
*
return $ret;
}
+ /**
+ * Get all entries which match the specified options
+ * Body is trimmed to the first 100 chars
+ *
+ * @param String $searchTerm
+ * @param String $intervalStart
+ * @param String $intervalEnd
+ * @param int $limit
+ * @return array
+ */
+ public function list(string $searchTerm='', string $intervalStart='', string $intervalEnd='', int $limit=100): array {
+ $ret = array();
+
+ $queryStr = "SELECT e.ident, e.date, SUBSTRING(e.body,1,100) AS body
+ FROM `".DB_PREFIX."_entry` AS e";
+ if(!empty($intervalStart) && !empty($intervalEnd)) {
+ $queryStr .= " WHERE e.date >= '".$intervalStart."' AND e.date <= '".$intervalEnd."'";
+ }
+ if(!empty($searchTerm)) {
+ $queryStr .= " AND MATCH(e.words) AGAINST('".$this->_DB->real_escape_string($searchTerm)."' IN BOOLEAN MODE)";
+ }
+ $queryStr .= " ORDER BY `created` DESC";
+ $queryStr .= " LIMIT $limit";
+
+ if(QUERY_DEBUG) error_log("[QUERY] ".__METHOD__." query: ".var_export($queryStr,true));
+ try {
+ $query = $this->_DB->query($queryStr);
+ $ret = $query->fetch_all(MYSQLI_ASSOC);
+ }
+ catch(Exception $e) {
+ error_log("[ERROR] ".__METHOD__." catch: ".$e->getMessage());
+ }
+
+ return $ret;
+ }
+
/**
* Create unique words from the given data
*
$TemplateData['entries'] = array();
-$queryStr = "SELECT e.ident, e.date, e.words, SUBSTRING(e.body,1,100) AS body FROM `".DB_PREFIX."_entry` AS e";
-$queryLimit = " LIMIT 100";
+require_once 'lib/entry.class.php';
+$Entry = new Entry($DB);
$searchTerm = '';
if(isset($_POST['submitForm']) && isset($_POST['searchInput'])) {
// the single date infos come from index.php
$_groupByFormat = $_year;
$breadcrumb = array('Y');
+$_intervalStart = '';
+$_intervalEnd = '';
if(!empty($_requestDateProvided)) {
- $_intervalStart = '';
- $_intervalEnd = '';
-
if($_requestDateProvided === 'Y-m-d') {
$queryLimit = "";
$_groupByFormat = $_year.'-'.$_month.'-'.$_day;
$_intervalStart = $_groupByFormat.'-01-01';
$_intervalEnd = $_groupByFormat.'-12-31';
}
-
- if(!empty($_intervalStart) && !empty($_intervalEnd)) {
- $queryStr .= " WHERE e.date >= '".$_intervalStart."' AND e.date <= '".$_intervalEnd."'";
- if(!empty($searchTerm)) {
- $queryStr .= " AND MATCH(e.words) AGAINST('".$DB->real_escape_string($searchTerm)."' IN BOOLEAN MODE)";
- }
- }
} else {
$_requestDateProvided = 'Y';
- if(!empty($searchTerm)) {
- $queryStr .= " WHERE MATCH(e.words) AGAINST('".$DB->real_escape_string($searchTerm)."' IN BOOLEAN MODE)";
- }
}
-$queryStr .= " ORDER BY `created` DESC";
-$queryStr .= $queryLimit;
-if(QUERY_DEBUG) error_log("[QUERY] query: ".var_export($queryStr,true));
-
-try {
- $query = $DB->query($queryStr);
- if($query !== false && $query->num_rows > 0) {
- while(($result = $query->fetch_assoc()) != false) {
- $_d = new DateTime($result['date']);
- $_breadcrumb = array();
- foreach($breadcrumb as $_b) {
- $_breadcrumb[] = $_d->format($_b);
- }
- $TemplateData['entries'][$_d->format($_requestDateProvided)]['breadcrumb'] = $_breadcrumb;
- $TemplateData['entries'][$_d->format($_requestDateProvided)]['e'][$result['ident']] = $result;
- $TemplateData['entries'][$_d->format($_requestDateProvided)]['e'][$result['ident']]['link'] = str_replace('-','/',$result['date']).'/'.$result['ident'];
- }
+$entries = $Entry->list($searchTerm, $_intervalStart, $_intervalEnd);
+foreach($entries as $k=>$entry) {
+ $_d = new DateTime($entry['date']);
+ $_breadcrumb = array();
+ foreach($breadcrumb as $_b) {
+ $_breadcrumb[] = $_d->format($_b);
}
-}
-catch(Exception $e) {
- error_log("[ERROR] catch: ".$e->getMessage());
+ $TemplateData['entries'][$_d->format($_requestDateProvided)]['breadcrumb'] = $_breadcrumb;
+ $TemplateData['entries'][$_d->format($_requestDateProvided)]['e'][$entry['ident']] = $entry;
+ $TemplateData['entries'][$_d->format($_requestDateProvided)]['e'][$entry['ident']]['link'] = str_replace('-','/',$entry['date']).'/'.$entry['ident'];
}