First commit

This commit is contained in:
2025-12-25 11:16:59 +01:00
commit 0c5ca09a63
720 changed files with 329234 additions and 0 deletions

215
Permissions.md Normal file
View File

@@ -0,0 +1,215 @@
# Permissions: Groups, Scopes, Authorization Rules
In Unify, the **permissions system** is designed to give you full control over who can **read**, **write**, or **delete** data, while allowing you to enforce security at various levels of the application.
Unify offers a **flexible**, **declarative** approach to managing permissions across different objects, allowing you to define **authorization rules** based on:
* **User Groups** (e.g., admin, guest, member)
* **Scopes** (e.g., a column, a table, or an entire resource)
* **Actions** (e.g., READ, WRITE, DELETE)
## 1. Groups: Defining User Roles
In Unify, **Groups** represent user roles, and each group has certain **permissions** associated with it. These groups can be used to control access at various levels, such as:
* Viewing data
* Editing data
* Deleting data
### Example: Defining Groups
```js
import groups from '/user/group/user.group.permission.js';
export default class user extends table {
username = new username();
email = new email();
groups = new groups(); // Associate user with groups
}
```
### Common Use Case
For instance, you might have:
* **Visitor**: Can only **read** public information
* **Member**: Can **read** and **write** content
* **Admin**: Can perform all actions, including **delete**
You can easily enforce these permissions using:
```js
permission() {
this.allow(groups.visitor, "READ"); // Visitors can read
this.allow(groups.member, "READ"); // Members can read
this.allow(groups.member, "WRITE"); // Members can write
this.allow(groups.admin, "READ"); // Admins can read
this.allow(groups.admin, "WRITE"); // Admins can write
this.allow(groups.admin, "DELETE"); // Admins can delete
}
```
---
## 2. Scopes: Fine-Grained Permission Control
**Scopes** allow you to define permissions not just for entire tables or models, but for **specific fields** or **columns** within those models.
For example, a user might be allowed to **read** all the data but only **edit** a certain field, such as a profile description or a specific product attribute.
### Example: Scope-Based Permissions
```js
permission() {
// Allow "member" group to read all users but only update email
this.allow(groups.member, "READ");
this.allow(groups.member, "WRITE", "email"); // Allow update on email only
this.allow(groups.admin, "READ");
this.allow(groups.admin, "WRITE");
this.allow(groups.admin, "DELETE");
}
```
In this example:
* **Members** can **read** all data but only **update** the `email` field.
* **Admins** have full access (can **read**, **write**, and **delete** all fields).
You can also control **views** or **actions** like **deleting** based on a particular column or resource.
---
## 3. Authorization Rules: Controlling Access
**Authorization rules** are how you declare which groups have what types of access to your tables, fields, or methods. These rules govern **what actions** a group can perform on **what objects**.
You can define rules for specific actions such as:
* **READ**: View data
* **WRITE**: Modify data
* **DELETE**: Remove data
Each object can implement an associated **`permission()`** method to specify which group can perform what action on the object.
### Example: Implementing Authorization Rules
```js
export default class news extends table {
title = new title();
body = new body();
permission() {
this.allow(groups.visitor, "READ"); // Visitors can read the news
this.allow(groups.member, "WRITE"); // Members can write/edit news
this.allow(groups.admin, "READ"); // Admins can read
this.allow(groups.admin, "WRITE"); // Admins can write
this.allow(groups.admin, "DELETE"); // Admins can delete
}
}
```
---
## 4. Implementing Permissions in `node` Methods
In addition to controlling UI elements like columns, you may want to enforce permissions when executing actions on the server (such as creating, updating, or deleting records). This is where **manual permission checks** come into play.
### Example: Using Permissions in `node` Methods
```js
node async deleteRow(client) {
const user = client.user;
// Check if the user has permission to delete
if (!user.hasPermission("DELETE_NEWS")) {
throw new Error("Permission denied: User cannot delete");
}
this.delete(); // Perform the delete action
}
```
In this example, the `deleteRow` method checks whether the **current user** has permission to delete the record. If they do not, it throws an error and prevents the action.
---
## 5. Permissions with Collections
Since collections may contain multiple rows (or objects), you may also need to control access at the **collection level**. This allows you to define permissions that apply across the entire dataset.
### Example: Permissions for Collection
```js
export default class newsListTableBody extends renderCollection, gridViewBody {
permission() {
this.allow(groups.visitor, "READ"); // Visitors can read all news in the collection
this.allow(groups.member, "WRITE"); // Members can write new news items
this.allow(groups.admin, "DELETE"); // Admins can delete news items
}
}
```
This ensures that each row in the collection respects the users permissions when they try to **view**, **create**, **update**, or **delete** entries.
---
## 6. Combining Permissions with UI
In Unify, you **don't** have to manually manage every UI element (such as showing or hiding a button) based on permissions. You can use the `permission()` method to dynamically control UI elements' visibility and accessibility by the roles assigned.
For instance:
```js
node async click() {
if (this.user.hasPermission("EDIT_NEWS")) {
this.showEditForm();
} else {
throw new Error("Permission denied: Cannot edit news");
}
}
```
You can pair the **permissions check** with UI changes to ensure users can only interact with elements they are authorized to use.
---
## 7. Custom Authorization Logic
You can also write custom authorization logic, such as role hierarchies (where one group has broader permissions than another).
### Example: Custom Authorization
```js
node async deleteRow(client) {
const user = client.user;
// Only admin or user who created the news can delete it
if (!(user.hasPermission("DELETE_NEWS") || this.createdBy === user.id)) {
throw new Error("Permission denied: User cannot delete this news item");
}
this.delete(); // Proceed to delete if authorized
}
```
This custom rule checks whether the **current user** is an **admin** or the **creator** of the news item before allowing them to delete it.
---
## Summary of Permissions System
| Element | Description |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **Groups** | Roles that define the access level of a user (e.g., Admin, Member, Visitor) |
| **Scopes** | Granular permissions tied to specific fields, columns, or actions within a model |
| **Authorization Rules** | Methods (`permission()`) where groups are assigned specific actions (READ, WRITE, DELETE) for objects, fields, or collections |
| **Custom Logic** | Developers can write custom authorization logic for complex rules like ownership or hierarchical access |
Unify's permission system is flexible, allowing developers to define, check, and enforce rules throughout the application — from **UI visibility** to **backend operations** like SQL queries and method executions.