mirror of
https://github.com/appwrite/appwrite
synced 2026-05-19 23:18:40 +00:00
Merge pull request #3889 from appwrite/fix-permission-selection
Fix permission selection before role entry
This commit is contained in:
commit
f39ed010c7
18 changed files with 106 additions and 53 deletions
2
.github/ISSUE_TEMPLATE/bug.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug.yaml
vendored
|
|
@ -37,7 +37,7 @@ body:
|
|||
label: "🎲 Appwrite version"
|
||||
description: "What version of Appwrite are you running?"
|
||||
options:
|
||||
- Version 1.0.0-RC1
|
||||
- Version 1.0.x
|
||||
- Version 0.15.x
|
||||
- Version 0.14.x
|
||||
- Version 0.13.x
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
# Version 1.0.1
|
||||
## Bugs
|
||||
- Fixed migration for abuse by migrating the `time` attribute [3839](https://github.com/appwrite/appwrite/pull/3839)
|
||||
|
||||
# Version 1.0.0
|
||||
## BREAKING CHANGES
|
||||
- All Date values are now stored as ISO-8601 instead of UNIX timestamps [#3516](https://github.com/appwrite/appwrite/pull/3516)
|
||||
- Permission levels and syntax have been reworked. See the Permissions V2 section in the document for more information [#3700](https://github.com/appwrite/appwrite/pull/3700)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ docker run -it --rm \
|
|||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
appwrite/appwrite:0.15.3
|
||||
appwrite/appwrite:1.0.1
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
|
@ -71,7 +71,7 @@ docker run -it --rm ^
|
|||
--volume //var/run/docker.sock:/var/run/docker.sock ^
|
||||
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
|
||||
--entrypoint="install" ^
|
||||
appwrite/appwrite:0.15.3
|
||||
appwrite/appwrite:1.0.1
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
|
@ -81,7 +81,7 @@ docker run -it --rm ,
|
|||
--volume /var/run/docker.sock:/var/run/docker.sock ,
|
||||
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ,
|
||||
--entrypoint="install" ,
|
||||
appwrite/appwrite:0.15.3
|
||||
appwrite/appwrite:1.0.1
|
||||
```
|
||||
|
||||
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
English | [简体中文](README-CN.md)
|
||||
|
||||
[**Appwrite 0.15 has been released! Learn what's new!**](https://dev.to/appwrite/announcing-appwrite-015-with-phone-authentication-more-5cjj)
|
||||
[**Appwrite 1.0 has been released! Learn what's new!**](https://appwrite.io/1.0)
|
||||
|
||||
Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend apps packaged as a set of Docker<nobr> microservices. Appwrite abstracts the complexity and repetitiveness required to build a modern backend API from scratch and allows you to build secure apps faster.
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ docker run -it --rm \
|
|||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
appwrite/appwrite:0.15.3
|
||||
appwrite/appwrite:1.0.1
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
|
@ -77,7 +77,7 @@ docker run -it --rm ^
|
|||
--volume //var/run/docker.sock:/var/run/docker.sock ^
|
||||
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
|
||||
--entrypoint="install" ^
|
||||
appwrite/appwrite:0.15.3
|
||||
appwrite/appwrite:1.0.1
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
|
@ -87,7 +87,7 @@ docker run -it --rm ,
|
|||
--volume /var/run/docker.sock:/var/run/docker.sock ,
|
||||
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ,
|
||||
--entrypoint="install" ,
|
||||
appwrite/appwrite:0.15.3
|
||||
appwrite/appwrite:1.0.1
|
||||
```
|
||||
|
||||
Once the Docker installation completes, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after installation completes.
|
||||
|
|
|
|||
|
|
@ -196,6 +196,35 @@ App::delete('/v1/mock/tests/bar')
|
|||
->action(function ($required, $default, $z) {
|
||||
});
|
||||
|
||||
/** Endpoint to test if required headers are sent from the SDK */
|
||||
App::get('/v1/mock/tests/general/headers')
|
||||
->desc('Get headers')
|
||||
->groups(['mock'])
|
||||
->label('scope', 'public')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'general')
|
||||
->label('sdk.method', 'headers')
|
||||
->label('sdk.description', 'Return headers from the request')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.model', Response::MODEL_MOCK)
|
||||
->label('sdk.mock', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (Request $request, Response $response) {
|
||||
$res = [
|
||||
'x-sdk-name' => $request->getHeader('x-sdk-name'),
|
||||
'x-sdk-platform' => $request->getHeader('x-sdk-platform'),
|
||||
'x-sdk-language' => $request->getHeader('x-sdk-language'),
|
||||
'x-sdk-version' => $request->getHeader('x-sdk-version'),
|
||||
];
|
||||
$res = array_map(function ($key, $value) {
|
||||
return $key . ': ' . $value;
|
||||
}, array_keys($res), $res);
|
||||
$res = implode("; ", $res);
|
||||
|
||||
$response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK);
|
||||
});
|
||||
|
||||
App::get('/v1/mock/tests/general/download')
|
||||
->desc('Download File')
|
||||
->groups(['mock'])
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate pe
|
|||
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_BUSTER = 500;
|
||||
const APP_VERSION_STABLE = '1.0.0';
|
||||
const APP_VERSION_STABLE = '1.0.1';
|
||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ $escapedPermissions = \array_map(function ($perm) {
|
|||
list="types"
|
||||
type="text"
|
||||
x-model="permission.role"
|
||||
@keydown.enter="prevent($event)"
|
||||
@keydown="clearPermission(index)"
|
||||
@keyup="updatePermission(index)"/>
|
||||
</td>
|
||||
<?php foreach ($escapedPermissions as $permission): ?>
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ $ appwrite users list
|
|||
|
||||
To create a document you can use the following command
|
||||
```sh
|
||||
$ appwrite database createDocument --collectionId <ID> --documentId 'unique()' --data '{ "Name": "Iron Man" }' --read role:all team:abc
|
||||
$ appwrite database createDocument --collectionId <ID> --documentId 'unique()' --data '{ "Name": "Iron Man" }' --permissions 'read("any")' 'read("team:abc")'
|
||||
```
|
||||
|
||||
### Some Gotchas
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
Init your Appwrite client:
|
||||
|
||||
```dart
|
||||
Client client = Client();
|
||||
|
||||
client
|
||||
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
|
||||
.setProject('5e8cf4f46b5e8') // Your project ID
|
||||
.setSelfSigned() // Remove in production
|
||||
;
|
||||
Client client = Client();
|
||||
|
||||
client
|
||||
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
|
||||
.setProject('5e8cf4f46b5e8') // Your project ID
|
||||
.setSelfSigned() // Remove in production
|
||||
;
|
||||
```
|
||||
|
||||
Create a new user:
|
||||
|
|
@ -18,12 +17,11 @@ Create a new user:
|
|||
```dart
|
||||
Users users = Users(client);
|
||||
|
||||
Response result = await users.create(
|
||||
User result = await users.create(
|
||||
userId: '[USER_ID]',
|
||||
email: 'email@example.com',
|
||||
password: 'password',
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Fetch user profile:
|
||||
|
|
@ -31,7 +29,7 @@ Fetch user profile:
|
|||
```dart
|
||||
Users users = Users(client);
|
||||
|
||||
Response profile = await users.get(
|
||||
User profile = await users.get(
|
||||
userId: '[USER_ID]',
|
||||
);
|
||||
```
|
||||
|
|
@ -47,8 +45,9 @@ storage.createFile(
|
|||
bucketId: '[BUCKET_ID]',
|
||||
fileId: '[FILE_ID]', // use 'unique()' to automatically generate a unique ID
|
||||
file: file,
|
||||
read: ['role:all'],
|
||||
write: []
|
||||
permissions: [
|
||||
Permission.read(Role.any()),
|
||||
],
|
||||
)
|
||||
.then((response) {
|
||||
print(response); // File uploaded!
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
Init your Appwrite client:
|
||||
|
||||
```dart
|
||||
Client client = Client();
|
||||
|
||||
client
|
||||
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
|
||||
.setProject('5e8cf4f46b5e8') // Your project ID
|
||||
.setSelfSigned() // Remove in production
|
||||
;
|
||||
Client client = Client();
|
||||
|
||||
client
|
||||
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
|
||||
.setProject('5e8cf4f46b5e8') // Your project ID
|
||||
.setSelfSigned() // Remove in production
|
||||
;
|
||||
```
|
||||
|
||||
Create a new user and session:
|
||||
|
|
@ -18,9 +17,9 @@ Create a new user and session:
|
|||
```dart
|
||||
Account account = Account(client);
|
||||
|
||||
Response user = await account.create(email: 'me@appwrite.io', password: 'password', name: 'My Name');
|
||||
final user = await account.create(userId: '[USER_ID]', email: 'me@appwrite.io', password: 'password', name: 'My Name');
|
||||
|
||||
Response session = await account.createSession(email: 'me@appwrite.io', password: 'password');
|
||||
final session = await account.createEmailSession(email: 'me@appwrite.io', password: 'password');
|
||||
|
||||
```
|
||||
|
||||
|
|
@ -29,7 +28,7 @@ Fetch user profile:
|
|||
```dart
|
||||
Account account = Account(client);
|
||||
|
||||
Response profile = await account.get();
|
||||
final profile = await account.get();
|
||||
```
|
||||
|
||||
Upload File:
|
||||
|
|
@ -37,12 +36,21 @@ Upload File:
|
|||
```dart
|
||||
Storage storage = Storage(client);
|
||||
|
||||
MultipartFile file = MultipartFile.fromFile('./path-to-file/image.jpg', filename: 'image.jpg');
|
||||
late InputFile file;
|
||||
|
||||
if(kIsWeb) {
|
||||
file = InputFile(bytes: pickedFile.bytes, filename: 'image.jpg');
|
||||
} else {
|
||||
file = InputFile(path: './path-to-file/image.jpg', filename: 'image.jpg');
|
||||
}
|
||||
|
||||
storage.createFile(
|
||||
bucketId: '[BUCKET_ID]',
|
||||
fileId: '[FILE_ID]', // use 'unique()' to automatically generate a unique ID
|
||||
file: file,
|
||||
read: ['role:all'],
|
||||
write: []
|
||||
permissions: [
|
||||
Permission.read(Role.any()),
|
||||
],
|
||||
)
|
||||
.then((response) {
|
||||
print(response); // File uploaded!
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
Init your Appwrite client:
|
||||
|
||||
```dart
|
||||
Client client = Client();
|
||||
|
||||
client
|
||||
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
|
||||
.setProject('5e8cf4f46b5e8') // Your project ID
|
||||
.setSelfSigned() // Remove in production
|
||||
;
|
||||
Client client = Client();
|
||||
|
||||
client
|
||||
.setEndpoint('https://localhost/v1') // Your Appwrite Endpoint
|
||||
.setProject('5e8cf4f46b5e8') // Your project ID
|
||||
.setSelfSigned() // Remove in production
|
||||
;
|
||||
```
|
||||
|
||||
Create a new user and session:
|
||||
|
|
@ -18,9 +17,9 @@ Create a new user and session:
|
|||
```dart
|
||||
Account account = Account(client);
|
||||
|
||||
Response user = await account.create(userId: '[USER_ID]', email: 'me@appwrite.io', password: 'password', name: 'My Name');
|
||||
final user = await account.create(userId: '[USER_ID]', email: 'me@appwrite.io', password: 'password', name: 'My Name');
|
||||
|
||||
Response session = await account.createSession(email: 'me@appwrite.io', password: 'password');
|
||||
final session = await account.createEmailSession(email: 'me@appwrite.io', password: 'password');
|
||||
|
||||
```
|
||||
|
||||
|
|
@ -29,7 +28,7 @@ Fetch user profile:
|
|||
```dart
|
||||
Account account = Account(client);
|
||||
|
||||
Response profile = await account.get();
|
||||
final profile = await account.get();
|
||||
```
|
||||
|
||||
Upload File:
|
||||
|
|
@ -40,7 +39,7 @@ Storage storage = Storage(client);
|
|||
late InputFile file;
|
||||
|
||||
if(kIsWeb) {
|
||||
file = InputFile(file: await MultipartFile.fromFile('file', './path-to-file/image.jpg', filename: 'image.jpg'));
|
||||
file = InputFile(bytes: pickedFile.bytes, filename: 'image.jpg');
|
||||
} else {
|
||||
file = InputFile(path: './path-to-file/image.jpg', filename: 'image.jpg');
|
||||
}
|
||||
|
|
@ -49,8 +48,9 @@ storage.createFile(
|
|||
bucketId: '[BUCKET_ID]',
|
||||
fileId: '[FILE_ID]', // use 'unique()' to automatically generate a unique ID
|
||||
file: file,
|
||||
read: ['role:all'],
|
||||
write: []
|
||||
permissions: [
|
||||
Permission.read(Role.any()),
|
||||
],
|
||||
)
|
||||
.then((response) {
|
||||
print(response); // File uploaded!
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@ All data returned by the Databases service are represented as structured JSON do
|
|||
|
||||
The Databases service can contain multiple databases, each database can contain multiple collections. A collection is a group of similarly structured documents. The accepted structure of documents is defined by [collection attributes](/docs/databases#attributes). The collection attributes help you ensure all your user-submitted data is validated and stored according to the collection structure.
|
||||
|
||||
Using Appwrite permissions architecture, you can assign read or write access to each collection or document in your project for either a specific user, team, user role, or even grant it with public access (`role:all`). You can learn more about [how Appwrite handles permissions and access control](/docs/permissions).
|
||||
Using Appwrite permissions architecture, you can assign read or write access to each collection or document in your project for either a specific user, team, user role, or even grant it with public access (`any`). You can learn more about [how Appwrite handles permissions and access control](/docs/permissions).
|
||||
|
|
@ -2,7 +2,7 @@ The Storage service allows you to manage your project files. Using the Storage s
|
|||
|
||||
Files are managed using buckets. Storage buckets are similar to Collections we have in our [Databases](/docs/databases) service. The difference is, buckets also provide more power to decide what kinds of files, what sizes you want to allow in that bucket, whether or not to encrypt the files, scan with antivirus and more.
|
||||
|
||||
Using Appwrite permissions architecture, you can assign read or write access to each bucket or file in your project for either a specific user, team, user role, or even grant it with public access (`role:all`). You can learn more about [how Appwrite handles permissions and access control](/docs/permissions).
|
||||
Using Appwrite permissions architecture, you can assign read or write access to each bucket or file in your project for either a specific user, team, user role, or even grant it with public access (`any`). You can learn more about [how Appwrite handles permissions and access control](/docs/permissions).
|
||||
|
||||
The preview endpoint allows you to generate preview images for your files. Using the preview endpoint, you can also manipulate the resulting image so that it will fit perfectly inside your app in terms of dimensions, file size, and style. The preview endpoint also allows you to change the resulting image file format for better compression or image quality for better delivery over the network.
|
||||
|
||||
|
|
|
|||
2
public/dist/scripts/app-all.js
vendored
2
public/dist/scripts/app-all.js
vendored
|
|
@ -4013,7 +4013,7 @@ this.rawPermissions=permissions;permissions.map(p=>{let{type,role}=this.parsePer
|
|||
if(existing===undefined){let newPermission={role,create:false,read:false,update:false,xdelete:false,};newPermission[type]=true;this.permissions.push(newPermission);}
|
||||
if(index!==-1){existing[type]=true;this.permissions[index]=existing;}});},addPermission(formId){if(this.permissions.length>0&&!this.validate(formId,this.permissions.length-1)){return;}
|
||||
this.permissions.push({role:'',create:false,read:false,update:false,xdelete:false,});},updatePermission(index){setTimeout(()=>{const permission=this.permissions[index];Object.keys(permission).forEach(key=>{if(key==='role'){return;}
|
||||
const parsedKey=this.parseOutputPermission(key);const permissionString=this.buildPermission(parsedKey,permission.role);if(permission[key]){if(!this.rawPermissions.includes(permissionString)){this.rawPermissions.push(permissionString);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(permissionString);});}});});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','').replaceAll('"','');return{type,role};},buildPermission(type,role){return`${type}("${role}")`},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
const parsedKey=this.parseOutputPermission(key);const permissionString=this.buildPermission(parsedKey,permission.role);if(permission[key]){if(!this.rawPermissions.includes(permissionString)){this.rawPermissions.push(permissionString);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(permissionString);});}});});},clearPermission(index){let currentRole=this.permissions[index].role;this.rawPermissions=this.rawPermissions.filter(p=>{let{type,role}=this.parsePermission(p);return role!==currentRole;});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','').replaceAll('"','');return{type,role};},buildPermission(type,role){return`${type}("${role}")`},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
return key;},parseOutputPermission(key){if(key==='xdelete'){return'delete';}
|
||||
return key;},validate(formId,index){const form=document.getElementById(formId);const input=document.getElementById(`${formId}Input${index}`);const permission=this.permissions[index];input.setCustomValidity('');if(permission.role===''){input.setCustomValidity('Role is required');}else if(!Object.entries(permission).some(([k,v])=>!k.includes('role')&&v)){input.setCustomValidity('No permissions selected');}else if(this.permissions.some(p=>p.role===permission.role&&p!==permission)){input.setCustomValidity('Role entry already exists');}
|
||||
return form.reportValidity();},prevent(event){event.preventDefault();event.stopPropagation();}}));});})(window);(function(window){"use strict";window.ls.view.add({selector:"data-service",controller:function(element,view,container,form,alerts,expression,window){let action=element.dataset["service"];let service=element.dataset["name"]||null;let event=expression.parse(element.dataset["event"]);let confirm=element.dataset["confirm"]||"";let loading=element.dataset["loading"]||"";let loaderId=null;let scope=element.dataset["scope"]||"sdk";let success=element.dataset["success"]||"";let failure=element.dataset["failure"]||"";let running=false;let callbacks={hide:function(){return function(){return element.style.opacity='0';};},reset:function(){return function(){if("FORM"===element.tagName){return element.reset();}
|
||||
|
|
|
|||
2
public/dist/scripts/app.js
vendored
2
public/dist/scripts/app.js
vendored
|
|
@ -607,7 +607,7 @@ this.rawPermissions=permissions;permissions.map(p=>{let{type,role}=this.parsePer
|
|||
if(existing===undefined){let newPermission={role,create:false,read:false,update:false,xdelete:false,};newPermission[type]=true;this.permissions.push(newPermission);}
|
||||
if(index!==-1){existing[type]=true;this.permissions[index]=existing;}});},addPermission(formId){if(this.permissions.length>0&&!this.validate(formId,this.permissions.length-1)){return;}
|
||||
this.permissions.push({role:'',create:false,read:false,update:false,xdelete:false,});},updatePermission(index){setTimeout(()=>{const permission=this.permissions[index];Object.keys(permission).forEach(key=>{if(key==='role'){return;}
|
||||
const parsedKey=this.parseOutputPermission(key);const permissionString=this.buildPermission(parsedKey,permission.role);if(permission[key]){if(!this.rawPermissions.includes(permissionString)){this.rawPermissions.push(permissionString);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(permissionString);});}});});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','').replaceAll('"','');return{type,role};},buildPermission(type,role){return`${type}("${role}")`},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
const parsedKey=this.parseOutputPermission(key);const permissionString=this.buildPermission(parsedKey,permission.role);if(permission[key]){if(!this.rawPermissions.includes(permissionString)){this.rawPermissions.push(permissionString);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(permissionString);});}});});},clearPermission(index){let currentRole=this.permissions[index].role;this.rawPermissions=this.rawPermissions.filter(p=>{let{type,role}=this.parsePermission(p);return role!==currentRole;});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','').replaceAll('"','');return{type,role};},buildPermission(type,role){return`${type}("${role}")`},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
return key;},parseOutputPermission(key){if(key==='xdelete'){return'delete';}
|
||||
return key;},validate(formId,index){const form=document.getElementById(formId);const input=document.getElementById(`${formId}Input${index}`);const permission=this.permissions[index];input.setCustomValidity('');if(permission.role===''){input.setCustomValidity('Role is required');}else if(!Object.entries(permission).some(([k,v])=>!k.includes('role')&&v)){input.setCustomValidity('No permissions selected');}else if(this.permissions.some(p=>p.role===permission.role&&p!==permission)){input.setCustomValidity('Role entry already exists');}
|
||||
return form.reportValidity();},prevent(event){event.preventDefault();event.stopPropagation();}}));});})(window);(function(window){"use strict";window.ls.view.add({selector:"data-service",controller:function(element,view,container,form,alerts,expression,window){let action=element.dataset["service"];let service=element.dataset["name"]||null;let event=expression.parse(element.dataset["event"]);let confirm=element.dataset["confirm"]||"";let loading=element.dataset["loading"]||"";let loaderId=null;let scope=element.dataset["scope"]||"sdk";let success=element.dataset["success"]||"";let failure=element.dataset["failure"]||"";let running=false;let callbacks={hide:function(){return function(){return element.style.opacity='0';};},reset:function(){return function(){if("FORM"===element.tagName){return element.reset();}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,14 @@
|
|||
});
|
||||
});
|
||||
},
|
||||
clearPermission(index) {
|
||||
let currentRole = this.permissions[index].role;
|
||||
this.rawPermissions = this.rawPermissions.filter(p => {
|
||||
let {type, role} = this.parsePermission(p);
|
||||
|
||||
return role !== currentRole;
|
||||
});
|
||||
},
|
||||
removePermission(index) {
|
||||
let row = this.permissions.splice(index, 1);
|
||||
if (row.length === 1) {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ abstract class Migration
|
|||
*/
|
||||
public static array $versions = [
|
||||
'1.0.0-RC1' => 'V15',
|
||||
'1.0.0' => 'V15'
|
||||
'1.0.0' => 'V15',
|
||||
'1.0.1' => 'V15',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -491,6 +491,7 @@ class V15 extends Migration
|
|||
$this->createPermissionsColumn($id);
|
||||
$this->migrateDateTimeAttribute($id, '_createdAt');
|
||||
$this->migrateDateTimeAttribute($id, '_updatedAt');
|
||||
$this->migrateDateTimeAttribute($id, 'time');
|
||||
break;
|
||||
|
||||
case 'attributes':
|
||||
|
|
|
|||
Loading…
Reference in a new issue