From d59e90885c7acc23865b40c10600fe4ca2336e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Fri, 17 Jun 2016 17:10:05 +0200 Subject: [PATCH] Enhancement: Create the wiki page if not exist when new links are created --- CHANGELOG.md | 1 + taiga/projects/notifications/services.py | 31 +++--- taiga/projects/wiki/api.py | 42 ++++++-- taiga/projects/wiki/permissions.py | 1 + tests/integration/test_wikilinks.py | 118 +++++++++++++++++++++++ 5 files changed, 173 insertions(+), 20 deletions(-) create mode 100644 tests/integration/test_wikilinks.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 3068820d..ef53bc7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Include created, modified and finished dates for tasks in CSV reports. - Add gravatar url to Users API endpoint. - ProjectTemplates now are sorted by the attribute 'order'. +- Create enpty wiki pages (if not exist) when a new link is created. - Comments: - Now comment owners and project admins can edit existing comments with the history Entry endpoint. - Add a new permissions to allow add comments instead of use the existent modify permission for this purpose. diff --git a/taiga/projects/notifications/services.py b/taiga/projects/notifications/services.py index 4a26545b..a4128622 100644 --- a/taiga/projects/notifications/services.py +++ b/taiga/projects/notifications/services.py @@ -223,6 +223,7 @@ def send_notifications(obj, *, history): if settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL == 0: send_sync_notifications(notification.id) + @transaction.atomic def send_sync_notifications(notification_id): """ @@ -261,19 +262,21 @@ def send_sync_notifications(notification_id): msg_id = 'taiga-system' now = datetime.datetime.now() - format_args = {"project_slug": notification.project.slug, - "project_name": notification.project.name, - "msg_id": msg_id, - "time": int(now.timestamp()), - "domain": domain} + format_args = { + "project_slug": notification.project.slug, + "project_name": notification.project.name, + "msg_id": msg_id, + "time": int(now.timestamp()), + "domain": domain + } - headers = {"Message-ID": "<{project_slug}/{msg_id}/{time}@{domain}>".format(**format_args), - "In-Reply-To": "<{project_slug}/{msg_id}@{domain}>".format(**format_args), - "References": "<{project_slug}/{msg_id}@{domain}>".format(**format_args), - - "List-ID": 'Taiga/{project_name} '.format(**format_args), - - "Thread-Index": make_ms_thread_index("<{project_slug}/{msg_id}@{domain}>".format(**format_args), now)} + headers = { + "Message-ID": "<{project_slug}/{msg_id}/{time}@{domain}>".format(**format_args), + "In-Reply-To": "<{project_slug}/{msg_id}@{domain}>".format(**format_args), + "References": "<{project_slug}/{msg_id}@{domain}>".format(**format_args), + "List-ID": 'Taiga/{project_name} '.format(**format_args), + "Thread-Index": make_ms_thread_index("<{project_slug}/{msg_id}@{domain}>".format(**format_args), now) + } for user in notification.notify_users.distinct(): context["user"] = user @@ -370,9 +373,11 @@ def get_projects_watched(user_or_id): user = get_user_model().objects.get(id=user_or_id) project_class = apps.get_model("projects", "Project") - project_ids = user.notify_policies.exclude(notify_level=NotifyLevel.none).values_list("project__id", flat=True) + project_ids = (user.notify_policies.exclude(notify_level=NotifyLevel.none) + .values_list("project__id", flat=True)) return project_class.objects.filter(id__in=project_ids) + def add_watcher(obj, user): """Add a watcher to an object. diff --git a/taiga/projects/wiki/api.py b/taiga/projects/wiki/api.py index 2ee75b14..bd82a065 100644 --- a/taiga/projects/wiki/api.py +++ b/taiga/projects/wiki/api.py @@ -18,23 +18,27 @@ from django.utils.translation import ugettext as _ -from taiga.base.api.permissions import IsAuthenticated - -from taiga.base import filters from taiga.base import exceptions as exc +from taiga.base import filters from taiga.base import response -from taiga.base.api import ModelCrudViewSet, ModelListViewSet +from taiga.base.api import ModelCrudViewSet +from taiga.base.api import ModelListViewSet from taiga.base.api.mixins import BlockedByProjectMixin +from taiga.base.api.permissions import IsAuthenticated from taiga.base.api.utils import get_object_or_404 from taiga.base.decorators import list_route -from taiga.projects.models import Project + from taiga.mdrender.service import render as mdrender -from taiga.projects.notifications.mixins import WatchedResourceMixin, WatchersViewSetMixin from taiga.projects.history.mixins import HistoryResourceMixin +from taiga.projects.history.services import take_snapshot +from taiga.projects.models import Project +from taiga.projects.notifications.mixins import WatchedResourceMixin +from taiga.projects.notifications.mixins import WatchersViewSetMixin +from taiga.projects.notifications.services import analize_object_for_watchers +from taiga.projects.notifications.services import send_notifications from taiga.projects.occ import OCCResourceMixin - from . import models from . import permissions from . import serializers @@ -99,3 +103,27 @@ class WikiLinkViewSet(BlockedByProjectMixin, ModelCrudViewSet): permission_classes = (permissions.WikiLinkPermission,) filter_backends = (filters.CanViewWikiPagesFilterBackend,) filter_fields = ["project"] + + def post_save(self, obj, created=False): + if created: + self._create_wiki_page_when_create_wiki_link_if_not_exist(obj) + super().pre_save(obj) + + def _create_wiki_page_when_create_wiki_link_if_not_exist(self, wiki_link): + try: + self.check_permissions(request, "create_wiki_page", wiki_link) + except exc.PermissionDenied: + pass + else: + # Create the wiki link and the wiki page if not exist. + wiki_page, created = models.WikiPage.objects.get_or_create( + slug=wiki_link.href, + project=wiki_link.project, + defaults={"owner": self.request.user,"last_modifier": self.request.user}) + + if created: + # Creaste the new history entre, sSet watcher for the new wiki page + # and send notifications about the new page created + history = take_snapshot(wiki_page, user=self.request.user) + analize_object_for_watchers(wiki_page, history.comment, history.owner) + send_notifications(wiki_page, history=history) diff --git a/taiga/projects/wiki/permissions.py b/taiga/projects/wiki/permissions.py index 0afea036..5f2311b2 100644 --- a/taiga/projects/wiki/permissions.py +++ b/taiga/projects/wiki/permissions.py @@ -54,3 +54,4 @@ class WikiLinkPermission(TaigaResourcePermission): partial_update_perms = HasProjectPerm('modify_wiki_link') destroy_perms = HasProjectPerm('delete_wiki_link') list_perms = AllowAny() + create_wiki_page_perms = HasProjectPerm('add_wiki_page') diff --git a/tests/integration/test_wikilinks.py b/tests/integration/test_wikilinks.py new file mode 100644 index 00000000..20e185dc --- /dev/null +++ b/tests/integration/test_wikilinks.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2014-2016 Andrey Antukh +# Copyright (C) 2014-2016 Jesús Espino +# Copyright (C) 2014-2016 David Barragán +# Copyright (C) 2014-2016 Alejandro Alonso +# Copyright (C) 2014-2016 Anler Hernández +# 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 . + +from django.core.urlresolvers import reverse +from django.core import mail + +from taiga.base.utils import json +from taiga.projects.notifications.choices import NotifyLevel + +from .. import factories as f + +import pytest +pytestmark = pytest.mark.django_db + + +def test_create_wiki_link_of_existent_wiki_page_with_permissions(client): + project = f.ProjectFactory.create() + role = f.RoleFactory.create(project=project, permissions=['view_wiki_pages', 'view_wiki_link', + 'add_wiki_page', 'add_wiki_link']) + + f.MembershipFactory.create(project=project, user=project.owner, role=role) + project.owner.notify_policies.filter(project=project).update(notify_level=NotifyLevel.all) + + user = f.UserFactory.create() + f.MembershipFactory.create(project=project, user=user, role=role) + + wiki_page = f.WikiPageFactory.create(project=project, owner=user, slug="test", content="test content") + + mail.outbox = [] + + url = reverse("wiki-links-list") + + data = { + "title": "test", + "href": "test", + "project": project.pk, + } + + assert project.wiki_pages.all().count() == 1 + client.login(user) + response = client.json.post(url, json.dumps(data)) + assert response.status_code == 201 + assert len(mail.outbox) == 0 + assert project.wiki_pages.all().count() == 1 + + +def test_create_wiki_link_of_inexistent_wiki_page_with_permissions(client): + project = f.ProjectFactory.create() + role = f.RoleFactory.create(project=project, permissions=['view_wiki_pages', 'view_wiki_link', + 'add_wiki_page', 'add_wiki_link']) + + f.MembershipFactory.create(project=project, user=project.owner, role=role) + project.owner.notify_policies.filter(project=project).update(notify_level=NotifyLevel.all) + + user = f.UserFactory.create() + f.MembershipFactory.create(project=project, user=user, role=role) + + mail.outbox = [] + + url = reverse("wiki-links-list") + + data = { + "title": "test", + "href": "test", + "project": project.pk, + } + + assert project.wiki_pages.all().count() == 0 + client.login(user) + response = client.json.post(url, json.dumps(data)) + assert response.status_code == 201 + assert len(mail.outbox) == 1 + assert project.wiki_pages.all().count() == 1 + + +def test_create_wiki_link_of_inexistent_wiki_page_without_permissions(client): + project = f.ProjectFactory.create() + role = f.RoleFactory.create(project=project, permissions=['view_wiki_pages', 'view_wiki_link', + 'add_wiki_link']) + + f.MembershipFactory.create(project=project, user=project.owner, role=role) + project.owner.notify_policies.filter(project=project).update(notify_level=NotifyLevel.all) + + user = f.UserFactory.create() + f.MembershipFactory.create(project=project, user=user, role=role) + + mail.outbox = [] + + url = reverse("wiki-links-list") + + data = { + "title": "test", + "href": "test", + "project": project.pk, + } + + assert project.wiki_pages.all().count() == 0 + client.login(user) + response = client.json.post(url, json.dumps(data)) + assert response.status_code == 201 + assert len(mail.outbox) == 0 + assert project.wiki_pages.all().count() == 0