package webdebug import ( "database/sql" "encoding/json" "errors" "io" "net/http" webutils "git.mstar.dev/mstar/goutils/http" "git.mstar.dev/mstar/goutils/sliceutils" "github.com/rs/zerolog/hlog" "gorm.io/gorm" "git.mstar.dev/mstar/linstrom/activitypub" "git.mstar.dev/mstar/linstrom/shared" "git.mstar.dev/mstar/linstrom/storage-new" "git.mstar.dev/mstar/linstrom/storage-new/dbgen" "git.mstar.dev/mstar/linstrom/storage-new/models" webap "git.mstar.dev/mstar/linstrom/web/public/api/activitypub" webshared "git.mstar.dev/mstar/linstrom/web/shared" ) func postAs(w http.ResponseWriter, r *http.Request) { type Inbound struct { Username string `json:"username"` Content string `json:"content"` } log := hlog.FromRequest(r) dec := json.NewDecoder(r.Body) data := Inbound{} err := dec.Decode(&data) if err != nil { _ = webutils.ProblemDetails( w, http.StatusBadRequest, "/errors/bad-request-data", "bad request data", nil, map[string]any{ "sample": Inbound{ Username: "bob", Content: "Heya there, this is sample data", }, }, ) return } user, err := dbgen.User.GetByUsername(data.Username) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { _ = webutils.ProblemDetailsStatusOnly(w, http.StatusNotFound) } else { log.Error().Err(err).Str("name", data.Username).Msg("Failed to find user") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) } return } n := dbgen.Note note := models.Note{ ID: shared.NewId(), Creator: user, CreatorId: user.ID, RawContent: data.Content, Remote: false, ContentWarning: sql.NullString{Valid: false}, RepliesTo: sql.NullString{Valid: false}, Quotes: sql.NullString{Valid: false}, AccessLevel: models.NOTE_TARGET_PUBLIC, OriginId: 1, } tx := dbgen.Q.Begin() err = tx.Note.Select( n.ID, n.CreatorId, n.RawContent, n.Remote, n.ContentWarning, n.RepliesTo, n.Quotes, n.AccessLevel, n.OriginId, ).Create(¬e) if err != nil { _ = tx.Rollback() log.Error(). Err(err). Str("username", data.Username). Str("content", data.Content). Msg("Failed to create message") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) return } activity := models.Activity{ Id: shared.NewId(), Type: string(models.ActivityCreate), ObjectId: note.ID, ObjectType: uint32(models.ActivitystreamsActivityTargetNote), } err = tx.Activity.Create(&activity) if err != nil { _ = tx.Rollback() log.Error().Err(err).Msg("Failed to create activity for new note") } err = tx.Commit() if err != nil { log.Error().Err(err).Msg("Failed to commit note creation") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) return } u2u := dbgen.UserToUserRelation links, err := u2u.GetFollowerInboxesForId(user.ID) if err != nil { log.Error().Err(err).Msg("Failed to get follower inbox links for user") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) return } log.Debug().Strs("links", links).Send() act, err := webap.CreateFromStorage(r.Context(), activity.Id) if err != nil { log.Error().Err(err).Msg("Failed to fetch and format new note") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) return } act.Context = activitypub.BaseLdContext outData, err := json.Marshal(act) if err != nil { log.Error().Err(err).Msg("Failed to marshal new note") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) return } for _, link := range links { log.Debug().Str("target-inbox", link).Msg("Sending message to") go func() { res, err := webshared.RequestSignedCavage("POST", link, outData, user) if err != nil { log.Warn().Err(err).Str("link", link).Msg("Failed to send create to target inbox") } if res.StatusCode >= 400 { body, _ := io.ReadAll(res.Body) log.Warn().Int("status-code", res.StatusCode).Bytes("body", body).Msg("Bad reply") } }() } } func notesFrom(w http.ResponseWriter, r *http.Request) { log := hlog.FromRequest(r) username := r.FormValue("username") user, err := dbgen.User.GetByUsername(username) if err != nil { log.Error().Err(err).Str("name", username).Msg("Failed to get user") storage.HandleReconnectError(err) _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) return } notes, err := dbgen.Note.GetNotesPaged(user.ID, 0, uint8(models.NOTE_TARGET_PUBLIC)) if err != nil { log.Error().Err(err).Str("name", username).Msg("Failed to get notes") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) return } publicNotes := sliceutils.Map(notes, func(t models.Note) webshared.Note { n := webshared.Note{} n.FromModel(&t) return n }) _ = webutils.SendJson(w, publicNotes) } func inReplyTo(w http.ResponseWriter, r *http.Request) { log := hlog.FromRequest(r) noteId := r.PathValue("id") notes, err := dbgen.Note. Where(dbgen.Note.RepliesTo.Eq(sql.NullString{Valid: true, String: noteId})). Find() if err != nil { log.Error().Err(err).Str("id", noteId).Msg("Error getting replies to note with id") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) return } _ = webutils.SendJson(w, notes) }