memos/store/db/postgres/memo_access.go

50 lines
2.6 KiB
Go

package postgres
import (
"fmt"
"strings"
"github.com/usememos/memos/store"
)
// postgresMemoAccessPredicate builds the canonical memo-local read predicate
// for memoAlias and appends its bind values to args. Callers supply distinct
// aliases when the predicate is embedded more than once in a query.
func postgresMemoAccessPredicate(access *store.MemoAccessScope, memoAlias, memberAlias string, args *[]any) string {
clauses := []string{}
if access.AllowPublic {
clauses = append(clauses, memoAlias+".visibility = 'PUBLIC'")
}
if access.UserID != nil {
activeHolder := placeholder(len(*args) + 1)
*args = append(*args, *access.UserID)
authenticatedClauses := []string{}
privateHolder := placeholder(len(*args) + 1)
*args = append(*args, *access.UserID)
authenticatedClauses = append(authenticatedClauses, "("+memoAlias+".visibility = 'PRIVATE' AND "+memoAlias+".creator_id = "+privateHolder+")")
if access.AllowProtected {
authenticatedClauses = append(authenticatedClauses, memoAlias+".visibility = 'PROTECTED'")
}
memberHolder := placeholder(len(*args) + 1)
*args = append(*args, *access.UserID)
authenticatedClauses = append(authenticatedClauses, "("+memoAlias+".visibility = 'SPACE' AND EXISTS (SELECT 1 FROM space_member AS "+memberAlias+" WHERE "+memberAlias+".space_id = "+memoAlias+".space_id AND "+memberAlias+".user_id = "+memberHolder+" AND "+memberAlias+".status = 'ACTIVE' AND "+memberAlias+".role IN ('ADMIN', 'USER')))")
clauses = append(clauses, `(EXISTS (SELECT 1 FROM "user" AS access_user WHERE access_user.id = `+activeHolder+` AND access_user.row_status = 'NORMAL') AND (`+strings.Join(authenticatedClauses, " OR ")+`))`)
}
if len(clauses) == 0 {
return "1 = 0"
}
validMemo := "(" + memoAlias + ".visibility IN ('PUBLIC', 'PROTECTED', 'PRIVATE', 'SPACE')" +
` AND EXISTS (SELECT 1 FROM "user" AS valid_creator WHERE valid_creator.id = ` + memoAlias + `.creator_id AND valid_creator.row_status IN ('NORMAL', 'ARCHIVED'))` +
" AND (" + memoAlias + ".visibility <> 'SPACE' OR (" + memoAlias + ".space_id IS NOT NULL" +
" AND EXISTS (SELECT 1 FROM space AS valid_space WHERE valid_space.id = " + memoAlias + ".space_id))))"
validState := memoAlias + ".row_status = 'NORMAL'"
if access.UserID != nil {
targetStateHolder := placeholder(len(*args) + 1)
*args = append(*args, *access.UserID)
validState = fmt.Sprintf("(%s.row_status = 'NORMAL' OR (%s.row_status = 'ARCHIVED' AND %s.creator_id = %s))", memoAlias, memoAlias, memoAlias, targetStateHolder)
}
return "(" + strings.Join(clauses, " OR ") + ") AND " + validMemo + " AND " + validState
}