commit
57777fc54c
|
@ -1,6 +1,6 @@
|
||||||
# Changelog #
|
# Changelog #
|
||||||
|
|
||||||
## 1.3.0 Dryas hookeriana (Unreleased)
|
## 1.3.0 Dryas hookeriana (2014-11-18)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- GitHub integration (Phase I):
|
- GitHub integration (Phase I):
|
||||||
|
|
|
@ -1 +1,17 @@
|
||||||
|
# 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 . import celery
|
from . import celery
|
||||||
|
|
|
@ -34,6 +34,7 @@ from djmail.template_mail import MagicMailBuilder
|
||||||
from taiga.base import exceptions as exc
|
from taiga.base import exceptions as exc
|
||||||
from taiga.users.serializers import UserSerializer
|
from taiga.users.serializers import UserSerializer
|
||||||
from taiga.users.services import get_and_validate_user
|
from taiga.users.services import get_and_validate_user
|
||||||
|
from taiga.base.utils.slug import slugify_uniquely
|
||||||
|
|
||||||
from .tokens import get_token_for_user
|
from .tokens import get_token_for_user
|
||||||
from .signals import user_registered as user_registered_signal
|
from .signals import user_registered as user_registered_signal
|
||||||
|
@ -50,7 +51,7 @@ def send_register_email(user) -> bool:
|
||||||
return bool(email.send())
|
return bool(email.send())
|
||||||
|
|
||||||
|
|
||||||
def is_user_already_registered(*, username:str, email:str, github_id:int=None) -> (bool, str):
|
def is_user_already_registered(*, username:str, email:str) -> (bool, str):
|
||||||
"""
|
"""
|
||||||
Checks if a specified user is already registred.
|
Checks if a specified user is already registred.
|
||||||
|
|
||||||
|
@ -65,9 +66,6 @@ def is_user_already_registered(*, username:str, email:str, github_id:int=None) -
|
||||||
if user_model.objects.filter(email=email):
|
if user_model.objects.filter(email=email):
|
||||||
return (True, _("Email is already in use."))
|
return (True, _("Email is already in use."))
|
||||||
|
|
||||||
if github_id and user_model.objects.filter(github_id=github_id):
|
|
||||||
return (True, _("GitHub id is already in use"))
|
|
||||||
|
|
||||||
return (False, None)
|
return (False, None)
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,20 +180,33 @@ def github_register(username:str, email:str, full_name:str, github_id:int, bio:s
|
||||||
:returns: User
|
:returns: User
|
||||||
"""
|
"""
|
||||||
user_model = apps.get_model("users", "User")
|
user_model = apps.get_model("users", "User")
|
||||||
user, created = user_model.objects.get_or_create(github_id=github_id,
|
|
||||||
defaults={"username": username,
|
try:
|
||||||
"email": email,
|
# Github user association exist?
|
||||||
"full_name": full_name,
|
user = user_model.objects.get(github_id=github_id)
|
||||||
"bio": bio})
|
except user_model.DoesNotExist:
|
||||||
|
try:
|
||||||
|
# Is a user with the same email as the github user?
|
||||||
|
user = user_model.objects.get(email=email)
|
||||||
|
user.github_id = github_id
|
||||||
|
user.save(update_fields=["github_id"])
|
||||||
|
except user_model.DoesNotExist:
|
||||||
|
# Create a new user
|
||||||
|
username_unique = slugify_uniquely(username, user_model, slugfield="username")
|
||||||
|
user = user_model.objects.create(email=email,
|
||||||
|
username=username_unique,
|
||||||
|
github_id=github_id,
|
||||||
|
full_name=full_name,
|
||||||
|
bio=bio)
|
||||||
|
|
||||||
|
send_register_email(user)
|
||||||
|
user_registered_signal.send(sender=user.__class__, user=user)
|
||||||
|
|
||||||
if token:
|
if token:
|
||||||
membership = get_membership_by_token(token)
|
membership = get_membership_by_token(token)
|
||||||
membership.user = user
|
membership.user = user
|
||||||
membership.save(update_fields=["user"])
|
membership.save(update_fields=["user"])
|
||||||
|
|
||||||
if created:
|
|
||||||
send_register_email(user)
|
|
||||||
user_registered_signal.send(sender=user.__class__, user=user)
|
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from celery import Celery
|
from celery import Celery
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
# 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 django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from .celery import app
|
from .celery import app
|
||||||
|
|
|
@ -110,11 +110,11 @@ class IssuesEventHook(BaseEventHook):
|
||||||
|
|
||||||
subject = self.payload.get('issue', {}).get('title', None)
|
subject = self.payload.get('issue', {}).get('title', None)
|
||||||
description = self.payload.get('issue', {}).get('body', None)
|
description = self.payload.get('issue', {}).get('body', None)
|
||||||
github_reference = self.payload.get('issue', {}).get('number', None)
|
github_url = self.payload.get('issue', {}).get('html_url', None)
|
||||||
github_user = self.payload.get('issue', {}).get('user', {}).get('id', None)
|
github_user = self.payload.get('issue', {}).get('user', {}).get('id', None)
|
||||||
project_url = self.payload.get('repository', {}).get('html_url', None)
|
project_url = self.payload.get('repository', {}).get('html_url', None)
|
||||||
|
|
||||||
if not all([subject, github_reference, project_url]):
|
if not all([subject, github_url, project_url]):
|
||||||
raise ActionSyntaxException(_("Invalid issue information"))
|
raise ActionSyntaxException(_("Invalid issue information"))
|
||||||
|
|
||||||
issue = Issue.objects.create(
|
issue = Issue.objects.create(
|
||||||
|
@ -125,7 +125,7 @@ class IssuesEventHook(BaseEventHook):
|
||||||
type=self.project.default_issue_type,
|
type=self.project.default_issue_type,
|
||||||
severity=self.project.default_severity,
|
severity=self.project.default_severity,
|
||||||
priority=self.project.default_priority,
|
priority=self.project.default_priority,
|
||||||
external_reference=['github', github_reference],
|
external_reference=['github', github_url],
|
||||||
owner=get_github_user(github_user)
|
owner=get_github_user(github_user)
|
||||||
)
|
)
|
||||||
take_snapshot(issue, user=get_github_user(github_user))
|
take_snapshot(issue, user=get_github_user(github_user))
|
||||||
|
@ -139,18 +139,18 @@ class IssueCommentEventHook(BaseEventHook):
|
||||||
if self.payload.get('action', None) != "created":
|
if self.payload.get('action', None) != "created":
|
||||||
raise ActionSyntaxException(_("Invalid issue comment information"))
|
raise ActionSyntaxException(_("Invalid issue comment information"))
|
||||||
|
|
||||||
github_reference = self.payload.get('issue', {}).get('number', None)
|
github_url = self.payload.get('issue', {}).get('html_url', None)
|
||||||
comment_message = self.payload.get('comment', {}).get('body', None)
|
comment_message = self.payload.get('comment', {}).get('body', None)
|
||||||
github_user = self.payload.get('sender', {}).get('id', None)
|
github_user = self.payload.get('sender', {}).get('id', None)
|
||||||
project_url = self.payload.get('repository', {}).get('html_url', None)
|
project_url = self.payload.get('repository', {}).get('html_url', None)
|
||||||
comment_message = replace_github_references(project_url, comment_message)
|
comment_message = replace_github_references(project_url, comment_message)
|
||||||
|
|
||||||
if not all([comment_message, github_reference, project_url]):
|
if not all([comment_message, github_url, project_url]):
|
||||||
raise ActionSyntaxException(_("Invalid issue comment information"))
|
raise ActionSyntaxException(_("Invalid issue comment information"))
|
||||||
|
|
||||||
issues = Issue.objects.filter(external_reference=["github", github_reference])
|
issues = Issue.objects.filter(external_reference=["github", github_url])
|
||||||
tasks = Task.objects.filter(external_reference=["github", github_reference])
|
tasks = Task.objects.filter(external_reference=["github", github_url])
|
||||||
uss = UserStory.objects.filter(external_reference=["github", github_reference])
|
uss = UserStory.objects.filter(external_reference=["github", github_url])
|
||||||
|
|
||||||
for item in list(issues) + list(tasks) + list(uss):
|
for item in list(issues) + list(tasks) + list(uss):
|
||||||
snapshot = take_snapshot(item,
|
snapshot = take_snapshot(item,
|
||||||
|
|
|
@ -52,7 +52,7 @@ from .extensions.references import TaigaReferencesExtension
|
||||||
|
|
||||||
|
|
||||||
# Bleach configuration
|
# Bleach configuration
|
||||||
bleach.ALLOWED_TAGS += ["p", "table", "th", "tr", "td", "h1", "h2", "h3",
|
bleach.ALLOWED_TAGS += ["p", "table", "thead", "tbody", "th", "tr", "td", "h1", "h2", "h3",
|
||||||
"div", "pre", "span", "hr", "dl", "dt", "dd", "sup",
|
"div", "pre", "span", "hr", "dl", "dt", "dd", "sup",
|
||||||
"img", "del", "br", "ins"]
|
"img", "del", "br", "ins"]
|
||||||
|
|
||||||
|
@ -74,7 +74,8 @@ def _make_extensions_list(wikilinks_config=None, project=None):
|
||||||
MentionsExtension(),
|
MentionsExtension(),
|
||||||
TaigaReferencesExtension(project),
|
TaigaReferencesExtension(project),
|
||||||
"extra",
|
"extra",
|
||||||
"codehilite"]
|
"codehilite",
|
||||||
|
"nl2br"]
|
||||||
|
|
||||||
|
|
||||||
import diff_match_patch
|
import diff_match_patch
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from taiga.base.serializers import Serializer, PickleField, NeighborsSerializerMixin
|
from taiga.base.serializers import Serializer, PickleField, NeighborsSerializerMixin, PgArrayField
|
||||||
from taiga.mdrender.service import render as mdrender
|
from taiga.mdrender.service import render as mdrender
|
||||||
from taiga.projects.validators import ProjectExistsValidator
|
from taiga.projects.validators import ProjectExistsValidator
|
||||||
from taiga.projects.notifications.validators import WatchersValidator
|
from taiga.projects.notifications.validators import WatchersValidator
|
||||||
|
@ -26,6 +26,7 @@ from . import models
|
||||||
|
|
||||||
class IssueSerializer(WatchersValidator, serializers.ModelSerializer):
|
class IssueSerializer(WatchersValidator, serializers.ModelSerializer):
|
||||||
tags = PickleField(required=False)
|
tags = PickleField(required=False)
|
||||||
|
external_reference = PgArrayField(required=False)
|
||||||
is_closed = serializers.Field(source="is_closed")
|
is_closed = serializers.Field(source="is_closed")
|
||||||
comment = serializers.SerializerMethodField("get_comment")
|
comment = serializers.SerializerMethodField("get_comment")
|
||||||
generated_user_stories = serializers.SerializerMethodField("get_generated_user_stories")
|
generated_user_stories = serializers.SerializerMethodField("get_generated_user_stories")
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from taiga.base.serializers import Serializer, PickleField, NeighborsSerializerMixin
|
from taiga.base.serializers import Serializer, PickleField, NeighborsSerializerMixin, PgArrayField
|
||||||
from taiga.mdrender.service import render as mdrender
|
from taiga.mdrender.service import render as mdrender
|
||||||
from taiga.projects.validators import ProjectExistsValidator, TaskStatusExistsValidator
|
from taiga.projects.validators import ProjectExistsValidator, TaskStatusExistsValidator
|
||||||
from taiga.projects.milestones.validators import SprintExistsValidator
|
from taiga.projects.milestones.validators import SprintExistsValidator
|
||||||
|
@ -28,6 +28,7 @@ from . import models
|
||||||
|
|
||||||
class TaskSerializer(WatchersValidator, serializers.ModelSerializer):
|
class TaskSerializer(WatchersValidator, serializers.ModelSerializer):
|
||||||
tags = PickleField(required=False, default=[])
|
tags = PickleField(required=False, default=[])
|
||||||
|
external_reference = PgArrayField(required=False)
|
||||||
comment = serializers.SerializerMethodField("get_comment")
|
comment = serializers.SerializerMethodField("get_comment")
|
||||||
milestone_slug = serializers.SerializerMethodField("get_milestone_slug")
|
milestone_slug = serializers.SerializerMethodField("get_milestone_slug")
|
||||||
blocked_note_html = serializers.SerializerMethodField("get_blocked_note_html")
|
blocked_note_html = serializers.SerializerMethodField("get_blocked_note_html")
|
||||||
|
|
|
@ -126,9 +126,15 @@ class UserStory(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, mod
|
||||||
return self.role_points
|
return self.role_points
|
||||||
|
|
||||||
def get_total_points(self):
|
def get_total_points(self):
|
||||||
|
not_null_role_points = self.role_points.select_related("points").\
|
||||||
|
exclude(points__value__isnull=True)
|
||||||
|
|
||||||
|
#If we only have None values the sum should be None
|
||||||
|
if not not_null_role_points:
|
||||||
|
return None
|
||||||
|
|
||||||
total = 0.0
|
total = 0.0
|
||||||
for rp in self.role_points.select_related("points"):
|
for rp in not_null_role_points:
|
||||||
if rp.points.value:
|
total += rp.points.value
|
||||||
total += rp.points.value
|
|
||||||
|
|
||||||
return total
|
return total
|
||||||
|
|
|
@ -18,7 +18,7 @@ import json
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from taiga.base.serializers import Serializer, PickleField, NeighborsSerializerMixin
|
from taiga.base.serializers import Serializer, PickleField, NeighborsSerializerMixin, PgArrayField
|
||||||
from taiga.mdrender.service import render as mdrender
|
from taiga.mdrender.service import render as mdrender
|
||||||
from taiga.projects.validators import ProjectExistsValidator, UserStoryStatusExistsValidator
|
from taiga.projects.validators import ProjectExistsValidator, UserStoryStatusExistsValidator
|
||||||
from taiga.projects.userstories.validators import UserStoryExistsValidator
|
from taiga.projects.userstories.validators import UserStoryExistsValidator
|
||||||
|
@ -39,6 +39,7 @@ class RolePointsField(serializers.WritableField):
|
||||||
|
|
||||||
class UserStorySerializer(WatchersValidator, serializers.ModelSerializer):
|
class UserStorySerializer(WatchersValidator, serializers.ModelSerializer):
|
||||||
tags = PickleField(default=[], required=False)
|
tags = PickleField(default=[], required=False)
|
||||||
|
external_reference = PgArrayField(required=False)
|
||||||
points = RolePointsField(source="role_points", required=False)
|
points = RolePointsField(source="role_points", required=False)
|
||||||
total_points = serializers.SerializerMethodField("get_total_points")
|
total_points = serializers.SerializerMethodField("get_total_points")
|
||||||
comment = serializers.SerializerMethodField("get_comment")
|
comment = serializers.SerializerMethodField("get_comment")
|
||||||
|
|
|
@ -115,6 +115,78 @@ def test_response_200_in_registration_with_github_account(client, settings):
|
||||||
assert response.data["bio"] == "time traveler"
|
assert response.data["bio"] == "time traveler"
|
||||||
assert response.data["github_id"] == 1955
|
assert response.data["github_id"] == 1955
|
||||||
|
|
||||||
|
def test_response_200_in_registration_with_github_account_and_existed_user_by_email(client, settings):
|
||||||
|
settings.PUBLIC_REGISTER_ENABLED = False
|
||||||
|
form = {"type": "github",
|
||||||
|
"code": "xxxxxx"}
|
||||||
|
user = factories.UserFactory()
|
||||||
|
user.email = "mmcfly@bttf.com"
|
||||||
|
user.github_id = None
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
with patch("taiga.base.connectors.github.me") as m_me:
|
||||||
|
m_me.return_value = ("mmcfly@bttf.com",
|
||||||
|
github.User(id=1955,
|
||||||
|
username="mmcfly",
|
||||||
|
full_name="martin seamus mcfly",
|
||||||
|
bio="time traveler"))
|
||||||
|
|
||||||
|
response = client.post(reverse("auth-list"), form)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["username"] == user.username
|
||||||
|
assert response.data["auth_token"] != "" and response.data["auth_token"] != None
|
||||||
|
assert response.data["email"] == user.email
|
||||||
|
assert response.data["full_name"] == user.full_name
|
||||||
|
assert response.data["bio"] == user.bio
|
||||||
|
assert response.data["github_id"] == 1955
|
||||||
|
|
||||||
|
def test_response_200_in_registration_with_github_account_and_existed_user_by_github_id(client, settings):
|
||||||
|
settings.PUBLIC_REGISTER_ENABLED = False
|
||||||
|
form = {"type": "github",
|
||||||
|
"code": "xxxxxx"}
|
||||||
|
user = factories.UserFactory()
|
||||||
|
user.github_id = 1955
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
with patch("taiga.base.connectors.github.me") as m_me:
|
||||||
|
m_me.return_value = ("mmcfly@bttf.com",
|
||||||
|
github.User(id=1955,
|
||||||
|
username="mmcfly",
|
||||||
|
full_name="martin seamus mcfly",
|
||||||
|
bio="time traveler"))
|
||||||
|
|
||||||
|
response = client.post(reverse("auth-list"), form)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["username"] != "mmcfly"
|
||||||
|
assert response.data["auth_token"] != "" and response.data["auth_token"] != None
|
||||||
|
assert response.data["email"] != "mmcfly@bttf.com"
|
||||||
|
assert response.data["full_name"] != "martin seamus mcfly"
|
||||||
|
assert response.data["bio"] != "time traveler"
|
||||||
|
assert response.data["github_id"] == user.github_id
|
||||||
|
|
||||||
|
def test_response_200_in_registration_with_github_account_and_change_github_username(client, settings):
|
||||||
|
settings.PUBLIC_REGISTER_ENABLED = False
|
||||||
|
form = {"type": "github",
|
||||||
|
"code": "xxxxxx"}
|
||||||
|
user = factories.UserFactory()
|
||||||
|
user.username = "mmcfly"
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
with patch("taiga.base.connectors.github.me") as m_me:
|
||||||
|
m_me.return_value = ("mmcfly@bttf.com",
|
||||||
|
github.User(id=1955,
|
||||||
|
username="mmcfly",
|
||||||
|
full_name="martin seamus mcfly",
|
||||||
|
bio="time traveler"))
|
||||||
|
|
||||||
|
response = client.post(reverse("auth-list"), form)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["username"] == "mmcfly-1"
|
||||||
|
assert response.data["auth_token"] != "" and response.data["auth_token"] != None
|
||||||
|
assert response.data["email"] == "mmcfly@bttf.com"
|
||||||
|
assert response.data["full_name"] == "martin seamus mcfly"
|
||||||
|
assert response.data["bio"] == "time traveler"
|
||||||
|
assert response.data["github_id"] == 1955
|
||||||
|
|
||||||
def test_response_200_in_registration_with_github_account_in_a_project(client, settings):
|
def test_response_200_in_registration_with_github_account_in_a_project(client, settings):
|
||||||
settings.PUBLIC_REGISTER_ENABLED = False
|
settings.PUBLIC_REGISTER_ENABLED = False
|
||||||
|
@ -171,7 +243,6 @@ def test_respond_400_if_username_or_email_is_duplicate(client, settings, registe
|
||||||
response = client.post(reverse("auth-register"), register_form)
|
response = client.post(reverse("auth-register"), register_form)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
|
||||||
register_form["username"] = "username"
|
register_form["username"] = "username"
|
||||||
register_form["email"] = "ff@dd.com"
|
register_form["email"] = "ff@dd.com"
|
||||||
response = client.post(reverse("auth-register"), register_form)
|
response = client.post(reverse("auth-register"), register_form)
|
||||||
|
|
|
@ -219,7 +219,7 @@ def test_issues_event_opened_issue(client):
|
||||||
"issue": {
|
"issue": {
|
||||||
"title": "test-title",
|
"title": "test-title",
|
||||||
"body": "test-body",
|
"body": "test-body",
|
||||||
"number": 10,
|
"html_url": "http://github.com/test/project/issues/11",
|
||||||
},
|
},
|
||||||
"assignee": {},
|
"assignee": {},
|
||||||
"label": {},
|
"label": {},
|
||||||
|
@ -249,7 +249,7 @@ def test_issues_event_other_than_opened_issue(client):
|
||||||
"issue": {
|
"issue": {
|
||||||
"title": "test-title",
|
"title": "test-title",
|
||||||
"body": "test-body",
|
"body": "test-body",
|
||||||
"number": 10,
|
"html_url": "http://github.com/test/project/issues/11",
|
||||||
},
|
},
|
||||||
"assignee": {},
|
"assignee": {},
|
||||||
"label": {},
|
"label": {},
|
||||||
|
@ -291,17 +291,17 @@ def test_issues_event_bad_issue(client):
|
||||||
|
|
||||||
|
|
||||||
def test_issue_comment_event_on_existing_issue_task_and_us(client):
|
def test_issue_comment_event_on_existing_issue_task_and_us(client):
|
||||||
issue = f.IssueFactory.create(external_reference=["github", "10"])
|
issue = f.IssueFactory.create(external_reference=["github", "http://github.com/test/project/issues/11"])
|
||||||
take_snapshot(issue, user=issue.owner)
|
take_snapshot(issue, user=issue.owner)
|
||||||
task = f.TaskFactory.create(project=issue.project, external_reference=["github", "10"])
|
task = f.TaskFactory.create(project=issue.project, external_reference=["github", "http://github.com/test/project/issues/11"])
|
||||||
take_snapshot(task, user=task.owner)
|
take_snapshot(task, user=task.owner)
|
||||||
us = f.UserStoryFactory.create(project=issue.project, external_reference=["github", "10"])
|
us = f.UserStoryFactory.create(project=issue.project, external_reference=["github", "http://github.com/test/project/issues/11"])
|
||||||
take_snapshot(us, user=us.owner)
|
take_snapshot(us, user=us.owner)
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"action": "created",
|
"action": "created",
|
||||||
"issue": {
|
"issue": {
|
||||||
"number": 10,
|
"html_url": "http://github.com/test/project/issues/11",
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"body": "Test body",
|
"body": "Test body",
|
||||||
|
@ -346,7 +346,7 @@ def test_issue_comment_event_on_not_existing_issue_task_and_us(client):
|
||||||
payload = {
|
payload = {
|
||||||
"action": "created",
|
"action": "created",
|
||||||
"issue": {
|
"issue": {
|
||||||
"number": 11,
|
"html_url": "http://github.com/test/project/issues/11",
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"body": "Test body",
|
"body": "Test body",
|
||||||
|
|
|
@ -200,3 +200,34 @@ def test_archived_filter(client):
|
||||||
data = {"is_archived": 1}
|
data = {"is_archived": 1}
|
||||||
response = client.get(url, data)
|
response = client.get(url, data)
|
||||||
assert len(json.loads(response.content)) == 1
|
assert len(json.loads(response.content)) == 1
|
||||||
|
|
||||||
|
def test_get_total_points(client):
|
||||||
|
project = f.ProjectFactory.create()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
us_with_points = f.UserStoryFactory.create(project=project)
|
||||||
|
us_with_points.role_points.all().delete()
|
||||||
|
f.RolePointsFactory.create(user_story=us_with_points, role=role1, points=points2)
|
||||||
|
f.RolePointsFactory.create(user_story=us_with_points, role=role2, points=points3)
|
||||||
|
|
||||||
|
assert us_with_points.get_total_points() == 3.0
|
||||||
|
|
||||||
|
us_without_points = f.UserStoryFactory.create(project=project)
|
||||||
|
us_without_points.role_points.all().delete()
|
||||||
|
f.RolePointsFactory.create(user_story=us_without_points, role=role1, points=points1)
|
||||||
|
f.RolePointsFactory.create(user_story=us_without_points, role=role2, points=points1)
|
||||||
|
|
||||||
|
assert us_without_points.get_total_points() is None
|
||||||
|
|
||||||
|
us_mixed = f.UserStoryFactory.create(project=project)
|
||||||
|
us_mixed.role_points.all().delete()
|
||||||
|
f.RolePointsFactory.create(user_story=us_mixed, role=role1, points=points1)
|
||||||
|
f.RolePointsFactory.create(user_story=us_mixed, role=role2, points=points2)
|
||||||
|
|
||||||
|
assert us_mixed.get_total_points() == 1.0
|
||||||
|
|
Loading…
Reference in New Issue