<commit_before>﻿//  Dapplo - building blocks for desktop applications
//  Copyright (C) 2016 Dapplo
// 
//  For more information see: http://dapplo.net/
//  Dapplo repositories are hosted on GitHub: https://github.com/dapplo
// 
//  This file is part of Dapplo.Jira
// 
//  Dapplo.Jira is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  Dapplo.Jira 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 Lesser General Public License for more details.
// 
//  You should have a copy of the GNU Lesser General Public License
//  along with Dapplo.Jira. If not, see <http://www.gnu.org/licenses/lgpl.txt>.

#region using

using System;
using System.Threading;
using System.Threading.Tasks;
using Dapplo.HttpExtensions;
using Dapplo.Jira.Entities;
using Dapplo.Log;
#if NET45 || NET46
using System.Collections.Generic;
using System.Net.Http;
using System.Linq;
using Dapplo.HttpExtensions.Extensions;
using Dapplo.HttpExtensions.OAuth;
using Dapplo.Jira.Converters;
#endif

#endregion

namespace Dapplo.Jira
{
	/// <summary>
	///     A client for accessing the Atlassian JIRA Api via REST, using Dapplo.HttpExtensions
	/// </summary>
	public class JiraClient : IProjectDomain, IWorkDomain, IUserDomain, ISessionDomain, IIssueDomain, IFilterDomain, IAttachmentDomain, IServerDomain
	{
		private static readonly LogSource Log = new LogSource();

		private string _password;
		private string _user;

		/// <summary>
		///     Store the specific HttpBehaviour, which contains a IHttpSettings and also some additional logic for making a
		///     HttpClient which works with Jira
		/// </summary>
		public IHttpBehaviour Behaviour { get; set; }

		/// <summary>
		///     Factory method to create the jira client
		/// </summary>
		public static IJiraClient Create(Uri baseUri, IHttpSettings httpSettings = null)
		{
			return new JiraClient(baseUri, httpSettings);
		}
		/// <summary>
		///     Create the JiraApi object, here the HttpClient is configured
		/// </summary>
		/// <param name="baseUri">Base URL, e.g. https://yourjiraserver</param>
		/// <param name="httpSettings">IHttpSettings or null for default</param>
		private JiraClient(Uri baseUri, IHttpSettings httpSettings = null) : this(baseUri)
		{
			Behaviour = ConfigureBehaviour(new HttpBehaviour(), httpSettings);
		}

#if NET45 || NET45
		/// <summary>
		///     Create the JiraApi, using OAuth 1 for the communication, here the HttpClient is configured
		/// </summary>
		/// <param name="baseUri">Base URL, e.g. https://yourjiraserver</param>
		/// <param name="jiraOAuthSettings">JiraOAuthSettings</param>
		/// <param name="httpSettings">IHttpSettings or null for default</param>
		public static IJiraClient Create(Uri baseUri, JiraOAuthSettings jiraOAuthSettings, IHttpSettings httpSettings = null)
		{
			JiraClient client = new JiraClient(baseUri, httpSettings);
			var jiraOAuthUri = client.JiraBaseUri.AppendSegments("plugins", "servlet", "oauth");

			var oAuthSettings = new OAuth1Settings
			{
				TokenUrl = jiraOAuthUri.AppendSegments("request-token"),
				TokenMethod = HttpMethod.Post,
				AccessTokenUrl = jiraOAuthUri.AppendSegments("access-token"),
				AccessTokenMethod = HttpMethod.Post,
				CheckVerifier = false,
				SignatureType = OAuth1SignatureTypes.RsaSha1,
				Token = jiraOAuthSettings.Token,
				ClientId = jiraOAuthSettings.ConsumerKey,
				CloudServiceName = jiraOAuthSettings.CloudServiceName,
				RsaSha1Provider = jiraOAuthSettings.RsaSha1Provider,
				AuthorizeMode = jiraOAuthSettings.AuthorizeMode,
				AuthorizationUri = jiraOAuthUri.AppendSegments("authorize")
					.ExtendQuery(new Dictionary<string, string>
					{
						{OAuth1Parameters.Token.EnumValueOf(), "{RequestToken}"},
						{OAuth1Parameters.Callback.EnumValueOf(), "{RedirectUrl}"}
					})
			};

			// Configure the OAuth1Settings

			client.Behaviour = client.ConfigureBehaviour(OAuth1HttpBehaviourFactory.Create(oAuthSettings), httpSettings);
			return client;
		}
#endif

