Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
Made improvements for Invite on client and server (#8624)
Browse files Browse the repository at this point in the history
* Changes to fix invite service

* Fixed spawn details column

* Fixed size check

* Updated migration to uuid

* Misc client fixes

* Fixed update crashing

* Fixed formatting

* Fixed formatting

---------

Co-authored-by: Kyle Baran <[email protected]>
  • Loading branch information
hanzlamateen and barankyle authored Aug 31, 2023
1 parent 259c224 commit 0c0e717
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const AdminInvites = ({ search, selectedInviteIds, setSelectedInviteIds }: Props
type: invite.inviteType,
targetObjectId: invite.targetObjectId,
spawnType: invite.spawnType,
spawnDetails: JSON.stringify(invite.spawnDetails),
spawnDetails: invite.spawnDetails ? JSON.stringify(invite.spawnDetails) : '',
action: (
<>
<a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,15 @@ const CreateInviteModal = ({ open, onClose }: Props) => {
const inviteType = INVITE_TYPE_TAB_MAP[inviteTypeTab.value]
const isPhone = PHONE_REGEX.test(target)
const isEmail = EMAIL_REGEX.test(target)
let inviteCode = ''
const sendData = {
inviteType,
identityProviderType: isEmail ? 'email' : isPhone ? 'sms' : null,
targetObjectId: instanceId.value || locationId.value || null,
makeAdmin: makeAdmin.value,
deleteOnUse: oneTimeUse.value
} as InviteData
if (target.length === 8) sendData.inviteCode = target
if (target.length === 8) inviteCode = target
else sendData.token = target
if (setSpawn.value && spawnTypeTab.value === 0 && userInviteCode.value) {
sendData.spawnType = 'inviteCode'
Expand All @@ -200,7 +201,7 @@ const CreateInviteModal = ({ open, onClose }: Props) => {
sendData.startTime = toDateTimeSql(startTime.value?.toDate())
sendData.endTime = toDateTimeSql(endTime.value?.toDate())
}
await InviteService.sendInvite(sendData)
await InviteService.sendInvite(sendData, inviteCode)
instanceId.set('')
locationId.set('')
textValue.set('')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ Ethereal Engine. All Rights Reserved.
*/

import classNames from 'classnames'
import dayjs, { Dayjs } from 'dayjs'
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'

Expand Down Expand Up @@ -85,8 +84,8 @@ const UpdateInviteModal = ({ open, onClose, invite }: Props) => {
const setSpawn = useHookstate(false)
const spawnTypeTab = useHookstate(0)
const timed = useHookstate(false)
const startTime = useHookstate<Dayjs>(dayjs(null))
const endTime = useHookstate<Dayjs>(dayjs(null))
const startTime = useHookstate<Date>(new Date())
const endTime = useHookstate<Date>(new Date())

const adminInstances = useFind('instance').data
const adminLocations = useFind(locationPath).data
Expand All @@ -98,7 +97,7 @@ const UpdateInviteModal = ({ open, onClose, invite }: Props) => {
value.components.find((component) => component.name === 'spawn-point')
)
: []
const updateInvite = useMutation(invitePath).patch
const patchInvite = useMutation(invitePath).patch

useEffect(() => {
inviteTypeTab.set(
Expand Down Expand Up @@ -147,8 +146,10 @@ const UpdateInviteModal = ({ open, onClose, invite }: Props) => {
}
if (invite.timed) {
timed.set(true)
startTime.set(dayjs(invite.startTime))
endTime.set(dayjs(invite.endTime))
const sTime = invite.startTime ? new Date(invite.startTime) : new Date()
startTime.set(sTime)
const eTime = invite.endTime ? new Date(invite.endTime) : new Date()
endTime.set(eTime)
}
}, [invite])

Expand Down Expand Up @@ -232,22 +233,14 @@ const UpdateInviteModal = ({ open, onClose, invite }: Props) => {
const isPhone = PHONE_REGEX.test(target)
const isEmail = EMAIL_REGEX.test(target)
const sendData = {
id: invite.id,
inviteType: inviteType,
inviteeId: invite.inviteeId,
passcode: invite.passcode,
identityProviderType: isEmail ? 'email' : isPhone ? 'sms' : null,
targetObjectId: instanceId.value || locationId.value || null,
createdAt: invite.createdAt || toDateTimeSql(new Date()),
updatedAt: invite.updatedAt || toDateTimeSql(new Date()),
makeAdmin: makeAdmin.value,
deleteOnUse: oneTimeUse.value,
invitee: undefined,
user: undefined,
userId: invite.userId
} as InvitePatch
if (target.length === 8) sendData.inviteCode = target
else sendData.token = target
if (target.length !== 8) sendData.token = target
if (setSpawn.value && spawnTypeTab.value === 0 && userInviteCode.value) {
sendData.spawnType = 'inviteCode'
sendData.spawnDetails = { inviteCode: userInviteCode.value }
Expand All @@ -257,10 +250,10 @@ const UpdateInviteModal = ({ open, onClose, invite }: Props) => {
}
sendData.timed = timed.value && (startTime.value != null || endTime.value != null)
if (sendData.timed) {
sendData.startTime = toDateTimeSql(startTime.value?.toDate())
sendData.endTime = toDateTimeSql(endTime.value?.toDate())
sendData.startTime = toDateTimeSql(startTime.value)
sendData.endTime = toDateTimeSql(endTime.value)
}
await updateInvite(invite.id, sendData)
await patchInvite(invite.id, sendData)
instanceId.set('')
locationId.set('')
textValue.set('')
Expand All @@ -272,8 +265,8 @@ const UpdateInviteModal = ({ open, onClose, invite }: Props) => {
spawnTypeTab.set(0)
inviteTypeTab.set(0)
timed.set(false)
startTime.set(dayjs(null))
endTime.set(dayjs(null))
startTime.set(new Date())
endTime.set(new Date())
} catch (err) {
NotificationService.dispatchNotify(err.message, { variant: 'error' })
}
Expand Down Expand Up @@ -352,23 +345,27 @@ const UpdateInviteModal = ({ open, onClose, invite }: Props) => {
<DateTimePicker
label="Start Time"
value={startTime.value}
onChange={(e) => startTime.set(dayjs(e))}
onChange={(e) => startTime.set(e || new Date())}
/>
<IconButton
color="primary"
size="small"
className={styles.clearTime}
onClick={() => startTime.set(dayjs(null))}
onClick={() => startTime.set(new Date())}
icon={<Icon type="HighlightOff" />}
/>
</div>
<div className={styles.pickerControls}>
<DateTimePicker label="End Time" value={endTime.value} onChange={(e) => endTime.set(dayjs(e))} />
<DateTimePicker
label="End Time"
value={endTime.value}
onChange={(e) => endTime.set(e || new Date())}
/>
<IconButton
color="primary"
size="small"
className={styles.clearTime}
onClick={() => endTime.set(dayjs(null))}
onClick={() => endTime.set(new Date())}
icon={<Icon type="HighlightOff" />}
/>
</div>
Expand Down
16 changes: 8 additions & 8 deletions packages/client-core/src/social/services/InviteService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export const InviteServiceReceptor = (action) => {

//Service
export const InviteService = {
sendInvite: async (data: InviteData) => {
sendInvite: async (data: InviteData, inviteCode: string) => {
if (data.identityProviderType === 'email') {
if (!data.token || !EMAIL_REGEX.test(data.token)) {
NotificationService.dispatchNotify(`Invalid email address: ${data.token}`, { variant: 'error' })
Expand All @@ -152,22 +152,22 @@ export const InviteService = {
return
}

if (data.spawnDetails?.inviteCode) {
if (!INVITE_CODE_REGEX.test(data.spawnDetails?.inviteCode)) {
NotificationService.dispatchNotify(`Invalid Invite Code: ${data.spawnDetails?.inviteCode}`, {
if (inviteCode) {
if (!INVITE_CODE_REGEX.test(inviteCode)) {
NotificationService.dispatchNotify(`Invalid Invite Code: ${inviteCode}`, {
variant: 'error'
})
return
} else {
try {
const inviteCodeLookups = await Engine.instance.api.service(inviteCodeLookupPath).find({
query: {
inviteCode: data.spawnDetails?.inviteCode
inviteCode: inviteCode
}
})

if (inviteCodeLookups.length === 0) {
NotificationService.dispatchNotify(`No user has the invite code ${data.spawnDetails?.inviteCode}`, {
NotificationService.dispatchNotify(`No user has the invite code ${inviteCode}`, {
variant: 'error'
})
return
Expand All @@ -179,14 +179,14 @@ export const InviteService = {
}
}

if (data.inviteeId != null) {
if (data.inviteeId) {
if (!USER_ID_REGEX.test(data.inviteeId)) {
NotificationService.dispatchNotify('Invalid user ID', { variant: 'error' })
return
}
}

if ((data.token == null || data.token.length === 0) && (data.inviteeId == null || data.inviteeId.length === 0)) {
if (!data.token && !data.inviteeId) {
NotificationService.dispatchNotify('Not a valid recipient', { variant: 'error' })
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import Icon from '@etherealengine/ui/src/primitives/mui/Icon'
import IconButton from '@etherealengine/ui/src/primitives/mui/IconButton'

import { InviteData } from '@etherealengine/engine/src/schemas/social/invite.schema'
import { UserID } from '@etherealengine/engine/src/schemas/user/user.schema'
import { InviteService } from '../../../../social/services/InviteService'
import { AuthState } from '../../../services/AuthService'
import { PopupMenuServices } from '../PopupMenuService'
Expand Down Expand Up @@ -85,17 +84,21 @@ export const useShareMenuHooks = ({ refLink }) => {
const isEmail = EMAIL_REGEX.test(token)
const isPhone = PHONE_REGEX.test(token)
const location = new URL(window.location as any)
let params = new URLSearchParams(location.search)
const params = new URLSearchParams(location.search)
let inviteCode = ''

const sendData = {
inviteType: 'instance',
token: token.length === 8 ? null : token,
inviteCode: token.length === 8 ? token : null,
identityProviderType: isEmail ? 'email' : isPhone ? 'sms' : null,
targetObjectId: params.get('instanceId'),
inviteeId: '' as UserID,
deleteOnUse: true
} as InviteData

if (token.length === 8) {
inviteCode = token
}

if (isSpectatorMode) {
sendData.spawnType = 'spectate'
sendData.spawnDetails = { spectate: selfUser.id.value }
Expand All @@ -104,7 +107,7 @@ export const useShareMenuHooks = ({ refLink }) => {
sendData.spawnDetails = { inviteCode: selfUser.inviteCode.value }
}

InviteService.sendInvite(sendData)
InviteService.sendInvite(sendData, inviteCode)
setToken('')
}

Expand All @@ -114,7 +117,7 @@ export const useShareMenuHooks = ({ refLink }) => {

const getInviteLink = () => {
const location = new URL(window.location as any)
let params = new URLSearchParams(location.search)
const params = new URLSearchParams(location.search)
if (selfUser?.inviteCode.value != null) {
params.set('inviteCode', selfUser.inviteCode.value)
location.search = params.toString()
Expand All @@ -126,7 +129,7 @@ export const useShareMenuHooks = ({ refLink }) => {

const getSpectateModeUrl = () => {
const location = new URL(window.location as any)
let params = new URLSearchParams(location.search)
const params = new URLSearchParams(location.search)
params.set('spectate', selfUser.id.value)
params.delete('inviteCode')
location.search = params.toString()
Expand Down Expand Up @@ -172,7 +175,7 @@ const ShareMenu = (): JSX.Element => {
})

// Ref: https://developer.oculus.com/documentation/web/web-launch
let questShareLink = new URL('https://oculus.com/open_url/')
const questShareLink = new URL('https://oculus.com/open_url/')
questShareLink.searchParams.set('url', shareLink)

const copyToClipboard = (text: string) => {
Expand Down
12 changes: 1 addition & 11 deletions packages/engine/src/schemas/social/invite.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,7 @@ export const inviteDataSchema = Type.Intersect(
[
inviteDataProperties,
// Add additional query properties here
Type.Object(
{
inviteCode: Type.Optional(
Type.String({
maxLength: 8,
minLength: 8
})
)
},
{ additionalProperties: false }
)
Type.Object({}, { additionalProperties: false })
],
{ additionalProperties: false }
)
Expand Down
23 changes: 12 additions & 11 deletions packages/server-core/src/social/invite/invite.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import {
InviteData,
InvitePatch,
InviteQuery,
InviteType
InviteType,
invitePath
} from '@etherealengine/engine/src/schemas/social/invite.schema'
import {
IdentityProviderType,
Expand Down Expand Up @@ -82,8 +83,8 @@ const afterInviteFind = async (app: Application, result: Paginated<InviteType>)
}
}

export const inviteReceived = async (inviteService: InviteService, query) => {
const identityProviders = (await inviteService.app.service(identityProviderPath).find({
export const inviteReceived = async (app: Application, query) => {
const identityProviders = (await app.service(identityProviderPath)._find({
query: {
userId: query.userId
}
Expand Down Expand Up @@ -112,7 +113,7 @@ export const inviteReceived = async (inviteService: InviteService, query) => {

delete query.type
delete query.search
return (await inviteService._find({
return (await app.service(invitePath)._find({
query: {
...query,
$or: [
Expand All @@ -129,7 +130,7 @@ export const inviteReceived = async (inviteService: InviteService, query) => {
})) as Paginated<InviteType>
}

export const inviteSent = async (inviteService: InviteService, query: Query) => {
export const inviteSent = async (app: Application, query: Query) => {
const { search } = query

if (search) {
Expand All @@ -152,15 +153,15 @@ export const inviteSent = async (inviteService: InviteService, query: Query) =>

delete query.type
delete query.search
return (await inviteService._find({
return (await app.service(invitePath)._find({
query: {
...query,
userId: query.userId
}
})) as Paginated<InviteType>
}

export const inviteAll = async (inviteService: InviteService, query: Query, user: UserType) => {
export const inviteAll = async (app: Application, query: Query, user: UserType) => {
if ((!user || !user.scopes || !user.scopes.find((scope) => scope.type === 'admin:admin')) && !query.existenceCheck)
throw new Forbidden('Must be admin to search invites in this way')

Expand All @@ -186,7 +187,7 @@ export const inviteAll = async (inviteService: InviteService, query: Query, user
if (!query.existenceCheck) delete query.userId
delete query.existenceCheck
delete query.search
return (await inviteService.find({
return (await app.service(invitePath)._find({
query: {
// userId: query.userId,
...query
Expand Down Expand Up @@ -235,11 +236,11 @@ export class InviteService<T = InviteType, ServiceParams extends Params = Invite
if (params && params.query) {
const query = params.query
if (query.type === 'received') {
result = await inviteReceived(this, query)
result = await inviteReceived(this.app, query)
} else if (query.type === 'sent') {
result = await inviteSent(this, query)
result = await inviteSent(this.app, query)
} else {
result = await inviteAll(this, query, params.user!)
result = await inviteAll(this.app, query, params.user!)
}
} else {
result = (await super._find(params)) as Paginated<InviteType>
Expand Down
Loading

0 comments on commit 0c0e717

Please sign in to comment.