From da2b6adab78027d4862eaa40721f3b88db2e2ca0 Mon Sep 17 00:00:00 2001 From: Vaibhav91one Date: Mon, 30 Oct 2023 13:17:28 +0530 Subject: [PATCH 1/3] doc: implemented Appwrite auth functionalities with Vuejs --- .../docs/tutorials/vue/step-1/+page.markdoc | 33 +- .../docs/tutorials/vue/step-2/+page.markdoc | 43 ++- .../docs/tutorials/vue/step-3/+page.markdoc | 40 ++- .../docs/tutorials/vue/step-4/+page.markdoc | 293 ++++++++++++------ .../docs/tutorials/vue/step-5/+page.markdoc | 279 +++++++++++++++-- .../docs/tutorials/vue/step-6/+page.markdoc | 214 +++++++++---- .../docs/tutorials/vue/step-7/+page.markdoc | 134 ++++---- .../docs/tutorials/vue/step-8/+page.markdoc | 15 +- 8 files changed, 770 insertions(+), 281 deletions(-) diff --git a/src/routes/docs/tutorials/vue/step-1/+page.markdoc b/src/routes/docs/tutorials/vue/step-1/+page.markdoc index 6f70bdf3b8..5916831f32 100644 --- a/src/routes/docs/tutorials/vue/step-1/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-1/+page.markdoc @@ -1,33 +1,20 @@ --- layout: tutorial -title: Build an ideas tracker with Vue.js -description: Learn to build an idea tracker app with Appwrite and Vue with authentication, databases and collections, queries, pagination, and file storage. +title: Authentication with Vue +description: Add Authentication to a Vue project using Appwrite. step: 1 -back: /docs +difficulty: beginner +readtime: 20 --- +## Appwrite: The backend you'll never have to build or maintain. -**Idea tracker**: an app to track all the side project ideas that you'll start, but probably never finish. -In this tutorial, you will build Idea tracker with Appwrite and Vue. +Appwrite is a self-hosted backend platform that takes away the stress of building and maintaining a backend. With Appwrite, you can implement authentication, databases, file storage, and real-time events with secure APIs out of the box. -{% only_dark %} -![Create project screen](/images/docs/tutorials/dark/idea-tracker.png) -{% /only_dark %} -{% only_light %} -![Create project screen](/images/docs/tutorials/idea-tracker.png) -{% /only_light %} +This means that you can focus on what you do best: building great Vue apps. You don't have to worry about managing servers, databases, or security. Appwrite takes care of all that for you. Even if you're a beginner, you can get started with Appwrite and Vue in no time. -# Concepts {% #concepts %} -This tutorial will introduce the following concepts: +## Before you start -1. Setting up your first project -2. Authentication -3. Databases and collections -4. Queries and pagination -5. Storage +Even if you've never tried Appwrite, you will get an idea of what it'll feel like to build with Vue and Appwrite. - -# Prerequisites {% #prerequisites %} - -1. Basic knowledge of JavaScript and Vue. -2. Have [Node.js](https://nodejs.org/en) and [NPM](https://www.npmjs.com/) installed on your computer. \ No newline at end of file +If you're inspired and wish to follow along, make sure you've followed [Start with Vue](https://appwrite.io/docs/quick-starts/vue) first and can later jump onto this tutorial. diff --git a/src/routes/docs/tutorials/vue/step-2/+page.markdoc b/src/routes/docs/tutorials/vue/step-2/+page.markdoc index 271f139c9d..64a56f5271 100644 --- a/src/routes/docs/tutorials/vue/step-2/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-2/+page.markdoc @@ -1,28 +1,51 @@ --- layout: tutorial -title: Create app -description: Create and app with Appwrite Cloud and Vue.js. +title: Create project +description: Add Authentication to a Vue project using Appwrite. step: 2 --- -# Create Vue project {% #create-vue-project %} -Create a Vue app with the `npm create` command. +You can create a Vue project using [Vue](https://vuejs.org/guide/quick-start.html). ```sh -npm create vite@latest --template vue ideas-tracker && cd ideas-tracker +npm create vue@latest ``` -# Add dependencies {% #add-dependencies %} +This command will install and execute [create-vue](https://github.com/vuejs/create-vue), the official Vue project scaffolding tool. You will be presented with prompts for several optional features such as TypeScript and testing support: -Install the JavaScript Appwrite SDK. +The prompt will be something similar to this. ```sh -npm install appwrite +✔ Project name: … +✔ Add TypeScript? … No / Yes +✔ Add JSX Support? … No / Yes +✔ Add Vue Router for Single Page Application development? … No / Yes +✔ Add Pinia for state management? … No / Yes +✔ Add Vitest for Unit testing? … No / Yes +✔ Add an End-to-End Testing Solution? … No / Cypress / Playwright +✔ Add ESLint for code quality? … No / Yes +✔ Add Prettier for code formatting? … No / Yes + +Scaffolding project in ./... +Done. +``` +For this project we will be using Vue router and Pinia. So, make sure to check **yes** for these. + +After the prompt is finished, you can head over to the newly create project. + +```sh + cd vue_appwrite + npm install + npm run dev ``` -You can start the development server to watch your app update in the browser as you make changes. +After running all these commands, you will be able to access you Vue app. + +## Adding Appwrite to Your Vue App + +Appwrite provides a Web SDK that can be used in your Vue apps. You can use Appwrite by installing the Web SDK as an NPM package. ```sh -npm run dev -- --open --port 3000 +npm install appwrite ``` \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue/step-3/+page.markdoc b/src/routes/docs/tutorials/vue/step-3/+page.markdoc index 66f4c2c3ca..7c88c127c8 100644 --- a/src/routes/docs/tutorials/vue/step-3/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-3/+page.markdoc @@ -31,7 +31,7 @@ You can skip optional steps. # Initialize Appwrite SDK {% #init-sdk %} -To use Appwrite in our Svelte app, we'll need to find our project ID. Find your project's ID in the **Settings** page. +To use Appwrite in our Vue app, we'll need to find our project ID. Find your project's ID in the **Settings** page. {% only_dark %} ![Project settings screen](/images/docs/quick-starts/dark/project-id.png) @@ -39,18 +39,38 @@ To use Appwrite in our Svelte app, we'll need to find our project ID. Find your {% only_light %} ![Project settings screen](/images/docs/quick-starts/project-id.png) {% /only_light %} -Create a new file `src/appwrite.js` to hold our Appwrite related code. +Create a new file `src/lib/appwrite.js` to hold our Appwrite related code. Only one instance of the `Client()` class should be created per app. Add the following code to it, replacing `` with your project ID. +Before you can use Appwrite, you need to instanciate the Appwrite `Client` class with the project ID and endpoint. +This tells the SDK where your Appwrite project is hosted and which one to connect to. + +The client is then used to initialize services like `Databases` and `Account`, so they all point to the same Appwrite project. + +You can do this by instantiating the services you need in a file like `src/lib/appwrite.js` and **exporting the instances**. + ```js -import { Client, Databases, Account } from "appwrite"; + import { Databases, Account, Client } from "appwrite"; + + const client = new Client(); + client + .setEndpoint(PUBLIC_APPWRITE_ENDPOINT) + .setProject(PUBLIC_APPWRITE_PROJECT); + + export const account = new Account(client); + export const databases = new Databases(client); +``` +For ease of building, we are using our `Endpoint` and `Project key` directly, but this is not advised when working with production code. + +For better security, we should use environment variables like +`VITE_PUBLIC_APPWRITE_ENDPOINT` and `VITE_PUBLIC_APPWRITE_PROJECT` are environment variables that are exported in your project's [.env file](https://cli.vuejs.org/guide/mode-and-env.html#environment-variables). -const client = new Client(); -client - .setEndpoint("https://cloud.appwrite.io/v1") - .setProject(""); // Replace with your project ID +For example, your `.env` might look something similar to this. -export const account = new Account(client); -export const databases = new Databases(client); -``` \ No newline at end of file +```text +VITE_PUBLIC_APPWRITE_ENDPOINT= +VITE_PUBLIC_APPWRITE_PROJECT= +``` +The env file must be placed in the project root. `VITE_` must be added in front of the environment variables in order for vite to identify them. +You can get the values for these variables from the Appwrite console's **Settings** page. \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue/step-4/+page.markdoc b/src/routes/docs/tutorials/vue/step-4/+page.markdoc index ea0941f10f..cc92e484a3 100644 --- a/src/routes/docs/tutorials/vue/step-4/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-4/+page.markdoc @@ -1,145 +1,238 @@ --- layout: tutorial -title: Add authentication -description: Add authentication to your Vue application using Appwrite Web SDK. +title: Set up Store, Navigation bar and routes +description: Setting up a pinia store, a navigation bar for ease of navigation and routes using vue-router step: 4 --- -# User store {% #user-store %} +# Auth store {% #auth-store %} -In Vue, you can use the [reactive](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#reactive) API to share data between components. -We'll create a store to share the user's data between components. +Since, we chose pinia for state management during the installatin process.So, we have already setuped our store. -Create a new file `src/lib/stores/user.js` and add the following code to it. +Now, We just need to declare state(data that user will have), actions (fetching of information for appwrite). We will discuss about these as we go. ```js -import { ID } from "appwrite"; -import { account } from "../appwrite"; -import { reactive } from "vue"; - -export const user = reactive({ - current: null, - async init() { - try { - this.current = await account.get(); - } catch (e) { - this.current = null; +import { defineStore } from 'pinia'; +import { ID } from 'appwrite'; +import { account } from '../lib/appwrite.js'; + +export const useAuthenticationStore = defineStore('auth', { + state: () => ({ + email: '', + password: '', + name: '', + user: {}, + isAuthenticated: false, + isVerified: false, + }), + actions: { + async login() { + const loginResponse = await account.createEmailSession(this.email, this.password); + this.isAuthenticated = true; + }, + async logout() { + await account.deleteSession("current"); + this.user = null; + this.isAuthenticated = false; + }, + async register() { + const registerResponse = await account.create(ID.unique(), this.email, this.password, this.name); + alert("Account Created and verification send") + this.user = registerResponse; + }, + async getUser() { + this.user = await account.get(); + this.isVerified = this.user.emailVerification; + }, + async verifyUser(){ + const verfication = await account.createVerification('http://localhost:5174/verify') + }, + async confirmVerification(id, secret){ + const confirResponse = await account.updateVerification(id, secret) + }, + async UpdatePassword(email){ + const update = await account.createRecovery(email, 'http://localhost:5174/forgot') + }, + async UpdatePasswordConfirm(id,secret, password, passwordAgain){ + const confirResponse = await account.updateRecovery(id, secret, password, passwordAgain) } }, - async register(email, password) { - await account.create(ID.unique(), email, password); - await this.login(email, password); - }, - async login(email, password) { - await account.createEmailSession(email, password); - window.location.href = "/"; // Redirect to home page - }, - async logout() { - await account.deleteSession("current"); - this.current = null; - }, }); - ``` +Now, we can import the `auth` store in any component and use it to login, logout, verify user, recover password or register a user. -Now, we can import the `user` store in any component and use it to login, logout, or register a user. However, we'll need to call the `init` method to initialize the user's data. - -# Basic routing {% #basic-routing %} +Here, we have declared all the actions that we will require in order to achieve the following things: +- `Log in` +- `Register up` +- `Logout` +- `Get user data` +- `Verify user` +- `Password Recovery` -First, import the `user` store in `src/App.vue` and call the `init` method when the component is mounted. +We will be going through each of them as we move forward in the tutorial. -Update `src/App.vue` to the following code. +# Basic Navigation {% #basic-navigation %} -```vue - +In `src/components` create a file called `Navbar.vue`, we will be using this in `src/App.vue` for ease of navigation. +```html ``` +Above we are using Use the `isAuthenticated` computed property to conditionally render the Dashboard and Login/Register route links. We also have a `logout` button which utilizes the `logout action` in the auth store. -You can use the [Vue Router](https://router.vuejs.org/) to handle routing in your app. However, we'll keep it simple for now. -Optionally render a `Login` component if the path is `/login`, otherwise render the `Home` component. +We maintain the `isAuthenticated` state in our store to enable navigation guards. -Update `src/App.vue` to the following code. +```js + +``` +In the script we are using `authenticationStore` and using `isAuthenticated` state. -```vue - - +``` +```html ``` - - # Home page {% #home-page %} -Create a new file `src/pages/Home.vue` and add the following stub code to it. +`src/views` folder will contain all the pages that we will have in our app. + +Create a new file `src/views/Home.vue` and add the following code to it. -```vue +```html ``` -# Login page {% #login-page %} +In the above code we have some introduction and a link to `/login` route where our login form is present. -Finally, we are able to create the login page. Users will be able to login or register from this page, so we'll need to add two buttons. +# Routes {% #Routes %} -Create a new file `src/pages/Login.vue` and add the following code to it. +Last setup, we require is to setup the routes using the `vue-router`. The routes `index.js` file is present in `src/router` folder. -```vue - +```js +import { createRouter, createWebHistory } from 'vue-router' +import {useAuthenticationStore} from '@/stores/auth.js'; +import HomeView from '../views/HomeView.vue' +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView, + }, + { + path: '/Dashboard', + name: 'dashboard', + component: () => import('../views/dashboard.vue'), + meta: { + requiresAuth: true, + }, + }, + { + path: '/verify', + name: 'verify', + component: () => import('../views/verify.vue'), + }, + { + path: '/login', + name: 'login', + component: () => import('../views/LoginRegister.vue'), + }, + { + path: '/forgot', + name: 'forgot', + component: () => import('../views/forgotPassword.vue'), + }, + { + path: '/:pathMatch(.*)*', + component: HomeView, + }, + ] +}) + +router.beforeEach((to, from, next) => { + const authenticationStore = useAuthenticationStore(); + + if (to.meta.requiresAuth && !authenticationStore.isAuthenticated) { + next('/'); + } else { + next(); + } +}); - +export default router ``` +The code above is a `Vue Router` configuration that defines the routes for your application and a navigation guard that prevents users from accessing protected routes if they are not authenticated. + +We will be having the following routes: + +- `home`: This is the home page of your application. It is accessible to all users. +- `dashboard`: This is a protected route that is only accessible to authenticated users. +- `verify`: This route is used to verify the user's email address. +- `login`: This route is used to log the user in, registering and password recovery. +- `forgot`: This route is used to reset the user's password. +- `/:pathMatch(.*)*`: This is a catch-all route that matches any URL that does not match another route. It redirects the user to the home page. diff --git a/src/routes/docs/tutorials/vue/step-5/+page.markdoc b/src/routes/docs/tutorials/vue/step-5/+page.markdoc index 9d70878590..77d047fc37 100644 --- a/src/routes/docs/tutorials/vue/step-5/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-5/+page.markdoc @@ -1,46 +1,271 @@ --- layout: tutorial -title: Add navigation +title: Basic Authentication description: Add navigation to your Vue.js app with Appwrite authentication and pinia stores. step: 5 --- -In our app we want to have a navigation bar that is always visible. Use the `user` store to show either: -- a logout button if the user is logged in. -- a login button if the user is not logged in. +# Login page {% #login-page %} -Update the App componenent in `src/App.vue`: +Finally, we are going to create our login page. Users will be able to login, register or recover their password from this page. -```vue +Create a new file `src/views/LoginRegister.vue` and add the following code to it. + +```html + +``` + +```js +``` -const isLoginPage = window.location.pathname === "/login"; +The above code is just a view/page in which we are importing the `login` component, the main login logic is written in the `login` component that we will be creating in the `src/components` folder. -onMounted(() => { - user.init(); -}); +Now, lets create our login component. Create a file `src/components/Login.vue` and the following code to it. + +```js + +``` +Here is a short overview of what the above code is doing: +- Importing the pinia `useAuthenticationStore()` and the useRouter() hook. +- Creating a data section and define the following variables: `email`, `password`, and `name`. +- Creating a setup section and define the following methods: `login()`, `register()`, and `sendPasswordRecoveryMail()`. +- In the `beforeMount()` lifecycle hook, check if the user is already authenticated. If the user is authenticated, redirect the user to the home. +- In the `login()` method, call the `login() action` from the auth store and also we are using `getUser()` action that gets user data from appwrite and fills the user object. +- In the `register()` method, call the `register() action` from the auth store. +- In the `sendPasswordRecoveryMail()` method, call the `UpdatePassword() action` from the auth store. + +```html +``` + +In the above code we are doing the following things: + +- Creating three variables: `isLogin`, `forgotPassword`, and `email`. +- Seting the `isLogin` variable to `false` and the `forgotPassword` variable to `false`. +- Writing three methods: `login()`, `register()`, and `sendPasswordRecoveryMail()`. These methods will be called when the user submits the corresponding form. +- Creating a Vue.js template with three sections: login, register, and forgot password. +- Using the `v-if` directive to conditionally render each section of the page. +- Using the `@submit.prevent` directive to prevent the default form submission behavior and call the corresponding method instead. + +Once you have completed these steps, you will have a basic Vue.js login, register, and forgot password form. Now, let's discuss the login, register, logout actions in deep. + +## Login action + +```js +async login() { + const loginResponse = await account.createEmailSession(this.email, this.password); + this.isAuthenticated = true; + } +``` + +To login to our app, we use `createEmailSession` function which appwrite provides this checks if the user is registered to the platform. +if user is registered, the user will be redirected to the `dashboard page` which will contain the user info, else the console will give the error invalid credentials. + + +The login action takes inputs such as email and password of the user. + +## Register action + +```js +async register() { + const registerResponse = await account.create(ID.unique(), this.email, this.password, this.name); + alert("Account Created") + } +``` + +To register to our app, we use `create` function which appwrite provides, this creates a user in our appwrite console. Now, user can login to the app with the credentials, the user entered during registration. + + +The register action takes inputs such as email, password and the name of the user. + +## Logout Action + +We can find the logout button in the navbar once the user is logged in. + +```js + await account.deleteSession("current"); + this.user = null; + this.isAuthenticated = false; +``` +we can logout the user using `deleteSession` and providing 'current' as the session ID to logout on this device. Also, this action makes the state of the user null. + +## getUser Action + +Using this action, we can fill the user state object with the user data which we will get via appwrite. + +```js + async getUser() { + this.user = await account.get(); + this.isVerified = this.user.emailVerification; + }, +``` +The above action fills our user state object with the user data we are getting via appwrite and also, assigns `isVerified` boolean state with `emailVerification` user data which is also boolean. + +# Dashboard page {% #Dashboard-page %} + +Now, we want to create our dashboard view/page which will show all the user information. Let's create a file `src/views/dashboard.vue` and add the following code to it. + +```js + +``` +In the above code we are doing the following things: + +- Importing the `useAuthenticationStore()`, `storeToRefs()`, and `computed` functions from Vue.js and the pinia library. +- Creating a variable called `authenticationStore` and assign it the result of calling the useAuthenticationStore() function. +- Creating a computed property called `isAuthenticated` that returns the value of the `isAuthenticated` property in the authentication store. +- Creating a computed property called `isVerified` that returns the value of the `isVerified` property in the authentication store. +- Creating a reactive reference to the `user` object in the authentication store by calling the `storeToRefs()` function and passing in the `authenticationStore` variable. +- Creating a method called `userDelete()` that calls the `DeleteUser()` method on the authentication store. +- Creating a method called `userVerify()` that calls the `verifyUser()` method on the authentication store. + + +```html + ``` +Here is what is happening in the above code: + +- The template first checks the value of the `isAuthenticated` computed property. If the user is authenticated, the template displays the "You are Logged In ✅" heading. Otherwise, the template displays the "You are Logged Out ❌" heading. +- If the user is authenticated, the template displays the user's name, email address, and ID. +- If the user is not verified and authenticated, the template displays the "Verify Account" button. +- If the user is verified and authenticated, the template displays the "Verified" button. +- If the user is authenticated, the template displays the "Delete Account" button. + +In the next step, we will be discussing about the **user verification** and **password recovery** functionality. \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue/step-6/+page.markdoc b/src/routes/docs/tutorials/vue/step-6/+page.markdoc index a646b24068..e268c376ac 100644 --- a/src/routes/docs/tutorials/vue/step-6/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-6/+page.markdoc @@ -1,64 +1,174 @@ --- layout: tutorial -title: Add database -description: Add data storage to your Vue.js project powered by Appwrite Cloud databases. +title: Password Recovery and User verification +description: This page deals with password recovery and user verification with Vue and Appwrite. step: 6 --- -# Create collection {% #create-collection %} -In Appwrite, data is stored as a collection of documents. Create a collection in the [Appwrite Console](https://cloud.appwrite.io/) to store our ideas. +# Password Recovery {% #Password-recovery %} -{% only_dark %} -![Create project screen](/images/docs/tutorials/dark/idea-tracker-collection.png) -{% /only_dark %} -{% only_light %} -![Create project screen](/images/docs/tutorials/idea-tracker-collection.png) -{% /only_light %} +Appwrite also provides us the functionality of recovering our password. We have already implemented our forgot password functionality in our `login page`, which will take the user email and Sends the user an email with a temporary secret key for password reset. -Create a new collection with the following attributes: -| Field | Type | Required | -|-------------|--------|----------| -| userId | String | Yes | -| title | String | Yes | -| description | String | No | +When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. -# Ideas context {% #ideas-context %} +## UpdatePassword action -Now that you have a collection to hold ideas, we can read and write to it from our app. Like we did with the user data, we will create a store hold our ideas. -Create a new file `src/lib/stores/ideas.js` and add the following code to it. +```js + async UpdatePassword(email){ + const update = await account.createRecovery(email, 'http://localhost:5174/forgot') + }, +``` + +The `UpdatePassword` action takes up the user email and a path for where the user will enter the new password. + +So, we have create a page, where we will take the query string params and the new password. Then, user can submit a request to update the password. + +**NOTE: The verification link sent to the user's email address is valid for 1 hour.** + +Now, let's create a new view/page `src/views/forgotPassword.vue` and copy the below code to it. + +```js + +``` +In the above script we are doing the following things: + +- Importing the `ref`, `computed`, `useRoute()`, `useRouter()`, and `useAuthenticationStore()` hooks from Vue.js. +- Creating a variable called `password` and initialize it with a ref. +- Creating a variable called `passwordAgain` and initialize it with a ref. +- Creating a method called `PasswordVerificationConfirm()`. This method should check if the `userID` and `secret` are present in the route query parameters. If they are, then the method should call the `UpdatePasswordConfirm()` method on the authentication store to update the user's password. + +```html + +``` +In the above code we are just taking password of the user and also we are confirming the password. Then, we are using the `PasswordVerificationConfirm` method to call `UpdatePasswordConfirm` action to submit a password update request to appwrite. + +## UpdatePasswordConfirm action + +```js +async UpdatePasswordConfirm(id,secret, password, passwordAgain){ + const confirResponse = await account.updateRecovery(id, secret, password, passwordAgain) + } +``` + +In the above `updateRecovery` request, we are sending the `userId`, `secret`, `password` and `passwordAgain` for updating the user password. + + +# User Verfication {% #user-verification %} + +It is a good practice to verify whether a user is authentic or not. Appwrite provides us a way to verify the user using different methods such as + +- Phone verification +- email verification + +In this tutorial we are using email verification. + +## createVerification action + +This action uses `createVerification` method provided by appwrite to send a verification email to the user. The parameter that this method requires is a page where the user will be redirected to from the mail where the user can be verified. + +```js + async verifyUser(){ + const verfication = await account.createVerification('http://localhost:5174/verify') + }, +``` + +So, we have create a page, where we will verify the user. Then, user can submit a request to verify using `updateVerification` action. + +Now, let's create a new view/page `src/views/verify.vue` and copy the below code to it. + +```js + +``` +In the above script we are doing the following things: + +- Storing the `userId` and `secret` query parameters from query string present in the URL. +- Then, using `verificationConfirm` function to first check if `userID` and `secret` are present in the URL, then only use the `confirmVerification` action from the store to send a verified request to appwrite. +- After verification the user will be redirected to the `home page`. +- If the user if successfully verified, the dashboard will show `verified`, else it will show `verify user` + + +```html + +``` +In the above code we have a verify button which will trigger the `verificationConfirm` method and based on the `verificationDone` state the above text will be rendered. + +## confirmVerification action ```js -import { ID, Query } from "appwrite"; -import { databases } from "../appwrite"; -import { reactive } from "vue"; - -export const IDEAS_DATABASE_ID = ""; // Replace with your database ID -export const IDEAS_COLLECTION_ID = ""; // Replace with your collection ID - -export const ideas = reactive({ - current: [], - async init() { - const response = await databases.listDocuments( - IDEAS_DATABASE_ID, - IDEAS_COLLECTION_ID, - [Query.orderDesc("$createdAt"), Query.limit(10)] - ); - this.current = response.documents; - }, - async add(idea) { - const response = await databases.createDocument( - IDEAS_DATABASE_ID, - IDEAS_COLLECTION_ID, - ID.unique(), - idea - ); - this.current = [response, ...this.current].slice(0, 10); - }, - async remove(id) { - await databases.deleteDocument(IDEAS_DATABASE_ID, IDEAS_COLLECTION_ID, id); - this.current = this.current.filter((idea) => idea.$id !== id); - await this.init(); // Refetch ideas to ensure we have 10 items - }, -}); + async confirmVerification(id, secret){ + const confirResponse = await account.updateVerification(id, secret) + }, ``` +The above action uses the `updateVerification` method which appwrite provides to send a verified request to the appwrite. This method takes two parameters `userId` and `secret` that is present in the query string from the URL we got in the email. -Note the init function, which uses `Query` to fetch the last 10 ideas from the database. We will call this function when the app starts to ensure we have some data to display. diff --git a/src/routes/docs/tutorials/vue/step-7/+page.markdoc b/src/routes/docs/tutorials/vue/step-7/+page.markdoc index b85a4bf2ec..0a5c6d466f 100644 --- a/src/routes/docs/tutorials/vue/step-7/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-7/+page.markdoc @@ -1,72 +1,90 @@ --- layout: tutorial -title: Create ideas page -description: Add data queries and pagination to your Vue.js project powered by Appwrite Cloud databases. +title: Protected routes +description: In this step we discuss about how routes are protected from being accessed when the user is not yet authenticated. step: 7 --- -Using the `ideas` store we can now display the ideas on the page. We will also add a form to submit new ideas. +Route protection is a powerful feature of the Vue Router that allows you to restrict access to certain routes based on the user's authentication status. This can help you to create more secure and user-friendly applications. -Overwrite the contents of `src/pages/Home.vue` with the following: +Let's visit the `index.js` file present in `src/router` to better understand how route protection is done. -```vue - +``` + +A simple step by step explanatin what we are doing is the following: + +- To protect a route, add the `requiresAuth` meta property to it. +- The `router.beforeEach` global navigation guard is called before every navigation. +- The `router.beforeEach` guard checks if the target route requires authentication and the user is not authenticated. +- If the target route requires authentication and the user is not authenticated, the navigation is canceled and the user is - redirected to the home page. +- Otherwise, the navigation is allowed to continue. - -``` \ No newline at end of file +```js + beforeMount(){ + const authenticationStore = useAuthenticationStore(); + const router = useRouter(); + if(authenticationStore.isAuthenticated){ + router.push({path: '/'}) + } + }, +``` +The above code just checks if the user is authenticated and is accessing `login` and `forgot` routes then, the user will be redirected to home page. Also, we have to use this lifecyle hook in both pages. \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue/step-8/+page.markdoc b/src/routes/docs/tutorials/vue/step-8/+page.markdoc index ecf970551b..ae0624c270 100644 --- a/src/routes/docs/tutorials/vue/step-8/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-8/+page.markdoc @@ -6,4 +6,17 @@ step: 8 --- # Test your project {% #test-project %} -Run your project with `npm run dev -- --open --port 3000` and open [http://localhost:3000](http://localhost:3000) in your browser. +Run your project with `npm run dev` and open the URL that comes up on the terminal. + + +# Play with your project {% #play-project %} + +Try to implement `validations` to input, make use of `phone verification`. + +# Use Appwrite{% #make-project %} + +Use appwrite in your projects and explore other amazing features that appwrite provides such as + +- Databases +- Functions +- Storage \ No newline at end of file From f8f30bd7300e9125509e5ba329c490daa020a054 Mon Sep 17 00:00:00 2001 From: Vaibhav91one Date: Tue, 31 Oct 2023 14:13:00 +0530 Subject: [PATCH 2/3] Problem solved + Build done --- .../docs/tutorials/vue-auth/+layout.svelte | 10 + src/routes/docs/tutorials/vue-auth/+layout.ts | 11 + src/routes/docs/tutorials/vue-auth/+page.ts | 6 + .../tutorials/vue-auth/step-1/+page.markdoc | 20 ++ .../tutorials/vue-auth/step-2/+page.markdoc | 51 +++ .../tutorials/vue-auth/step-3/+page.markdoc | 76 +++++ .../tutorials/vue-auth/step-4/+page.markdoc | 184 +++++++++++ .../tutorials/vue-auth/step-5/+page.markdoc | 271 ++++++++++++++++ .../tutorials/vue-auth/step-6/+page.markdoc | 174 +++++++++++ .../tutorials/vue-auth/step-7/+page.markdoc | 33 ++ .../tutorials/vue-auth/step-8/+page.markdoc | 22 ++ .../docs/tutorials/vue/step-1/+page.markdoc | 33 +- .../docs/tutorials/vue/step-2/+page.markdoc | 43 +-- .../docs/tutorials/vue/step-3/+page.markdoc | 40 +-- .../docs/tutorials/vue/step-4/+page.markdoc | 293 ++++++------------ .../docs/tutorials/vue/step-5/+page.markdoc | 279 ++--------------- .../docs/tutorials/vue/step-6/+page.markdoc | 214 ++++--------- .../docs/tutorials/vue/step-7/+page.markdoc | 134 ++++---- .../docs/tutorials/vue/step-8/+page.markdoc | 15 +- 19 files changed, 1139 insertions(+), 770 deletions(-) create mode 100644 src/routes/docs/tutorials/vue-auth/+layout.svelte create mode 100644 src/routes/docs/tutorials/vue-auth/+layout.ts create mode 100644 src/routes/docs/tutorials/vue-auth/+page.ts create mode 100644 src/routes/docs/tutorials/vue-auth/step-1/+page.markdoc create mode 100644 src/routes/docs/tutorials/vue-auth/step-2/+page.markdoc create mode 100644 src/routes/docs/tutorials/vue-auth/step-3/+page.markdoc create mode 100644 src/routes/docs/tutorials/vue-auth/step-4/+page.markdoc create mode 100644 src/routes/docs/tutorials/vue-auth/step-5/+page.markdoc create mode 100644 src/routes/docs/tutorials/vue-auth/step-6/+page.markdoc create mode 100644 src/routes/docs/tutorials/vue-auth/step-7/+page.markdoc create mode 100644 src/routes/docs/tutorials/vue-auth/step-8/+page.markdoc diff --git a/src/routes/docs/tutorials/vue-auth/+layout.svelte b/src/routes/docs/tutorials/vue-auth/+layout.svelte new file mode 100644 index 0000000000..fb9fb3980f --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/+layout.svelte @@ -0,0 +1,10 @@ + + + diff --git a/src/routes/docs/tutorials/vue-auth/+layout.ts b/src/routes/docs/tutorials/vue-auth/+layout.ts new file mode 100644 index 0000000000..562b11506f --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/+layout.ts @@ -0,0 +1,11 @@ +import type { LayoutLoad } from './$types'; + +export const load: LayoutLoad = ({ url }) => { + const tutorials = import.meta.glob('./**/*.markdoc', { + eager: true + }); + return { + tutorials, + pathname: url.pathname + }; +}; diff --git a/src/routes/docs/tutorials/vue-auth/+page.ts b/src/routes/docs/tutorials/vue-auth/+page.ts new file mode 100644 index 0000000000..027e659825 --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/+page.ts @@ -0,0 +1,6 @@ +import { redirect } from '@sveltejs/kit'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async () => { + throw redirect(303, '/docs/tutorials/vue-auth/step-1'); +}; diff --git a/src/routes/docs/tutorials/vue-auth/step-1/+page.markdoc b/src/routes/docs/tutorials/vue-auth/step-1/+page.markdoc new file mode 100644 index 0000000000..8c8fcac633 --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/step-1/+page.markdoc @@ -0,0 +1,20 @@ +--- +layout: tutorial +title: Authentication with Vue +description: Add Authentication to a Vue project using Appwrite. +step: 1 +difficulty: medium +readtime: 40 +--- +## Appwrite: The backend you'll never have to build or maintain. + +Appwrite is a self-hosted backend platform that takes away the stress of building and maintaining a backend. With Appwrite, you can implement authentication, databases, file storage, and real-time events with secure APIs out of the box. + +This means that you can focus on what you do best: building great Vue apps. You don't have to worry about managing servers, databases, or security. Appwrite takes care of all that for you. Even if you're a beginner, you can get started with Appwrite and Vue in no time. + + +## Before you start + +Even if you've never tried Appwrite, you will get an idea of what it'll feel like to build with Vue and Appwrite. + +If you're inspired and wish to follow along, make sure you've followed [Start with Vue](https://appwrite.io/docs/quick-starts/vue) first and can later jump onto this tutorial. diff --git a/src/routes/docs/tutorials/vue-auth/step-2/+page.markdoc b/src/routes/docs/tutorials/vue-auth/step-2/+page.markdoc new file mode 100644 index 0000000000..64a56f5271 --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/step-2/+page.markdoc @@ -0,0 +1,51 @@ +--- +layout: tutorial +title: Create project +description: Add Authentication to a Vue project using Appwrite. +step: 2 +--- + + +You can create a Vue project using [Vue](https://vuejs.org/guide/quick-start.html). + +```sh +npm create vue@latest +``` + +This command will install and execute [create-vue](https://github.com/vuejs/create-vue), the official Vue project scaffolding tool. You will be presented with prompts for several optional features such as TypeScript and testing support: + +The prompt will be something similar to this. + +```sh +✔ Project name: … +✔ Add TypeScript? … No / Yes +✔ Add JSX Support? … No / Yes +✔ Add Vue Router for Single Page Application development? … No / Yes +✔ Add Pinia for state management? … No / Yes +✔ Add Vitest for Unit testing? … No / Yes +✔ Add an End-to-End Testing Solution? … No / Cypress / Playwright +✔ Add ESLint for code quality? … No / Yes +✔ Add Prettier for code formatting? … No / Yes + +Scaffolding project in ./... +Done. +``` +For this project we will be using Vue router and Pinia. So, make sure to check **yes** for these. + +After the prompt is finished, you can head over to the newly create project. + +```sh + cd vue_appwrite + npm install + npm run dev +``` + +After running all these commands, you will be able to access you Vue app. + +## Adding Appwrite to Your Vue App + +Appwrite provides a Web SDK that can be used in your Vue apps. You can use Appwrite by installing the Web SDK as an NPM package. + +```sh +npm install appwrite +``` \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue-auth/step-3/+page.markdoc b/src/routes/docs/tutorials/vue-auth/step-3/+page.markdoc new file mode 100644 index 0000000000..7c88c127c8 --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/step-3/+page.markdoc @@ -0,0 +1,76 @@ +--- +layout: tutorial +title: Set up Appwrite +description: Import and configure a project with Appwrite Cloud and Vue.js. +step: 3 +--- + +# Create project {% #create-project %} + +Head to the [Appwrite Console](https://cloud.appwrite.io/console). + +{% only_dark %} +![Create project screen](/images/docs/quick-starts/dark/create-project.png) +{% /only_dark %} +{% only_light %} +![Create project screen](/images/docs/quick-starts/create-project.png) +{% /only_light %} + +If this is your first time using Appwrite, create an account and create your first project. + +Then, under **Add a platform**, add a **Web app**. The **Hostname** should be localhost. + +{% only_dark %} +![Add a platform](/images/docs/quick-starts/dark/add-platform.png) +{% /only_dark %} +{% only_light %} +![Add a platform](/images/docs/quick-starts/add-platform.png) +{% /only_light %} + +You can skip optional steps. + +# Initialize Appwrite SDK {% #init-sdk %} + +To use Appwrite in our Vue app, we'll need to find our project ID. Find your project's ID in the **Settings** page. + +{% only_dark %} +![Project settings screen](/images/docs/quick-starts/dark/project-id.png) +{% /only_dark %} +{% only_light %} +![Project settings screen](/images/docs/quick-starts/project-id.png) +{% /only_light %} +Create a new file `src/lib/appwrite.js` to hold our Appwrite related code. +Only one instance of the `Client()` class should be created per app. +Add the following code to it, replacing `` with your project ID. + +Before you can use Appwrite, you need to instanciate the Appwrite `Client` class with the project ID and endpoint. +This tells the SDK where your Appwrite project is hosted and which one to connect to. + +The client is then used to initialize services like `Databases` and `Account`, so they all point to the same Appwrite project. + +You can do this by instantiating the services you need in a file like `src/lib/appwrite.js` and **exporting the instances**. + +```js + import { Databases, Account, Client } from "appwrite"; + + const client = new Client(); + client + .setEndpoint(PUBLIC_APPWRITE_ENDPOINT) + .setProject(PUBLIC_APPWRITE_PROJECT); + + export const account = new Account(client); + export const databases = new Databases(client); +``` +For ease of building, we are using our `Endpoint` and `Project key` directly, but this is not advised when working with production code. + +For better security, we should use environment variables like +`VITE_PUBLIC_APPWRITE_ENDPOINT` and `VITE_PUBLIC_APPWRITE_PROJECT` are environment variables that are exported in your project's [.env file](https://cli.vuejs.org/guide/mode-and-env.html#environment-variables). + +For example, your `.env` might look something similar to this. + +```text +VITE_PUBLIC_APPWRITE_ENDPOINT= +VITE_PUBLIC_APPWRITE_PROJECT= +``` +The env file must be placed in the project root. `VITE_` must be added in front of the environment variables in order for vite to identify them. +You can get the values for these variables from the Appwrite console's **Settings** page. \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue-auth/step-4/+page.markdoc b/src/routes/docs/tutorials/vue-auth/step-4/+page.markdoc new file mode 100644 index 0000000000..994dc34051 --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/step-4/+page.markdoc @@ -0,0 +1,184 @@ +--- +layout: tutorial +title: Set up Store, Navigation bar and routes +description: Setting up a pinia store, a navigation bar for ease of navigation and routes using vue-router +step: 4 +--- + +# Auth store {% #auth-store %} + +Since, we chose pinia for state management during the installatin process.So, we have already setuped our store. + +Now, We just need to declare state(data that user will have), actions (fetching of information for appwrite). We will discuss about these as we go. + +```js +import { defineStore } from 'pinia'; +import { ID } from 'appwrite'; +import { account } from '../lib/appwrite.js'; + +export const useAuthenticationStore = defineStore('auth', { + state: () => ({ + email: '', + password: '', + name: '', + user: {}, + isAuthenticated: false, + isVerified: false, + }), + actions: { + async login() { + const loginResponse = await account.createEmailSession(this.email, this.password); + this.isAuthenticated = true; + }, + async logout() { + await account.deleteSession("current"); + this.user = null; + this.isAuthenticated = false; + }, + async register() { + const registerResponse = await account.create(ID.unique(), this.email, this.password, this.name); + alert("Account Created and verification send") + this.user = registerResponse; + }, + async getUser() { + this.user = await account.get(); + this.isVerified = this.user.emailVerification; + }, + async verifyUser(){ + const verfication = await account.createVerification('http://localhost:5174/verify') + }, + async confirmVerification(id, secret){ + const confirResponse = await account.updateVerification(id, secret) + }, + async UpdatePassword(email){ + const update = await account.createRecovery(email, 'http://localhost:5174/forgot') + }, + async UpdatePasswordConfirm(id,secret, password, passwordAgain){ + const confirResponse = await account.updateRecovery(id, secret, password, passwordAgain) + } + }, +}); +``` +Now, we can import the `auth` store in any component and use it to login, logout, verify user, recover password or register a user. + +Here, we have declared all the actions that we will require in order to achieve the following things: +- `Log in` +- `Register up` +- `Logout` +- `Get user data` +- `Verify user` +- `Password Recovery` + +We will be going through each of them as we move forward in the tutorial. + +# Basic Navigation {% #basic-navigation %} + +In `src/components` create a file called `Navbar.vue`, we will be using this in `src/App.vue` for ease of navigation. + +```html + +``` +Above we are using Use the `isAuthenticated` computed property to conditionally render the Dashboard and Login/Register route links. We also have a `logout` button which utilizes the `logout action` in the auth store. + +We maintain the `isAuthenticated` state in our store to enable navigation guards. + +```js + +``` +In the script we are using `authenticationStore` and using `isAuthenticated` state. + +Also, we have a logout function that will be visible only if user is logged in. This logout function is calling the `logout action` declared in our store, which will logout our user from the app. + +Below is how our `src/App.vue` will look. We have a navbar and `RouterView` which renders our views/pages. + +```js + +``` +```html + +``` + +# Home page {% #home-page %} + +`src/views` folder will contain all the pages that we will have in our app. + +Create a new file `src/views/Home.vue` and add the following code to it. + +```html + +``` + +In the above code we have some introduction and a link to `/login` route where our login form is present. + +# Routes {% #Routes %} + +Last setup, we require is to setup the routes using the `vue-router`. The routes `index.js` file is present in `src/router` folder. + +Now, add the code from this [index.js](https://gist.github.com/Vaibhav91one/02a2bc139625b985cc597c9fb0e7156e) file. + +The code above is a `Vue Router` configuration that defines the routes for your application and a navigation guard that prevents users from accessing protected routes if they are not authenticated. + +We will be having the following routes: + +- `home`: This is the home page of your application. It is accessible to all users. +- `dashboard`: This is a protected route that is only accessible to authenticated users. +- `verify`: This route is used to verify the user's email address. +- `login`: This route is used to log the user in, registering and password recovery. +- `forgot`: This route is used to reset the user's password. +- `/:pathMatch(.*)*`: This is a catch-all route that matches any URL that does not match another route. It redirects the user to the home page. + diff --git a/src/routes/docs/tutorials/vue-auth/step-5/+page.markdoc b/src/routes/docs/tutorials/vue-auth/step-5/+page.markdoc new file mode 100644 index 0000000000..77d047fc37 --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/step-5/+page.markdoc @@ -0,0 +1,271 @@ +--- +layout: tutorial +title: Basic Authentication +description: Add navigation to your Vue.js app with Appwrite authentication and pinia stores. +step: 5 +--- + +# Login page {% #login-page %} + +Finally, we are going to create our login page. Users will be able to login, register or recover their password from this page. + +Create a new file `src/views/LoginRegister.vue` and add the following code to it. + +```html + +``` + +```js + +``` + +The above code is just a view/page in which we are importing the `login` component, the main login logic is written in the `login` component that we will be creating in the `src/components` folder. + +Now, lets create our login component. Create a file `src/components/Login.vue` and the following code to it. + +```js + +``` +Here is a short overview of what the above code is doing: +- Importing the pinia `useAuthenticationStore()` and the useRouter() hook. +- Creating a data section and define the following variables: `email`, `password`, and `name`. +- Creating a setup section and define the following methods: `login()`, `register()`, and `sendPasswordRecoveryMail()`. +- In the `beforeMount()` lifecycle hook, check if the user is already authenticated. If the user is authenticated, redirect the user to the home. +- In the `login()` method, call the `login() action` from the auth store and also we are using `getUser()` action that gets user data from appwrite and fills the user object. +- In the `register()` method, call the `register() action` from the auth store. +- In the `sendPasswordRecoveryMail()` method, call the `UpdatePassword() action` from the auth store. + + +```html + +``` + +In the above code we are doing the following things: + +- Creating three variables: `isLogin`, `forgotPassword`, and `email`. +- Seting the `isLogin` variable to `false` and the `forgotPassword` variable to `false`. +- Writing three methods: `login()`, `register()`, and `sendPasswordRecoveryMail()`. These methods will be called when the user submits the corresponding form. +- Creating a Vue.js template with three sections: login, register, and forgot password. +- Using the `v-if` directive to conditionally render each section of the page. +- Using the `@submit.prevent` directive to prevent the default form submission behavior and call the corresponding method instead. + +Once you have completed these steps, you will have a basic Vue.js login, register, and forgot password form. Now, let's discuss the login, register, logout actions in deep. + +## Login action + +```js +async login() { + const loginResponse = await account.createEmailSession(this.email, this.password); + this.isAuthenticated = true; + } +``` + +To login to our app, we use `createEmailSession` function which appwrite provides this checks if the user is registered to the platform. +if user is registered, the user will be redirected to the `dashboard page` which will contain the user info, else the console will give the error invalid credentials. + + +The login action takes inputs such as email and password of the user. + +## Register action + +```js +async register() { + const registerResponse = await account.create(ID.unique(), this.email, this.password, this.name); + alert("Account Created") + } +``` + +To register to our app, we use `create` function which appwrite provides, this creates a user in our appwrite console. Now, user can login to the app with the credentials, the user entered during registration. + + +The register action takes inputs such as email, password and the name of the user. + +## Logout Action + +We can find the logout button in the navbar once the user is logged in. + +```js + await account.deleteSession("current"); + this.user = null; + this.isAuthenticated = false; +``` +we can logout the user using `deleteSession` and providing 'current' as the session ID to logout on this device. Also, this action makes the state of the user null. + +## getUser Action + +Using this action, we can fill the user state object with the user data which we will get via appwrite. + +```js + async getUser() { + this.user = await account.get(); + this.isVerified = this.user.emailVerification; + }, +``` +The above action fills our user state object with the user data we are getting via appwrite and also, assigns `isVerified` boolean state with `emailVerification` user data which is also boolean. + +# Dashboard page {% #Dashboard-page %} + +Now, we want to create our dashboard view/page which will show all the user information. Let's create a file `src/views/dashboard.vue` and add the following code to it. + +```js + +``` +In the above code we are doing the following things: + +- Importing the `useAuthenticationStore()`, `storeToRefs()`, and `computed` functions from Vue.js and the pinia library. +- Creating a variable called `authenticationStore` and assign it the result of calling the useAuthenticationStore() function. +- Creating a computed property called `isAuthenticated` that returns the value of the `isAuthenticated` property in the authentication store. +- Creating a computed property called `isVerified` that returns the value of the `isVerified` property in the authentication store. +- Creating a reactive reference to the `user` object in the authentication store by calling the `storeToRefs()` function and passing in the `authenticationStore` variable. +- Creating a method called `userDelete()` that calls the `DeleteUser()` method on the authentication store. +- Creating a method called `userVerify()` that calls the `verifyUser()` method on the authentication store. + + +```html + +``` +Here is what is happening in the above code: + +- The template first checks the value of the `isAuthenticated` computed property. If the user is authenticated, the template displays the "You are Logged In ✅" heading. Otherwise, the template displays the "You are Logged Out ❌" heading. +- If the user is authenticated, the template displays the user's name, email address, and ID. +- If the user is not verified and authenticated, the template displays the "Verify Account" button. +- If the user is verified and authenticated, the template displays the "Verified" button. +- If the user is authenticated, the template displays the "Delete Account" button. + +In the next step, we will be discussing about the **user verification** and **password recovery** functionality. \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue-auth/step-6/+page.markdoc b/src/routes/docs/tutorials/vue-auth/step-6/+page.markdoc new file mode 100644 index 0000000000..e268c376ac --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/step-6/+page.markdoc @@ -0,0 +1,174 @@ +--- +layout: tutorial +title: Password Recovery and User verification +description: This page deals with password recovery and user verification with Vue and Appwrite. +step: 6 +--- +# Password Recovery {% #Password-recovery %} + +Appwrite also provides us the functionality of recovering our password. We have already implemented our forgot password functionality in our `login page`, which will take the user email and Sends the user an email with a temporary secret key for password reset. + +When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. + +## UpdatePassword action + +```js + async UpdatePassword(email){ + const update = await account.createRecovery(email, 'http://localhost:5174/forgot') + }, +``` + +The `UpdatePassword` action takes up the user email and a path for where the user will enter the new password. + +So, we have create a page, where we will take the query string params and the new password. Then, user can submit a request to update the password. + +**NOTE: The verification link sent to the user's email address is valid for 1 hour.** + +Now, let's create a new view/page `src/views/forgotPassword.vue` and copy the below code to it. + +```js + +``` +In the above script we are doing the following things: + +- Importing the `ref`, `computed`, `useRoute()`, `useRouter()`, and `useAuthenticationStore()` hooks from Vue.js. +- Creating a variable called `password` and initialize it with a ref. +- Creating a variable called `passwordAgain` and initialize it with a ref. +- Creating a method called `PasswordVerificationConfirm()`. This method should check if the `userID` and `secret` are present in the route query parameters. If they are, then the method should call the `UpdatePasswordConfirm()` method on the authentication store to update the user's password. + +```html + +``` +In the above code we are just taking password of the user and also we are confirming the password. Then, we are using the `PasswordVerificationConfirm` method to call `UpdatePasswordConfirm` action to submit a password update request to appwrite. + +## UpdatePasswordConfirm action + +```js +async UpdatePasswordConfirm(id,secret, password, passwordAgain){ + const confirResponse = await account.updateRecovery(id, secret, password, passwordAgain) + } +``` + +In the above `updateRecovery` request, we are sending the `userId`, `secret`, `password` and `passwordAgain` for updating the user password. + + +# User Verfication {% #user-verification %} + +It is a good practice to verify whether a user is authentic or not. Appwrite provides us a way to verify the user using different methods such as + +- Phone verification +- email verification + +In this tutorial we are using email verification. + +## createVerification action + +This action uses `createVerification` method provided by appwrite to send a verification email to the user. The parameter that this method requires is a page where the user will be redirected to from the mail where the user can be verified. + +```js + async verifyUser(){ + const verfication = await account.createVerification('http://localhost:5174/verify') + }, +``` + +So, we have create a page, where we will verify the user. Then, user can submit a request to verify using `updateVerification` action. + +Now, let's create a new view/page `src/views/verify.vue` and copy the below code to it. + +```js + +``` +In the above script we are doing the following things: + +- Storing the `userId` and `secret` query parameters from query string present in the URL. +- Then, using `verificationConfirm` function to first check if `userID` and `secret` are present in the URL, then only use the `confirmVerification` action from the store to send a verified request to appwrite. +- After verification the user will be redirected to the `home page`. +- If the user if successfully verified, the dashboard will show `verified`, else it will show `verify user` + + +```html + +``` +In the above code we have a verify button which will trigger the `verificationConfirm` method and based on the `verificationDone` state the above text will be rendered. + +## confirmVerification action + +```js + async confirmVerification(id, secret){ + const confirResponse = await account.updateVerification(id, secret) + }, +``` +The above action uses the `updateVerification` method which appwrite provides to send a verified request to the appwrite. This method takes two parameters `userId` and `secret` that is present in the query string from the URL we got in the email. + diff --git a/src/routes/docs/tutorials/vue-auth/step-7/+page.markdoc b/src/routes/docs/tutorials/vue-auth/step-7/+page.markdoc new file mode 100644 index 0000000000..576f528285 --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/step-7/+page.markdoc @@ -0,0 +1,33 @@ +--- +layout: tutorial +title: Protected routes +description: In this step we discuss about how routes are protected from being accessed when the user is not yet authenticated. +step: 7 +--- + +Route protection is a powerful feature of the Vue Router that allows you to restrict access to certain routes based on the user's authentication status. This can help you to create more secure and user-friendly applications. + +Let's visit the [index.js](https://gist.github.com/Vaibhav91one/02a2bc139625b985cc597c9fb0e7156e) file present in `src/router` to better understand how route protection is done. + +A simple step by step explanatin what we are doing is the following: + +- To protect a route, add the `requiresAuth` meta property to it. +- The `router.beforeEach` global navigation guard is called before every navigation. +- The `router.beforeEach` guard checks if the target route requires authentication and the user is not authenticated. +- If the target route requires authentication and the user is not authenticated, the navigation is canceled and the user is - redirected to the home page. +- Otherwise, the navigation is allowed to continue. + +We also want to restritct access to pages such as `login` and `forgot` when the user is logged in. To acheive that we are using `beforeMount` lifecycle hook. + +## beforeMount lifecycle hook + +```js + beforeMount(){ + const authenticationStore = useAuthenticationStore(); + const router = useRouter(); + if(authenticationStore.isAuthenticated){ + router.push({path: '/'}) + } + }, +``` +The above code just checks if the user is authenticated and is accessing `login` and `forgot` routes then, the user will be redirected to home page. Also, we have to use this lifecyle hook in both pages. \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue-auth/step-8/+page.markdoc b/src/routes/docs/tutorials/vue-auth/step-8/+page.markdoc new file mode 100644 index 0000000000..ae0624c270 --- /dev/null +++ b/src/routes/docs/tutorials/vue-auth/step-8/+page.markdoc @@ -0,0 +1,22 @@ +--- +layout: tutorial +title: Next steps +description: View your Vue.js app build on Appwrite Cloud. +step: 8 +--- + +# Test your project {% #test-project %} +Run your project with `npm run dev` and open the URL that comes up on the terminal. + + +# Play with your project {% #play-project %} + +Try to implement `validations` to input, make use of `phone verification`. + +# Use Appwrite{% #make-project %} + +Use appwrite in your projects and explore other amazing features that appwrite provides such as + +- Databases +- Functions +- Storage \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue/step-1/+page.markdoc b/src/routes/docs/tutorials/vue/step-1/+page.markdoc index 5916831f32..6f70bdf3b8 100644 --- a/src/routes/docs/tutorials/vue/step-1/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-1/+page.markdoc @@ -1,20 +1,33 @@ --- layout: tutorial -title: Authentication with Vue -description: Add Authentication to a Vue project using Appwrite. +title: Build an ideas tracker with Vue.js +description: Learn to build an idea tracker app with Appwrite and Vue with authentication, databases and collections, queries, pagination, and file storage. step: 1 -difficulty: beginner -readtime: 20 +back: /docs --- -## Appwrite: The backend you'll never have to build or maintain. -Appwrite is a self-hosted backend platform that takes away the stress of building and maintaining a backend. With Appwrite, you can implement authentication, databases, file storage, and real-time events with secure APIs out of the box. +**Idea tracker**: an app to track all the side project ideas that you'll start, but probably never finish. +In this tutorial, you will build Idea tracker with Appwrite and Vue. -This means that you can focus on what you do best: building great Vue apps. You don't have to worry about managing servers, databases, or security. Appwrite takes care of all that for you. Even if you're a beginner, you can get started with Appwrite and Vue in no time. +{% only_dark %} +![Create project screen](/images/docs/tutorials/dark/idea-tracker.png) +{% /only_dark %} +{% only_light %} +![Create project screen](/images/docs/tutorials/idea-tracker.png) +{% /only_light %} +# Concepts {% #concepts %} -## Before you start +This tutorial will introduce the following concepts: -Even if you've never tried Appwrite, you will get an idea of what it'll feel like to build with Vue and Appwrite. +1. Setting up your first project +2. Authentication +3. Databases and collections +4. Queries and pagination +5. Storage -If you're inspired and wish to follow along, make sure you've followed [Start with Vue](https://appwrite.io/docs/quick-starts/vue) first and can later jump onto this tutorial. + +# Prerequisites {% #prerequisites %} + +1. Basic knowledge of JavaScript and Vue. +2. Have [Node.js](https://nodejs.org/en) and [NPM](https://www.npmjs.com/) installed on your computer. \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue/step-2/+page.markdoc b/src/routes/docs/tutorials/vue/step-2/+page.markdoc index 64a56f5271..271f139c9d 100644 --- a/src/routes/docs/tutorials/vue/step-2/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-2/+page.markdoc @@ -1,51 +1,28 @@ --- layout: tutorial -title: Create project -description: Add Authentication to a Vue project using Appwrite. +title: Create app +description: Create and app with Appwrite Cloud and Vue.js. step: 2 --- +# Create Vue project {% #create-vue-project %} -You can create a Vue project using [Vue](https://vuejs.org/guide/quick-start.html). +Create a Vue app with the `npm create` command. ```sh -npm create vue@latest +npm create vite@latest --template vue ideas-tracker && cd ideas-tracker ``` -This command will install and execute [create-vue](https://github.com/vuejs/create-vue), the official Vue project scaffolding tool. You will be presented with prompts for several optional features such as TypeScript and testing support: +# Add dependencies {% #add-dependencies %} -The prompt will be something similar to this. +Install the JavaScript Appwrite SDK. ```sh -✔ Project name: … -✔ Add TypeScript? … No / Yes -✔ Add JSX Support? … No / Yes -✔ Add Vue Router for Single Page Application development? … No / Yes -✔ Add Pinia for state management? … No / Yes -✔ Add Vitest for Unit testing? … No / Yes -✔ Add an End-to-End Testing Solution? … No / Cypress / Playwright -✔ Add ESLint for code quality? … No / Yes -✔ Add Prettier for code formatting? … No / Yes - -Scaffolding project in ./... -Done. -``` -For this project we will be using Vue router and Pinia. So, make sure to check **yes** for these. - -After the prompt is finished, you can head over to the newly create project. - -```sh - cd vue_appwrite - npm install - npm run dev +npm install appwrite ``` -After running all these commands, you will be able to access you Vue app. - -## Adding Appwrite to Your Vue App - -Appwrite provides a Web SDK that can be used in your Vue apps. You can use Appwrite by installing the Web SDK as an NPM package. +You can start the development server to watch your app update in the browser as you make changes. ```sh -npm install appwrite +npm run dev -- --open --port 3000 ``` \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue/step-3/+page.markdoc b/src/routes/docs/tutorials/vue/step-3/+page.markdoc index 7c88c127c8..66f4c2c3ca 100644 --- a/src/routes/docs/tutorials/vue/step-3/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-3/+page.markdoc @@ -31,7 +31,7 @@ You can skip optional steps. # Initialize Appwrite SDK {% #init-sdk %} -To use Appwrite in our Vue app, we'll need to find our project ID. Find your project's ID in the **Settings** page. +To use Appwrite in our Svelte app, we'll need to find our project ID. Find your project's ID in the **Settings** page. {% only_dark %} ![Project settings screen](/images/docs/quick-starts/dark/project-id.png) @@ -39,38 +39,18 @@ To use Appwrite in our Vue app, we'll need to find our project ID. Find your pro {% only_light %} ![Project settings screen](/images/docs/quick-starts/project-id.png) {% /only_light %} -Create a new file `src/lib/appwrite.js` to hold our Appwrite related code. +Create a new file `src/appwrite.js` to hold our Appwrite related code. Only one instance of the `Client()` class should be created per app. Add the following code to it, replacing `` with your project ID. -Before you can use Appwrite, you need to instanciate the Appwrite `Client` class with the project ID and endpoint. -This tells the SDK where your Appwrite project is hosted and which one to connect to. - -The client is then used to initialize services like `Databases` and `Account`, so they all point to the same Appwrite project. - -You can do this by instantiating the services you need in a file like `src/lib/appwrite.js` and **exporting the instances**. - ```js - import { Databases, Account, Client } from "appwrite"; - - const client = new Client(); - client - .setEndpoint(PUBLIC_APPWRITE_ENDPOINT) - .setProject(PUBLIC_APPWRITE_PROJECT); - - export const account = new Account(client); - export const databases = new Databases(client); -``` -For ease of building, we are using our `Endpoint` and `Project key` directly, but this is not advised when working with production code. - -For better security, we should use environment variables like -`VITE_PUBLIC_APPWRITE_ENDPOINT` and `VITE_PUBLIC_APPWRITE_PROJECT` are environment variables that are exported in your project's [.env file](https://cli.vuejs.org/guide/mode-and-env.html#environment-variables). +import { Client, Databases, Account } from "appwrite"; -For example, your `.env` might look something similar to this. +const client = new Client(); +client + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject(""); // Replace with your project ID -```text -VITE_PUBLIC_APPWRITE_ENDPOINT= -VITE_PUBLIC_APPWRITE_PROJECT= -``` -The env file must be placed in the project root. `VITE_` must be added in front of the environment variables in order for vite to identify them. -You can get the values for these variables from the Appwrite console's **Settings** page. \ No newline at end of file +export const account = new Account(client); +export const databases = new Databases(client); +``` \ No newline at end of file diff --git a/src/routes/docs/tutorials/vue/step-4/+page.markdoc b/src/routes/docs/tutorials/vue/step-4/+page.markdoc index cc92e484a3..ea0941f10f 100644 --- a/src/routes/docs/tutorials/vue/step-4/+page.markdoc +++ b/src/routes/docs/tutorials/vue/step-4/+page.markdoc @@ -1,238 +1,145 @@ --- layout: tutorial -title: Set up Store, Navigation bar and routes -description: Setting up a pinia store, a navigation bar for ease of navigation and routes using vue-router +title: Add authentication +description: Add authentication to your Vue application using Appwrite Web SDK. step: 4 --- -# Auth store {% #auth-store %} +# User store {% #user-store %} -Since, we chose pinia for state management during the installatin process.So, we have already setuped our store. +In Vue, you can use the [reactive](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#reactive) API to share data between components. +We'll create a store to share the user's data between components. -Now, We just need to declare state(data that user will have), actions (fetching of information for appwrite). We will discuss about these as we go. +Create a new file `src/lib/stores/user.js` and add the following code to it. ```js -import { defineStore } from 'pinia'; -import { ID } from 'appwrite'; -import { account } from '../lib/appwrite.js'; - -export const useAuthenticationStore = defineStore('auth', { - state: () => ({ - email: '', - password: '', - name: '', - user: {}, - isAuthenticated: false, - isVerified: false, - }), - actions: { - async login() { - const loginResponse = await account.createEmailSession(this.email, this.password); - this.isAuthenticated = true; - }, - async logout() { - await account.deleteSession("current"); - this.user = null; - this.isAuthenticated = false; - }, - async register() { - const registerResponse = await account.create(ID.unique(), this.email, this.password, this.name); - alert("Account Created and verification send") - this.user = registerResponse; - }, - async getUser() { - this.user = await account.get(); - this.isVerified = this.user.emailVerification; - }, - async verifyUser(){ - const verfication = await account.createVerification('http://localhost:5174/verify') - }, - async confirmVerification(id, secret){ - const confirResponse = await account.updateVerification(id, secret) - }, - async UpdatePassword(email){ - const update = await account.createRecovery(email, 'http://localhost:5174/forgot') - }, - async UpdatePasswordConfirm(id,secret, password, passwordAgain){ - const confirResponse = await account.updateRecovery(id, secret, password, passwordAgain) +import { ID } from "appwrite"; +import { account } from "../appwrite"; +import { reactive } from "vue"; + +export const user = reactive({ + current: null, + async init() { + try { + this.current = await account.get(); + } catch (e) { + this.current = null; } }, + async register(email, password) { + await account.create(ID.unique(), email, password); + await this.login(email, password); + }, + async login(email, password) { + await account.createEmailSession(email, password); + window.location.href = "/"; // Redirect to home page + }, + async logout() { + await account.deleteSession("current"); + this.current = null; + }, }); + ``` -Now, we can import the `auth` store in any component and use it to login, logout, verify user, recover password or register a user. -Here, we have declared all the actions that we will require in order to achieve the following things: -- `Log in` -- `Register up` -- `Logout` -- `Get user data` -- `Verify user` -- `Password Recovery` +Now, we can import the `user` store in any component and use it to login, logout, or register a user. However, we'll need to call the `init` method to initialize the user's data. + +# Basic routing {% #basic-routing %} -We will be going through each of them as we move forward in the tutorial. +First, import the `user` store in `src/App.vue` and call the `init` method when the component is mounted. -# Basic Navigation {% #basic-navigation %} +Update `src/App.vue` to the following code. -In `src/components` create a file called `Navbar.vue`, we will be using this in `src/App.vue` for ease of navigation. +```vue + -```html ``` -Above we are using Use the `isAuthenticated` computed property to conditionally render the Dashboard and Login/Register route links. We also have a `logout` button which utilizes the `logout action` in the auth store. -We maintain the `isAuthenticated` state in our store to enable navigation guards. +You can use the [Vue Router](https://router.vuejs.org/) to handle routing in your app. However, we'll keep it simple for now. +Optionally render a `Login` component if the path is `/login`, otherwise render the `Home` component. -```js - -``` -In the script we are using `authenticationStore` and using `isAuthenticated` state. +Update `src/App.vue` to the following code. -Also, we have a logout function that will be visible only if user is logged in. This logout function is calling the `logout action` declared in our store, which will logout our user from the app. +```vue + -``` -```html + ``` -# Home page {% #home-page %} -`src/views` folder will contain all the pages that we will have in our app. -Create a new file `src/views/Home.vue` and add the following code to it. +# Home page {% #home-page %} -```html -