memos/store/db/mysql/memo_relation_policy.go

101 lines
2.9 KiB
Go

package mysql
import (
"context"
"database/sql"
stderrors "errors"
"github.com/usememos/memos/store"
)
type mysqlRelationMemoState struct {
id int32
creatorID int32
rowStatus store.RowStatus
visibility store.Visibility
spaceID *int32
}
func validateMySQLMemoRelationEndpoints(ctx context.Context, tx *sql.Tx, mutation *store.MemoMutation) error {
if !mutation.ReplaceReferenceRelations && mutation.CommentContextMemoID == nil {
return nil
}
var actorStatus store.RowStatus
actorErr := tx.QueryRowContext(ctx, "SELECT row_status FROM user WHERE id = ?", mutation.MemoCreatorID).Scan(&actorStatus)
if actorErr != nil && !stderrors.Is(actorErr, sql.ErrNoRows) {
return actorErr
}
actorActive := actorErr == nil && actorStatus == store.Normal
endpointIDs := mysqlRelationAuthorizationEndpointIDs(mutation)
for _, endpointID := range endpointIDs {
state, err := getMySQLRelationMemoState(ctx, tx, endpointID)
if err != nil {
if stderrors.Is(err, sql.ErrNoRows) {
return store.ErrMemoMutationConflict
}
return err
}
snapshot := &store.MemoRelationEndpointSnapshot{
ActorUserID: mutation.MemoCreatorID,
ActorActive: actorActive,
EndpointID: state.id,
EndpointCreatorID: state.creatorID,
EndpointRowStatus: state.rowStatus,
EndpointVisibility: state.visibility,
EndpointSpaceID: state.spaceID,
}
if state.spaceID != nil {
snapshot.EndpointSpaceExists, err = mysqlSpaceExists(ctx, tx, *state.spaceID)
if err != nil {
return err
}
if snapshot.EndpointSpaceExists {
snapshot.EndpointMemberActive, err = mysqlSpaceMemberActive(ctx, tx, *state.spaceID, mutation.MemoCreatorID)
if err != nil {
return err
}
}
}
if err := store.ValidateMemoRelationEndpointRead(snapshot); err != nil {
return err
}
}
return nil
}
func getMySQLRelationMemoState(ctx context.Context, tx *sql.Tx, memoID int32) (*mysqlRelationMemoState, error) {
state := &mysqlRelationMemoState{}
var spaceID sql.NullInt64
if err := tx.QueryRowContext(ctx, `SELECT id, creator_id, row_status, visibility, space_id FROM memo WHERE id = ?`, memoID).Scan(
&state.id, &state.creatorID, &state.rowStatus, &state.visibility, &spaceID,
); err != nil {
return nil, err
}
state.spaceID = store.NullInt32Pointer(spaceID)
return state, nil
}
func mysqlRelationAuthorizationEndpointIDs(mutation *store.MemoMutation) []int32 {
ids := make([]int32, 0, len(mutation.ReferenceRelations)+1)
seen := make(map[int32]struct{}, len(mutation.ReferenceRelations)+1)
add := func(id int32) {
if _, ok := seen[id]; ok {
return
}
seen[id] = struct{}{}
ids = append(ids, id)
}
if mutation.MemoCreate == nil && mutation.MemoID > 0 {
add(mutation.MemoID)
} else if mutation.CommentContextMemoID != nil {
add(*mutation.CommentContextMemoID)
}
for _, relation := range mutation.ReferenceRelations {
if relation != nil {
add(relation.RelatedMemoID)
}
}
return ids
}