Meeting attach record (#7196)

This commit is contained in:
Kristina 2024-11-19 15:12:41 +04:00 committed by GitHub
parent a374f22acc
commit 13c03e3d24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 89 additions and 19 deletions

View File

@ -108,6 +108,7 @@ export class TRoom extends TDoc implements Room {
language!: RoomLanguage
startWithTranscription!: boolean
startWithRecording!: boolean
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
attachments?: number

View File

@ -89,6 +89,7 @@ async function createReception (client: MigrationUpgradeClient): Promise<void> {
y: 0,
language: 'en',
startWithTranscription: false,
startWithRecording: false,
description: makeCollaborativeDoc(love.ids.Reception, 'description')
},
love.ids.Reception
@ -105,7 +106,7 @@ export const loveOperation: MigrateOperation = {
}
},
{
state: 'setup-defaults-settings',
state: 'setup-defaults-settings-v2',
func: async (client: MigrationClient) => {
await client.update(
DOMAIN_LOVE,
@ -132,6 +133,21 @@ export const loveOperation: MigrateOperation = {
{ _class: love.class.Office, startWithTranscription: { $exists: false } },
{ startWithTranscription: false }
)
await client.update(
DOMAIN_LOVE,
{ _class: love.class.Room, type: RoomType.Video, startWithRecording: { $exists: false } },
{ startWithRecording: true }
)
await client.update(
DOMAIN_LOVE,
{ _class: love.class.Room, startWithRecording: { $exists: false } },
{ startWithRecording: false }
)
await client.update(
DOMAIN_LOVE,
{ _class: love.class.Office, startWithRecording: { $exists: false } },
{ startWithRecording: false }
)
}
},
{

View File

@ -77,6 +77,7 @@
"MeetingEnd": "Meeting end",
"Status": "Status",
"Active": "Active",
"Finished": "Finished"
"Finished": "Finished",
"StartWithRecording": "Start with recording"
}
}

View File

@ -77,6 +77,7 @@
"MeetingEnd": "Fin de la reunión",
"Status": "Estado",
"Active": "Activo",
"Finished": "Terminado"
"Finished": "Terminado",
"StartWithRecording": "Iniciar con grabación"
}
}

View File

@ -77,6 +77,7 @@
"MeetingEnd": "Fin de la réunion",
"Status": "Statut",
"Active": "Actif",
"Finished": "Terminé"
"Finished": "Terminé",
"StartWithRecording": "Démarrer avec l'enregistrement"
}
}

View File

@ -77,6 +77,7 @@
"MeetingEnd": "Fine riunione",
"Status": "Stato",
"Active": "Attivo",
"Finished": "Finito"
"Finished": "Finito",
"StartWithRecording": "Inizia con la registrazione"
}
}

View File

@ -77,6 +77,7 @@
"MeetingEnd": "Fim da reunião",
"Status": "Estado",
"Active": "Ativo",
"Finished": "Finalizado"
"Finished": "Finalizado",
"StartWithRecording": "Começar com gravação"
}
}

View File

@ -77,6 +77,7 @@
"MeetingEnd": "Конец встречи",
"Status": "Статус",
"Active": "Активно",
"Finished": "Завершено"
"Finished": "Завершено",
"StartWithRecording": "Начинать с записью"
}
}

View File

@ -77,6 +77,7 @@
"MeetingEnd": "会议结束",
"Status": "状态",
"Active": "活动",
"Finished": "已完成"
"Finished": "已完成",
"StartWithRecording": "开始录制"
}
}

View File

