Skip to content
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
1 change: 1 addition & 0 deletions e2e_config.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"notifications.subscriber.id": "NTS-0829-7123-7123",
"integration.extension.id": "EXT-6587-4477",
"integration.term.id": "ETC-6587-4477-0062",
"program.media.id": "PMD-9643-3741-0001",
"program.program.id": "PRG-9643-3741",
"program.document.file.id": "PDM-9643-3741-0001"
}
6 changes: 6 additions & 0 deletions mpt_api_client/resources/program/mixins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@
AsyncDocumentMixin,
DocumentMixin,
)
from mpt_api_client.resources.program.mixins.media_mixin import (
AsyncMediaMixin,
MediaMixin,
)
from mpt_api_client.resources.program.mixins.publishable_mixin import (
AsyncPublishableMixin,
PublishableMixin,
)

__all__ = [ # noqa: WPS410
"AsyncDocumentMixin",
"AsyncMediaMixin",
"AsyncPublishableMixin",
"DocumentMixin",
"MediaMixin",
"PublishableMixin",
]
26 changes: 26 additions & 0 deletions mpt_api_client/resources/program/mixins/media_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from mpt_api_client.http.mixins import (
AsyncCreateFileMixin,
AsyncDownloadFileMixin,
CreateFileMixin,
DownloadFileMixin,
)
from mpt_api_client.resources.program.mixins.publishable_mixin import (
AsyncPublishableMixin,
PublishableMixin,
)


class MediaMixin[Model](
CreateFileMixin[Model],
DownloadFileMixin[Model],
PublishableMixin[Model],
):
"""Media mixin."""


class AsyncMediaMixin[Model](
AsyncCreateFileMixin[Model],
AsyncDownloadFileMixin[Model],
AsyncPublishableMixin[Model],
):
"""Media mixin."""
16 changes: 16 additions & 0 deletions mpt_api_client/resources/program/programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
AsyncDocumentService,
DocumentService,
)
from mpt_api_client.resources.program.programs_media import (
AsyncMediaService,
MediaService,
)


class Program(Model):
Expand Down Expand Up @@ -81,6 +85,12 @@ def documents(self, program_id: str) -> DocumentService:
http_client=self.http_client, endpoint_params={"program_id": program_id}
)

def media(self, program_id: str) -> MediaService:
"""Return program media service."""
return MediaService(
http_client=self.http_client, endpoint_params={"program_id": program_id}
)


