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/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..5606a732 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
@@ -25,6 +27,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,18 +181,21 @@ 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,
key="jira-oauth",
defaults={
- "value": "",
+ "value": uuid.uuid4().hex,
"extra": {},
}
)
@@ -208,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']
@@ -219,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 f1ffa691..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
@@ -45,6 +46,8 @@ 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
+from taiga.front.templatetags.functions import resolve as resolve_front_url
EPIC_COLORS = {
"ghx-label-0": "#ffffff",
@@ -734,9 +737,13 @@ 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:
+ raise exceptions.InvalidServiceConfiguration()
request = dict(parse_qsl(r.text))
request_token = request['oauth_token']
request_token_secret = request['oauth_token_secret']
@@ -748,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))
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