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.POST("/send", handlers.HandleSendTermail)
protected.GET("/inbox", handlers.HandleGetInbox)
protected.GET("/:id", handlers.HandleGetTermail)
protected.POST("/:id/read", handlers.HandleMarkTermailRead)
protected.DELETE("/:id", handlers.HandleDeleteTermail)

View File

@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
@ -62,6 +63,14 @@ var inboxCmd = &cobra.Command{
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{
Use: "read [termail_id]",
Short: "Mark termail as read",
@ -92,6 +101,7 @@ func init() {
inboxCmd.Flags().IntP("offset", "o", 0, "Number of termails to skip")
inboxCmd.Flags().Bool("unread", false, "Show only unread termails")
inboxCmd.AddCommand(inboxViewCmd)
inboxCmd.AddCommand(inboxReadCmd)
inboxCmd.AddCommand(inboxDeleteCmd)
@ -170,6 +180,64 @@ func makeAuthenticatedRequest(method, endpoint string, body []byte) (*http.Respo
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) {
search, _ := cmd.Flags().GetString("search")
limit, _ := cmd.Flags().GetInt("limit")
@ -195,16 +263,27 @@ func runInbox(cmd *cobra.Command, args []string) {
json.NewDecoder(resp.Body).Decode(&response)
if resp.StatusCode == http.StatusOK {
termails := response["termails"].([]interface{})
if len(termails) == 0 {
termails, exists := response["termails"]
if !exists || termails == nil {
fmt.Println("No termails found.")
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{})
status := "READ"
if !termail["is_read"].(bool) {
if isRead, ok := termail["is_read"].(bool); ok && !isRead {
status = "UNREAD"
}
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"`
}
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) {
receiver, err := GetUserByUsername(ctx, req.ReceiverUsername)
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 {
userID := c.Get("user_id").(int)
termailID, err := strconv.Atoi(c.Param("id"))