Add new user setting to hide bookmarks from other users (and anon) (#424)

* Add new setting to hide bookmarks from other users (and anon)

* Optional chaining in case user doesnt exist, and avoid duplicate sql query in some cases
This commit is contained in:
SatsAllDay 2023-08-23 16:29:55 -04:00 committed by GitHub
parent 427fc9aeec
commit ee3f892053
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 35 additions and 7 deletions

View File

@ -314,6 +314,21 @@ export default {
const decodedCursor = decodeCursor(cursor) const decodedCursor = decodeCursor(cursor)
let items, user, pins, subFull, table let items, user, pins, subFull, table
// special authorization for bookmarks depending on owning users' privacy settings
if (type === 'bookmarks' && name && me?.name !== name) {
// the calling user is either not logged in, or not the user upon which the query is made,
// so we need to check authz
user = await models.user.findUnique({ where: { name } })
if (user?.hideBookmarks) {
// early return with no results if bookmarks are hidden
return {
cursor: null,
items: [],
pins: []
}
}
}
// HACK we want to optionally include the subName in the query // HACK we want to optionally include the subName in the query
// but the query planner doesn't like unused parameters // but the query planner doesn't like unused parameters
const subArr = sub ? [sub] : [] const subArr = sub ? [sub] : []
@ -324,7 +339,7 @@ export default {
throw new GraphQLError('must supply name', { extensions: { code: 'BAD_INPUT' } }) throw new GraphQLError('must supply name', { extensions: { code: 'BAD_INPUT' } })
} }
user = await models.user.findUnique({ where: { name } }) user ??= await models.user.findUnique({ where: { name } })
if (!user) { if (!user) {
throw new GraphQLError('no user has that name', { extensions: { code: 'BAD_INPUT' } }) throw new GraphQLError('no user has that name', { extensions: { code: 'BAD_INPUT' } })
} }

View File

@ -24,7 +24,7 @@ export default gql`
noteEarning: Boolean!, noteAllDescendants: Boolean!, noteMentions: Boolean!, noteDeposits: Boolean!, noteEarning: Boolean!, noteAllDescendants: Boolean!, noteMentions: Boolean!, noteDeposits: Boolean!,
noteInvites: Boolean!, noteJobIndicator: Boolean!, noteCowboyHat: Boolean!, hideInvoiceDesc: Boolean!, noteInvites: Boolean!, noteJobIndicator: Boolean!, noteCowboyHat: Boolean!, hideInvoiceDesc: Boolean!,
hideFromTopUsers: Boolean!, hideCowboyHat: Boolean!, clickToLoadImg: Boolean!, hideFromTopUsers: Boolean!, hideCowboyHat: Boolean!, clickToLoadImg: Boolean!,
wildWestMode: Boolean!, greeterMode: Boolean!, nostrPubkey: String, nostrRelays: [String!]): User wildWestMode: Boolean!, greeterMode: Boolean!, nostrPubkey: String, nostrRelays: [String!], hideBookmarks: Boolean!): User
setPhoto(photoId: ID!): Int! setPhoto(photoId: ID!): Int!
upsertBio(bio: String!): User! upsertBio(bio: String!): User!
setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean
@ -79,6 +79,7 @@ export default gql`
hideInvoiceDesc: Boolean! hideInvoiceDesc: Boolean!
hideFromTopUsers: Boolean! hideFromTopUsers: Boolean!
hideCowboyHat: Boolean! hideCowboyHat: Boolean!
hideBookmarks: Boolean!
clickToLoadImg: Boolean! clickToLoadImg: Boolean!
wildWestMode: Boolean! wildWestMode: Boolean!
greeterMode: Boolean! greeterMode: Boolean!

View File

@ -52,6 +52,7 @@ export const SETTINGS_FIELDS = gql`
hideInvoiceDesc hideInvoiceDesc
hideFromTopUsers hideFromTopUsers
hideCowboyHat hideCowboyHat
hideBookmarks
clickToLoadImg clickToLoadImg
nostrPubkey nostrPubkey
nostrRelays nostrRelays
@ -81,13 +82,13 @@ mutation setSettings($tipDefault: Int!, $turboTipping: Boolean!, $fiatCurrency:
$noteEarning: Boolean!, $noteAllDescendants: Boolean!, $noteMentions: Boolean!, $noteDeposits: Boolean!, $noteEarning: Boolean!, $noteAllDescendants: Boolean!, $noteMentions: Boolean!, $noteDeposits: Boolean!,
$noteInvites: Boolean!, $noteJobIndicator: Boolean!, $noteCowboyHat: Boolean!, $hideInvoiceDesc: Boolean!, $noteInvites: Boolean!, $noteJobIndicator: Boolean!, $noteCowboyHat: Boolean!, $hideInvoiceDesc: Boolean!,
$hideFromTopUsers: Boolean!, $hideCowboyHat: Boolean!, $clickToLoadImg: Boolean!, $hideFromTopUsers: Boolean!, $hideCowboyHat: Boolean!, $clickToLoadImg: Boolean!,
$wildWestMode: Boolean!, $greeterMode: Boolean!, $nostrPubkey: String, $nostrRelays: [String!]) { $wildWestMode: Boolean!, $greeterMode: Boolean!, $nostrPubkey: String, $nostrRelays: [String!], $hideBookmarks: Boolean!) {
setSettings(tipDefault: $tipDefault, turboTipping: $turboTipping, fiatCurrency: $fiatCurrency, setSettings(tipDefault: $tipDefault, turboTipping: $turboTipping, fiatCurrency: $fiatCurrency,
noteItemSats: $noteItemSats, noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants, noteItemSats: $noteItemSats, noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants,
noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites, noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites,
noteJobIndicator: $noteJobIndicator, noteCowboyHat: $noteCowboyHat, hideInvoiceDesc: $hideInvoiceDesc, noteJobIndicator: $noteJobIndicator, noteCowboyHat: $noteCowboyHat, hideInvoiceDesc: $hideInvoiceDesc,
hideFromTopUsers: $hideFromTopUsers, hideCowboyHat: $hideCowboyHat, clickToLoadImg: $clickToLoadImg, hideFromTopUsers: $hideFromTopUsers, hideCowboyHat: $hideCowboyHat, clickToLoadImg: $clickToLoadImg,
wildWestMode: $wildWestMode, greeterMode: $greeterMode, nostrPubkey: $nostrPubkey, nostrRelays: $nostrRelays) { wildWestMode: $wildWestMode, greeterMode: $greeterMode, nostrPubkey: $nostrPubkey, nostrRelays: $nostrRelays, hideBookmarks: $hideBookmarks) {
...SettingsFields ...SettingsFields
} }
} }

View File

@ -1,4 +1,4 @@
import { string, ValidationError, number, object, array, addMethod } from 'yup' import { string, ValidationError, number, object, array, addMethod, boolean } from 'yup'
import { BOOST_MIN, MAX_POLL_CHOICE_LENGTH, MAX_TITLE_LENGTH, MAX_POLL_NUM_CHOICES, MIN_POLL_NUM_CHOICES, SUBS_NO_JOBS } from './constants' import { BOOST_MIN, MAX_POLL_CHOICE_LENGTH, MAX_TITLE_LENGTH, MAX_POLL_NUM_CHOICES, MIN_POLL_NUM_CHOICES, SUBS_NO_JOBS } from './constants'
import { NAME_QUERY } from '../fragments/users' import { NAME_QUERY } from '../fragments/users'
import { URL_REGEXP, WS_REGEXP } from './url' import { URL_REGEXP, WS_REGEXP } from './url'
@ -203,7 +203,8 @@ export const settingsSchema = object({
nostrRelays: array().of( nostrRelays: array().of(
string().matches(WS_REGEXP, 'invalid web socket address') string().matches(WS_REGEXP, 'invalid web socket address')
).max(NOSTR_MAX_RELAY_NUM, ).max(NOSTR_MAX_RELAY_NUM,
({ max, value }) => `${Math.abs(max - value.length)} too many`) ({ max, value }) => `${Math.abs(max - value.length)} too many`),
hideBookmarks: boolean()
}) })
const warningMessage = 'If I logout, even accidentally, I will never be able to access my account again' const warningMessage = 'If I logout, even accidentally, I will never be able to access my account again'

View File

@ -73,7 +73,8 @@ export default function Settings ({ ssrData }) {
wildWestMode: settings?.wildWestMode, wildWestMode: settings?.wildWestMode,
greeterMode: settings?.greeterMode, greeterMode: settings?.greeterMode,
nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '', nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '',
nostrRelays: settings?.nostrRelays?.length ? settings?.nostrRelays : [''] nostrRelays: settings?.nostrRelays?.length ? settings?.nostrRelays : [''],
hideBookmarks: settings?.hideBookmarks
}} }}
schema={settingsSchema} schema={settingsSchema}
onSubmit={async ({ tipDefault, nostrPubkey, nostrRelays, ...values }) => { onSubmit={async ({ tipDefault, nostrPubkey, nostrRelays, ...values }) => {
@ -221,6 +222,11 @@ export default function Settings ({ ssrData }) {
<Checkbox <Checkbox
label={<>click to load external images</>} label={<>click to load external images</>}
name='clickToLoadImg' name='clickToLoadImg'
groupClassName='mb-0'
/>
<Checkbox
label={<>hide my bookmarks from other stackers</>}
name='hideBookmarks'
/> />
<div className='form-label'>content</div> <div className='form-label'>content</div>
<Checkbox <Checkbox

View File

@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "users" ADD COLUMN "hideBookmarks" BOOLEAN NOT NULL DEFAULT false;

View File

@ -84,6 +84,7 @@ model User {
referrees User[] @relation("referrals") referrees User[] @relation("referrals")
Account Account[] Account Account[]
Session Session[] Session Session[]
hideBookmarks Boolean @default(false)
@@index([createdAt], map: "users.created_at_index") @@index([createdAt], map: "users.created_at_index")
@@index([inviteId], map: "users.inviteId_index") @@index([inviteId], map: "users.inviteId_index")