Skip to content

auth fix + GithubAPI + Types #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ module.exports = {
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};
11 changes: 9 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.21.1",
"core-js": "^3.6.5",
"firebase": "^8.6.8",
"vue": "^2.6.11",
Expand Down
14 changes: 14 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<v-app>
<the-navbar :onLogin="login" :onLogout="logout" />
<v-main>
<router-view />
</v-main>
Expand All @@ -8,12 +9,25 @@

<script lang="ts">
import Vue from 'vue';
import TheNavbar from './components/TheNavbar.vue';

export default Vue.extend({
name: 'App',

data: () => ({
//
}),

components: {
TheNavbar,
},
methods: {
login() {
this.$store.dispatch('login');
},
logout() {
this.$store.dispatch('logout');
},
},
});
</script>
30 changes: 30 additions & 0 deletions src/api/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Repo } from '@/utils/types';
import apiHelpers from './helper';
import { GithubRepoIndentifier } from '@/utils/types';

const baseURL = 'https://api.github.com';

const GithubAPI = {
async getRepo(repoIden: GithubRepoIndentifier): Promise<Partial<Repo>> {
const repoRes = await apiHelpers.get(
baseURL + `/repos/${repoIden.owner}/${repoIden.repo}`,
{
headers: {
Accept: 'application/vnd.github.v3+json',
},
}
);
const repo: Partial<Repo> = {
name: repoRes.name,
shortDes: repoRes.description,
link: repoRes.html_url,
topics: repoRes.topics || [],
};
const readmeLink = `https://raw.githubusercontent.com/${repoRes.owner.login}/${repo.name}/${repoRes.default_branch}/README.md`;
const readmeString = await apiHelpers.get(readmeLink);
repo.longDes = readmeString;
return repo;
},
};

export default GithubAPI;
20 changes: 20 additions & 0 deletions src/api/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';

const apiHelpers = {
get(url: string, config?: AxiosRequestConfig): Promise<any> {
return APICreatingUtility(axios.get(url, config));
},
};

export default apiHelpers;

export const APICreatingUtility = async (
promise: Promise<AxiosResponse<any>>
): Promise<any> => {
try {
const _res = await promise;
return _res.data;
} catch (err) {
throw err.response.data;
}
};
43 changes: 40 additions & 3 deletions src/components/TheNavbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,25 @@
<v-app-bar>
<v-app-bar-nav-icon @click="drawer = true"></v-app-bar-nav-icon>
<v-toolbar-title>Searchbar</v-toolbar-title>
<v-spacer />
<v-btn
color="primary"
@click="onLogin"
:loading="authLoading"
:disabled="authLoading"
v-if="!authenticated"
>
Login
</v-btn>
<v-btn
color="primary"
@click="onLogout"
:loading="authLoading"
:disabled="authLoading"
v-if="authenticated"
>
Logout
</v-btn>
</v-app-bar>
<v-navigation-drawer v-model="drawer" absolute temporary>
<v-list>
Expand Down Expand Up @@ -33,11 +52,29 @@
</template>

<script lang="ts">
export default {
name: 'TheNavbar',
import Vue, { PropType } from 'vue';
import { mapState } from 'vuex';

export default Vue.extend({
name: 'TheNavbar',
props: {
onLogin: {
type: Function as PropType<() => void>,
required: true,
},
onLogout: {
type: Function as PropType<() => void>,
required: true,
},
},
computed: {
...mapState({
authLoading: 'authLoading',
authenticated: 'authenticated',
}),
},
data: () => ({
drawer: false,
}),
};
});
</script>
49 changes: 35 additions & 14 deletions src/components/TheNewProjectForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
required
></v-text-field>
</v-form>
<v-btn :disabled="!valid.link" @click="submitLink">Continue</v-btn>
<v-btn
:disabled="!valid.link"
@click="submitLink"
:loading="continueLoading"
>Continue</v-btn
>
</v-stepper-content>

<v-stepper-step :complete="current > 2" step="2">
Expand Down Expand Up @@ -52,24 +57,40 @@
</template>

