diff --git a/config.json b/config.json new file mode 100644 index 0000000..6b612ec --- /dev/null +++ b/config.json @@ -0,0 +1,14 @@ +{ + "server": { + "ipAddress": "192.168.1.222", + "port": 8080, + "messageMaxAge": 259200 + }, + "paths": { + "databasePath": "/home/radon/Documents/chattest.db", + "indexJsPath": "./content/root.js", + "indexCssPath": "./content/root.css", + "indexHtmlPath": "./content/root.html", + "messagesHtmlPath": "./content/messages.html" + } +} diff --git a/messages.html b/content/messages.html similarity index 100% rename from messages.html rename to content/messages.html diff --git a/root.css b/content/root.css similarity index 100% rename from root.css rename to content/root.css diff --git a/root.html b/content/root.html similarity index 100% rename from root.html rename to content/root.html diff --git a/root.js b/content/root.js similarity index 89% rename from root.js rename to content/root.js index b5a4c92..77df7ba 100644 --- a/root.js +++ b/content/root.js @@ -149,31 +149,29 @@ async function loadMessages() { url, ); if (videoId) { - return `${url} -
`; + return ` `; } else if (isImageUrl(url)) { console.log( "Attempting to embed image:", url, ); - return `${url} - `; + return ` `; } return `${url}`; }, diff --git a/main.go b/main.go index b0a60bb..bcc1133 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "net" "net/http" "os" + "path/filepath" "strconv" "strings" "sync" @@ -77,27 +78,24 @@ func (db *Database) DbCreateTableUsers() { } func (db *Database) UserTimezoneSet(ip_address, timezone string) { - stmt, err := db.db.Prepare("UPDATE users SET timezone = ? WHERE ip_address = ?") + _, err := db.db.Exec("UPDATE users SET timezone = ? WHERE ip_address = ?", timezone, ip_address) if err != nil { fmt.Println(err) } - stmt.Exec(timezone, ip_address) } func (db *Database) UserAdd(ip_address, username string) { - stmt, err := db.db.Prepare("INSERT INTO users (username, ip_address) VALUES (?, ?)") + _, err := db.db.Exec("INSERT INTO users (username, ip_address) VALUES (?, ?)", username, ip_address) if err != nil { fmt.Println(err) } - stmt.Exec(username, ip_address) } func (db *Database) MessageAdd(ip_address string, content string) { - stmt, err := db.db.Prepare("INSERT INTO messages (ip_address, content) VALUES (?, ?)") + _, err := db.db.Exec("INSERT INTO messages (ip_address, content) VALUES (?, ?)", ip_address, content) if err != nil { fmt.Println(err) } - stmt.Exec(ip_address, content) } func (db *Database) UserNameGet(ip_address string) string { @@ -112,6 +110,18 @@ func (db *Database) UserNameGet(ip_address string) string { return username } +func (db *Database) UserIpGet(username string) string { + rows, err := db.db.Query("SELECT ip_address FROM users WHERE username = ?", username) + if err != nil { + fmt.Println(err) + } + defer rows.Close() + var ip_address string + rows.Next() + rows.Scan(&ip_address) + return ip_address +} + func (db *Database) UserGetTimezone(ip_address string) string { rows, err := db.db.Query("SELECT timezone FROM users WHERE ip_address = ?", ip_address) if err != nil { @@ -171,6 +181,27 @@ func (db *Database) MessagesGet() []Message { var created_at string var username string rows.Scan(&id, &ip_address, &content, &created_at, &username) + + // TODO: Implement better message parsing for admin commands + // TESTING: + // if msgId, ok := strings.CutPrefix(content, "@delete message id"); ok { + // msgId = strings.TrimSpace(msgId) + // go func() { + // db.MessageDeleteId(msgId) + // // db.MessageDeleteId(id) + // }() + // continue + // } + // TESTING: + // if msgId, ok := strings.CutPrefix(content, "@delete user messages"); ok { + // msgId = strings.TrimSpace(msgId) + // go func() { + // db.UserMessagesDelete(ip_address) + // // db.MessageDeleteId(id) + // }() + // continue + // } + message := Message{ Id: id, Content: content, @@ -178,6 +209,7 @@ func (db *Database) MessagesGet() []Message { SenderUsername: username, Timestamp: created_at, } + messages = append(messages, message) } return messages @@ -202,11 +234,17 @@ func (db *Database) UserExists(ip string) bool { } func (db *Database) UserNameChange(ip, newUsername string) { - stmt, err := db.db.Prepare("UPDATE users SET username = ? WHERE ip_address = ?") + _, err := db.db.Exec("UPDATE users SET username = ? WHERE ip_address = ?", newUsername, ip) + if err != nil { + fmt.Println(err) + } +} + +func (db *Database) UserMessagesDelete(ip string) { + _, err := db.db.Exec("DELETE FROM messages WHERE ip_address = ?", ip) if err != nil { fmt.Println(err) } - stmt.Exec(newUsername, ip) } func (db *Database) UserMessagesGet(ip string) []Message { @@ -244,36 +282,43 @@ func (db *Database) UserMessagesGet(ip string) []Message { return messages } -func (db *Database) MessageDelete(id string) { - stmt, err := db.db.Prepare("DELETE FROM messages WHERE id = ?") +func (db *Database) MessageDeleteId(id string) { + _, err := db.db.Exec("DELETE FROM messages WHERE id = ?", id) if err != nil { fmt.Println(err) } - stmt.Exec(id) } -func (db *Database) UserDelete(ip string) { - stmt, err := db.db.Prepare("DELETE FROM users WHERE ip_address = ?") +func (db *Database) DeleteOldMessages(ageMinutes int) { + if ageMinutes <= 0 { + return + } + age := strconv.Itoa(ageMinutes) + _, err := db.db.Exec("DELETE FROM messages WHERE created_at < datetime('now', ? || ' minutes')", "-"+age) + if err != nil { + fmt.Println(err) + } +} + +func (db *Database) UserDeleteIp(ip string) { + _, err := db.db.Exec("DELETE FROM users WHERE ip_address = ?", ip) if err != nil { fmt.Println(err) } - stmt.Exec(ip) } func (db *Database) UsersDelete() { - stmt, err := db.db.Prepare("DELETE FROM users") + _, err := db.db.Exec("DELETE FROM users") if err != nil { fmt.Println(err) } - stmt.Exec() } func (db *Database) MessagesDelete() { - stmt, err := db.db.Prepare("DELETE FROM messages") + _, err := db.db.Exec("DELETE FROM messages") if err != nil { fmt.Println(err) } - stmt.Exec() } type gzipResponseWriter struct { @@ -328,19 +373,18 @@ type Message struct { } type Server struct { - Ip string - Port int Connected map[string]time.Time // Map IP -> Last activity time Database *Database + Config Config mu sync.Mutex // For thread safety } -func NewServer(ip string, port int, dbpath string) *Server { +func NewServer(config Config) *Server { + return &Server{ - Ip: ip, - Port: port, Connected: make(map[string]time.Time), - Database: OpenDatabase(dbpath), + Database: OpenDatabase(config.Paths.DatabasePath), + Config: config, mu: sync.Mutex{}, } } @@ -431,8 +475,8 @@ func (s *Server) handleUsername(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(map[string]string{"status": "Username registered"}) } -func getMessageTemplate(file string, body string) string { - contents, _ := os.ReadFile(file) +func getMessageTemplate(filepath string, body string) string { + contents, _ := os.ReadFile(filepath) return strings.Replace(string(contents), "{{body}}", body, 1) } @@ -447,11 +491,11 @@ func (s *Server) handleMessages(w http.ResponseWriter, r *http.Request) { clientIP := getClientIP(r) timeZone := s.Database.UserGetTimezone(clientIP) timeLocal := TimeStringToTimeInLocation(msg.Timestamp, timeZone) - body += fmt.Sprintf(`%s
%s