diff --git a/options/options.css b/options/options.css index dc4af6d..68c7ed5 100644 --- a/options/options.css +++ b/options/options.css @@ -61,7 +61,7 @@ .form .logout-container { display: none; } -.form .ghe-login-container { +.form .ghe-login-container, .form .bitbucket-login-container { display: none; } .form .error { diff --git a/options/options.html b/options/options.html index 2452fa2..acd455c 100644 --- a/options/options.html +++ b/options/options.html @@ -13,7 +13,7 @@

Logged in as: XXX

After logout, remember to delete the access token

-
+

Star this extension on Github for support

-

Using Github Enterprise? Login to Github Enterprise

+

Switch to Github Enterprise or Bitbucket

@@ -43,9 +43,20 @@

Logged in as: XXX

Please star this extension on Github for support

-

Using Github.com? Login to Github.com

+

Switch to Github or Bitbucket

+ +
+
+ + + +
+ +

Please star this extension on Github for support

+

Switch to Github or Github Enterprise

+
diff --git a/options/options.js b/options/options.js index 28a3eb8..5b37ebc 100644 --- a/options/options.js +++ b/options/options.js @@ -1,9 +1,10 @@ "use strict"; $(() => { - $('.message a').click(function(){ + $('.message a').click(function(e){ $('.error').hide(); - $('.login-container').animate({height: 'toggle', opacity: 'toggle'}, 'slow'); + $('.login-container').animate({height: 'hide', opacity: 'hide'}, 'slow'); + $(`.${e.target.name}-login-container`).animate({height: 'show', opacity: 'show'}, 'slow'); }); $('#login').click((e) => { addCred(getGithubParam()); @@ -11,30 +12,41 @@ $(() => { $('#ghe-login').click((e) => { addCred(getGHEParam()); }); + $('#bitbucket-login').click((e) => { + addCred(getBitbucketParam()); + }); $('#logout').click((e) => { - logoutGithub(); + logout(); }); checkToken() .then((item) => { $('.login-container').hide(); $('.logout-container').show(); - let domain = '@Github.com'; - let userLink = `https://github.com/${item.user}`; - let tokenLink = 'https://github.com/settings/tokens'; - if (item.baseUrl !== 'https://api.github.com') { - let match = item.baseUrl.match(/:\/\/(.*)\/api\/v3/); - if (!match || !match[1]) { - domain = ''; - userLink = ''; - tokenLink = ''; - } else { - domain = `@${match[1]}`; - userLink = `https://${match[1]}/${item.user}`; - tokenLink = `https://${match[1]}/settings/tokens`; + let user = item.user, domain, userLink, tokenLink; + if(item.scm !== 'bitbucket') { + domain = '@Github.com'; + userLink = `https://github.com/${item.user}`; + tokenLink = 'https://github.com/settings/tokens'; + if (item.baseUrl !== 'https://api.github.com') { + let match = item.baseUrl.match(/:\/\/(.*)\/api\/v3/); + if (!match || !match[1]) { + domain = ''; + userLink = ''; + tokenLink = ''; + } else { + domain = `@${match[1]}`; + userLink = `https://${match[1]}/${item.user}`; + tokenLink = `https://${match[1]}/settings/tokens`; + } } + } else { + domain = '@Bitbucket.org'; + userLink = `https://bitbucket.org/${user}`; + tokenLink = `https://bitbucket.org/account/user/${user}/api`; } - $('#login-user').text(`${item.user}${domain}`).attr('href', userLink); + + $('#login-user').text(`${user}${domain}`).attr('href', userLink); $('#token').attr('href', tokenLink); }) .catch((err) => { @@ -43,12 +55,14 @@ $(() => { }) function getGithubParam() { + const scm = 'github'; const username = $('#username').val(); const password = $('#password').val(); const token = $('#accesstoken').val(); const baseUrl = `https://api.github.com`; const otp = $('#otp').val(); return { + scm, username, password, token, @@ -58,12 +72,14 @@ function getGithubParam() { } function getGHEParam() { + const scm = 'github'; const username = $('#ghe-username').val(); const password = $('#ghe-password').val(); const token = $('#ghe-accesstoken').val(); const baseUrl = $('#ghe-url').val() + '/api/v3'; const otp = $('#ghe-otp').val(); return { + scm, username, password, token, @@ -72,6 +88,21 @@ function getGHEParam() { }; } +function getBitbucketParam() { + const scm = 'bitbucket'; + const username = $('#bitbucket-username').val(); + const email = $('#bitbucket-email').val(); + const password = $('#bitbucket-password').val(); + const baseUrl = `https://api.bitbucket.org/2.0`; + return { + scm, + username, + email, + password, + baseUrl + } +} + function addCred(param) { if (param.username === '') { return; @@ -80,11 +111,12 @@ function addCred(param) { return; } - if (param.password !== '') return loginGithub(param); + if (param.scm == 'bitbucket') return loginBitbucket(param); + if (param.password !== '' && param.scm == 'github') return loginGithub(param); addStar(param.token) .then(() => { - chrome.storage.sync.set({ user: param.username, token: param.token, baseUrl: param.baseUrl}, () => { + chrome.storage.sync.set({scm: param.scm, user: param.username, token: param.token, baseUrl: param.baseUrl}, () => { location.reload(); }); chrome.storage.local.get('tab', (item) => { @@ -124,7 +156,7 @@ function loginGithub(param) { .done((response) => { addStar(response.token) .then(() => { - chrome.storage.sync.set({ scm: 'github', user: username, token: response.token, baseUrl: baseUrl}, () => { + chrome.storage.sync.set({scm: param.scm, user: username, token: response.token, baseUrl: baseUrl}, () => { location.reload(); }); chrome.storage.local.get('tab', (item) => { @@ -145,7 +177,42 @@ function loginGithub(param) { }) } -function logoutGithub() { +function loginBitbucket(param) { + const username = param.username; + const email = param.email; + const password = param.password; + const baseUrl = param.baseUrl; + const headers = { + Authorization: `Basic RmZIVE02ZnN5NDJQQlJDRjRQOmVDZDN0TTh5TUpUeTJSMld4bTJWUzZoYWVKdnpuNzdw` + } + $.ajax({ + url: 'https://bitbucket.org/site/oauth2/access_token', + headers: headers, + method: 'POST', + dataType: 'json', + contentType: 'application/x-www-form-urlencoded', + data: { + grant_type: 'password', + username: email, + password: password + } + }) + .done((response) => { + chrome.storage.sync.set({scm: param.scm, user: username, token: response.refresh_token, baseUrl: baseUrl}, () => { + location.reload(); + }); + chrome.storage.local.get('tab', (item) => { + if(item.tab) { + chrome.tabs.reload(item.tab); + } + }); + }) + .fail(() => { + $('.error').show(); + }) +} + +function logout() { chrome.storage.sync.remove(['scm', 'token', 'user', 'baseUrl'], () => { location.reload(); }); @@ -158,7 +225,7 @@ function logoutGithub() { function checkToken() { return new Promise((resolve, reject) => { - chrome.storage.sync.get(['token', 'user', 'baseUrl'], (item) => { + chrome.storage.sync.get(['scm', 'token', 'user', 'baseUrl'], (item) => { if (item.token && item.token !== ''){ resolve(item); } diff --git a/src/gas-api.js b/src/gas-api.js index bd12f9e..c544359 100644 --- a/src/gas-api.js +++ b/src/gas-api.js @@ -3,7 +3,7 @@ class Gas { pull(code) { const changed = $('.diff-file:checked').toArray().map(e => e.value); - const update_promises = changed.filter(f => code.github[f]) + const updatePromises = changed.filter(f => code.github[f]) .map((file) => { const match = file.match(/(.*?)\.(gs|html)$/); if (!match || !match[1] || !match[2]) { @@ -24,7 +24,7 @@ class Gas { }) .filter(n => n != undefined); - const delete_promises = changed.filter(f => !code.github[f]) + const deletePromises = changed.filter(f => !code.github[f]) .map((file) => { const match = file.match(/(.*?)\.(gs|html)$/); if (!match || !match[1] || !match[2]) { @@ -35,16 +35,16 @@ class Gas { return () => this.gasDeleteFile(name); }); - if (update_promises.length === 0 && delete_promises.length === 0) { + if (updatePromises.length === 0 && deletePromises.length === 0) { showAlert('Nothing to do', LEVEL_WARN); return; } this.getGasContext() .then(() => { - return Promise.all(update_promises.map(f => f())) + return Promise.all(updatePromises.map(f => f())) .then(() => { - return Promise.all(delete_promises.map(f => f())); + return Promise.all(deletePromises.map(f => f())); }) }) .then(() => { diff --git a/src/gas-hub.js b/src/gas-hub.js index 0423692..2b90eac 100644 --- a/src/gas-hub.js +++ b/src/gas-hub.js @@ -185,17 +185,15 @@ function initPageEvent() { let label; switch (type) { case 'repo' : - if (context.repo && target.text() === context.repo.name) return; + if (context.repo && target.text() === context.repo.fullName) return; //update context.repo with name and fullName - const name = target.text(); const fullName = target.attr('data'); content = { - name: name, fullName : fullName, gist: fullName === 'gist' } - label = name; - context.gist = content.gist + label = fullName; + context.gist = content.gist; break; case 'branch' : if (context[type] && target.text() === context[type]) return; @@ -335,15 +333,15 @@ function showDiff(code, type) { function updateRepo(repos) { $('.repo-menu').empty().append('
Create new repo
'); - $('.repo-menu').append('
Using Gist
'); + $('.repo-menu').append('
gist
'); repos.forEach((repo) => { - let content = `
${repo.name}
` + let content = `
${repo}
` $('.repo-menu').append(content); }); if (context.repo) { - $('#scm-bind-repo').text(`Repo: ${context.repo.name}`); - return context.repo.name; + $('#scm-bind-repo').text(`Repo: ${context.repo.fullName}`); + return context.repo.fullName; } return null; } diff --git a/src/scm/github.js b/src/scm/github.js index dd753f4..31bafc0 100644 --- a/src/scm/github.js +++ b/src/scm/github.js @@ -31,7 +31,7 @@ class Github { contentType: 'application/json', data: JSON.stringify(payload) }) - .then((response) => { + .then(response => { return {file: file, blob: response}; }) }); @@ -47,7 +47,7 @@ class Github { { access_token: this.accessToken } ) ]) - .then((responses) => { + .then(responses => { return $.getJSON( responses[1].commit.commit.tree.url, { @@ -55,7 +55,7 @@ class Github { access_token: this.accessToken } ) - .then((baseTree) => { + .then(baseTree => { const tree = responses[0].map((data) => { return { path: data.file, @@ -71,7 +71,7 @@ class Github { tree: tree }; }) - .then((payload) => { + .then(payload => { return $.ajax({ url: `${this.baseUrl}/repos/${context.repo.fullName}/git/trees`, headers: { @@ -84,14 +84,14 @@ class Github { data: JSON.stringify(payload) }); }) - .then((response) => { + .then(response => { return Object.assign(response, { parent: responses[1].commit.sha }) }) - .fail((err) => { + .fail(err => { throw err; - }) + }); }) - .then((response) => { + .then(response => { const payload = { message: $('#commit-comment').val(), tree: response.sha, @@ -111,7 +111,7 @@ class Github { data: JSON.stringify(payload) }); }) - .then((response) => { + .then(response => { const payload = { force: true, sha: response.sha @@ -129,9 +129,9 @@ class Github { }); }) .then(() => { - showAlert(`Successfully push to ${context.branch} of ${context.repo.name}`); + showAlert(`Successfully push to ${context.branch} of ${context.repo.fullName}`); }) - .catch((err) => { + .catch(err => { showAlert('Failed to push', LEVEL_ERROR); }); } @@ -145,18 +145,17 @@ class Github { const payload = { files: {} }; - files.forEach((file) => { + files.forEach(file => { payload.files[file] = { content: code.gas[file] }; - }) + }); if (code.github['init_by_gas_hub.html']) { payload.files['init_by_gas_hub.html'] = null; } if ($('#gist-desc').val() !== '') { payload.description = $('#gist-desc').val(); } - console.log(payload); return $.ajax({ url: `${this.baseUrl}/gists/${context.branch}`, headers: { @@ -171,17 +170,17 @@ class Github { .then(() => { showAlert(`Successfully update gist: ${context.branch}`); }) - .fail((err) => { + .fail(err => { showAlert('Failed to update', LEVEL_ERROR); }); } getAllGists() { - return getAllItems(Promise.resolve({items: [], url: `${this.baseUrl}/users/${this.user}/gists?access_token=${this.accessToken}`})) + return getAllItems(Promise.resolve({ items: [], url: `${this.baseUrl}/users/${this.user}/gists?access_token=${this.accessToken}` }), 'github'); } getAllBranches() { - return getAllItems(Promise.resolve({items: [], url: `${this.baseUrl}/repos/${context.repo.fullName}/branches?access_token=${this.accessToken}`})) + return getAllItems(Promise.resolve({ items: [], url: `${this.baseUrl}/repos/${context.repo.fullName}/branches?access_token=${this.accessToken}` }), 'github'); } getCode() { @@ -198,21 +197,21 @@ class Github { .then(resolve) .fail(reject); }) - .then((response) => { + .then(response => { return $.getJSON( `${this.baseUrl}/repos/${context.repo.fullName}/git/trees/${response.commit.commit.tree.sha}`, { recursive: 1, access_token: this.accessToken } ); }) - .then((response) => { + .then(response => { const promises = response.tree.filter((tree) => { return tree.type === 'blob' && /(\.gs|\.html)$/.test(tree.path); }) - .map((tree) => { + .map(tree => { return new Promise((resolve, reject) => { - $.getJSON(tree.url, {access_token: this.accessToken }) + $.getJSON(tree.url, { access_token: this.accessToken }) .then((content) => { - resolve({ file: tree.path, content: decodeURIComponent(escape(atob(content.content)))}); + resolve({ file: tree.path, content: decodeURIComponent(escape(atob(content.content))) }); }) .fail(reject) }); @@ -250,24 +249,21 @@ class Github { } getRepos() { - return getAllItems(Promise.resolve({items: [], url: `${this.baseUrl}/user/repos?access_token=${this.accessToken}`})) - .then((response) => { - const repos = response.map((repo) => { - return { name : repo.name, fullName : repo.full_name } - }); + return getAllItems(Promise.resolve({ items: [], url: `${this.baseUrl}/user/repos?access_token=${this.accessToken}` }), 'github') + .then(response => { + const repos = response.map(repo => repo.full_name); //if current bind still existed, use it const repo = context.bindRepo[context.id]; - if (repo && $.inArray(repo.name, repos.map(repo => repo.name)) >= 0 ) { + if (repo && $.inArray(repo.fullName, repos) >= 0) { context.repo = repo; } else if (context.gist) { context.repo = { - name: 'Using Gist', fullName: 'gist', gist: true } } return repos; - }) + }); } createRepo() { @@ -296,9 +292,8 @@ class Github { .then(resolve) .fail(reject); }) - .then((response) => { + .then(response => { const repo = { - name : response.name, fullName : response.full_name }; context.repo = repo; @@ -309,7 +304,7 @@ class Github { chrome.storage.sync.set({ bindRepo: context.bindRepo }); return response; }) - .then(getGithubRepos) + .then(this.getRepos.bind(this)) .then(updateRepo) .then(updateBranch) .then(() => { @@ -318,7 +313,7 @@ class Github { $('#new-repo-type').val('public'); showAlert(`Successfully create new repository ${repo}`); }) - .catch((err) => { + .catch(err => { showAlert('Failed to create new repository.', LEVEL_ERROR); }); } @@ -351,7 +346,7 @@ class Github { .then(resolve) .fail(reject); }) - .then((response) => { + .then(response => { const gist = response.id; context.branch = gist; Object.assign(context.bindBranch, { [context.id] : gist }); @@ -364,7 +359,7 @@ class Github { $('#new-gist-public').val('public'); showAlert(`Successfully create new gist.`); }) - .catch((err) => { + .catch(err => { showAlert('Failed to create new gist.', LEVEL_ERROR); }); } @@ -380,7 +375,7 @@ class Github { .then(resolve) .fail(reject) }) - .then((response) => { + .then(response => { if (response.object) { return response.object.sha; } @@ -389,12 +384,12 @@ class Github { `${this.baseUrl}/repos/${context.repo.fullName}/git/refs/heads`, { access_token: this.accessToken } ) - .then((response) => { + .then(response => { return response[0].object.sha; }) } }) - .then((sha) => { + .then(sha => { const payload = { ref: `refs/heads/${branch}`, sha: sha @@ -411,18 +406,18 @@ class Github { data: JSON.stringify(payload) }); }) - .then((response) => { + .then(response => { context.branch = branch; Object.assign(context.bindBranch, { [context.id] : branch }); chrome.storage.sync.set({ bindBranch: context.bindBranch }); - return context.repo.name; + return context.repo.fullName; }) .then(updateBranch) .then(() => { $('#new-branch-name').val(''); showAlert(`Successfully create new branch: ${branch}`); }) - .catch((err) => { + .catch(err => { if (err.status === 409) { showAlert('Cannot create branch in empty repository with API, try to create branch in Github.', LEVEL_ERROR); } else {