""" Admin configuration for rfiles.online file management. """ from django import forms from django.contrib import admin from django.utils.html import format_html from .models import MediaFile, PublicShare, FileAccessLog, SharedSpace class SharedSpaceAdminForm(forms.ModelForm): password = forms.CharField( widget=forms.PasswordInput, required=False, help_text="Leave blank to keep existing password. Set to change." ) class Meta: model = SharedSpace fields = '__all__' exclude = ['password_hash'] def save(self, commit=True): instance = super().save(commit=False) password = self.cleaned_data.get('password') if password: instance.set_password(password) if commit: instance.save() return instance @admin.register(SharedSpace) class SharedSpaceAdmin(admin.ModelAdmin): form = SharedSpaceAdminForm list_display = [ 'name', 'slug', 'url_display', 'file_count_display', 'total_size_display', 'is_active', 'created_at', ] list_filter = ['is_active', 'created_at'] search_fields = ['name', 'slug', 'description'] readonly_fields = ['id', 'created_at', 'updated_at', 'url_display', 'file_count_display', 'total_size_display'] fieldsets = ( (None, { 'fields': ('id', 'name', 'slug', 'description', 'url_display') }), ('Access Control', { 'fields': ('password', 'is_active', 'max_file_size_mb') }), ('Statistics', { 'fields': ('file_count_display', 'total_size_display') }), ('Metadata', { 'fields': ('created_by', 'created_at', 'updated_at') }), ) def url_display(self, obj): url = obj.get_url() return format_html('{}', url, url) url_display.short_description = 'URL' def file_count_display(self, obj): return obj.file_count file_count_display.short_description = 'Files' def total_size_display(self, obj): size = obj.total_size_bytes for unit in ['B', 'KB', 'MB', 'GB']: if size < 1024: return f"{size:.1f} {unit}" size /= 1024 return f"{size:.1f} TB" total_size_display.short_description = 'Total Size' @admin.register(MediaFile) class MediaFileAdmin(admin.ModelAdmin): list_display = [ 'title', 'original_filename', 'mime_type', 'formatted_file_size', 'share_count', 'is_processed', 'created_at', ] list_filter = ['mime_type', 'is_processed', 'created_at'] search_fields = ['title', 'original_filename', 'description', 'tags'] readonly_fields = ['id', 'file_hash', 'file_size', 'created_at', 'updated_at', 'share_links'] fieldsets = ( (None, { 'fields': ('id', 'title', 'description', 'tags') }), ('File Info', { 'fields': ('file', 'original_filename', 'mime_type', 'file_size', 'file_hash') }), ('Processing', { 'fields': ('is_processed', 'processing_error', 'extracted_text'), 'classes': ('collapse',) }), ('Links', { 'fields': ('shared_space',), 'classes': ('collapse',) }), ('Metadata', { 'fields': ('uploaded_by', 'created_at', 'updated_at') }), ('Public Shares', { 'fields': ('share_links',) }), ) def formatted_file_size(self, obj): size = obj.file_size for unit in ['B', 'KB', 'MB', 'GB']: if size < 1024: return f"{size:.1f} {unit}" size /= 1024 return f"{size:.1f} TB" formatted_file_size.short_description = 'Size' def share_count(self, obj): count = obj.get_public_shares().count() if count > 0: return format_html('{}', count) return count share_count.short_description = 'Active Shares' def share_links(self, obj): shares = obj.get_public_shares() if not shares: return "No active shares" links = [] for share in shares: url = share.get_public_url() status_parts = [] if share.expires_at: status_parts.append(f"expires {share.expires_at}") if share.max_downloads: status_parts.append(f"{share.download_count}/{share.max_downloads} downloads") if share.is_password_protected: status_parts.append("password protected") status_str = f" ({', '.join(status_parts)})" if status_parts else "" links.append(f'{share.token[:12]}...{status_str}') return format_html('
'.join(links)) share_links.short_description = 'Share Links' @admin.register(PublicShare) class PublicShareAdmin(admin.ModelAdmin): list_display = [ 'token_display', 'media_file', 'status_display', 'download_count', 'is_password_protected', 'expires_at', 'created_at', ] list_filter = ['is_active', 'is_password_protected', 'created_at', 'expires_at'] search_fields = ['token', 'media_file__title', 'media_file__original_filename', 'note'] readonly_fields = ['id', 'token', 'download_count', 'created_at', 'public_url_display'] fieldsets = ( (None, { 'fields': ('id', 'token', 'media_file', 'public_url_display') }), ('Access Control', { 'fields': ('is_active', 'expires_at', 'max_downloads', 'download_count') }), ('Password Protection', { 'fields': ('is_password_protected', 'password_hash'), 'classes': ('collapse',) }), ('Metadata', { 'fields': ('note', 'created_by', 'created_at') }), ) def token_display(self, obj): return f"{obj.token[:16]}..." token_display.short_description = 'Token' def status_display(self, obj): if not obj.is_active: return format_html('Revoked') if obj.is_expired: return format_html('Expired') if obj.is_download_limit_reached: return format_html('Limit Reached') return format_html('Active') status_display.short_description = 'Status' def public_url_display(self, obj): url = obj.get_public_url() return format_html('{}', url, url) public_url_display.short_description = 'Public URL' @admin.register(FileAccessLog) class FileAccessLogAdmin(admin.ModelAdmin): list_display = [ 'accessed_at', 'media_file', 'access_type', 'ip_address', 'share_token_display', ] list_filter = ['access_type', 'accessed_at'] search_fields = ['media_file__title', 'ip_address'] readonly_fields = [ 'id', 'media_file', 'share', 'accessed_at', 'ip_address', 'user_agent', 'access_type', 'user', ] def share_token_display(self, obj): if obj.share: return f"{obj.share.token[:12]}..." return "-" share_token_display.short_description = 'Share' def has_add_permission(self, request): return False def has_change_permission(self, request, obj=None): return False