remotes/origin/issue/4795/notification_even_they_are_disabled
parent
40eaa7e119
commit
9f4886963a
|
@ -4,7 +4,14 @@
|
|||
## 2.1.0 ??? (unreleased)
|
||||
|
||||
### Features
|
||||
- ...
|
||||
- Webhooks: Improve webhook data:
|
||||
- add permalinks
|
||||
- owner, assigned_to, status, type, priority, severity, user_story, milestone, project are objects
|
||||
- add role to 'points' object
|
||||
- add the owner to every notification ('by' field)
|
||||
- add the date of the notification ('date' field)
|
||||
- show human diffs in 'changes'
|
||||
- remove unnecessary data
|
||||
|
||||
### Misc
|
||||
- Add sprint name and slug on search results for user stories ((thanks to [@everblut](https://github.com/everblut)))
|
||||
|
|
|
@ -22,8 +22,8 @@ from taiga.base.api.utils import encoders
|
|||
import json
|
||||
|
||||
|
||||
def dumps(data, ensure_ascii=True, encoder_class=encoders.JSONEncoder):
|
||||
return json.dumps(data, cls=encoder_class, indent=None, ensure_ascii=ensure_ascii)
|
||||
def dumps(data, ensure_ascii=True, encoder_class=encoders.JSONEncoder, indent=None):
|
||||
return json.dumps(data, cls=encoder_class, ensure_ascii=ensure_ascii, indent=indent)
|
||||
|
||||
|
||||
def loads(data):
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# 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 django.utils import timezone
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from taiga.base import filters
|
||||
|
@ -45,7 +46,7 @@ class WebhookViewSet(BlockedByProjectMixin, ModelCrudViewSet):
|
|||
self.check_permissions(request, 'test', webhook)
|
||||
self.pre_conditions_blocked(webhook)
|
||||
|
||||
webhooklog = tasks.test_webhook(webhook.id, webhook.url, webhook.key)
|
||||
webhooklog = tasks.test_webhook(webhook.id, webhook.url, webhook.key, request.user, timezone.now())
|
||||
log = serializers.WebhookLogSerializer(webhooklog)
|
||||
|
||||
return response.Ok(log.data)
|
||||
|
|
|
@ -20,21 +20,26 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||
from taiga.base.api import serializers
|
||||
from taiga.base.fields import TagsField, PgArrayField, JsonField
|
||||
|
||||
from taiga.projects.userstories import models as us_models
|
||||
from taiga.projects.tasks import models as task_models
|
||||
from taiga.front.templatetags.functions import resolve as resolve_front_url
|
||||
|
||||
from taiga.projects.history import models as history_models
|
||||
from taiga.projects.issues import models as issue_models
|
||||
from taiga.projects.milestones import models as milestone_models
|
||||
from taiga.projects.wiki import models as wiki_models
|
||||
from taiga.projects.history import models as history_models
|
||||
from taiga.projects.notifications.mixins import EditableWatchedResourceModelSerializer
|
||||
from taiga.projects.services import get_logo_big_thumbnail_url
|
||||
from taiga.projects.tasks import models as task_models
|
||||
from taiga.projects.userstories import models as us_models
|
||||
from taiga.projects.wiki import models as wiki_models
|
||||
|
||||
from taiga.users.gravatar import get_gravatar_url
|
||||
from taiga.users.services import get_photo_or_gravatar_url
|
||||
|
||||
from .models import Webhook, WebhookLog
|
||||
|
||||
|
||||
class HistoryDiffField(serializers.Field):
|
||||
def to_native(self, obj):
|
||||
return {key: {"from": value[0], "to": value[1]} for key, value in obj.items()}
|
||||
|
||||
########################################################################
|
||||
## WebHooks
|
||||
########################################################################
|
||||
|
||||
class WebhookSerializer(serializers.ModelSerializer):
|
||||
logs_counter = serializers.SerializerMethodField("get_logs_counter")
|
||||
|
@ -55,16 +60,93 @@ class WebhookLogSerializer(serializers.ModelSerializer):
|
|||
model = WebhookLog
|
||||
|
||||
|
||||
########################################################################
|
||||
## User
|
||||
########################################################################
|
||||
|
||||
class UserSerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
permalink = serializers.SerializerMethodField("get_permalink")
|
||||
gravatar_url = serializers.SerializerMethodField("get_gravatar_url")
|
||||
username = serializers.SerializerMethodField("get_username")
|
||||
full_name = serializers.SerializerMethodField("get_full_name")
|
||||
photo = serializers.SerializerMethodField("get_photo")
|
||||
|
||||
def get_pk(self, obj):
|
||||
return obj.pk
|
||||
|
||||
def get_name(self, obj):
|
||||
return obj.full_name
|
||||
def get_permalink(self, obj):
|
||||
return resolve_front_url("user", obj.username)
|
||||
|
||||
def get_gravatar_url(self, obj):
|
||||
return get_gravatar_url(obj.email)
|
||||
|
||||
def get_username(self, obj):
|
||||
return obj.get_username
|
||||
|
||||
def get_full_name(self, obj):
|
||||
return obj.get_full_name()
|
||||
|
||||
def get_photo(self, obj):
|
||||
return get_photo_or_gravatar_url(obj)
|
||||
|
||||
########################################################################
|
||||
## Project
|
||||
########################################################################
|
||||
|
||||
class ProjectSerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
permalink = serializers.SerializerMethodField("get_permalink")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
logo_big_url = serializers.SerializerMethodField("get_logo_big_url")
|
||||
|
||||
def get_pk(self, obj):
|
||||
return obj.pk
|
||||
|
||||
def get_permalink(self, obj):
|
||||
return resolve_front_url("project", obj.slug)
|
||||
|
||||
def get_name(self, obj):
|
||||
return obj.name
|
||||
|
||||
def get_logo_big_url(self, obj):
|
||||
return get_logo_big_thumbnail_url(obj)
|
||||
|
||||
|
||||
########################################################################
|
||||
## History Serializer
|
||||
########################################################################
|
||||
|
||||
class HistoryDiffField(serializers.Field):
|
||||
def to_native(self, value):
|
||||
# Tip: 'value' is the object returned by
|
||||
# taiga.projects.history.models.HistoryEntry.values_diff()
|
||||
|
||||
ret = {}
|
||||
|
||||
for key, val in value.items():
|
||||
if key in ["attachments", "custom_attributes"]:
|
||||
ret[key] = val
|
||||
elif key == "points":
|
||||
ret[key] = {k: {"from": v[0], "to": v[1]} for k, v in val.items()}
|
||||
else:
|
||||
ret[key] = {"from": val[0], "to": val[1]}
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class HistoryEntrySerializer(serializers.ModelSerializer):
|
||||
diff = HistoryDiffField(source="values_diff")
|
||||
|
||||
class Meta:
|
||||
model = history_models.HistoryEntry
|
||||
exclude = ("id", "type", "key", "is_hidden", "is_snapshot", "snapshot", "user", "delete_comment_user",
|
||||
"values", "created_at")
|
||||
|
||||
|
||||
########################################################################
|
||||
## _Misc_
|
||||
########################################################################
|
||||
|
||||
class CustomAttributesValuesWebhookSerializerMixin(serializers.ModelSerializer):
|
||||
custom_attributes_values = serializers.SerializerMethodField("get_custom_attributes_values")
|
||||
|
@ -90,86 +172,251 @@ class CustomAttributesValuesWebhookSerializerMixin(serializers.ModelSerializer):
|
|||
except ObjectDoesNotExist:
|
||||
return None
|
||||
|
||||
class PointSerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
|
||||
class RolePointsSerializer(serializers.Serializer):
|
||||
role = serializers.SerializerMethodField("get_role")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
value = serializers.SerializerMethodField("get_value")
|
||||
|
||||
def get_role(self, obj):
|
||||
return obj.role.name
|
||||
|
||||
def get_name(self, obj):
|
||||
return obj.points.name
|
||||
|
||||
def get_value(self, obj):
|
||||
return obj.points.value
|
||||
|
||||
|
||||
class UserStoryStatusSerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
slug = serializers.SerializerMethodField("get_slug")
|
||||
color = serializers.SerializerMethodField("get_color")
|
||||
is_closed = serializers.SerializerMethodField("get_is_closed")
|
||||
is_archived = serializers.SerializerMethodField("get_is_archived")
|
||||
|
||||
def get_pk(self, obj):
|
||||
return obj.pk
|
||||
|
||||
def get_name(self, obj):
|
||||
return obj.name
|
||||
|
||||
def get_value(self, obj):
|
||||
return obj.value
|
||||
def get_slug(self, obj):
|
||||
return obj.slug
|
||||
|
||||
def get_color(self, obj):
|
||||
return obj.color
|
||||
|
||||
def get_is_closed(self, obj):
|
||||
return obj.is_closed
|
||||
|
||||
def get_is_archived(self, obj):
|
||||
return obj.is_archived
|
||||
|
||||
|
||||
class UserStorySerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
|
||||
serializers.ModelSerializer):
|
||||
tags = TagsField(default=[], required=False)
|
||||
external_reference = PgArrayField(required=False)
|
||||
owner = UserSerializer()
|
||||
assigned_to = UserSerializer()
|
||||
points = PointSerializer(many=True)
|
||||
class TaskStatusSerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
slug = serializers.SerializerMethodField("get_slug")
|
||||
color = serializers.SerializerMethodField("get_color")
|
||||
is_closed = serializers.SerializerMethodField("get_is_closed")
|
||||
|
||||
class Meta:
|
||||
model = us_models.UserStory
|
||||
exclude = ("backlog_order", "sprint_order", "kanban_order", "version")
|
||||
def get_pk(self, obj):
|
||||
return obj.pk
|
||||
|
||||
def custom_attributes_queryset(self, project):
|
||||
return project.userstorycustomattributes.all()
|
||||
def get_name(self, obj):
|
||||
return obj.name
|
||||
|
||||
def get_slug(self, obj):
|
||||
return obj.slug
|
||||
|
||||
def get_color(self, obj):
|
||||
return obj.color
|
||||
|
||||
def get_is_closed(self, obj):
|
||||
return obj.is_closed
|
||||
|
||||
|
||||
class TaskSerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
|
||||
serializers.ModelSerializer):
|
||||
tags = TagsField(default=[], required=False)
|
||||
owner = UserSerializer()
|
||||
assigned_to = UserSerializer()
|
||||
class IssueStatusSerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
slug = serializers.SerializerMethodField("get_slug")
|
||||
color = serializers.SerializerMethodField("get_color")
|
||||
is_closed = serializers.SerializerMethodField("get_is_closed")
|
||||
|
||||
class Meta:
|
||||
model = task_models.Task
|
||||
def get_pk(self, obj):
|
||||
return obj.pk
|
||||
|
||||
def custom_attributes_queryset(self, project):
|
||||
return project.taskcustomattributes.all()
|
||||
def get_name(self, obj):
|
||||
return obj.name
|
||||
|
||||
def get_slug(self, obj):
|
||||
return obj.slug
|
||||
|
||||
def get_color(self, obj):
|
||||
return obj.color
|
||||
|
||||
def get_is_closed(self, obj):
|
||||
return obj.is_closed
|
||||
|
||||
|
||||
class IssueSerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
|
||||
serializers.ModelSerializer):
|
||||
tags = TagsField(default=[], required=False)
|
||||
owner = UserSerializer()
|
||||
assigned_to = UserSerializer()
|
||||
class IssueTypeSerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
color = serializers.SerializerMethodField("get_color")
|
||||
|
||||
class Meta:
|
||||
model = issue_models.Issue
|
||||
def get_pk(self, obj):
|
||||
return obj.pk
|
||||
|
||||
def custom_attributes_queryset(self, project):
|
||||
return project.issuecustomattributes.all()
|
||||
def get_name(self, obj):
|
||||
return obj.name
|
||||
|
||||
def get_color(self, obj):
|
||||
return obj.color
|
||||
|
||||
|
||||
class WikiPageSerializer(serializers.ModelSerializer):
|
||||
owner = UserSerializer()
|
||||
last_modifier = UserSerializer()
|
||||
class PrioritySerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
color = serializers.SerializerMethodField("get_color")
|
||||
|
||||
class Meta:
|
||||
model = wiki_models.WikiPage
|
||||
exclude = ("watchers", "version")
|
||||
def get_pk(self, obj):
|
||||
return obj.pk
|
||||
|
||||
def get_name(self, obj):
|
||||
return obj.name
|
||||
|
||||
def get_color(self, obj):
|
||||
return obj.color
|
||||
|
||||
|
||||
class SeveritySerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
color = serializers.SerializerMethodField("get_color")
|
||||
|
||||
def get_pk(self, obj):
|
||||
return obj.pk
|
||||
|
||||
def get_name(self, obj):
|
||||
return obj.name
|
||||
|
||||
def get_color(self, obj):
|
||||
return obj.color
|
||||
|
||||
|
||||
########################################################################
|
||||
## Milestone
|
||||
########################################################################
|
||||
|
||||
class MilestoneSerializer(serializers.ModelSerializer):
|
||||
permalink = serializers.SerializerMethodField("get_permalink")
|
||||
project = ProjectSerializer()
|
||||
owner = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = milestone_models.Milestone
|
||||
exclude = ("order", "watchers")
|
||||
|
||||
def get_permalink(self, obj):
|
||||
return resolve_front_url("taskboard", obj.project.slug, obj.slug)
|
||||
|
||||
class HistoryEntrySerializer(serializers.ModelSerializer):
|
||||
diff = HistoryDiffField()
|
||||
snapshot = JsonField()
|
||||
values = JsonField()
|
||||
user = JsonField()
|
||||
delete_comment_user = JsonField()
|
||||
|
||||
########################################################################
|
||||
## User Story
|
||||
########################################################################
|
||||
|
||||
class UserStorySerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
|
||||
serializers.ModelSerializer):
|
||||
permalink = serializers.SerializerMethodField("get_permalink")
|
||||
tags = TagsField(default=[], required=False)
|
||||
external_reference = PgArrayField(required=False)
|
||||
project = ProjectSerializer()
|
||||
owner = UserSerializer()
|
||||
assigned_to = UserSerializer()
|
||||
points = RolePointsSerializer(source="role_points", many=True)
|
||||
status = UserStoryStatusSerializer()
|
||||
milestone = MilestoneSerializer()
|
||||
|
||||
class Meta:
|
||||
model = history_models.HistoryEntry
|
||||
model = us_models.UserStory
|
||||
exclude = ("backlog_order", "sprint_order", "kanban_order", "version", "total_watchers", "is_watcher")
|
||||
|
||||
def get_permalink(self, obj):
|
||||
return resolve_front_url("userstory", obj.project.slug, obj.ref)
|
||||
|
||||
def custom_attributes_queryset(self, project):
|
||||
return project.userstorycustomattributes.all()
|
||||
|
||||
|
||||
########################################################################
|
||||
## Task
|
||||
########################################################################
|
||||
|
||||
class TaskSerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
|
||||
serializers.ModelSerializer):
|
||||
permalink = serializers.SerializerMethodField("get_permalink")
|
||||
tags = TagsField(default=[], required=False)
|
||||
project = ProjectSerializer()
|
||||
owner = UserSerializer()
|
||||
assigned_to = UserSerializer()
|
||||
status = TaskStatusSerializer()
|
||||
user_story = UserStorySerializer()
|
||||
milestone = MilestoneSerializer()
|
||||
|
||||
class Meta:
|
||||
model = task_models.Task
|
||||
exclude = ("version", "total_watchers", "is_watcher")
|
||||
|
||||
def get_permalink(self, obj):
|
||||
return resolve_front_url("task", obj.project.slug, obj.ref)
|
||||
|
||||
def custom_attributes_queryset(self, project):
|
||||
return project.taskcustomattributes.all()
|
||||
|
||||
|
||||
########################################################################
|
||||
## Issue
|
||||
########################################################################
|
||||
|
||||
class IssueSerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
|
||||
serializers.ModelSerializer):
|
||||
permalink = serializers.SerializerMethodField("get_permalink")
|
||||
tags = TagsField(default=[], required=False)
|
||||
project = ProjectSerializer()
|
||||
milestone = MilestoneSerializer()
|
||||
owner = UserSerializer()
|
||||
assigned_to = UserSerializer()
|
||||
status = IssueStatusSerializer()
|
||||
type = IssueTypeSerializer()
|
||||
priority = PrioritySerializer()
|
||||
severity = SeveritySerializer()
|
||||
|
||||
class Meta:
|
||||
model = issue_models.Issue
|
||||
exclude = ("version", "total_watchers", "is_watcher")
|
||||
|
||||
def get_permalink(self, obj):
|
||||
return resolve_front_url("issue", obj.project.slug, obj.ref)
|
||||
|
||||
def custom_attributes_queryset(self, project):
|
||||
return project.issuecustomattributes.all()
|
||||
|
||||
|
||||
########################################################################
|
||||
## Wiki Page
|
||||
########################################################################
|
||||
|
||||
class WikiPageSerializer(serializers.ModelSerializer):
|
||||
permalink = serializers.SerializerMethodField("get_permalink")
|
||||
project = ProjectSerializer()
|
||||
owner = UserSerializer()
|
||||
last_modifier = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = wiki_models.WikiPage
|
||||
exclude = ("watchers", "total_watchers", "is_watcher", "version")
|
||||
|
||||
def get_permalink(self, obj):
|
||||
return resolve_front_url("wiki", obj.project.slug, obj.slug)
|
||||
|
|
|
@ -61,10 +61,13 @@ def on_new_history_entry(sender, instance, created, **kwargs):
|
|||
extra_args = [instance]
|
||||
elif instance.type == HistoryType.delete:
|
||||
task = tasks.delete_webhook
|
||||
extra_args = [timezone.now()]
|
||||
extra_args = []
|
||||
|
||||
by = instance.owner
|
||||
date = timezone.now()
|
||||
|
||||
for webhook in webhooks:
|
||||
args = [webhook["id"], webhook["url"], webhook["key"], obj] + extra_args
|
||||
args = [webhook["id"], webhook["url"], webhook["key"], by, date, obj] + extra_args
|
||||
|
||||
if settings.CELERY_ENABLED:
|
||||
connection.on_commit(lambda: task.delay(*args))
|
||||
|
|
|
@ -26,7 +26,7 @@ from taiga.celery import app
|
|||
|
||||
from .serializers import (UserStorySerializer, IssueSerializer, TaskSerializer,
|
||||
WikiPageSerializer, MilestoneSerializer,
|
||||
HistoryEntrySerializer)
|
||||
HistoryEntrySerializer, UserSerializer)
|
||||
from .models import WebhookLog
|
||||
|
||||
|
||||
|
@ -67,58 +67,70 @@ def _send_request(webhook_id, url, key, data):
|
|||
request = requests.Request('POST', url, data=serialized_data, headers=headers)
|
||||
prepared_request = request.prepare()
|
||||
|
||||
session = requests.Session()
|
||||
try:
|
||||
response = session.send(prepared_request)
|
||||
webhook_log = WebhookLog.objects.create(webhook_id=webhook_id, url=url,
|
||||
status=response.status_code,
|
||||
request_data=data,
|
||||
request_headers=dict(prepared_request.headers),
|
||||
response_data=response.content,
|
||||
response_headers=dict(response.headers),
|
||||
duration=response.elapsed.total_seconds())
|
||||
except RequestException as e:
|
||||
webhook_log = WebhookLog.objects.create(webhook_id=webhook_id, url=url, status=0,
|
||||
request_data=data,
|
||||
request_headers=dict(prepared_request.headers),
|
||||
response_data="error-in-request: {}".format(str(e)),
|
||||
response_headers={},
|
||||
duration=0)
|
||||
session.close()
|
||||
with requests.Session() as session:
|
||||
try:
|
||||
response = session.send(prepared_request)
|
||||
except RequestException as e:
|
||||
# Error sending the webhook
|
||||
webhook_log = WebhookLog.objects.create(webhook_id=webhook_id, url=url, status=0,
|
||||
request_data=data,
|
||||
request_headers=dict(prepared_request.headers),
|
||||
response_data="error-in-request: {}".format(str(e)),
|
||||
response_headers={},
|
||||
duration=0)
|
||||
else:
|
||||
# Webhook was sent successfully
|
||||
webhook_log = WebhookLog.objects.create(webhook_id=webhook_id, url=url,
|
||||
status=response.status_code,
|
||||
request_data=data,
|
||||
request_headers=dict(prepared_request.headers),
|
||||
response_data=response.content,
|
||||
response_headers=dict(response.headers),
|
||||
duration=response.elapsed.total_seconds())
|
||||
finally:
|
||||
# Only the last ten webhook logs traces are required
|
||||
# so remove the leftover
|
||||
ids = (WebhookLog.objects.filter(webhook_id=webhook_id)
|
||||
.order_by("-id")
|
||||
.values_list('id', flat=True)[10:])
|
||||
WebhookLog.objects.filter(id__in=ids).delete()
|
||||
|
||||
ids = [log.id for log in WebhookLog.objects.filter(webhook_id=webhook_id).order_by("-id")[10:]]
|
||||
WebhookLog.objects.filter(id__in=ids).delete()
|
||||
return webhook_log
|
||||
|
||||
|
||||
@app.task
|
||||
def change_webhook(webhook_id, url, key, obj, change):
|
||||
def create_webhook(webhook_id, url, key, by, date, obj):
|
||||
data = {}
|
||||
data['data'] = _serialize(obj)
|
||||
data['action'] = "change"
|
||||
data['type'] = _get_type(obj)
|
||||
data['change'] = _serialize(change)
|
||||
|
||||
return _send_request(webhook_id, url, key, data)
|
||||
|
||||
|
||||
@app.task
|
||||
def create_webhook(webhook_id, url, key, obj):
|
||||
data = {}
|
||||
data['data'] = _serialize(obj)
|
||||
data['action'] = "create"
|
||||
data['type'] = _get_type(obj)
|
||||
data['by'] = UserSerializer(by).data
|
||||
data['date'] = date
|
||||
data['data'] = _serialize(obj)
|
||||
|
||||
return _send_request(webhook_id, url, key, data)
|
||||
|
||||
|
||||
@app.task
|
||||
def delete_webhook(webhook_id, url, key, obj, deleted_date):
|
||||
def delete_webhook(webhook_id, url, key, by, date, obj):
|
||||
data = {}
|
||||
data['data'] = _serialize(obj)
|
||||
data['action'] = "delete"
|
||||
data['type'] = _get_type(obj)
|
||||
data['deleted_date'] = deleted_date
|
||||
data['by'] = UserSerializer(by).data
|
||||
data['date'] = date
|
||||
data['data'] = _serialize(obj)
|
||||
|
||||
return _send_request(webhook_id, url, key, data)
|
||||
|
||||
|
||||
@app.task
|
||||
def change_webhook(webhook_id, url, key, by, date, obj, change):
|
||||
data = {}
|
||||
data['action'] = "change"
|
||||
data['type'] = _get_type(obj)
|
||||
data['by'] = UserSerializer(by).data
|
||||
data['date'] = date
|
||||
data['data'] = _serialize(obj)
|
||||
data['change'] = _serialize(change)
|
||||
|
||||
return _send_request(webhook_id, url, key, data)
|
||||
|
||||
|
@ -129,10 +141,12 @@ def resend_webhook(webhook_id, url, key, data):
|
|||
|
||||
|
||||
@app.task
|
||||
def test_webhook(webhook_id, url, key):
|
||||
def test_webhook(webhook_id, url, key, by, date):
|
||||
data = {}
|
||||
data['data'] = {"test": "test"}
|
||||
data['action'] = "test"
|
||||
data['type'] = "test"
|
||||
data['by'] = UserSerializer(by).data
|
||||
data['date'] = date
|
||||
data['data'] = {"test": "test"}
|
||||
|
||||
return _send_request(webhook_id, url, key, data)
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
|
||||
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
||||
# Copyright (C) 2014-2016 Anler Hernández <hello@anler.me>
|
||||
# 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/>.
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
from taiga.projects.history import services
|
||||
|
||||
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
from taiga.base.utils import json
|
||||
|
||||
def test_webhooks_when_create_issue(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.IssueFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "create"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
|
||||
|
||||
def test_webhooks_when_update_issue(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.IssueFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
obj.subject = "test webhook update"
|
||||
obj.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["data"]["subject"] == obj.subject
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert data["change"]["diff"]["subject"]["to"] == data["data"]["subject"]
|
||||
assert data["change"]["diff"]["subject"]["from"] != data["data"]["subject"]
|
||||
|
||||
|
||||
def test_webhooks_when_delete_issue(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.IssueFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, delete=True)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "delete"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert "data" in data
|
||||
|
||||
|
||||
def test_webhooks_when_update_issue_attachments(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.IssueFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
# Create attachments
|
||||
attachment1 = f.IssueAttachmentFactory(project=obj.project, content_object=obj, owner=obj.owner)
|
||||
attachment2 = f.IssueAttachmentFactory(project=obj.project, content_object=obj, owner=obj.owner)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 2
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 0
|
||||
|
||||
# Update attachment
|
||||
attachment1.description = "new attachment description"
|
||||
attachment1.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 1
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 0
|
||||
|
||||
# Delete attachment
|
||||
attachment2.delete()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 1
|
||||
|
||||
|
||||
def test_webhooks_when_update_issue_custom_attributes(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.IssueFactory.create(project=project)
|
||||
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory(project=obj.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=obj.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
# Create custom attributes
|
||||
obj.custom_attributes_values.attributes_values = {
|
||||
ct1_id: "test_1_updated",
|
||||
ct2_id: "test_2_updated"
|
||||
}
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 2
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 0
|
||||
|
||||
# Update custom attributes
|
||||
obj.custom_attributes_values.attributes_values[ct1_id] = "test_2_updated"
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 1
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 0
|
||||
|
||||
# Delete custom attributes
|
||||
del obj.custom_attributes_values.attributes_values[ct1_id]
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "issue"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 1
|
|
@ -0,0 +1,101 @@
|
|||
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
|
||||
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
||||
# Copyright (C) 2014-2016 Anler Hernández <hello@anler.me>
|
||||
# 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/>.
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
from taiga.projects.history import services
|
||||
|
||||
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
from taiga.base.utils import json
|
||||
|
||||
def test_webhooks_when_create_milestone(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.MilestoneFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "create"
|
||||
assert data["type"] == "milestone"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
|
||||
|
||||
def test_webhooks_when_update_milestone(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.MilestoneFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
obj.name = "test webhook update"
|
||||
obj.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "milestone"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["data"]["name"] == obj.name
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert data["change"]["diff"]["name"]["to"] == data["data"]["name"]
|
||||
assert data["change"]["diff"]["name"]["from"] != data["data"]["name"]
|
||||
|
||||
|
||||
def test_webhooks_when_delete_milestone(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.MilestoneFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, delete=True)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "delete"
|
||||
assert data["type"] == "milestone"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert "data" in data
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import pytest
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
|
@ -26,7 +27,7 @@ from taiga.projects.history import services
|
|||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
def test_new_object_with_one_webhook(settings):
|
||||
def test_new_object_with_one_webhook_signal(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
@ -38,28 +39,31 @@ def test_new_object_with_one_webhook(settings):
|
|||
f.WikiPageFactory.create(project=project)
|
||||
]
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks.create_webhook') as create_webhook_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test")
|
||||
assert create_webhook_mock.call_count == 1
|
||||
response = Mock(status_code=200, headers={}, content="ok")
|
||||
response.elapsed.total_seconds.return_value = 100
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks.change_webhook') as change_webhook_mock:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test")
|
||||
assert session_send_mock.call_count == 1
|
||||
|
||||
for obj in objects:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert change_webhook_mock.call_count == 0
|
||||
assert session_send_mock.call_count == 0
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks.change_webhook') as change_webhook_mock:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test")
|
||||
assert change_webhook_mock.call_count == 1
|
||||
assert session_send_mock.call_count == 1
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks.delete_webhook') as delete_webhook_mock:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test", delete=True)
|
||||
assert delete_webhook_mock.call_count == 1
|
||||
assert session_send_mock.call_count == 1
|
||||
|
||||
|
||||
def test_new_object_with_two_webhook(settings):
|
||||
def test_new_object_with_two_webhook_signals(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
@ -72,28 +76,31 @@ def test_new_object_with_two_webhook(settings):
|
|||
f.WikiPageFactory.create(project=project)
|
||||
]
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks.create_webhook') as create_webhook_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test")
|
||||
assert create_webhook_mock.call_count == 2
|
||||
response = Mock(status_code=200, headers={}, content="ok")
|
||||
response.elapsed.total_seconds.return_value = 100
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks.change_webhook') as change_webhook_mock:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test")
|
||||
assert change_webhook_mock.call_count == 2
|
||||
assert session_send_mock.call_count == 2
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks.change_webhook') as change_webhook_mock:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test")
|
||||
assert session_send_mock.call_count == 2
|
||||
|
||||
for obj in objects:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert change_webhook_mock.call_count == 0
|
||||
assert session_send_mock.call_count == 0
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks.delete_webhook') as delete_webhook_mock:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test", delete=True)
|
||||
assert delete_webhook_mock.call_count == 2
|
||||
assert session_send_mock.call_count == 2
|
||||
|
||||
|
||||
def test_send_request_one_webhook(settings):
|
||||
def test_send_request_one_webhook_signal(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
@ -105,12 +112,15 @@ def test_send_request_one_webhook(settings):
|
|||
f.WikiPageFactory.create(project=project)
|
||||
]
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks._send_request') as _send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test")
|
||||
assert _send_request_mock.call_count == 1
|
||||
response = Mock(status_code=200, headers={}, content="ok")
|
||||
response.elapsed.total_seconds.return_value = 100
|
||||
|
||||
for obj in objects:
|
||||
with patch('taiga.webhooks.tasks._send_request') as _send_request_mock:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test")
|
||||
assert session_send_mock.call_count == 1
|
||||
|
||||
for obj in objects:
|
||||
with patch("taiga.webhooks.tasks.requests.Session.send", return_value=response) as session_send_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test", delete=True)
|
||||
assert _send_request_mock.call_count == 1
|
||||
assert session_send_mock.call_count == 1
|
|
@ -0,0 +1,248 @@
|
|||
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
|
||||
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
||||
# Copyright (C) 2014-2016 Anler Hernández <hello@anler.me>
|
||||
# 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/>.
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
from taiga.projects.history import services
|
||||
|
||||
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
from taiga.base.utils import json
|
||||
|
||||
def test_webhooks_when_create_task(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.TaskFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "create"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
|
||||
|
||||
def test_webhooks_when_update_task(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.TaskFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
obj.subject = "test webhook update"
|
||||
obj.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["data"]["subject"] == obj.subject
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert data["change"]["diff"]["subject"]["to"] == data["data"]["subject"]
|
||||
assert data["change"]["diff"]["subject"]["from"] != data["data"]["subject"]
|
||||
|
||||
|
||||
def test_webhooks_when_delete_task(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.TaskFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, delete=True)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "delete"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert "data" in data
|
||||
|
||||
|
||||
def test_webhooks_when_update_task_attachments(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.TaskFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
# Create attachments
|
||||
attachment1 = f.TaskAttachmentFactory(project=obj.project, content_object=obj, owner=obj.owner)
|
||||
attachment2 = f.TaskAttachmentFactory(project=obj.project, content_object=obj, owner=obj.owner)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 2
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 0
|
||||
|
||||
# Update attachment
|
||||
attachment1.description = "new attachment description"
|
||||
attachment1.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 1
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 0
|
||||
|
||||
# Delete attachment
|
||||
attachment2.delete()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 1
|
||||
|
||||
|
||||
def test_webhooks_when_update_task_custom_attributes(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.TaskFactory.create(project=project)
|
||||
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory(project=obj.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=obj.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
# Create custom attributes
|
||||
obj.custom_attributes_values.attributes_values = {
|
||||
ct1_id: "test_1_updated",
|
||||
ct2_id: "test_2_updated"
|
||||
}
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 2
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 0
|
||||
|
||||
# Update custom attributes
|
||||
obj.custom_attributes_values.attributes_values[ct1_id] = "test_2_updated"
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 1
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 0
|
||||
|
||||
# Delete custom attributes
|
||||
del obj.custom_attributes_values.attributes_values[ct1_id]
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "task"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 1
|
|
@ -0,0 +1,308 @@
|
|||
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
|
||||
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
||||
# Copyright (C) 2014-2016 Anler Hernández <hello@anler.me>
|
||||
# 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/>.
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
from taiga.projects.history import services
|
||||
|
||||
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
from taiga.base.utils import json
|
||||
|
||||
def test_webhooks_when_create_user_story(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.UserStoryFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "create"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
|
||||
|
||||
def test_webhooks_when_update_user_story(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.UserStoryFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
obj.subject = "test webhook update"
|
||||
obj.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["data"]["subject"] == obj.subject
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert data["change"]["diff"]["subject"]["to"] == data["data"]["subject"]
|
||||
assert data["change"]["diff"]["subject"]["from"] != data["data"]["subject"]
|
||||
|
||||
|
||||
def test_webhooks_when_delete_user_story(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.UserStoryFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, delete=True)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "delete"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert "data" in data
|
||||
|
||||
|
||||
def test_webhooks_when_update_user_story_attachments(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.UserStoryFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
# Create attachments
|
||||
attachment1 = f.UserStoryAttachmentFactory(project=obj.project, content_object=obj, owner=obj.owner)
|
||||
attachment2 = f.UserStoryAttachmentFactory(project=obj.project, content_object=obj, owner=obj.owner)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 2
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 0
|
||||
|
||||
# Update attachment
|
||||
attachment1.description = "new attachment description"
|
||||
attachment1.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 1
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 0
|
||||
|
||||
# Delete attachment
|
||||
attachment2.delete()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 1
|
||||
|
||||
|
||||
def test_webhooks_when_update_user_story_custom_attributes(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.UserStoryFactory.create(project=project)
|
||||
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory(project=obj.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=obj.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
# Create custom attributes
|
||||
obj.custom_attributes_values.attributes_values = {
|
||||
ct1_id: "test_1_updated",
|
||||
ct2_id: "test_2_updated"
|
||||
}
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 2
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 0
|
||||
|
||||
# Update custom attributes
|
||||
obj.custom_attributes_values.attributes_values[ct1_id] = "test_2_updated"
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 1
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 0
|
||||
|
||||
# Delete custom attributes
|
||||
del obj.custom_attributes_values.attributes_values[ct1_id]
|
||||
obj.custom_attributes_values.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["custom_attributes"]["deleted"]) == 1
|
||||
|
||||
|
||||
def test_webhooks_when_update_user_story_points(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
role1 = f.RoleFactory.create(project=project)
|
||||
role2 = f.RoleFactory.create(project=project)
|
||||
|
||||
points1 = f.PointsFactory.create(project=project, value=None)
|
||||
points2 = f.PointsFactory.create(project=project, value=1)
|
||||
points3 = f.PointsFactory.create(project=project, value=2)
|
||||
|
||||
obj = f.UserStoryFactory.create(project=project)
|
||||
obj.role_points.all().delete()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
# Set points
|
||||
f.RolePointsFactory.create(user_story=obj, role=role1, points=points1)
|
||||
f.RolePointsFactory.create(user_story=obj, role=role2, points=points2)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == ""
|
||||
assert data["change"]["diff"]["points"][role1.name]["from"] == None
|
||||
assert data["change"]["diff"]["points"][role1.name]["to"] == points1.name
|
||||
assert data["change"]["diff"]["points"][role2.name]["from"] == None
|
||||
assert data["change"]["diff"]["points"][role2.name]["to"] == points2.name
|
||||
|
||||
# Change points
|
||||
obj.role_points.all().update(points=points3)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "userstory"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == ""
|
||||
assert data["change"]["diff"]["points"][role1.name]["from"] == points1.name
|
||||
assert data["change"]["diff"]["points"][role1.name]["to"] == points3.name
|
||||
assert data["change"]["diff"]["points"][role2.name]["from"] == points2.name
|
||||
assert data["change"]["diff"]["points"][role2.name]["to"] == points3.name
|
|
@ -0,0 +1,170 @@
|
|||
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
|
||||
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
||||
# Copyright (C) 2014-2016 Anler Hernández <hello@anler.me>
|
||||
# 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/>.
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
from taiga.projects.history import services
|
||||
|
||||
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
from taiga.base.utils import json
|
||||
|
||||
def test_webhooks_when_create_wiki_page(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.WikiPageFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "create"
|
||||
assert data["type"] == "wikipage"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
|
||||
|
||||
def test_webhooks_when_update_wiki_page(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.WikiPageFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
obj.content = "test webhook update"
|
||||
obj.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "wikipage"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["data"]["content"] == obj.content
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert data["change"]["diff"]["content_html"]["from"] != data["change"]["diff"]["content_html"]["to"]
|
||||
assert obj.content in data["change"]["diff"]["content_html"]["to"]
|
||||
|
||||
|
||||
def test_webhooks_when_delete_wiki_page(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.WikiPageFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, delete=True)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "delete"
|
||||
assert data["type"] == "wikipage"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert "data" in data
|
||||
|
||||
|
||||
def test_webhooks_when_update_wiki_page_attachments(settings):
|
||||
settings.WEBHOOKS_ENABLED = True
|
||||
project = f.ProjectFactory()
|
||||
f.WebhookFactory.create(project=project)
|
||||
f.WebhookFactory.create(project=project)
|
||||
|
||||
obj = f.WikiPageFactory.create(project=project)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner)
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
# Create attachments
|
||||
attachment1 = f.WikiAttachmentFactory(project=obj.project, content_object=obj, owner=obj.owner)
|
||||
attachment2 = f.WikiAttachmentFactory(project=obj.project, content_object=obj, owner=obj.owner)
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "wikipage"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 2
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 0
|
||||
|
||||
# Update attachment
|
||||
attachment1.description = "new attachment description"
|
||||
attachment1.save()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "wikipage"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 1
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 0
|
||||
|
||||
# Delete attachment
|
||||
attachment2.delete()
|
||||
|
||||
with patch('taiga.webhooks.tasks._send_request') as send_request_mock:
|
||||
services.take_snapshot(obj, user=obj.owner, comment="test_comment")
|
||||
assert send_request_mock.call_count == 2
|
||||
|
||||
(webhook_id, url, key, data) = send_request_mock.call_args[0]
|
||||
assert data["action"] == "change"
|
||||
assert data["type"] == "wikipage"
|
||||
assert data["by"]["id"] == obj.owner.id
|
||||
assert "date" in data
|
||||
assert data["data"]["id"] == obj.id
|
||||
assert data["change"]["comment"] == "test_comment"
|
||||
assert len(data["change"]["diff"]["attachments"]["new"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["changed"]) == 0
|
||||
assert len(data["change"]["diff"]["attachments"]["deleted"]) == 1
|
Loading…
Reference in New Issue