diff --git a/src/partials/account-vs-user.md b/src/partials/account-vs-user.md new file mode 100644 index 0000000000..638d806300 --- /dev/null +++ b/src/partials/account-vs-user.md @@ -0,0 +1,21 @@ + +{% info title="Account vs Users API" %} +Appwrite provides two APIs to manager user accounts. + +The Account API is the API you should use in your **client applications** like web, Flutter, mobile, and native apps. +Account API creates sessions, which represent an authenticated user and is attached to a user's [account](/docs/products/auth/account). +Sessions respect [permissions](/docs/advanced/platform/permissions), which means users can only access resources if they have been granted the correct permissions. + +You'll notice that the Account API doesn't allow you to view or make changes to other users. +This is by design and for **security reasons**. + +[Account API references](/docs/references/cloud/client-web/account) + +The Users API is a dedicated API for managing users from an admin's perspective. **Do not use the Users API on client applications**. +It should be used with backend or server-side applications with the [Server SDK](#). + +Users API uses API keys instead of sessions. +This means they're not resticted by permissions, but by the scopes granted to the API key used. + +[Users API references](/docs/references/cloud/server-nodejs/users) +{% /info %} \ No newline at end of file diff --git a/src/routes/docs/advanced/platform/webhooks/+page.markdoc b/src/routes/docs/advanced/platform/webhooks/+page.markdoc index b5c80e23ca..56bed361da 100644 --- a/src/routes/docs/advanced/platform/webhooks/+page.markdoc +++ b/src/routes/docs/advanced/platform/webhooks/+page.markdoc @@ -4,17 +4,6 @@ title: Webhooks description: Placeholder SEO. --- -Certainly! Below is the content converted to Markdown format: - -```md -```php -getParam('events', []); - -?> -``` - Webhooks allow you to build or set up integrations which subscribe to certain events on Appwrite. When one of those events is triggered, we'll send an HTTP POST payload to the webhook's configured URL. Webhooks can be used to purge cache from CDN, calculate data or send a Slack notification. You're only limited by your imagination. ## Add your webhook {% #addWebhook %} diff --git a/src/routes/docs/advanced/self-hosting/functions/+page.markdoc b/src/routes/docs/advanced/self-hosting/functions/+page.markdoc index 94de2be9ec..4dd9324697 100644 --- a/src/routes/docs/advanced/self-hosting/functions/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/functions/+page.markdoc @@ -79,8 +79,6 @@ Check the **Any account** box under **Where can this GitHub App be installed?** After creating your app, you'll have to configure the following environment variables. -Markdown doesn't natively support tables with complex markup like HTML does. However, you can create simple tables with Markdown. Here's a basic conversion of your table to Markdown: - | Variable | Description | |------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `_APP_DOMAIN` | Your main Appwrite domain used to access the Appwrite Console. When setting a public suffix domain, Appwrite will attempt to issue a valid SSL certificate automatically. When used with a dev domain, Appwrite will assign a self-signed SSL certificate. If you're using a proxy for **localhost development**, such as [ngrok](https://ngrok.com/), this will be the domain of your localhost proxy. | diff --git a/src/routes/docs/apis/graphql/+page.markdoc b/src/routes/docs/apis/graphql/+page.markdoc index 8b788531e2..555deff73c 100644 --- a/src/routes/docs/apis/graphql/+page.markdoc +++ b/src/routes/docs/apis/graphql/+page.markdoc @@ -1,56 +1,45 @@ --- layout: article title: GraphQL -description: -difficulty: beginner -readtime: 10 +description: Description used for SEO --- -Appwrite supports multiple protocols for accessing the server, including [REST](/docs/apis/rest), [GraphQL](/docs/apis/graphql), and [Realtime](/docs/apis/realtime). The GraphQL API allows you to query and mutate any resource type on your Appwrite server through the endpoint `/v1/graphql`. Every endpoint available through REST is available through GraphQL, except for OAuth. +Appwrite supports multiple protocols for accessing the server, including [REST](/docs/rest), [GraphQL](/docs/graphql), and [Realtime](/docs/realtime). + +The GraphQL API allows you to query and mutate any resource type on your Appwrite server through the endpoint `/v1/graphql`. +Every endpoint available through REST is available through GraphQL, except for OAuth. + +## Requests {% #requests %} + +Although every query executes through the same endpoint, there are multiple ways to make a GraphQL request. All requests, however, share a common structure. + +| Name | Type | Description | +|----------------|--------|---------------------------------------------------------------------------| +| query | string | **Required**, the GraphQL query to execute. | +| operationName | string | **Optional**, if the query contains several named operations, controls which one to execute. | +| variables | object | **Optional**, an object containing variable names and values for the query. Variables are made available to your query with the `$` prefix. | + +### GraphQL model parameters {% #graphql-model-parameters %} -{% info title="GraphQL Model Parameters" %} In Appwrite's GraphQL API, all internal model parameters are prefixed with `_` instead of `$` because `$` is reserved by GraphQL. For example, `$collectionId` in the REST API would be referenced as `_collectionId` in the GraphQL API. -{% /info %} -## Requests {% #requests %} -Although every query executes through the same endpoint, there are multiple ways to make a GraphQL request. All requests, however, share a common structure. +### GET requests {% #get-resquest %} -{% table %} -* Name {% width=100 %} -*   {% width=100 %} -* Type {% width=100 %} -* Description ---- -* `query` -* required -* string -* The GraphQL query to execute. ---- -* `operationName` -* optional -* string -* If the query contains several named operations, controls which one to execute. ---- -* `variables` -* optional -* object -* An object containing variable names and values for the query. Variables are made available to your query with the $ prefix. ---- -{% /table %} +You can execute a GraphQL query via a GET request, passing a `query` and optionally `operationName` and `variables` as query parameters. -### GET -You can execute a GraphQL query via a GET request, passing a query and optionally operationName and variables as query parameters. +### POST requests {% #post-request %} -### POST There are multiple ways to make a GraphQL POST request, differentiated by content type. -#### JSON +{% tabs %} +{% tabsitem #json title="JSON" %} -There are two ways to make requests with the `application/json` content type. You can send a JSON object containing a `query` and optionally `operationName` and `variables`, or an array of objects with the same structure. +There are two ways to make requests with the `application/json` content type. +You can send a JSON object containing a `query` and optionally `operationName` and `variables`, or an array of objects with the same structure. -**object** +#### Object ```json { @@ -60,7 +49,7 @@ There are two ways to make requests with the `application/json` content type. Yo } ``` -**array** +#### Array ```json [ @@ -71,9 +60,9 @@ There are two ways to make requests with the `application/json` content type. Yo } ] ``` +{% /tabsitem %} -#### GraphQL - +{% tabsitem #graphql title="GraphQL" %} The `application/graphql` content type can be used to send a query as the raw POST body. ```graphql @@ -84,69 +73,55 @@ query GetAccount { } } ``` +{% /tabsitem %} +{% /tabs %} -#### Multipart Form Data -The `multipart/form-data` content type can be used to upload files via GraphQL. In this case, the form data must include the following parts in addition to the files to upload. +### Multipart form data {% #multipart-form-data %} -{% table %} -* Name {% width=100 %} -*   {% width=100 %} -* Type {% width=100 %} -* Description ---- -* `operations` -* required -* string -* JSON encoded GraphQL query and optionally operation name and variables. File variables should contain null values. ---- -* `map` -* required -* string -* JSON encoded map of form-data filenames to the operations dot-path to inject the file to, e.g. variables.file. ---- -{% /table %} +The `multipart/form-data` content type can be used to upload files via GraphQL. +In this case, the form data must include the following parts in addition to the files to upload. + +| Name | Type | Description | +|-------------|--------|---------------------------------------------------------------------------------------------------------------------------| +| operations |string | **Required**, JSON encoded GraphQL query and optionally operation name and variables. File variables should contain null values. | +| map | string | **Required**, JSON encoded map of form-data filenames to the operations dot-path to inject the file to, e.g. `variables.file`. | ## Responses {% #responses %} -A response to a GraphQL request will have the following structure. +A response to a GraphQL request will have the following structure: -{% table %} -* Name {% width=100 %} -*   {% width=100 %} -* Type {% width=100 %} -* Description ---- -* `data` -* -* object -* The data returned by the query, maps requested field names to their results. ---- -* `errors` -* -* object[] -* An array of errors that occurred during the request. ---- -{% /table %} +| Name | Type | Description | +|--------|----------|--------------------------------------------------------------------------------| +| data | object | The data returned by the query, maps requested field names to their results. | +| errors | object[] | An array of errors that occurred during the request. | -The data object will contain a map of requested field names to their results. If no data is returned, the object will not be present in the response. +The data object will contain a map of requested field names to their results. +If no data is returned, the object will not be present in the response. -The errors array will contain error objects, each with their own **message** and **path**. The path will contain the field key that is null due to the error. If no errors occur, the array will not be present in the response. +The errors array will contain error objects, each with their own **message** and **path**. +The path will contain the field key that is null due to the error. +If no errors occur, the array will not be present in the response. ## Authentication {% #authentication %} -GraphQL authenticates using Appwrite accounts and sessions. Both accounts and sessions can be created with GraphQL using the `accountCreate`, `accountCreateEmailSession`, `accountCreateAnonymousSession`, or `accountCreatePhoneSession` mutations. -More information and examples of authenticating users can be found in the dedicated [authentication guide](/docs/products/auth). +GraphQL authenticates using Appwrite accounts and sessions. +Both accounts and sessions can be created with GraphQL using the `accountCreate`, `accountCreateEmailSession`, +`accountCreateAnonymousSession`, or `accountCreatePhoneSession` mutations. -## GraphQL vs REST {% #graphql-vs-rest %} +More information and examples of authenticating users can be found in the dedicated [authentication guide](/docs/authentication). + +## GraphQL vs REST {% #graphql-vs-rest %} There are two main features that make GraphQL appealing when compared to the REST API: **selection sets** and **query batching**. -### Selection Sets +### Selection sets {% #selection-sets %} -Selection sets can be used to tell a GraphQL API exactly which fields of a particular resource you would like to receive in the response. The server will respond with only those fields, nothing more, nothing less. This gives you full control over what data comes into your application. +Selection sets can be used to tell a GraphQL API exactly which fields of a particular resource you would like to receive in the response. +The server will respond with only those fields, nothing more, nothing less. This gives you full control over what data comes into your application. -For example, to retrieve only the email of a currently authenticated user, you could query the `accountGet` field, passing only email as the **field selection set**. +For example, to retrieve only the email of a currently authenticated user, you could query the `accountGet` field, +passing only email as the **field selection set**. ```graphql query GetAccount { @@ -159,7 +134,7 @@ query GetAccount { Given this query, the GraphQL API will respond with: -```graphql +```json { "data": { "accountGet": { @@ -170,11 +145,13 @@ Given this query, the GraphQL API will respond with: } ``` -This can be a useful feature for performance, network efficiency, and app responsiveness. As the processing happens on the server, the bandwidth consumed for the request can be dramatically reduced. +This can be a useful feature for performance, network efficiency, and app responsiveness. +As the processing happens on the server, the bandwidth consumed for the request can be dramatically reduced. -## Query batching {% #query-batching %} +## Query batching {% #query-batching %} -GraphQL allows sending multiple queries or mutations in the same request. There are two different ways to batch queries. The simplest way is to include multiple fields in a single query **or** mutation. +GraphQL allows sending multiple queries or mutations in the same request. +There are two different ways to batch queries. The simplest way is to include multiple fields in a single query **or** mutation. ```graphql query GetAccountAndLocale { @@ -204,7 +181,8 @@ If both field executions succeed, the response will contain a data key for each } ``` -If there was no authenticated user, the `accountGet` field would fail to resolve. In such a case the value of the data key for that field will be null, and an object will be added to the errors array instead. +If there was no authenticated user, the `accountGet` field would fail to resolve. +In such a case the value of the data key for that field will be null, and an object will be added to the errors array instead. ```json { @@ -224,13 +202,16 @@ If there was no authenticated user, the `accountGet` field would fail to resolve } ``` -Batching with a single query or mutation has some down-sides. You can not mix and match queries and mutations within the same request unless you provide an operationName, in which case you can only execute one query per request. +Batching with a single query or mutation has some down-sides. +You cannot mix and match queries and mutations within the same request unless you provide an operationName, +in which case you can only execute one query per request. Additionally, all **variables** must be passed in the same object, which can be cumbersome and hard to maintain. -The second way to batch is to pass an array of queries or mutations in the request. In this way, you can execute queries **and** mutations and keep variables separated for each. +The second way to batch is to pass an array of queries or mutations in the request. +In this way, you can execute queries **and** mutations and keep variables separated for each. -```graphql +```json [ { "query": "query GetAccount { accountGet{ email } }", @@ -241,7 +222,9 @@ The second way to batch is to pass an array of queries or mutations in the reque ] ``` -## SDK Usage {% #sdk-usage %} +This allows you to execute complex actions in a single network request. + +## SDK usage {% #sdk-usage %} Appwrite SDKs also support GraphQL in addition to the REST services. @@ -283,7 +266,6 @@ mutation.then(response => { console.log(error); }); ``` - ```dart import 'package:appwrite/appwrite.dart'; @@ -321,8 +303,7 @@ mutation.then((response) { print(error.message); }); ``` - -```java +```kotlin import io.appwrite.Client import io.appwrite.services.Graphql @@ -360,7 +341,6 @@ try { ex.printStackTrace() } ``` - ```swift import Appwrite @@ -401,4 +381,4 @@ do { print(error.localizedDescription) } ``` -{% /multicode %} \ No newline at end of file +{% /multicode %} diff --git a/src/routes/docs/products/auth/+layout.svelte b/src/routes/docs/products/auth/+layout.svelte index 09863d6421..9cd071a117 100644 --- a/src/routes/docs/products/auth/+layout.svelte +++ b/src/routes/docs/products/auth/+layout.svelte @@ -14,46 +14,80 @@ { label: 'Overview', href: '/docs/products/auth' + }, + { + label: 'Quick start', + href: '/docs/products/auth/quick-start' } ] }, { - label: 'Guides', + label: 'Journeys', items: [ { - label: 'Email and Password', + label: 'Email and password login', href: '/docs/products/auth/email-password' }, { - label: 'Phone (SMS)', + label: 'Phone (SMS) login', href: '/docs/products/auth/phone-sms' }, { - label: 'Magic URL', + label: 'Magic URL login', href: '/docs/products/auth/magic-url' }, { - label: 'OAuth 2', + label: 'OAuth 2 login', href: '/docs/products/auth/oauth2' }, { - label: 'Anonymous', + label: 'Anonymous login', href: '/docs/products/auth/anonymous' }, { - label: 'User Management', - href: '/docs/products/auth/user-management' + label: 'JWT login', + href: '/docs/products/auth/server-integrations' + }, + ] + }, + { + label: 'Concepts', + items: [ + { + label: 'Accounts', + href: '/docs/products/auth/accounts' + }, + { + label: 'Teams', + href: '/docs/products/auth/teams' }, { - label: 'Server Integrations', - href: '/docs/products/auth/server-integrations' + label: 'Labels', + href: '/docs/products/auth/labels' }, { label: 'Security', href: '/docs/products/auth/security' } ] - } + }, + { + label: 'References', + items: [ + { + label: 'Account API', + href: '/docs/references/cloud/client-web/account' + }, + { + label: 'Users API', + href: '/docs/references/cloud/server-nodejs/users' + }, + { + label: 'Users API', + href: '/docs/references/cloud/client-web/teams' + } + ] + }, ]; diff --git a/src/routes/docs/products/auth/+page.markdoc b/src/routes/docs/products/auth/+page.markdoc index fe64635494..d35cb98dcc 100644 --- a/src/routes/docs/products/auth/+page.markdoc +++ b/src/routes/docs/products/auth/+page.markdoc @@ -10,19 +10,4 @@ Authentication makes it easy to build secure and robust authentication with supp You can manage user accounts with user preferences, user labeling, or organizing users into teams. Combined with a robust permissions system, Appwrite Authentication provides everything you need to authenticate and manage users. -## Explore implementation {% #explore %} - -Learn how you can add Appwrite Authentication to your application by exploring the following features. -| Explore | | -|-------------------------------------------------------------------------|----------------------------------------------------| -| [Quick start](/docs/products/auth/quick-start) | Add Appwrite authentication to your app in minutes. | -| [Email and password](/docs/products/auth/email-password) | Authenticate your users using email and passwords. | -| [Account verification](/docs/products/auth/email-password#verification) | Verify the email of registered users. | -| [Phone (SMS)](/docs/products/auth/phone-sms) | Authenticate users with their phone number using SMS messages. | -| [Magic URL](/docs/products/auth/magic-url) | Authenticate users through a magic link sent to their email, without needing a password. | -| [OAuth 2](/docs/products/auth/oauth2) | Authenticate users by connecting to existing accounts from an OAuth provider. | -| [Anonymous](/docs/products/auth/anonymous) | Create guest user sessions that can be convered to full accounts later. | -| [User preferences](/docs/products/auth/user-management#preferences) | Store and manage user preferences, like notification settings and themes. | -| [Organize users](/docs/products/auth/user-management#labels) | Organize users by adding labels or creating teams. | -| [Server integration](/docs/products/auth/server-integrations) | Authenticate users in backend code or act on behalf of users using the [Appwrite Server SDKs](#). | -| [Security](/docs/products/auth/security) | Learn about Appwrite's session persistence and enhanced security features. | \ No newline at end of file +[Quick start {% icon icon="cheveron-right" /%}](/docs/products/auth/quick-start) diff --git a/src/routes/docs/products/auth/accounts/+page.markdoc b/src/routes/docs/products/auth/accounts/+page.markdoc new file mode 100644 index 0000000000..a4f1559da8 --- /dev/null +++ b/src/routes/docs/products/auth/accounts/+page.markdoc @@ -0,0 +1,185 @@ +--- +layout: article +title: Accounts +description: This is the description used for SEO. +--- + +Appwrite allows users to create accounts. +Users can be organized into teams and be given labels, so they can be given different permissions and access different resources. +Each user's account can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings. + +{% partial file="account-vs-user.md" /%} + +## Signup and login {% signup-login %} +You can signup and login a user with an account create through +[email password](/docs/products/auth/email-password), +[phone (SMS)](/docs/products/auth/phone-sms), +[Anonymous](/docs/products/auth/anonymous) +[magic URL](/docs/products/auth/magic-url), and +[OAuth 2](/docs/products/auth/oauth2) +authentication. + +## Preferences {% #preferences %} + +You can store user preferences on a user's account using Appwrite's [Update Preferences](#) endpoint. You can store preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices. + +Preferences are stored as a key-value JSON object. The maximum allowed size for preferences is 64kB, and an error will be thrown if this limit is exceeded. + +{% multicode %} +```js +import { Client, Account } from "appwrite"; + +const client = new Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const promise = account.updatePrefs({darkTheme: true, language: 'en'}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); +``` +```dart +import 'package:appwrite/appwrite.dart'; + +final client = Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +final account = Account(client); + +final user = await account.updatePrefs( + prefs: { + "darkTheme": true, + "language": "en", + } +); +``` +```kotlin +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +val account = Account(client) + +val user = account.updatePrefs( + prefs = mapOf( + "darkTheme" to true, + "language" to "en" + ) +) +``` +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let account = Account(client) + +let user = try await account.updatePrefs( + prefs: [ + "darkTheme": true, + "language": "en" + ] +) +``` +```graphql +mutation { + accountUpdatePrefs( + prefs: "{\"darkTheme\": true, \"language\": \"en\"}" + ) { + _id + name + prefs { + data + } + } +} +``` +{% /multicode %} + +After a user's preferences are updated, they can be retrieved using the [Get Preferences](#) endpoint. + +{% multicode %} +```js +import { Client, Account } from "appwrite"; + +const client = new Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const promise = account.getPrefs(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); +``` +```dart +import 'package:appwrite/appwrite.dart'; + +final client = Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +final account = Account(client); + +final prefs = await account.getPrefs(); +``` +```kotlin +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +val account = Account(client) + +val prefs = account.getPrefs() +``` +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let account = Account(client) + +let prefs = try await account.getPrefs() +``` +```graphql +query { + accountGetPrefs { + data + } +} +``` +{% /multicode %} + +## Permissions {% #permissions %} + +You can grant permissions to all users using the `Role.users()` role or +individual users using the `Role.user(, )` role. + +| Description | Role | +| ------------------------------------------- | ------------------------------------------- | +| Verified users | `Role.users('verified')`| +| Unverified users | `Role.users('unverified')` | +| Verified user | `Role.user(, 'verified')`| +| Unverified user | `Role.user(, 'unverified')` | + +[Learn more about permissions](/docs/advanced/platform/permissions) \ No newline at end of file diff --git a/src/routes/docs/products/auth/labels/+page.markdoc b/src/routes/docs/products/auth/labels/+page.markdoc new file mode 100644 index 0000000000..e3c4c916fa --- /dev/null +++ b/src/routes/docs/products/auth/labels/+page.markdoc @@ -0,0 +1,186 @@ +--- +layout: article +title: Labels +description: This is the description used for SEO. +--- + +Labels are a good way to categorize a user to grant them access to resources. For example, a `subscriber` label can be added to a user once they've purchased a subscription. + +{% multicode %} +```js +const sdk = require('node-appwrite'); + +const client = new sdk.Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('98fd4...a2ad2'); // Your secret API key + +const users = new sdk.Users(client); + +const promise = users.updateLabels( + '[USER_ID]', + [ 'subscriber' ] +); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); +``` + +```php +use Appwrite\Client; +use Appwrite\Services\Users; +use Appwrite\Role; + +$client = new Client(); + +$client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('98fd4...a2ad2'); // Your secret API key + +$users = new Users($client); + +$result = $users->updateLabels( + '[USER_ID]', + [ 'subscriber' ] +); +``` + +```python +from appwrite.client import Client +from appwrite.services.users import Users +from appwrite.role import Role + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('98fd4...a2ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_labels( + '[USER_ID]', + [ 'subscriber' ] +); +``` +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('98fd4...a2ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_labels( + user_id: '[USER_ID]', + labels: [ 'subscriber' ] +); +``` + +```deno +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +let client = new sdk.Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('98fd4...a2ad2'); // Your secret API key + +let users = new sdk.Users(client); + +const promise = users.updateLabels( + '[USER_ID]', + [ 'subscriber' ] +); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); +``` +```dart +import 'package:dart_appwrite/dart_appwrite.dart'; + +final client = Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('98fd4...a2ad2'); // Your secret API key + +final users = Users(client); + +final result = await users.updateLabels( + userId: '[USER_ID]', + labels: [ 'subscriber' ], +); +``` +```kotlin +import io.appwrite.Client +import io.appwrite.Role +import io.appwrite.services.Users + +val client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("98fd4...a2ad2") // Your secret API key + +val users = Users(client) + +val response = users.updateLabels( + userId = "[USER_ID]", + labels = [ 'subscriber' ] +); +``` + +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("98fd4...a2ad2") // Your secret API key + +let users = Users(client) + +let response = try await users.updateLabels( + userId: "[USER_ID]", + labels: [ 'subscriber' ] +); +``` + +```csharp +using Appwrite; + +var client = new Client() + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("98fd4...a2ad2"); // Your secret API key + +var users = new Users(client); + +var response = await users.UpdateLabels( + userId: "[USER_ID]", + labels: [ 'subscriber' ] +); +``` +{% /multicode %} + +This would correspond with the permissions below. + +| Description | Code Snippet | +| ------------------------------------------- | ------------------------------------------- | +| Read | `Permissions.read(Role.label('subscriber'))`| +| Update | `Permissions.update(Role.label('subscriber'))` | +| Delete | `Permissions.delete(Role.label('subscriber'))` | +| Create | `Permissions.create(Role.label('subscriber'))` | + +[Learn more about permissions](/docs/advanced/platform/permissions) diff --git a/src/routes/docs/products/auth/magic-url/+page.markdoc b/src/routes/docs/products/auth/magic-url/+page.markdoc index 492b4f288b..f316c4bd5c 100644 --- a/src/routes/docs/products/auth/magic-url/+page.markdoc +++ b/src/routes/docs/products/auth/magic-url/+page.markdoc @@ -3,7 +3,6 @@ layout: article title: Magic URL description: This is the description used for SEO. --- -Certainly, here's the HTML content converted into Markdown format: Magic URL is a password-less way to authenticate users. When a user logs in by providing their email, they will receive an email with a "magic" link that contains a secret used to log in the user. The user can simply click the link to be logged in. diff --git a/src/routes/docs/products/auth/quick-start/+page.markdoc b/src/routes/docs/products/auth/quick-start/+page.markdoc index 9a16808b7c..1f6a2f1810 100644 --- a/src/routes/docs/products/auth/quick-start/+page.markdoc +++ b/src/routes/docs/products/auth/quick-start/+page.markdoc @@ -93,8 +93,6 @@ mutation { After you've created your account, users can be logged in using the Create Email Session route. -Converting your HTML code into your custom Markdown with the multi-select code feature can be done like this. - {% multicode %} ```js import { Client, Account } from "appwrite"; @@ -172,19 +170,12 @@ mutation { ``` {% /multicode %} -## Explore -Appwrite's feature rich Authentication service has much more to offer. -Explore the features below. - -| Explore | | -|-------------------------------------------------------------------------|----------------------------------------------------| -| [Email and password](/docs/products/auth/email-password) | Authenticate your users using email and passwords. | -| [Account verification](/docs/products/auth/email-password#verification) | Verify the email of registered users. | -| [Phone (SMS)](/docs/products/auth/phone-sms) | Authenticate users with their phone number using SMS messages. | -| [Magic URL](/docs/products/auth/magic-url) | Authenticate users through a magic link sent to their email, without needing a password. | -| [OAuth 2](/docs/products/auth/oauth2) | Authenticate users by connecting to existing accounts from an OAuth provider. | -| [Anonymous](/docs/products/auth/anonymous) | Create guest user sessions that can be convered to full accounts later. | -| [User preferences](/docs/products/auth/user-management#preferences) | Store and manage user preferences, like notification settings and themes. | -| [Organize users](/docs/products/auth/user-management#labels) | Organize users by adding labels or creating teams. | -| [Server integration](/docs/products/auth/server-integrations) | Authenticate users in backend code or act on behalf of users using the [Appwrite Server SDKs](#). | -| [Security](/docs/products/auth/security) | Learn about Appwrite's session persistence and enhanced security features. | \ No newline at end of file +## More ways to Authenticate +You can signup and login a user with an account create through +[email password](/docs/products/auth/email-password), +[phone (SMS)](/docs/products/auth/phone-sms), +[Anonymous](/docs/products/auth/anonymous) +[magic URL](/docs/products/auth/magic-url), and +[OAuth 2](/docs/products/auth/oauth2) +authentication. + diff --git a/src/routes/docs/products/auth/teams/+page.markdoc b/src/routes/docs/products/auth/teams/+page.markdoc new file mode 100644 index 0000000000..2ccffd89ad --- /dev/null +++ b/src/routes/docs/products/auth/teams/+page.markdoc @@ -0,0 +1,198 @@ +--- +layout: article +title: User Managements +description: This is the description used for SEO. +--- + +Teams are a good way to allow users to share access to resources. +For example, in a todo app, a user can [create a team](#) for one of their todo lists and [invite another user](#) to the team to grant the other user access. +You can further give special rights to parts of a team using team roles. + +The invited user can [accept the invitation](#) to gain access. If the user's ever removed from the team, they'll lose access again. + +## Create team {% #create %} +For example, we can create a team called `teachers` with roles `maths`, `sciences`, `arts`, and `literature`. + +The creator of the team is also granted the `owner` role. **Only those with the `owner` role can invite and remove members**. + +{% multicode %} +```js +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.create( + 'teachers', + 'Teachers', + ['maths', 'sciences', 'arts', 'literature'] +); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); +``` +```dart +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.create( + teamId: 'teachers', + name: 'Teachers', + roles: ['maths', 'sciences', 'arts', 'literature'] + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} +``` +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let team = try await teams.create( + teamId: "teachers", + name: "Teachers", + roles: ["maths", "sciences", "arts", "literature"] +) +``` +```kotlin +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.create( + teamId = "teachers", + name = "Teachers", + roles = listOf("maths", "sciences", "arts", "literature") +) +``` + +{% /multicode %} + +## Invite a member {% #create-membership %} + +You can invite members to a team by creating team memberships. For example, inviting "David" a math teacher, to the teachers team. + +{% multicode %} +```js +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.createMembership( + 'teachers', + ["maths"], + "david@example.com" + ); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); +``` +```dart +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.createMembership( + teamId: 'teachers', + roles: ['maths'], + email: 'david@example.com' + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} +``` +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let membership = try await teams.createMembership( + teamId: "teachers", + roles: ["maths"], + email: "david@example.com" +) +``` +```kotlin +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.createMembership( + teamId = "teachers", + roles = listOf("maths"), + email = "david@example.com" +) +``` + +{% /multicode %} + +## Permissions {% #permissions %} + +You can grant permissions to all members of a team using the `Role.team()` role or +individual roles in the team using the `Role.team(, [, , ...])` role. + +| Description | Role | +| ------------------------------------------- | ------------------------------------------- | +| All members | `Role.team()`| +| Select roles | `Role.team(, [, , ...])`| \ No newline at end of file diff --git a/src/routes/docs/products/auth/user-management/+page.markdoc b/src/routes/docs/products/auth/user-management/+page.markdoc deleted file mode 100644 index fdd25fde4f..0000000000 --- a/src/routes/docs/products/auth/user-management/+page.markdoc +++ /dev/null @@ -1,357 +0,0 @@ ---- -layout: article -title: User Managements -description: This is the description used for SEO. ---- - -Appwrite has built-in features to help manage user accounts. Users can be organized into teams and be given labels, so they can be given different permissions and access different resources. Each user can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings. - -## User preferences {% #preferences %} - -You can store user preferences on a user's account using Appwrite's [Update Preferences](#) endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices. - -Preferences are stored as a key-value JSON object. The maximum allowed size for preferences is 64kB, and an error will be thrown if this limit is exceeded. - -{% multicode %} -```js -import { Client, Account } from "appwrite"; - -const client = new Client() - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const promise = account.updatePrefs({darkTheme: true, language: 'en'}); - -promise.then(function (response) { - console.log(response); // Success -}, function (error) { - console.log(error); // Failure -}); -``` -```dart -import 'package:appwrite/appwrite.dart'; - -final client = Client() - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -final account = Account(client); - -final user = await account.updatePrefs( - prefs: { - "darkTheme": true, - "language": "en", - } -); -``` -```kotlin -import io.appwrite.Client -import io.appwrite.services.Account - -val client = Client() - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -val account = Account(client) - -val user = account.updatePrefs( - prefs = mapOf( - "darkTheme" to true, - "language" to "en" - ) -) -``` -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let account = Account(client) - -let user = try await account.updatePrefs( - prefs: [ - "darkTheme": true, - "language": "en" - ] -) -``` -```graphql -mutation { - accountUpdatePrefs( - prefs: "{\"darkTheme\": true, \"language\": \"en\"}" - ) { - _id - name - prefs { - data - } - } -} -``` -{% /multicode %} - -After a user's preferences are updated, they can be retrieved using the [Get Preferences](#) endpoint. - -{% multicode %} -```js -import { Client, Account } from "appwrite"; - -const client = new Client() - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const promise = account.getPrefs(); - -promise.then(function (response) { - console.log(response); // Success -}, function (error) { - console.log(error); // Failure -}); -``` -```dart -import 'package:appwrite/appwrite.dart'; - -final client = Client() - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -final account = Account(client); - -final prefs = await account.getPrefs(); -``` -```kotlin -import io.appwrite.Client -import io.appwrite.services.Account - -val client = Client(context) - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -val account = Account(client) - -val prefs = account.getPrefs() -``` -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let account = Account(client) - -let prefs = try await account.getPrefs() -``` -```graphql -query { - accountGetPrefs { - data - } -} -``` -{% /multicode %} - -## Users API {% #users-api %} - -The Users API is a dedicated API for managing users from an admin's perspective. You'll notice that the Account API doesn't allow you to view or make changes to other users. This is by design and for **security reasons**. - -You can use the Users API with an API key authenticated [Server SDK](#) to manage users. If you must expose parts of the Users API to normal users, we suggest doing so through an Appwrite Function. Exposing API keys to users is **dangerous and a security risk**, by using an Appwrite Function, you can add your own validation to prevent malicious behavior. - -[Learn more about the Users API](#) - -## Labels {% #labels %} - -Labels are a good way to categorize a user to grant them access to resources. For example, a `subscriber` label can be added to a user once they've purchased a subscription. - -Using your extended markdown with the `{% multicode %}` syntax, the HTML content can be converted to the following markdown: - -{% multicode %} -```js -const sdk = require('node-appwrite'); - -const client = new sdk.Client() - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('5df5acd0d48c2') // Your project ID - .setKey('98fd4...a2ad2'); // Your secret API key - -const users = new sdk.Users(client); - -const promise = users.updateLabels( - '[USER_ID]', - [ 'subscriber' ] -); - -promise.then(function (response) { - console.log(response); // Success -}, function (error) { - console.log(error); // Failure -}); -``` - -```php -use Appwrite\Client; -use Appwrite\Services\Users; -use Appwrite\Role; - -$client = new Client(); - -$client - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('5df5acd0d48c2') // Your project ID - .setKey('98fd4...a2ad2'); // Your secret API key - -$users = new Users($client); - -$result = $users->updateLabels( - '[USER_ID]', - [ 'subscriber' ] -); -``` - -```python -from appwrite.client import Client -from appwrite.services.users import Users -from appwrite.role import Role - -client = Client() - -(client - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('5df5acd0d48c2') # Your project ID - .set_key('98fd4...a2ad2') # Your secret API key -) - -users = Users(client) - -result = users.update_labels( - '[USER_ID]', - [ 'subscriber' ] -); -``` -```ruby -require 'appwrite' - -include Appwrite - -client = Client.new - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('5df5acd0d48c2') # Your project ID - .set_key('98fd4...a2ad2') # Your secret API key - -users = Users.new(client) - -response = users.update_labels( - user_id: '[USER_ID]', - labels: [ 'subscriber' ] -); -``` - -```deno -import * as sdk from "https://deno.land/x/appwrite/mod.ts"; - -let client = new sdk.Client() - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('5df5acd0d48c2') // Your project ID - .setKey('98fd4...a2ad2'); // Your secret API key - -let users = new sdk.Users(client); - -const promise = users.updateLabels( - '[USER_ID]', - [ 'subscriber' ] -); - -promise.then(function (response) { - console.log(response); // Success -}, function (error) { - console.log(error); // Failure -}); -``` -```dart -import 'package:dart_appwrite/dart_appwrite.dart'; - -final client = Client() - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('5df5acd0d48c2') // Your project ID - .setKey('98fd4...a2ad2'); // Your secret API key - -final users = Users(client); - -final result = await users.updateLabels( - userId: '[USER_ID]', - labels: [ 'subscriber' ], -); -``` -```kotlin -import io.appwrite.Client -import io.appwrite.Role -import io.appwrite.services.Users - -val client = Client() - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID - .setKey("98fd4...a2ad2") // Your secret API key - -val users = Users(client) - -val response = users.updateLabels( - userId = "[USER_ID]", - labels = [ 'subscriber' ] -); -``` - -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID - .setKey("98fd4...a2ad2") // Your secret API key - -let users = Users(client) - -let response = try await users.updateLabels( - userId: "[USER_ID]", - labels: [ 'subscriber' ] -); -``` - -```csharp -using Appwrite; - -var client = new Client() - .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .SetProject("5df5acd0d48c2") // Your project ID - .SetKey("98fd4...a2ad2"); // Your secret API key - -var users = new Users(client); - -var response = await users.UpdateLabels( - userId: "[USER_ID]", - labels: [ 'subscriber' ] -); -``` -{% /multicode %} - -This would correspond with the permissions below. - -| Description | Code Snippet | -| ------------------------------------------- | ------------------------------------------- | -| Read | `Permissions.read(Role.label('subscriber'))`| -| Update | `Permissions.update(Role.label('subscriber'))` | -| Delete | `Permissions.delete(Role.label('subscriber'))` | -| Create | `Permissions.create(Role.label('subscriber'))` | - -[Learn more about permissions](/docs/advanced/platform/permissions) - -## Teams {% #teams %} - -Teams are a good way to allow users to share access to resources. - -For example, in a todo app, a user can [create a team](#) for one of their todo lists and [invite another user](#) to the team to grant the other user access. The invited user can [accept the invitation](#) to gain access. If the user's ever removed from the team, they'll lose access again. diff --git a/src/routes/docs/products/databases/+layout.svelte b/src/routes/docs/products/databases/+layout.svelte index 688324f4d8..b1ebf61e20 100644 --- a/src/routes/docs/products/databases/+layout.svelte +++ b/src/routes/docs/products/databases/+layout.svelte @@ -14,16 +14,16 @@ { label: 'Overview', href: '/docs/products/databases' - } - ] - }, - { - label: 'Guides', - items: [ + }, { label: 'Quick Start', href: '/docs/products/databases/quick-start' }, + ] + }, + { + label: 'Concepts', + items: [ { label: 'Databases', href: '/docs/products/databases/databases' @@ -36,6 +36,19 @@ label: 'Documents', href: '/docs/products/databases/documents' }, + { + label: 'Permissions', + href: '/docs/products/databases/permissions' + }, + { + label: 'Relationships', + href: '/docs/products/databases/relationships' + } + ] + }, + { + label: 'Journeys', + items: [ { label: 'Queries', href: '/docs/products/databases/queries' @@ -47,14 +60,6 @@ { label: 'Pagination', href: '/docs/products/databases/pagination' - }, - { - label: 'Permissions', - href: '/docs/products/databases/permissions' - }, - { - label: 'Relationships', - href: '/docs/products/databases/relationships' } ] } diff --git a/src/routes/docs/products/databases/+page.markdoc b/src/routes/docs/products/databases/+page.markdoc index f4a07efb2f..9a81116efd 100644 --- a/src/routes/docs/products/databases/+page.markdoc +++ b/src/routes/docs/products/databases/+page.markdoc @@ -11,41 +11,7 @@ Databases provide high-performance and scalable data storage for your key applic Databases store data, if you need to store files like images, PDFs or videos, use [Appwrite Storage](/docs/products/storage). {% /info %} -## Get started -Learn to setup up a database, create and retrieve documents, and basic permissions. +You can organize data into databases, collections, and documents. You can also paginate, order, and query documents. +For complex business logic, Appwrite supports relationships to help you model your data. -[Quick start {% icon icon="cheveron-right" /%}](#) - -## Organize your data -Appwrite organizes data heirarchically into databases, collections and documents. A database contains many collections, a collection contains many documents. - -[Learn about databases {% icon icon="cheveron-right" /%}](#) - -[Learn about collections {% icon icon="cheveron-right" /%}](#) - -[Learn about documents {% icon icon="cheveron-right" /%}](#) - -## Structure your data -Collections define the structure of its documents. All documents in a collection share the same structure. - -[Learn about structuring data {% icon icon="cheveron-right" /%}](#) - -## Query your data -Appwrite supports a powerful set of query operators, so you can filter and order the data returned by Databases. - -[Learn about quering data {% icon icon="cheveron-right" /%}](#) - -## Paginate your data -Paginate large data sets into smaller pages using offset or cursor pagination. - -[Learn about paginating data {% icon icon="cheveron-right" /%}](#) - -## Relationships -Express complex and interconnected data models by organizing data using relationships. - -[Learn about relationships {% icon icon="cheveron-right" /%}](#) - -## Permissions -Manage which users can access data with permissions at the collection or document level. - -[Learn about permissions {% icon icon="cheveron-right" /%}](#) \ No newline at end of file +[Quick start {% icon icon="cheveron-right" /%}](#) \ No newline at end of file diff --git a/src/routes/docs/products/functions/+layout.svelte b/src/routes/docs/products/functions/+layout.svelte index c7066ac158..7718528faa 100644 --- a/src/routes/docs/products/functions/+layout.svelte +++ b/src/routes/docs/products/functions/+layout.svelte @@ -14,16 +14,16 @@ { label: 'Overview', href: '/docs/products/functions' - } + }, + { + label: 'Quick Start', + href: '/docs/products/functions/quick-start' + }, ] }, { label: 'Guides', items: [ - { - label: 'Quick Start', - href: '/docs/products/functions/quick-start' - }, { label: 'Development', href: '/docs/products/functions/development' diff --git a/src/routes/docs/products/functions/+page.markdoc b/src/routes/docs/products/functions/+page.markdoc index 82a61ae9e4..9d1b73762d 100644 --- a/src/routes/docs/products/functions/+page.markdoc +++ b/src/routes/docs/products/functions/+page.markdoc @@ -11,21 +11,11 @@ Appwrite Functions are user-defined functions that can start small and scale big These Functions can be triggered by HTTP requests, SDK methods, server events, webhooks, and scheduled executions. Each function will have its own URL, execute in its own isolated container, and have its own configurable environment variables and permissions. -# Getting started {% #getting-started %} +## Getting started {% #getting-started %} Appwrite Functions let you build anything you can imagine, but this flexibility makes it difficult to know where to start. Start exploring by cloning one of the quick start templates or using a template with pre-built integration to quickly implement features. -![](https://appwrite.io/images-ee/docs/functions-starter-dark.png) +[Quick start {% icon icon="cheveron-right" /%}](/docs/products/function/quick-start) -# Explore features {% #explore %} - -Appwrite Functions use familiar HTTP concepts, so you can learn quickly and gain transferable skills. - -| Explore | | -| ----------------- | ----------------- | -| [Develop](functions/development) | Appwrite Functions use familiar HTTP concepts, so you can learn quickly and gain transferable skills. | -| [Deploy](functions/deployment) | Appwrite Functions can be deployed automatically from Git, through the Appwrite CLI, or be uploaded manually. Develop and deploy with the workflow you're already comfortable with. | -| [Execute](functions/execution) | Appwrite Functions can be triggered by HTTP requests, SDK methods, server events, webhooks, and scheduled executions. Explore how Appwrite Functions can be invoked. | -| [Runtimes](functions/runtimes) | Appwrite supports a growing list of **10+** runtimes. Avoid adding additional complexity to your codebase by coding in languages you already use and love. | -| [Examples](functions/examples) | Like to learn from examples? Here's a curated list of examples that showcase Appwrite Functions' capabilities. | \ No newline at end of file +![](https://appwrite.io/images-ee/docs/functions-starter-dark.png) \ No newline at end of file diff --git a/src/routes/docs/products/storage/+layout.svelte b/src/routes/docs/products/storage/+layout.svelte index bbb56836ea..bdbe83487a 100644 --- a/src/routes/docs/products/storage/+layout.svelte +++ b/src/routes/docs/products/storage/+layout.svelte @@ -14,20 +14,29 @@ { label: 'Overview', href: '/docs/products/storage' - } - ] - }, - { - label: 'Guides', - items: [ + }, { label: 'Quick start', href: '/docs/products/storage/quick-start' }, + ] + }, + { + label: 'Concepts', + items: [ { label: 'Buckets', href: '/docs/products/storage/buckets' }, + { + label: 'Permissions', + href: '/docs/products/storage/permissions' + } + ] + }, + { + label: 'Guides', + items: [ { label: 'Upload and download', href: '/docs/products/storage/upload-download' @@ -36,10 +45,6 @@ label: 'Images', href: '/docs/products/storage/images' }, - { - label: 'Permissions', - href: '/docs/products/storage/permissions' - } ] } ]; diff --git a/src/routes/docs/products/storage/+page.markdoc b/src/routes/docs/products/storage/+page.markdoc index 814e92139b..2458da1dfa 100644 --- a/src/routes/docs/products/storage/+page.markdoc +++ b/src/routes/docs/products/storage/+page.markdoc @@ -15,26 +15,6 @@ Appwrite Storage stores files like images, PDFs or videos. If you need to store {% /info %} ## Get started {% #get-started %} -Get started with Appwrite Storage. Learn to setup up a bucket, upload, and dowload your first file. +Get started with Appwrite Storage. Learn to setup up a bucket, upload, and download your first file. -- [Quick start](/docs/products/storage/quick-start) - -## Organize files and enforce rules {% #buckets %} -Organize your files into buckets and configure rules for each bucket, like enforcing size limit, allowed file extensions, compression, and more. - -- [Learn about buckets](/docs/products/storage/buckets) - -## Upload and serve files {% #upload-download %} -You can upload and download files using the Appwrite Console, or one of many SDKs. - -- [Learn about file upload and downlod](/docs/products/storage/upload-download) - -## Previews and image manipulation {% #images %} -You can upload and download files using the Appwrite Console, or one of many SDKs. - -- [Learn about file upload and downlod](/docs/products/storage/images) - -## Permissions {% #permissions %} -You can upload and download files using the Appwrite Console, or one of many SDKs. - -- [Learn about file upload and downlod](/docs/products/storage/permissions) +[Quick start {% icon icon="cheveron-right" /%}](/docs/products/storage/quick-start) \ No newline at end of file diff --git a/src/routes/docs/products/storage/images/+page.markdoc b/src/routes/docs/products/storage/images/+page.markdoc index 477f14aa35..bee82f9d95 100644 --- a/src/routes/docs/products/storage/images/+page.markdoc +++ b/src/routes/docs/products/storage/images/+page.markdoc @@ -15,6 +15,11 @@ Appwrite Storage's [preview endpoint](#) let you manipulate resolution, add bord You can manipulate images resolution to display appropriately on responsive websites. You can also adjust the image border, background color, and border-radius to match the theming of your application. The Appwrite Storage also allows you to change the format and compression of your images for network transfer optimization and to help you speed your application. You can do all that without caring about how the image was originally uploaded. +{% info title="Caching" %} +When manipulating images in Appwrite, the resulting images are cached by Appwrite and your browser. +When you repeatedly use the same transformed images, the performance impact will be minimal. +{% /info %} + Below you can find all the different parameters offered by the preview endpoint to manipulate the image. | Parameter | Description | diff --git a/src/routes/docs/quick-starts/android/+page.markdoc b/src/routes/docs/quick-starts/android/+page.markdoc index 5b4d5aa4fe..23f1bdd2ad 100644 --- a/src/routes/docs/quick-starts/android/+page.markdoc +++ b/src/routes/docs/quick-starts/android/+page.markdoc @@ -6,4 +6,51 @@ difficulty: beginner readtime: 3 --- -hello world \ No newline at end of file +Learn to setup your first Apple project powered by Appwrite. +{% section #step-1 step=1 title="Create project" %} +Head to the [Appwrite Console](https://cloud.appwrite.io/console). + +![Create project screen](/images/docs/databases/quick-start/create-project.png) + +If this is your first time using Appwrite, create an accout and create your first project. + +Then, under **Add a platform**, add a **Android app** with the **Name** `My Application` and **Package name** `com.example.myapplication`. + +![Add a platform](/images/docs/databases/quick-start/add-platform.png) + +You can skip optional steps. + +{% /section %} +{% section #step-2 step=2 title="Create Android project" %} +Open Android Studios and click **New Project**, select **Empty Activity**. +**Name** the project `My Application` with **Package Name** `com.example.myapplication`. +{% /section %} + +{% section #step-3 step=3 title="Install Appwrite" %} +Install the Appwrite SDK for Android. + + +{% /section %} + +{% section #step-4 step=4 title="Import Appwrite" %} +Find your project's ID in the **Settings** page. + +![Settings page in Appwrite Console.](/images/docs/databases/quick-start/project-id.png) + +Create a new file `src/lib/appwrite.js` and add the following code to it, replace `` with your project ID. + +```swift +TODO +``` +{% /section %} +{% section #step-5 step=5 title="Create a login page" %} +Add the following code to `src/App.jsx`. + +```swift +TODO +``` +{% /section %} + +{% section #step-6 step=6 title="Checkout what you've built" %} +Run your project with `npm run dev -- --open --port 3000` and open [http://localhost:3000](http://localhost:3000) in your browser. +{% /section %} \ No newline at end of file diff --git a/src/routes/docs/quick-starts/apple/+page.markdoc b/src/routes/docs/quick-starts/apple/+page.markdoc index 8e7b0bbc89..059fec0d4f 100644 --- a/src/routes/docs/quick-starts/apple/+page.markdoc +++ b/src/routes/docs/quick-starts/apple/+page.markdoc @@ -1,9 +1,61 @@ --- layout: article -title: Quick start with Apple +title: Start with Apple description: Learn how to quickly integrate Appwrite products and services into your iOS, iPadOS, macOS, watchOS, tvOS, or visionOS project. difficulty: beginner readtime: 3 --- -hello world \ No newline at end of file +Learn to setup your first Apple project powered by Appwrite. +{% section #step-1 step=1 title="Create project" %} +Head to the [Appwrite Console](https://cloud.appwrite.io/console). + +![Create project screen](/images/docs/databases/quick-start/create-project.png) + +If this is your first time using Appwrite, create an accout and create your first project. + +Then, under **Add a platform**, add a **Apple app**. The **Bundle ID** can be `example.my-app`. + +![Add a platform](/images/docs/databases/quick-start/add-platform.png) + +You can skip optional steps. + +{% /section %} +{% section #step-2 step=2 title="Create XCode project" %} +Open XCode and select **Create a new XCode project** > select **App** > create an app named `my-app` under the **Organization Identifier** `example`. +This creates a new app with the **Bundle ID** `example.my-app`. +{% /section %} + +{% section #step-3 step=3 title="Install Appwrite" %} +Install the Appwrite SDK for Apple. + +1. Select **File** > **Add Packages** +2. Search for the Appwrite SDK with the URL `https://github.com/appwrite/sdk-for-apple` +3. In the right panel, select your target project and add your desired version rules +4. Select Add Package and wait for package resolution to complete +5. Make sure the Appwrite package product is checked and select Add Package again + +{% /section %} + +{% section #step-4 step=4 title="Import Appwrite" %} +Find your project's ID in the **Settings** page. + +![Settings page in Appwrite Console.](/images/docs/databases/quick-start/project-id.png) + +Create a new file `src/lib/appwrite.js` and add the following code to it, replace `` with your project ID. + +```swift +TODO +``` +{% /section %} +{% section #step-5 step=5 title="Create a login page" %} +Add the following code to `src/App.jsx`. + +```swift +TODO +``` +{% /section %} + +{% section #step-6 step=6 title="Checkout what you've built" %} +Run your project with `npm run dev -- --open --port 3000` and open [http://localhost:3000](http://localhost:3000) in your browser. +{% /section %} \ No newline at end of file diff --git a/src/routes/docs/quick-starts/flutter/+page.markdoc b/src/routes/docs/quick-starts/flutter/+page.markdoc index 4799e5496e..4df853c009 100644 --- a/src/routes/docs/quick-starts/flutter/+page.markdoc +++ b/src/routes/docs/quick-starts/flutter/+page.markdoc @@ -6,4 +6,294 @@ difficulty: beginner readtime: 3 --- -hello world \ No newline at end of file +Learn to setup your first Flutter project powered by Appwrite. +{% section #step-1 step=1 title="Create project" %} +Head to the [Appwrite Console](https://cloud.appwrite.io/console). + +![Create project screen](/images/docs/databases/quick-start/create-project.png) + +If this is your first time using Appwrite, create an accout and create your first project. + +Then, under **Add a platform**, add a **Flutter app**. You can choose between many different platfroms. + +{% tabs %} +{% tabsitem #web title="Web" %} +Add your app **name** and **Hostname**. If you're testing your app locally, **Hostname** should be `localhost`. + +For web, in order to capture the OAuth2 callback URL and send it to the application using JavaScript `postMessage()`, you need to create an html file inside `./web` folder of your Flutter project. For example `auth.html` with the following content. + +```html + +Authentication complete +

Authentication is complete. If this does not happen automatically, please close the window.

+ +``` + +The redirection URL passed to the authentication service must be the same as the URL on which the application is running including schema, host, and port if applicable. +The path must point to the created HTML file, `/auth.html` in this case. +The callbackUrlScheme parameter in the authenticate() method isn't applicable when you're developing for web platforms. This means you can use this parameter to define URL schemes specifically for native platforms without affecting the web version of your Flutter application. + +{% info title="Flutter web cross-domain communication & cookies" %} +While running Flutter Web, make sure your Appwrite server and your Flutter client use the same top-level domain and protocol (HTTP or HTTPS) to communicate. +When communicating between different domains or protocols, you may receive HTTP status error 401 because some modern browsers block cross-site or insecure cookies for enhanced privacy. +In production, Appwrite allows you to set multiple [custom-domains](/docs/advanced/platform/custom-domains) for each project. +{% /info %} + +{% /tabsitem %} + +{% tabsitem #ios title="iOS" %} + +Add your app **name** and **Bundle ID**. You can find your **Bundle Identifier** in the **General** tab for your app's primary target in XCode. + +The Appwrite SDK uses `ASWebAuthenticationSession` on iOS 12+ and `SFAuthenticationSession` on iOS 11 to allow OAuth authentication. +You have to change your iOS Deployment Target in Xcode to be iOS >= 11 to be able to build your app on an emulator or a real device. + +1. In **XCode**, open `Runner.xcworkspace` in your app's iOS folder. +2. To view your app's settings, select the Runner project in the XCode project navigator. Then, in the main view sidebar, select the **Runner target**. +3. Select the **General** tab. +4. In **Deployment Info** > **Target**, select iOS 11.0 or above +{% /tabsitem %} + +{% tabsitem #android title="Android" %} +Add your app's **name** and *package name*, Your package name is generally the **applicationId** in your app-level [build.gradle](https://github.com/appwrite/playground-for-flutter/blob/master/android/app/build.gradle#L41) file. + +In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `` tag, along side the existing `` tags in your [AndroidManifest.xml](https://github.com/appwrite/playground-for-flutter/blob/master/android/app/src/main/AndroidManifest.xml). +Be sure to replace the **[PROJECT_ID]** string with your actual Appwrite project ID. +You can find your Appwrite project ID in you project settings screen in your Appwrite Console. + +```xml + + ... + + ... + + + + + + + + + + + +``` +{% /tabsitem %} + +{% tabsitem #linux title="Linux" %} + +Add your app **name** and **package name**. +Your package name is generally the **name** in your [pubspec.yaml](https://github.com/appwrite/playground-for-flutter/blob/master/pubspec.yaml#L1) file. +If you cannot find the correct package name, run the application in Linux and make any request with proper exception handling. +You should get the application ID needed to add in the received error message. + +{% /tabsitem %} + +{% tabsitem #macos title="macOS" %} + +Add your app **name** and **Bundle ID**. You can find your **Bundle Identifier** in the **General** tab for your app's primary target in XCode. + +The Appwrite SDK uses `ASWebAuthenticationSession` on macOS 10.15+ to allow OAuth authentication. You have to change your macOS **Deployment Target** in XCode to be macOS >= 10.15 to be able to build your app for macOS. + +In order to capture the Appwrite OAuth 2 callback url, the following URL scheme needs to added to your `Info.plist`. + +```xml +CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + io.appwrite + CFBundleURLSchemes + + appwrite-callback-[PROJECT_ID] + + + +``` +{% /tabsitem %} + +{% tabsitem #windows title="Windows" %} + +For **Windows**, add your app *name* and *package name*. +Your package name is generally the **name** in your [pubspec.yaml](https://github.com/appwrite/playground-for-flutter/blob/master/pubspec.yaml#L1) file. +If you cannot find the correct package name, run the application in Windows, and make any request with proper exception handling. You should get the application ID needed to add in the received error message. +{% /tabsitem %} + +{% /tabs %} + +![Add a platform](/images/docs/databases/quick-start/add-platform.png) + +You can skip optional steps. + +{% /section %} +{% section #step-2 step=2 title="Create Flutter project" %} +Create a Flutter project. + +```sh +flutter create my_app && cd my_app +``` +{% /section %} + +{% section #step-3 step=3 title="Install Appwrite" %} +Install the Appwrite SDK for Flutter. + +```sh +flutter pub add appwrite +``` + +{% /section %} + +{% section #step-4 step=4 title="Import Appwrite" %} +Find your project's ID in the **Settings** page. + +![Settings page in Appwrite Console.](/images/docs/databases/quick-start/project-id.png) + +Create a new file `lib/appwrite.dart` and add the following code to it, replace `` with your project ID. + +```dart +import 'package:appwrite/appwrite.dart'; + +class Appwrite { + static final Appwrite instance = Appwrite._internal(); + + late final Client client; + late final Account account; + factory Appwrite._() { + return instance; + } + + Appwrite._internal() { + client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject(""); + account = Account(client); + } +} +``` +{% /section %} +{% section #step-5 step=5 title="Create a login page" %} +Add the following code to `src/App.jsx`. +import 'package:appwrite/appwrite.dart'; + +```dart +import 'package:flutter/material.dart'; +import 'package:appwrite/appwrite.dart'; +import 'package:appwrite/models.dart' as models; + +import 'package:my_app/appwrite.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('My App')), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: MyForm(), + ), + ), + ); + } +} + +class MyForm extends StatefulWidget { + @override + MyFormState createState() { + return MyFormState(); + } +} + +class MyFormState extends State { + models.User? loggedInUser; + final TextEditingController emailController = TextEditingController(); + final TextEditingController passwordController = TextEditingController(); + final TextEditingController nameController = TextEditingController(); + + Future login(String email, String password) async { + await Appwrite.instance.account + .createEmailSession(email: email, password: password); + final user = await Appwrite.instance.account.get(); + setState(() { + loggedInUser = user; + }); + } + + Future register(String email, String password, String name) async { + await Appwrite.instance.account.create( + userId: ID.unique(), email: email, password: password, name: name); + await login(email, password); + } + + Future logout() async { + await Appwrite.instance.account.deleteSession(sessionId: 'current'); + setState(() { + loggedInUser = null; + }); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(loggedInUser != null + ? 'Logged in as ${loggedInUser!.name}' + : 'Not logged in'), + SizedBox(height: 16.0), + TextField( + controller: emailController, + decoration: InputDecoration(labelText: 'Email'), + ), + SizedBox(height: 16.0), + TextField( + controller: passwordController, + decoration: InputDecoration(labelText: 'Password'), + obscureText: true, + ), + SizedBox(height: 16.0), + TextField( + controller: nameController, + decoration: InputDecoration(labelText: 'Name'), + ), + SizedBox(height: 16.0), + ElevatedButton( + onPressed: () { + login(emailController.text, passwordController.text); + }, + child: Text('Login'), + ), + ElevatedButton( + onPressed: () { + register(emailController.text, passwordController.text, + nameController.text); + }, + child: Text('Register'), + ), + ElevatedButton( + onPressed: () { + logout(); + }, + child: Text('Logout'), + ), + ], + ); + } +} +``` +{% /section %} + +{% section #step-6 step=6 title="Checkout what you've built" %} +Run your project with `flutter run` and select a browser, platform, or emulator to run your project. +{% /section %} \ No newline at end of file diff --git a/src/routes/docs/quick-starts/react/+page.markdoc b/src/routes/docs/quick-starts/react/+page.markdoc index cd35a56637..9859409d62 100644 --- a/src/routes/docs/quick-starts/react/+page.markdoc +++ b/src/routes/docs/quick-starts/react/+page.markdoc @@ -14,7 +14,7 @@ Head to the [Appwrite Console](https://cloud.appwrite.io/console). If this is your first time using Appwrite, create an accout and create your first project. -Then, under **Add a platform**, add a **Web app**. The **Hostname** should be localhost. +Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `localhost`. ![Add a platform](/images/docs/databases/quick-start/add-platform.png) @@ -59,55 +59,64 @@ export { ID } from 'appwrite'; {% section #step-5 step=5 title="Create a login page" %} Add the following code to `src/App.jsx`. -```html - - - +export default App; ``` {% /section %} {% section #step-6 step=6 title="Checkout what you've built" %} -Run your project with `npm run dev` and open [http://localhost:3000](http://localhost:3000) in your browser. +Run your project with `npm run dev -- --open --port 3000` and open [http://localhost:3000](http://localhost:3000) in your browser. {% /section %} \ No newline at end of file diff --git a/src/routes/docs/quick-starts/sveltekit/+page.markdoc b/src/routes/docs/quick-starts/sveltekit/+page.markdoc index d767b33166..2208fab870 100644 --- a/src/routes/docs/quick-starts/sveltekit/+page.markdoc +++ b/src/routes/docs/quick-starts/sveltekit/+page.markdoc @@ -11,7 +11,7 @@ Head to the [Appwrite Console](https://cloud.appwrite.io/console). If this is your first time using Appwrite, create an accout and create your first project. -Then, under **Add a platform**, add a **Web app**. The **Hostname** should be localhost. +Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `localhost`. ![Add a platform](/images/docs/databases/quick-start/add-platform.png) @@ -100,7 +100,7 @@ Create a new file `src/routes/index.svelte` and add the following code to it. {% /section %} {% section #step-6 step=6 title="Checkout what you've built" %} -Run your project with `npm run dev` and open [http://localhost:3000](http://localhost:3000) in your browser. +Run your project with `npm run dev -- --open --port 3000` and open [http://localhost:3000](http://localhost:3000) in your browser. {% /section %} diff --git a/src/routes/docs/quick-starts/vuejs/+page.markdoc b/src/routes/docs/quick-starts/vuejs/+page.markdoc index 39da5bfe12..5c8bf345c9 100644 --- a/src/routes/docs/quick-starts/vuejs/+page.markdoc +++ b/src/routes/docs/quick-starts/vuejs/+page.markdoc @@ -14,7 +14,7 @@ Head to the [Appwrite Console](https://cloud.appwrite.io/console). If this is your first time using Appwrite, create an accout and create your first project. -Then, under **Add a platform**, add a **Web app**. The **Hostname** should be localhost. +Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `localhost`. ![Add a platform](/images/docs/databases/quick-start/add-platform.png) @@ -109,5 +109,5 @@ const logout = async () => { {% /section %} {% section #step-6 step=6 title="Checkout what you've built" %} -Run your project with `npm run dev` and open [http://localhost:3000](http://localhost:3000) in your browser. +Run your project with `npm run dev -- --open --port 3000` and open [http://localhost:3000](http://localhost:3000) in your browser. {% /section %} diff --git a/src/routes/docs/tutorials/react/+layout.svelte b/src/routes/docs/tutorials/react/+layout.svelte new file mode 100644 index 0000000000..fb9fb3980f --- /dev/null +++ b/src/routes/docs/tutorials/react/+layout.svelte @@ -0,0 +1,10 @@ + + + diff --git a/src/routes/docs/tutorials/react/+layout.ts b/src/routes/docs/tutorials/react/+layout.ts new file mode 100644 index 0000000000..562b11506f --- /dev/null +++ b/src/routes/docs/tutorials/react/+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/react/+page.ts b/src/routes/docs/tutorials/react/+page.ts new file mode 100644 index 0000000000..c026e98b75 --- /dev/null +++ b/src/routes/docs/tutorials/react/+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/react/step-1'); +}; diff --git a/src/routes/docs/tutorials/react/step-1/+page.markdoc b/src/routes/docs/tutorials/react/step-1/+page.markdoc new file mode 100644 index 0000000000..3a46e1177d --- /dev/null +++ b/src/routes/docs/tutorials/react/step-1/+page.markdoc @@ -0,0 +1,31 @@ +--- +layout: tutorial +title: Introduction +description: This is the description used for SEO. +step: 1 +difficulty: easy +readtime: 10 +--- + +**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 React. + +[TODO: Image] + +You can follow along with a fresh repo or [clone the project on GitHub](#). + +## Concepts {% #concepts %} + +This tutorial will introduce the following concepts: + +1. Setting up your first project +2. Authentication +3. Databases and collections +4. Queries and pagination +5. Storage + + +## Prerequisites {% #prerequisites %} + +1. Basic knowledge of JavaScript and React. +2. Have [Node.js](#) and [NPM](#) installed on your computer \ No newline at end of file diff --git a/src/routes/docs/tutorials/react/step-2/+page.markdoc b/src/routes/docs/tutorials/react/step-2/+page.markdoc new file mode 100644 index 0000000000..d166dfceb0 --- /dev/null +++ b/src/routes/docs/tutorials/react/step-2/+page.markdoc @@ -0,0 +1,28 @@ +--- +layout: tutorial +title: Create app +description: This is the description used for SEO. +step: 2 +--- + +## Create React project {% #create-react-project %} + +Create a React app with the `npm create` command. + +```sh +npm create vite@latest --template react ideas-tracker && cd ideas-tracker +``` + +## Add dependencies {% #add-dependencies %} + +Install the JavaScript Appwrite SDK. + +```sh +npm install appwrite +``` + +You can start the development server to watch your app update in the browser as you make changes. + +```sh +npm run dev -- --open --port 3000 +``` \ No newline at end of file diff --git a/src/routes/docs/tutorials/react/step-3/+page.markdoc b/src/routes/docs/tutorials/react/step-3/+page.markdoc new file mode 100644 index 0000000000..50c9fa0f4c --- /dev/null +++ b/src/routes/docs/tutorials/react/step-3/+page.markdoc @@ -0,0 +1,42 @@ +--- +layout: tutorial +title: Set up Appwrite +description: This is the description used for SEO. +step: 3 +--- + +## Create project {% #create-project %} + +Head to the [Appwrite Console](https://cloud.appwrite.io/console). + +![Create project screen](/images/docs/databases/quick-start/create-project.png) + +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. + +![Add a platform](/images/docs/databases/quick-start/add-platform.png) + +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. + +![Settings page in Appwrite Console.](/images/docs/databases/quick-start/project-id.png) + +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. + +```js +import { Client } from "appwrite"; + +const client = new Client(); +client + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject(""); // Replace with your project IDxw + +export const account = new Account(client); +export const database = new Database(client); +``` \ No newline at end of file diff --git a/src/routes/docs/tutorials/react/step-4/+page.markdoc b/src/routes/docs/tutorials/react/step-4/+page.markdoc new file mode 100644 index 0000000000..5551c802b2 --- /dev/null +++ b/src/routes/docs/tutorials/react/step-4/+page.markdoc @@ -0,0 +1,185 @@ +--- +layout: tutorial +title: Add authentication +description: This is the description used for SEO. +step: 4 +--- + +## User context + +In React, you can use [context](https://reactjs.org/docs/context.html) to share data between components. +We'll use context and a custom hook to manage our user's data. + +Create a new file `src/lib/context/user.jsx` and add the following code to it. + +```js +import { createContext, useContext, useEffect, useState } from "react"; +import { account } from "../appwrite"; + +const UserContext = createContext(); + +export function useUser() { + return useContext(UserContext); +} + +export function UserProvider(props) { + const [user, setUser] = useState(null); + + async function login(email, password) { + const loggedIn = await account.createEmailSession(email, password); + setUser(loggedIn); + } + + async function logout() { + await account.deleteSession("current"); + setUser(null); + } + + async function register(email, password) { + await account.create(email, password); + await login(email, password); + } + + async function init() { + try { + const loggedIn = await account.get(); + setUser(loggedIn); + } catch (err) { + setUser(null); + } + } + + useEffect(() => { + init(); + }, []); + + return ( + + {props.children} + + ); +} +``` + +Now, we can use the `useUser` hook to access the user's data from any component. However, we first need to wrap our app with the `UserProvider`. + +## Basic routing + +First, wrap the `main` element with the `UserProvider` component. + +Update `src/App.jsx` to the following code. + +```jsx +import { Home } from "./pages/Home"; +import { UserProvider } from "./lib/context/user"; + +function App() { + const isLoginPage = window.location.pathname === "/login"; + + return ( +
+ +
Home page
+
+
+ ); +} + +export default App; +``` + +Then, optionally render the `Login` component if the path is `/login`, otherwise render the `Home` component. + +Update `src/App.jsx` to the following code. + +```jsx +import { Login } from "./pages/Login"; +import { Home } from "./pages/Home"; +import { UserProvider } from "./lib/context/user"; + +function App() { + const isLoginPage = window.location.pathname === "/login"; + + return ( +
+ +
{isLoginPage ? : }
+
+
+ ); +} + +export default App; +``` + +## Home page + +Create a new file `src/pages/Home.jsx` and add the following stub code to it. + +```jsx +// We'll complete this component later +export function Home() { + return ( +

