215 lines
6.4 KiB
JavaScript
215 lines
6.4 KiB
JavaScript
import { ApolloClient, InMemoryCache } from '@apollo/client'
|
|
import { SchemaLink } from '@apollo/client/link/schema'
|
|
import { makeExecutableSchema } from '@graphql-tools/schema'
|
|
import resolvers from './resolvers'
|
|
import typeDefs from './typeDefs'
|
|
import models from './models'
|
|
import { print } from 'graphql'
|
|
import lnd from './lnd'
|
|
import search from './search'
|
|
import { ME } from '@/fragments/users'
|
|
import { PRICE } from '@/fragments/price'
|
|
import { BLOCK_HEIGHT } from '@/fragments/blockHeight'
|
|
import { CHAIN_FEE } from '@/fragments/chainFee'
|
|
import { getServerSession } from 'next-auth/next'
|
|
import { getAuthOptions } from '@/pages/api/auth/[...nextauth]'
|
|
|
|
export default async function getSSRApolloClient ({ req, res, me = null }) {
|
|
const session = req && await getServerSession(req, res, getAuthOptions(req))
|
|
const client = new ApolloClient({
|
|
ssrMode: true,
|
|
link: new SchemaLink({
|
|
schema: makeExecutableSchema({
|
|
typeDefs,
|
|
resolvers
|
|
}),
|
|
context: {
|
|
models,
|
|
me: session
|
|
? session.user
|
|
: me,
|
|
lnd,
|
|
search
|
|
}
|
|
}),
|
|
cache: new InMemoryCache({
|
|
freezeResults: true
|
|
}),
|
|
assumeImmutableResults: true,
|
|
defaultOptions: {
|
|
watchQuery: {
|
|
fetchPolicy: 'no-cache',
|
|
nextFetchPolicy: 'no-cache',
|
|
ssr: true
|
|
},
|
|
query: {
|
|
fetchPolicy: 'no-cache',
|
|
nextFetchPolicy: 'no-cache',
|
|
ssr: true
|
|
}
|
|
}
|
|
})
|
|
|
|
await client.clearStore()
|
|
return client
|
|
}
|
|
|
|
function oneDayReferral (request, { me }) {
|
|
if (!me) return
|
|
const refHeader = request.headers['x-stacker-news-referrer']
|
|
if (!refHeader) return
|
|
|
|
const referrers = refHeader.split('; ').filter(Boolean)
|
|
for (const referrer of referrers) {
|
|
let prismaPromise, getData
|
|
|
|
if (referrer.startsWith('item-')) {
|
|
prismaPromise = models.item.findUnique({ where: { id: parseInt(referrer.slice(5)) } })
|
|
getData = item => ({
|
|
referrerId: item.userId,
|
|
refereeId: parseInt(me.id),
|
|
type: item.parentId ? 'COMMENT' : 'POST',
|
|
typeId: String(item.id)
|
|
})
|
|
} else if (referrer.startsWith('profile-')) {
|
|
const name = referrer.slice(8)
|
|
// exclude all pages that are not user profiles
|
|
if (['api', 'auth', 'day', 'invites', 'invoices', 'referrals', 'rewards',
|
|
'satistics', 'settings', 'stackers', 'wallet', 'withdrawals', '404', '500',
|
|
'email', 'live', 'login', 'notifications', 'offline', 'search', 'share',
|
|
'signup', 'territory', 'recent', 'top', 'edit', 'post', 'rss', 'saloon',
|
|
'faq', 'story', 'privacy', 'copyright', 'tos', 'changes', 'guide', 'daily',
|
|
'anon', 'ad'].includes(name)) continue
|
|
|
|
prismaPromise = models.user.findUnique({ where: { name } })
|
|
getData = user => ({
|
|
referrerId: user.id,
|
|
refereeId: parseInt(me.id),
|
|
type: 'PROFILE',
|
|
typeId: String(user.id)
|
|
})
|
|
} else if (referrer.startsWith('territory-')) {
|
|
prismaPromise = models.sub.findUnique({ where: { name: referrer.slice(10) } })
|
|
getData = sub => ({
|
|
referrerId: sub.userId,
|
|
refereeId: parseInt(me.id),
|
|
type: 'TERRITORY',
|
|
typeId: sub.name
|
|
})
|
|
} else {
|
|
prismaPromise = models.user.findUnique({ where: { name: referrer } })
|
|
getData = user => ({
|
|
referrerId: user.id,
|
|
refereeId: parseInt(me.id),
|
|
type: 'REFERRAL',
|
|
typeId: String(user.id)
|
|
})
|
|
}
|
|
|
|
prismaPromise?.then(ref => {
|
|
if (ref && getData) {
|
|
const data = getData(ref)
|
|
// can't refer yourself
|
|
if (data.refereeId === data.referrerId) return
|
|
models.oneDayReferral.create({ data }).catch(console.error)
|
|
}
|
|
}).catch(console.error)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Takes a query and variables and returns a getServerSideProps function
|
|
*
|
|
* @param opts Options
|
|
* @param opts.query graphql query or function that return graphql query
|
|
* @param opts.variables graphql variables or function that return graphql variables
|
|
* @param opts.notFound function that tests data to determine if 404
|
|
* @param opts.authRequired boolean that determines if auth is required
|
|
*/
|
|
export function getGetServerSideProps (
|
|
{ query: queryOrFunc, variables: varsOrFunc, notFound, authRequired }) {
|
|
return async function ({ req, res, query: params }) {
|
|
const { nodata, ...realParams } = params
|
|
// we want to use client-side cache
|
|
if (nodata) return { props: { } }
|
|
|
|
const variables = typeof varsOrFunc === 'function' ? varsOrFunc(realParams) : varsOrFunc
|
|
const vars = { ...realParams, ...variables }
|
|
const query = typeof queryOrFunc === 'function' ? queryOrFunc(vars) : queryOrFunc
|
|
|
|
const client = await getSSRApolloClient({ req, res })
|
|
|
|
let { data: { me } } = await client.query({ query: ME })
|
|
|
|
// required to redirect to /signup on page reload
|
|
// if we switched to anon and authentication is required
|
|
if (req.cookies['multi_auth.user-id'] === 'anonymous') {
|
|
me = null
|
|
}
|
|
|
|
if (authRequired && !me) {
|
|
let callback = process.env.NEXT_PUBLIC_URL + req.url
|
|
// On client-side routing, the callback is a NextJS URL
|
|
// so we need to remove the NextJS stuff.
|
|
// Example: /_next/data/development/territory.json
|
|
callback = callback.replace(/\/_next\/data\/\w+\//, '/').replace(/\.json$/, '')
|
|
return {
|
|
redirect: {
|
|
destination: `/signup?callbackUrl=${encodeURIComponent(callback)}`
|
|
}
|
|
}
|
|
}
|
|
|
|
const { data: { price } } = await client.query({
|
|
query: PRICE, variables: { fiatCurrency: me?.privates?.fiatCurrency }
|
|
})
|
|
|
|
const { data: { blockHeight } } = await client.query({
|
|
query: BLOCK_HEIGHT, variables: {}
|
|
})
|
|
|
|
const { data: { chainFee } } = await client.query({
|
|
query: CHAIN_FEE, variables: {}
|
|
})
|
|
|
|
let error = null; let data = null; let props = {}
|
|
if (query) {
|
|
try {
|
|
({ error, data } = await client.query({
|
|
query,
|
|
variables: vars
|
|
}))
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
|
|
if (error || !data || (notFound && notFound(data, vars, me))) {
|
|
error && console.error(error)
|
|
res.writeHead(302, {
|
|
Location: '/404'
|
|
}).end()
|
|
}
|
|
|
|
props = {
|
|
apollo: {
|
|
query: print(query),
|
|
variables: vars
|
|
}
|
|
}
|
|
}
|
|
|
|
oneDayReferral(req, { me })
|
|
|
|
return {
|
|
props: {
|
|
...props,
|
|
me,
|
|
price,
|
|
blockHeight,
|
|
chainFee,
|
|
ssrData: data
|
|
}
|
|
}
|
|
}
|
|
}
|