<script lang="ts">
export default {
import GithubAPI from '@/api/github';
import Parsers from '@/utils/parsers';
import Vue from 'vue';
export default Vue.extend({
name: 'TheNewProjectForm',

data: () => ({
current: 1,
valid: { link: false, nameAbout: false },
link: '',
linkRules: [(link: string) => !!link || 'Link is required'],
name: '',
nameRules: [(name: string) => !!name || 'Name is required'],
description: '',
readme: '',
}),
data() {
return {
current: 1,
valid: { link: false, nameAbout: false },
link: '',
linkRules: [(link: string) => !!link || 'Link is required'],
name: '',
nameRules: [(name: string) => !!name || 'Name is required'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also have a limit on the size of name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

description: '',
readme: '',
continueLoading: false,
};
},

methods: {
submitLink: function (e: any) {
submitLink: async function (e: any) {
e.preventDefault();
if (!this.valid.link) return;
const parsed = Parsers.parseRepoLink(this.link);
if (parsed) {
this.continueLoading = true;
const repo = await GithubAPI.getRepo(parsed);
this.name = repo.name || '';
this.description = repo.shortDes || '';
this.readme = repo.longDes || '';
this.continueLoading = false;
}

this.current++;
},
submitNameAbout: function (e: any) {
Expand All @@ -83,5 +104,5 @@ export default {
console.log('submit');
},
},
};
});
</script>
6 changes: 3 additions & 3 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ const routes: Array<RouteConfig> = [
component: Home,
},
{
path: '/about',
name: 'About',
path: '/new-project',
name: 'New',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ '../views/About.vue'),
import(/* webpackChunkName: "about" */ '../views/NewProject.vue'),
},
];

Expand Down
42 changes: 24 additions & 18 deletions src/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import Vue from 'vue';
import Vuex from 'vuex';
import firebase from 'firebase';
import { auth, provider, usersCollection } from '@/firebase'
import { auth, provider, usersCollection } from '@/firebase';
import router from '@/router';

Vue.use(Vuex);

export default new Vuex.Store({
state: {
authLoading: false,
authenticated: false,
accessToken: "", // github access token to acces the github api
userProfile: {} // user profile object
accessToken: '', // github access token to acces the github api
userProfile: {}, // user profile object
},
mutations: {
setUserProfile(state, val) {
Expand All @@ -21,50 +22,55 @@ export default new Vuex.Store({
},
setAuthenticated(state, val: boolean) {
state.authenticated = val;
}
},
setAuthLoading(state, val: boolean) {
state.authLoading = val;
},
},
actions: {
async login({ dispatch, commit }) {
try {
const result = await auth.signInWithPopup(provider)
commit('setAuthLoading', true);
const result = await auth.signInWithPopup(provider);
/** @type {firebase.auth.OAuthCredential} */
const credential = <firebase.auth.OAuthCredential>result.credential;
// This gives you a GitHub Access Token. You can use it to access the GitHub API.
const credential = <firebase.auth.OAuthCredential>(
result.credential
);

const user = result.user;
const token = credential.accessToken;
dispatch('fetchUserProfile', user);
commit('setAccessToken', token);
} catch (error) {
// Handle Errors here.
commit('setAuthLoading', false);
const errorCode = error.code;
const errorMessage = error.message;
// // The email of the user's account used.
const email = error.email;
// // The firebase.auth.AuthCredential type that was used.
const credential = error.credential;
}
},
async fetchUserProfile({ commit }, user) {
const userProfile = await usersCollection.doc(user.uid).get()
const userProfile = await usersCollection.doc(user.uid).get();
if (!userProfile.exists) {
usersCollection.doc(user.uid).set({
username: user.displayName,
email: user.email
})
email: user.email,
});
}
commit('setUserProfile', userProfile.data())
commit('setUserProfile', userProfile.data());
commit('setAuthenticated', true);
router.push('/')
commit('setAuthLoading', false);
router.push('/');
},
async signOut({ commit }) {
async logout({ commit }) {
try {
const result = await auth.signOut()
const result = await auth.signOut();
commit('setAuthenticated', false);
} catch (error) {
const errorCode = error.code;
const errorMessage = error.message;
}
}
},
},
modules: {},
});
19 changes: 19 additions & 0 deletions src/utils/parsers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { GithubRepoIndentifier } from './types';

const Parsers = {
parseRepoLink(link: string): GithubRepoIndentifier | null {
const url = new URL(link);

if (url.host != 'github.com') return null;
else {
const split = url.pathname.split('/');
const repo: GithubRepoIndentifier = {
owner: split[1],
repo: split[2],
};
return repo;
}
},
};

export default Parsers;
Loading