More progress. Fixed storage bug. Need to get media stuff going
This commit is contained in:
Melody Becker 2024-11-05 16:29:01 +01:00
parent 1bb6cd8a70
commit 83f47d17be
11 changed files with 209 additions and 27 deletions

View file

@ -42,6 +42,7 @@ func setupLinstromApiV1Router() http.Handler {
router.HandleFunc("GET /accounts/{accountId}", linstromGetAccount)
// 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
router.HandleFunc(
"PATCH /accounts/{accountId}",
requireValidSessionMiddleware(linstromUpdateAccount),

View file

@ -81,6 +81,89 @@ func linstromGetAccount(w http.ResponseWriter, r *http.Request) {
func linstromUpdateAccount(w http.ResponseWriter, r *http.Request) {
store := StorageFromRequest(r)
log := hlog.FromRequest(r)
// Assumption: There must be a valid session once this function is called due to middlewares
actorId, _ := ActorIdFromRequest(r)
apiTarget := linstromAccount{}
err := jsonapi.UnmarshalPayload(r.Body, &apiTarget)
if err != nil {
other.HttpErr(w, HttpErrIdBadRequest, "bad body", http.StatusBadRequest)
return
}
targetAccId := AccountIdFromRequest(r)
if apiTarget.Id != targetAccId {
other.HttpErr(
w,
HttpErrIdBadRequest,
"Provided entity's id doesn't match path id",
http.StatusConflict,
)
return
}
if !(actorId == apiTarget.Id) {
other.HttpErr(w, HttpErrIdNotAuthenticated, "Invalid permissions", http.StatusForbidden)
return
}
dbTarget, err := store.FindAccountById(apiTarget.Id)
// Assumption: The only sort of errors that can be returned are db failures.
// The account not existing is not possible anymore since this is in a valid session
// and a session is only injected if the actor account can be found
if err != nil {
log.Error().
Err(err).
Str("account-id", actorId).
Msg("Failed to get account from db despite valid session")
other.HttpErr(
w,
HttpErrIdDbFailure,
"Failed to get account despite valid session",
http.StatusInternalServerError,
)
return
}
// location, birthday, icon, banner, background, custom fields
// bluesky federation, uhhh
dbTarget.DisplayName = apiTarget.DisplayName
dbTarget.Indexable = apiTarget.Indexable
dbTarget.Description = apiTarget.Description
// TODO: Figure out how to properly update custom fields
dbTarget.Gender = apiTarget.Pronouns
dbTarget.IdentifiesAs = sliceutils.Map(
sliceutils.Filter(apiTarget.IdentifiesAs, func(t string) bool {
return storage.IsValidBeing(t)
}),
func(t string) storage.Being { return storage.Being(t) },
)
dbTarget.Indexable = apiTarget.Indexable
dbTarget.RestrictedFollow = apiTarget.RestrictedFollow
err = store.UpdateAccount(dbTarget)
if err != nil {
log.Error().Err(err).Msg("Failed to update account in db")
other.HttpErr(
w,
HttpErrIdDbFailure,
"Failed to update db entries",
http.StatusInternalServerError,
)
return
}
w.WriteHeader(http.StatusOK)
newAccData, err := convertAccountStorageToLinstrom(dbTarget, store)
if err != nil {
log.Error().Err(err).Msg("Failed to convert updated account back into api form")
other.HttpErr(
w,
HttpErrIdConverionFailure,
"Failed to convert updated account back into api form",
http.StatusInternalServerError,
)
return
}
err = jsonapi.MarshalPayload(w, newAccData)
if err != nil {
log.Error().Err(err).Msg("Failed to marshal and write updated account")
}
}
func linstromDeleteAccount(w http.ResponseWriter, r *http.Request) {}

View file

@ -1,6 +1,8 @@
package server
import (
"fmt"
"gitlab.com/mstarongitlab/goutils/sliceutils"
"gitlab.com/mstarongitlab/linstrom/storage"
)
@ -11,23 +13,23 @@ func convertAccountStorageToLinstrom(
) (*linstromAccount, error) {
storageServer, err := store.FindRemoteServerById(acc.ServerId)
if err != nil {
return nil, err
return nil, fmt.Errorf("remote server: %w", err)
}
apiServer, err := convertServerStorageToLinstrom(storageServer, store)
if err != nil {
return nil, err
return nil, fmt.Errorf("remote server conversion: %w", err)
}
storageIcon, err := store.GetMediaMetadataById(acc.Icon)
if err != nil {
return nil, err
return nil, fmt.Errorf("icon: %w", err)
}
storageBanner, err := store.GetMediaMetadataById(acc.Banner)
if err != nil {
return nil, err
return nil, fmt.Errorf("banner: %w", err)
}
storageFields, err := store.FindMultipleUserFieldsById(acc.CustomFields)
if err != nil {
return nil, err
return nil, fmt.Errorf("customFields: %w", err)
}
return &linstromAccount{
@ -68,7 +70,7 @@ func convertServerStorageToLinstrom(
) (*linstromOriginServer, error) {
storageMeta, err := store.GetMediaMetadataById(server.Icon)
if err != nil {
return nil, err
return nil, fmt.Errorf("icon metadata: %w", err)
}
return &linstromOriginServer{
Id: server.ID,

View file

@ -5,7 +5,7 @@ import "net/http"
// Mounted at /api
func setupApiRouter() http.Handler {
router := http.NewServeMux()
router.Handle("/linstrom/", setupLinstromApiRouter())
router.Handle("/linstrom/", http.StripPrefix("/linstrom", setupLinstromApiRouter()))
// Section MastoApi
// First segment are endpoints that will need to be moved to primary router since at top route

View file

@ -103,6 +103,7 @@ func fuckWithRegisterRequest(
} else {
// Not authenticated, ensure that no existing name is registered with
_, err = store.FindLocalAccountByUsername(username.Username)
log.Debug().Bool("err-equals-not_found", err == storage.ErrEntryNotFound).Send()
switch err {
case nil:
// No error while getting account means account exists, refuse access

View file

@ -27,6 +27,11 @@ func StorageFromRequest(r *http.Request) *storage.Storage {
return store
}
func ActorIdFromRequest(r *http.Request) (string, bool) {
id, ok := r.Context().Value(ContextKeyActorId).(string)
return id, ok
}
func NoteIdFromRequest(r *http.Request) string {
return r.PathValue("noteId")
}
@ -34,3 +39,16 @@ func NoteIdFromRequest(r *http.Request) string {
func AccountIdFromRequest(r *http.Request) string {
return r.PathValue("accountId")
}
func CheckIfAccountIdHasPermissions(accId string, perms storage.Role, store *storage.Storage) bool {
acc, err := store.FindAccountById(accId)
if err != nil {
return false
}
roles, err := store.FindRolesByNames(acc.Roles)
if err != nil {
return false
}
collapsed := storage.CollapseRolesIntoOne(roles...)
return storage.CompareRoles(&collapsed, &perms)
}