Skip to content

Commit

Permalink
Merge pull request #5140 from dojutsu-user/admin-action-for-version
Browse files Browse the repository at this point in the history
Add admin functions for wiping a version
  • Loading branch information
ericholscher authored Feb 26, 2019
2 parents cca41b7 + b206c70 commit bba018d
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 10 deletions.
18 changes: 17 additions & 1 deletion readthedocs/builds/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from readthedocs.builds.models import Build, BuildCommandResult, Version
from readthedocs.core.utils import trigger_build
from readthedocs.core.utils.general import wipe_version_via_slugs


class BuildCommandResultInline(admin.TabularInline):
Expand Down Expand Up @@ -57,7 +58,22 @@ class VersionAdmin(GuardedModelAdmin):
list_filter = ('type', 'privacy_level', 'active', 'built')
search_fields = ('slug', 'project__slug')
raw_id_fields = ('project',)
actions = ['build_version']
actions = ['wipe_selected_versions', 'build_version']

def wipe_selected_versions(self, request, queryset):
"""Wipes the selected versions."""
for version in queryset:
wipe_version_via_slugs(
version_slug=version.slug,
project_slug=version.project.slug
)
self.message_user(
request,
'Wiped {}.'.format(version.slug),
level=messages.SUCCESS
)

wipe_selected_versions.short_description = 'Wipe selected versions'

def build_version(self, request, queryset):
"""Trigger a build for the project version."""
Expand Down
25 changes: 25 additions & 0 deletions readthedocs/core/utils/general.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-

import os

from django.shortcuts import get_object_or_404

from readthedocs.core.utils import broadcast
from readthedocs.projects.tasks import remove_dirs
from readthedocs.builds.models import Version