class AsyncProgramsService(
AsyncGetMixin[Program],
Expand Down Expand Up @@ -108,3 +118,9 @@ def documents(self, program_id: str) -> AsyncDocumentService:
return AsyncDocumentService(
http_client=self.http_client, endpoint_params={"program_id": program_id}
)

def media(self, program_id: str) -> AsyncMediaService:
"""Return async program media service."""
return AsyncMediaService(
http_client=self.http_client, endpoint_params={"program_id": program_id}
)
73 changes: 73 additions & 0 deletions mpt_api_client/resources/program/programs_media.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from mpt_api_client.http import AsyncService, Service
from mpt_api_client.http.mixins import (
AsyncCollectionMixin,
AsyncModifiableResourceMixin,
CollectionMixin,
ModifiableResourceMixin,
)
from mpt_api_client.models import Model
from mpt_api_client.models.model import BaseModel
from mpt_api_client.resources.program.mixins import (
AsyncMediaMixin,
MediaMixin,
)


class Media(Model):
"""Media resource.

Attributes:
name: Media name.
type: Media type.
description: Media description.
status: Media status.
filename: Original file name.
size: File size in bytes.
content_type: MIME content type of the media file.
display_order: Display order of the media item.
url: URL to access the media file.
program: Reference to the program.
audit: Audit information (created, updated events).
"""

name: str | None
type: str | None
description: str | None
status: str | None
filename: str | None
size: int | None
content_type: str | None
display_order: int | None
url: str | None
program: BaseModel | None
audit: BaseModel | None


class MediaServiceConfig:
"""Media service configuration."""

_endpoint = "/public/v1/program/programs/{program_id}/media"
_model_class = Media
_collection_key = "data"
_upload_file_key = "file"
_upload_data_key = "media"


class MediaService(
MediaMixin[Media],
ModifiableResourceMixin[Media],
CollectionMixin[Media],
Service[Media],
MediaServiceConfig,
):
"""Media service."""


class AsyncMediaService(
AsyncMediaMixin[Media],
AsyncModifiableResourceMixin[Media],
AsyncCollectionMixin[Media],
AsyncService[Media],
MediaServiceConfig,
):
"""Async media service."""
5 changes: 5 additions & 0 deletions tests/e2e/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ def jpg_url():
return "https://sample-files.com/downloads/images/jpg/color_test_800x600_118kb.jpg"


@pytest.fixture(scope="session")
def video_url():
return "https://www.youtube.com/watch?v=DUMMY1_0000"


@pytest.fixture(scope="session")
def e2e_config(project_root_path):
filename = os.getenv("TEST_CONFIG_FILE", "e2e_config.test.json")
Expand Down
27 changes: 27 additions & 0 deletions tests/e2e/program/program/media/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest


@pytest.fixture
def invalid_media_id():
return "PMD-0000-0000-0000"


@pytest.fixture
def media_id(e2e_config):
return e2e_config["program.media.id"]


@pytest.fixture
def media_data_factory():
def factory(media_type: str = "Image"):
return {
"name": "E2E Created Program Media",
"description": "E2E Created Program Media",
"displayOrder": 1,
"type": media_type,
"mediatype": media_type,
"url": "",
"language": "en-us",
}

return factory
105 changes: 105 additions & 0 deletions tests/e2e/program/program/media/test_async_media.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import pytest

from mpt_api_client.exceptions import MPTAPIError
from mpt_api_client.rql.query_builder import RQLQuery

pytestmark = [pytest.mark.flaky]


@pytest.fixture
def async_vendor_media_service(async_mpt_vendor, program_id):
return async_mpt_vendor.program.programs.media(program_id)


@pytest.fixture
async def created_media_from_file(async_vendor_media_service, media_data_factory, logo_fd):
media_data = media_data_factory()
media = await async_vendor_media_service.create(media_data, file=logo_fd)
yield media, media_data
try:
await async_vendor_media_service.delete(media.id)
except MPTAPIError as error:
print(f"TEARDOWN - Unable to delete media {media.id}: {error.title}") # noqa: WPS421


@pytest.fixture
async def created_media_from_url(
async_vendor_media_service, media_data_factory, video_url, logo_fd
):
media_data = media_data_factory(media_type="Video")

media_data["url"] = video_url
media = await async_vendor_media_service.create(media_data, file=logo_fd)
yield media, media_data
Comment thread
robcsegal marked this conversation as resolved.
try:
await async_vendor_media_service.delete(media.id)
except MPTAPIError as error:
print(f"TEARDOWN - Unable to delete media {media.id}: {error.title}") # noqa: WPS421


def test_create_media(created_media_from_file): # noqa: AAA01
result, media_data = created_media_from_file

assert result.name == media_data["name"]
assert result.description == media_data["description"]


def test_create_media_from_url(created_media_from_url): # noqa: AAA01
result, media_data = created_media_from_url

assert result.name == media_data["name"]
assert result.description == media_data["description"]


async def test_update_media(async_vendor_media_service, created_media_from_file):
media, _ = created_media_from_file
update_data = {"name": "E2E Updated Program Media"}

result = await async_vendor_media_service.update(media.id, update_data)

assert result.name == update_data["name"]


async def test_delete_media(async_vendor_media_service, created_media_from_file):
media, _ = created_media_from_file

result = await async_vendor_media_service.delete(media.id)

assert result is None


async def test_get_media(async_vendor_media_service, media_id):
result = await async_vendor_media_service.get(media_id)

assert result.id == media_id


async def test_get_media_invalid_id(async_vendor_media_service, invalid_media_id):
with pytest.raises(MPTAPIError):
await async_vendor_media_service.get(invalid_media_id)


async def test_filter_and_select_media(async_vendor_media_service, media_id):
select_fields = ["-revision", "-audit"]
filtered_media = async_vendor_media_service.filter(RQLQuery(id=media_id)).select(*select_fields)

result = [media async for media in filtered_media.iterate()]

assert len(result) == 1


async def test_media_publish(async_vendor_media_service, created_media_from_file):
media, _ = created_media_from_file

result = await async_vendor_media_service.publish(media.id)

assert result.status == "Published"


async def test_media_unpublish(async_vendor_media_service, created_media_from_file):
media, _ = created_media_from_file
await async_vendor_media_service.publish(media.id)

result = await async_vendor_media_service.unpublish(media.id)

assert result.status == "Unpublished"
Loading