		/// <summary>
		///     Constructor for only the Uri, used internally
		/// </summary>
		/// <param name="baseUri"></param>
		private JiraClient(Uri baseUri)
		{
			JiraBaseUri = baseUri;
			JiraRestUri = baseUri.AppendSegments("rest", "api", "2");
			JiraAuthUri = baseUri.AppendSegments("rest", "auth", "1");
		}

		/// <summary>
		///     Helper method to configure the IChangeableHttpBehaviour
		/// </summary>
		/// <param name="behaviour">IChangeableHttpBehaviour</param>
		/// <param name="httpSettings">IHttpSettings</param>
		/// <returns>the behaviour, but configured as IHttpBehaviour </returns>
		private IHttpBehaviour ConfigureBehaviour(IChangeableHttpBehaviour behaviour, IHttpSettings httpSettings = null)
		{
#if NET45 || NET46

			if (HttpExtensionsGlobals.HttpContentConverters.All(x => x.GetType() != typeof(SvgBitmapHttpContentConverter)))
			{
				HttpExtensionsGlobals.HttpContentConverters.Add(SvgBitmapHttpContentConverter.Instance.Value);
			}
#endif
			behaviour.HttpSettings = httpSettings ?? HttpExtensionsGlobals.HttpSettings;
			behaviour.OnHttpRequestMessageCreated = httpMessage =>
			{
				httpMessage?.Headers.TryAddWithoutValidation("X-Atlassian-Token", "no-check");
				if (!string.IsNullOrEmpty(_user) && _password != null)
				{
					httpMessage?.SetBasicAuthorization(_user, _password);
				}
				return httpMessage;
			};
			return behaviour;
		}

		/// <summary>
		///     The base URI for your JIRA server
		/// </summary>
		public Uri JiraBaseUri { get; }

		/// <summary>
		///     The rest URI for your JIRA server
		/// </summary>
		public Uri JiraRestUri { get; }

		/// <summary>
		///     The base URI for JIRA auth api
		/// </summary><commit_msg>BUG-2122: Was using X-Atlassian-Token: no-check instead of X-Atlassian-Token: <PASSWORD><commit_after>﻿//  Dapplo - building blocks for desktop applications
//  Copyright (C) 2016 Dapplo
// 
//  For more information see: http://dapplo.net/
//  Dapplo repositories are hosted on GitHub: https://github.com/dapplo
// 
//  This file is part of Dapplo.Jira
// 
//  Dapplo.Jira is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  Dapplo.Jira 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 Lesser General Public License for more details.
// 
//  You should have a copy of the GNU Lesser General Public License
//  along with Dapplo.Jira. If not, see <http://www.gnu.org/licenses/lgpl.txt>.

#region using

using System;
using System.Threading;
using System.Threading.Tasks;
using Dapplo.HttpExtensions;
using Dapplo.Jira.Entities;
using Dapplo.Log;
#if NET45 || NET46
using System.Collections.Generic;
using System.Net.Http;
using System.Linq;
using Dapplo.HttpExtensions.Extensions;
using Dapplo.HttpExtensions.OAuth;
using Dapplo.Jira.Converters;
#endif

#endregion

namespace Dapplo.Jira
{
	/// <summary>
	///     A client for accessing the Atlassian JIRA Api via REST, using Dapplo.HttpExtensions
	/// </summary>
	public class JiraClient : IProjectDomain, IWorkDomain, IUserDomain, ISessionDomain, IIssueDomain, IFilterDomain, IAttachmentDomain, IServerDomain
	{
		private static readonly LogSource Log = new LogSource();

		private string _password;
		private string _user;

		/// <summary>
		///     Store the specific HttpBehaviour, which contains a IHttpSettings and also some additional logic for making a
		///     HttpClient which works with Jira
		/// </summary>
		public IHttpBehaviour Behaviour { get; set; }

