1
0
mirror of https://github.com/typemill/typemill.git synced 2025-08-12 17:14:03 +02:00

Activate plugins

This commit is contained in:
trendschau
2023-02-28 22:39:30 +01:00
parent 9b206c15c9
commit 807f490eb5
9 changed files with 221 additions and 61 deletions

View File

@@ -0,0 +1,76 @@
<?php
namespace Typemill\Controllers;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Typemill\Models\Validation;
use Typemill\Models\StorageWrapper;
use Typemill\Models\License;
use Typemill\Static\Settings;
class ControllerApiSystemExtensions extends ControllerData
{
public function activateExtension(Request $request, Response $response)
{
$params = $request->getParsedBody();
# validate input
$validate = new Validation();
$vresult = $validate->activateExtension($params);
if($vresult !== true)
{
$response->getBody()->write(json_encode([
'message' => 'Something went wrong, the input is not valid.',
'errors' => $vresult
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
if(!isset($this->settings[$params['type']][$params['name']]))
{
$response->getBody()->write(json_encode([
'message' => 'The plugin or themes was not found.',
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$storage = new StorageWrapper('\Typemill\Models\Storage');
if($params['checked'] == true)
{
$definitions = $storage->getYaml($params['type'] . DIRECTORY_SEPARATOR . $params['name'], $params['name'] . '.yaml');
if(isset($definitions['license']) && in_array($definitions['license'], ['MAKER', 'BUSINESS']))
{
$license = new License();
$licenseScope = $license->getLicenseScope($this->c->get('urlinfo'));
if(!isset($licenseScope[$definitions['license']]))
{
$response->getBody()->write(json_encode([
'message' => 'We can not activate this plugin because you need a valid '. $definitions['license'] .'-license and your website must run under the domain of your license.',
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
}
}
$objectdata = [];
$objectdata[$params['type']][$params['name']] = $this->settings[$params['type']][$params['name']];
$objectdata[$params['type']][$params['name']]['active'] = $params['checked'];
# store updated settings here
$updatedSettings = Settings::updateSettings($objectdata);
$response->getBody()->write(json_encode([
'message' => 'settings have been saved'
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
}
}

View File

@@ -34,6 +34,13 @@ class ControllerApiSystemPlugins extends ControllerData
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
# keep the active setting
$validatedOutput['active'] = false;
if(isset($plugininput['active']) && $plugininput['active'] == true)
{
$validatedOutput['active'] = true;
}
$plugindata['plugins'][$pluginname] = $validatedOutput;
# store updated settings here

View File

@@ -62,13 +62,19 @@ class ControllerWebSystem extends ControllerData
public function showPlugins($request, $response, $args)
{
$translations = $this->c->get('translations');
$pluginSettings = $this->getPluginDetails();
$pluginDefinitions = $this->getPluginDetails();
$plugindata = [];
$pluginSettings = [];
foreach($this->settings['plugins'] as $pluginname => $plugininputs)
{
$plugindata[$pluginname] = $plugininputs;
$pluginSettings[$pluginname] = $plugininputs;
}
$license = [];
if(is_array($this->settings['license']))
{
$license = array_keys($this->settings['license']);
}
return $this->c->get('view')->render($response, 'system/plugins.twig', [
@@ -76,8 +82,9 @@ class ControllerWebSystem extends ControllerData
'mainnavi' => $this->getMainNavigation($request->getAttribute('c_userrole')),
'systemnavi' => $this->getSystemNavigation($request->getAttribute('c_userrole')),
'jsdata' => [
'settings' => $plugindata,
'plugins' => $pluginSettings,
'settings' => $pluginSettings,
'definitions' => $pluginDefinitions,
'license' => $license,
'labels' => $translations,
'urlinfo' => $this->c->get('urlinfo')
]

View File

@@ -367,6 +367,21 @@ class Validation
return $v->errors();
}
public function activateExtension(array $params)
{
$v = new Validator($params);
$v->rule('required', ['name', 'type', 'checked']);
$v->rule('in', 'type', ['plugins', 'themes']);
$v->rule('boolean', 'checked');
if($v->validate())
{
return true;
}
return $v->errors();
}
/**
* validation for system settings

View File

@@ -36,6 +36,7 @@ abstract class Plugin implements EventSubscriberInterface
protected function isXhr()
{
return true;
if($this->container['request']->isXhr())
{
return true;
@@ -45,11 +46,13 @@ abstract class Plugin implements EventSubscriberInterface
protected function getParams()
{
return true;
return $this->container['request']->getParams();
}
protected function returnJson($data)
{
return true;
return $this->container['response']
->withHeader("Content-Type", "application/json")
->withStatus(200)
@@ -58,6 +61,7 @@ abstract class Plugin implements EventSubscriberInterface
protected function returnJsonError($data)
{
return true;
return $this->container['response']
->withHeader("Content-Type", "application/json")
->withStatus(400)
@@ -66,118 +70,141 @@ abstract class Plugin implements EventSubscriberInterface
protected function getSettings()
{
return true;
return $this->container->get('settings');
}
protected function getPluginSettings($plugin)
{
return true;
return $this->container->get('settings')['plugins'][$plugin];
}
protected function getRoute()
{
return true;
return $this->container['request']->getUri()->withUserInfo('');
}
protected function getPath()
{
return true;
return $this->container['request']->getUri()->getPath();
}
protected function getDispatcher()
{
return true;
return $this->container['dispatcher'];
}
protected function getTwig()
{
return true;
return $this->container['view'];
}
protected function addTwigGlobal($name, $class)
{
return true;
$this->container->view->getEnvironment()->addGlobal($name, $class);
}
protected function addTwigFilter($name, $filter)
{
return true;
$filter = new \Twig_SimpleFilter($name, $filter);
$this->container->view->getEnvironment()->addFilter($filter);
}
protected function addTwigFunction($name, $function)
{
return true;
$function = new \Twig_SimpleFunction($name, $function);
$this->container->view->getEnvironment()->addFunction($function);
}
protected function addJS($JS)
{
return true;
$this->container->assets->addJS($JS);
}
protected function addEditorJS($JS)
{
return true;
$this->container->assets->addEditorJS($JS);
}
protected function addInlineJS($JS)
{
return true;
$this->container->assets->addInlineJS($JS);
}
protected function addSvgSymbol($symbol)
{
return true;
$this->container->assets->addSvgSymbol($symbol);
}
protected function addEditorInlineJS($JS)
{
return true;
$this->container->assets->addEditorInlineJS($JS);
}
protected function addCSS($CSS)
{
return true;
$this->container->assets->addCSS($CSS);
}
protected function addInlineCSS($CSS)
{
return true;
$this->container->assets->addInlineCSS($CSS);
}
protected function addEditorCSS($CSS)
{
return true;
$this->container->assets->addEditorCSS($CSS);
}
protected function getMeta()
{
return true;
return $this->container->assets->meta;
}
public function addMeta($key,$meta)
{
return true;
$this->container->assets->addMeta($key, $meta);
}
protected function activateAxios()
{
return true;
$this->container->assets->activateAxios();
}
protected function activateVue()
{
return true;
$this->container->assets->activateVue();
}
protected function activateTachyons()
{
return true;
$this->container->assets->activateTachyons();
}
protected function markdownToHtml($markdown)
{
return true;
$parsedown = new ParsedownExtension();
$contentArray = $parsedown->text($markdown);
@@ -188,6 +215,7 @@ abstract class Plugin implements EventSubscriberInterface
protected function getFormData($pluginName)
{
return true;
$flash = $this->container->flash->getMessages();
if(isset($flash['formdata']))

View File

@@ -3,16 +3,16 @@ const app = Vue.createApp({
<div class="w-full">
<ul>
<li v-for="(plugin,pluginname) in formDefinitions" class="w-full my-4 bg-stone-100">
<div class="flex justify-between w-full px-8 py-3 border-b border-white">
<p class="py-2">License: free</p>
<activebox
:key="pluginname"
:errors="false"
:name="pluginname"
:value="true"
:label="'active'"
></activebox>
</div>
<div class="flex justify-between w-full px-8 py-3 border-b border-white" :class="getActiveClass(pluginname)">
<p class="py-2">License: {{ plugin.license }}</p>
<div class="flex">
<label :for="pluginname" class="p-2">{{ $filters.translate('active') }}</label>
<input type="checkbox" class="w-6 h-6 my-2"
:name="pluginname"
v-model="formData[pluginname]['active']"
@change="activate(pluginname)">
</div>
</div>
<div class="w-full p-8">
<div class="w-full">
<h2 class="text-xl font-bold mb-3">{{plugin.name}}</h2>
@@ -21,7 +21,8 @@ const app = Vue.createApp({
</div>
<div class="w-full mt-6 flex justify-between">
<button @click="setCurrent(pluginname)" class="w-half p-3 bg-stone-700 hover:bg-stone-900 text-white cursor-pointer transition duration-100">Configure</button>
<button class="w-half p-3 bg-teal-500 hover:bg-teal-600 text-white cursor-pointer transition duration-100">Donate/Buy</button>
<a v-if="!checkLicense(license, plugin.license)" href="https://typemill.net/buy" target="_blank" class="w-half p-3 py-4 text-center bg-teal-500 hover:bg-teal-600 text-white cursor-pointer transition duration-100">Buy a license</a>
<a v-else-if="plugin.donate" :href="plugin.donate" target="_blank" class="w-full p-3 my-1 bg-teal-500 hover:bg-teal-600 text-white cursor-pointer transition duration-100">Donate</a>
</div>
</div>
<form class="w-full p-8" v-if="current == pluginname">
@@ -52,23 +53,40 @@ const app = Vue.createApp({
<div :class="messageClass" class="block w-full h-8 px-3 py-1 my-1 text-white transition duration-100">{{ message }}</div>
<div class="w-full">
<button type="submit" @click.prevent="save()" class="w-full p-3 my-1 bg-stone-700 hover:bg-stone-900 text-white cursor-pointer transition duration-100">Save</button>
<button @click.prevent="" class="w-full p-3 my-1 bg-teal-500 hover:bg-teal-600 text-white cursor-pointer transition duration-100">Donate/Buy</button>
<a v-if="checkLicense(license, plugin.license)" href="https://typemill.net/buy" target="_blank" class="w-full p-3 my-1 bg-teal-500 hover:bg-teal-600 text-white cursor-pointer transition duration-100">Get a license</a>
<a v-else-if="plugin.donate" :href="plugin.donate" target="_blank" class="w-full p-3 my-1 bg-teal-500 hover:bg-teal-600 text-white cursor-pointer transition duration-100">Donate</a>
</div>
</div>
</form>
</li>
</ul>
<div class="my-5 text-center">
<modal v-if="showModal" @close="showModal = false">
<template #header>
<h3>License required</h3>
</template>
<template #body>
<p>{{ modalMessage }}</p>
</template>
<template #button>
<a :href="getLinkToLicense()" class="focus:outline-none px-4 p-3 mr-3 text-white bg-teal-500 hover:bg-teal-700 transition duration-100">Check your license</a>
</template>
</modal>
</div>
</div>
</Transition>`,
data() {
return {
current: '',
formDefinitions: data.plugins,
formDefinitions: data.definitions,
formData: data.settings,
license: data.license,
message: '',
messageClass: '',
errors: {},
userroles: false,
showModal: false,
modalMessage: 'default',
}
},
mounted() {
@@ -77,6 +95,50 @@ const app = Vue.createApp({
});
},
methods: {
getActiveClass: function(pluginname)
{
if(this.formData[pluginname]['active'])
{
return 'bg-teal-500 text-white';
}
},
getLinkToLicense: function()
{
return tmaxios.defaults.baseURL + "/tm/license";
},
checkLicense: function(haystack, needle)
{
if(needle == 'MAKER' || needle == 'BUSINESS')
{
if(haystack.indexOf(needle) == -1)
{
return false;
}
}
return true;
},
activate: function(pluginname)
{
var self = this;
tmaxios.post('/api/v1/extensions',{
'csrf_name': document.getElementById("csrf_name").value,
'csrf_value': document.getElementById("csrf_value").value,
'type': 'plugins',
'name': pluginname,
'checked': this.formData[pluginname]['active']
})
.then(function (response)
{
})
.catch(function (error)
{
self.formData[pluginname]['active'] = false;
self.modalMessage = error.response.data.message;
self.showModal = true;
});
},
setCurrent: function(name)
{
if(this.current == name)

View File

@@ -1087,43 +1087,6 @@ app.component('modal', {
},
})
app.component('activebox', {
props: ['id', 'description', 'readonly', 'required', 'disabled', 'label', 'checkboxlabel', 'name', 'type', 'css', 'value', 'errors'],
data() {
return {
checked: false
}
},
template: `<div class="flex">
<label :for="name" class="p-2">{{ $filters.translate(label) }}</label>
<input type="checkbox" class="w-6 h-6 my-2"
:id="id"
:disabled="disabled"
:name="name"
v-model="checked"
@change="activate(checked, name)">
<p v-if="errors[name]" class="text-xs text-red-500">{{ errors[name] }}</p>
<p v-else class="text-xs">{{ $filters.translate(description) }}</p>
</div>`,
mounted: function()
{
if(this.value === true || this.value == 'on')
{
this.checked = true;
}
},
methods: {
activate: function(checked, name)
{
alert("yes");
},
},
})
const medialib = app.component('medialib', {
props: ['parentcomponent'],
template: `<div class="medialib">

View File

@@ -8,6 +8,7 @@ use Typemill\Controllers\ControllerApiMedia;
use Typemill\Controllers\ControllerApiSystemSettings;
use Typemill\Controllers\ControllerApiSystemThemes;
use Typemill\Controllers\ControllerApiSystemPlugins;
use Typemill\Controllers\ControllerApiSystemExtensions;
use Typemill\Controllers\ControllerApiSystemLicense;
use Typemill\Controllers\ControllerApiSystemUsers;
use Typemill\Controllers\ControllerApiImage;
@@ -24,6 +25,7 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
$group->post('/license', ControllerApiSystemLicense::class . ':createLicense')->setName('api.license.create')->add(new ApiAuthorization($acl, 'system', 'update')); # admin
$group->post('/theme', ControllerApiSystemThemes::class . ':updateTheme')->setName('api.theme.set')->add(new ApiAuthorization($acl, 'system', 'update')); # admin
$group->post('/plugin', ControllerApiSystemPlugins::class . ':updatePlugin')->setName('api.plugin.set')->add(new ApiAuthorization($acl, 'system', 'update')); # admin
$group->post('/extensions', ControllerApiSystemExtensions::class . ':activateExtension')->setName('api.extension.activate')->add(new ApiAuthorization($acl, 'system', 'update')); # admin
$group->get('/users/getbynames', ControllerApiSystemUsers::class . ':getUsersByNames')->setName('api.usersbynames')->add(new ApiAuthorization($acl, 'user', 'update')); # admin
$group->get('/users/getbyemail', ControllerApiSystemUsers::class . ':getUsersByEmail')->setName('api.usersbyemail')->add(new ApiAuthorization($acl, 'user', 'update')); # admin
$group->get('/users/getbyrole', ControllerApiSystemUsers::class . ':getUsersByRole')->setName('api.usersbyrole')->add(new ApiAuthorization($acl, 'user', 'update')); # admin

View File

@@ -4,6 +4,12 @@
'icon': 'icon-wrench'
'aclresource': 'system'
'aclprivilege': 'view'
'license':
'title': 'License'
'routename': 'license.show'
'icon': 'icon-wrench'
'aclresource': 'system'
'aclprivilege': 'view'
'themes':
'title': 'Themes'
'routename': 'themes.show'
@@ -16,12 +22,6 @@
'icon': 'icon-plug'
'aclresource': 'system'
'aclprivilege': 'view'
'license':
'title': 'License'
'routename': 'license.show'
'icon': 'icon-wrench'
'aclresource': 'system'
'aclprivilege': 'view'
'account':
'title': 'Account'
'routename': 'user.account'