you can now read termails (kinda important)

This commit is contained in:
Keiran 2025-08-06 06:38:03 +01:00
parent 71283b2248
commit 1872fad367
4 changed files with 120 additions and 4 deletions

View File

@ -30,6 +30,7 @@ func main() {
protected.Use(handlers.AuthMiddleware) protected.Use(handlers.AuthMiddleware)
protected.POST("/send", handlers.HandleSendTermail) protected.POST("/send", handlers.HandleSendTermail)
protected.GET("/inbox", handlers.HandleGetInbox) protected.GET("/inbox", handlers.HandleGetInbox)
protected.GET("/:id", handlers.HandleGetTermail)
protected.POST("/:id/read", handlers.HandleMarkTermailRead) protected.POST("/:id/read", handlers.HandleMarkTermailRead)
protected.DELETE("/:id", handlers.HandleDeleteTermail) protected.DELETE("/:id", handlers.HandleDeleteTermail)

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
@ -62,6 +63,14 @@ var inboxCmd = &cobra.Command{
Run: runInbox, Run: runInbox,
} }
var inboxViewCmd = &cobra.Command{
Use: "view [termail_id]",
Short: "View termail content",
Long: "View the full content of a specific termail by ID.",
Args: cobra.ExactArgs(1),
Run: runInboxView,
}
var inboxReadCmd = &cobra.Command{ var inboxReadCmd = &cobra.Command{
Use: "read [termail_id]", Use: "read [termail_id]",
Short: "Mark termail as read", Short: "Mark termail as read",
@ -92,6 +101,7 @@ func init() {
inboxCmd.Flags().IntP("offset", "o", 0, "Number of termails to skip") inboxCmd.Flags().IntP("offset", "o", 0, "Number of termails to skip")
inboxCmd.Flags().Bool("unread", false, "Show only unread termails") inboxCmd.Flags().Bool("unread", false, "Show only unread termails")
inboxCmd.AddCommand(inboxViewCmd)
inboxCmd.AddCommand(inboxReadCmd) inboxCmd.AddCommand(inboxReadCmd)
inboxCmd.AddCommand(inboxDeleteCmd) inboxCmd.AddCommand(inboxDeleteCmd)
@ -170,6 +180,64 @@ func makeAuthenticatedRequest(method, endpoint string, body []byte) (*http.Respo
return http.DefaultClient.Do(req) return http.DefaultClient.Do(req)
} }
func runInboxView(cmd *cobra.Command, args []string) {
termailID, err := strconv.Atoi(args[0])
if err != nil {
fmt.Printf("Invalid termail ID: %s\n", args[0])
return
}
endpoint := fmt.Sprintf("/termail/%d", termailID)
resp, err := makeAuthenticatedRequest("GET", endpoint, nil)
if err != nil {
fmt.Printf("Error fetching termail: %v\n", err)
return
}
defer resp.Body.Close()
var response map[string]interface{}
json.NewDecoder(resp.Body).Decode(&response)
if resp.StatusCode != http.StatusOK {
fmt.Printf("Error: %s\n", response["error"])
return
}
termailData := response["termail"].(map[string]interface{})
content := fmt.Sprintf("From: %s\nSubject: %s\nSent: %s\nRead: %t\n\n%s\n",
termailData["sender"].(string),
termailData["subject"].(string),
termailData["sent_at"].(string),
termailData["is_read"].(bool),
termailData["content"].(string),
)
if shouldUsePager(content) {
if err := displayWithLess(content); err != nil {
fmt.Print(content)
}
} else {
fmt.Print(content)
}
markAsReadEndpoint := fmt.Sprintf("/termail/%d/read", termailID)
makeAuthenticatedRequest("POST", markAsReadEndpoint, nil)
}
func shouldUsePager(content string) bool {
lines := strings.Count(content, "\n")
return lines > 20
}
func displayWithLess(content string) error {
lessCmd := exec.Command("less", "-R")
lessCmd.Stdin = strings.NewReader(content)
lessCmd.Stdout = os.Stdout
lessCmd.Stderr = os.Stderr
return lessCmd.Run()
}
func runInbox(cmd *cobra.Command, args []string) { func runInbox(cmd *cobra.Command, args []string) {
search, _ := cmd.Flags().GetString("search") search, _ := cmd.Flags().GetString("search")
limit, _ := cmd.Flags().GetInt("limit") limit, _ := cmd.Flags().GetInt("limit")
@ -195,16 +263,27 @@ func runInbox(cmd *cobra.Command, args []string) {
json.NewDecoder(resp.Body).Decode(&response) json.NewDecoder(resp.Body).Decode(&response)
if resp.StatusCode == http.StatusOK { if resp.StatusCode == http.StatusOK {
termails := response["termails"].([]interface{}) termails, exists := response["termails"]
if len(termails) == 0 { if !exists || termails == nil {
fmt.Println("No termails found.") fmt.Println("No termails found.")
return return
} }
for _, t := range termails { termailList, ok := termails.([]interface{})
if !ok {
fmt.Println("No termails found.")
return
}
if len(termailList) == 0 {
fmt.Println("No termails found.")
return
}
for _, t := range termailList {
termail := t.(map[string]interface{}) termail := t.(map[string]interface{})
status := "READ" status := "READ"
if !termail["is_read"].(bool) { if isRead, ok := termail["is_read"].(bool); ok && !isRead {
status = "UNREAD" status = "UNREAD"
} }
fmt.Printf("[%s] ID: %.0f | From: %s | Subject: %s | Sent: %s\n", fmt.Printf("[%s] ID: %.0f | From: %s | Subject: %s | Sent: %s\n",

View File

@ -191,6 +191,22 @@ type SendTermailRequest struct {
Content string `json:"content"` Content string `json:"content"`
} }
func GetTermail(ctx context.Context, termailID, userID int) (*Termail, error) {
var t Termail
err := Pool.QueryRow(ctx, `
SELECT t.id, t.sender_id, t.receiver_id, t.subject, t.content, t.is_read, t.sent_at, u.username as sender
FROM termails t
JOIN users u ON t.sender_id = u.id
WHERE t.id = $1 AND t.receiver_id = $2
`, termailID, userID).Scan(&t.ID, &t.SenderID, &t.ReceiverID, &t.Subject, &t.Content, &t.IsRead, &t.SentAt, &t.Sender)
if err != nil {
return nil, err
}
return &t, nil
}
func SendTermail(ctx context.Context, senderID int, req SendTermailRequest) (*Termail, error) { func SendTermail(ctx context.Context, senderID int, req SendTermailRequest) (*Termail, error) {
receiver, err := GetUserByUsername(ctx, req.ReceiverUsername) receiver, err := GetUserByUsername(ctx, req.ReceiverUsername)
if err != nil { if err != nil {

View File

@ -195,6 +195,26 @@ func HandleGetInbox(c echo.Context) error {
}) })
} }
func HandleGetTermail(c echo.Context) error {
userID := c.Get("user_id").(int)
termailID, err := strconv.Atoi(c.Param("id"))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid termail ID"})
}
termail, err := db.GetTermail(c.Request().Context(), termailID, userID)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
return c.JSON(http.StatusNotFound, map[string]string{"error": "Termail not found"})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to fetch termail"})
}
return c.JSON(http.StatusOK, map[string]any{
"termail": termail,
})
}
func HandleMarkTermailRead(c echo.Context) error { func HandleMarkTermailRead(c echo.Context) error {
userID := c.Get("user_id").(int) userID := c.Get("user_id").(int)
termailID, err := strconv.Atoi(c.Param("id")) termailID, err := strconv.Atoi(c.Param("id"))