Add nsfw setting to territories (#788)
* add nsfw column to sub * add nsfw boolean to territorySchema * save nsfw value in upsertSub mutation * return nsfw value from Sub query for correct value in edit territory form * add nsfw checkbox to territory form * add nsfw badge to territory header * add nsfwMode to user * show nsfw badge next to item territory * exclude nsfw sub from items query * show nsfw mode checkbox on settings page * fix nsfw badge formatting * separate user from current, signed in user * update relationClause to join with sub table * refactor to simplify hide nsfw sql * filter nsfw items when viewing user items * hide nsfw posts for logged out users * filter nsfw subs based on user preference * show nsfw sub name if logged out user is viewing the page * show current sub at the top of the list instead of bottom * always join item with sub to check nsfw * check for sub presence before showing nsfw badge on item * skip manually adding sub to select if sub is null * fix relationClause to join with root item * move moderation and nsfw into accordion --------- Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
parent
b3d485e8c4
commit
6355d7eabc
@ -152,19 +152,19 @@ const relationClause = (type) => {
|
|||||||
let clause = ''
|
let clause = ''
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'comments':
|
case 'comments':
|
||||||
clause += ' FROM "Item" JOIN "Item" root ON "Item"."rootId" = root.id '
|
clause += ' FROM "Item" JOIN "Item" root ON "Item"."rootId" = root.id LEFT JOIN "Sub" ON "Sub"."name" = root."subName" '
|
||||||
break
|
break
|
||||||
case 'bookmarks':
|
case 'bookmarks':
|
||||||
clause += ' FROM "Item" JOIN "Bookmark" ON "Bookmark"."itemId" = "Item"."id" '
|
clause += ' FROM "Item" JOIN "Bookmark" ON "Bookmark"."itemId" = "Item"."id" LEFT JOIN "Sub" ON "Sub"."name" = "Item"."subName" '
|
||||||
break
|
break
|
||||||
case 'outlawed':
|
case 'outlawed':
|
||||||
case 'borderland':
|
case 'borderland':
|
||||||
case 'freebies':
|
case 'freebies':
|
||||||
case 'all':
|
case 'all':
|
||||||
clause += ' FROM "Item" LEFT JOIN "Item" root ON "Item"."rootId" = root.id '
|
clause += ' FROM "Item" LEFT JOIN "Item" root ON "Item"."rootId" = root.id LEFT JOIN "Sub" ON "Sub"."name" = root."subName" '
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
clause += ' FROM "Item" '
|
clause += ' FROM "Item" LEFT JOIN "Sub" ON "Sub"."name" = "Item"."subName" '
|
||||||
}
|
}
|
||||||
|
|
||||||
return clause
|
return clause
|
||||||
@ -192,12 +192,20 @@ const activeOrMine = (me) => {
|
|||||||
export const muteClause = me =>
|
export const muteClause = me =>
|
||||||
me ? `NOT EXISTS (SELECT 1 FROM "Mute" WHERE "Mute"."muterId" = ${me.id} AND "Mute"."mutedId" = "Item"."userId")` : ''
|
me ? `NOT EXISTS (SELECT 1 FROM "Mute" WHERE "Mute"."muterId" = ${me.id} AND "Mute"."mutedId" = "Item"."userId")` : ''
|
||||||
|
|
||||||
const subClause = (sub, num, table, me) => {
|
const HIDE_NSFW_CLAUSE = '"Sub"."nsfw" = FALSE'
|
||||||
return sub
|
|
||||||
? `${table ? `"${table}".` : ''}"subName" = $${num}::CITEXT`
|
export const nsfwClause = showNsfw => showNsfw ? '' : HIDE_NSFW_CLAUSE
|
||||||
: me
|
|
||||||
? `NOT EXISTS (SELECT 1 FROM "MuteSub" WHERE "MuteSub"."userId" = ${me.id} AND "MuteSub"."subName" = ${table ? `"${table}".` : ''}"subName")`
|
const subClause = (sub, num, table, me, showNsfw) => {
|
||||||
: ''
|
// Intentionally show nsfw posts (i.e. no nsfw clause) when viewing a specific nsfw sub
|
||||||
|
if (sub) { return `${table ? `"${table}".` : ''}"subName" = $${num}::CITEXT` }
|
||||||
|
|
||||||
|
if (!me) { return HIDE_NSFW_CLAUSE }
|
||||||
|
|
||||||
|
const excludeMuted = `NOT EXISTS (SELECT 1 FROM "MuteSub" WHERE "MuteSub"."userId" = ${me.id} AND "MuteSub"."subName" = ${table ? `"${table}".` : ''}"subName")`
|
||||||
|
if (showNsfw) return excludeMuted
|
||||||
|
|
||||||
|
return excludeMuted + ' AND ' + HIDE_NSFW_CLAUSE
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function filterClause (me, models, type) {
|
export async function filterClause (me, models, type) {
|
||||||
@ -307,6 +315,9 @@ export default {
|
|||||||
// 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] : []
|
||||||
|
|
||||||
|
const currentUser = me ? await models.user.findUnique({ where: { id: me.id } }) : null
|
||||||
|
const showNsfw = currentUser ? currentUser.nsfwMode : false
|
||||||
|
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case 'user':
|
case 'user':
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@ -329,6 +340,7 @@ export default {
|
|||||||
`"${table}"."userId" = $3`,
|
`"${table}"."userId" = $3`,
|
||||||
activeOrMine(me),
|
activeOrMine(me),
|
||||||
await filterClause(me, models, type),
|
await filterClause(me, models, type),
|
||||||
|
nsfwClause(showNsfw),
|
||||||
typeClause(type),
|
typeClause(type),
|
||||||
whenClause(when || 'forever', table))}
|
whenClause(when || 'forever', table))}
|
||||||
${orderByClause(by, me, models, type)}
|
${orderByClause(by, me, models, type)}
|
||||||
@ -346,7 +358,7 @@ export default {
|
|||||||
${relationClause(type)}
|
${relationClause(type)}
|
||||||
${whereClause(
|
${whereClause(
|
||||||
'"Item".created_at <= $1',
|
'"Item".created_at <= $1',
|
||||||
subClause(sub, 4, subClauseTable(type), me),
|
subClause(sub, 4, subClauseTable(type), me, showNsfw),
|
||||||
activeOrMine(me),
|
activeOrMine(me),
|
||||||
await filterClause(me, models, type),
|
await filterClause(me, models, type),
|
||||||
typeClause(type),
|
typeClause(type),
|
||||||
@ -370,7 +382,7 @@ export default {
|
|||||||
${joinZapRankPersonalView(me, models)}
|
${joinZapRankPersonalView(me, models)}
|
||||||
${whereClause(
|
${whereClause(
|
||||||
'"Item"."deletedAt" IS NULL',
|
'"Item"."deletedAt" IS NULL',
|
||||||
subClause(sub, 5, subClauseTable(type), me),
|
subClause(sub, 5, subClauseTable(type), me, showNsfw),
|
||||||
typeClause(type),
|
typeClause(type),
|
||||||
whenClause(when, 'Item'),
|
whenClause(when, 'Item'),
|
||||||
await filterClause(me, models, type),
|
await filterClause(me, models, type),
|
||||||
@ -389,7 +401,7 @@ export default {
|
|||||||
${relationClause(type)}
|
${relationClause(type)}
|
||||||
${whereClause(
|
${whereClause(
|
||||||
'"Item"."deletedAt" IS NULL',
|
'"Item"."deletedAt" IS NULL',
|
||||||
subClause(sub, 5, subClauseTable(type), me),
|
subClause(sub, 5, subClauseTable(type), me, showNsfw),
|
||||||
typeClause(type),
|
typeClause(type),
|
||||||
whenClause(when, 'Item'),
|
whenClause(when, 'Item'),
|
||||||
await filterClause(me, models, type),
|
await filterClause(me, models, type),
|
||||||
@ -440,13 +452,14 @@ export default {
|
|||||||
query: `
|
query: `
|
||||||
${SELECT}, ${me ? 'GREATEST(g.tf_hot_score, l.tf_hot_score)' : 'g.tf_hot_score'} AS rank
|
${SELECT}, ${me ? 'GREATEST(g.tf_hot_score, l.tf_hot_score)' : 'g.tf_hot_score'} AS rank
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
|
LEFT JOIN "Sub" ON "Sub"."name" = "Item"."subName"
|
||||||
${joinZapRankPersonalView(me, models)}
|
${joinZapRankPersonalView(me, models)}
|
||||||
${whereClause(
|
${whereClause(
|
||||||
'"Item"."pinId" IS NULL',
|
'"Item"."pinId" IS NULL',
|
||||||
'"Item"."deletedAt" IS NULL',
|
'"Item"."deletedAt" IS NULL',
|
||||||
'"Item"."parentId" IS NULL',
|
'"Item"."parentId" IS NULL',
|
||||||
'"Item".bio = false',
|
'"Item".bio = false',
|
||||||
subClause(sub, 3, 'Item', me),
|
subClause(sub, 3, 'Item', me, showNsfw),
|
||||||
muteClause(me))}
|
muteClause(me))}
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
OFFSET $1
|
OFFSET $1
|
||||||
@ -462,8 +475,9 @@ export default {
|
|||||||
query: `
|
query: `
|
||||||
${SELECT}
|
${SELECT}
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
|
LEFT JOIN "Sub" ON "Sub"."name" = "Item"."subName"
|
||||||
${whereClause(
|
${whereClause(
|
||||||
subClause(sub, 3, 'Item', me),
|
subClause(sub, 3, 'Item', me, showNsfw),
|
||||||
muteClause(me),
|
muteClause(me),
|
||||||
// in "home" (sub undefined), we want to show pinned items (but without the pin icon)
|
// in "home" (sub undefined), we want to show pinned items (but without the pin icon)
|
||||||
sub ? '"Item"."pinId" IS NULL' : '',
|
sub ? '"Item"."pinId" IS NULL' : '',
|
||||||
|
@ -84,21 +84,24 @@ export default {
|
|||||||
sub: getSub,
|
sub: getSub,
|
||||||
subs: async (parent, args, { models, me }) => {
|
subs: async (parent, args, { models, me }) => {
|
||||||
if (me) {
|
if (me) {
|
||||||
return await models.$queryRaw`
|
const currentUser = await models.user.findUnique({ where: { id: me.id } })
|
||||||
|
const showNsfw = currentUser ? currentUser.nsfwMode : false
|
||||||
|
return await models.$queryRawUnsafe(`
|
||||||
SELECT "Sub".*, COALESCE(json_agg("MuteSub".*) FILTER (WHERE "MuteSub"."userId" IS NOT NULL), '[]') AS "MuteSub"
|
SELECT "Sub".*, COALESCE(json_agg("MuteSub".*) FILTER (WHERE "MuteSub"."userId" IS NOT NULL), '[]') AS "MuteSub"
|
||||||
FROM "Sub"
|
FROM "Sub"
|
||||||
LEFT JOIN "MuteSub" ON "Sub".name = "MuteSub"."subName" AND "MuteSub"."userId" = ${me.id}::INTEGER
|
LEFT JOIN "MuteSub" ON "Sub".name = "MuteSub"."subName" AND "MuteSub"."userId" = ${me.id}::INTEGER
|
||||||
WHERE status <> 'STOPPED'
|
WHERE status <> 'STOPPED' ${showNsfw ? '' : 'AND "Sub"."nsfw" = FALSE'}
|
||||||
GROUP BY "Sub".name, "MuteSub"."userId"
|
GROUP BY "Sub".name, "MuteSub"."userId"
|
||||||
ORDER BY "Sub".name ASC
|
ORDER BY "Sub".name ASC
|
||||||
`
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return await models.sub.findMany({
|
return await models.sub.findMany({
|
||||||
where: {
|
where: {
|
||||||
status: {
|
status: {
|
||||||
not: 'STOPPED'
|
not: 'STOPPED'
|
||||||
}
|
},
|
||||||
|
nsfw: false
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy: {
|
||||||
name: 'asc'
|
name: 'asc'
|
||||||
@ -193,7 +196,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function createSub (parent, data, { me, models, lnd, hash, hmac }) {
|
async function createSub (parent, data, { me, models, lnd, hash, hmac }) {
|
||||||
const { billingType } = data
|
const { billingType, nsfw } = data
|
||||||
let billingCost = TERRITORY_COST_MONTHLY
|
let billingCost = TERRITORY_COST_MONTHLY
|
||||||
let billAt = datePivot(new Date(), { months: 1 })
|
let billAt = datePivot(new Date(), { months: 1 })
|
||||||
|
|
||||||
@ -226,7 +229,8 @@ async function createSub (parent, data, { me, models, lnd, hash, hmac }) {
|
|||||||
...data,
|
...data,
|
||||||
billingCost,
|
billingCost,
|
||||||
rankingType: 'WOT',
|
rankingType: 'WOT',
|
||||||
userId: me.id
|
userId: me.id,
|
||||||
|
nsfw
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
// record 'em
|
// record 'em
|
||||||
|
@ -11,7 +11,7 @@ export default gql`
|
|||||||
upsertSub(oldName: String, name: String!, desc: String, baseCost: Int!,
|
upsertSub(oldName: String, name: String!, desc: String, baseCost: Int!,
|
||||||
postTypes: [String!]!, allowFreebies: Boolean!,
|
postTypes: [String!]!, allowFreebies: Boolean!,
|
||||||
billingType: String!, billingAutoRenew: Boolean!,
|
billingType: String!, billingAutoRenew: Boolean!,
|
||||||
moderated: Boolean!, hash: String, hmac: String): Sub
|
moderated: Boolean!, hash: String, hmac: String, nsfw: Boolean!): Sub
|
||||||
paySub(name: String!, hash: String, hmac: String): Sub
|
paySub(name: String!, hash: String, hmac: String): Sub
|
||||||
toggleMuteSub(name: String!): Boolean!
|
toggleMuteSub(name: String!): Boolean!
|
||||||
}
|
}
|
||||||
@ -35,5 +35,6 @@ export default gql`
|
|||||||
moderated: Boolean!
|
moderated: Boolean!
|
||||||
moderatedCount: Int!
|
moderatedCount: Int!
|
||||||
meMuteSub: Boolean!
|
meMuteSub: Boolean!
|
||||||
|
nsfw: Boolean!
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -80,6 +80,7 @@ export default gql`
|
|||||||
noteItemSats: Boolean!
|
noteItemSats: Boolean!
|
||||||
noteJobIndicator: Boolean!
|
noteJobIndicator: Boolean!
|
||||||
noteMentions: Boolean!
|
noteMentions: Boolean!
|
||||||
|
nsfwMode: Boolean!
|
||||||
tipDefault: Int!
|
tipDefault: Int!
|
||||||
turboTipping: Boolean!
|
turboTipping: Boolean!
|
||||||
wildWestMode: Boolean!
|
wildWestMode: Boolean!
|
||||||
@ -138,6 +139,7 @@ export default gql`
|
|||||||
noteItemSats: Boolean!
|
noteItemSats: Boolean!
|
||||||
noteJobIndicator: Boolean!
|
noteJobIndicator: Boolean!
|
||||||
noteMentions: Boolean!
|
noteMentions: Boolean!
|
||||||
|
nsfwMode: Boolean!
|
||||||
tipDefault: Int!
|
tipDefault: Int!
|
||||||
turboTipping: Boolean!
|
turboTipping: Boolean!
|
||||||
wildWestMode: Boolean!
|
wildWestMode: Boolean!
|
||||||
|
@ -122,6 +122,8 @@ export default function ItemInfo ({
|
|||||||
<Link href={`/~${item.subName}`}>
|
<Link href={`/~${item.subName}`}>
|
||||||
{' '}<Badge className={styles.newComment} bg={null}>{item.subName}</Badge>
|
{' '}<Badge className={styles.newComment} bg={null}>{item.subName}</Badge>
|
||||||
</Link>}
|
</Link>}
|
||||||
|
{sub?.nsfw &&
|
||||||
|
<Badge className={styles.newComment} bg={null}>nsfw</Badge>}
|
||||||
{(item.outlawed && !item.mine &&
|
{(item.outlawed && !item.mine &&
|
||||||
<Link href='/recent/outlawed'>
|
<Link href='/recent/outlawed'>
|
||||||
{' '}<Badge className={styles.newComment} bg={null}>outlawed</Badge>
|
{' '}<Badge className={styles.newComment} bg={null}>outlawed</Badge>
|
||||||
|
@ -53,6 +53,10 @@ export default function SubSelect ({ prependSubs, sub, onChange, large, appendSu
|
|||||||
overrideValue: sub
|
overrideValue: sub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If logged out user directly visits a nsfw sub, subs will not contain `sub`, so manually add it
|
||||||
|
// to display the correct sub name in the sub selector
|
||||||
|
const subItems = !sub || subs.find((s) => s === sub) ? subs : [sub].concat(subs)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
onChange={onChange || ((_, e) => {
|
onChange={onChange || ((_, e) => {
|
||||||
@ -102,7 +106,7 @@ export default function SubSelect ({ prependSubs, sub, onChange, large, appendSu
|
|||||||
{...valueProps}
|
{...valueProps}
|
||||||
{...props}
|
{...props}
|
||||||
className={`${className} ${styles.subSelect} ${large ? 'me-2' : styles.subSelectSmall}`}
|
className={`${className} ${styles.subSelect} ${large ? 'me-2' : styles.subSelectSmall}`}
|
||||||
items={subs}
|
items={subItems}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import AccordianItem from './accordian-item'
|
||||||
import { Col, InputGroup, Row, Form as BootstrapForm, Badge } from 'react-bootstrap'
|
import { Col, InputGroup, Row, Form as BootstrapForm, Badge } from 'react-bootstrap'
|
||||||
import { Checkbox, CheckboxGroup, Form, Input, MarkdownInput } from './form'
|
import { Checkbox, CheckboxGroup, Form, Input, MarkdownInput } from './form'
|
||||||
import FeeButton, { FeeButtonProvider } from './fee-button'
|
import FeeButton, { FeeButtonProvider } from './fee-button'
|
||||||
@ -17,10 +18,10 @@ export default function TerritoryForm ({ sub }) {
|
|||||||
gql`
|
gql`
|
||||||
mutation upsertSub($oldName: String, $name: String!, $desc: String, $baseCost: Int!,
|
mutation upsertSub($oldName: String, $name: String!, $desc: String, $baseCost: Int!,
|
||||||
$postTypes: [String!]!, $allowFreebies: Boolean!, $billingType: String!,
|
$postTypes: [String!]!, $allowFreebies: Boolean!, $billingType: String!,
|
||||||
$billingAutoRenew: Boolean!, $moderated: Boolean!, $hash: String, $hmac: String) {
|
$billingAutoRenew: Boolean!, $moderated: Boolean!, $hash: String, $hmac: String, $nsfw: Boolean!) {
|
||||||
upsertSub(oldName: $oldName, name: $name, desc: $desc, baseCost: $baseCost,
|
upsertSub(oldName: $oldName, name: $name, desc: $desc, baseCost: $baseCost,
|
||||||
postTypes: $postTypes, allowFreebies: $allowFreebies, billingType: $billingType,
|
postTypes: $postTypes, allowFreebies: $allowFreebies, billingType: $billingType,
|
||||||
billingAutoRenew: $billingAutoRenew, moderated: $moderated, hash: $hash, hmac: $hmac) {
|
billingAutoRenew: $billingAutoRenew, moderated: $moderated, hash: $hash, hmac: $hmac, nsfw: $nsfw) {
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
@ -65,7 +66,8 @@ export default function TerritoryForm ({ sub }) {
|
|||||||
allowFreebies: typeof sub?.allowFreebies === 'undefined' ? true : sub?.allowFreebies,
|
allowFreebies: typeof sub?.allowFreebies === 'undefined' ? true : sub?.allowFreebies,
|
||||||
billingType: sub?.billingType || 'MONTHLY',
|
billingType: sub?.billingType || 'MONTHLY',
|
||||||
billingAutoRenew: sub?.billingAutoRenew || false,
|
billingAutoRenew: sub?.billingAutoRenew || false,
|
||||||
moderated: sub?.moderated || false
|
moderated: sub?.moderated || false,
|
||||||
|
nsfw: sub?.nsfw || false
|
||||||
}}
|
}}
|
||||||
schema={territorySchema({ client, me })}
|
schema={territorySchema({ client, me })}
|
||||||
invoiceable
|
invoiceable
|
||||||
@ -145,22 +147,6 @@ export default function TerritoryForm ({ sub }) {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</CheckboxGroup>
|
</CheckboxGroup>
|
||||||
<BootstrapForm.Label>moderation</BootstrapForm.Label>
|
|
||||||
<Checkbox
|
|
||||||
inline
|
|
||||||
label={
|
|
||||||
<div className='d-flex align-items-center'>enable moderation
|
|
||||||
<Info>
|
|
||||||
<ol>
|
|
||||||
<li>Outlaw posts and comments with a click</li>
|
|
||||||
<li>Your territory will get a <Badge bg='secondary'>moderated</Badge> badge</li>
|
|
||||||
</ol>
|
|
||||||
</Info>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
name='moderated'
|
|
||||||
groupClassName='ms-1'
|
|
||||||
/>
|
|
||||||
<CheckboxGroup
|
<CheckboxGroup
|
||||||
label='billing'
|
label='billing'
|
||||||
name='billing'
|
name='billing'
|
||||||
@ -206,6 +192,46 @@ export default function TerritoryForm ({ sub }) {
|
|||||||
name='billingAutoRenew'
|
name='billingAutoRenew'
|
||||||
groupClassName='ms-1 mt-2'
|
groupClassName='ms-1 mt-2'
|
||||||
/>}
|
/>}
|
||||||
|
<AccordianItem
|
||||||
|
header={<div style={{ fontWeight: 'bold', fontSize: '92%' }}>options</div>}
|
||||||
|
body={
|
||||||
|
<>
|
||||||
|
<BootstrapForm.Label>moderation</BootstrapForm.Label>
|
||||||
|
<Checkbox
|
||||||
|
inline
|
||||||
|
label={
|
||||||
|
<div className='d-flex align-items-center'>enable moderation
|
||||||
|
<Info>
|
||||||
|
<ol>
|
||||||
|
<li>Outlaw posts and comments with a click</li>
|
||||||
|
<li>Your territory will get a <Badge bg='secondary'>moderated</Badge> badge</li>
|
||||||
|
</ol>
|
||||||
|
</Info>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
name='moderated'
|
||||||
|
groupClassName='ms-1'
|
||||||
|
/>
|
||||||
|
<BootstrapForm.Label>nsfw</BootstrapForm.Label>
|
||||||
|
<Checkbox
|
||||||
|
inline
|
||||||
|
label={
|
||||||
|
<div className='d-flex align-items-center'>mark as nsfw
|
||||||
|
<Info>
|
||||||
|
<ol>
|
||||||
|
<li>Let stackers know that your territory may contain explicit content</li>
|
||||||
|
<li>Your territory will get a <Badge bg='secondary'>nsfw</Badge> badge</li>
|
||||||
|
</ol>
|
||||||
|
</Info>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
name='nsfw'
|
||||||
|
groupClassName='ms-1'
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
|
||||||
|
}
|
||||||
|
/>
|
||||||
<div className='mt-3 d-flex justify-content-end'>
|
<div className='mt-3 d-flex justify-content-end'>
|
||||||
<FeeButton
|
<FeeButton
|
||||||
text={sub ? 'save' : 'found it'}
|
text={sub ? 'save' : 'found it'}
|
||||||
|
@ -19,6 +19,7 @@ export function TerritoryDetails ({ sub }) {
|
|||||||
territory details
|
territory details
|
||||||
{sub.status === 'STOPPED' && <Badge className='ms-2' bg='danger'>archived</Badge>}
|
{sub.status === 'STOPPED' && <Badge className='ms-2' bg='danger'>archived</Badge>}
|
||||||
{(sub.moderated || sub.moderatedCount > 0) && <Badge className='ms-2' bg='secondary'>moderated{sub.moderatedCount > 0 && ` ${sub.moderatedCount}`}</Badge>}
|
{(sub.moderated || sub.moderatedCount > 0) && <Badge className='ms-2' bg='secondary'>moderated{sub.moderatedCount > 0 && ` ${sub.moderatedCount}`}</Badge>}
|
||||||
|
{(sub.nsfw) && <Badge className='ms-2' bg='secondary'>nsfw</Badge>}
|
||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -22,6 +22,7 @@ export const ITEM_FIELDS = gql`
|
|||||||
userId
|
userId
|
||||||
moderated
|
moderated
|
||||||
meMuteSub
|
meMuteSub
|
||||||
|
nsfw
|
||||||
}
|
}
|
||||||
otsHash
|
otsHash
|
||||||
position
|
position
|
||||||
|
@ -19,6 +19,7 @@ export const SUB_FIELDS = gql`
|
|||||||
moderated
|
moderated
|
||||||
moderatedCount
|
moderatedCount
|
||||||
meMuteSub
|
meMuteSub
|
||||||
|
nsfw
|
||||||
}`
|
}`
|
||||||
|
|
||||||
export const SUB_FULL_FIELDS = gql`
|
export const SUB_FULL_FIELDS = gql`
|
||||||
|
@ -82,6 +82,7 @@ export const SETTINGS_FIELDS = gql`
|
|||||||
nostrRelays
|
nostrRelays
|
||||||
wildWestMode
|
wildWestMode
|
||||||
greeterMode
|
greeterMode
|
||||||
|
nsfwMode
|
||||||
authMethods {
|
authMethods {
|
||||||
lightning
|
lightning
|
||||||
nostr
|
nostr
|
||||||
|
@ -304,7 +304,8 @@ export function territorySchema (args) {
|
|||||||
.min(1, 'must be at least 1')
|
.min(1, 'must be at least 1')
|
||||||
.max(100000, 'must be at most 100k'),
|
.max(100000, 'must be at most 100k'),
|
||||||
postTypes: array().of(string().oneOf(POST_TYPES)).min(1, 'must support at least one post type'),
|
postTypes: array().of(string().oneOf(POST_TYPES)).min(1, 'must support at least one post type'),
|
||||||
billingType: string().required('required').oneOf(TERRITORY_BILLING_TYPES, 'required')
|
billingType: string().required('required').oneOf(TERRITORY_BILLING_TYPES, 'required'),
|
||||||
|
nsfw: boolean()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +82,7 @@ export default function Settings ({ ssrData }) {
|
|||||||
imgproxyOnly: settings?.imgproxyOnly,
|
imgproxyOnly: settings?.imgproxyOnly,
|
||||||
wildWestMode: settings?.wildWestMode,
|
wildWestMode: settings?.wildWestMode,
|
||||||
greeterMode: settings?.greeterMode,
|
greeterMode: settings?.greeterMode,
|
||||||
|
nsfwMode: settings?.nsfwMode,
|
||||||
nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '',
|
nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '',
|
||||||
nostrCrossposting: settings?.nostrCrossposting,
|
nostrCrossposting: settings?.nostrCrossposting,
|
||||||
nostrRelays: settings?.nostrRelays?.length ? settings?.nostrRelays : [''],
|
nostrRelays: settings?.nostrRelays?.length ? settings?.nostrRelays : [''],
|
||||||
@ -354,6 +355,19 @@ export default function Settings ({ ssrData }) {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
name='greeterMode'
|
name='greeterMode'
|
||||||
|
groupClassName='mb-0'
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
label={
|
||||||
|
<div className='d-flex align-items-center'>nsfw mode
|
||||||
|
<Info>
|
||||||
|
<ul className='fw-bold'>
|
||||||
|
<li>see posts from nsfw territories</li>
|
||||||
|
</ul>
|
||||||
|
</Info>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
name='nsfwMode'
|
||||||
/>
|
/>
|
||||||
<h4>nostr</h4>
|
<h4>nostr</h4>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Sub" ADD COLUMN "nsfw" BOOLEAN NOT NULL DEFAULT false;
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "users" ADD COLUMN "nsfwMode" BOOLEAN NOT NULL DEFAULT false;
|
@ -49,6 +49,7 @@ model User {
|
|||||||
hideInvoiceDesc Boolean @default(false)
|
hideInvoiceDesc Boolean @default(false)
|
||||||
wildWestMode Boolean @default(false)
|
wildWestMode Boolean @default(false)
|
||||||
greeterMode Boolean @default(false)
|
greeterMode Boolean @default(false)
|
||||||
|
nsfwMode Boolean @default(false)
|
||||||
fiatCurrency String @default("USD")
|
fiatCurrency String @default("USD")
|
||||||
withdrawMaxFeeDefault Int @default(10)
|
withdrawMaxFeeDefault Int @default(10)
|
||||||
autoDropBolt11s Boolean @default(false)
|
autoDropBolt11s Boolean @default(false)
|
||||||
@ -423,6 +424,7 @@ model Sub {
|
|||||||
billedLastAt DateTime @default(now())
|
billedLastAt DateTime @default(now())
|
||||||
moderated Boolean @default(false)
|
moderated Boolean @default(false)
|
||||||
moderatedCount Int @default(0)
|
moderatedCount Int @default(0)
|
||||||
|
nsfw Boolean @default(false)
|
||||||
|
|
||||||
parent Sub? @relation("ParentChildren", fields: [parentName], references: [name])
|
parent Sub? @relation("ParentChildren", fields: [parentName], references: [name])
|
||||||
children Sub[] @relation("ParentChildren")
|
children Sub[] @relation("ParentChildren")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user