├── .gitignore
├── README.md
├── babel.config.js
├── firestoreRules.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
└── src
├── App.vue
├── assets
├── logo.png
├── logo.svg
└── main.scss
├── components
└── Landing.vue
├── firebase
└── index.js
├── main.js
├── plugins
└── vuetify.js
├── routes
└── index.js
├── store
└── store.js
└── views
├── About.vue
├── Home.vue
├── Profile.vue
├── SignIn.vue
├── SignOut.vue
└── SignUp.vue
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-auth-bolierplate
2 |
3 |
4 | ## Firebase / Firestore Setup
5 | go to
6 | ```
7 | http://firebase.coogle.com
8 | ```
9 | 1. Under the Authentication tab - select email/password and click the activate switch.
10 | - create a user and set a field in that user
11 | ```
12 | Name: isAdmin
13 | Type: boolean
14 | Value: true
15 | ```
16 | This will be your admin user. You can add more admin users if you like.
17 |
18 | 2. Under the database tab - Create a Cloud Firestore database
19 | 3. Under Storage tab - enable storage.
20 | 4. At the top of the main menu find "Project Settings" & click on the gear to the right. At the bottom of the next screen in "Your Apps" select "Web App" and replace the code in src/firebase/index.js with the setting shown.
21 |
22 | You should then be good to go.
23 |
24 | ## Project setup
25 | ```
26 | npm install
27 | ```
28 |
29 | ### Compiles and hot-reloads for development
30 | ```
31 | npm run serve
32 | ```
33 |
34 | ### Compiles and minifies for production
35 | ```
36 | npm run build
37 | ```
38 |
39 | ### Run your tests
40 | ```
41 | npm run test
42 | ```
43 |
44 | ### Lints and fixes files
45 | ```
46 | npm run lint
47 | ```
48 |
49 | ### Customize configuration
50 | See [Configuration Reference](https://cli.vuejs.org/config/).
51 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/firestoreRules.md:
--------------------------------------------------------------------------------
1 | Is admin
2 | QWBhjkJqE6VHpZTNSdYdm1AmJXF3
3 |
4 | IS normal
5 | mULPAmagVnN00HhtW8G0M6qMrYY2
6 |
7 |
8 |
9 |
10 | match /user/{document} {
11 | allow read: if getRole('subscriber') == true;
12 | allow update: if getRole('editor') == true;
13 | allow create, delete: if getRole('admin') == true;
14 | }
15 | // Allow the user to read data if the document has the 'visibility'
16 | // field set to 'public'
17 | match /cities/{city} {
18 | allow read: if resource.data.visibility == 'public';
19 | }
20 |
21 |
22 |
23 |
24 |
25 | match /user/{document} {
26 | allow read: if isAdmin('admin') == true;
27 | allow update: if getRole('editor') == true;
28 | allow create, delete: if getRole('admin') == true;
29 | }
30 |
31 | // Check if current user is admin
32 | function isAdmin(isAdmin) {
33 | return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin[isAdmin]
34 | // check with --> if isAdmin('admin') == true;
35 | }
36 |
37 | // Check if current user is level
38 | function getLevel(userLevel) {
39 | return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.userLevel[userLevel]
40 | // check with -->
41 | // if getLevel('free') == true;
42 | // if getLevel('personal') == true;
43 | // if getLevel('business') == true;
44 | // if getLevel('godLike') == true;
45 | }
46 |
47 | // check if user owns profile
48 |
49 |
50 | // Check is user is creator of document
51 | function isOwner(createdBy) {
52 | return get(/databases/$(database)/documents/dashboard/{document}).data.createdBy[$(request.auth.uid)]
53 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-auth-bolierplate",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "@firebase/firestore": "^0.9.3",
12 | "axios": "^0.18.0",
13 | "firebase": "^5.7.3",
14 | "node-sass": "^4.11.0",
15 | "sass-loader": "^7.1.0",
16 | "vue": "^2.5.21",
17 | "vue-router": "^3.0.1",
18 | "vuetify": "^1.4.1",
19 | "vuex": "^3.0.1",
20 | "vuex-router-sync": "^5.0.0"
21 | },
22 | "devDependencies": {
23 | "@vue/cli-plugin-babel": "^3.3.0",
24 | "@vue/cli-plugin-eslint": "^3.3.0",
25 | "@vue/cli-service": "^3.3.0",
26 | "babel-eslint": "^10.0.1",
27 | "eslint": "^5.8.0",
28 | "eslint-plugin-vue": "^5.0.0",
29 | "stylus": "^0.54.5",
30 | "stylus-loader": "^3.0.1",
31 | "vue-cli-plugin-vuetify": "^0.4.6",
32 | "vue-template-compiler": "^2.5.21",
33 | "vuetify-loader": "^1.0.5"
34 | },
35 | "eslintConfig": {
36 | "root": true,
37 | "env": {
38 | "node": true
39 | },
40 | "extends": [
41 | "plugin:vue/essential",
42 | "eslint:recommended"
43 | ],
44 | "rules": {},
45 | "parserOptions": {
46 | "parser": "babel-eslint"
47 | }
48 | },
49 | "postcss": {
50 | "plugins": {
51 | "autoprefixer": {}
52 | }
53 | },
54 | "browserslist": [
55 | "> 1%",
56 | "last 2 versions",
57 | "not ie <= 8"
58 | ]
59 | }
60 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiaranPearse/Vie-firebase-firestore-auth-storage-database/3983b0c22cc824f19320a427716de94091d9d0e0/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | vue-auth-bolierplate
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | VueAuth
6 |
7 |
8 |
12 | Home
13 |
14 |
19 | Login
20 |
21 |
26 | Sign Up
27 |
28 |
33 | Profile
34 |
35 |
40 | Signout
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
58 |
59 |
64 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CiaranPearse/Vie-firebase-firestore-auth-storage-database/3983b0c22cc824f19320a427716de94091d9d0e0/src/assets/logo.png
--------------------------------------------------------------------------------
/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/main.scss:
--------------------------------------------------------------------------------
1 | #app {
2 | .fingerprint-spinner, .fingerprint-spinner * {
3 | box-sizing: border-box;
4 | }
5 | .fingerprint-spinner {
6 | height: 64px;
7 | width: 64px;
8 | padding: 2px;
9 | overflow: hidden;
10 | position: relative;
11 | margin: 0 auto;
12 | .spinner-ring {
13 | position: absolute;
14 | border-radius: 50%;
15 | border: 2px solid transparent;
16 | border-top-color: #ff1d5e;
17 | animation: fingerprint-spinner-animation 1500ms cubic-bezier(0.680, -0.750, 0.265, 1.750) infinite forwards;
18 | margin: auto;
19 | bottom: 0;
20 | left: 0;
21 | right: 0;
22 | top: 0;
23 | &:nth-child(1) {
24 | height: calc(60px / 9 + 0 * 60px / 9);
25 | width: calc(60px / 9 + 0 * 60px / 9);
26 | animation-delay: calc(50ms * 1);
27 | }
28 | &:nth-child(2) {
29 | height: calc(60px / 9 + 1 * 60px / 9);
30 | width: calc(60px / 9 + 1 * 60px / 9);
31 | animation-delay: calc(50ms * 2);
32 | }
33 | &:nth-child(3) {
34 | height: calc(60px / 9 + 2 * 60px / 9);
35 | width: calc(60px / 9 + 2 * 60px / 9);
36 | animation-delay: calc(50ms * 3);
37 | }
38 | &:nth-child(4) {
39 | height: calc(60px / 9 + 3 * 60px / 9);
40 | width: calc(60px / 9 + 3 * 60px / 9);
41 | animation-delay: calc(50ms * 4);
42 | }
43 | &:nth-child(5) {
44 | height: calc(60px / 9 + 4 * 60px / 9);
45 | width: calc(60px / 9 + 4 * 60px / 9);
46 | animation-delay: calc(50ms * 5);
47 | }
48 | &:nth-child(6) {
49 | height: calc(60px / 9 + 5 * 60px / 9);
50 | width: calc(60px / 9 + 5 * 60px / 9);
51 | animation-delay: calc(50ms * 6);
52 | }
53 | &:nth-child(7) {
54 | height: calc(60px / 9 + 6 * 60px / 9);
55 | width: calc(60px / 9 + 6 * 60px / 9);
56 | animation-delay: calc(50ms * 7);
57 | }
58 | &:nth-child(8) {
59 | height: calc(60px / 9 + 7 * 60px / 9);
60 | width: calc(60px / 9 + 7 * 60px / 9);
61 | animation-delay: calc(50ms * 8);
62 | }
63 | &:nth-child(9) {
64 | height: calc(60px / 9 + 8 * 60px / 9);
65 | width: calc(60px / 9 + 8 * 60px / 9);
66 | animation-delay: calc(50ms * 9);
67 | }
68 | }
69 | }
70 | @keyframes fingerprint-spinner-animation {
71 | 100% {
72 | transform: rotate( 360deg );
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/src/components/Landing.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 | Home Page
9 | Current User is: {{ this.user }}
10 | Current Level is: {{ this.userLevel }}
11 |
12 |
13 |
14 |
15 |
16 |
24 |
25 |
28 |
--------------------------------------------------------------------------------
/src/firebase/index.js:
--------------------------------------------------------------------------------
1 | import store from '@/store/store'
2 | import Firebase from 'firebase'
3 | import 'firebase/firestore'
4 |
5 | const config = {
6 | apiKey: 'YOUR_FIREBASE_API_KAY',
7 | authDomain: 'something.firebaseapp.com',
8 | databaseURL: 'https://something.firebaseio.com',
9 | projectId: 'something',
10 | storageBucket: 'something.appspot.com',
11 | messagingSenderId: 'SOME_NUMBER'
12 | }
13 |
14 | export default {
15 | install: (Vue, options) => {
16 | const firebase = Firebase.initializeApp(config)
17 | const auth = firebase.auth()
18 | Vue.prototype.$auth = {
19 | login: async (username, pass) => {
20 | return await auth.signInWithEmailAndPassword(username, pass)
21 | },
22 | logout: async () => {
23 | await auth.signOut()
24 | }
25 | }
26 | auth.onAuthStateChanged(user => {
27 | store.commit('updateUser',{ user })
28 | store.dispatch('fetchUserData')
29 | })
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import './plugins/vuetify'
3 | import App from './App.vue'
4 | import { sync } from 'vuex-router-sync'
5 | import Vuetify from 'vuetify'
6 | import router from './routes'
7 | import store from './store/store'
8 | import FirebaseAuthPlugin from './firebase/'
9 |
10 | Vue.config.productionTip = false
11 | Vue.use(FirebaseAuthPlugin)
12 | Vue.use(Vuetify)
13 |
14 | sync(store, router)
15 |
16 | new Vue({
17 | router,
18 | store,
19 | render: h => h(App)
20 | }).$mount('#app')
21 |
22 | // const app = new Vue({
23 | // router,
24 | // store,
25 | // ...App
26 | // })
27 |
28 | export { router, store }
29 |
--------------------------------------------------------------------------------
/src/plugins/vuetify.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuetify from 'vuetify/lib'
3 | import 'vuetify/src/stylus/app.styl'
4 |
5 | Vue.use(Vuetify, {
6 | iconfont: 'md',
7 | })
8 |
--------------------------------------------------------------------------------
/src/routes/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import store from '@/store/store'
4 | import Home from '@/views/Home'
5 | import SignIn from '@/views/SignIn'
6 | import SignOut from '@/views/SignOut'
7 | import SignUp from '@/views/SignUp'
8 | import Profile from '@/views/Profile'
9 |
10 | Vue.use(Router)
11 |
12 | const router = new Router({
13 | mode: 'history',
14 | routes: [
15 | {
16 | path: '/',
17 | name: 'home',
18 | component: Home
19 | },
20 | {
21 | path: '/signin',
22 | name: 'signin',
23 | component: SignIn
24 | },
25 | {
26 | path: '/signout',
27 | name: 'signout',
28 | component: SignOut
29 | },
30 | {
31 | path: '/signup',
32 | name: 'signup',
33 | component: SignUp
34 | },
35 | {
36 | path: '/profile',
37 | name: 'profile',
38 | component: Profile,
39 | meta: {
40 | authRequired: true
41 | }
42 | }
43 | ]
44 | })
45 |
46 | router.beforeEach((to, from, next) => {
47 | if (to.matched.some(record => record.meta.authRequired)) {
48 | if (!store.state.user) {
49 | next({
50 | path: '/signin',
51 | query: { redirect: to.fullPath }
52 | })
53 | } else {
54 | next()
55 | }
56 | } else {
57 | next()
58 | }
59 | })
60 |
61 | export default router
62 |
--------------------------------------------------------------------------------
/src/store/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import firebase from 'firebase'
4 | import 'firebase/firestore';
5 | import router from '@/routes'
6 |
7 | Vue.use(Vuex)
8 |
9 | export default new Vuex.Store({
10 | state: {
11 | user: null,
12 | userProfile: null
13 | },
14 | mutations: {
15 | updateUser (state, { user }) {
16 | Vue.set(state, 'user', user)
17 | },
18 | setUser (state, payload) {
19 | state.user = payload
20 | },
21 | setProfile (state, payload) {
22 | state.userProfile = payload
23 | },
24 | setLoading (state, payload) {
25 | state.loading = payload
26 | },
27 | setError (state, payload) {
28 | state.error = payload
29 | },
30 | clearError (state) {
31 | state.error = null
32 | }
33 | },
34 | getters: {
35 | user (state) {
36 | return state.user
37 | },
38 | userProfile (state) {
39 | return state.userProfile
40 | }
41 | },
42 | computed: {
43 | },
44 | actions: {
45 | signUserUp ({commit}, payload) {
46 | firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
47 | .then(
48 | user => {
49 | const newUser = {
50 | id: user.user.uid
51 | }
52 | commit('setUser', newUser)
53 | }
54 | )
55 | .then(
56 | // eslint-disable-next-line
57 | user => {
58 | const dateNow = new Date()
59 | firebase.firestore().collection("users").doc(this.state.user.id).set({
60 | userLevel: 'free',
61 | joinDate: dateNow.toISOString(),
62 | isAdmin: false
63 | })
64 | }
65 | )
66 | .then(
67 | router.push('/profile')
68 | )
69 | .catch(function(error) {
70 | commit('setError', error)
71 | })
72 | },
73 | signUserOut ({commit}) {
74 | commit('setProfile', null)
75 | },
76 | fetchUserData ({commit, getters}) {
77 | let currentUser = this.state.user.uid
78 | commit('setLoading', true)
79 | var docRef = firebase.firestore().collection('/users').doc(currentUser)
80 | docRef.get().then(function(doc) {
81 | if (doc.exists) {
82 | commit('setProfile', doc.data())
83 | } else {
84 | this.state.usersProfile = null
85 | }
86 | })
87 | .catch(
88 | error => {
89 | commit('setLoading', false)
90 | commit('setError', error)
91 | }
92 | )
93 | },
94 | updateUserData ({commit}, payload) {
95 | commit('setLoading', true)
96 | const updateUserObj = {}
97 | let filename
98 | let ext
99 | console.log('PAYLOAD', payload)
100 | if (payload.firstName) {
101 | updateUserObj.firstName = payload.firstName
102 | }
103 | if (payload.lastName) {
104 | updateUserObj.lastName = payload.lastName
105 | }
106 | if (payload.avatar) {
107 | updateUserObj.avatar = payload.avatar
108 | }
109 | if (payload.currency) {
110 | updateUserObj.currency = payload.currency
111 | }
112 | if (payload.location) {
113 | updateUserObj.location = payload.location
114 | }
115 | if (payload.timeZone) {
116 | updateUserObj.timeZone = payload.timeZone
117 | }
118 | if (payload.longitude) {
119 | updateUserObj.longitude = payload.longitude
120 | }
121 | if (payload.latitude) {
122 | updateUserObj.latitude = payload.latitude
123 | }
124 | if (payload.language) {
125 | updateUserObj.language = payload.language
126 | }
127 | if (payload.updated) {
128 | updateUserObj.updated = payload.updated
129 | }
130 | if (payload.image) {
131 | filename = payload.image.name
132 | ext = filename.slice(filename.lastIndexOf('.'))
133 | updateUserObj.imageExt = ext
134 | }
135 |
136 | let imageUrl
137 | let key = firebase.auth().currentUser.uid
138 | let userRef = firebase.firestore().collection('users').doc(firebase.auth().currentUser.uid)
139 | let setWithMerge = userRef.set({
140 | ...updateUserObj
141 | }, { merge: true })
142 | .then(() => {
143 | return firebase.storage().ref('users/' + key + ext).put(payload.image)
144 | })
145 | .then(() => {
146 | commit('setLoading', false)
147 | console.log('This is the push of the USER payload', payload)
148 | // commit('updateUser', payload)
149 | })
150 | .catch(error => {
151 | console.log(error)
152 | commit('setLoading', false)
153 | })
154 | console.log('at the end of the loop')
155 | }
156 | }
157 | })
158 |
--------------------------------------------------------------------------------
/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
--------------------------------------------------------------------------------
/src/views/Profile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
Profile Admin?: {{ this.isAdmin }}
20 |
26 |
27 |
28 |
29 | {{ this.userId }} | {{ this.userLevel }}
30 | {{ this.userEmail }}
31 | {{ this.firstName }} {{ this.lastName}}
32 | Joined: {{ this.joined }}
33 | Updated: {{ this.updated }}
34 | Edit Profile
35 |
36 |
37 | Edit stuff here
38 |
70 |
71 |
72 |
Only show to Admin
73 |
{{ userProfile.isAdmin }}
74 |
75 |
76 |
77 |
78 |
79 |
80 |
185 |
--------------------------------------------------------------------------------
/src/views/SignIn.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
84 |
85 |
--------------------------------------------------------------------------------
/src/views/SignOut.vue:
--------------------------------------------------------------------------------
1 |
2 | Logged out
3 |
4 |
13 |
--------------------------------------------------------------------------------
/src/views/SignUp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
84 |
85 |
--------------------------------------------------------------------------------