/// <summary>
        /// Get Webhook service from v1 API
        /// </summary>
        public async Task <BitbucketProxy.BitbucketHookInfo> GetService(string repoUrl, string accessToken, string serviceUrl)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("accessToken", accessToken);
            CommonUtils.ValidateNullArgument("serviceUrl", serviceUrl);

            var serviceUri = new Uri(serviceUrl);
            var requestUri = BitbucketProxyHelper.GetRequestUri(APiV1BaseUrl, repoUrl, "services");

            using (var client = CreateHttpClient(accessToken))
                using (HttpResponseMessage response = await client.GetAsync(requestUri))
                {
                    BitbucketProxy.BitbucketHookInfo[] services = await ProcessResponse <BitbucketProxy.BitbucketHookInfo[]>("GetService", response);

                    return(services.FirstOrDefault(service =>
                    {
                        if (service.service != null && service.service.url != null && string.Equals(service.service.type, "POST", StringComparison.OrdinalIgnoreCase))
                        {
                            Uri configUri;
                            if (Uri.TryCreate(service.service.url, UriKind.Absolute, out configUri))
                            {
                                return string.Equals(serviceUri.Host, configUri.Host, StringComparison.OrdinalIgnoreCase);
                            }
                        }

                        return false;
                    }));
                }
        }
        public async Task AddSSHKey(string repoUrl, string accessToken, string title, string sshKey)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("accessToken", accessToken);
            CommonUtils.ValidateNullArgument("title", title);
            CommonUtils.ValidateNullArgument("sshKey", sshKey);

            await RemoveSSHKey(repoUrl, accessToken, sshKey);

            // deploy key only allow read-only access
            var sshKeyInfo = new BitbucketProxy.BitbucketSSHKeyInfo {
                label = title, key = sshKey
            };
            // BUG https://bitbucket.org/site/master/issues/12746/missing-v2-api-to-add-remove-deployment
            var requestUri = BitbucketProxyHelper.GetRequestUri(APiV1BaseUrl, repoUrl, "deploy-keys");

            using (var client = CreateHttpClient(accessToken))
                using (var response = await client.PostAsJsonAsync(requestUri, sshKeyInfo))
                {
                    if (!response.IsSuccessStatusCode)
                    {
                        throw CreateOAuthException("AddSSHKey", await response.Content.ReadAsStringAsync(), response.StatusCode);
                    }
                }
        }
        public async Task <bool> RemoveSSHKey(string repoUrl, string accessToken, string sshKey)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("accessToken", accessToken);
            CommonUtils.ValidateNullArgument("sshKey", sshKey);

            var sshKeyInfo = await GetSSHKey(repoUrl, accessToken, sshKey);

            if (sshKeyInfo != null)
            {
                var requestUri = BitbucketProxyHelper.GetRequestUri(APiV1BaseUrl, repoUrl, "deploy-keys", sshKeyInfo.pk);
                using (var client = CreateHttpClient(accessToken))
                {
                    using (var response = await client.DeleteAsync(requestUri))
                    {
                        if (!response.IsSuccessStatusCode)
                        {
                            throw CreateOAuthException("RemoveSSHKey", await response.Content.ReadAsStringAsync(), response.StatusCode);
                        }
                    }
                }
            }

            return(sshKeyInfo != null);
        }
        public async Task AddWebHook(string repoUrl, string token, string tokenSecret, string hookUrl)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("token", token);
            CommonUtils.ValidateNullArgument("tokenSecret", tokenSecret);
            CommonUtils.ValidateNullArgument("hookUrl", hookUrl);

            var hook = await GetWebHookInfo(repoUrl, token, tokenSecret, hookUrl);

            if (hook != null)
            {
                if (string.Equals(hookUrl, hook.service.url, StringComparison.OrdinalIgnoreCase))
                {
                    return;
                }

                var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "services", hook.id);
                await _provider.PutAsJsonAsync("UpdateWebHook", requestUri, token, tokenSecret, new CreateBitbucketHookInfo(hookUrl));
            }
            else
            {
                var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "services");
                var content    = new StringContent(String.Format("type=POST;URL={0}", hookUrl), Encoding.UTF8, "application/text");
                await _provider.PostAsync("AddWebHook", requestUri, token, tokenSecret, content);
            }
        }
        private async Task <BitbucketSSHKeyFullInfo> GetSSHKey(string repoUrl, string token, string tokenSecret, string sshKey)
        {
            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "deploy-keys");
            var sshKeys    = await _provider.GetAsync <BitbucketSSHKeyFullInfo[]>("GetSSHKey", requestUri, token, tokenSecret);

            return(sshKeys.FirstOrDefault(info => SSHKeyEquals(info.key, sshKey)));
        }
        public async Task <List <BitbucketV2WebHook> > ListWebHooks(string repoUrl, string accessToken)
        {
            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "hooks");

            using (var client = CreateHttpClient(accessToken))
            {
                return(await ListPagingItems <BitbucketV2WebHook>(client, requestUri, "ListWebHooks"));
            }
        }
        // Deprecated due to better V2 api
        //public async Task<IEnumerable<BitbucketRepoInfo>> ListRepositories(string token, string tokenSecret)
        //{
        //    CommonUtils.ValidateNullArgument("token", token);
        //    CommonUtils.ValidateNullArgument("tokenSecret", tokenSecret);
        //    return await _provider.GetAsync<BitbucketRepoInfo[]>("ListRepositories", "https://api.bitbucket.org/1.0/user/repositories/", token, tokenSecret);
        //}

        public async Task <BitbucketRepoInfo> GetRepository(string repoUrl, string token, string tokenSecret)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("token", token);
            CommonUtils.ValidateNullArgument("tokenSecret", tokenSecret);

            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl);

            return(await _provider.GetAsync <BitbucketRepoInfo>("GetRepository", requestUri, token, tokenSecret));
        }
        public async Task <BitbucketProxy.BitbucketSSHKeyFullInfo[]> ListSSHKeys(string repoUrl, string accessToken)
        {
            var requestUri = BitbucketProxyHelper.GetRequestUri(APiV1BaseUrl, repoUrl, "deploy-keys");

            using (var client = CreateHttpClient(accessToken))
                using (var response = await client.GetAsync(requestUri))
                {
                    return(await this.ProcessResponse <BitbucketProxy.BitbucketSSHKeyFullInfo[]>("GetSSHKey", response));
                }
        }
        public async Task <BitbucketBranchInfo[]> ListBranches(string repoUrl, string token, string tokenSecret)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("token", token);
            CommonUtils.ValidateNullArgument("tokenSecret", tokenSecret);

            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "branches-tags");
            var info       = await _provider.GetAsync <BitbucketProxy.BitbucketBranchesTagsInfo>("ListBranches", requestUri, token, tokenSecret);

            return(info.branches);
        }
        private async Task <BitbucketProxy.BitbucketSSHKeyFullInfo> GetSSHKey(string repoUrl, string accessToken, string sshKey)
        {
            var requestUri = BitbucketProxyHelper.GetRequestUri(APiV1BaseUrl, repoUrl, "deploy-keys");

            using (var client = CreateHttpClient(accessToken))
                using (var response = await client.GetAsync(requestUri))
                {
                    var sshKeys = await this.ProcessResponse <BitbucketProxy.BitbucketSSHKeyFullInfo[]>("GetSSHKey", response);

                    return(sshKeys.FirstOrDefault(info => BitbucketProxy.SSHKeyEquals(info.key, sshKey)));
                }
        }
        public async Task <StreamContent> DownloadFile(string repoUrl, string path, string token, string tokenSecret, string branch = "master")
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("path", path);
            CommonUtils.ValidateNullArgument("token", token);
            CommonUtils.ValidateNullArgument("tokenSecret", tokenSecret);
            CommonUtils.ValidateNullArgument("branch", branch);

            var requestUri = String.Format("{0}/{1}/{2}", BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "raw"), branch, path);

            return(await _provider.GetStreamAsync("DownloadFile", requestUri, token, tokenSecret));
        }
        public async Task <BitbucketProxy.BitbucketRepoInfo> GetRepository(string repoUrl, string accessToken)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);

            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl);

            using (var client = CreateHttpClient(accessToken))
                using (var response = await client.GetAsync(requestUri))
                {
                    return((await this.ProcessResponse <BitbucketV2Repository>("GetRepository", response)).ToRepoInfo());
                }
        }
        public async Task <BitbucketProxy.BitbucketHookInfo[]> ListServices(string repoUrl, string accessToken)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("accessToken", accessToken);

            var requestUri = BitbucketProxyHelper.GetRequestUri(APiV1BaseUrl, repoUrl, "services");

            using (var client = CreateHttpClient(accessToken))
                using (HttpResponseMessage response = await client.GetAsync(requestUri))
                {
                    return(await ProcessResponse <BitbucketProxy.BitbucketHookInfo[]>("ListServices", response));
                }
        }
        public async Task <BitbucketProxy.BitbucketBranchInfo[]> ListBranches(string repoUrl, string accessToken)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("accessToken", accessToken);

            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "refs", "branches");

            using (var client = CreateHttpClient(accessToken))
            {
                List <BitbucketV2Branch> branchResults = await ListPagingItems <BitbucketV2Branch>(client, requestUri, "ListBranches");

                return(branchResults.Select(v => v.ToBranchInfo()).ToArray());
            }
        }
        public async Task <bool> RemoveSSHKey(string repoUrl, string token, string tokenSecret, string sshKey)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("token", token);
            CommonUtils.ValidateNullArgument("tokenSecret", tokenSecret);
            CommonUtils.ValidateNullArgument("sshKey", sshKey);

            var sshKeyInfo = await GetSSHKey(repoUrl, token, tokenSecret, sshKey);

            if (sshKeyInfo != null)
            {
                var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "deploy-keys", sshKeyInfo.pk);
                await _provider.DeleteAsync("RemoveSSHKey", requestUri, token, tokenSecret);
            }

            return(sshKeyInfo != null);
        }
        public async Task AddSSHKey(string repoUrl, string token, string tokenSecret, string title, string sshKey)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("token", token);
            CommonUtils.ValidateNullArgument("tokenSecret", tokenSecret);
            CommonUtils.ValidateNullArgument("title", title);
            CommonUtils.ValidateNullArgument("sshKey", sshKey);

            await RemoveSSHKey(repoUrl, token, tokenSecret, sshKey);

            // deploy key only allow read-only access
            var sshKeyInfo = new BitbucketSSHKeyInfo {
                label = title, key = sshKey
            };
            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "deploy-keys");
            await _provider.PostAsJsonAsync("AddSSHKey", requestUri, token, tokenSecret, sshKeyInfo);
        }
        public async Task <bool> RemoveWebHook(string repoUrl, string token, string tokenSecret, string hookUrl)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("token", token);
            CommonUtils.ValidateNullArgument("tokenSecret", tokenSecret);
            CommonUtils.ValidateNullArgument("hookUrl", hookUrl);

            var hook = await GetWebHookInfo(repoUrl, token, tokenSecret, hookUrl);

            if (hook != null)
            {
                var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "services", hook.id);
                await _provider.DeleteAsync("RemoveWebHook", requestUri, token, tokenSecret);
            }

            return(hook != null);
        }
        public async Task AddWebHook(string repoUrl, string accessToken, string hookUrl)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("accessToken", accessToken);
            CommonUtils.ValidateNullArgument("hookUrl", hookUrl);

            var hook = await GetWebHookInfo(repoUrl, accessToken, hookUrl);

            if (hook != null)
            {
                if (string.Equals(hookUrl, hook.url, StringComparison.OrdinalIgnoreCase))
                {
                    return;
                }

                hook.url = hookUrl;
                var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "hooks", hook.uuid);
                using (var client = CreateHttpClient(accessToken))
                    using (var response = await client.PutAsJsonAsync(requestUri, hook))
                    {
                        if (!response.IsSuccessStatusCode)
                        {
                            throw CreateOAuthException("UpdateWebHook", await response.Content.ReadAsStringAsync(), response.StatusCode);
                        }
                    }
            }
            else
            {
                hook             = new BitbucketV2WebHook();
                hook.active      = true;
                hook.description = "Azure Webhook";
                hook.events      = new string[] { "repo:push" };
                hook.url         = hookUrl;

                var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "hooks");
                using (var client = CreateHttpClient(accessToken))
                    using (var response = await client.PostAsJsonAsync(requestUri, hook))
                    {
                        if (!response.IsSuccessStatusCode)
                        {
                            throw CreateOAuthException("AddWebHook", await response.Content.ReadAsStringAsync(), response.StatusCode);
                        }
                    }
            }
        }
        private async Task <BitbucketHookInfo> GetWebHookInfo(string repoUrl, string token, string tokenSecret, string hookUrl)
        {
            var hookUri    = new Uri(hookUrl);
            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "services");
            var services   = await _provider.GetAsync <BitbucketHookInfo[]>("GetWebHookInfo", requestUri, token, tokenSecret);

            return(services.FirstOrDefault(service =>
            {
                if (service.service != null && service.service.url != null && string.Equals(service.service.type, "POST", StringComparison.OrdinalIgnoreCase))
                {
                    Uri configUri;
                    if (Uri.TryCreate(service.service.url, UriKind.Absolute, out configUri))
                    {
                        return string.Equals(hookUri.Host, configUri.Host, StringComparison.OrdinalIgnoreCase);
                    }
                }

                return false;
            }));
        }
        public async Task <StreamContent> DownloadFile(string repoUrl, string path, string accessToken, string branch = "master")
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("path", path);
            CommonUtils.ValidateNullArgument("branch", branch);

            // Missing v2 api to get file content
            // BUG: https://bitbucket.org/site/master/issues/12741/missing-v2-api-to-get-file-content
            var requestUri = String.Format("{0}/{1}/{2}", BitbucketProxyHelper.GetRequestUri(APiV1BaseUrl, repoUrl, "raw"), branch, path);

            using (var client = CreateHttpClient(accessToken))
                using (var response = await client.GetAsync(requestUri))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        return((StreamContent)response.Content);
                    }

                    throw CreateOAuthException("DownloadFile", await response.Content.ReadAsStringAsync(), response.StatusCode);
                }
        }
        private async Task <BitbucketV2WebHook> GetWebHookInfo(string repoUrl, string accessToken, string hookUrl)
        {
            var hookUri    = new Uri(hookUrl);
            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "hooks");

            using (var client = CreateHttpClient(accessToken))
            {
                List <BitbucketV2WebHook> webhookResults = await ListPagingItems <BitbucketV2WebHook>(client, requestUri, "GetWebHookInfo");

                return(webhookResults.FirstOrDefault(w =>
                {
                    Uri configUri;
                    if (Uri.TryCreate(w.url, UriKind.Absolute, out configUri))
                    {
                        return string.Equals(hookUri.Host, configUri.Host, StringComparison.OrdinalIgnoreCase);
                    }

                    return false;
                }));
            }
        }
        public async Task <bool> RemoveWebHook(string repoUrl, string accessToken, string hookUrl)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("accessToken", accessToken);
            CommonUtils.ValidateNullArgument("hookUrl", hookUrl);

            var hook = await GetWebHookInfo(repoUrl, accessToken, hookUrl);

            if (hook != null)
            {
                var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "hooks", hook.uuid);
                using (var client = CreateHttpClient(accessToken))
                    using (var response = await client.DeleteAsync(requestUri))
                    {
                        if (!response.IsSuccessStatusCode)
                        {
                            throw CreateOAuthException("RemoveWebHook", await response.Content.ReadAsStringAsync(), response.StatusCode);
                        }
                    }
            }

            return(hook != null);
        }
        /// <summary>
        /// Remove Webhook service from v1 API
        /// </summary>
        public async Task <bool> RemoveService(string repoUrl, string accessToken, string serviceUrl)
        {
            CommonUtils.ValidateNullArgument("repoUrl", repoUrl);
            CommonUtils.ValidateNullArgument("accessToken", accessToken);
            CommonUtils.ValidateNullArgument("serviceUrl", serviceUrl);

            var service = await GetService(repoUrl, accessToken, serviceUrl);

            if (service != null)
            {
                var requestUri = BitbucketProxyHelper.GetRequestUri(APiV1BaseUrl, repoUrl, "services", service.id);
                using (var client = CreateHttpClient(accessToken))
                    using (HttpResponseMessage response = await client.DeleteAsync(requestUri))
                    {
                        if (!response.IsSuccessStatusCode)
                        {
                            throw CreateOAuthException("RemoveService", await response.Content.ReadAsStringAsync(), response.StatusCode);
                        }
                    }
            }

            return(service != null);
        }
        public async Task <BitbucketSSHKeyFullInfo[]> ListSSHKeys(string repoUrl, string token, string tokenSecret)
        {
            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "deploy-keys");

            return(await _provider.GetAsync <BitbucketSSHKeyFullInfo[]>("ListSSHKeys", requestUri, token, tokenSecret));
        }
        public async Task <BitbucketHookInfo[]> ListWebHooks(string repoUrl, string token, string tokenSecret)
        {
            var requestUri = BitbucketProxyHelper.GetRequestUri(ApiBaseUrl, repoUrl, "services");

            return(await _provider.GetAsync <BitbucketHookInfo[]>("ListWebHooks", requestUri, token, tokenSecret));
        }