mirror of
https://github.com/typemill/typemill.git
synced 2025-08-12 17:14:03 +02:00
Activate plugins
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
@@ -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')
|
||||
]
|
||||
|
@@ -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
|
||||
|
@@ -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']))
|
||||
|
@@ -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)
|
||||
|
@@ -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">
|
||||
|
@@ -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
|
||||
|
@@ -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'
|
||||
|
Reference in New Issue
Block a user