further invite code

This commit is contained in:
Moriz Wahl 2021-01-07 13:30:11 +01:00
parent bcbc933657
commit a1967815bf
9 changed files with 124 additions and 1 deletions

View File

@ -149,6 +149,7 @@ export default shield(
pinPost: isAdmin,
unpinPost: isAdmin,
UpdateDonations: isAdmin,
CreateInviteCode: isAuthenticated,
},
User: {
email: or(isMyOwn, isAdmin),

View File

@ -0,0 +1,19 @@
export default {
code: { type: 'string', primary: true },
createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() },
uses: { type: 'int', default: () => 0 },
maxUses: { type: 'int', default: () => 1 },
active: { type: 'boolean', default: () => true },
createdBy: {
type: 'relationship',
relationship: 'CREATED',
target: 'User',
direction: 'in',
},
usedBy: {
type: 'relationship',
relationship: 'USED',
target: 'User',
direction: 'in',
},
}

View File

@ -100,6 +100,18 @@ export default {
target: 'User',
direction: 'in',
},
createdInvite: {
type: 'relationship',
relationship: 'CREATED',
target: 'InviteCode',
direction: 'out',
},
usedInvite: {
type: 'relationship',
relationship: 'USED',
target: 'InviteCode',
direction: 'out',
},
termsAndConditionsAgreedVersion: {
type: 'string',
allow: [null],

View File

@ -15,4 +15,5 @@ export default {
Donations: require('./Donations.js').default,
Report: require('./Report.js').default,
Migration: require('./Migration.js').default,
InviteCode: require('./InviteCode.js').default,
}

View File

@ -0,0 +1,5 @@
export default function generateInviteCode() {
return Array.from({length: 6}, (n = Math.floor(Math.random() * 36)) => {
return String.fromCharCode(n > 9 ? n + 55 : n + 48)
}).join('')
}

View File

@ -0,0 +1,66 @@
import { neo4jgraphql } from 'neo4j-graphql-js'
import generateInvieCode from './helpers/generateInviteCode'
import Resolver from './helpers/Resolver'
const uniqueInviteCode = async (session, code) => {
return session.readTransaction(async (txc) => {
const result = await txc.run(
`MATCH (ic:InviteCode { id: $code }) RETURN count(ic) AS count`,
{ code },
)
return parseInt(String(result.records[0].get('count'))) === 0
})
}
export default {
Mutation: {
CreateInviteCode: async (_parent, args, context, _resolveInfo) => {
const {
user: { id: userId },
} = context
const session = context.driver.session()
let code = generateInvieCode()
let response
while(!await uniqueInviteCode(session, code)) {
code = generateInvieCode()
}
const writeTxResultPromise = session.writeTransaction(async (txc) => {
const result = await txc.run(
`MATCH (user:User {id: $userId})
MERGE (user)-[:CREATED]->(ic:InviteCode {
code: $code,
createdAt: toString(datetime()),
uses: $uses,
maxUses: $maxUses,
active: true
}) RETURN ic AS inviteCode`,
{
userId,
code,
maxUses: args.maxUses,
uses: 0,
},
)
return result.records.map((record) => record.get('inviteCode').properties)
})
try {
const txResult = await writeTxResultPromise
console.log(txResult)
response = txResult[0]
} finally {
session.close()
}
return response
}
},
InviteCode: {
...Resolver('InviteCode', {
hasOne: {
createdBy: '<-[:CREATED]-(related:User)',
},
hasMany: {
usedBy: '<-[:USED]-(related:User)',
},
}),
},
}

View File

@ -293,6 +293,7 @@ export default {
avatar: '-[:AVATAR_IMAGE]->(related:Image)',
invitedBy: '<-[:INVITED]-(related:User)',
location: '-[:IS_IN]->(related:Location)',
usedInviteCode: '-[:USED]->(related:InviteCode)',
},
hasMany: {
followedBy: '<-[:FOLLOWS]-(related:User)',
@ -304,6 +305,7 @@ export default {
shouted: '-[:SHOUTED]->(related:Post)',
categories: '-[:CATEGORIZED]->(related:Category)',
badges: '<-[:REWARDED]-(related:Badge)',
inviteCodes: '-[:CREATED]->(related:InviteCode)',
},
}),
},

View File

@ -0,0 +1,14 @@
type InviteCode {
code: ID!
createdAt: String
uses: Int!
maxUses: Int!
createdBy: User @relation(name: "CREATED", direction: "IN")
usedBy: [User] @relation(name: "USED", direction: "IN")
active: Boolean!
}
type Mutation {
CreateInviteCode(maxUses: Int = 1): InviteCode
}

View File

@ -56,6 +56,9 @@ type User {
followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN")
followedByCount: Int! @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(DISTINCT r)")
inviteCodes: [InviteCode] @relation(name: "CREATED", direction: "OUT")
usedInviteCode: InviteCode @relation(name: "USED", direction: "OUT")
# Is the currently logged in user following that user?
followedByCurrentUser: Boolean! @cypher(
statement: """