192 lines
6.3 KiB
Go
192 lines
6.3 KiB
Go
package server
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/google/jsonapi"
|
|
"github.com/rs/zerolog/hlog"
|
|
"gitlab.com/mstarongitlab/goutils/other"
|
|
"gitlab.com/mstarongitlab/goutils/sliceutils"
|
|
"gitlab.com/mstarongitlab/linstrom/storage"
|
|
)
|
|
|
|
// No create account. That happens during passkey registration
|
|
// and remote accounts are getting created at fetch time
|
|
func linstromGetAccount(w http.ResponseWriter, r *http.Request) {
|
|
store := StorageFromRequest(r)
|
|
log := hlog.FromRequest(r)
|
|
|
|
accId := AccountIdFromRequest(r)
|
|
acc, err := store.FindAccountById(accId)
|
|
switch err {
|
|
case nil:
|
|
// Ok, do nothing
|
|
case storage.ErrEntryNotFound:
|
|
other.HttpErr(w, HttpErrIdNotFound, "account not found", http.StatusNotFound)
|
|
return
|
|
default:
|
|
log.Error().Err(err).Str("account-id", accId).Msg("Failed to get account from storage")
|
|
other.HttpErr(
|
|
w,
|
|
HttpErrIdDbFailure,
|
|
"Failed to get account from storage",
|
|
http.StatusInternalServerError,
|
|
)
|
|
return
|
|
}
|
|
actorId, ok := r.Context().Value(ContextKeyActorId).(string)
|
|
if ok {
|
|
// Logged in user is accessing account, check if target account has them blocked
|
|
roles, err := store.FindRolesByNames(acc.Roles)
|
|
if err != nil {
|
|
log.Error().
|
|
Err(err).
|
|
Strs("role-names", acc.Roles).
|
|
Msg("Failed to get roles from storage")
|
|
other.HttpErr(
|
|
w,
|
|
HttpErrIdDbFailure,
|
|
"Failed to get roles of target account",
|
|
http.StatusInternalServerError,
|
|
)
|
|
return
|
|
}
|
|
collapsedRole := storage.CollapseRolesIntoOne(roles...)
|
|
if sliceutils.Contains(collapsedRole.BlockedUsers, actorId) {
|
|
// Actor account is in list of blocked accounts, deny access
|
|
other.HttpErr(w, HttpErrIdNotAuthenticated, "Access forbidden", http.StatusForbidden)
|
|
return
|
|
}
|
|
}
|
|
|
|
outAccount, err := convertAccountStorageToLinstrom(acc, store)
|
|
if err != nil {
|
|
log.Error().
|
|
Err(err).
|
|
Msg("Failed to convert storage account (and attached data) into linstrom API representation")
|
|
other.HttpErr(
|
|
w,
|
|
HttpErrIdConverionFailure,
|
|
"Failed to convert storage account and attached data into API representation",
|
|
http.StatusInternalServerError,
|
|
)
|
|
return
|
|
}
|
|
err = jsonapi.MarshalPayload(w, outAccount)
|
|
if err != nil {
|
|
log.Error().Err(err).Any("account", outAccount).Msg("Failed to marshal and write account")
|
|
}
|
|
}
|
|
|
|
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) {}
|
|
|
|
func linstromIsFollowingAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromFollowAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromUnfollowAccount(w http.ResponseWriter, r *http.Request) {}
|
|
|
|
func linstromIsBlockingAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromBlockAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromUnblockAccount(w http.ResponseWriter, r *http.Request) {}
|
|
|
|
func linstromIsMutedAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromMuteAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromUnmuteAccount(w http.ResponseWriter, r *http.Request) {}
|
|
|
|
func linstromReportAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromRetractReportAccount(w http.ResponseWriter, r *http.Request) {}
|
|
|
|
func linstromAdminAddRoleAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromAdminRemoveRoleAccount(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromAdminWarnAccount(w http.ResponseWriter, r *http.Request) {}
|
|
|
|
func linstromGetRole(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromCreateRole(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromUpdateRole(w http.ResponseWriter, r *http.Request) {}
|
|
func linstromDeleteRole(w http.ResponseWriter, r *http.Request) {}
|