@ -63,6 +63,7 @@
access: val.access,
language: 'en',
startWithTranscription: val._class !== love.class.Office && val.type === RoomType.Video,
startWithRecording: val._class !== love.class.Office && val.type === RoomType.Video,
description: makeCollaborativeDoc(_id, 'description')
}
if (val._class === love.class.Office) {

View File

@ -26,6 +26,10 @@
async function toggleTranscribing (): Promise<void> {
await client.diffUpdate(room, { startWithTranscription: !room.startWithTranscription })
}
async function toggleRecording (): Promise<void> {
await client.diffUpdate(room, { startWithRecording: !room.startWithRecording })
}
</script>
<div class="antiGrid">
@ -41,4 +45,10 @@
</div>
<ModernToggle size="small" checked={room.startWithTranscription} on:change={toggleTranscribing} />
</div>
<div class="antiGrid-row">
<div class="antiGrid-row__header">
<Label label={love.string.StartWithRecording} />
</div>
<ModernToggle size="small" checked={room.startWithRecording} on:change={toggleRecording} />
</div>
</div>

View File

@ -420,6 +420,10 @@ function initRoomMetadata (metadata: string | undefined): void {
) {
void startTranscription(room)
}
if (get(isRecordingAvailable) && data.recording == null && room?.startWithRecording === true) {
void record(room)
}
}
export async function connect (name: string, room: Room, _id: string): Promise<void> {
const wsURL = getMetadata(love.metadata.WebSocketURL)
@ -869,7 +873,7 @@ export async function record (room: Room): Promise<void> {
Authorization: 'Bearer ' + token,
'Content-Type': 'application/json'
},
body: JSON.stringify({ roomName, room: room.name })
body: JSON.stringify({ roomName, room: room.name, meetingMinutes: get(currentMeetingMinutes)?._id })
})
}
} catch (err: any) {

View File

@ -102,6 +102,7 @@ export interface Room extends Doc {
y: number
language: RoomLanguage
startWithTranscription: boolean
startWithRecording: boolean
description: CollaborativeDoc
attachments?: number
meetings?: number
@ -225,7 +226,8 @@ const love = plugin(loveId, {
MeetingEnd: '' as IntlString,
Status: '' as IntlString,
Active: '' as IntlString,
Finished: '' as IntlString
Finished: '' as IntlString,
StartWithRecording: '' as IntlString
},
ids: {
MainFloor: '' as Ref<Floor>,

View File

@ -33,6 +33,7 @@ export function createDefaultRooms (employees: Ref<Employee>[]): (Data<Room | Of
person: employees[index] ?? null,
language: 'en',
startWithTranscription: false,
startWithRecording: false,
description: makeCollaborativeDoc(_id, 'description')
}
res.push(office)
@ -51,6 +52,7 @@ export function createDefaultRooms (employees: Ref<Employee>[]): (Data<Room | Of
y: 0,
language: 'en',
startWithTranscription: true,
startWithRecording: true,
description: makeCollaborativeDoc(allHands, 'description')
})
@ -67,6 +69,7 @@ export function createDefaultRooms (employees: Ref<Employee>[]): (Data<Room | Of
y: 4,
language: 'en',
startWithTranscription: true,
startWithRecording: true,
description: makeCollaborativeDoc(meetingRoom1, 'description')
})
const meetingRoom2 = generateId<Room>()
@ -82,6 +85,7 @@ export function createDefaultRooms (employees: Ref<Employee>[]): (Data<Room | Of
y: 4,
language: 'en',
startWithTranscription: true,
startWithRecording: true,
description: makeCollaborativeDoc(meetingRoom2, 'description')
})
const voiceRoom1 = generateId<Room>()
@ -97,6 +101,7 @@ export function createDefaultRooms (employees: Ref<Employee>[]): (Data<Room | Of
y: 8,
language: 'en',
startWithTranscription: false,
startWithRecording: false,
description: makeCollaborativeDoc(voiceRoom1, 'description')
})
const voiceRoom2 = generateId<Room>()
@ -112,6 +117,7 @@ export function createDefaultRooms (employees: Ref<Employee>[]): (Data<Room | Of
y: 8,
language: 'en',
startWithTranscription: false,
startWithRecording: false,
description: makeCollaborativeDoc(voiceRoom2, 'description')
})
return res

View File

