inital commit
This commit is contained in:
73
notes_send.go
Normal file
73
notes_send.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package fa
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
|
||||
"git.anthrove.art/public/go-fa-api/internal/urls"
|
||||
)
|
||||
|
||||
// SendNote sends a new private message (note) to a user. Requires login.
|
||||
//
|
||||
// FA's note form posts to /msg/send/ with a per-form CSRF key that must
|
||||
// be scraped from the notes inbox (or any page that renders the send
|
||||
// form). This method does the scrape + post in one call.
|
||||
//
|
||||
// Returns nil on success. ErrUnauthorized when not logged in.
|
||||
// *SystemMessageError when FA rejects the send (recipient blocked, rate
|
||||
// limited, etc.).
|
||||
func (c *Client) SendNote(ctx context.Context, to string, subject string, body string) error {
|
||||
to = strings.TrimSpace(to)
|
||||
if to == "" {
|
||||
return fmt.Errorf("fa: SendNote: empty recipient")
|
||||
}
|
||||
if subject == "" {
|
||||
return fmt.Errorf("fa: SendNote: empty subject")
|
||||
}
|
||||
if body == "" {
|
||||
return fmt.Errorf("fa: SendNote: empty body")
|
||||
}
|
||||
|
||||
// Scrape the form key from /msg/pms/. The notes inbox renders the same
|
||||
// CSRF key in any note-related form on the page; we don't actually need
|
||||
// to be replying to anything to harvest it.
|
||||
var key string
|
||||
err := c.fetch(ctx, urls.MsgPMs(), func(doc *goquery.Document) error {
|
||||
key = findNoteKey(doc)
|
||||
if key == "" {
|
||||
return fmt.Errorf("%w: SendNote: could not locate form key on /msg/pms/", ErrUnauthorized)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("key", key)
|
||||
v.Set("to", to)
|
||||
v.Set("subject", subject)
|
||||
v.Set("message", body)
|
||||
v.Set("send", "Send Note")
|
||||
_, err = c.postForm(ctx, urls.Host+"/msg/send/", v)
|
||||
return err
|
||||
}
|
||||
|
||||
// findNoteKey looks for a hidden input named "key" inside any form that
|
||||
// targets the notes subsystem (/msg/send/ or /msg/pms/). FA reuses the
|
||||
// same key value across these forms within a session.
|
||||
func findNoteKey(doc *goquery.Document) string {
|
||||
var key string
|
||||
doc.Find("form[action='/msg/send/'] input[name='key'], form[action='/msg/pms/'] input[name='key'], form[action^='/msg/'] input[name='key']").EachWithBreak(func(_ int, sel *goquery.Selection) bool {
|
||||
if v := strings.TrimSpace(trimAttr(sel, "value")); v != "" {
|
||||
key = v
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return key
|
||||
}
|
||||
Reference in New Issue
Block a user