diff --git a/app/views/docs/admin.phtml b/app/views/docs/admin.phtml index 7cc3a2c64..b0ef020e8 100644 --- a/app/views/docs/admin.phtml +++ b/app/views/docs/admin.phtml @@ -1,6 +1,6 @@
The Appwrite API has two different modes it can use, the first mode is the client mode, which is the default mode, and the second one is the admin or server mode.
-When using Appwrite from the client-side, you should go with the normal default mode. This mode allows every user of your project to access only resources he has granted access to. When running in admin mode, you remove Appwrite default access restriction and ultimately allow access to any of the resources available on your Appwrite project (files, documents, or collections).
+When using Appwrite from the client-side, you should go with the normal default mode. This mode allows every user of your project to access only resources they have been granted access to. When running in admin mode, you remove Appwrite default access restriction and ultimately allow access to any of the resources available on your Appwrite project (files, documents, or collections).
For security reasons, the admin mode only works in combination with an API key. You can create an API key from the Appwrite console, and you can choose what scopes of access you are willing to grant your SDK.
diff --git a/app/views/docs/architecture.phtml b/app/views/docs/architecture.phtml index 675692c23..c509624a8 100644 --- a/app/views/docs/architecture.phtml +++ b/app/views/docs/architecture.phtml @@ -21,7 +21,7 @@ $image = new View(__DIR__.'/../general/image.phtml');The Appwrite architecture allows to monitor and detect how the different microservices perform efficiently. Each microservice has its own usage metrics and logs to allow you to debug or scale it quickly. Using Docker, you can also limit the resource usage (CPU, Memory, Swap) by specific services.
Each service in the stack has a specific type of workload he has to handle, like sending emails, executing cloud functions or logging user activity. All the heavy lifting workloads are delegated from the API service to the background workers consuming messages in an event-driven way from the Appwrite pub/sub mechanism (implemented using Redis). Using this design, we make sure the Appwrite API is fast, responsive and has to handle only critical sync operations as appropriate for a request->response based service that should respond as fast as possible for minimum latency.
+Each service in the stack has a specific type of workload it has to handle, like sending emails, executing cloud functions or logging user activity. All the heavy lifting workloads are delegated from the API service to the background workers consuming messages in an event-driven way from the Appwrite pub/sub mechanism (implemented using Redis). Using this design, we make sure the Appwrite API is fast, responsive and has to handle only critical sync operations as appropriate for a request->response based service that should respond as fast as possible for minimum latency.
To create a new document in an existing collection, use the `createDocument` command.
appwrite databases createDocument --collectionId --documentId 'unique()' --data '{ "Name": "Iron Man" }' --read role:all team:abc
+appwrite databases createDocument --collectionId --documentId 'unique()' --data '{ "Name": "Iron Man" }' --permissions 'read("any")' 'write("team:abc")'
You can create your database by adding it to your Appwrite project's dashboard. Access the Databases Service settings from your project's left-hand navigation panel. - To create a new database, click the click the Add Database button. Name your new database and optionally provide a custom database ID instead of a randomly generated one. + To create a new database, click the Add Database button. Name your new database, and optionally provide a custom database ID.
@@ -33,25 +33,14 @@
- Once you create your collection, you will reach your collection's settings page, where you can choose the permission model for your collection. There are two types of permissions models available, each one with different pros and cons designed to be flexible to best match your use case. + Appwrite provides permissions to restrict access to documents at two levels, document and collection level. When a user has the appropriate type of access permissions granted at either the document or the collection level, they will be able to access or change the document. If the permission field is left empty, Client SDKs cannot access the document.
- With this permission model, you have granular access control over every document, and users will only be able to access documents for which they have explicit permissions. Document permissions are required in this permission model, and collection permissions are optional. -
+Document level permissions grant access to individual documents. Document level permissions are only applied if Document Security is enabled in the settings of your collection.
- With collection-level permissions, you assign permissions once for every document in the collection's settings - users with "read" access to the collection can see all documents in that collection. This permission model requires you to set collection permissions on the collection settings page. Document permissions are optional and will not be evaluated even when set. -
- -For security purposes, an active Account session is required to create resources. So, even if wildcard write permissions are set, only logged-in users can create documents in a collection. If you require this behavior for your app, create an anonymous session first. An active session helps Appwrite enforce rate-control limits and protect your projects from intensive write operations.
-Collection level permissions apply to every document in the collection.
@@ -211,7 +200,7 @@ func main() async throws {
You can only query correctly indexed queries. You can easily add new indexes from both the Appwrite console or one of the server SDKs. Appwrite uses this limitation to enforce optimized queries for maximum performance and scalability of your collection. You can learn more about it on the Appwrite Indexes section.
+You can only query indexed attributes. You can easily add new indexes from both the Appwrite console or any of the server SDKs. Appwrite uses this limitation to enforce optimized queries for maximum performance and scalability of your collection. You can learn more about it in the Appwrite Indexes section.
To find specific documents in a collection, pass an array of query strings as a parameter to the listDocuments endpoint. The SDKs provide a Query class to make query building simpler: @@ -301,42 +290,80 @@ func main() async throws{ -
The following operators are currently supported:
+The following query methods are currently supported:
| Operator | +Query Method | +SDK Method Example | Description | |
|---|---|---|---|---|
| equal | -Equal to. | +Query.equal("title", ["Iron Man"]) | +Returns document if attribute is equal to any value in the provided array. Applies to any indexed attribute. | |
| notEqual | -Not equal to. | +Query.notEqual("title", ["Iron Man"]) | +Returns document if attribute is not equal to any value in the provided array. Applies to any indexed attribute. | |
| lesser | -Lesser than. | +lessThan | +Query.lessThan("score", 10) | +Returns document if attribute is less than the provided value. Applies to any indexed attribute. |
| lesserEqual | -Less than or equal to. | +lessThanEqual | +Query.lessThanEqual("score", 10) | +Returns document if attribute is less than or equal to the provided value. Applies to any indexed attribute. |
| greater | -Greater than. | +greaterThan | +Query.greaterThan("score", 10) | +Returns document if attribute is greater than the provided value. Applies to any indexed attribute. |
| greaterEqual | -Greater than or equal to. | +greaterThanEqual | +Query.greaterThanEqual("score", 10) | +Returns document if attribute is greater than or equal to the provided value. Applies to any indexed attribute. |
| search | -Requires a Fulltext Index. | +Query.search("text", "key words") | +Searches string attributes for provided keywords. Applies to any string attribute with a full-text index. | +|
| orderDesc | +Query.orderDesc("attribute") | +Orders results in descending order by attribute. Attribute must be indexed. Pass in an empty string to return in natural order. | +||
| orderAsc | +Query.orderAsc("attribute") | +Orders results in ascending order by attribute. Attribute must be indexed. Pass in an empty string to return in natural order. | +||
| limit | +Query.limit(25) | +Limits the number of results returned by the query. Used for pagination. | +||
| offset | +Query.offset(0) | +Offset the results returned by skipping some of the results. Used for pagination. | +||
| cursorAfter | +Query.cursorAfter("62a7...f620") | +Places the cursor after the specified resource ID. Used for pagination. | +||
| cursorBefore | +Query.cursorBefore("62a7...a600") | +Places the cursor before the specified resource ID. Used for pagination. |
When performing a query against multiple attributes, a single index with all queries attributes is required. In the example above, a single index with both title and year is queried.
+When performing a query against multiple attributes, a single index with all query attributes is required. In the example above, a single index with both title and year is required.
@@ -473,10 +500,7 @@ func main() async throws {
When querying using the listDocuments endpoint, you can specify the order of the documents returned by providing the orderAttributes and orderTypes parameters. The results will be sorted by $id (create date) in ascending order when no order parameters are provided.
- -The parameter orderAttributes takes a string array of attributes IDs. The orderTypes parameter takes a string array equal in length to orderAttributes that indicate if each attribute should be sorted in ascending or descending order. Ascending and descending is denoted as "ASC" and "DESC" respectively.
- +When querying using the listDocuments endpoint, you can specify the order of the documents returned using the "Query.orderAsc()" and "Query.orderDesc()" query methods.
Appwrite Functions allow you to extend and customize your Appwrite server functionality by executing your custom code. Appwrite can execute your custom code in response to any Appwrite system event like account creation, user login, or document update. You can also schedule your functions to run according to a CRON schedule or start them manually by triggering your function from an HTTP endpoint using the Appwrite client or server APIs.
+Appwrite Functions allow you to extend and customize your Appwrite server functionality by executing your custom code. Appwrite can execute your custom code in response to any Appwrite system event like account creation, user login, or document update. You can also schedule your functions to run according to a CRON schedule or start them manually by triggering your function from an HTTP endpoint using the Appwrite client or server APIs.
Appwrite Functions run in a secure, isolated Docker container. By default, Appwrite supports multiple runtimes for different languages that you can use to run your code.
@@ -531,7 +531,7 @@ $image = new View(__DIR__.'/../general/image.phtml'); ->render(); ?> -To execute a function from the Appwrite console, click the 'Execute Now' button on your function's overview page. To execute a function from the API, send a POST request to the function execution endpoint.
+To execute a function from the Appwrite console, click the 'Execute Now' button on your function's overview page. To execute a function from the API, send a POST request to the function execution endpoint.
The function execution endpoint is available from both Appwrite client and server APIs. To execute your function from the server API, you need an API key with 'execution.write' scope.
@@ -830,9 +830,9 @@ class MainActivity : AppCompatActivity() {You can integrate Appwrite Functions with other Appwrite services by using the appropriate Server SDK for your runtime. You can find starter code for your function's runtime in the Appwrite Function Starter repository.
+You can integrate Appwrite Functions with other Appwrite services by using the appropriate Server SDK for your runtime. You can find starter code for your function's runtime in the Appwrite Function Starter repository.
-To initialize a Server SDK in a function, you need to provide your Appwrite project's endpoint and an API key as variables in the Settings tab of your Function. The ID of your Appwrite project is passed in automatically as APPWRITE_FUNCTION_PROJECT_ID.
+To initialize a Server SDK in a function, you need to provide your Appwrite endpoint and an API key in the Variables tab of your Function. The ID of your Appwrite project is passed in automatically as APPWRITE_FUNCTION_PROJECT_ID.
import { Databases } from "appwrite";
+ import { Databases, Query } from "appwrite";
const databases = new Databases(client, "[DATABASE_ID]"); // 'client' comes from setup
// Page 1
-const page1 = await databases.listDocuments('movies', [], 25, 0);
+const page1 = await databases.listDocuments('movies', [Query.limit(25), Query.offset(0)]);
// Page 2
-const page2 = await databases.listDocuments('movies', [], 25, 25);
+const page2 = await databases.listDocuments('movies', [Query.limit(25), Query.offset(25)]);
import { Databases } from "appwrite";
+ import { Databases, Query } from "appwrite";
const databases = new Databases(client, "[DATABASE_ID]"); // 'client' comes from setup
// Page 1
-const page1 = await databases.listDocuments('movies', [], 25, 0);
+const page1 = await databases.listDocuments('movies', [Query.limit(25)]);
const lastId = results.documents[results.documents.length - 1].$id;
// Page 2
-const page2 = await databases.listDocuments('movies', [], 25, 0, lastId);
+const page2 = await databases.listDocuments('movies', [Query.limit(25), Query.cursorAfter(lastId)]);
Appwrite permission mechanism offers a simple and yet flexible way to manage which users, teams, or roles can access a specific resource of your project, like documents and files.
+Appwrite permission mechanism offers a simple, yet flexible way to manage which users, teams, or roles can access a specific resource in your project, like documents and files.
-Using permissions, you can decide that only user A and user B will have read access to a specific database document, while user C and team X will be the only ones with write access.
+p>Using permissions, you can decide that only user A and user B will have read and update access to a specific database document, while user C and team X will be the only ones with delete access. -As the name suggests, read permission will allow users and teams to view a resource while with write permission, they will be able to both update or delete it.
+As the name suggests, read permission allows a user to read a resource, create allows users to create new resources, update allows a user to make changes to a resource, and delete allows the user to remove the resource.
-Read and write permissions can be given to specific users, entire teams, or only to a particular group of role members inside a team.
+All permissions can be granted to individuals or groups of users, entire teams, or only to team members with a specific role. Permission can also be granted based on authentication status such as to all users, only authenticated users, or only guest users.
-A project user can only grant a resource with permissions he or she owns. For example, if a user is trying to share a document with a team, he or she are not members of, they will encounter a 401 not authorized error.
+A project user can only grant a resource with permissions that they own. For example, if a user is trying to share a document with a team that they are not a member of, they will encounter a 401 not authorized error. If your app needs users to grant access to teams they're not a member of, you can create Appwrite Functions with a Server SDK to achieve this functionality.
An Appwrite resource can be a database collection, database document, or a storage file. Each resource has both read and write permissions to define who can access it.
- -Using the Appwrite permissions mechanism, you can share resources between users, teams, and members with different roles.
+An Appwrite resource can be a database, collection, document, bucket, or file. Each resource has its own set of permissions to define who can interact with it.
+ +Using the Appwrite permissions mechanism, you can grant resource access to users, teams, and members with different roles.
When not providing a resource with read or write permissions, the default value will be empty. When a read or write permissions is missing, no one will be granted access control to the resource.
-You will need an active session to handle database transactions for your collections.
-If you have rules where you allow for wild cards or role:guest in a collection, you can create an Anonymous Session before you make the API call.
-A server or admin integration can be used for increased flexibility. When using a server integration in combination with the proper API scopes, you can have both read and write access to any of your project resources regardless of their permissions.
+A server or admin integration can be used for increased flexibility. When using a Server SDK in combination with the proper API key scopes, you can have any type of access to any of your project resources regardless of their permissions.
Using the server integration flexibility, you can change resource permissions, share resources between different users and teams, or edit and delete them without any limitations.
-In Client and Server SDKs, you will find a Permission class with helper methods for each role described below.
|
- role:all
- version >= 0.12 - |
- Wildcard permission. Gives anyone read or write access. | +Permission.read() | +Access to read a resource. |
| user:[USER_ID] | -Access to a specific user by his UID. | +Permission.create() | +Access to create new resources. Does not apply to files or documents. Applying this type of access to files or documents results in an error. |
| team:[TEAM_ID] | -Access to any member of the specific team. To gain access to this permission, the user must be the team creator (owner), or receive and accept an invitation to join this team. | +Permission.update() | +Access to change a resource, but not remove or create new resources. Does not apply to functions. |
| team:[TEAM_ID]/[ROLE] | -Access to any member who possesses a specific role in a team. To gain access to this permission, the user must be a member of the specific team and have the given role assigned to him or her. Team roles can be assigned when inviting a user to become a team member. | +Permission.delete() | +Access to remove a resource. Does not apply to functions. |
| member:[MEMBER_ID] | -Access to a specific member of a team. Unlike the basic user permission, this permission will only be valid as long as the user is still an active member of the specific team. To view user member ID, fetch the team members list. | +Permission.write() | +Alias to grant create, update, and delete access for collections and buckets and update and delete access for documents and files. |
In Client and Server SDKs, you will find a Role class with helper methods for each role described below.
+|
- role:guest
- version >= 0.7 - |
- Access to any guest user. Logged in users don't have access to this role. | +Type | +Description | +
| Role.any() | +Grants access to anyone. | +||
| Role.guests() | +Grants access to any guest user without a session. Authenticated users don't have access to this role. | +||
| Role.users() | +Grants access to any authenticated or anonymous user. | +||
| Role.user([USER_ID]) | +Grants access to a specific user by user ID. | ||
|
- role:member
- version >= 0.7 - |
- Access to any logged in user. A logged in user is a user with a valid session. Logged in users don't have access to `role:guest` role. For wildcard access use `*` role. | +Role.team([TEAM_ID]) | +Grants access to any member of the specific team. To gain access to this permission, the user must be the team creator (owner), or receive and accept an invitation to join this team. |
|
- *
- version <= 0.11 (deprecated) - |
- Wildcard permission. Gives anyone read or write access. | +Role.team([TEAM_ID], [ROLE]) | +Grants access to any member who possesses a specific role in a team. To gain access to this permission, the user must be a member of the specific team and have the given role assigned to them. Team roles can be assigned when inviting a user to become a team member. |
In the following example, we are creating a document that can be read by everyone and only be edited, or deleted by a user with a UID user:5c1f88b42259e.
+In the following example, we are creating a document that can be read by anyone, edited by writers or admins, and deleted by administrators or a user with the user ID user:5c1f88b42259e.
import { Client, Databases } from "appwrite";
+ import { Client, Databases, Permission, Role } from "appwrite";
const client = new Client();
@@ -123,27 +119,30 @@ client
const databases = new Databases(client, '[DATABASE_ID]');
let promise = databases.createDocument(
- '[COLLECTION_ID]',
- {'actorName': 'Chris Evans', 'height': 183},
- ['role:all'], // Anyone can view this document
- ['user:5c1f88b42259e'] // You can only grant permissions you own, this must be the current user UID
+ '[COLLECTION_ID]', // Collection ID
+ {'actorName': 'Chris Evans', 'height': 183}, // Data
+ [ // Permissions
+ Permission.read(Role.any()), // Anyone can view this document
+ Permission.update(Role.team("writers")), // Writers can update this document
+ Permissions.update(Role.team("admin")), // Admins can update this document
+ Permission.delete(Role.user("5c1f88b42259e")) // User 5c1f88b42259e can delete this document
+ Permission.delete(Role.team("admin")) // Admins can delete this document
+ ]
);
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
-});
-
-
+});
In the following example, we are creating a document that can be read-only by members of team:5c1f88b87435e and can only be edited, or deleted by members of the same team that possesses the role owner.
+In the following example, we are creating a document that can be read by members of the team with ID 5c1f88b87435e and can only be edited or deleted by members of the same team that possess the team role owner.
import { Client, Databases } from "appwrite";
+ import { Client, Databases, Permission, Role } from "appwrite";
const client = new Client();
@@ -156,68 +155,16 @@ const databases = new Databases(client, '[DATABASE_ID]');
let promise = databases.createDocument(
'[COLLECTION_ID]',
{'actorName': 'Chris Evans', 'height': 183},
- ['team:5c1f88b87435e'], // The user must be a team member to grant this permission
- ['team:5c1f88b87435e/owner']); // The user must be a team owner to grant this permission
+ [
+ Permission.read(Role.team("5c1f88b87435e")), // Only users of team 5c1f88b87435e can read the document
+ Permission.update(Role.team("5c1f88b87435e", "owner")), // Only users of team 5c1f88b87435e with the role owner can update the document
+ Permission.delete(Role.team("5c1f88b87435e", "owner") // Only users of team 5c1f88b87435e with the role owner can delete the document
+ ]
+);
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
-});
-
-
-All subscriptions are secured by the permissions offered by Appwrite, meaning a user will only receive updates to resources to which he has read permission.
-Using role:all on read permissions will allow any client to receive updates.
+All subscriptions are secured by the permissions system offered by Appwrite, meaning a user will only receive updates to resources they have permission to access.
+Using Role.any() on read permissions will allow any client to receive updates.
To access this route, init your SDK with your project unique ID and API Key secret token. Make sure your API Key is granted with access to the "" permission scope. You can also authenticate using a valid JWT and perform actions on behalf of your user.
+To access this route, init your SDK with your project unique ID and an API Key. Make sure your API Key is created with the "" scope. You can also authenticate using a valid JWT and perform actions on behalf of your user.
-To access this route, init your SDK with your project unique ID and API Key secret token. Make sure your API Key is granted with access to the "" permission scope.
+To access this route, init your SDK with your project unique ID and an API Key. Make sure your API Key is create with the "" scope.
To access this route, init your SDK with your project unique ID and a valid JWT. Using the JWT authentication you will be able to perform API actions on behalf of your user.
diff --git a/app/views/docs/storage.phtml b/app/views/docs/storage.phtml index 788c67d5d..d2fc3ef56 100644 --- a/app/views/docs/storage.phtml +++ b/app/views/docs/storage.phtml @@ -13,24 +13,18 @@As buckets are very similar to collections we have in the database, we have a similar permission model. Buckets support either bucket level permission or file level permission to allow different ways to manage access to your buckets and files. Check out the Permissions documentation to learn more about the permissions types available.
+The Storage Service allows you to configure permissions at both the bucket level and the file level. When a user has the appropriate type of access permissions granted at **either** the bucket or the file level, they will be able to access the file. If the permission field is left empty, no one can access the file.
-With this permission model, you have granular access control over every file, and users will only be able to access files for which they have explicit permissions. This permission model requires file permissions, and bucket permissions are optional. +
File level permissions grant access to individual files. File level permissions are only enabled if File Security is enabled in the settings of your bucket.
-With bucket-level permissions, you assign permissions once for every file in the buckets' settings - users with "read" access to the bucket can see all files in that bucket. This permission model requires you to set bucket permissions on the bucket settings page. File permissions are optional and will not be evaluated even when set.
- -For security purposes, an active Account session is required to create resources. So, even if wildcard write permissions are set, only logged-in users can create files in a bucket. If you require this behavior for your app, create an anonymous session first. An active session helps Appwrite enforce rate-control limits and protect your projects from intensive write operations.
-Bucket level permissions apply to every file in the bucket.
Unlike collections, storage buckets have more configuration options regarding the type and size of the files in the bucket, encryption, and anti-virus scanning. If you look at the bucket settings or the REST API example above, you can find these configurations. Let's look at what those are:
+Storage buckets have many configuration options, including the type and maximum size of files in the bucket, whether encryption or anti-virus is enabled, and the compression algorithm to use. If you look at the bucket settings or the REST API example above, you can find these configurations. Let's look at what those are: