Skip to content

Ability to delete video resources #2602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
37 changes: 20 additions & 17 deletions static/js/components/RepeatableContentListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -270,23 +270,26 @@ export default function RepeatableContentListing(props: {
</div>
</div>
<StudioList>
{listing.results.map((item: WebsiteContentListItem) => (
<StudioListItem
key={item.text_id}
to={siteContentDetailUrl
.param({
name: website.name,
contentType: configItem.name,
uuid: item.text_id,
})
.toString()}
title={item.title ?? ""}
subtitle={`Updated ${formatUpdatedOn(item)}`}
menuOptions={
isDeletable ? [["Delete", startDelete(item)]] : undefined
}
/>
))}
{listing.results.map((item: WebsiteContentListItem) => {
const showDelete = isDeletable && item.is_deletable_by_resourcetype
return (
<StudioListItem
key={item.text_id}
to={siteContentDetailUrl
.param({
name: website.name,
contentType: configItem.name,
uuid: item.text_id,
})
.toString()}
title={item.title ?? ""}
subtitle={`Updated ${formatUpdatedOn(item)}`}
menuOptions={
showDelete ? [["Delete", startDelete(item)]] : undefined
}
/>
)
})}
</StudioList>
<PaginationControls previous={pages.previous} next={pages.next} />
<Route
Expand Down
1 change: 1 addition & 0 deletions static/js/types/websites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ export interface WebsiteContentListItem {
/** ISO 8601 formatted datetime string */
updated_on: string
is_deletable?: boolean
is_deletable_by_resourcetype?: boolean
}

export interface WebsiteContent extends WebsiteContentListItem {
Expand Down
1 change: 1 addition & 0 deletions static/js/util/factories/websites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const makeWebsiteContentListItem = (): WebsiteContentListItem => ({
type: casual.word,
updated_on: randomISO8601(),
is_deletable: true,
is_deletable_by_resourcetype: true,
})

export const makeWebsiteContentDetail = (): WebsiteContent => ({
Expand Down
25 changes: 24 additions & 1 deletion websites/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ class WebsiteContentSerializer(serializers.ModelSerializer):

website_name = serializers.CharField(source="website.name")
is_deletable = serializers.SerializerMethodField()
is_deletable_by_resourcetype = serializers.SerializerMethodField()

def get_is_deletable(self, obj):
request = self.context.get("request", None)
Expand All @@ -488,6 +489,14 @@ def get_is_deletable(self, obj):
return len(refs) == 0
return True

def get_is_deletable_by_resourcetype(self, obj):
# if not a resource, always OK, because we're using config var to
# control deletable content types
if obj.type != CONTENT_TYPE_RESOURCE:
return True
# for resources only, check metadata.resourcetype === "Video"
return (obj.metadata or {}).get("resourcetype") == "Video"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using the RESOURCE_TYPE_VIDEO constant from websites.constants for maintainability.

Suggested change
return (obj.metadata or {}).get("resourcetype") == "Video"
return (obj.metadata or {}).get("resourcetype") == RESOURCE_TYPE_VIDEO


class Meta:
model = WebsiteContent
read_only_fields = [
Expand All @@ -497,6 +506,7 @@ class Meta:
"type",
"updated_on",
"is_deletable",
"is_deletable_by_resourcetype",
]
# See WebsiteContentCreateSerializer below for creating new WebsiteContent objects # noqa: E501
fields = read_only_fields
Expand Down Expand Up @@ -620,9 +630,22 @@ def to_representation(self, instance):
result[file_field["name"]] = instance.file.url
return result

is_deletable_by_resourcetype = serializers.SerializerMethodField()

def get_is_deletable_by_resourcetype(self, obj):
if obj.type != CONTENT_TYPE_RESOURCE:
return True
return (obj.metadata or {}).get("resourcetype") == "Video"

class Meta:
model = WebsiteContent
read_only_fields = ["text_id", "type", "content_context", "url_path"]
read_only_fields = [
"text_id",
"type",
"content_context",
"url_path",
"is_deletable_by_resourcetype",
]
fields = [
*read_only_fields,
"title",
Expand Down
39 changes: 39 additions & 0 deletions websites/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from content_sync.constants import VERSION_DRAFT, VERSION_LIVE
from content_sync.tasks import update_mass_build_pipelines_on_publish
from gdrive_sync.constants import WebsiteSyncStatus
from gdrive_sync.models import DriveFile
from gdrive_sync.tasks import import_website_files
from main import features
from main.permissions import ReadonlyPermission
Expand Down Expand Up @@ -692,6 +693,44 @@ def get_serializer_context(self):
)
return {**super().get_serializer_context(), **added_context}

def destroy(self, request, *args, **kwargs):
content: WebsiteContent = self.get_object()

is_video = (
content.type == "resource"
and (content.metadata or {}).get("resourcetype") == RESOURCE_TYPE_VIDEO
)
if not is_video:
return super().destroy(request, *args, **kwargs)

drive_file = DriveFile.objects.filter(resource=content).first()
# print("drive file") # noqa: ERA001
# print("drive file") # noqa: ERA001
# print("drive file") # noqa: ERA001
# print(drive_file) # noqa: ERA001
video = drive_file.video if drive_file else None
# print("Vide") # noqa: ERA001
# print("Vide") # noqa: ERA001
# print("Vide") # noqa: ERA001
# print(video) # noqa: ERA001

# content.updated_by = request.user # noqa: ERA001
# super().perform_destroy(content) # noqa: ERA001

# if drive_file and drive_file.file_id:
# ds = get_drive_service() # noqa: ERA001
# ds.files().delete(fileId=drive_file.file_id).execute() # noqa: ERA001

if video:
video.delete()

# api.delete_drive_file(drive_file, sync_datetime=now_in_utc()) # noqa: ERA001
# (drivefile pre_delete ..S3 cleanup)
# drive_file.delete() # noqa: ERA001 # noqa: ERA001

update_website_backend(content.website)
return Response(status=status.HTTP_204_NO_CONTENT)

def perform_destroy(self, instance: WebsiteContent):
"""(soft) deletes a WebsiteContent record"""
instance.updated_by = self.request.user
Expand Down
Loading