Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: invite code validity check #600

Merged
merged 6 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions apps/api/src/app/invites/invites.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ export class InvitesController {
return mapEntity(invite)
}

@Get("check/:code/group/:groupId")
@ApiOperation({ description: "Checks if a specific invite is valid." })
@ApiCreatedResponse({ type: Boolean })
async checkInvite(
@Param("code") inviteCode: string,
@Param("groupId") groupId: string
): Promise<boolean> {
return this.invitesService.checkInvite(inviteCode, groupId)
}

@Patch("redeem")
@ApiBody({ type: RedeemInviteDto })
@ApiHeader({ name: "x-api-key", required: true })
Expand Down
19 changes: 19 additions & 0 deletions apps/api/src/app/invites/invites.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,25 @@ describe("InvitesService", () => {
})
})

describe("# checkInvite", () => {
it("Should return true if invite is valid", async () => {
const { code } = await invitesService.createInvite(
{ groupId },
admin.id
)

const invite = await invitesService.checkInvite(code, groupId)

expect(invite).toBeTruthy()
})

it("Should return false if invite is invalid", async () => {
const invite = await invitesService.checkInvite("12345", groupId)

expect(invite).toBeFalsy()
})
})

describe("# redeemInvite", () => {
let invite: Invite

Expand Down
18 changes: 18 additions & 0 deletions apps/api/src/app/invites/invites.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,24 @@ export class InvitesService {
return invite
}

/**
* Returns boolean value if the invite code is valid.
* @param inviteCode Invite code.
* @param groupId Group id.
* @returns Boolean.
*/
async checkInvite(inviteCode: string, groupId: string): Promise<boolean> {
const invite = await this.inviteRepository.findOne({
where: {
code: inviteCode,
group: { id: groupId }
},
relations: ["group"]
})

return !!invite
}

/**
* Redeems an invite by consuming its code. Every invite
* can be used only once.
Expand Down
21 changes: 21 additions & 0 deletions apps/client/src/api/bandadaAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,27 @@ export async function addMemberByInviteCode(
}
}

export async function checkInvite(
inviteCode: string,
groupId: string
): Promise<boolean> {
try {
return await request(
`${API_URL}/invites/check/${inviteCode}/group/${groupId}`
)
} catch (error: any) {
console.error(error)

if (error.response) {
alert(error.response.statusText)
} else {
alert("Some error occurred!")
}

return false
}
}

export async function redeemInvite(
inviteCode: string,
groupId: string
Expand Down
11 changes: 11 additions & 0 deletions apps/client/src/pages/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ export default function HomePage(): JSX.Element {
return
}

const isValid = await bandadaAPI.checkInvite(
inviteCode,
invite.group.id
)

if (!isValid) {
setLoading(false)
alert("Invalid invite code")
return
}

const signer = library.getSigner(account)

const message = `Sign this message to generate your Semaphore identity.`
Expand Down
26 changes: 26 additions & 0 deletions apps/docs/docs/api-sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,32 @@ const apiKey = "70f07d0d-6aa2-4fe1-b4b9-06c271a641dc"
const invite = await apiSdk.getInvite(inviteCode)
```

## Check invite

\# **checkInvite**(): _Promise\<boolean>_

Returns boolean value if the invite code is valid.

```ts
const inviteCode = "C5VAG4HD"
const groupId = "10402173435763029700781503965100"

const isValid = await apiSdk.checkInvite(inviteCode, groupId)
```

## Redeem invite

\# **redeemInvite**(): _Promise\<Invite>_

Redeems a specific invite.

```ts
const groupId = "10402173435763029700781503965100"
const inviteCode = "C5VAG4HD"

const invite = await apiSdk.redeemInvite(inviteCode, groupId)
```

## Get credential group join URL

\# **getCredentialGroupJoinUrl**(): _string_
Expand Down
13 changes: 13 additions & 0 deletions libs/api-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,19 @@ const apiKey = "70f07d0d-6aa2-4fe1-b4b9-06c271a641dc"
const invite = await apiSdk.getInvite(inviteCode)
```

## Check invite

\# **checkInvite**(): _Promise\<boolean>_

Returns boolean value if the invite code is valid.

```ts
const inviteCode = "C5VAG4HD"
const groupId = "10402173435763029700781503965100"

const isValid = await apiSdk.checkInvite(inviteCode, groupId)
```

## Redeem invite

\# **redeemInvite**(): _Promise\<Invite>_
Expand Down
18 changes: 17 additions & 1 deletion libs/api-sdk/src/apiSdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
getGroupsByType,
createAssociatedGroup
} from "./groups"
import { createInvite, getInvite, redeemInvite } from "./invites"
import { checkInvite, createInvite, getInvite, redeemInvite } from "./invites"

export default class ApiSdk {
private _url: string
Expand Down Expand Up @@ -419,6 +419,22 @@ export default class ApiSdk {
return invite
}

/**
* Returns boolean value if the invite code is valid.
* @param inviteCode Invite code.
* @param groupId Group id.
* @returns Boolean.
*/
async checkInvite(inviteCode: string, groupId: string): Promise<boolean> {
const isInviteValid = await checkInvite(
this._config,
inviteCode,
groupId
)

return isInviteValid
}

/**
* Redeems a specific invite.
* @param inviteCode Invite code.
Expand Down
19 changes: 19 additions & 0 deletions libs/api-sdk/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,25 @@ describe("Bandada API SDK", () => {
})
})

describe("# checkInvite", () => {
it("Should check if an invite is valid", async () => {
const groupId = "95633257675970239314311768035433"
const inviteCode = "C5VAG4HD"

requestMocked.mockImplementationOnce(() =>
Promise.resolve(true)
)

const apiSdk: ApiSdk = new ApiSdk(SupportedUrl.DEV)
const isInviteValid = await apiSdk.checkInvite(
inviteCode,
groupId
)

expect(isInviteValid).toBeTruthy()
})
})

describe("# redeemInvite", () => {
it("Should redeem an invite", async () => {
const groupId = "95633257675970239314311768035433"
Expand Down
25 changes: 25 additions & 0 deletions libs/api-sdk/src/invites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ export async function getInvite(
return invite
}

/**
* Returns boolean value if the invite code is valid.
* @param inviteCode Invite code.
* @param groupId Group id.
* @returns Boolean.
*/
export async function checkInvite(
config: object,
inviteCode: string,
groupId: string
): Promise<boolean> {
const requestUrl = `${url}/check/${inviteCode}/group/${groupId}`

const req = await request(requestUrl, config)

return req
}

/**
* Creates one new group invite.
* @param groupId The group identifier.
Expand All @@ -47,6 +65,13 @@ export async function createInvite(
return req
}

/**
* Redeems a specific invite.
* @param inviteCode Invite code to be redeemed.
* @param groupId Group id.
* @param apiKey API Key of the admin.
* @returns The updated redeemed invite.
*/
export async function redeemInvite(
config: object,
inviteCode: string,
Expand Down
Loading