parent
89adc8e18d
commit
6f1ea6e8e7
@ -0,0 +1,126 @@ |
||||
import React from 'react' // eslint-disable-line
|
||||
import { Plugin } from '@remixproject/engine' |
||||
import { AppModal } from 'libs/remix-ui/app/src' |
||||
import { PermissionHandlerDialog, PermissionHandlerValue } from 'libs/remix-ui/permission-handler/src' |
||||
import { Profile } from '@remixproject/plugin-utils' |
||||
|
||||
const profile = { |
||||
name: 'permissionhandler', |
||||
displayName: 'permissionhandler', |
||||
description: 'permissionhandler', |
||||
methods: ['askPermission'] |
||||
} |
||||
|
||||
export class PermissionHandlerPlugin extends Plugin { |
||||
permissions: any |
||||
currentVersion: number |
||||
constructor() { |
||||
super(profile) |
||||
this.permissions = this._getFromLocal() |
||||
this.currentVersion = 1 |
||||
// here we remove the old permissions saved before adding 'permissionVersion'
|
||||
// since with v1 the structure has been changed because of new engine ^0.2.0-alpha.6 changes
|
||||
if (!localStorage.getItem('permissionVersion')) { |
||||
localStorage.setItem('plugins/permissions', '') |
||||
localStorage.setItem('permissionVersion', this.currentVersion.toString()) |
||||
} |
||||
} |
||||
|
||||
_getFromLocal() { |
||||
const permission = localStorage.getItem('plugins/permissions') |
||||
return permission ? JSON.parse(permission) : {} |
||||
} |
||||
|
||||
persistPermissions() { |
||||
const permissions = JSON.stringify(this.permissions) |
||||
localStorage.setItem('plugins/permissions', permissions) |
||||
} |
||||
|
||||
switchMode (from: Profile, to: Profile, method: string, set: boolean) { |
||||
set |
||||
? this.permissions[to.name][method][from.name] = {} |
||||
: delete this.permissions[to.name][method][from.name] |
||||
} |
||||
|
||||
clear() { |
||||
localStorage.removeItem('plugins/permissions') |
||||
} |
||||
|
||||
notAllowWarning(from: Profile, to: Profile, method: string) { |
||||
return `${from.displayName || from.name} is not allowed to call ${method} method of ${to.displayName || to.name}.` |
||||
} |
||||
|
||||
async getTheme() { |
||||
return (await this.call('theme', 'currentTheme')).quality |
||||
} |
||||
|
||||
/** |
||||
* Check if a plugin has the permission to call another plugin and askPermission if needed |
||||
* @param {PluginProfile} from the profile of the plugin that make the call |
||||
* @param {ModuleProfile} to The profile of the module that receive the call |
||||
* @param {string} method The name of the function to be called |
||||
* @param {string} message from the caller plugin to add more details if needed |
||||
* @returns {Promise<boolean>} |
||||
*/ |
||||
async askPermission(from: Profile, to: Profile, method: string, message: string) { |
||||
try { |
||||
this.permissions = this._getFromLocal() |
||||
if (!this.permissions[to.name]) this.permissions[to.name] = {} |
||||
if (!this.permissions[to.name][method]) this.permissions[to.name][method] = {} |
||||
if (!this.permissions[to.name][method][from.name]) return this.openPermission(from, to, method, message) |
||||
|
||||
const { allow, hash } = this.permissions[to.name][method][from.name] |
||||
if (!allow) { |
||||
const warning = this.notAllowWarning(from, to, method) |
||||
this.call('modal', 'toast', warning) |
||||
return false |
||||
} |
||||
return hash === from.hash |
||||
? true // Allow
|
||||
: await this.openPermission(from, to, method, message) |
||||
} catch (err) { |
||||
throw new Error(err) |
||||
} |
||||
} |
||||
|
||||
async openPermission(from: Profile, to: Profile, method: string, message: string) { |
||||
const remember = this.permissions[to.name][method][from.name] |
||||
const value: PermissionHandlerValue = { |
||||
from, |
||||
to, |
||||
method, |
||||
message, |
||||
remember |
||||
} |
||||
const modal: AppModal = { |
||||
id: 'PermissionHandler', |
||||
title: `Permission needed for ${to.displayName || to.name}`, |
||||
message: <PermissionHandlerDialog plugin={this} theme={await this.getTheme()} value={value}></PermissionHandlerDialog>, |
||||
okLabel: 'sure', |
||||
cancelLabel: 'no' |
||||
} |
||||
|
||||
const result = await this.call('modal', 'modal', modal) |
||||
return new Promise((resolve, reject) => { |
||||
if (result) { |
||||
if (this.permissions[to.name][method][from.name]) { |
||||
this.permissions[to.name][method][from.name] = { |
||||
allow: true, |
||||
hash: from.hash |
||||
} |
||||
this.persistPermissions() |
||||
} |
||||
resolve(true) |
||||
} else { |
||||
if (this.permissions[to.name][method][from.name]) { |
||||
this.permissions[to.name][method][from.name] = { |
||||
allow: false, |
||||
hash: from.hash |
||||
} |
||||
this.persistPermissions() |
||||
} |
||||
reject(this.notAllowWarning(from, to, method)) |
||||
} |
||||
}) |
||||
} |
||||
} |
@ -1,202 +0,0 @@ |
||||
import Registry from '../state/registry' |
||||
|
||||
/* global localStorage */ |
||||
const yo = require('yo-yo') |
||||
const csjs = require('csjs-inject') |
||||
const addTooltip = require('./tooltip') |
||||
const modalDialog = require('./modaldialog') |
||||
|
||||
const css = csjs` |
||||
.permission h4 { |
||||
text-transform: uppercase; |
||||
text-align: center; |
||||
} |
||||
.permission h6 { |
||||
text-transform: uppercase; |
||||
} |
||||
.remember { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
} |
||||
.images { |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
padding: 10px; |
||||
} |
||||
.images img { |
||||
width: 40px; |
||||
height: 40px; |
||||
} |
||||
.images i { |
||||
margin: 0 20px; |
||||
} |
||||
` |
||||
|
||||
function notAllowWarning (from, to, method) { |
||||
return `${from.displayName || from.name} is not allowed to call ${method} method of ${to.displayName || to.name}.` |
||||
} |
||||
|
||||
export class PermissionHandler { |
||||
constructor () { |
||||
this.permissions = this._getFromLocal() |
||||
this.currentVersion = 1 |
||||
// here we remove the old permissions saved before adding 'permissionVersion'
|
||||
// since with v1 the structure has been changed because of new engine ^0.2.0-alpha.6 changes
|
||||
if (!localStorage.getItem('permissionVersion')) { |
||||
localStorage.setItem('plugins/permissions', '') |
||||
localStorage.setItem('permissionVersion', this.currentVersion) |
||||
} |
||||
} |
||||
|
||||
_getFromLocal () { |
||||
const permission = localStorage.getItem('plugins/permissions') |
||||
return permission ? JSON.parse(permission) : {} |
||||
} |
||||
|
||||
persistPermissions () { |
||||
const permissions = JSON.stringify(this.permissions) |
||||
localStorage.setItem('plugins/permissions', permissions) |
||||
} |
||||
|
||||
clear () { |
||||
localStorage.removeItem('plugins/permissions') |
||||
addTooltip('All Permissions have been reset') |
||||
} |
||||
|
||||
/** |
||||
* Show a message to ask the user for a permission |
||||
* @param {PluginProfile} from The name and hash of the plugin that make the call |
||||
* @param {ModuleProfile} to The name of the plugin that receive the call |
||||
* @param {string} method The name of the function to be called |
||||
* @param {string} message from the caller plugin to add more details if needed |
||||
* @returns {Promise<{ allow: boolean; remember: boolean }} Answer from the user to the permission |
||||
*/ |
||||
async openPermission (from, to, method, message) { |
||||
return new Promise((resolve, reject) => { |
||||
modalDialog( |
||||
`Permission needed for ${to.displayName || to.name}`, |
||||
this.form(from, to, method, message), |
||||
{ |
||||
label: 'Accept', |
||||
fn: () => { |
||||
if (this.permissions[to.name][method][from.name]) { |
||||
this.permissions[to.name][method][from.name] = { |
||||
allow: true, |
||||
hash: from.hash |
||||
} |
||||
this.persistPermissions() |
||||
} |
||||
resolve(true) |
||||
} |
||||
}, |
||||
{ |
||||
label: 'Decline', |
||||
fn: () => { |
||||
if (this.permissions[to.name][method][from.name]) { |
||||
this.permissions[to.name][method][from.name] = { |
||||
allow: false, |
||||
hash: from.hash |
||||
} |
||||
this.persistPermissions() |
||||
} |
||||
reject(notAllowWarning(from, to, method)) |
||||
} |
||||
} |
||||
) |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* Check if a plugin has the permission to call another plugin and askPermission if needed |
||||
* @param {PluginProfile} from the profile of the plugin that make the call |
||||
* @param {ModuleProfile} to The profile of the module that receive the call |
||||
* @param {string} method The name of the function to be called |
||||
* @param {string} message from the caller plugin to add more details if needed |
||||
* @returns {Promise<boolean>} |
||||
*/ |
||||
async askPermission (from, to, method, message) { |
||||
try { |
||||
this.permissions = this._getFromLocal() |
||||
if (!this.permissions[to.name]) this.permissions[to.name] = {} |
||||
if (!this.permissions[to.name][method]) this.permissions[to.name][method] = {} |
||||
if (!this.permissions[to.name][method][from.name]) return this.openPermission(from, to, method, message) |
||||
|
||||
const { allow, hash } = this.permissions[to.name][method][from.name] |
||||
if (!allow) { |
||||
const warning = notAllowWarning(from, to, method) |
||||
addTooltip(warning) |
||||
return false |
||||
} |
||||
return hash === from.hash |
||||
? true // Allow
|
||||
: this.openPermission(from, to, method, message) // New version of a plugin
|
||||
} catch (err) { |
||||
throw new Error(err) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* The permission form |
||||
* @param {PluginProfile} from The name and hash of the plugin that make the call |
||||
* @param {ModuleProfile} to The name of the plugin that receive the call |
||||
* @param {string} method The name of te methode to be called |
||||
* @param {string} message from the caller plugin to add more details if needed |
||||
*/ |
||||
form (from, to, method, message) { |
||||
const fromName = from.displayName || from.name |
||||
const toName = to.displayName || to.name |
||||
const remember = this.permissions[to.name][method][from.name] |
||||
|
||||
const switchMode = (e) => { |
||||
e.target.checked |
||||
? this.permissions[to.name][method][from.name] = {} |
||||
: delete this.permissions[to.name][method][from.name] |
||||
} |
||||
const rememberSwitch = remember |
||||
? yo`<input type="checkbox" onchange="${switchMode}" checkbox class="form-check-input" id="remember" data-id="permissionHandlerRememberChecked">` |
||||
: yo`<input type="checkbox" onchange="${switchMode}" class="form-check-input" id="remember" data-id="permissionHandlerRememberUnchecked">` |
||||
const text = `"${fromName}" ${(remember ? 'has changed and' : '')} would like to access to "${method}" of "${toName}"` |
||||
const imgFrom = yo`<img id="permissionModalImagesFrom" src="${from.icon}" />` |
||||
const imgTo = yo`<img id="permissionModalImagesTo" src="${to.icon}" />` |
||||
const pluginsImages = yo` |
||||
<article class="${css.images}"> |
||||
${imgFrom} |
||||
<i class="fas fa-arrow-right"></i> |
||||
${imgTo} |
||||
</article> |
||||
` |
||||
|
||||
Registry.getInstance().get('themeModule').api.fixInvert(imgFrom) |
||||
Registry.getInstance().get('themeModule').api.fixInvert(imgTo) |
||||
|
||||
const pluginMessage = message ? yo` |
||||
<div> |
||||
<h6>Description</h6> |
||||
<p>${message}</p> |
||||
</div> |
||||
` : ''
|
||||
return yo` |
||||
<section class="${css.permission}"> |
||||
${pluginsImages} |
||||
<article> |
||||
<h4 data-id="permissionHandlerMessage">${text} :</h4> |
||||
<h6>${fromName}</h6> |
||||
<p>${from.description || yo`<i>No description Provided</i>`}</p> |
||||
<h6>${toName} :</p> |
||||
<p>${to.description || yo`<i>No description Provided</i>`}</p> |
||||
${pluginMessage} |
||||
</article> |
||||
|
||||
<article class="${css.remember}"> |
||||
<div class="form-check"> |
||||
${rememberSwitch} |
||||
<label class="form-check-label" for="remember" data-id="permissionHandlerRememberChoice">Remember this choice</label> |
||||
</div> |
||||
<button class="btn btn-sm" onclick="${_ => this.clear()}">Reset all Permissions</button> |
||||
</article> |
||||
</section> |
||||
` |
||||
} |
||||
} |
@ -1 +1,2 @@ |
||||
export { default as Permissionhandler } from './lib/permission-handler' |
||||
export { default as PermissionHandlerDialog } from './lib/permission-dialog' |
||||
export { PermissionHandlerValue, PermissionHandlerProps } from './interface/index' |
||||
|
@ -1,25 +0,0 @@ |
||||
import { useDialogDispatchers } from 'libs/remix-ui/app/src/lib/remix-app/context/provider' |
||||
import React, { useContext, useEffect, useRef, useState } from 'react' // eslint-disable-line
|
||||
import { PermissionHandlerValue } from '../interface' |
||||
import PermissionHandlerDialog from './permission-dialog' |
||||
|
||||
const PermissionHandler = () => { |
||||
const { alert, toast, modal } = useDialogDispatchers() |
||||
const [value, setValue] = useState<PermissionHandlerValue>() |
||||
useEffect(() => { |
||||
if (value) { |
||||
modal({ |
||||
id: 'PermissionHandler', |
||||
title: 'permissions', |
||||
message: <PermissionHandlerDialog value={value}></PermissionHandlerDialog>, |
||||
okFn: () => {}, |
||||
cancelFn: () => {}, |
||||
okLabel: 'sure', |
||||
cancelLabel: 'no' |
||||
}) |
||||
} |
||||
}, [value]) |
||||
return (<></>) |
||||
} |
||||
|
||||
export default PermissionHandler |
Loading…
Reference in new issue