		/// <summary>
		///     Factory method to create the jira client
		/// </summary>
		public static IJiraClient Create(Uri baseUri, IHttpSettings httpSettings = null)
		{
			return new JiraClient(baseUri, httpSettings);
		}
		/// <summary>
		///     Create the JiraApi object, here the HttpClient is configured
		/// </summary>
		/// <param name="baseUri">Base URL, e.g. https://yourjiraserver</param>
		/// <param name="httpSettings">IHttpSettings or null for default</param>
		private JiraClient(Uri baseUri, IHttpSettings httpSettings = null) : this(baseUri)
		{
			Behaviour = ConfigureBehaviour(new HttpBehaviour(), httpSettings);
		}

#if NET45 || NET45
		/// <summary>
		///     Create the JiraApi, using OAuth 1 for the communication, here the HttpClient is configured
		/// </summary>
		/// <param name="baseUri">Base URL, e.g. https://yourjiraserver</param>
		/// <param name="jiraOAuthSettings">JiraOAuthSettings</param>
		/// <param name="httpSettings">IHttpSettings or null for default</param>
		public static IJiraClient Create(Uri baseUri, JiraOAuthSettings jiraOAuthSettings, IHttpSettings httpSettings = null)
		{
			JiraClient client = new JiraClient(baseUri, httpSettings);
			var jiraOAuthUri = client.JiraBaseUri.AppendSegments("plugins", "servlet", "oauth");

			var oAuthSettings = new OAuth1Settings
			{
				TokenUrl = jiraOAuthUri.AppendSegments("request-token"),
				TokenMethod = HttpMethod.Post,
				AccessTokenUrl = jiraOAuthUri.AppendSegments("access-token"),
				AccessTokenMethod = HttpMethod.Post,
				CheckVerifier = false,
				SignatureType = OAuth1SignatureTypes.RsaSha1,
				Token = jiraOAuthSettings.Token,
				ClientId = jiraOAuthSettings.ConsumerKey,
				CloudServiceName = jiraOAuthSettings.CloudServiceName,
				RsaSha1Provider = jiraOAuthSettings.RsaSha1Provider,
				AuthorizeMode = jiraOAuthSettings.AuthorizeMode,
				AuthorizationUri = jiraOAuthUri.AppendSegments("authorize")
					.ExtendQuery(new Dictionary<string, string>
					{
						{OAuth1Parameters.Token.EnumValueOf(), "{RequestToken}"},
						{OAuth1Parameters.Callback.EnumValueOf(), "{RedirectUrl}"}
					})
			};

			// Configure the OAuth1Settings

			client.Behaviour = client.ConfigureBehaviour(OAuth1HttpBehaviourFactory.Create(oAuthSettings), httpSettings);
			return client;
		}
#endif

		/// <summary>
		///     Constructor for only the Uri, used internally
		/// </summary>
		/// <param name="baseUri"></param>
		private JiraClient(Uri baseUri)
		{
			JiraBaseUri = baseUri;
			JiraRestUri = baseUri.AppendSegments("rest", "api", "2");
			JiraAuthUri = baseUri.AppendSegments("rest", "auth", "1");
		}

		/// <summary>
		///     Helper method to configure the IChangeableHttpBehaviour
		/// </summary>
		/// <param name="behaviour">IChangeableHttpBehaviour</param>
		/// <param name="httpSettings">IHttpSettings</param>
		/// <returns>the behaviour, but configured as IHttpBehaviour </returns>
		private IHttpBehaviour ConfigureBehaviour(IChangeableHttpBehaviour behaviour, IHttpSettings httpSettings = null)
		{
#if NET45 || NET46

			if (HttpExtensionsGlobals.HttpContentConverters.All(x => x.GetType() != typeof(SvgBitmapHttpContentConverter)))
			{
				HttpExtensionsGlobals.HttpContentConverters.Add(SvgBitmapHttpContentConverter.Instance.Value);
			}
#endif
			behaviour.HttpSettings = httpSettings ?? HttpExtensionsGlobals.HttpSettings;
			behaviour.OnHttpRequestMessageCreated = httpMessage =>
			{
				httpMessage?.Headers.TryAddWithoutValidation("X-Atlassian-Token", "nocheck");
				if (!string.IsNullOrEmpty(_user) && _password != null)
				{
					httpMessage?.SetBasicAuthorization(_user, _password);
				}
				return httpMessage;
			};
			return behaviour;
		}

		/// <summary>
		///     The base URI for your JIRA server
		/// </summary>
		public Uri JiraBaseUri { get; }

		/// <summary>
		///     The rest URI for your JIRA server
		/// </summary>
		public Uri JiraRestUri { get; }

		/// <summary>
		///     The base URI for JIRA auth api
		/// </summary>
{'fraction_non_alphanumeric': 0.11280943678351886, 'fraction_numerical': 0.005150357202193055, 'mean_word_length': 3.750986582478295, 'pattern_counts': {'":': 0, '<': 84, '<?xml version=': 0, '>': 88, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4899526', 'n_tokens_mistral': 4071, 'n_tokens_neox': 3625, 'n_words': 981}