diff --git a/components/collections/import-export-collections.vue b/components/collections/import-export-collections.vue index 641edf135..10e924f34 100644 --- a/components/collections/import-export-collections.vue +++ b/components/collections/import-export-collections.vue @@ -6,6 +6,44 @@

{{ $t("import_export") }} {{ $t("collections") }}

+ + + + @@ -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") }, diff --git a/components/environments/import-export-environment.vue b/components/environments/import-export-environment.vue index c05cdf165..a88ac0de7 100644 --- a/components/environments/import-export-environment.vue +++ b/components/environments/import-export-environment.vue @@ -6,6 +6,44 @@

{{ $t("import_export") }} {{ $t("environments") }}

+ + + + @@ -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") }, diff --git a/components/firebase/login.vue b/components/firebase/login.vue index 33eb4ad82..7b6dfe69b 100644 --- a/components/firebase/login.vue +++ b/components/firebase/login.vue @@ -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, diff --git a/helpers/__tests__/fb.spec.js b/helpers/__tests__/fb.spec.js index ead98b043..5d864eea5 100644 --- a/helpers/__tests__/fb.spec.js +++ b/helpers/__tests__/fb.spec.js @@ -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() diff --git a/helpers/fb.js b/helpers/fb.js index 30c3dd7d8..01757de66 100644 --- a/helpers/fb.js +++ b/helpers/fb.js @@ -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) diff --git a/lang/en-US.json b/lang/en-US.json index d992a9378..aa64102c6 100644 --- a/lang/en-US.json +++ b/lang/en-US.json @@ -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" }