extensions-website/extensions/admin.py
Anna Sirota caae613747 Make it possible to fully delete unlisted/unrated extensions and versions (#81)
* removes all soft-deletion;
* shows a "Delete extension" button on the draft page in case it can be deleted;
* shows a "Delete version" button on the version page in case it can be deleted;
* a version can be deleted if
  * its file isn't approved, and it doesn't have any ratings;
* an extension can be deleted if
  * it's not listed, and doesn't have any ratings or abuse reports;
  * all it's versions can also be deleted;
* changes default `File.status` from `APPROVED` to `AWAITING_REVIEW`
  With version's file status being `APPROVED` by default, a version can never be deleted, even when the extension is still a draft.
  This change doesn't affect the approval process because
   * when an extension is approved its latest version becomes approved automatically (no change here);
   * when a new version is uploaded to an approved extension, it's approved automatically (this is new).

This allows authors to delete their drafts, freeing the extension slug and making it possible to re-upload the same file.
This also makes it possible to easily fix mistakes during the drafting of a new extension (e.g. delete a version and re-upload it without bumping a version for each typo/mistake in packaging and so on).
(see #78 and #63)

Reviewed-on: #81
2024-04-19 11:00:13 +02:00

210 lines
5.1 KiB
Python

import functools
import logging
from django.contrib import admin
from . import models
from common.admin import NoAddDeleteMixin
from extensions.models import Extension, Maintainer, Version, Tag
log = logging.getLogger(__name__)
class MaintainerInline(admin.TabularInline):
model = Maintainer
raw_id_fields = ('user',)
extra = 0
class PreviewInline(NoAddDeleteMixin, admin.TabularInline):
model = Extension.previews.through
raw_id_fields = ('file',)
show_change_link = True
can_add = False
extra = 0
class VersionInline(NoAddDeleteMixin, admin.TabularInline):
model = Version
fields = ('version', 'blender_version_min', 'blender_version_max', 'file')
raw_id_fields = ('file',)
show_change_link = True
extra = 0
class ExtensionAdmin(admin.ModelAdmin):
list_display = (
'__str__',
'type',
'status',
'download_count',
'view_count',
'average_score',
)
list_filter = ('type', 'status')
search_fields = ('id', '^slug', 'name')
inlines = (MaintainerInline, PreviewInline, VersionInline)
readonly_fields = (
'id',
'type',
'name',
'slug',
'date_created',
'date_status_changed',
'date_approved',
'date_modified',
'average_score',
'text_ratings_count',
'total_ratings_count',
'download_count',
'view_count',
'website',
)
raw_id_fields = ('team',)
fieldsets = (
(
'Details',
{
'fields': (
('team',),
('id', 'type'),
(
'date_created',
'date_status_changed',
'date_approved',
'date_modified',
),
'name',
'slug',
'description',
'status',
),
},
),
(
'Support',
{
'fields': ('website', 'support'),
},
),
(
'Stats',
{
'fields': (
('average_score', 'text_ratings_count', 'download_count', 'view_count'),
),
},
),
)
def get_urls(self):
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return functools.update_wrapper(wrapper, view)
urlpatterns = super().get_urls()
custom_urlpatterns = []
return custom_urlpatterns + urlpatterns
class VersionAdmin(admin.ModelAdmin):
list_display = (
'__str__',
'extension',
'download_count',
'average_score',
)
list_filter = (
'file__status',
'blender_version_min',
'blender_version_max',
'licenses',
'tags',
'permissions',
)
search_fields = ('id', 'extension__slug', 'extension__name')
raw_id_fields = ('extension', 'file')
readonly_fields = (
'id',
'tagline',
'date_created',
'date_modified',
'average_score',
'download_count',
)
fieldsets = (
(
'Details',
{
'fields': (
'id',
'tagline',
('date_created', 'date_modified'),
'extension',
'version',
'blender_version_min',
'blender_version_max',
'release_notes',
'licenses',
'tags',
'file',
'permissions',
),
},
),
(
'Stats',
{
'fields': (
'average_score',
'download_count',
),
},
),
)
def get_urls(self):
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return functools.update_wrapper(wrapper, view)
urlpatterns = super().get_urls()
custom_urlpatterns = []
return custom_urlpatterns + urlpatterns
class MaintainerAdmin(admin.ModelAdmin):
model = Maintainer
list_display = ('extension', 'user')
readonly_fields = ('extension', 'user')
class LicenseAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'url')
class TagAdmin(admin.ModelAdmin):
model = Tag
list_display = ('name', 'slug', 'type')
def get_readonly_fields(self, request, ob=None):
"""Allow to edit all fields when adding a new tag, but not when editing an existing one"""
if ob:
return ('name', 'type')
else:
return ()
admin.site.register(models.Extension, ExtensionAdmin)
admin.site.register(models.Version, VersionAdmin)
admin.site.register(models.Maintainer, MaintainerAdmin)
admin.site.register(models.License, LicenseAdmin)
admin.site.register(models.Tag, TagAdmin)