@ -54,6 +54,7 @@
"typescript": "^5.3.3"
},
"dependencies": {
"@hcengineering/attachment": "^0.6.14",
"@hcengineering/love": "^0.6.0",
"@hcengineering/drive": "^0.6.0",
"@hcengineering/core": "^0.6.32",

View File

@ -13,13 +13,13 @@
// limitations under the License.
//
import { toWorkspaceString, WorkspaceId } from '@hcengineering/core'
import { Ref, toWorkspaceString, WorkspaceId } from '@hcengineering/core'
import { setMetadata } from '@hcengineering/platform'
import serverClient from '@hcengineering/server-client'
import { initStatisticsContext, StorageConfig, StorageConfiguration } from '@hcengineering/server-core'
import { buildStorageFromConfig, storageConfigFromEnv } from '@hcengineering/server-storage'
import serverToken, { decodeToken } from '@hcengineering/server-token'
import { RoomMetadata, TranscriptionStatus } from '@hcengineering/love'
import { RoomMetadata, TranscriptionStatus, MeetingMinutes } from '@hcengineering/love'
import cors from 'cors'
import express from 'express'
import { IncomingHttpHeaders } from 'http'
@ -70,6 +70,7 @@ export const main = async (): Promise<void> => {
name: string
workspace: string
workspaceId: WorkspaceId
meetingMinutes?: Ref<MeetingMinutes>
}
>()
@ -86,7 +87,7 @@ export const main = async (): Promise<void> => {
const storedBlob = await storageAdapter.stat(ctx, data.workspaceId, filename)
if (storedBlob !== undefined) {
const client = await WorkspaceClient.create(data.workspace)
await client.saveFile(filename, data.name, storedBlob)
await client.saveFile(filename, data.name, storedBlob, data.meetingMinutes)
await client.close()
}
dataByUUID.delete(res.filename)
@ -128,13 +129,14 @@ export const main = async (): Promise<void> => {
const roomName = req.body.roomName
const room = req.body.room
const meetingMinutes = req.body.meetingMinutes
const { workspace } = decodeToken(token)
try {
const dateStr = new Date().toISOString().replace('T', '_').slice(0, 19)
const name = `${room}_${dateStr}.mp4`
const id = await startRecord(storageConfig, egressClient, roomClient, roomName, workspace)
dataByUUID.set(id, { name, workspace: workspace.name, workspaceId: workspace })
dataByUUID.set(id, { name, workspace: workspace.name, workspaceId: workspace, meetingMinutes })
res.send()
} catch (e) {
console.error(e)

View File

@ -12,10 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import core, { Client, Ref, TxOperations, type Blob } from '@hcengineering/core'
import core, { Client, Ref, TxOperations, type Blob, Data } from '@hcengineering/core'
import drive, { createFile } from '@hcengineering/drive'
import love from '@hcengineering/love'
import love, { MeetingMinutes } from '@hcengineering/love'
import { generateToken } from '@hcengineering/server-token'
import attachment, { Attachment } from '@hcengineering/attachment'
import { getClient } from './client'
import config from './config'
@ -41,7 +42,7 @@ export class WorkspaceClient {
return this.client
}
async saveFile (uuid: string, name: string, blob: Blob): Promise<void> {
async saveFile (uuid: string, name: string, blob: Blob, meetingMinutes?: Ref<MeetingMinutes>): Promise<void> {
const current = await this.client.findOne(drive.class.Drive, { _id: love.space.Drive })
if (current === undefined) {
await this.client.createDoc(
@ -61,7 +62,6 @@ export class WorkspaceClient {
}
const data = {
file: uuid as Ref<Blob>,
title: name,
size: blob.size,
type: blob.contentType,
lastModified: blob.modifiedOn,
@ -72,6 +72,26 @@ export class WorkspaceClient {
originalWidth: 1280
}
}
await createFile(this.client, love.space.Drive, drive.ids.Root, data)
await createFile(this.client, love.space.Drive, drive.ids.Root, { ...data, title: name })
await this.attachToMeetingMinutes({ ...data, name }, meetingMinutes)
}
async attachToMeetingMinutes (
data: Omit<Data<Attachment>, 'attachedToClass' | 'attachedTo' | 'collection'>,
ref?: Ref<MeetingMinutes>
): Promise<void> {
if (ref === undefined) return
const meeting = await this.client.findOne(love.class.MeetingMinutes, { _id: ref })
if (meeting === undefined) return
await this.client.addCollection(
attachment.class.Attachment,
meeting.space,
meeting._id,
meeting._class,
'attachments',
data
)
}
}