summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2020-07-18 14:28:32 +0900
committersyuilo <syuilotan@yahoo.co.jp>2020-07-18 14:28:32 +0900
commitb39850de012fa7b05959c7f4bbbbade841d186ff (patch)
treef726b3b0d3125e1473d5e800e13fd26dffe1987c /src
parentfix(docs): Update api doc (diff)
downloadsharkey-b39850de012fa7b05959c7f4bbbbade841d186ff.tar.gz
sharkey-b39850de012fa7b05959c7f4bbbbade841d186ff.tar.bz2
sharkey-b39850de012fa7b05959c7f4bbbbade841d186ff.zip
feat(client): AiScriptプラグインからAPIアクセスできるように
Diffstat (limited to 'src')
-rw-r--r--src/client/components/token-generate-window.vue34
-rw-r--r--src/client/pages/preferences/plugins.vue65
-rw-r--r--src/client/scripts/aiscript/api.ts12
-rw-r--r--src/client/store.ts14
4 files changed, 105 insertions, 20 deletions
diff --git a/src/client/components/token-generate-window.vue b/src/client/components/token-generate-window.vue
index 5486ae92e7..e58dcbda78 100644
--- a/src/client/components/token-generate-window.vue
+++ b/src/client/components/token-generate-window.vue
@@ -3,13 +3,16 @@
<template #header>{{ title || $t('generateAccessToken') }}</template>
<div class="ugkkpisj">
<div>
+ <mk-info warn v-if="information">{{ information }}</mk-info>
+ </div>
+ <div>
<mk-input v-model="name">{{ $t('name') }}</mk-input>
</div>
<div>
<div style="margin-bottom: 16px;"><b>{{ $t('permission') }}</b></div>
<mk-button inline @click="disableAll">{{ $t('disableAll') }}</mk-button>
<mk-button inline @click="enableAll">{{ $t('enableAll') }}</mk-button>
- <mk-switch v-for="kind in kinds" :key="kind" v-model="permissions[kind]">{{ $t(`_permissions.${kind}`) }}</mk-switch>
+ <mk-switch v-for="kind in (initialPermissions || kinds)" :key="kind" v-model="permissions[kind]">{{ $t(`_permissions.${kind}`) }}</mk-switch>
</div>
</div>
</x-window>
@@ -23,6 +26,7 @@ import MkInput from './ui/input.vue';
import MkTextarea from './ui/textarea.vue';
import MkSwitch from './ui/switch.vue';
import MkButton from './ui/button.vue';
+import MkInfo from './ui/info.vue';
export default Vue.extend({
components: {
@@ -31,6 +35,7 @@ export default Vue.extend({
MkTextarea,
MkSwitch,
MkButton,
+ MkInfo,
},
props: {
@@ -38,20 +43,41 @@ export default Vue.extend({
type: String,
required: false,
default: null
+ },
+ information: {
+ type: String,
+ required: false,
+ default: null
+ },
+ initialName: {
+ type: String,
+ required: false,
+ default: null
+ },
+ initialPermissions: {
+ type: Array,
+ required: false,
+ default: null
}
},
data() {
return {
- name: null,
+ name: this.initialName,
permissions: {},
kinds
};
},
created() {
- for (const kind of this.kinds) {
- Vue.set(this.permissions, kind, false);
+ if (this.initialPermissions) {
+ for (const kind of this.initialPermissions) {
+ Vue.set(this.permissions, kind, true);
+ }
+ } else {
+ for (const kind of this.kinds) {
+ Vue.set(this.permissions, kind, false);
+ }
}
},
diff --git a/src/client/pages/preferences/plugins.vue b/src/client/pages/preferences/plugins.vue
index afe7c8cafa..ee0ac3652c 100644
--- a/src/client/pages/preferences/plugins.vue
+++ b/src/client/pages/preferences/plugins.vue
@@ -30,7 +30,10 @@
<div>{{ $t('description') }}:</div>
<div>{{ selectedPlugin.description }}</div>
</div>
- <mk-button @click="uninstall()" style="margin-top: 8px;"><fa :icon="faTrashAlt"/> {{ $t('uninstall') }}</mk-button>
+ <div style="margin-top: 8px;">
+ <mk-button @click="config()" inline v-if="selectedPlugin.config"><fa :icon="faCog"/> {{ $t('settings') }}</mk-button>
+ <mk-button @click="uninstall()" inline><fa :icon="faTrashAlt"/> {{ $t('uninstall') }}</mk-button>
+ </div>
</template>
</details>
</div>
@@ -39,7 +42,7 @@
<script lang="ts">
import Vue from 'vue';
-import { faPlug, faSave, faTrashAlt, faFolderOpen, faDownload } from '@fortawesome/free-solid-svg-icons';
+import { faPlug, faSave, faTrashAlt, faFolderOpen, faDownload, faCog } from '@fortawesome/free-solid-svg-icons';
import MkButton from '../../components/ui/button.vue';
import MkTextarea from '../../components/ui/textarea.vue';
import MkSelect from '../../components/ui/select.vue';
@@ -58,7 +61,7 @@ export default Vue.extend({
return {
script: '',
selectedPluginId: null,
- faPlug, faSave, faTrashAlt, faFolderOpen, faDownload
+ faPlug, faSave, faTrashAlt, faFolderOpen, faDownload, faCog
}
},
@@ -70,7 +73,7 @@ export default Vue.extend({
},
methods: {
- install() {
+ async install() {
let ast;
try {
ast = parse(this.script);
@@ -82,7 +85,6 @@ export default Vue.extend({
return;
}
const meta = AiScript.collectMetadata(ast);
- console.log(meta);
if (meta == null) {
this.$root.dialog({
type: 'error',
@@ -98,7 +100,7 @@ export default Vue.extend({
});
return;
}
- const { id, name, version, author, description } = data;
+ const { id, name, version, author, description, permissions, config } = data;
if (id == null || name == null || version == null || author == null) {
this.$root.dialog({
type: 'error',
@@ -106,16 +108,40 @@ export default Vue.extend({
});
return;
}
+
+ const token = permissions == null || permissions.length === 0 ? null : await new Promise(async (res, rej) => {
+ this.$root.new(await import('../../components/token-generate-window.vue').then(m => m.default), {
+ title: this.$t('tokenRequested'),
+ information: this.$t('pluginTokenRequestedDescription'),
+ initialName: name,
+ initialPermissions: permissions
+ }).$on('ok', async ({ name, permissions }) => {
+ const { token } = await this.$root.api('miauth/gen-token', {
+ session: null,
+ name: name,
+ permission: permissions,
+ });
+
+ res(token);
+ });
+ });
+
this.$store.commit('deviceUser/installPlugin', {
meta: {
- id, name, version, author, description
+ id, name, version, author, description, permissions, config
},
- ast
+ token,
+ ast // TODO: astにはMapが含まれることがあり、MapはJSONとしてシリアライズできないのでバグる。どうにかする
});
+
this.$root.dialog({
type: 'success',
iconOnly: true, autoClose: true
});
+
+ this.$nextTick(() => {
+ location.reload();
+ });
},
uninstall() {
@@ -124,6 +150,29 @@ export default Vue.extend({
type: 'success',
iconOnly: true, autoClose: true
});
+ this.$nextTick(() => {
+ location.reload();
+ });
+ },
+
+ // TODO: この処理をstore側にactionとして移動し、設定画面を開くAiScriptAPIを実装できるようにする
+ async config() {
+ const config = this.selectedPlugin.config;
+ for (const key in this.selectedPlugin.configData) {
+ config[key].default = this.selectedPlugin.configData[key];
+ }
+
+ const { canceled, result } = await this.$root.form(this.selectedPlugin.name, config);
+ if (canceled) return;
+
+ this.$store.commit('deviceUser/configPlugin', {
+ id: this.selectedPluginId,
+ config: result
+ });
+
+ this.$nextTick(() => {
+ location.reload();
+ });
}
},
});
diff --git a/src/client/scripts/aiscript/api.ts b/src/client/scripts/aiscript/api.ts
index 29baa25b1a..0db02c2a21 100644
--- a/src/client/scripts/aiscript/api.ts
+++ b/src/client/scripts/aiscript/api.ts
@@ -1,4 +1,5 @@
import { utils, values } from '@syuilo/aiscript';
+import { jsToVal } from '@syuilo/aiscript/built/interpreter/util';
export function createAiScriptEnv(vm, opts) {
let apiRequests = 0;
@@ -26,7 +27,7 @@ export function createAiScriptEnv(vm, opts) {
if (token) utils.assertString(token);
apiRequests++;
if (apiRequests > 16) return values.NULL;
- const res = await vm.$root.api(ep.value, utils.valToJs(param), token ? token.value : null);
+ const res = await vm.$root.api(ep.value, utils.valToJs(param), token ? token.value : (opts.token || null));
return utils.jsToVal(res);
}),
'Mk:save': values.FN_NATIVE(([key, value]) => {
@@ -42,8 +43,14 @@ export function createAiScriptEnv(vm, opts) {
}
export function createPluginEnv(vm, opts) {
+ const config = new Map();
+ for (const key in opts.plugin.config) {
+ const val = opts.plugin.configData[key] || opts.plugin.config[key].default;
+ config.set(key, jsToVal(val));
+ }
+
return {
- ...createAiScriptEnv(vm, opts),
+ ...createAiScriptEnv(vm, { ...opts, token: opts.plugin.token }),
'Mk:register_post_form_action': values.FN_NATIVE(([title, handler]) => {
vm.$store.commit('registerPostFormAction', { pluginId: opts.plugin.id, title: title.value, handler });
}),
@@ -53,5 +60,6 @@ export function createPluginEnv(vm, opts) {
'Mk:register_note_action': values.FN_NATIVE(([title, handler]) => {
vm.$store.commit('registerNoteAction', { pluginId: opts.plugin.id, title: title.value, handler });
}),
+ 'Plugin:config': values.OBJ(config),
};
}
diff --git a/src/client/store.ts b/src/client/store.ts
index c7b8e84e9d..2cd2c8cf3c 100644
--- a/src/client/store.ts
+++ b/src/client/store.ts
@@ -587,13 +587,11 @@ export default () => new Vuex.Store({
},
//#endregion
- installPlugin(state, { meta, ast }) {
+ installPlugin(state, { meta, ast, token }) {
state.plugins.push({
- id: meta.id,
- name: meta.name,
- version: meta.version,
- author: meta.author,
- description: meta.description,
+ ...meta,
+ configData: {},
+ token: token,
ast: ast
});
},
@@ -601,6 +599,10 @@ export default () => new Vuex.Store({
uninstallPlugin(state, id) {
state.plugins = state.plugins.filter(x => x.id != id);
},
+
+ configPlugin(state, { id, config }) {
+ state.plugins.find(p => p.id === id).configData = config;
+ },
}
},