Skip to content

Commit 6f4b39d

Browse files
dojutsu-userericholscher
authored andcommitted
Add admin methods for reindexing versions from project and version admin. (#5343)
* Add admin methods * add else * add another else * Change short_description * add improvements
1 parent 1fd489c commit 6f4b39d

File tree

3 files changed

+146
-3
lines changed

3 files changed

+146
-3
lines changed

readthedocs/builds/admin.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
from readthedocs.builds.models import Build, BuildCommandResult, Version
99
from readthedocs.core.utils import trigger_build
10+
from readthedocs.projects.models import HTMLFile
11+
from readthedocs.search.utils import _indexing_helper
1012
from readthedocs.core.utils.general import wipe_version_via_slugs
1113

1214

@@ -58,7 +60,7 @@ class VersionAdmin(GuardedModelAdmin):
5860
list_filter = ('type', 'privacy_level', 'active', 'built')
5961
search_fields = ('slug', 'project__slug')
6062
raw_id_fields = ('project',)
61-
actions = ['wipe_selected_versions', 'build_version']
63+
actions = ['build_version', 'reindex_version', 'wipe_version', 'wipe_selected_versions']
6264

6365
def wipe_selected_versions(self, request, queryset):
6466
"""Wipes the selected versions."""
@@ -92,6 +94,46 @@ def build_version(self, request, queryset):
9294

9395
build_version.short_description = 'Build version'
9496

97+
def reindex_version(self, request, queryset):
98+
"""Reindexes all selected versions to ES."""
99+
html_objs_qs = []
100+
for version in queryset.iterator():
101+
html_objs = HTMLFile.objects.filter(project=version.project, version=version)
102+
103+
if html_objs.exists():
104+
html_objs_qs.append(html_objs)
105+
106+
if html_objs_qs:
107+
_indexing_helper(html_objs_qs, wipe=False)
108+
109+
self.message_user(
110+
request,
111+
'Task initiated successfully.',
112+
messages.SUCCESS
113+
)
114+
115+
reindex_version.short_description = 'Reindex version to ES'
116+
117+
def wipe_version(self, request, queryset):
118+
"""Wipe selected versions from ES."""
119+
html_objs_qs = []
120+
for version in queryset.iterator():
121+
html_objs = HTMLFile.objects.filter(project=version.project, version=version)
122+
123+
if html_objs.exists():
124+
html_objs_qs.append(html_objs)
125+
126+
if html_objs_qs:
127+
_indexing_helper(html_objs_qs, wipe=True)
128+
129+
self.message_user(
130+
request,
131+
'Task initiated successfully',
132+
messages.SUCCESS,
133+
)
134+
135+
wipe_version.short_description = 'Wipe version from ES'
136+
95137

96138
admin.site.register(Build, BuildAdmin)
97139
admin.site.register(Version, VersionAdmin)

readthedocs/projects/admin.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from readthedocs.core.utils import broadcast, trigger_build
1313
from readthedocs.notifications.views import SendNotificationView
1414
from readthedocs.redirects.models import Redirect
15+
from readthedocs.search.utils import _indexing_helper
1516

1617
from .forms import FeatureForm
1718
from .models import (
@@ -145,7 +146,13 @@ class ProjectAdmin(GuardedModelAdmin):
145146
]
146147
readonly_fields = ('feature_flags',)
147148
raw_id_fields = ('users', 'main_language_project')
148-
actions = ['send_owner_email', 'ban_owner', 'build_default_version']
149+
actions = [
150+
'send_owner_email',
151+
'ban_owner',
152+
'build_default_version',
153+
'reindex_active_versions',
154+
'wipe_all_versions',
155+
]
149156

150157
def feature_flags(self, obj):
151158
return ', '.join([str(f.get_feature_display()) for f in obj.features])
@@ -222,6 +229,68 @@ def build_default_version(self, request, queryset):
222229

223230
build_default_version.short_description = 'Build default version'
224231

232+
def reindex_active_versions(self, request, queryset):
233+
"""Reindex all active versions of the selected projects to ES."""
234+
qs_iterator = queryset.iterator()
235+
for project in qs_iterator:
236+
version_qs = Version.objects.filter(project=project)
237+
active_versions = version_qs.filter(active=True)
238+
239+
if not active_versions.exists():
240+
self.message_user(
241+
request,
242+
'No active versions of project {}'.format(project),
243+
messages.ERROR
244+
)
245+
else:
246+
html_objs_qs = []
247+
for version in active_versions.iterator():
248+
html_objs = HTMLFile.objects.filter(project=project, version=version)
249+
250+
if html_objs.exists():
251+
html_objs_qs.append(html_objs)
252+
253+
if html_objs_qs:
254+
_indexing_helper(html_objs_qs, wipe=False)
255+
256+
self.message_user(
257+
request,
258+
'Task initiated successfully for {}'.format(project),
259+
messages.SUCCESS
260+
)
261+
262+
reindex_active_versions.short_description = 'Reindex active versions to ES'
263+
264+
def wipe_all_versions(self, request, queryset):
265+
"""Wipe indexes of all versions of selected projects."""
266+
qs_iterator = queryset.iterator()
267+
for project in qs_iterator:
268+
version_qs = Version.objects.filter(project=project)
269+
if not version_qs.exists():
270+
self.message_user(
271+
request,
272+
'No active versions of project {}.'.format(project),
273+
messages.ERROR
274+
)
275+
else:
276+
html_objs_qs = []
277+
for version in version_qs.iterator():
278+
html_objs = HTMLFile.objects.filter(project=project, version=version)
279+
280+
if html_objs.exists():
281+
html_objs_qs.append(html_objs)
282+
283+
if html_objs_qs:
284+
_indexing_helper(html_objs_qs, wipe=True)
285+
286+
self.message_user(
287+
request,
288+
'Task initiated successfully for {}.'.format(project),
289+
messages.SUCCESS
290+
)
291+
292+
wipe_all_versions.short_description = 'Wipe all versions from ES'
293+
225294
def get_actions(self, request):
226295
actions = super().get_actions(request)
227296
actions['delete_selected'] = (

readthedocs/search/utils.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from django_elasticsearch_dsl.registries import registry
99

1010
from readthedocs.builds.models import Version
11-
from readthedocs.projects.models import Project
11+
from readthedocs.projects.models import Project, HTMLFile
12+
from readthedocs.search.documents import PageDocument
1213

1314

1415
log = logging.getLogger(__name__)
@@ -67,3 +68,34 @@ def _get_document(model, document_class):
6768
for document in documents:
6869
if str(document) == document_class:
6970
return document
71+
72+
73+
def _indexing_helper(html_objs_qs, wipe=False):
74+
"""
75+
Helper function for reindexing and wiping indexes of projects and versions.
76+
77+
If ``wipe`` is set to False, html_objs are deleted from the ES index,
78+
else, html_objs are indexed.
79+
"""
80+
from readthedocs.search.tasks import index_objects_to_es, delete_objects_in_es
81+
82+
if html_objs_qs:
83+
obj_ids = []
84+
for html_objs in html_objs_qs:
85+
obj_ids.extend([obj.id for obj in html_objs])
86+
87+
# removing redundant ids if exists.
88+
obj_ids = list(set(obj_ids))
89+
90+
if obj_ids:
91+
kwargs = {
92+
'app_label': HTMLFile._meta.app_label,
93+
'model_name': HTMLFile.__name__,
94+
'document_class': str(PageDocument),
95+
'objects_id': obj_ids,
96+
}
97+
98+
if not wipe:
99+
index_objects_to_es.delay(**kwargs)
100+
else:
101+
delete_objects_in_es.delay(**kwargs)

0 commit comments

Comments
 (0)