From d6a69c2702d0e240eb22fc6a801e248e12ac2a0e Mon Sep 17 00:00:00 2001 From: Anthony Johnson Date: Thu, 7 Feb 2019 17:53:23 -0700 Subject: [PATCH] Add admin actions for building versions This gets around not having admin access to build a project, and makes rebuilding an arbitrary version a site admin feature. --- readthedocs/builds/admin.py | 22 +++++++++++++++++- readthedocs/projects/admin.py | 43 +++++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/readthedocs/builds/admin.py b/readthedocs/builds/admin.py index 571536f03a2..ac20db480b0 100644 --- a/readthedocs/builds/admin.py +++ b/readthedocs/builds/admin.py @@ -2,10 +2,11 @@ """Django admin interface for `~builds.models.Build` and related models.""" -from django.contrib import admin +from django.contrib import admin, messages from guardian.admin import GuardedModelAdmin from readthedocs.builds.models import Build, BuildCommandResult, Version +from readthedocs.core.utils import trigger_build class BuildCommandResultInline(admin.TabularInline): @@ -54,7 +55,26 @@ class VersionAdmin(GuardedModelAdmin): 'built', ) list_filter = ('type', 'privacy_level', 'active', 'built') + search_fields = ('slug', 'project__slug') raw_id_fields = ('project',) + actions = ['build_version'] + + def build_version(self, request, queryset): + """Trigger a build for the project version.""" + total = 0 + for version in queryset: + trigger_build( + project=version.project, + version=version, + ) + total += 1 + messages.add_message( + request, + messages.INFO, + 'Triggered builds for {} version(s).'.format(total), + ) + + build_version.short_description = 'Build version' admin.site.register(Build, BuildAdmin) diff --git a/readthedocs/projects/admin.py b/readthedocs/projects/admin.py index 205a397bbb4..db29088aa9f 100644 --- a/readthedocs/projects/admin.py +++ b/readthedocs/projects/admin.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -"""Django administration interface for `projects.models`""" +"""Django administration interface for `projects.models`.""" from django.contrib import admin, messages from django.contrib.admin.actions import delete_selected @@ -9,7 +9,7 @@ from readthedocs.builds.models import Version from readthedocs.core.models import UserProfile -from readthedocs.core.utils import broadcast +from readthedocs.core.utils import broadcast, trigger_build from readthedocs.notifications.views import SendNotificationView from readthedocs.redirects.models import Redirect @@ -47,7 +47,7 @@ def get_object_recipients(self, obj): class ProjectRelationshipInline(admin.TabularInline): - """Project inline relationship view for :py:class:`ProjectAdmin`""" + """Project inline relationship view for :py:class:`ProjectAdmin`.""" model = ProjectRelationship fk_name = 'parent' @@ -56,14 +56,14 @@ class ProjectRelationshipInline(admin.TabularInline): class VersionInline(admin.TabularInline): - """Version inline relationship view for :py:class:`ProjectAdmin`""" + """Version inline relationship view for :py:class:`ProjectAdmin`.""" model = Version class RedirectInline(admin.TabularInline): - """Redirect inline relationship view for :py:class:`ProjectAdmin`""" + """Redirect inline relationship view for :py:class:`ProjectAdmin`.""" model = Redirect @@ -77,7 +77,15 @@ class DomainInline(admin.TabularInline): # class ImpressionInline(admin.TabularInline): # from readthedocs.donate.models import ProjectImpressions # model = ProjectImpressions -# readonly_fields = ('date', 'promo', 'offers', 'views', 'clicks', 'view_ratio', 'click_ratio') +# readonly_fields = ( +# 'date', +# 'promo', +# 'offers', +# 'views', +# 'clicks', +# 'view_ratio', +# 'click_ratio', +# ) # extra = 0 # can_delete = False # max_num = 15 @@ -137,7 +145,7 @@ class ProjectAdmin(GuardedModelAdmin): ] readonly_fields = ('feature_flags',) raw_id_fields = ('users', 'main_language_project') - actions = ['send_owner_email', 'ban_owner'] + actions = ['send_owner_email', 'ban_owner', 'build_default_version'] def feature_flags(self, obj): return ', '.join([str(f.get_feature_display()) for f in obj.features]) @@ -162,8 +170,9 @@ def ban_owner(self, request, queryset): for project in queryset: if project.users.count() == 1: count = ( - UserProfile.objects.filter(user__projects=project - ).update(banned=True) + UserProfile.objects.filter( + user__projects=project, + ).update(banned=True) ) # yapf: disabled total += count else: @@ -199,6 +208,20 @@ def delete_selected_and_artifacts(self, request, queryset): ) return delete_selected(self, request, queryset) + def build_default_version(self, request, queryset): + """Trigger a build for the project version.""" + total = 0 + for project in queryset: + trigger_build(project=project) + total += 1 + messages.add_message( + request, + messages.INFO, + 'Triggered builds for {} project(s).'.format(total), + ) + + build_default_version.short_description = 'Build default version' + def get_actions(self, request): actions = super().get_actions(request) actions['delete_selected'] = ( @@ -211,7 +234,7 @@ def get_actions(self, request): class ImportedFileAdmin(admin.ModelAdmin): - """Admin view for :py:class:`ImportedFile`""" + """Admin view for :py:class:`ImportedFile`.""" raw_id_fields = ('project', 'version') list_display = ('path', 'name', 'version')