I'm the home page

+ ); +} +``` + +## Login page + +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. + +Create a new file `src/pages/Login.jsx` and add the following code to it. + +```jsx +import { useState } from "react"; +import { useUser } from "../lib/context/user"; + +export function Login() { + const user = useUser(); + + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + + return ( +
+

Login or register

+
+ { + setEmail(event.target.value); + }} + /> + { + setPassword(event.target.value); + }} + /> +
+ + +
+
+
+ ); +} +``` + diff --git a/src/routes/docs/tutorials/react/step-5/+page.markdoc b/src/routes/docs/tutorials/react/step-5/+page.markdoc new file mode 100644 index 0000000000..709163abc2 --- /dev/null +++ b/src/routes/docs/tutorials/react/step-5/+page.markdoc @@ -0,0 +1,57 @@ +--- +layout: tutorial +title: Add navigation +description: This is the description used for SEO. +step: 5 +difficulty: easy +readtime: 10 +--- + +In our app we want to have a navigation bar that is always visible. We will add it to the `App` component and use the `useUser` hook to show either: +- a logout button if the user is logged in. +- a login button if the user is not logged in. + +Update the App componenent in `src/App.jsx`: + +```jsx +import { Login } from "./pages/Login"; +import { Home } from "./pages/Home"; +import { UserProvider, useUser } from "./lib/context/user"; + +function App() { + const isLoginPage = window.location.pathname === "/login"; + + return ( +
+ + {/* Add the navbar before page content */} +
{isLoginPage ? : }
+
+
+ ); +} + +function Navbar() { + const user = useUser(); + + return ( + + ); +} + +export default App; +``` diff --git a/src/routes/docs/tutorials/react/step-6/+page.markdoc b/src/routes/docs/tutorials/react/step-6/+page.markdoc new file mode 100644 index 0000000000..fc1783ea81 --- /dev/null +++ b/src/routes/docs/tutorials/react/step-6/+page.markdoc @@ -0,0 +1,79 @@ +--- +layout: tutorial +title: Add database +description: This is the description used for SEO. +step: 6 +difficulty: easy +readtime: 10 +--- +## 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. + +![Create collection screen](#TODO update me) + +Create a new collection with the following attributes: +| Field | Type | Required | +|-------------|--------|----------| +| userId | String | Yes | +| title | String | Yes | +| description | String | No | + +## Ideas context + +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 React context to hold our ideas. +Create a new file `src/lib/context/ideas.jsx` and add the following code to it. + +```js +import { createContext, useContext, useEffect, useState } from "react"; +import { databases } from "../appwrite"; +import { ID, Query } from "appwrite"; + +export const IDEAS_DATABASE_ID = ""; // Replace with your database ID +export const IDEAS_COLLECTION_ID = ""; // Replace with your collection ID + +const IdeasContext = createContext(); + +export function useIdeas() { + return useContext(IdeasContext); +} + +export function IdeasProvider(props) { + const [ideas, setIdeas] = useState([]); + + async function add(idea) { + const response = await databases.createDocument( + IDEAS_DATABASE_ID, + IDEAS_COLLECTION_ID, + ID.unique(), + idea + ); + setIdeas((ideas) => [response.$id, ...ideas].slice(0, 10)); + } + + async function remove(id) { + await databases.deleteDocument(IDEAS_DATABASE_ID, IDEAS_COLLECTION_ID, id); + setIdeas((ideas) => ideas.filter((idea) => idea.$id !== id)); + await init(); // Refetch ideas to ensure we have 10 items + } + + async function init() { + const response = await databases.listDocuments( + IDEAS_DATABASE_ID, + IDEAS_COLLECTION_ID, + [Query.orderDesc("$createdAt"), Query.limit(10)] + ); + setIdeas(response.documents); + } + + useEffect(() => { + init(); + }, []); + + return ( + + {props.children} + + ); +} +``` + diff --git a/src/routes/docs/tutorials/react/step-7/+page.markdoc b/src/routes/docs/tutorials/react/step-7/+page.markdoc new file mode 100644 index 0000000000..fa6db81157 --- /dev/null +++ b/src/routes/docs/tutorials/react/step-7/+page.markdoc @@ -0,0 +1,83 @@ +--- +layout: tutorial +title: Create ideas page +description: This is the description used for SEO. +step: 7 +difficulty: easy +readtime: 10 +--- + +Using the `useIdeas` hook we can now display the ideas on the page. We will also add a form to submit new ideas. + +Overwrite the contents of `src/pages/Home.jsx` with the following: + +```jsx +import { useState } from "react"; +import { useUser } from "../lib/context/user"; +import { useIdeas } from "../lib/context/ideas"; + +export function Home() { + const user = useUser(); + const ideas = useIdeas(); + + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + + return ( + <> + {/* Show the submit form to logged in users. */} + {user.current ? ( +
+

Submit Idea

+
+ { + setTitle(event.target.value); + }} + /> + + +
+
+

Please login to submit an idea.

+ +
+

Latest Ideas

+
    +
  • + {{ idea.title }} +

    {{ idea.description }}

    + +
  • +
+
+ +``` \ 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 new file mode 100644 index 0000000000..9c5af3c44c --- /dev/null +++ b/src/routes/docs/tutorials/vue/step-8/+page.markdoc @@ -0,0 +1,14 @@ +--- +layout: tutorial +title: Next steps +description: This is the description used for SEO. +step: 8 +difficulty: easy +readtime: 10 +--- + +## 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. + +## Add style {% #add-style %} +If you want to see a version of this project, complete with CSS styles, clone [this GitHub repository](). \ No newline at end of file diff --git a/static/images/docs/databases/quick-start/project-id.png b/static/images/docs/databases/quick-start/project-id.png index 5f14d12ebe..1849efa695 100644 Binary files a/static/images/docs/databases/quick-start/project-id.png and b/static/images/docs/databases/quick-start/project-id.png differ