Task #422 - Create issues in bulk

remotes/origin/enhancement/email-actions
Anler Hp 2014-07-29 13:43:57 +02:00
parent 4c2585a891
commit 0b02cc4523
5 changed files with 150 additions and 2 deletions

View File

@ -24,7 +24,7 @@ from rest_framework import status
from taiga.base import filters
from taiga.base import exceptions as exc
from taiga.base.decorators import detail_route
from taiga.base.decorators import detail_route, list_route
from taiga.base.api import ModelCrudViewSet, ModelListViewSet
from taiga.base import tags
@ -34,11 +34,12 @@ from taiga.projects.notifications import WatchedResourceMixin
from taiga.projects.occ import OCCResourceMixin
from taiga.projects.history import HistoryResourceMixin
from taiga.projects.models import Project
from taiga.projects.votes.utils import attach_votescount_to_queryset
from taiga.projects.votes import services as votes_service
from taiga.projects.votes import serializers as votes_serializers
from . import models
from . import services
from . import permissions
from . import serializers
@ -152,6 +153,28 @@ class IssueViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
if obj.type and obj.type.project != obj.project:
raise exc.PermissionDenied(_("You don't have permissions to set this type to this issue."))
@list_route(methods=["POST"])
def bulk_create(self, request, **kwargs):
bulk_issues = request.DATA.get('bulkIssues', None)
if bulk_issues is None:
raise exc.BadRequest(_('bulkIssues parameter is mandatory'))
project_id = request.DATA.get('projectId', None)
if project_id is None:
raise exc.BadRequest(_('projectId parameter is mandatory'))
project = get_object_or_404(Project, id=project_id)
self.check_permissions(request, 'bulk_create', project)
issues = services.create_issues_in_bulk(
bulk_issues, callback=self.post_save, project=project, owner=request.user,
status=project.default_issue_status, severity=project.default_severity,
priority=project.default_priority, type=project.default_issue_type)
issues_serialized = self.serializer_class(issues, many=True)
return Response(data=issues_serialized.data)
@detail_route(methods=['post'])
def upvote(self, request, pk=None):
issue = get_object_or_404(models.Issue, pk=pk)

View File

@ -30,6 +30,7 @@ class IssuePermission(ResourcePermission):
list_perms = AllowAny()
upvote_perms = IsAuthenticated() & HasProjectPerm('vote_issues')
downvote_perms = IsAuthenticated() & HasProjectPerm('vote_issues')
bulk_create_perms = IsAuthenticated() & (HasProjectPerm('add_issue_to_project') | HasProjectPerm('add_issue'))
class HasIssueIdUrlParam(PermissionComponent):

View File

@ -0,0 +1,60 @@
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
# Copyright (C) 2014 Jesús Espino <jespinog@gmail.com>
# Copyright (C) 2014 David Barragán <bameda@dbarragan.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from taiga.base.utils import db, text
from . import models
def get_issues_from_bulk(bulk_data, **additional_fields):
"""Convert `bulk_data` into a list of issues.
:param bulk_data: List of issues in bulk format.
:param additional_fields: Additional fields when instantiating each issue.
:return: List of `Issue` instances.
"""
return [models.Issue(subject=line, **additional_fields)
for line in text.split_in_lines(bulk_data)]
def create_issues_in_bulk(bulk_data, callback=None, **additional_fields):
"""Create issues from `bulk_data`.
:param bulk_data: List of issues in bulk format.
:param callback: Callback to execute after each issue save.
:param additional_fields: Additional fields when instantiating each issue.
:return: List of created `Issue` instances.
"""
issues = get_issues_from_bulk(bulk_data, **additional_fields)
db.save_in_bulk(issues, callback)
return issues
def update_issues_order_in_bulk(bulk_data):
"""Update the order of some issues.
`bulk_data` should be a list of tuples with the following format:
[(<issue id>, <new issue order value>), ...]
"""
issue_ids = []
new_order_values = []
for issue_id, new_order_value in bulk_data:
issue_ids.append(issue_id)
new_order_values.append({"order": new_order_value})
db.update_in_bulk_with_ids(issue_ids, new_order_values, model=models.Issue)

View File

@ -376,3 +376,18 @@ def create_userstory(**kwargs):
defaults.update(kwargs)
return UserStoryFactory(**defaults)
def create_project(**kwargs):
"Create a project along with its dependencies"
defaults = {}
defaults.update(kwargs)
project = ProjectFactory.create(**defaults)
project.default_issue_status = IssueStatusFactory.create(project=project)
project.default_severity = SeverityFactory.create(project=project)
project.default_priority = PriorityFactory.create(project=project)
project.default_issue_type = IssueTypeFactory.create(project=project)
project.save()
return project

View File

@ -1,12 +1,61 @@
from unittest import mock
import pytest
from django.core.urlresolvers import reverse
from taiga.projects.issues import services, models
from .. import factories as f
pytestmark = pytest.mark.django_db
def test_get_issues_from_bulk():
data = """
Issue #1
Issue #2
"""
issues = services.get_issues_from_bulk(data)
assert len(issues) == 2
assert issues[0].subject == "Issue #1"
assert issues[1].subject == "Issue #2"
@mock.patch("taiga.projects.issues.services.db")
def test_create_issues_in_bulk(db):
data = """
Issue #1
Issue #2
"""
issues = services.create_issues_in_bulk(data)
db.save_in_bulk.assert_called_once_with(issues, None)
@mock.patch("taiga.projects.issues.services.db")
def test_update_issues_order_in_bulk(db):
data = [(1, 1), (2, 2)]
services.update_issues_order_in_bulk(data)
db.update_in_bulk_with_ids.assert_called_once_with([1, 2], [{"order": 1}, {"order": 2}],
model=models.Issue)
def test_api_create_issues_in_bulk(client):
project = f.create_project()
url = reverse("issues-bulk-create")
data = {"bulkIssues": "Issue #1\nIssue #2",
"projectId": project.id}
client.login(project.owner)
response = client.json.post(url, data)
assert response.status_code == 200, response.data
def test_api_filter_by_subject(client):
f.create_issue()
issue = f.create_issue(subject="some random subject")