Follow accept works and messags are pushed as expected
Some checks failed
/ docker (push) Failing after 2m50s
Some checks failed
/ docker (push) Failing after 2m50s
This commit is contained in:
parent
9a3a330b1d
commit
ff6a730e58
10 changed files with 482 additions and 19 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
webutils "git.mstar.dev/mstar/goutils/http"
|
||||
"git.mstar.dev/mstar/goutils/other"
|
||||
|
@ -15,8 +16,10 @@ import (
|
|||
"gorm.io/gorm"
|
||||
|
||||
"git.mstar.dev/mstar/linstrom/activitypub"
|
||||
"git.mstar.dev/mstar/linstrom/shared"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/models"
|
||||
webshared "git.mstar.dev/mstar/linstrom/web/shared"
|
||||
)
|
||||
|
||||
var objectIdRegex = regexp.MustCompile(
|
||||
|
@ -316,8 +319,54 @@ func handleFollow(w http.ResponseWriter, r *http.Request, object map[string]any)
|
|||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to commit follow activity transaction")
|
||||
}
|
||||
if !followed.RestrictedFollow {
|
||||
// FIXME: Handle errors
|
||||
tx = dbgen.Q.Begin()
|
||||
_, err = u2u.Where(u2u.ID.Eq(req.ID)).UpdateColumn(u2u.Relation, models.RelationFollow)
|
||||
acceptActivity := models.Activity{
|
||||
Id: shared.NewId(),
|
||||
Type: string(models.ActivityAccept),
|
||||
ObjectId: activity.Id,
|
||||
ObjectType: uint32(models.ActivitystreamsActivityTargetActivity),
|
||||
}
|
||||
err = tx.Activity.Create(&acceptActivity)
|
||||
tx.Commit()
|
||||
go func() {
|
||||
// FIXME: Clean this entire mess up
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
webAccept, err := AcceptFromStorage(r.Context(), acceptActivity.Id)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get accept from db")
|
||||
return
|
||||
}
|
||||
webAccept.Context = activitypub.BaseLdContext
|
||||
body, err := json.Marshal(webAccept)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal accept")
|
||||
return
|
||||
}
|
||||
res, err := webshared.RequestSignedCavage(
|
||||
"POST",
|
||||
follower.RemoteInfo.InboxLink,
|
||||
body,
|
||||
followed,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to send accept")
|
||||
return
|
||||
}
|
||||
if res.StatusCode >= 400 {
|
||||
body, _ = io.ReadAll(res.Body)
|
||||
log.Error().
|
||||
Int("status-code", res.StatusCode).
|
||||
Bytes("body", body).
|
||||
Msg("Post of accept failed")
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// WARN: Untested as can't send follow activities yet
|
||||
func handleAccept(w http.ResponseWriter, r *http.Request, object map[string]any) {
|
||||
log := hlog.FromRequest(r)
|
||||
rawTarget, ok := object["object"]
|
||||
|
@ -404,9 +453,124 @@ func handleAccept(w http.ResponseWriter, r *http.Request, object map[string]any)
|
|||
}
|
||||
relationId := other.Must(strconv.ParseUint(followActivity.ObjectId, 10, 64))
|
||||
dbrel := dbgen.UserToUserRelation
|
||||
_, err = dbrel.Where(dbrel.ID.Eq(relationId)).
|
||||
tx := dbgen.Q.Begin()
|
||||
_, err = tx.UserToUserRelation.Where(dbrel.ID.Eq(relationId)).
|
||||
UpdateColumn(dbrel.Relation, models.RelationFollow)
|
||||
switch err {
|
||||
case gorm.ErrRecordNotFound:
|
||||
// No need to rollback, nothing was done
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusNotFound)
|
||||
return
|
||||
case nil:
|
||||
default:
|
||||
_ = tx.Rollback()
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("target-id", internalId).
|
||||
Msg("Failed to update follow status to confirmed follow")
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
activity := models.Activity{
|
||||
Id: object["id"].(string),
|
||||
Type: string(models.ActivityAccept),
|
||||
ObjectType: uint32(models.ActivitystreamsActivityTargetActivity),
|
||||
ObjectId: followActivity.Id,
|
||||
}
|
||||
err = tx.Activity.Create(&activity)
|
||||
if err != nil {
|
||||
err = tx.Rollback()
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("target-id", internalId).
|
||||
Msg("Failed to store accept activity in db")
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("target-id", internalId).
|
||||
Msg("Failed to commit accept transaction")
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// WARN: Untested as can't send follow activities yet
|
||||
func handleReject(w http.ResponseWriter, r *http.Request, object map[string]any) {
|
||||
log := hlog.FromRequest(r)
|
||||
rawTarget, ok := object["object"]
|
||||
if !ok {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusBadRequest,
|
||||
"/errors/bad-request-data",
|
||||
"Bad activity data",
|
||||
other.IntoPointer(`Request data needs to contain a field "object"`),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
// FIXME: Also handle other undo cases, such as follows
|
||||
var targetObjectId string
|
||||
// I *think* the spec says that this must be an object. Not sure though
|
||||
switch target := rawTarget.(type) {
|
||||
case string:
|
||||
targetObjectId = target
|
||||
case map[string]any:
|
||||
objType, ok := target["type"].(string)
|
||||
// TODO: Ensure accept is only used for follows
|
||||
if !ok || objType != "Follow" {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusBadRequest,
|
||||
"/errors/bad-request-data",
|
||||
"Bad activity data",
|
||||
other.IntoPointer(`Target object type must be a string with value "Follow"`),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
targetObjectId, ok = target["id"].(string)
|
||||
if !ok {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusBadRequest,
|
||||
"/errors/bad-request-data",
|
||||
"Bad activity data",
|
||||
other.IntoPointer(`Missing id in undone object`),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
default:
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusBadRequest,
|
||||
"/errors/bad-request-data",
|
||||
"Bad activity data",
|
||||
other.IntoPointer(`Request data needs to contain a field "object" of type string or object`),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
internalIdMatch := objectIdRegex.FindStringSubmatch(targetObjectId)
|
||||
if len(internalIdMatch) != 2 {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusBadRequest,
|
||||
"/errors/bad-request-data",
|
||||
"Bad activity data",
|
||||
other.IntoPointer(`Request data target object is not internal id`),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
internalId := internalIdMatch[1]
|
||||
followActivity, err := dbgen.Activity.Where(dbgen.Activity.Id.Eq(internalId)).First()
|
||||
switch err {
|
||||
case gorm.ErrRecordNotFound:
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusNotFound)
|
||||
return
|
||||
|
@ -419,6 +583,59 @@ func handleAccept(w http.ResponseWriter, r *http.Request, object map[string]any)
|
|||
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
relationId := other.Must(strconv.ParseUint(followActivity.ObjectId, 10, 64))
|
||||
dbrel := dbgen.UserToUserRelation
|
||||
tx := dbgen.Q.Begin()
|
||||
_, err = tx.UserToUserRelation.Where(dbrel.ID.Eq(relationId)).Delete()
|
||||
switch err {
|
||||
case gorm.ErrRecordNotFound:
|
||||
// No need to rollback, nothing was done
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusNotFound)
|
||||
return
|
||||
case nil:
|
||||
default:
|
||||
_ = tx.Rollback()
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("target-id", internalId).
|
||||
Msg("Failed to delete follow status")
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, err = tx.Activity.Where(
|
||||
dbgen.Activity.ObjectId.Eq(followActivity.Id),
|
||||
dbgen.Activity.Type.Eq("Accept"),
|
||||
).
|
||||
Delete()
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
log.Error().Err(err).Msg("Failed to delete accept for later rejected follow")
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
activity := models.Activity{
|
||||
Id: object["id"].(string),
|
||||
Type: string(models.ActivityAccept),
|
||||
ObjectType: uint32(models.ActivitystreamsActivityTargetActivity),
|
||||
ObjectId: followActivity.Id,
|
||||
}
|
||||
err = tx.Activity.Create(&activity)
|
||||
if err != nil {
|
||||
err = tx.Rollback()
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("target-id", internalId).
|
||||
Msg("Failed to store accept activity in db")
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("target-id", internalId).
|
||||
Msg("Failed to commit accept transaction")
|
||||
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func handleReject(w http.ResponseWriter, r *http.Request, object map[string]any) {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue