mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2026-03-30 10:56:47 +00:00
feat: send email in share transcript and add email sending in room (#924)
* fix: add source language for file pipeline * feat: send email in share transcript and add email sending in room * fix: hide audio and video streaming for unauthenticated users * fix: security order
This commit is contained in:
committed by
GitHub
parent
74b9b97453
commit
e2ba502697
@@ -103,3 +103,162 @@ async def test_transcript_get_includes_video_fields(authenticated_client, client
|
||||
data = response.json()
|
||||
assert data["has_cloud_video"] is False
|
||||
assert data["cloud_video_duration"] is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_video_url_requires_authentication(client):
|
||||
"""Test that video URL endpoint returns 401 for unauthenticated requests."""
|
||||
response = await client.get("/transcripts/any-id/video/url")
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_video_url_presigned_params(authenticated_client, client):
|
||||
"""Test that presigned URL is generated with short expiry and inline disposition."""
|
||||
from reflector.db import get_database
|
||||
from reflector.db.meetings import meetings
|
||||
|
||||
meeting_id = "test-meeting-presigned-params"
|
||||
await get_database().execute(
|
||||
meetings.insert().values(
|
||||
id=meeting_id,
|
||||
room_name="Presigned Params Meeting",
|
||||
room_url="https://example.com",
|
||||
host_room_url="https://example.com/host",
|
||||
start_date=datetime.now(timezone.utc),
|
||||
end_date=datetime.now(timezone.utc) + timedelta(hours=1),
|
||||
room_id=None,
|
||||
daily_composed_video_s3_key="recordings/video.mp4",
|
||||
daily_composed_video_duration=60,
|
||||
)
|
||||
)
|
||||
|
||||
transcript = await transcripts_controller.add(
|
||||
name="presigned-params",
|
||||
source_kind=SourceKind.ROOM,
|
||||
meeting_id=meeting_id,
|
||||
user_id="randomuserid",
|
||||
)
|
||||
|
||||
with patch("reflector.views.transcripts_video.get_source_storage") as mock_storage:
|
||||
mock_instance = AsyncMock()
|
||||
mock_instance.get_file_url = AsyncMock(
|
||||
return_value="https://s3.example.com/presigned-url"
|
||||
)
|
||||
mock_storage.return_value = mock_instance
|
||||
|
||||
await client.get(f"/transcripts/{transcript.id}/video/url")
|
||||
|
||||
mock_instance.get_file_url.assert_called_once_with(
|
||||
"recordings/video.mp4",
|
||||
operation="get_object",
|
||||
expires_in=900,
|
||||
extra_params={
|
||||
"ResponseContentDisposition": "inline",
|
||||
"ResponseContentType": "video/mp4",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def _create_meeting_with_video(meeting_id):
|
||||
"""Helper to create a meeting with cloud video."""
|
||||
from reflector.db import get_database
|
||||
from reflector.db.meetings import meetings
|
||||
|
||||
await get_database().execute(
|
||||
meetings.insert().values(
|
||||
id=meeting_id,
|
||||
room_name="Video Meeting",
|
||||
room_url="https://example.com",
|
||||
host_room_url="https://example.com/host",
|
||||
start_date=datetime.now(timezone.utc),
|
||||
end_date=datetime.now(timezone.utc) + timedelta(hours=1),
|
||||
room_id=None,
|
||||
daily_composed_video_s3_key="recordings/video.mp4",
|
||||
daily_composed_video_duration=60,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_video_url_private_transcript_denies_non_owner(
|
||||
authenticated_client, client
|
||||
):
|
||||
"""Authenticated non-owner cannot access video for a private transcript."""
|
||||
meeting_id = "test-meeting-private-deny"
|
||||
await _create_meeting_with_video(meeting_id)
|
||||
|
||||
transcript = await transcripts_controller.add(
|
||||
name="private-video",
|
||||
source_kind=SourceKind.ROOM,
|
||||
meeting_id=meeting_id,
|
||||
user_id="other-owner",
|
||||
share_mode="private",
|
||||
)
|
||||
|
||||
with patch("reflector.views.transcripts_video.get_source_storage") as mock_storage:
|
||||
mock_instance = AsyncMock()
|
||||
mock_instance.get_file_url = AsyncMock(
|
||||
return_value="https://s3.example.com/url"
|
||||
)
|
||||
mock_storage.return_value = mock_instance
|
||||
|
||||
response = await client.get(f"/transcripts/{transcript.id}/video/url")
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_video_url_public_transcript_allows_authenticated_non_owner(
|
||||
authenticated_client, client
|
||||
):
|
||||
"""Authenticated non-owner can access video for a public transcript."""
|
||||
meeting_id = "test-meeting-public-allow"
|
||||
await _create_meeting_with_video(meeting_id)
|
||||
|
||||
transcript = await transcripts_controller.add(
|
||||
name="public-video",
|
||||
source_kind=SourceKind.ROOM,
|
||||
meeting_id=meeting_id,
|
||||
user_id="other-owner",
|
||||
share_mode="public",
|
||||
)
|
||||
|
||||
with patch("reflector.views.transcripts_video.get_source_storage") as mock_storage:
|
||||
mock_instance = AsyncMock()
|
||||
mock_instance.get_file_url = AsyncMock(
|
||||
return_value="https://s3.example.com/url"
|
||||
)
|
||||
mock_storage.return_value = mock_instance
|
||||
|
||||
response = await client.get(f"/transcripts/{transcript.id}/video/url")
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_video_url_semi_private_allows_authenticated_non_owner(
|
||||
authenticated_client, client
|
||||
):
|
||||
"""Authenticated non-owner can access video for a semi-private transcript."""
|
||||
meeting_id = "test-meeting-semi-private-allow"
|
||||
await _create_meeting_with_video(meeting_id)
|
||||
|
||||
transcript = await transcripts_controller.add(
|
||||
name="semi-private-video",
|
||||
source_kind=SourceKind.ROOM,
|
||||
meeting_id=meeting_id,
|
||||
user_id="other-owner",
|
||||
share_mode="semi-private",
|
||||
)
|
||||
|
||||
with patch("reflector.views.transcripts_video.get_source_storage") as mock_storage:
|
||||
mock_instance = AsyncMock()
|
||||
mock_instance.get_file_url = AsyncMock(
|
||||
return_value="https://s3.example.com/url"
|
||||
)
|
||||
mock_storage.return_value = mock_instance
|
||||
|
||||
response = await client.get(f"/transcripts/{transcript.id}/video/url")
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
Reference in New Issue
Block a user