diff --git a/packages/client-core/src/social/services/InviteService.ts b/packages/client-core/src/social/services/InviteService.ts index 8d1f848056..499dfc0980 100644 --- a/packages/client-core/src/social/services/InviteService.ts +++ b/packages/client-core/src/social/services/InviteService.ts @@ -146,7 +146,7 @@ export const InviteService = { try { const existingInviteResult = (await Engine.instance.api.service(invitePath).find({ - query: data + query: { ...data, action: 'sent' } })) as Paginated let inviteResult diff --git a/packages/common/src/interfaces/UploadAssetInterface.ts b/packages/common/src/interfaces/UploadAssetInterface.ts index 7f9bec8ec0..5a8efa9163 100644 --- a/packages/common/src/interfaces/UploadAssetInterface.ts +++ b/packages/common/src/interfaces/UploadAssetInterface.ts @@ -36,6 +36,7 @@ export type AvatarUploadType = { type: 'user-avatar-upload' files: (Blob | Buffer)[] userId?: UserID + path?: string args: string | AvatarUploadArgsType } diff --git a/packages/engine/src/avatar/state/AvatarNetworkState.tsx b/packages/engine/src/avatar/state/AvatarNetworkState.tsx index 74dd02877f..0da36f6615 100644 --- a/packages/engine/src/avatar/state/AvatarNetworkState.tsx +++ b/packages/engine/src/avatar/state/AvatarNetworkState.tsx @@ -131,7 +131,7 @@ const AvatarReactor = React.memo(({ entityUUID }: { entityUUID: EntityUUID }) => }, [entityUUID]) useEffect(() => { - if (!state.avatarID.value) return + if (!isClient || !state.avatarID.value) return let aborted = false diff --git a/packages/engine/src/recording/ECSRecordingSystem.ts b/packages/engine/src/recording/ECSRecordingSystem.ts index a1f8a8b226..88ffd5d0f0 100644 --- a/packages/engine/src/recording/ECSRecordingSystem.ts +++ b/packages/engine/src/recording/ECSRecordingSystem.ts @@ -476,9 +476,7 @@ export const onStartRecording = async (action: ReturnType resource.key.substring(resource.key.length - 3, resource.key.length) !== '.ee' - ) - const entityChunks = (await Promise.all( entityFiles.map(async (resource) => { const data = await fetch(resource.url) diff --git a/packages/engine/src/schemas/recording/recording-resource-upload.schema.ts b/packages/engine/src/schemas/recording/recording-resource-upload.schema.ts new file mode 100644 index 0000000000..12abff90ee --- /dev/null +++ b/packages/engine/src/schemas/recording/recording-resource-upload.schema.ts @@ -0,0 +1,28 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + +export const recordingResourceUploadPath = 'recording-resource-upload' + +export const recordingResourceUploadMethods = ['create'] as const diff --git a/packages/instanceserver/src/MediasoupRecordingSystem.ts b/packages/instanceserver/src/MediasoupRecordingSystem.ts index 67a2a47092..dddab136f0 100644 --- a/packages/instanceserver/src/MediasoupRecordingSystem.ts +++ b/packages/instanceserver/src/MediasoupRecordingSystem.ts @@ -43,12 +43,9 @@ import { DataChannelType } from '@etherealengine/common/src/interfaces/DataChann import { PresentationSystemGroup } from '@etherealengine/engine/src/ecs/functions/EngineFunctions' import { defineSystem } from '@etherealengine/engine/src/ecs/functions/SystemFunctions' import { RecordingAPIState } from '@etherealengine/engine/src/recording/ECSRecordingSystem' -import { staticResourcePath } from '@etherealengine/engine/src/schemas/media/static-resource.schema' -import { recordingResourcePath } from '@etherealengine/engine/src/schemas/recording/recording-resource.schema' +import { recordingResourceUploadPath } from '@etherealengine/engine/src/schemas/recording/recording-resource-upload.schema' import { RecordingID, RecordingSchemaType } from '@etherealengine/engine/src/schemas/recording/recording.schema' import { getMutableState, none } from '@etherealengine/hyperflux' -import { getCachedURL } from '@etherealengine/server-core/src/media/storageprovider/getCachedURL' -import { getStorageProvider } from '@etherealengine/server-core/src/media/storageprovider/storageprovider' import { PassThrough } from 'stream' import { startFFMPEG } from './FFMPEG' import { SocketWebRTCServerNetwork } from './SocketWebRTCServerFunctions' @@ -212,43 +209,9 @@ type onUploadPartArgs = { hash: string } -export const uploadMediaStaticResource = async (props: onUploadPartArgs) => { - const api = Engine.instance.api - - const storageProvider = getStorageProvider() - - const uploadPromise = storageProvider.putObject({ - Key: props.key, - Body: props.body, - ContentType: props.mimeType - }) - - const url = getCachedURL(props.key, storageProvider.cacheDomain) - - const staticResource = await api.service(staticResourcePath).create( - { - hash: props.hash, - key: props.key, - url, - mimeType: props.mimeType - }, - { isInternal: true } - ) - - const recordingResource = await api.service(recordingResourcePath).create({ - recordingId: props.recordingID, - staticResourceId: staticResource.id - }) - - await uploadPromise - - await api.service(recordingResourcePath).patch(recordingResource.id, { - updatedAt: new Date().toISOString().slice(0, 19).replace('T', ' ') - }) -} - // todo - refactor to be in a reactor such that we can record media tracks that are started after the recording is export const startMediaRecording = async (recordingID: RecordingID, schema: RecordingSchemaType['peers']) => { + const api = Engine.instance.api const network = NetworkState.mediaNetwork as SocketWebRTCServerNetwork const mediaStreams = {} as Record @@ -295,15 +258,18 @@ export const startMediaRecording = async (recordingID: RecordingID, schema: Reco .update(format) .digest('hex') - return uploadMediaStaticResource({ - recordingID, - key, - body: stream, - mimeType: format, - hash - }).then(() => { - logger.info('Uploaded media file' + key) - }) + return api + .service(recordingResourceUploadPath) + .create({ + recordingID, + key, + body: stream, + mimeType: format, + hash + }) + .then(() => { + logger.info('Uploaded media file' + key) + }) }) logger.info('media recording started') diff --git a/packages/instanceserver/src/ServerHostNetworkSystem.tsx b/packages/instanceserver/src/ServerHostNetworkSystem.tsx index 4fbef2d173..6eccf0f913 100644 --- a/packages/instanceserver/src/ServerHostNetworkSystem.tsx +++ b/packages/instanceserver/src/ServerHostNetworkSystem.tsx @@ -29,17 +29,13 @@ import { updatePeers } from '@etherealengine/engine/src/networking/systems/Outgo import { useEffect } from 'react' import { RecordingAPIState } from '@etherealengine/engine/src/recording/ECSRecordingSystem' -import { staticResourcePath } from '@etherealengine/engine/src/schemas/media/static-resource.schema' -import { recordingResourcePath } from '@etherealengine/engine/src/schemas/recording/recording-resource.schema' import { RecordingID } from '@etherealengine/engine/src/schemas/recording/recording.schema' import { getMutableState, none } from '@etherealengine/hyperflux' import { PeerID } from '@etherealengine/common/src/interfaces/PeerID' import { SimulationSystemGroup } from '@etherealengine/engine/src/ecs/functions/EngineFunctions' import { NetworkState } from '@etherealengine/engine/src/networking/NetworkState' -import { getCachedURL } from '@etherealengine/server-core/src/media/storageprovider/getCachedURL' -import { getStorageProvider } from '@etherealengine/server-core/src/media/storageprovider/storageprovider' -import { createStaticResourceHash } from '@etherealengine/server-core/src/media/upload-asset/upload-asset.service' +import { recordingResourceUploadPath } from '@etherealengine/engine/src/schemas/recording/recording-resource-upload.schema' import { SocketWebRTCServerNetwork } from './SocketWebRTCServerFunctions' export async function validateNetworkObjects(network: SocketWebRTCServerNetwork): Promise { @@ -67,30 +63,11 @@ export const uploadRecordingStaticResource = async (props: { }) => { const api = Engine.instance.api - const storageProvider = getStorageProvider() - await storageProvider.putObject({ - Key: props.key, - Body: props.body, - ContentType: props.mimeType - }) - - const provider = getStorageProvider() - const url = getCachedURL(props.key, provider.cacheDomain) - const hash = createStaticResourceHash(props.body, { mimeType: props.mimeType, assetURL: props.key }) - - const staticResource = await api.service(staticResourcePath).create( - { - hash, - key: props.key, - url, - mimeType: props.mimeType - }, - { isInternal: true } - ) - - await api.service(recordingResourcePath).create({ - staticResourceId: staticResource.id, - recordingId: props.recordingID + await api.service(recordingResourceUploadPath).create({ + recordingID: props.recordingID, + key: props.key, + body: props.body, + mimeType: props.mimeType }) } diff --git a/packages/instanceserver/src/SocketFunctions.ts b/packages/instanceserver/src/SocketFunctions.ts index c80479a6c5..5e347db17a 100644 --- a/packages/instanceserver/src/SocketFunctions.ts +++ b/packages/instanceserver/src/SocketFunctions.ts @@ -58,7 +58,6 @@ export const setupSocketFunctions = async (app: Application, spark: any) => { const network = getServerNetwork(app) const onAuthenticationRequest = async (data) => { - console.log(data) const peerID = data.peerID if (authTask) return @@ -90,7 +89,7 @@ export const setupSocketFunctions = async (app: Application, spark: any) => { {} ) userId = authResult[identityProviderPath].userId as UserID - user = await app.service(userPath).get(userId) + user = await app.service(userPath).get(userId, { headers: spark.headers }) if (!user) { authTask.status = 'fail' diff --git a/packages/instanceserver/src/channels.ts b/packages/instanceserver/src/channels.ts index e297634c13..2699bf23ad 100755 --- a/packages/instanceserver/src/channels.ts +++ b/packages/instanceserver/src/channels.ts @@ -72,7 +72,7 @@ const logger = multiLogger.child({ component: 'instanceserver:channels' }) interface PrimusConnectionType { provider: string - headers: any + headers: object socketQuery?: NetworkConnectionParams & { EIO: string transport: string @@ -96,6 +96,7 @@ interface InstanceserverStatus { * If it is a location instance, creates a 'channel' entry * @param app * @param newInstance + * @param headers */ const createNewInstance = async (app: Application, newInstance: InstanceData, headers: object) => { const { locationId, channelId } = newInstance @@ -119,15 +120,22 @@ const createNewInstance = async (app: Application, newInstance: InstanceData, he * @param existingInstance * @param channelId * @param locationId + * @param headers */ -const assignExistingInstance = async ( - app: Application, - existingInstance: InstanceType, - channelId: ChannelID, - locationId: LocationID, +const assignExistingInstance = async ({ + app, + existingInstance, + channelId, + headers, + locationId +}: { + app: Application + existingInstance: InstanceType + channelId: ChannelID + locationId: LocationID headers: object -) => { +}) => { const serverState = getState(ServerState) const instanceServerState = getMutableState(InstanceServerState) @@ -154,18 +162,26 @@ const assignExistingInstance = async ( * @param status * @param locationId * @param channelId + * @param headers * @param userId * @returns */ -const initializeInstance = async ( - app: Application, - headers: object, - status: InstanceserverStatus, - locationId: LocationID, - channelId: ChannelID, +const initializeInstance = async ({ + app, + status, + locationId, + channelId, + headers, + userId +}: { + app: Application + status: InstanceserverStatus + locationId: LocationID + channelId: ChannelID + headers: object userId?: UserID -) => { +}) => { logger.info('Initializing new instance') const serverState = getState(ServerState) @@ -211,7 +227,8 @@ const initializeInstance = async ( query: { instanceId: instance.id, $limit: 1 - } + }, + headers })) as Paginated if (existingChannel.total === 0) { await app.service(channelPath).create({ @@ -222,7 +239,13 @@ const initializeInstance = async ( await serverState.agonesSDK.allocate() if (!instanceServerState.instance.value) instanceServerState.instance.set(instance) if (userId && !(await authorizeUserToJoinServer(app, instance, userId))) return - await assignExistingInstance(app, instance, channelId, locationId, headers) + await assignExistingInstance({ + app, + existingInstance: instance, + channelId, + headers, + locationId + }) } } @@ -230,9 +253,10 @@ const initializeInstance = async ( * Creates and initializes the server network and transport, then loads all systems for the engine * @param app * @param sceneId + * @param headers */ -const loadEngine = async (app: Application, sceneId?: SceneID) => { +const loadEngine = async ({ app, sceneId, headers }: { app: Application; sceneId?: SceneID; headers?: object }) => { const instanceServerState = getState(InstanceServerState) const hostId = instanceServerState.instance.id as UserID & InstanceID @@ -264,7 +288,9 @@ const loadEngine = async (app: Application, sceneId?: SceneID) => { if (!sceneId) throw new Error('No sceneId provided') const sceneUpdatedListener = async () => { - const sceneData = await app.service(scenePath).get(null, { query: { sceneKey: sceneId, metadataOnly: false } }) + const sceneData = await app + .service(scenePath) + .get(null, { query: { sceneKey: sceneId, metadataOnly: false }, headers }) SceneState.loadScene(sceneId, sceneData) getMutableState(SceneState).activeScene.set(sceneId) /** @todo - quick hack to wait until scene has loaded */ @@ -301,16 +327,18 @@ const loadEngine = async (app: Application, sceneId?: SceneID) => { * Update instance attendance with the new user for analytics purposes * @param app * @param userId + * @param headers */ -const handleUserAttendance = async (app: Application, userId: UserID) => { +const handleUserAttendance = async (app: Application, userId: UserID, headers: object) => { const instanceServerState = getState(InstanceServerState) const channel = (await app.service(channelPath).find({ query: { instanceId: instanceServerState.instance.id, $limit: 1 - } + }, + headers })) as Paginated /** Only a world server gets assigned a channel, since it has chat. A media server uses a channel but does not have one itself */ @@ -319,7 +347,8 @@ const handleUserAttendance = async (app: Application, userId: UserID) => { query: { channelId: channel.data[0].id, userId: userId - } + }, + headers })) as Paginated if (!existingChannelUser.total) { @@ -350,7 +379,7 @@ const handleUserAttendance = async (app: Application, userId: UserID) => { userId: userId } if (!instanceServerState.isMediaInstance) { - const location = await app.service(locationPath).get(instanceServerState.instance.locationId!) + const location = await app.service(locationPath).get(instanceServerState.instance.locationId!, { headers }) ;(newInstanceAttendance as any).sceneId = location.sceneId } await app.service(instanceAttendancePath).create(newInstanceAttendance as any) @@ -365,18 +394,27 @@ let instanceStarted = false * @param locationId * @param channelId * @param sceneId + * @param headers * @param userId * @returns */ -const createOrUpdateInstance = async ( - app: Application, - headers: object, - status: InstanceserverStatus, - locationId: LocationID, - channelId: ChannelID, - sceneId?: SceneID, +const createOrUpdateInstance = async ({ + app, + status, + locationId, + channelId, + sceneId, + headers, + userId +}: { + app: Application + status: InstanceserverStatus + locationId: LocationID + channelId: ChannelID + sceneId?: SceneID + headers: object userId?: UserID -) => { +}) => { const instanceServerState = getState(InstanceServerState) const serverState = getState(ServerState) @@ -390,8 +428,8 @@ const createOrUpdateInstance = async ( if (isReady || isNeedingNewServer) { instanceStarted = true - await initializeInstance(app, headers, status, locationId, channelId, userId) - await loadEngine(app, sceneId) + await initializeInstance({ app, status, locationId, channelId, headers, userId }) + await loadEngine({ app, sceneId, headers }) } else { try { if (!getState(InstanceServerState).ready) @@ -422,7 +460,7 @@ const createOrUpdateInstance = async ( } } -const shutdownServer = async (app: Application, connection: PrimusConnectionType, instanceId: InstanceID) => { +const shutdownServer = async (app: Application, instanceId: InstanceID, headers: object) => { const instanceServer = getState(InstanceServerState) const serverState = getState(ServerState) @@ -436,16 +474,21 @@ const shutdownServer = async (app: Application, connection: PrimusConnectionType { ended: true }, - { headers: connection.headers } + { headers } ) if (instanceServer.instance.locationId) { const channel = (await app.service(channelPath).find({ query: { instanceId: instanceServer.instance.id, $limit: 1 - } + }, + headers })) as Paginated - await app.service(channelPath).remove(channel.data[0].id) + try { + await app.service(channelPath).remove(channel.data[0].id) + } catch (err) { + //If something else has removed the channel between lookup and now, just ignore the error. + } } } catch (err) { logger.error(err) @@ -477,12 +520,19 @@ const getActiveUsersCount = (app: Application, userToIgnore: UserType) => { return activeUsers.length } -const handleUserDisconnect = async ( - app: Application, - connection: PrimusConnectionType, - user: UserType, +const handleUserDisconnect = async ({ + app, + connection, + user, + instanceId, + headers +}: { + app: Application + connection: PrimusConnectionType + user: UserType instanceId: InstanceID -) => { + headers: object +}) => { const instanceServerState = getState(InstanceServerState) try { @@ -492,7 +542,7 @@ const handleUserDisconnect = async ( { currentUsers: activeUsersCount }, - { headers: connection.headers } + { headers } ) } catch (err) { logger.info('Failed to patch instance user count, likely because it was destroyed.') @@ -522,7 +572,7 @@ const handleUserDisconnect = async ( // 0 if the serer was just starting when someone connected and disconnected) if (Object.keys(network.peers).length <= 1) { logger.info('Shutting down instance server as there are no users present.') - await shutdownServer(app, connection, instanceId) + await shutdownServer(app, instanceId, connection.headers) } } @@ -644,14 +694,22 @@ const onConnection = (app: Application) => async (connection: PrimusConnectionTy const isResult = await serverState.agonesSDK.getGameServer() const status = isResult.status as InstanceserverStatus - await createOrUpdateInstance(app, connection.headers, status, locationId, channelId, sceneID, userId) + await createOrUpdateInstance({ + app, + status, + locationId, + channelId, + sceneId: sceneID, + headers: connection.headers, + userId + }) if (instanceServerState.instance) { connection.instanceId = instanceServerState.instance.id app.channel(`instanceIds/${instanceServerState.instance.id}`).join(connection) } - await handleUserAttendance(app, userId) + await handleUserAttendance(app, userId, connection.headers) } const onDisconnection = (app: Application) => async (connection: PrimusConnectionType) => { @@ -677,7 +735,7 @@ const onDisconnection = (app: Application) => async (connection: PrimusConnectio const identityProvider = authResult[identityProviderPath] as IdentityProviderType if (identityProvider != null && identityProvider.id != null) { const userId = identityProvider.userId - const user = await app.service(userPath).get(userId) + const user = await app.service(userPath).get(userId, { headers: connection.headers }) const instanceId = !config.kubernetes.enabled ? connection.instanceId : instanceServerState.instance?.id let instance logger.info('On disconnect, instanceId: ' + instanceId) @@ -701,7 +759,13 @@ const onDisconnection = (app: Application) => async (connection: PrimusConnectio } logger.info('instanceId %s instance %o', instanceId, instance) if (instanceId != null && instance != null) { - await handleUserDisconnect(app, connection, user, instanceId) + await handleUserDisconnect({ + app, + connection, + user, + instanceId, + headers: connection.headers + }) } } } @@ -737,7 +801,14 @@ export default (app: Application): void => { return } - createOrUpdateInstance(app, params.headers, status, locationId, null!, sceneId) + await createOrUpdateInstance({ + app, + status, + locationId, + channelId: null!, + headers: params.headers, + sceneId + }) }) const kickCreatedListener = async (data: UserKickType) => { diff --git a/packages/server-core/src/cluster/pods/pods-helper.ts b/packages/server-core/src/cluster/pods/pods-helper.ts index 2e3ba59543..c390cbd419 100644 --- a/packages/server-core/src/cluster/pods/pods-helper.ts +++ b/packages/server-core/src/cluster/pods/pods-helper.ts @@ -166,7 +166,7 @@ export const getPodsData = async ( } } -const getGameserversData = async (labelSelector: string, id: string, label: string, app: Application) => { +const getGameserversData = async (labelSelector: string, id: string, label: string) => { let gameservers: ServerPodInfoType[] = [] try { diff --git a/packages/server-core/src/cluster/pods/pods.class.ts b/packages/server-core/src/cluster/pods/pods.class.ts index 615afb23a4..eeb37cf587 100644 --- a/packages/server-core/src/cluster/pods/pods.class.ts +++ b/packages/server-core/src/cluster/pods/pods.class.ts @@ -60,7 +60,7 @@ export class PodsService implements ServiceInterface { return async (context: HookContext): Promise => { let inviteIdentityProviderUser - // Getting logged in user and attaching owner of user + // Getting logged-in user and attaching owner of user const { id, params, app } = context const loggedInUser = params.user as UserType const invite = await app.service(invitePath).get(id!) diff --git a/packages/server-core/src/hooks/is-scope.ts b/packages/server-core/src/hooks/is-scope.ts index 0b06a7342e..766d74d1a7 100644 --- a/packages/server-core/src/hooks/is-scope.ts +++ b/packages/server-core/src/hooks/is-scope.ts @@ -47,9 +47,6 @@ export default (currentType: string, scopeToVerify: string) => { if (sc.type.split(':')[0] === currentType) result.push(sc.type.split(':')[1]) return result }, []) - if (!currentScopes.includes(scopeToVerify)) { - return false - } - return true + return currentScopes.includes(scopeToVerify) } } diff --git a/packages/server-core/src/hooks/persist-headers.ts b/packages/server-core/src/hooks/persist-headers.ts index 753da1ce72..5d32c3cb3b 100644 --- a/packages/server-core/src/hooks/persist-headers.ts +++ b/packages/server-core/src/hooks/persist-headers.ts @@ -28,7 +28,7 @@ import { HookContext, NextFunction } from '@feathersjs/feathers' import { AsyncLocalStorage } from 'async_hooks' import { Application } from '../../declarations' -export const asyncLocalStorage = new AsyncLocalStorage<{ headers: any }>() +export const asyncLocalStorage = new AsyncLocalStorage<{ headers: object }>() /** * https://github.com/feathersjs-ecosystem/dataloader/blob/main/docs/guide.md diff --git a/packages/server-core/src/hooks/send-invite.ts b/packages/server-core/src/hooks/send-invite.ts index d782edd8f9..6a46ab1235 100755 --- a/packages/server-core/src/hooks/send-invite.ts +++ b/packages/server-core/src/hooks/send-invite.ts @@ -59,14 +59,21 @@ export function getInviteLink(type: string, id: string, passcode: string): strin return `${config.server.url}/${acceptInvitePath}/${id}?t=${passcode}` } -async function generateEmail( - app: Application, - result: InviteType, - toEmail: string, - inviteType: string, - inviterUsername: string, +async function generateEmail({ + app, + result, + toEmail, + inviteType, + inviterUsername, + targetObjectId +}: { + app: Application + result: InviteType + toEmail: string + inviteType: string + inviterUsername: string targetObjectId?: string -): Promise { +}): Promise { if (config.testEnabled) { return } @@ -88,8 +95,7 @@ async function generateEmail( if (inviteType === 'instance') { const instance = await app.service(instancePath).get(targetObjectId!) - const location = await app.service(locationPath).get(instance.locationId!) - locationName = location.name + locationName = instance.location.name } const compiledHTML = pug.compileFile(templatePath)({ @@ -112,20 +118,28 @@ async function generateEmail( await app.service(emailPath).create(email) } -async function generateSMS( - app: Application, - result: InviteType, - mobile: string, - inviteType: string, - inviterUsername: string, +async function generateSMS({ + app, + result, + mobile, + inviteType, + inviterUsername, + targetObjectId +}: { + app: Application + result: InviteType + mobile: string + inviteType: string + inviterUsername: string targetObjectId?: string -): Promise { +}): Promise { if (config.testEnabled) { return } let channelName, locationName const hashLink = getInviteLink(inviteType, result.id, result.passcode!) + if (inviteType === 'channel') { const channel = await app.service(channelPath).get(targetObjectId! as ChannelID) channelName = channel.name @@ -138,8 +152,7 @@ async function generateSMS( if (inviteType === 'instance') { const instance = await app.service(instancePath).get(targetObjectId!) - const location = await app.service(locationPath).get(instance.locationId!) - locationName = location.name + locationName = instance.location.name } const templatePath = path.join(emailAccountTemplatesPath, `magiclink-sms-invite-${inviteType}.pug`) const compiledHTML = pug @@ -180,9 +193,23 @@ export const sendInvite = async (context: HookContext) => { const authUser = params.user as UserType if (result.identityProviderType === 'email') { - await generateEmail(app, result, token, inviteType, authUser.name, targetObjectId) + await generateEmail({ + app, + result, + toEmail: token, + inviteType, + inviterUsername: authUser.name, + targetObjectId + }) } else if (result.identityProviderType === 'sms') { - await generateSMS(app, result, token, inviteType, authUser.name, targetObjectId) + await generateSMS({ + app, + result, + mobile: token, + inviteType, + inviterUsername: authUser.name, + targetObjectId + }) } else if (result.inviteeId != null) { if (inviteType === 'friend') { const existingRelationshipStatus = await app.service(userRelationshipPath).find({ @@ -219,14 +246,14 @@ export const sendInvite = async (context: HookContext) => { })) as Paginated if (emailIdentityProviderResult.total > 0) { - await generateEmail( + await generateEmail({ app, result, - emailIdentityProviderResult.data[0].token, + toEmail: emailIdentityProviderResult.data[0].token, inviteType, - authUser.name, + inviterUsername: authUser.name, targetObjectId - ) + }) } else { const SMSIdentityProviderResult = (await app.service(identityProviderPath).find({ query: { @@ -236,14 +263,14 @@ export const sendInvite = async (context: HookContext) => { })) as Paginated if (SMSIdentityProviderResult.total > 0) { - await generateSMS( + await generateSMS({ app, result, - SMSIdentityProviderResult.data[0].token, + mobile: SMSIdentityProviderResult.data[0].token, inviteType, - authUser.name, + inviterUsername: authUser.name, targetObjectId - ) + }) } } } diff --git a/packages/server-core/src/media/file-browser/file-browser.class.ts b/packages/server-core/src/media/file-browser/file-browser.class.ts index 9412dcfa1c..a9c64e3d70 100755 --- a/packages/server-core/src/media/file-browser/file-browser.class.ts +++ b/packages/server-core/src/media/file-browser/file-browser.class.ts @@ -54,8 +54,11 @@ export interface FileBrowserParams extends KnexAdapterParams { } const checkDirectoryInsideNesting = (directory: string, nestingDirectory?: string) => { - if (!nestingDirectory) nestingDirectory = 'projects' - const isInsideNestingDirectoryRegex = new RegExp(`(${nestingDirectory})(/).+`, 'g') + if (!nestingDirectory) { + if (/recordings/.test(directory)) nestingDirectory = 'recordings' + else nestingDirectory = 'projects' + } + const isInsideNestingDirectoryRegex = new RegExp(`^\/?(${nestingDirectory})`, 'g') if (!isInsideNestingDirectoryRegex.test(directory)) { throw new Error(`Not allowed to access "${directory}"`) @@ -243,6 +246,7 @@ export class FileBrowserService await this.app.service(staticResourcePath).patch( resource.id, { + key, url }, { isInternal: true } diff --git a/packages/server-core/src/media/upload-asset/upload-asset.service.ts b/packages/server-core/src/media/upload-asset/upload-asset.service.ts index 49b7c9eddf..d4e03e2131 100755 --- a/packages/server-core/src/media/upload-asset/upload-asset.service.ts +++ b/packages/server-core/src/media/upload-asset/upload-asset.service.ts @@ -177,15 +177,14 @@ const uploadAssets = (app: Application) => async (data: AssetUploadType, params: if (typeof data.args === 'string') data.args = JSON.parse(data.args) const files = params.files if (data.type === 'user-avatar-upload') { - return await uploadAvatarStaticResource( - app, - { - avatar: files[0].buffer as Buffer, - thumbnail: files[1].buffer as Buffer, - ...(data.args as AvatarUploadArgsType) - }, - params - ) + const callData = { + avatar: files[0].buffer as Buffer, + thumbnail: files[1].buffer as Buffer, + ...(data.args as AvatarUploadArgsType) + } as any + if (data.path) callData.path = data.path + + return await uploadAvatarStaticResource(app, callData, params) } else if (data.type === 'admin-file-upload') { if (!(await verifyScope('admin', 'admin')({ app, params } as any))) throw new Error('Unauthorized') @@ -304,7 +303,6 @@ export default (app: Application): void => { before: [ multipartMiddleware.any(), async (ctx, next) => { - const files = ctx.request.files if (ctx?.feathers && ctx.method !== 'GET') { ctx.feathers.headers = ctx.headers ;(ctx as any).feathers.files = (ctx as any).request.files.media diff --git a/packages/server-core/src/networking/instance/instance.ts b/packages/server-core/src/networking/instance/instance.ts index 437674d037..7860530d44 100755 --- a/packages/server-core/src/networking/instance/instance.ts +++ b/packages/server-core/src/networking/instance/instance.ts @@ -23,7 +23,7 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ -import { Application } from '../../../declarations' +import { Application, HookContext } from '../../../declarations' import { instanceMethods, @@ -70,14 +70,15 @@ export default (app: Application): void => { * @param data * @returns deleted channel */ - service.publish('removed', async (data): Promise => { + service.publish('removed', async (data, context: HookContext): Promise => { try { const adminScopes = (await app.service(scopePath).find({ query: { type: 'admin:admin' as ScopeType }, + headers: context.params.headers, paginate: false - })) as ScopeTypeInterface[] + })) as unknown as ScopeTypeInterface[] const targetIds = adminScopes.map((admin) => admin.userId) // eslint-disable-next-line @typescript-eslint/restrict-template-expressions diff --git a/packages/server-core/src/projects/project/project-helper.ts b/packages/server-core/src/projects/project/project-helper.ts index 191dc4a25e..f69872d9c7 100644 --- a/packages/server-core/src/projects/project/project-helper.ts +++ b/packages/server-core/src/projects/project/project-helper.ts @@ -1275,7 +1275,7 @@ export const checkProjectAutoUpdate = async (app: Application, projectName: stri const project = projectData.data[0] - const user = await app.service(userPath).get(project.updateUserId!) + const user = await app.service(userPath)._get(project.updateUserId!) if (project.updateType === 'tag') { const latestTaggedCommit = await getLatestProjectTaggedCommitInBranch( app, diff --git a/packages/server-core/src/projects/scene/scene.ts b/packages/server-core/src/projects/scene/scene.ts index b2b4d44466..efd292fec5 100644 --- a/packages/server-core/src/projects/scene/scene.ts +++ b/packages/server-core/src/projects/scene/scene.ts @@ -56,7 +56,7 @@ export default (app: Application): void => { service.hooks(hooks) if (getState(ServerState).serverMode === ServerMode.API) - service.publish('updated', async (data, context) => { + service.publish('updated', async (data) => { const updatedScene = data as SceneUpdate const instanceActive = await app.service(instanceActivePath).find({ query: { sceneId: updatedScene.id as SceneID } diff --git a/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.class.ts b/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.class.ts new file mode 100755 index 0000000000..b625cc2691 --- /dev/null +++ b/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.class.ts @@ -0,0 +1,85 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + +import { ServiceInterface } from '@feathersjs/feathers/lib/declarations' + +import { staticResourcePath } from '@etherealengine/engine/src/schemas/media/static-resource.schema' +import { recordingResourcePath } from '@etherealengine/engine/src/schemas/recording/recording-resource.schema' +import { KnexAdapterParams } from '@feathersjs/knex' +import { Application } from '../../../declarations' +import { getCachedURL } from '../../media/storageprovider/getCachedURL' +import { getStorageProvider } from '../../media/storageprovider/storageprovider' +import { createStaticResourceHash } from '../../media/upload-asset/upload-asset.service' +import { getDateTimeSql } from '../../util/datetime-sql' + +export interface RecordingResourceUploadParams extends KnexAdapterParams {} + +/** + * A class for File Browser Upload service + */ +export class RecordingResourceUploadService implements ServiceInterface { + app: Application + + constructor(app: Application) { + this.app = app + } + + async create(data: any, params?: RecordingResourceUploadParams) { + const { key, body, mimeType, recordingID, hash } = data + + const storageProvider = getStorageProvider() + + const uploadPromise = storageProvider.putObject({ + Key: key, + Body: body, + ContentType: mimeType + }) + + const url = getCachedURL(key, storageProvider.cacheDomain) + const localHash = hash || createStaticResourceHash(body, { mimeType: mimeType, assetURL: key }) + + const staticResource = await this.app.service(staticResourcePath).create( + { + hash: localHash, + key: key, + url, + mimeType: mimeType + }, + { isInternal: true } + ) + + const recordingResource = await this.app.service(recordingResourcePath).create({ + recordingId: recordingID, + staticResourceId: staticResource.id + }) + + const updatedAt = await getDateTimeSql() + await uploadPromise + + await this.app.service(recordingResourcePath).patch(recordingResource.id, { + updatedAt + }) + } +} diff --git a/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.docs.ts b/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.docs.ts new file mode 100755 index 0000000000..1c1a2d64d1 --- /dev/null +++ b/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.docs.ts @@ -0,0 +1,34 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + +import { createSwaggerServiceOptions } from 'feathers-swagger' + +export default createSwaggerServiceOptions({ + schemas: {}, + docs: { + description: 'Recording Resource Update service description', + securities: ['all'] + } +}) diff --git a/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.hooks.ts b/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.hooks.ts new file mode 100755 index 0000000000..0bc6787fe0 --- /dev/null +++ b/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.hooks.ts @@ -0,0 +1,63 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + +import { disallow } from 'feathers-hooks-common' +import { SYNC } from 'feathers-sync' + +export default { + before: { + all: [], + find: [disallow()], + get: [disallow()], + create: [ + disallow('external'), + (context) => { + context[SYNC] = false + return context + } + ], + update: [disallow()], + patch: [disallow()], + remove: [disallow()] + }, + after: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + }, + error: { + all: [], + find: [], + get: [], + create: [], + update: [], + patch: [], + remove: [] + } +} as any diff --git a/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.ts b/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.ts new file mode 100755 index 0000000000..d1b763f2b4 --- /dev/null +++ b/packages/server-core/src/recording/recording-resource-upload/recording-resource-upload.ts @@ -0,0 +1,52 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + +import { + recordingResourceUploadMethods, + recordingResourceUploadPath +} from '@etherealengine/engine/src/schemas/recording/recording-resource-upload.schema' +import { Application } from '../../../declarations' +import { RecordingResourceUploadService } from './recording-resource-upload.class' +import RecordingResourceUploadDocs from './recording-resource-upload.docs' +import hooks from './recording-resource-upload.hooks' + +declare module '@etherealengine/common/declarations' { + interface ServiceTypes { + [recordingResourceUploadPath]: RecordingResourceUploadService + } +} + +export default (app: Application): void => { + app.use(recordingResourceUploadPath, new RecordingResourceUploadService(app), { + // A list of all methods this service exposes externally + methods: recordingResourceUploadMethods, + // You can add additional custom events to be sent to clients here + events: [], + docs: RecordingResourceUploadDocs + }) + + const service = app.service(recordingResourceUploadPath) + service.hooks(hooks) +} diff --git a/packages/server-core/src/recording/recording/recording.resolvers.ts b/packages/server-core/src/recording/recording/recording.resolvers.ts index 1acc51c8bf..b4287fc4fc 100644 --- a/packages/server-core/src/recording/recording/recording.resolvers.ts +++ b/packages/server-core/src/recording/recording/recording.resolvers.ts @@ -29,7 +29,10 @@ import { v4 } from 'uuid' import type { HookContext } from '@etherealengine/server-core/declarations' -import { recordingResourcePath } from '@etherealengine/engine/src/schemas/recording/recording-resource.schema' +import { + recordingResourcePath, + RecordingResourceType +} from '@etherealengine/engine/src/schemas/recording/recording-resource.schema' import { RecordingDatabaseType, RecordingID, @@ -58,12 +61,12 @@ export const recordingDbToSchema = (rawData: RecordingDatabaseType): RecordingTy export const recordingResolver = resolve( { resources: virtual(async (recording, context) => { - const recordingResources = await context.app.service(recordingResourcePath).find({ + const recordingResources = (await context.app.service(recordingResourcePath).find({ query: { recordingId: recording.id }, paginate: false - }) + })) as RecordingResourceType[] return recordingResources.map((resource) => resource.staticResource) }), @@ -77,7 +80,7 @@ export const recordingResolver = resolve( }, { // Convert the raw data into a new structure before running property resolvers - converter: async (rawData, context) => { + converter: async (rawData) => { return recordingDbToSchema(rawData) } } @@ -95,7 +98,7 @@ export const recordingDataResolver = resolve }, { // Convert the raw data into a new structure before running property resolvers - converter: async (rawData, context) => { + converter: async (rawData) => { return { ...rawData, schema: JSON.stringify(rawData.schema) @@ -110,7 +113,7 @@ export const recordingPatchResolver = resolve( }, { // Convert the raw data into a new structure before running property resolvers - converter: async (rawData, context) => { + converter: async (rawData) => { return { ...rawData, schema: JSON.stringify(rawData.schema) diff --git a/packages/server-core/src/recording/services.ts b/packages/server-core/src/recording/services.ts index f1826fcb83..1bfd447a02 100755 --- a/packages/server-core/src/recording/services.ts +++ b/packages/server-core/src/recording/services.ts @@ -23,7 +23,8 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ +import RecordingResourceUpload from './recording-resource-upload/recording-resource-upload' import RecordingResource from './recording-resource/recording-resource' import Recording from './recording/recording' -export default [Recording, RecordingResource] +export default [Recording, RecordingResource, RecordingResourceUpload] diff --git a/packages/server-core/src/social/channel/channel.resolvers.ts b/packages/server-core/src/social/channel/channel.resolvers.ts index 38f2437f52..ecac1f3314 100644 --- a/packages/server-core/src/social/channel/channel.resolvers.ts +++ b/packages/server-core/src/social/channel/channel.resolvers.ts @@ -42,14 +42,12 @@ export const channelResolver = resolve({ export const channelExternalResolver = resolve({ channelUsers: virtual(async (channel, context) => { if (context.method === 'find' && !context.params.query.instanceId) { - const channelUsers = (await context.app.service(channelUserPath).find({ + return (await context.app.service(channelUserPath).find({ query: { channelId: channel.id }, paginate: false })) as ChannelUserType[] - - return channelUsers } }), messages: virtual(async (channel, context) => { diff --git a/packages/server-core/src/social/channel/channel.ts b/packages/server-core/src/social/channel/channel.ts index 9c3183bc0c..c38213a252 100755 --- a/packages/server-core/src/social/channel/channel.ts +++ b/packages/server-core/src/social/channel/channel.ts @@ -29,7 +29,7 @@ import { ChannelType, channelMethods, channelPath } from '@etherealengine/engine import { ChannelUserType, channelUserPath } from '@etherealengine/engine/src/schemas/social/channel-user.schema' import { UserID } from '@etherealengine/engine/src/schemas/user/user.schema' -import { Application } from '../../../declarations' +import { Application, HookContext } from '../../../declarations' import { ChannelService } from './channel.class' import channelDocs from './channel.docs' import hooks from './channel.hooks' @@ -61,13 +61,14 @@ export default (app: Application): void => { const onCRUD = (app: Application) => - async (data: ChannelType): Promise => { + async (data: ChannelType, context: HookContext): Promise => { const channelUsers = (await app.service(channelUserPath).find({ query: { channelId: data.id }, + headers: context.params.headers, paginate: false - })) as ChannelUserType[] + })) as unknown as ChannelUserType[] const userIds = channelUsers.map((channelUser) => { return channelUser.userId diff --git a/packages/server-core/src/social/location-ban/location-ban.ts b/packages/server-core/src/social/location-ban/location-ban.ts index e6be51d622..bf519537db 100755 --- a/packages/server-core/src/social/location-ban/location-ban.ts +++ b/packages/server-core/src/social/location-ban/location-ban.ts @@ -60,7 +60,7 @@ export default (app: Application): void => { const service = app.service(locationBanPath) service.hooks(hooks) - service.publish('created', async (data: LocationBanType, params) => { + service.publish('created', async (data: LocationBanType) => { try { return Promise.all([app.channel(`userIds/${data.userId}`).send({ locationBan: data })]) } catch (err) { diff --git a/packages/server-core/src/social/message/message.ts b/packages/server-core/src/social/message/message.ts index 66da028341..0f4f5c633b 100755 --- a/packages/server-core/src/social/message/message.ts +++ b/packages/server-core/src/social/message/message.ts @@ -27,7 +27,7 @@ import { MessageType, messageMethods, messagePath } from '@etherealengine/engine import { ChannelUserType, channelUserPath } from '@etherealengine/engine/src/schemas/social/channel-user.schema' import { UserID, userPath } from '@etherealengine/engine/src/schemas/user/user.schema' -import { Application } from '../../../declarations' +import { Application, HookContext } from '../../../declarations' import { MessageService } from './message.class' import messageDocs from './message.docs' import hooks from './message.hooks' @@ -59,16 +59,17 @@ export default (app: Application): void => { const onCRUD = (app: Application) => - async (data: MessageType): Promise => { + async (data: MessageType, context: HookContext): Promise => { if (!data.sender && data.senderId) { - data.sender = await app.service(userPath).get(data.senderId) + data.sender = await app.service(userPath).get(data.senderId, { headers: context.params.headers }) } const channelUsers = (await app.service(channelUserPath).find({ query: { channelId: data.channelId }, + headers: context.params.headers, paginate: false - })) as ChannelUserType[] + })) as unknown as ChannelUserType[] const userIds = channelUsers.map((channelUser) => { return channelUser.userId }) diff --git a/packages/server-core/src/user/avatar/avatar-helper.ts b/packages/server-core/src/user/avatar/avatar-helper.ts index 80f3f271b7..be44032bbd 100644 --- a/packages/server-core/src/user/avatar/avatar-helper.ts +++ b/packages/server-core/src/user/avatar/avatar-helper.ts @@ -32,7 +32,6 @@ import { CommonKnownContentTypes } from '@etherealengine/common/src/utils/Common import { AvatarID, avatarPath, AvatarType } from '@etherealengine/engine/src/schemas/user/avatar.schema' import { Application } from '../../../declarations' -import { isAssetFromDomain } from '../../media/static-resource/static-resource-helper' import { getStorageProvider } from '../../media/storageprovider/storageprovider' import { addAssetAsStaticResource } from '../../media/upload-asset/upload-asset.service' import logger from '../../ServerLogger' @@ -132,7 +131,6 @@ export const installAvatarsFromProject = async (app: Application, avatarsFolder: ] } })) as Paginated - console.log({ existingAvatar }) let selectedAvatar: AvatarType if (existingAvatar && existingAvatar.data.length > 0) { @@ -172,8 +170,8 @@ export const uploadAvatarStaticResource = async ( ) => { const name = data.avatarName ? data.avatarName : 'Avatar-' + Math.round(Math.random() * 100000) - const staticResourceKey = `static-resources/avatar/${data.isPublic ? 'public' : params?.user!.id}/` - const isFromDomain = !!data.path && isAssetFromDomain(data.path) + const staticResourceKey = `avatars/${data.isPublic ? 'public' : params?.user!.id}/` + const isFromDomain = !!data.path const path = isFromDomain ? data.path! : staticResourceKey // const thumbnail = await generateAvatarThumbnail(data.avatar as Buffer) @@ -214,14 +212,10 @@ export const uploadAvatarStaticResource = async ( if (data.avatarId) { try { - await app.service(avatarPath).patch( - data.avatarId, - { - modelResourceId: modelResource.id, - thumbnailResourceId: thumbnailResource.id - }, - params - ) + await app.service(avatarPath).patch(data.avatarId, { + modelResourceId: modelResource.id, + thumbnailResourceId: thumbnailResource.id + }) } catch (err) { console.log(err) } diff --git a/packages/server-core/src/user/avatar/avatar.resolvers.ts b/packages/server-core/src/user/avatar/avatar.resolvers.ts index 41d9d8b757..e78eef3001 100644 --- a/packages/server-core/src/user/avatar/avatar.resolvers.ts +++ b/packages/server-core/src/user/avatar/avatar.resolvers.ts @@ -58,7 +58,7 @@ export const avatarExternalResolver = resolve({ modelResource: virtual(async (avatar, context) => { if (context.event !== 'removed' && avatar.modelResourceId) try { - return await context.app.service(staticResourcePath).get(avatar.modelResourceId) + return await context.app.service(staticResourcePath)._get(avatar.modelResourceId) } catch (err) { //Swallow missing resource errors, deal with them elsewhere } @@ -66,7 +66,7 @@ export const avatarExternalResolver = resolve({ thumbnailResource: virtual(async (avatar, context) => { if (context.event !== 'removed' && avatar.thumbnailResourceId) try { - return await context.app.service(staticResourcePath).get(avatar.thumbnailResourceId) + return await context.app.service(staticResourcePath)._get(avatar.thumbnailResourceId) } catch (err) { //Swallow missing resource errors, deal with them elsewhere } diff --git a/packages/server-core/src/user/identity-provider/identity-provider.hooks.ts b/packages/server-core/src/user/identity-provider/identity-provider.hooks.ts index 4a4e188cd6..2bc25c3cbf 100755 --- a/packages/server-core/src/user/identity-provider/identity-provider.hooks.ts +++ b/packages/server-core/src/user/identity-provider/identity-provider.hooks.ts @@ -122,7 +122,11 @@ async function validateAuthParams(context: HookContext) throw new BadRequest('userId not found') } - context.existingUser = await context.app.service(userPath).get(userId) + try { + context.existingUser = await context.app.service(userPath).get(userId) + } catch (err) { + // + } } async function addIdentityProviderType(context: HookContext) { diff --git a/packages/server-core/src/user/strategies/twitter.ts b/packages/server-core/src/user/strategies/twitter.ts index 411cca7296..6ad47dff07 100755 --- a/packages/server-core/src/user/strategies/twitter.ts +++ b/packages/server-core/src/user/strategies/twitter.ts @@ -65,7 +65,6 @@ export class TwitterStrategy extends CustomOAuthStrategy { } async updateEntity(entity: any, profile: any, params: Params): Promise { - console.log('updateEntity', entity, profile, params) const authResult = await (this.app.service('authentication') as any).strategies.jwt.authenticate( { accessToken: params?.authentication?.accessToken }, {} diff --git a/packages/server-core/src/user/user-avatar/user-avatar.ts b/packages/server-core/src/user/user-avatar/user-avatar.ts index 3df0538bd7..1b4dca6c0c 100644 --- a/packages/server-core/src/user/user-avatar/user-avatar.ts +++ b/packages/server-core/src/user/user-avatar/user-avatar.ts @@ -76,7 +76,7 @@ export default (app: Application): void => { * This method find all users * @returns users */ - service.publish('patched', async (data: UserAvatarType, context) => { + service.publish('patched', async (data: UserAvatarType) => { try { const userId = data.userId diff --git a/packages/server-core/src/user/user/user.hooks.ts b/packages/server-core/src/user/user/user.hooks.ts index aae122b71c..7857007a9c 100755 --- a/packages/server-core/src/user/user/user.hooks.ts +++ b/packages/server-core/src/user/user/user.hooks.ts @@ -119,9 +119,9 @@ const restrictUserRemove = async (context: HookContext) => { if (await checkScope(loggedInUser, 'user', 'write')) { const isRemovedUserAdmin = ( - await context.app - .service(scopePath) - .find({ query: { userId: context.id as UserID, type: 'admin:admin' as ScopeType } }) + await context.app.service(scopePath).find({ + query: { userId: context.id as UserID, type: 'admin:admin' as ScopeType } + }) ).total > 0 if (isRemovedUserAdmin && !(await checkScope(loggedInUser, 'admin', 'admin'))) {