def wipe_version_via_slugs(version_slug, project_slug):
"""Wipes the given version of a given project."""
version = get_object_or_404(
Version,
slug=version_slug,
project__slug=project_slug,
)
del_dirs = [
os.path.join(version.project.doc_path, 'checkouts', version.slug),
os.path.join(version.project.doc_path, 'envs', version.slug),
os.path.join(version.project.doc_path, 'conda', version.slug),
]
for del_dir in del_dirs:
broadcast(type='build', task=remove_dirs, args=[(del_dir,)])
14 changes: 5 additions & 9 deletions readthedocs/core/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
documentation and header rendering, and server errors.
"""

from __future__ import absolute_import
from __future__ import division
import os
import logging
from urllib.parse import urlparse
Expand All @@ -19,6 +17,7 @@


from readthedocs.builds.models import Version
from readthedocs.core.utils.general import wipe_version_via_slugs
from readthedocs.core.resolver import resolve_path
from readthedocs.core.symlink import PrivateSymlink, PublicSymlink
from readthedocs.core.utils import broadcast
Expand Down Expand Up @@ -89,13 +88,10 @@ def wipe_version(request, project_slug, version_slug):
raise Http404('You must own this project to wipe it.')

if request.method == 'POST':
del_dirs = [
os.path.join(version.project.doc_path, 'checkouts', version.slug),
os.path.join(version.project.doc_path, 'envs', version.slug),
os.path.join(version.project.doc_path, 'conda', version.slug),
]
for del_dir in del_dirs:
broadcast(type='build', task=remove_dirs, args=[(del_dir,)])
wipe_version_via_slugs(
version_slug=version_slug,
project_slug=project_slug
)
return redirect('project_version_list', project_slug)
return render(
request,
Expand Down
61 changes: 61 additions & 0 deletions readthedocs/rtd_tests/tests/test_core_utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# -*- coding: utf-8 -*-
"""Test core util functions."""

import os
import mock

from mock import call
from django.http import Http404
from django.test import TestCase
from django_dynamic_fixture import get

from readthedocs.builds.models import Version
from readthedocs.core.utils.general import wipe_version_via_slugs
from readthedocs.projects.tasks import remove_dirs
from readthedocs.core.utils import slugify, trigger_build
from readthedocs.projects.models import Project

Expand Down Expand Up @@ -153,3 +159,58 @@ def test_slugify(self):
slugify('A title_-_with separated parts', dns_safe=False),
'a-title_-_with-separated-parts',
)

@mock.patch('readthedocs.core.utils.general.broadcast')
def test_wipe_version_via_slug(self, mock_broadcast):
wipe_version_via_slugs(
version_slug=self.version.slug,
project_slug=self.version.project.slug
)
expected_del_dirs = [
os.path.join(self.version.project.doc_path, 'checkouts', self.version.slug),
os.path.join(self.version.project.doc_path, 'envs', self.version.slug),
os.path.join(self.version.project.doc_path, 'conda', self.version.slug),
]

mock_broadcast.assert_has_calls(
[
call(type='build', task=remove_dirs, args=[(expected_del_dirs[0],)]),
call(type='build', task=remove_dirs, args=[(expected_del_dirs[1],)]),
call(type='build', task=remove_dirs, args=[(expected_del_dirs[2],)]),
],
any_order=False
)

@mock.patch('readthedocs.core.utils.general.broadcast')
def test_wipe_version_via_slug_wrong_param(self, mock_broadcast):
self.assertFalse(Version.objects.filter(slug='wrong-slug').exists())
with self.assertRaises(Http404):
wipe_version_via_slugs(
version_slug='wrong-slug',
project_slug=self.version.project.slug
)
mock_broadcast.assert_not_called()

@mock.patch('readthedocs.core.utils.general.broadcast')
def test_wipe_version_via_slugs_same_version_slug_with_diff_proj(self, mock_broadcast):
project_2 = get(Project)
version_2 = get(Version, project=project_2, slug=self.version.slug)
wipe_version_via_slugs(
version_slug=version_2.slug,
project_slug=project_2.slug,
)

expected_del_dirs = [
os.path.join(version_2.project.doc_path, 'checkouts', version_2.slug),
os.path.join(version_2.project.doc_path, 'envs', version_2.slug),
os.path.join(version_2.project.doc_path, 'conda', version_2.slug),
]

mock_broadcast.assert_has_calls(
[
call(type='build', task=remove_dirs, args=[(expected_del_dirs[0],)]),
call(type='build', task=remove_dirs, args=[(expected_del_dirs[1],)]),
call(type='build', task=remove_dirs, args=[(expected_del_dirs[2],)]),
],
any_order=False
)
Empty file.
60 changes: 60 additions & 0 deletions readthedocs/rtd_tests/tests/versions/test_admin_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-

import os
import mock

from mock import call
import django_dynamic_fixture as fixture
from django.test import TestCase
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
from django.contrib.auth.models import User
from django import urls

from readthedocs.builds.models import Version
from readthedocs.core.models import UserProfile
from readthedocs.projects.models import Project
from readthedocs.projects.tasks import remove_dirs


class VersionAdminActionsTest(TestCase):

@classmethod
def setUpTestData(cls):
cls.owner = fixture.get(User)
cls.profile = fixture.get(UserProfile, user=cls.owner, banned=False)
cls.admin = fixture.get(User, is_staff=True, is_superuser=True)
cls.project = fixture.get(
Project,
main_language_project=None,
users=[cls.owner],
)
cls.version = fixture.get(Version, project=cls.project)

def setUp(self):
self.client.force_login(self.admin)

@mock.patch('readthedocs.core.utils.general.broadcast')
def test_wipe_selected_version(self, mock_broadcast):
action_data = {
ACTION_CHECKBOX_NAME: [self.version.pk],
'action': 'wipe_selected_versions',
'post': 'yes',
}
resp = self.client.post(
urls.reverse('admin:builds_version_changelist'),
action_data
)
expected_del_dirs = [
os.path.join(self.version.project.doc_path, 'checkouts', self.version.slug),
os.path.join(self.version.project.doc_path, 'envs', self.version.slug),
os.path.join(self.version.project.doc_path, 'conda', self.version.slug),
]

mock_broadcast.assert_has_calls(
[
call(type='build', task=remove_dirs, args=[(expected_del_dirs[0],)]),
call(type='build', task=remove_dirs, args=[(expected_del_dirs[1],)]),
call(type='build', task=remove_dirs, args=[(expected_del_dirs[2],)]),
],
any_order=False
)

0 comments on commit bba018d

Please sign in to comment.