mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
further invite code
This commit is contained in:
parent
bcbc933657
commit
a1967815bf
@ -149,6 +149,7 @@ export default shield(
|
|||||||
pinPost: isAdmin,
|
pinPost: isAdmin,
|
||||||
unpinPost: isAdmin,
|
unpinPost: isAdmin,
|
||||||
UpdateDonations: isAdmin,
|
UpdateDonations: isAdmin,
|
||||||
|
CreateInviteCode: isAuthenticated,
|
||||||
},
|
},
|
||||||
User: {
|
User: {
|
||||||
email: or(isMyOwn, isAdmin),
|
email: or(isMyOwn, isAdmin),
|
||||||
|
|||||||
19
backend/src/models/InviteCode.js
Normal file
19
backend/src/models/InviteCode.js
Normal 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',
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -100,6 +100,18 @@ export default {
|
|||||||
target: 'User',
|
target: 'User',
|
||||||
direction: 'in',
|
direction: 'in',
|
||||||
},
|
},
|
||||||
|
createdInvite: {
|
||||||
|
type: 'relationship',
|
||||||
|
relationship: 'CREATED',
|
||||||
|
target: 'InviteCode',
|
||||||
|
direction: 'out',
|
||||||
|
},
|
||||||
|
usedInvite: {
|
||||||
|
type: 'relationship',
|
||||||
|
relationship: 'USED',
|
||||||
|
target: 'InviteCode',
|
||||||
|
direction: 'out',
|
||||||
|
},
|
||||||
termsAndConditionsAgreedVersion: {
|
termsAndConditionsAgreedVersion: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
allow: [null],
|
allow: [null],
|
||||||
|
|||||||
@ -15,4 +15,5 @@ export default {
|
|||||||
Donations: require('./Donations.js').default,
|
Donations: require('./Donations.js').default,
|
||||||
Report: require('./Report.js').default,
|
Report: require('./Report.js').default,
|
||||||
Migration: require('./Migration.js').default,
|
Migration: require('./Migration.js').default,
|
||||||
|
InviteCode: require('./InviteCode.js').default,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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('')
|
||||||
|
}
|
||||||
66
backend/src/schema/resolvers/inviteCodes.js
Normal file
66
backend/src/schema/resolvers/inviteCodes.js
Normal 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)',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -293,6 +293,7 @@ export default {
|
|||||||
avatar: '-[:AVATAR_IMAGE]->(related:Image)',
|
avatar: '-[:AVATAR_IMAGE]->(related:Image)',
|
||||||
invitedBy: '<-[:INVITED]-(related:User)',
|
invitedBy: '<-[:INVITED]-(related:User)',
|
||||||
location: '-[:IS_IN]->(related:Location)',
|
location: '-[:IS_IN]->(related:Location)',
|
||||||
|
usedInviteCode: '-[:USED]->(related:InviteCode)',
|
||||||
},
|
},
|
||||||
hasMany: {
|
hasMany: {
|
||||||
followedBy: '<-[:FOLLOWS]-(related:User)',
|
followedBy: '<-[:FOLLOWS]-(related:User)',
|
||||||
@ -304,6 +305,7 @@ export default {
|
|||||||
shouted: '-[:SHOUTED]->(related:Post)',
|
shouted: '-[:SHOUTED]->(related:Post)',
|
||||||
categories: '-[:CATEGORIZED]->(related:Category)',
|
categories: '-[:CATEGORIZED]->(related:Category)',
|
||||||
badges: '<-[:REWARDED]-(related:Badge)',
|
badges: '<-[:REWARDED]-(related:Badge)',
|
||||||
|
inviteCodes: '-[:CREATED]->(related:InviteCode)',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|||||||
14
backend/src/schema/types/type/InviteCode.gql
Normal file
14
backend/src/schema/types/type/InviteCode.gql
Normal 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
|
||||||
|
}
|
||||||
@ -56,6 +56,9 @@ type User {
|
|||||||
followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN")
|
followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN")
|
||||||
followedByCount: Int! @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(DISTINCT r)")
|
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?
|
# Is the currently logged in user following that user?
|
||||||
followedByCurrentUser: Boolean! @cypher(
|
followedByCurrentUser: Boolean! @cypher(
|
||||||
statement: """
|
statement: """
|
||||||
@ -83,7 +86,7 @@ type User {
|
|||||||
RETURN COUNT(user) >= 1
|
RETURN COUNT(user) >= 1
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
# contributions: [WrittenPost]!
|
# contributions: [WrittenPost]!
|
||||||
# contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]!
|
# contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]!
|
||||||
# @cypher(
|
# @cypher(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user