Work on following relations api and small docs

This commit is contained in:
Melody Becker 2024-11-15 16:15:07 +01:00
parent 526b5c2fef
commit f656757710
3 changed files with 217 additions and 22 deletions

View file

@ -1,6 +1,11 @@
package server
import "net/http"
import (
"net/http"
"gitlab.com/mstarongitlab/goutils/other"
"gitlab.com/mstarongitlab/linstrom/storage"
)
func setupLinstromApiRouter() http.Handler {
router := http.NewServeMux()
@ -12,25 +17,50 @@ func setupLinstromApiRouter() http.Handler {
func setupLinstromApiV1Router() http.Handler {
router := http.NewServeMux()
// Notes
// Get a note
router.HandleFunc("GET /notes/{noteId}", linstromGetNote)
// Send a new note
router.HandleFunc("POST /notes", linstromNewNote)
// Update a note
router.HandleFunc("PATCH /notes/{noteId}", linstromUpdateNote)
// Delete a note
router.HandleFunc("DELETE /notes/{noteId}", linstromDeleteNote)
// Reactions
// Get all reactions for a note
router.HandleFunc("GET /notes/{noteId}/reactions", linstromGetReactions)
// Send a new reaction to a note
router.HandleFunc("POST /notes/{noteId}/reactions", linstromAddReaction)
// Update own reaction on a note
router.HandleFunc("PATCH /notes/{noteId}/reactions", linstromUpdateReaction)
// Remove own reaction on a note
router.HandleFunc("DELETE /notes/{noteId}/reactions", linstromDeleteReaction)
// Boosts
// Get all boosters of a note
router.HandleFunc("GET /notes/{noteId}/boosts", linstromGetBoosts)
// Boost a note
router.HandleFunc("POST /notes/{noteId}/boosts", linstromAddBoost)
// Unboost a note
router.HandleFunc("DELETE /notes/{noteId}/boosts", linstromRemoveBoost)
// Quotes
// Get all quotes of a note
router.HandleFunc("GET /notes/{noteId}/quotes", linstromGetQuotes)
// Create a new quote message of a given note
router.HandleFunc("POST /notes/{noteId}/quotes", linstromAddQuote)
// Pinning
// Pin a note to account profile
router.HandleFunc("POST /notes/{noteId}/pin", linstromPinNote)
// Unpin a note from account profile
router.HandleFunc("DELETE /notes/{noteId}/pin", linstromUnpinNote)
// Reports
router.HandleFunc("POST /notes/{noteId}/report", linstromReportNote)
@ -40,7 +70,10 @@ func setupLinstromApiV1Router() http.Handler {
// Accounts
// Creating a new account happens either during fetch of a remote one or during registration with a passkey
// Get an account
router.HandleFunc("GET /accounts/{accountId}", linstromGetAccount)
// Update own account
// Technically also requires authenticated account to also be owner or correct admin perms,
// but that's annoying to handle in a general sense. So leaving that to the function
// though figuring out a nice generic-ish way to handle those checks would be nice too
@ -48,6 +81,7 @@ func setupLinstromApiV1Router() http.Handler {
"PATCH /accounts/{accountId}",
requireValidSessionMiddleware(linstromUpdateAccount),
)
// Delete own account
// Technically also requires authenticated account to also be owner or correct admin perms,
// but that's annoying to handle in a general sense. So leaving that to the function
router.HandleFunc(
@ -55,38 +89,87 @@ func setupLinstromApiV1Router() http.Handler {
requireValidSessionMiddleware(linstromDeleteAccount),
)
// Follow
router.HandleFunc("GET /accounts/{accountId}/follow", linstromIsFollowingAccount)
router.HandleFunc("POST /accounts/{accountId}/follow", linstromFollowAccount)
router.HandleFunc("DELETE /accounts/{accountId}/follow", linstromUnfollowAccount)
// Block
router.HandleFunc("GET /accounts/{accountId}/block", linstromIsBlockingAccount)
router.HandleFunc("POST /accounts/{accountId}/block", linstromBlockAccount)
router.HandleFunc("DELETE /accounts/{accountId}/block", linstromUnblockAccount)
// Mute
router.HandleFunc("GET /accounts/{accountId}/mute", linstromIsMutedAccount)
router.HandleFunc("POST /accounts/{accountId}/mute", linstromMuteAccount)
router.HandleFunc("DELETE /accounts/{accountId}/mute", linstromUnmuteAccount)
// Report
router.HandleFunc("POST /accounts/{accountId}/reports", linstromReportAccount)
router.HandleFunc("DELETE /accounts/{accountId}/reports", linstromRetractReportAccount)
// Admin
router.HandleFunc("POST /accounts/{accountId}/admin/roles", linstromAdminAddRoleAccount)
// Is logged in following accountId
router.HandleFunc(
"DELETE /accounts/{accountId}/admin/roles/{roleName}",
linstromAdminRemoveRoleAccount,
"GET /accounts/{accountId}/follow/to",
requireValidSessionMiddleware(linstromIsFollowingToAccount),
)
// Is accountId following logged in
router.HandleFunc(
"GET /accounts/{accountId}/follow/from",
requireValidSessionMiddleware(linstromIsFollowingFromAccount),
)
// Send follow request to accountId
router.HandleFunc("POST /accounts/{accountId}/follow", linstromFollowAccount)
// Undo follow request to accountId
router.HandleFunc("DELETE /accounts/{accountId}/follow", linstromUnfollowAccount)
// Block
// Is logged in account blocking target account
router.HandleFunc("GET /accounts/{accountId}/block", linstromIsBlockingAccount)
// Block target account
router.HandleFunc("POST /accounts/{accountId}/block", linstromBlockAccount)
// Unblock target account
router.HandleFunc("DELETE /accounts/{accountId}/block", linstromUnblockAccount)
// Mute
// Has logged in account muted target account?
router.HandleFunc("GET /accounts/{accountId}/mute", linstromIsMutedAccount)
// Mute target account
router.HandleFunc("POST /accounts/{accountId}/mute", linstromMuteAccount)
// Unmute target account
router.HandleFunc("DELETE /accounts/{accountId}/mute", linstromUnmuteAccount)
// Report
// Report a target account
router.HandleFunc("POST /accounts/{accountId}/reports", linstromReportAccount)
// Undo report on target account
router.HandleFunc("DELETE /accounts/{accountId}/reports", linstromRetractReportAccount)
// Admin
// Add new role to account
router.Handle(
"POST /accounts/{accountId}/admin/roles",
buildRequirePermissionsMiddleware(
&storage.Role{CanAssignRoles: other.IntoPointer(true)},
)(
http.HandlerFunc(linstromAdminAddRoleAccount),
),
)
// Remove role from account
router.Handle(
"DELETE /accounts/{accountId}/admin/roles/{roleName}",
buildRequirePermissionsMiddleware(&storage.Role{CanAssignRoles: other.IntoPointer(true)})(
http.HandlerFunc(linstromAdminRemoveRoleAccount),
),
)
// Send a warning to account
router.HandleFunc("POST /accounts/{accountId}/admin/warn", linstromAdminWarnAccount)
// Roles
// Get a role
router.HandleFunc("GET /roles/{roleId}", linstromGetRole)
// Create a new role
router.HandleFunc("POST /roles", linstromCreateRole)
// Update a role. Builtin roles cannot be edited
router.HandleFunc("PATCH /roles/{roleId}", linstromUpdateRole)
// Delete a role. Builtin roles cannot be deleted
router.HandleFunc("DELETE /roles/{roleId}", linstromDeleteRole)
// Media metadata
// Get the metadata for some media
router.HandleFunc("GET /media/{mediaId}", linstromGetMediaMetadata)
// Upload new media
router.HandleFunc("POST /media", linstromNewMediaMetadata)
// Update the metadata for some media
router.HandleFunc("PATCH /media/{mediaId}", linstromUpdateMediaMetadata)
// Delete a media entry
router.HandleFunc("DELETE /media/{mediaId}", linstromDeleteMediaMetadata)
// Event streams

View file

@ -165,6 +165,7 @@ func linstromUpdateAccount(w http.ResponseWriter, r *http.Request) {
log.Error().Err(err).Msg("Failed to marshal and write updated account")
}
}
func linstromDeleteAccount(w http.ResponseWriter, r *http.Request) {
actorId, _ := ActorIdFromRequest(r)
log := hlog.FromRequest(r)
@ -238,7 +239,117 @@ func linstromDeleteAccount(w http.ResponseWriter, r *http.Request) {
}
}
func linstromIsFollowingAccount(w http.ResponseWriter, r *http.Request) {}
// Is logged in following accountId
func linstromIsFollowingToAccount(w http.ResponseWriter, r *http.Request) {
store := StorageFromRequest(r)
log := hlog.FromRequest(r)
actorId, _ := ActorIdFromRequest(r)
targetId := AccountIdFromRequest(r)
relation, err := store.GetRelationBetween(actorId, targetId)
var outData linstromRelation
switch err {
case nil:
outData = linstromRelation{
Id: relation.ID,
CreatedAt: relation.CreatedAt,
UpdatedAt: relation.UpdatedAt,
FromId: relation.FromId,
ToId: relation.ToId,
Accepted: relation.Accepted,
Requested: true,
}
case storage.ErrEntryNotFound:
outData = linstromRelation{
Id: relation.ID,
CreatedAt: relation.CreatedAt,
UpdatedAt: relation.UpdatedAt,
FromId: relation.FromId,
ToId: relation.ToId,
Accepted: false,
Requested: false,
}
default:
log.Error().
Err(err).
Str("from-id", actorId).
Str("to-id", targetId).
Msg("Failed to get follow relation")
other.HttpErr(
w,
HttpErrIdDbFailure,
"Failed to get relation",
http.StatusInternalServerError,
)
}
err = jsonapi.MarshalPayload(w, outData)
if err != nil {
log.Warn().Err(err).Msg("Failed to marshal response")
other.HttpErr(
w,
HttpErrIdJsonMarshalFail,
"Failed to marshal response",
http.StatusInternalServerError,
)
}
}
func linstromIsFollowingFromAccount(w http.ResponseWriter, r *http.Request) {
store := StorageFromRequest(r)
log := hlog.FromRequest(r)
actorId, _ := ActorIdFromRequest(r)
targetId := AccountIdFromRequest(r)
relation, err := store.GetRelationBetween(targetId, actorId)
var outData linstromRelation
switch err {
case nil:
outData = linstromRelation{
Id: relation.ID,
CreatedAt: relation.CreatedAt,
UpdatedAt: relation.UpdatedAt,
FromId: relation.FromId,
ToId: relation.ToId,
Accepted: relation.Accepted,
Requested: true,
}
case storage.ErrEntryNotFound:
outData = linstromRelation{
Id: relation.ID,
CreatedAt: relation.CreatedAt,
UpdatedAt: relation.UpdatedAt,
FromId: relation.FromId,
ToId: relation.ToId,
Accepted: false,
Requested: false,
}
default:
log.Error().
Err(err).
Str("from-id", targetId).
Str("to-id", actorId).
Msg("Failed to get follow relation")
other.HttpErr(
w,
HttpErrIdDbFailure,
"Failed to get relation",
http.StatusInternalServerError,
)
}
err = jsonapi.MarshalPayload(w, outData)
if err != nil {
log.Warn().Err(err).Msg("Failed to marshal response")
other.HttpErr(
w,
HttpErrIdJsonMarshalFail,
"Failed to marshal response",
http.StatusInternalServerError,
)
}
}
func linstromFollowAccount(w http.ResponseWriter, r *http.Request) {}
func linstromUnfollowAccount(w http.ResponseWriter, r *http.Request) {}

View file

@ -96,6 +96,7 @@ type linstromRelation struct {
UpdatedAt time.Time `jsonapi:"attr,updated-at"`
FromId string `jsonapi:"attr,from-id"`
ToId string `jsonapi:"attr,to-id"`
Requested bool `jsonapi:"attr,requested"`
Accepted bool `jsonapi:"attr,accepted"`
}