Verified contributors (#474)
* `isContributor`, `hideIsContributor` user fields and basic UI decoration on profile page * Update verified contributor decoration on profile page * Add contributors instructions * update setting label * Remove `isContributor` from DB, load contributors from file into memory * fix merge error --------- Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
parent
8ab58fff87
commit
bc2363dfab
|
@ -1,3 +1,5 @@
|
|||
import { readFile } from 'fs/promises'
|
||||
import { join, resolve } from 'path'
|
||||
import { GraphQLError } from 'graphql'
|
||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
||||
import { msatsToSats } from '../../lib/format'
|
||||
|
@ -5,6 +7,20 @@ import { bioSchema, emailSchema, settingsSchema, ssValidate, userSchema } from '
|
|||
import { getItem, updateItem, filterClause, createItem } from './item'
|
||||
import { datePivot } from '../../lib/time'
|
||||
|
||||
const contributors = new Set()
|
||||
|
||||
const loadContributors = async (set) => {
|
||||
try {
|
||||
const fileContent = await readFile(resolve(join(process.cwd(), 'contributors.txt')), 'utf-8')
|
||||
fileContent.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => !!line)
|
||||
.forEach(name => set.add(name))
|
||||
} catch (err) {
|
||||
console.error('Error loading contributors', err)
|
||||
}
|
||||
}
|
||||
|
||||
export function within (table, within) {
|
||||
let interval = ' AND "' + table + '".created_at >= $1 - INTERVAL '
|
||||
switch (within) {
|
||||
|
@ -817,6 +833,16 @@ export default {
|
|||
})
|
||||
|
||||
return !!subscription?.commentsSubscribedAt
|
||||
},
|
||||
isContributor: async (user, args, { me }) => {
|
||||
// lazy init contributors only once
|
||||
if (contributors.size === 0) {
|
||||
await loadContributors(contributors)
|
||||
}
|
||||
if (me?.id === user.id) {
|
||||
return contributors.has(user.name)
|
||||
}
|
||||
return !user.hideIsContributor && contributors.has(user.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ export default gql`
|
|||
noteInvites: Boolean!, noteJobIndicator: Boolean!, noteCowboyHat: Boolean!, hideInvoiceDesc: Boolean!,
|
||||
hideFromTopUsers: Boolean!, hideCowboyHat: Boolean!, clickToLoadImg: Boolean!,
|
||||
wildWestMode: Boolean!, greeterMode: Boolean!, nostrPubkey: String, nostrRelays: [String!], hideBookmarks: Boolean!,
|
||||
noteForwardedSats: Boolean!, hideWalletBalance: Boolean!): User
|
||||
noteForwardedSats: Boolean!, hideWalletBalance: Boolean!, hideIsContributor: Boolean!): User
|
||||
setPhoto(photoId: ID!): Int!
|
||||
upsertBio(bio: String!): User!
|
||||
setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean
|
||||
|
@ -92,6 +92,8 @@ export default gql`
|
|||
greeterMode: Boolean!
|
||||
lastCheckedJobs: String
|
||||
authMethods: AuthMethods!
|
||||
isContributor: Boolean!
|
||||
hideIsContributor: Boolean!
|
||||
meSubscriptionPosts: Boolean!
|
||||
meSubscriptionComments: Boolean!
|
||||
}
|
||||
|
|
|
@ -212,6 +212,7 @@ function HeaderHeader ({ user }) {
|
|||
: <span>never</span>}
|
||||
</small>
|
||||
<small className='text-muted d-flex-inline'>longest cowboy streak: {user.maxStreak !== null ? user.maxStreak : 'none'}</small>
|
||||
{user.isContributor && <small className='text-muted'>🧑💻✅ verified stacker.news contributor</small>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
k00b
|
||||
kr
|
||||
ekzyis
|
||||
WeAreAllSatoshi
|
|
@ -36,6 +36,8 @@ export const ME = gql`
|
|||
lastCheckedJobs
|
||||
hideWelcomeBanner
|
||||
hideWalletBalance
|
||||
isContributor
|
||||
hideIsContributor
|
||||
}
|
||||
}`
|
||||
|
||||
|
@ -57,6 +59,7 @@ export const SETTINGS_FIELDS = gql`
|
|||
hideFromTopUsers
|
||||
hideCowboyHat
|
||||
hideBookmarks
|
||||
hideIsContributor
|
||||
clickToLoadImg
|
||||
hideWalletBalance
|
||||
nostrPubkey
|
||||
|
@ -88,14 +91,14 @@ mutation setSettings($tipDefault: Int!, $turboTipping: Boolean!, $fiatCurrency:
|
|||
$noteInvites: Boolean!, $noteJobIndicator: Boolean!, $noteCowboyHat: Boolean!, $hideInvoiceDesc: Boolean!,
|
||||
$hideFromTopUsers: Boolean!, $hideCowboyHat: Boolean!, $clickToLoadImg: Boolean!,
|
||||
$wildWestMode: Boolean!, $greeterMode: Boolean!, $nostrPubkey: String, $nostrRelays: [String!], $hideBookmarks: Boolean!,
|
||||
$noteForwardedSats: Boolean!, $hideWalletBalance: Boolean!) {
|
||||
$noteForwardedSats: Boolean!, $hideWalletBalance: Boolean!, $hideIsContributor: Boolean!) {
|
||||
setSettings(tipDefault: $tipDefault, turboTipping: $turboTipping, fiatCurrency: $fiatCurrency,
|
||||
noteItemSats: $noteItemSats, noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants,
|
||||
noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites,
|
||||
noteJobIndicator: $noteJobIndicator, noteCowboyHat: $noteCowboyHat, hideInvoiceDesc: $hideInvoiceDesc,
|
||||
hideFromTopUsers: $hideFromTopUsers, hideCowboyHat: $hideCowboyHat, clickToLoadImg: $clickToLoadImg,
|
||||
wildWestMode: $wildWestMode, greeterMode: $greeterMode, nostrPubkey: $nostrPubkey, nostrRelays: $nostrRelays, hideBookmarks: $hideBookmarks,
|
||||
noteForwardedSats: $noteForwardedSats, hideWalletBalance: $hideWalletBalance) {
|
||||
noteForwardedSats: $noteForwardedSats, hideWalletBalance: $hideWalletBalance, hideIsContributor: $hideIsContributor) {
|
||||
...SettingsFields
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +153,7 @@ export const USER_FIELDS = gql`
|
|||
stacked
|
||||
since
|
||||
photoId
|
||||
isContributor
|
||||
meSubscriptionPosts
|
||||
meSubscriptionComments
|
||||
}`
|
||||
|
|
|
@ -224,7 +224,8 @@ export const settingsSchema = object({
|
|||
).max(NOSTR_MAX_RELAY_NUM,
|
||||
({ max, value }) => `${Math.abs(max - value.length)} too many`),
|
||||
hideBookmarks: boolean(),
|
||||
hideWalletBalance: boolean()
|
||||
hideWalletBalance: boolean(),
|
||||
hideIsContributor: boolean()
|
||||
})
|
||||
|
||||
const warningMessage = 'If I logout, even accidentally, I will never be able to access my account again'
|
||||
|
|
|
@ -23,6 +23,7 @@ import { useShowModal } from '../components/modal'
|
|||
import { authErrorMessage } from '../components/login'
|
||||
import { NostrAuth } from '../components/nostr-auth'
|
||||
import { useToast } from '../components/toast'
|
||||
import { useMe } from '../components/me'
|
||||
|
||||
export const getServerSideProps = getGetServerSideProps({ query: SETTINGS, authRequired: true })
|
||||
|
||||
|
@ -32,6 +33,7 @@ function bech32encode (hexString) {
|
|||
|
||||
export default function Settings ({ ssrData }) {
|
||||
const toaster = useToast()
|
||||
const me = useMe()
|
||||
const [setSettings] = useMutation(SET_SETTINGS, {
|
||||
update (cache, { data: { setSettings } }) {
|
||||
cache.modify({
|
||||
|
@ -77,7 +79,8 @@ export default function Settings ({ ssrData }) {
|
|||
nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '',
|
||||
nostrRelays: settings?.nostrRelays?.length ? settings?.nostrRelays : [''],
|
||||
hideBookmarks: settings?.hideBookmarks,
|
||||
hideWalletBalance: settings?.hideWalletBalance
|
||||
hideWalletBalance: settings?.hideWalletBalance,
|
||||
hideIsContributor: settings?.hideIsContributor
|
||||
}}
|
||||
schema={settingsSchema}
|
||||
onSubmit={async ({ tipDefault, nostrPubkey, nostrRelays, ...values }) => {
|
||||
|
@ -241,6 +244,12 @@ export default function Settings ({ ssrData }) {
|
|||
name='clickToLoadImg'
|
||||
groupClassName='mb-0'
|
||||
/>
|
||||
{me.isContributor &&
|
||||
<Checkbox
|
||||
label={<>hide that I'm a stacker.news contributor</>}
|
||||
name='hideIsContributor'
|
||||
groupClassName='mb-0'
|
||||
/>}
|
||||
<Checkbox
|
||||
label={<>hide my bookmarks from other stackers</>}
|
||||
name='hideBookmarks'
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "users" ADD COLUMN "hideIsContributor" BOOLEAN NOT NULL DEFAULT false;
|
|
@ -90,6 +90,7 @@ model User {
|
|||
followers UserSubscription[] @relation("follower")
|
||||
followees UserSubscription[] @relation("followee")
|
||||
hideWelcomeBanner Boolean @default(false)
|
||||
hideIsContributor Boolean @default(false)
|
||||
|
||||
@@index([createdAt], map: "users.created_at_index")
|
||||
@@index([inviteId], map: "users.inviteId_index")
|
||||
|
|
Loading…
Reference in New Issue