Merge pull request #1367 from hoppscotch/feat/gist
Collections and environments + GitHub gist
This commit is contained in:
@@ -6,6 +6,44 @@
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("import_export") }} {{ $t("collections") }}</h3>
|
||||
<div>
|
||||
<v-popover>
|
||||
<button class="tooltip-target icon" v-tooltip.left="$t('more')">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button class="icon" @click="readCollectionGist" v-close-popover>
|
||||
<i class="material-icons">code</i>
|
||||
<span>{{ $t("import_from_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-tooltip.bottom="{
|
||||
content: !fb.currentUser
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: null,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
:disabled="
|
||||
!fb.currentUser
|
||||
? true
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? true
|
||||
: false
|
||||
"
|
||||
class="icon"
|
||||
@click="createCollectionGist"
|
||||
v-close-popover
|
||||
>
|
||||
<i class="material-icons">code</i>
|
||||
<span>{{ $t("create_secret_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
@@ -93,6 +131,57 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async createCollectionGist() {
|
||||
await this.$axios
|
||||
.$post(
|
||||
"https://api.github.com/gists",
|
||||
{
|
||||
files: {
|
||||
"hoppscotch-collections.json": {
|
||||
content: this.collectionJson,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `token ${fb.currentUser.accessToken}`,
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
this.$toast.success(this.$t("gist_created"), {
|
||||
icon: "done",
|
||||
})
|
||||
window.open(response.html_url)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(this.$t("something_went_wrong"), {
|
||||
icon: "error",
|
||||
})
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
async readCollectionGist() {
|
||||
let gist = prompt(this.$t("enter_gist_url"))
|
||||
if (!gist) return
|
||||
await this.$axios
|
||||
.$get(`https://api.github.com/gists/${gist.split("/").pop()}`, {
|
||||
headers: {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
let collections = JSON.parse(Object.values(response.files)[0].content)
|
||||
this.$store.commit("postwoman/replaceCollections", collections)
|
||||
this.fileImported()
|
||||
this.syncToFBCollections()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.failedImport()
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
|
||||
@@ -6,6 +6,44 @@
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("import_export") }} {{ $t("environments") }}</h3>
|
||||
<div>
|
||||
<v-popover>
|
||||
<button class="tooltip-target icon" v-tooltip.left="$t('more')">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button class="icon" @click="readEnvironmentGist" v-close-popover>
|
||||
<i class="material-icons">code</i>
|
||||
<span>{{ $t("import_from_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-tooltip.bottom="{
|
||||
content: !fb.currentUser
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: null,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
:disabled="
|
||||
!fb.currentUser
|
||||
? true
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? true
|
||||
: false
|
||||
"
|
||||
class="icon"
|
||||
@click="createEnvironmentGist"
|
||||
v-close-popover
|
||||
>
|
||||
<i class="material-icons">code</i>
|
||||
<span>{{ $t("create_secret_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
@@ -93,6 +131,57 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async createEnvironmentGist() {
|
||||
await this.$axios
|
||||
.$post(
|
||||
"https://api.github.com/gists",
|
||||
{
|
||||
files: {
|
||||
"hoppscotch-environments.json": {
|
||||
content: this.environmentJson,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `token ${fb.currentUser.accessToken}`,
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
this.$toast.success(this.$t("gist_created"), {
|
||||
icon: "done",
|
||||
})
|
||||
window.open(response.html_url)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(this.$t("something_went_wrong"), {
|
||||
icon: "error",
|
||||
})
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
async readEnvironmentGist() {
|
||||
let gist = prompt(this.$t("enter_gist_url"))
|
||||
if (!gist) return
|
||||
await this.$axios
|
||||
.$get(`https://api.github.com/gists/${gist.split("/").pop()}`, {
|
||||
headers: {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
let environments = JSON.parse(Object.values(response.files)[0].content)
|
||||
this.$store.commit("postwoman/replaceEnvironments", environments)
|
||||
this.fileImported()
|
||||
this.syncToFBEnvironments()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.failedImport()
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
|
||||
@@ -62,6 +62,7 @@ export default {
|
||||
|
||||
this.showLoginSuccess()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
// An error happened.
|
||||
if (err.code === "auth/account-exists-with-different-credential") {
|
||||
// Step 2.
|
||||
@@ -80,22 +81,23 @@ export default {
|
||||
// Asks the user their password.
|
||||
// In real scenario, you should handle this asynchronously.
|
||||
const password = promptUserForPassword() // TODO: implement promptUserForPassword.
|
||||
const user = await fb.signInWithEmailAndPassword(email, password)
|
||||
|
||||
const user = await fb.signInWithEmailAndPassword(email, password)
|
||||
await user.linkWithCredential(pendingCred)
|
||||
|
||||
this.showLoginSuccess()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.$toast.info(`${this.$t("login_with")}`, {
|
||||
this.$toast.info(`${this.$t("account_exists")}`, {
|
||||
icon: "vpn_key",
|
||||
duration: null,
|
||||
closeOnSwipe: false,
|
||||
action: {
|
||||
text: this.$t("yes"),
|
||||
onClick: async (e, toastObject) => {
|
||||
const user = await fb.signInWithGithub()
|
||||
const { user } = await fb.signInWithGithub()
|
||||
await user.linkAndRetrieveDataWithCredential(pendingCred)
|
||||
|
||||
this.showLoginSuccess()
|
||||
@@ -109,7 +111,9 @@ export default {
|
||||
},
|
||||
async signInWithGithub() {
|
||||
try {
|
||||
const { additionalUserInfo } = await fb.signInUserWithGithub()
|
||||
const { credential, additionalUserInfo } = await fb.signInUserWithGithub()
|
||||
|
||||
fb.setProviderInfo(credential.providerId, credential.accessToken)
|
||||
|
||||
if (additionalUserInfo.isNewUser) {
|
||||
this.$toast.info(`${this.$t("turn_on")} ${this.$t("sync")}`, {
|
||||
@@ -131,6 +135,7 @@ export default {
|
||||
|
||||
this.showLoginSuccess()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
// An error happened.
|
||||
if (err.code === "auth/account-exists-with-different-credential") {
|
||||
// Step 2.
|
||||
@@ -158,7 +163,7 @@ export default {
|
||||
return
|
||||
}
|
||||
|
||||
this.$toast.info(`${this.$t("login_with")}`, {
|
||||
this.$toast.info(`${this.$t("account_exists")}`, {
|
||||
icon: "vpn_key",
|
||||
duration: null,
|
||||
closeOnSwipe: false,
|
||||
|
||||
@@ -205,7 +205,11 @@ describe("FirebaseInstance", () => {
|
||||
const fbFunc = jest.spyOn(mockAuth, "signInWithPopup")
|
||||
|
||||
const fb = new FirebaseInstance(mocksdk, {
|
||||
github: () => {},
|
||||
github: () => {
|
||||
return {
|
||||
addScope: () => {}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
signOutUser()
|
||||
@@ -218,7 +222,11 @@ describe("FirebaseInstance", () => {
|
||||
const fbFunc = jest.spyOn(mockAuth, "signInWithPopup")
|
||||
|
||||
const fb = new FirebaseInstance(mocksdk, {
|
||||
github: () => {},
|
||||
github: () => {
|
||||
return {
|
||||
addScope: () => {}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
signOutUser()
|
||||
@@ -231,7 +239,11 @@ describe("FirebaseInstance", () => {
|
||||
const fbFunc = jest.spyOn(mockAuth, "signInWithPopup")
|
||||
|
||||
const fb = new FirebaseInstance(mocksdk, {
|
||||
github: () => {},
|
||||
github: () => {
|
||||
return {
|
||||
addScope: () => {}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
signOutUser()
|
||||
@@ -240,11 +252,35 @@ describe("FirebaseInstance", () => {
|
||||
|
||||
await expect(fb.signInUserWithGithub()).rejects.toEqual("test error")
|
||||
})
|
||||
test("adds 'repo gist' scope", async () => {
|
||||
const fbFunc = jest.spyOn(mockAuth, "signInWithPopup")
|
||||
|
||||
const addScopeMock = jest.fn()
|
||||
|
||||
const fb = new FirebaseInstance(mocksdk, {
|
||||
github: () => {
|
||||
return {
|
||||
addScope: addScopeMock
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
signOutUser()
|
||||
|
||||
fbFunc.mockImplementation(() => Promise.resolve("test"))
|
||||
await fb.signInUserWithGithub()
|
||||
|
||||
expect(addScopeMock).toBeCalledWith("repo gist")
|
||||
})
|
||||
test("resolves the response the firebase request resolves", async () => {
|
||||
const fbFunc = jest.spyOn(mockAuth, "signInWithPopup")
|
||||
|
||||
const fb = new FirebaseInstance(mocksdk, {
|
||||
github: () => {},
|
||||
github: () => {
|
||||
return {
|
||||
addScope: () => {}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
signOutUser()
|
||||
|
||||
@@ -36,6 +36,7 @@ export class FirebaseInstance {
|
||||
this.app.auth().onAuthStateChanged((user) => {
|
||||
if (user) {
|
||||
this.currentUser = user
|
||||
|
||||
this.currentUser.providerData.forEach((profile) => {
|
||||
let us = {
|
||||
updatedOn: new Date(),
|
||||
@@ -47,10 +48,15 @@ export class FirebaseInstance {
|
||||
}
|
||||
this.usersCollection
|
||||
.doc(this.currentUser.uid)
|
||||
.set(us)
|
||||
.set(us, { merge: true })
|
||||
.catch((e) => console.error("error updating", us, e))
|
||||
})
|
||||
|
||||
this.usersCollection.doc(this.currentUser.uid).onSnapshot((doc) => {
|
||||
this.currentUser.provider = doc.data().provider
|
||||
this.currentUser.accessToken = doc.data().accessToken
|
||||
})
|
||||
|
||||
this.usersCollection
|
||||
.doc(this.currentUser.uid)
|
||||
.collection("feeds")
|
||||
@@ -131,7 +137,7 @@ export class FirebaseInstance {
|
||||
}
|
||||
|
||||
async signInUserWithGithub() {
|
||||
return await this.app.auth().signInWithPopup(this.authProviders.github())
|
||||
return await this.app.auth().signInWithPopup(this.authProviders.github().addScope("repo gist"))
|
||||
}
|
||||
|
||||
async signInWithEmailAndPassword(email, password) {
|
||||
@@ -288,6 +294,24 @@ export class FirebaseInstance {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
async setProviderInfo(id, token) {
|
||||
const us = {
|
||||
updatedOn: new Date(),
|
||||
provider: id,
|
||||
accessToken: token,
|
||||
}
|
||||
try {
|
||||
await this.usersCollection
|
||||
.doc(this.currentUser.uid)
|
||||
.update(us)
|
||||
.catch((e) => console.error("error updating", us, e))
|
||||
} catch (e) {
|
||||
console.error("error updating", ev, e)
|
||||
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const fb = new FirebaseInstance(firebase.initializeApp(firebaseConfig), authProviders)
|
||||
|
||||
@@ -294,5 +294,11 @@
|
||||
"experiments": "Experiments",
|
||||
"experiments_notice": "This is a collection of experiments we're working on that might turn out to be useful, fun, both, or neither. They're not final and may not be stable, so if something overly weird happens, don't panic. Just turn the dang thing off. Jokes aside, ",
|
||||
"use_experimental_url_bar": "Use experimental URL bar with environment highlighting",
|
||||
"select_environment": "Select environment"
|
||||
"select_environment": "Select environment",
|
||||
"login_with_github_to": "Login with GitHub to ",
|
||||
"create_secret_gist": "Create secret Gist",
|
||||
"gist_created": "Gist created",
|
||||
"import_from_gist": "Import from Gist",
|
||||
"enter_gist_url": "Enter Gist URL",
|
||||
"account_exists": "Account exists with different credential - Login to link both accounts"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user