From 095d613cf9f9fd5374af9ccdfd2041d0bfb789e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?=
Date: Sun, 12 Mar 2017 18:00:59 +0100
Subject: [PATCH 1/9] Update djmail to the last version
---
requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index 517d0b99..8877887d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,7 +8,7 @@ Pillow==3.4.2
pytz==2016.10
six==1.10.0
amqp==2.1.4
-djmail==1.0.0
+djmail==1.0.1
django-jinja==2.2.2
jinja2==2.9.5
pygments==2.2.0
From fd71ae704fc5def5dab233898dc375333839323b Mon Sep 17 00:00:00 2001
From: Alejandro Alonso
Date: Sat, 11 Mar 2017 03:59:13 +0100
Subject: [PATCH 2/9] Fixing contact project
---
taiga/projects/contact/services.py | 2 +-
taiga/projects/models.py | 7 +++++--
tests/integration/test_contact.py | 6 ++++--
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/taiga/projects/contact/services.py b/taiga/projects/contact/services.py
index d623c78b..a6623a2f 100644
--- a/taiga/projects/contact/services.py
+++ b/taiga/projects/contact/services.py
@@ -38,7 +38,7 @@ def send_contact_email(contact_entry_id):
"user_profile_url": resolve_front_url("user", contact_entry.user.username),
"project_settings_url": resolve_front_url("project-admin", contact_entry.project.slug),
}
- users = contact_entry.project.get_users().exclude(id=contact_entry.user_id)
+ users = contact_entry.project.get_users(with_admin_privileges=True).exclude(id=contact_entry.user_id)
addresses = ", ".join([u.email for u in users])
email = mail_builder.contact_notification(addresses, ctx)
email.extra_headers["Reply-To"] = ", ".join([contact_entry.user.email])
diff --git a/taiga/projects/models.py b/taiga/projects/models.py
index 3a345088..f28072ed 100644
--- a/taiga/projects/models.py
+++ b/taiga/projects/models.py
@@ -382,9 +382,12 @@ class Project(ProjectDefaults, TaggedMixin, TagsColorsMixin, models.Model):
def get_roles(self):
return self.roles.all()
- def get_users(self):
+ def get_users(self, with_admin_privileges=None):
user_model = get_user_model()
- members = self.memberships.values_list("user", flat=True)
+ members = self.memberships.all()
+ if with_admin_privileges is not None:
+ members = members.filter(Q(is_admin=True)|Q(user__id=self.owner.id))
+ members = members.values_list("user", flat=True)
return user_model.objects.filter(id__in=list(members))
def update_role_points(self, user_stories=None):
diff --git a/tests/integration/test_contact.py b/tests/integration/test_contact.py
index 17676f55..600b40f7 100644
--- a/tests/integration/test_contact.py
+++ b/tests/integration/test_contact.py
@@ -31,7 +31,9 @@ pytestmark = pytest.mark.django_db
def test_create_comment(client):
user = f.UserFactory.create()
project = f.ProjectFactory.create()
- f.MembershipFactory(user=project.owner, project=project, is_admin=True)
+ m1 = f.MembershipFactory(user=project.owner, project=project)
+ m2 = f.MembershipFactory(project=project, is_admin=True)
+ m3 = f.MembershipFactory(project=project, is_admin=False)
url = reverse("contact-list")
@@ -46,7 +48,7 @@ def test_create_comment(client):
response = client.post(url, contact_data, content_type="application/json")
assert response.status_code == 201
assert len(mail.outbox) == 1
- assert mail.outbox[0].to == [project.owner.email]
+ assert set(mail.outbox[0].to[0].split(", ")) == set([project.owner.email, m2.user.email])
From 2ea75b1aeeedc2ef8fae69a50ca209d0c1ce126e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?=
Date: Mon, 13 Mar 2017 11:40:06 +0100
Subject: [PATCH 3/9] Fix trello importer error where avatarHash is a NoneType
object
---
taiga/importers/trello/importer.py | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/taiga/importers/trello/importer.py b/taiga/importers/trello/importer.py
index 719a3660..02ff979b 100644
--- a/taiga/importers/trello/importer.py
+++ b/taiga/importers/trello/importer.py
@@ -129,10 +129,20 @@ class TrelloImporter:
for member in self._client.get("/board/{}/members/all".format(project_id), {"fields": "id"}):
user = self._client.get("/member/{}".format(member['id']), {"fields": "id,fullName,email,avatarSource,avatarHash,gravatarHash"})
avatar = None
- if user['avatarSource'] == "gravatar" and user['gravatarHash']:
- avatar = 'https://www.gravatar.com/avatar/' + user['gravatarHash'] + '.jpg?s=50'
- elif user['avatarHash']:
- avatar = 'https://trello-avatars.s3.amazonaws.com/' + user['avatarHash'] + '/50.png'
+ try:
+ if user['avatarSource'] == "gravatar" and user['gravatarHash']:
+ avatar = 'https://www.gravatar.com/avatar/' + user['gravatarHash'] + '.jpg?s=50'
+ elif user['avatarHash'] is not None:
+ avatar = 'https://trello-avatars.s3.amazonaws.com/' + user['avatarHash'] + '/50.png'
+ except:
+ # NOTE: Sometimes this piece of code return this exception:
+ #
+ # File "/home/taiga/taiga-back/taiga/importers/trello/importer.py" in list_users
+ # 135. avatar = 'https://trello-avatars.s3.amazonaws.com/' + user['avatarHash'] + '/50.png'
+ #
+ # Exception Type: TypeError at /api/v1/importers/trello/list_users
+ # Exception Value: Can't convert 'NoneType' object to str implicitly
+ pass
members.append({
"id": user['id'],
From 363c9432f52f484caa52e7fae0cab3c2f92aeb13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?=
Date: Tue, 14 Mar 2017 12:57:01 +0100
Subject: [PATCH 4/9] Allow to resolve wikipages with references endpoint
---
taiga/projects/references/api.py | 48 +++++++++++--------
taiga/projects/references/validators.py | 4 +-
.../integration/test_references_sequences.py | 41 ++++++++++++++++
3 files changed, 73 insertions(+), 20 deletions(-)
diff --git a/taiga/projects/references/api.py b/taiga/projects/references/api.py
index 10a08538..67cf9f1d 100644
--- a/taiga/projects/references/api.py
+++ b/taiga/projects/references/api.py
@@ -66,24 +66,34 @@ class ResolverViewSet(viewsets.ViewSet):
if data["ref"]:
ref_found = False # No need to continue once one ref is found
- if ref_found is False and user_has_perm(request.user, "view_epics", project):
- epic = project.epics.filter(ref=data["ref"]).first()
- if epic:
- result["epic"] = epic.pk
- ref_found = True
- if user_has_perm(request.user, "view_us", project):
- us = project.user_stories.filter(ref=data["ref"]).first()
- if us:
- result["us"] = us.pk
- ref_found = True
- if ref_found is False and user_has_perm(request.user, "view_tasks", project):
- task = project.tasks.filter(ref=data["ref"]).first()
- if task:
- result["task"] = task.pk
- ref_found = True
- if ref_found is False and user_has_perm(request.user, "view_issues", project):
- issue = project.issues.filter(ref=data["ref"]).first()
- if issue:
- result["issue"] = issue.pk
+ try:
+ value = int(data["ref"])
+
+ if user_has_perm(request.user, "view_epics", project):
+ epic = project.epics.filter(ref=value).first()
+ if epic:
+ result["epic"] = epic.pk
+ ref_found = True
+ if ref_found is False and user_has_perm(request.user, "view_us", project):
+ us = project.user_stories.filter(ref=value).first()
+ if us:
+ result["us"] = us.pk
+ ref_found = True
+ if ref_found is False and user_has_perm(request.user, "view_tasks", project):
+ task = project.tasks.filter(ref=value).first()
+ if task:
+ result["task"] = task.pk
+ ref_found = True
+ if ref_found is False and user_has_perm(request.user, "view_issues", project):
+ issue = project.issues.filter(ref=value).first()
+ if issue:
+ result["issue"] = issue.pk
+ except:
+ value = data["ref"]
+
+ if user_has_perm(request.user, "view_wiki_pages", project):
+ wiki_page = project.wiki_pages.filter(slug=value).first()
+ if wiki_page:
+ result["wikipage"] = wiki_page.pk
return response.Ok(result)
diff --git a/taiga/projects/references/validators.py b/taiga/projects/references/validators.py
index ad51e42c..3b2baba1 100644
--- a/taiga/projects/references/validators.py
+++ b/taiga/projects/references/validators.py
@@ -28,8 +28,8 @@ class ResolverValidator(validators.Validator):
us = serializers.IntegerField(required=False)
task = serializers.IntegerField(required=False)
issue = serializers.IntegerField(required=False)
- ref = serializers.IntegerField(required=False)
wikipage = serializers.CharField(max_length=512, required=False)
+ ref = serializers.CharField(max_length=512, required=False)
def validate(self, attrs):
if "ref" in attrs:
@@ -41,5 +41,7 @@ class ResolverValidator(validators.Validator):
raise ValidationError("'task' param is incompatible with 'ref' in the same request")
if "issue" in attrs:
raise ValidationError("'issue' param is incompatible with 'ref' in the same request")
+ if "wikipage" in attrs:
+ raise ValidationError("'wikipage' param is incompatible with 'ref' in the same request")
return attrs
diff --git a/tests/integration/test_references_sequences.py b/tests/integration/test_references_sequences.py
index 7bb035de..24cf639b 100644
--- a/tests/integration/test_references_sequences.py
+++ b/tests/integration/test_references_sequences.py
@@ -191,3 +191,44 @@ def test_params_validation_in_api_request(client, refmodels):
response = client.json.get("{}?project={}&ref={}&milestone={}".format(url, project.slug, us.ref,
milestone.slug))
assert response.status_code == 200
+
+
+@pytest.mark.django_db
+def test_by_ref_calls_in_api_request(client, refmodels):
+ refmodels.Reference.objects.all().delete()
+
+ user = factories.UserFactory.create()
+ project = factories.ProjectFactory.create(owner=user)
+ seqname1 = refmodels.make_sequence_name(project)
+ role = factories.RoleFactory.create(project=project)
+ factories.MembershipFactory.create(project=project, user=user, role=role, is_admin=True)
+
+ epic = factories.EpicFactory.create(project=project)
+ milestone = factories.MilestoneFactory.create(project=project)
+ us = factories.UserStoryFactory.create(project=project)
+ task = factories.TaskFactory.create(project=project)
+ issue = factories.IssueFactory.create(project=project)
+ wiki_page = factories.WikiPageFactory.create(project=project)
+
+ client.login(user)
+
+ url = reverse("resolver-list")
+ response = client.json.get("{}?project={}&ref={}".format(url, project.slug, epic.ref))
+ assert response.status_code == 200
+ assert response.data["epic"] == epic.id
+
+ response = client.json.get("{}?project={}&ref={}".format(url, project.slug, us.ref))
+ assert response.status_code == 200
+ assert response.data["us"] == us.id
+
+ response = client.json.get("{}?project={}&ref={}".format(url, project.slug, task.ref))
+ assert response.status_code == 200
+ assert response.data["task"] == task.id
+
+ response = client.json.get("{}?project={}&ref={}".format(url, project.slug, issue.ref))
+ assert response.status_code == 200
+ assert response.data["issue"] == issue.id
+
+ response = client.json.get("{}?project={}&ref={}".format(url, project.slug, wiki_page.slug))
+ assert response.status_code == 200
+ assert response.data["wikipage"] == wiki_page.id
From 282b964bd36e470e8ea4d9034d62f8462252783a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?=
Date: Wed, 15 Mar 2017 17:33:52 +0100
Subject: [PATCH 5/9] Fix test_emails command and add some missed emails
---
taiga/base/management/commands/test_emails.py | 73 +++++++++++++++++--
.../contact_notification-body-html.jinja | 4 +-
2 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/taiga/base/management/commands/test_emails.py b/taiga/base/management/commands/test_emails.py
index faf9414c..12a2cc06 100644
--- a/taiga/base/management/commands/test_emails.py
+++ b/taiga/base/management/commands/test_emails.py
@@ -23,12 +23,16 @@ from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
from django.utils import timezone
+from taiga.base.mails import InlineCSSTemplateMail
from taiga.base.mails import mail_builder
from taiga.projects.models import Project, Membership
from taiga.projects.history.models import HistoryEntry
from taiga.projects.history.services import get_history_queryset_by_model_instance
+from taiga.users.services import get_user_photo_url
+from taiga.front.templatetags.functions import resolve as resolve_front_url
+
class Command(BaseCommand):
help = 'Send an example of all emails'
@@ -186,18 +190,17 @@ class Command(BaseCommand):
email = cls()
email.send(email_address, context)
-
# Transfer Emails
context = {
"project": Project.objects.all().order_by("?").first(),
- "requester": User.objects.all().order_by("?").first(),
+ "requester": get_user_model().objects.all().order_by("?").first(),
}
email = mail_builder.transfer_request(email_address, context)
email.send()
context = {
"project": Project.objects.all().order_by("?").first(),
- "receiver": User.objects.all().order_by("?").first(),
+ "receiver": get_user_model().objects.all().order_by("?").first(),
"token": "test-token",
"reason": "Test reason"
}
@@ -206,8 +209,8 @@ class Command(BaseCommand):
context = {
"project": Project.objects.all().order_by("?").first(),
- "old_owner": User.objects.all().order_by("?").first(),
- "new_owner": User.objects.all().order_by("?").first(),
+ "old_owner": get_user_model().objects.all().order_by("?").first(),
+ "new_owner": get_user_model().objects.all().order_by("?").first(),
"reason": "Test reason"
}
email = mail_builder.transfer_accept(email_address, context)
@@ -215,8 +218,66 @@ class Command(BaseCommand):
context = {
"project": Project.objects.all().order_by("?").first(),
- "rejecter": User.objects.all().order_by("?").first(),
+ "rejecter": get_user_model().objects.all().order_by("?").first(),
"reason": "Test reason"
}
email = mail_builder.transfer_reject(email_address, context)
email.send()
+
+
+ # Contact with project admins email
+ project = Project.objects.all().order_by("?").first()
+ user = get_user_model().objects.all().order_by("?").first()
+ context = {
+ "full_name": user.get_full_name(),
+ "project_name": project.name,
+ "photo_url": get_user_photo_url(user),
+ "user_profile_url": resolve_front_url("user", user.username),
+ "project_settings_url": resolve_front_url("project-admin", project.slug),
+ "comment": "Test comment notification."
+ }
+ email = mail_builder.contact_notification(email_address, context)
+ email.send()
+
+ # GitHub importer email
+ context = {
+ "project": Project.objects.all().order_by("?").first(),
+ "user": get_user_model().objects.all().order_by("?").first()
+ }
+ email = mail_builder.github_import_success(email_address, context)
+ email.send()
+
+ # Jira importer email
+ context = {
+ "project": Project.objects.all().order_by("?").first(),
+ "user": get_user_model().objects.all().order_by("?").first()
+ }
+ email = mail_builder.jira_import_success(email_address, context)
+ email.send()
+
+ # Trello importer email
+ context = {
+ "project": Project.objects.all().order_by("?").first(),
+ "user": get_user_model().objects.all().order_by("?").first()
+ }
+ email = mail_builder.trello_import_success(email_address, context)
+ email.send()
+
+ # Asana importer email
+ context = {
+ "project": Project.objects.all().order_by("?").first(),
+ "user": get_user_model().objects.all().order_by("?").first()
+ }
+ email = mail_builder.asana_import_success(email_address, context)
+ email.send()
+
+ # Error importer email
+ context = {
+ "user": get_user_model().objects.all().order_by("?").first(),
+ "error_subject": "Error importing GitHub project",
+ "error_message": "Error importing GitHub project",
+ "project": 1234,
+ "exception": "Exception message"
+ }
+ email = mail_builder.importer_import_error(email_address, context)
+ email.send()
diff --git a/taiga/projects/contact/templates/emails/contact_notification-body-html.jinja b/taiga/projects/contact/templates/emails/contact_notification-body-html.jinja
index 257a5905..812733f8 100644
--- a/taiga/projects/contact/templates/emails/contact_notification-body-html.jinja
+++ b/taiga/projects/contact/templates/emails/contact_notification-body-html.jinja
@@ -7,7 +7,7 @@
{% endif %}
- {% trans full_name=full_name, comment=comment, project_name=project_name %}
+ {% trans full_name=full_name, user_profile_url=user_profile_url, project_name=project_name %}
{{ full_name }} has written to {{ project_name }}
{% endtrans %}
@@ -17,7 +17,7 @@
- {% trans project_name=project_name %}
+ {% trans project_name=project_name, project_settings_url=project_settings_url %}
You are receiving this message because you are listed as administrator of the project titled {{ project_name }}. If you don't want members of the Taiga community contacting your project, please update your project settings to prevent such contacts. Regular communications amongst members of the project will not be affected.
{% endtrans %}
From a726f2882b7b7fbdaa0f1b6cdfea8fc2822bfd89 Mon Sep 17 00:00:00 2001
From: Alejandro Alonso
Date: Fri, 17 Mar 2017 12:32:31 +0100
Subject: [PATCH 6/9] Fixing svg processors
---
taiga/base/utils/thumbnails.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/taiga/base/utils/thumbnails.py b/taiga/base/utils/thumbnails.py
index 7d704b8e..04e1110e 100644
--- a/taiga/base/utils/thumbnails.py
+++ b/taiga/base/utils/thumbnails.py
@@ -34,13 +34,16 @@ from io import BytesIO
try:
from cairosvg.surface import PNGSurface
+ def _accept(prefix):
+ return "svg" in str(prefix.lower())
+
def svg_image_factory(data, *args):
png_data = PNGSurface.convert(data.read())
return PngImageFile(BytesIO(png_data))
Image.register_mime("SVG", "image/svg+xml")
Image.register_extension("SVG", ".svg")
- Image.register_open("SVG", svg_image_factory)
+ Image.register_open("SVG", svg_image_factory, _accept)
except Exception:
pass
From e3b390087a9e18736f9466855b2abfa6bc03dd6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jes=C3=BAs=20Espino?=
Date: Tue, 21 Mar 2017 12:10:11 +0100
Subject: [PATCH 7/9] Capture invalid response from the jira server
---
taiga/importers/exceptions.py | 3 +++
taiga/importers/jira/api.py | 16 ++++++++++------
taiga/importers/jira/common.py | 3 +++
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/taiga/importers/exceptions.py b/taiga/importers/exceptions.py
index 0646095d..df78efd1 100644
--- a/taiga/importers/exceptions.py
+++ b/taiga/importers/exceptions.py
@@ -22,5 +22,8 @@ class InvalidRequest(Exception):
class InvalidAuthResult(Exception):
pass
+class InvalidServiceConfiguration(Exception):
+ pass
+
class FailedRequest(Exception):
pass
diff --git a/taiga/importers/jira/api.py b/taiga/importers/jira/api.py
index 9c5d0b4d..75c6e2c5 100644
--- a/taiga/importers/jira/api.py
+++ b/taiga/importers/jira/api.py
@@ -25,6 +25,7 @@ from taiga.users.services import get_user_photo_url
from taiga.users.gravatar import get_user_gravatar_id
from taiga.importers import permissions
+from taiga.importers import exceptions
from taiga.importers.services import resolve_users_bindings
from .normal import JiraNormalImporter
from .agile import JiraAgileImporter
@@ -178,12 +179,15 @@ class JiraImporterViewSet(viewsets.ViewSet):
if not jira_url:
raise exc.WrongArguments(_("The url param is needed"))
- (oauth_token, oauth_secret, url) = JiraNormalImporter.get_auth_url(
- jira_url,
- settings.IMPORTERS.get('jira', {}).get('consumer_key', None),
- settings.IMPORTERS.get('jira', {}).get('cert', None),
- True
- )
+ try:
+ (oauth_token, oauth_secret, url) = JiraNormalImporter.get_auth_url(
+ jira_url,
+ settings.IMPORTERS.get('jira', {}).get('consumer_key', None),
+ settings.IMPORTERS.get('jira', {}).get('cert', None),
+ True
+ )
+ except exceptions.InvalidServiceConfiguration:
+ raise exc.BadRequest(_("Invalid Jira server configuration."))
(auth_data, created) = AuthData.objects.get_or_create(
user=request.user,
diff --git a/taiga/importers/jira/common.py b/taiga/importers/jira/common.py
index f1ffa691..3eaa6ee6 100644
--- a/taiga/importers/jira/common.py
+++ b/taiga/importers/jira/common.py
@@ -45,6 +45,7 @@ from taiga.projects.custom_attributes.models import (UserStoryCustomAttribute,
from taiga.projects.history.models import HistoryEntry
from taiga.projects.history.choices import HistoryType
from taiga.mdrender.service import render as mdrender
+from taiga.importers import exceptions
EPIC_COLORS = {
"ghx-label-0": "#ffffff",
@@ -737,6 +738,8 @@ class JiraImporterCommon:
oauth = OAuth1(consumer_key, signature_method=SIGNATURE_RSA, rsa_key=key_cert_data)
r = requests.post(
server + '/plugins/servlet/oauth/request-token', verify=verify, auth=oauth)
+ if r.status_code != 200:
+ raise exceptions.InvalidServiceConfiguration()
request = dict(parse_qsl(r.text))
request_token = request['oauth_token']
request_token_secret = request['oauth_token_secret']
From 500fe01b6e1b6590361910a6a956a930e50008b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jes=C3=BAs=20Espino?=
Date: Thu, 23 Mar 2017 17:41:14 +0100
Subject: [PATCH 8/9] Fix jira auth data creation
---
taiga/importers/jira/api.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/taiga/importers/jira/api.py b/taiga/importers/jira/api.py
index 75c6e2c5..905631d8 100644
--- a/taiga/importers/jira/api.py
+++ b/taiga/importers/jira/api.py
@@ -13,6 +13,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import uuid
+
from django.utils.translation import ugettext as _
from django.conf import settings
@@ -193,7 +195,7 @@ class JiraImporterViewSet(viewsets.ViewSet):
user=request.user,
key="jira-oauth",
defaults={
- "value": "",
+ "value": uuid.uuid4().hex,
"extra": {},
}
)
From cfbe29e9a0ce538a58d78f04ac9e46df4ecae65d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jes=C3=BAs=20Espino?=
Date: Thu, 23 Mar 2017 18:04:16 +0100
Subject: [PATCH 9/9] Add callback url to jira importer
---
taiga/front/urls.py | 2 ++
taiga/importers/jira/api.py | 4 +++-
taiga/importers/jira/common.py | 15 +++++++++++----
3 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/taiga/front/urls.py b/taiga/front/urls.py
index 393913e3..244e0a72 100644
--- a/taiga/front/urls.py
+++ b/taiga/front/urls.py
@@ -55,4 +55,6 @@ urls = {
"project-transfer": "/project/{0}/transfer/{1}", # project.slug, project.transfer_token
"project-admin": "/login?next=/project/{0}/admin/project-profile/details", # project.slug
+
+ "project-import-jira": "/project/new/import/jira?url={}",
}
diff --git a/taiga/importers/jira/api.py b/taiga/importers/jira/api.py
index 905631d8..5606a732 100644
--- a/taiga/importers/jira/api.py
+++ b/taiga/importers/jira/api.py
@@ -214,6 +214,7 @@ class JiraImporterViewSet(viewsets.ViewSet):
try:
oauth_data = request.user.auth_data.get(key="jira-oauth")
+ oauth_verifier = request.DATA.get("oauth_verifier", None)
oauth_token = oauth_data.extra['oauth_token']
oauth_secret = oauth_data.extra['oauth_secret']
server_url = oauth_data.extra['url']
@@ -225,7 +226,8 @@ class JiraImporterViewSet(viewsets.ViewSet):
settings.IMPORTERS.get('jira', {}).get('cert', None),
oauth_token,
oauth_secret,
- True
+ oauth_verifier,
+ False
)
except Exception as e:
raise exc.WrongArguments(_("Invalid or expired auth token"))
diff --git a/taiga/importers/jira/common.py b/taiga/importers/jira/common.py
index 3eaa6ee6..c4c6c3eb 100644
--- a/taiga/importers/jira/common.py
+++ b/taiga/importers/jira/common.py
@@ -17,12 +17,13 @@
# along with this program. If not, see .
import requests
-from urllib.parse import parse_qsl
+from urllib.parse import parse_qsl, quote_plus
from oauthlib.oauth1 import SIGNATURE_RSA
from requests_oauthlib import OAuth1
from django.core.files.base import ContentFile
from django.contrib.contenttypes.models import ContentType
+from django.conf import settings
from taiga.users.models import User
from taiga.projects.models import Points
@@ -46,6 +47,7 @@ from taiga.projects.history.models import HistoryEntry
from taiga.projects.history.choices import HistoryType
from taiga.mdrender.service import render as mdrender
from taiga.importers import exceptions
+from taiga.front.templatetags.functions import resolve as resolve_front_url
EPIC_COLORS = {
"ghx-label-0": "#ffffff",
@@ -735,7 +737,9 @@ class JiraImporterCommon:
if verify is None:
verify = server.startswith('https')
- oauth = OAuth1(consumer_key, signature_method=SIGNATURE_RSA, rsa_key=key_cert_data)
+ callback_uri = resolve_front_url("project-import-jira", quote_plus(server))
+ oauth = OAuth1(consumer_key, signature_method=SIGNATURE_RSA, rsa_key=key_cert_data, callback_uri=callback_uri)
+
r = requests.post(
server + '/plugins/servlet/oauth/request-token', verify=verify, auth=oauth)
if r.status_code != 200:
@@ -751,13 +755,16 @@ class JiraImporterCommon:
)
@classmethod
- def get_access_token(cls, server, consumer_key, key_cert_data, request_token, request_token_secret, verify=False):
+ def get_access_token(cls, server, consumer_key, key_cert_data, request_token, request_token_secret, request_verifier, verify=False):
+ callback_uri = resolve_front_url("project-import-jira", quote_plus(server))
oauth = OAuth1(
consumer_key,
signature_method=SIGNATURE_RSA,
+ callback_uri=callback_uri,
rsa_key=key_cert_data,
resource_owner_key=request_token,
- resource_owner_secret=request_token_secret
+ resource_owner_secret=request_token_secret,
+ verifier=request_verifier,
)
r = requests.post(server + '/plugins/servlet/oauth/access-token', verify=verify, auth=oauth)
access = dict(parse_qsl(r.text))