Compare commits

...

39 Commits

Author SHA1 Message Date
adphi abdf1777f5 Mettre à jour 'README.md' 2020-06-20 04:31:41 +02:00
adphi 317c2483d4 deprecation notice 2020-06-20 03:59:38 +02:00
adphi d0c4cd1488 obviously, it's in front of the description 2020-06-20 03:46:31 +02:00
adphi 5a5ba37b69 Deprecated application 2020-06-20 03:44:49 +02:00
Adphi 4fecde9d9d returns error message on exception 2020-02-02 17:54:29 +01:00
Adphi 411e9e800f fix name cases 2020-02-02 13:15:44 +00:00
Adphi 6579503c63 Makefile: added make version 2020-02-01 15:10:33 +01:00
Adphi ad5306cf67 occweb lowercase 2020-02-01 14:54:37 +01:00
Adphi f2d7ff4c14 increment version 2020-01-30 22:05:35 +01:00
Adphi aa2848cfee fix #11 2020-01-30 22:04:23 +01:00
Adphi e5d211826f fix Makefile dist 2020-01-29 22:51:19 +01:00
Adphi 222e9d5956 fix #6 2020-01-29 22:03:47 +01:00
Adphi 93e4701a82 v0.0.5 2020-01-26 15:59:19 +01:00
Adphi 5e7ddb1578 build dist 2020-01-26 15:53:43 +01:00
Adphi e03bd71092 fix app compliance 2020-01-26 15:38:26 +01:00
Adphi 2447aea115 Fix core server lib import path 2019-07-20 14:02:52 +02:00
Adphi b4761ebb4f updated build 2019-06-04 19:45:21 +02:00
Adphi a9019903cf added version 16 to info.xml 2019-06-04 19:43:58 +02:00
Adphi 608b0e2462 removed memory infos 2019-01-24 20:22:55 +01:00
Adphi e725fd3ed7 rebuild 2019-01-24 20:04:24 +01:00
Adphi 4dbbcce938 rebuild 2019-01-24 20:02:06 +01:00
Adphi 16de1641ea Merge branch 'master' of http://git.adphi.net/Adphi/OCCWeb 2019-01-24 19:56:32 +01:00
Adphi 77b1f007cf fix #1 remove dirty hack 2019-01-24 19:56:20 +01:00
Adphi 9ade0837b0 added screenshot to README.md 2019-01-21 18:27:30 +01:00
Adphi cee4b7a7e1 fix website url in info.xml 2019-01-21 18:24:52 +01:00
Adphi 42ccc2e7e5 improved app infos, add website 2019-01-21 18:22:46 +01:00
Adphi 1831886e20 improved app infos, fix app category 2019-01-21 18:17:23 +01:00
Adphi a79cc12161 build 2019-01-21 17:57:25 +01:00
Adphi 8c4d675e1f Updated README.md 2019-01-19 21:00:53 +01:00
Adphi 1745aa185a fix greetings not updating date on exit 2019-01-19 19:15:22 +01:00
Adphi a1efcf2096 updated build 2019-01-19 18:45:27 +01:00
Adphi d077d211c8 fixed android keyboard 2019-01-19 18:43:06 +01:00
Adphi 96dfe2ebdb updated build 2019-01-19 18:25:55 +01:00
Adphi e5a9f0142f add scroll down on key down 2019-01-19 18:09:39 +01:00
Adphi 4fc2359fdc Updated README.md 2019-01-19 17:45:02 +01:00
Adphi 83ed35c4c5 Fix Controllers Files names 2019-01-19 17:20:07 +01:00
Adphi 0d59a3595e again... sorry. 2019-01-19 17:07:42 +01:00
Adphi 395cbee8cc fix dist 2019-01-19 16:58:37 +01:00
Adphi 2325df3667 build dist 2019-01-19 16:52:40 +01:00
15 changed files with 210 additions and 582 deletions

BIN
.DS_Store vendored

Binary file not shown.

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea
build

View File

@ -115,20 +115,21 @@ dist:
source:
rm -rf $(source_build_directory)
mkdir -p $(source_build_directory)
tar cvzf $(source_package_name).tar.gz ../$(app_name) \
tar \
--exclude-vcs \
--exclude="../$(app_name)/build" \
--exclude="../$(app_name)/js/node_modules" \
--exclude="../$(app_name)/node_modules" \
--exclude="../$(app_name)/*.log" \
--exclude="../$(app_name)/js/*.log" \
-cvzf $(source_package_name).tar.gz ../$(app_name)
# Builds the source package for the app store, ignores php and js tests
.PHONY: appstore
appstore:
rm -rf $(appstore_build_directory)
mkdir -p $(appstore_build_directory)
tar cvzf $(appstore_package_name).tar.gz ../$(app_name) \
tar \
--exclude-vcs \
--exclude="../$(app_name)/build" \
--exclude="../$(app_name)/tests" \
@ -150,8 +151,23 @@ appstore:
--exclude="../$(app_name)/protractor\.*" \
--exclude="../$(app_name)/.*" \
--exclude="../$(app_name)/js/.*" \
-cvzf $(appstore_package_name).tar.gz ../$(app_name)
.PHONY: test
test: composer
$(CURDIR)/vendor/phpunit/phpunit/phpunit -c phpunit.xml
$(CURDIR)/vendor/phpunit/phpunit/phpunit -c phpunit.integration.xml
.PHONY: sign
sign:
@openssl dgst -sha512 -sign ~/.nextcloud/certificates/occweb.key build/artifacts/appstore/occweb.tar.gz |openssl base64
.PHONY: version
version:
@echo "Creating version v$(VERSION)"
@sed -i "s/<version>[0-9a-z.]\{1,\}<\/version>/<version>$(VERSION)<\/version>/g" appinfo/info.xml
@git tag v$(VERSION)
@git push origin v$(VERSION)
@make dist
@echo "\nRelease Signature: \n"
@make sign

View File

@ -1,52 +1,25 @@
# Test Nextcloud App
# ⚠️ Deprecated ⚠️ OCCWeb terminal
### A web terminal for admins to launch Nextcloud's occ commands
![occweb](https://git.adphi.net/Adphi/OCCWeb/raw/master/appinfo/screenshot.png)
## ⚠️ Deprecated ⚠️
As nextcloudd has no native support for asynchronous operations, due to the use of php, this aplication is deprecated, and will no longer support the Nextcloud' future versions (19+). I did not find a way to implemement true support for interactive and long running occ tasks in a web terminal whitout introducing addtional dependencies (through websockets, for example), the lack of true asynchronous occ operations can lead to serious alterations of voluminous instances.
[This issue](https://github.com/nextcloud/server/issues/16726) may give some hints on why I decided to not support this application anymore.
And over all of this , I want to say I really dislike, even dispise the overall Nextloud teams communication, the "we are the best", and other "look, we make so many commits", witout fixing good old issues, moving fast forward, "we make more commits than pydio"! what a good point ! your more than 10x their developpers ! What a 'prouesse' !!!
## Install
Place this app in **nextcloud/apps/**
## Building the app
## ⚠️ Warnings ⚠️
The app can be built by using the provided Makefile by running:
- The application is not a real interactive terminal and does not support long running tasks.
So if your instance is pretty big, commands like `occ files:scan` will time out and fail.
- Do not use `occ maintenance:mode --on`, obvious...
make
This requires the following things to be present:
* make
* which
* tar: for building the archive
* curl: used if phpunit and composer are not installed to fetch them from the web
* npm: for building and testing everything JS, only required if a package.json is placed inside the **js/** folder
The make command will install or update Composer dependencies if a composer.json is present and also **npm run build** if a package.json is present in the **js/** folder. The npm **build** script should use local paths for build systems and package managers, so people that simply want to build the app won't need to install npm libraries globally, e.g.:
**package.json**:
```json
"scripts": {
"test": "node node_modules/gulp-cli/bin/gulp.js karma",
"prebuild": "npm install && node_modules/bower/bin/bower install && node_modules/bower/bin/bower update",
"build": "node node_modules/gulp-cli/bin/gulp.js"
}
```
## Publish to App Store
First get an account for the [App Store](http://apps.nextcloud.com/) then run:
make && make appstore
The archive is located in build/artifacts/appstore and can then be uploaded to the App Store.
## Running tests
You can use the provided Makefile to run all tests by using:
make test
This will run the PHP unit and integration tests and if a package.json is present in the **js/** folder will execute **npm run test**
Of course you can also install [PHPUnit](http://phpunit.de/getting-started.html) and use the configurations directly:
phpunit -c phpunit.xml
or:
phpunit -c phpunit.integration.xml
for integration tests
## TODOs:
See [open issues](https://git.adphi.net/Adphi/OCCWeb/issues)

View File

@ -3,16 +3,19 @@
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>occweb</id>
<name>OCC Web</name>
<summary>OCC Command in a web terminal</summary>
<summary>OCC Commands in a web terminal</summary>
<description><![CDATA[Run OCC Commands in a web terminal]]></description>
<version>0.0.1</version>
<version>0.0.7</version>
<licence>agpl</licence>
<author mail="adphi.apps@gmail.com" >Adphi</author>
<namespace>OCCWeb</namespace>
<category>security</category>
<bugs>https://git.adphi.net/Adphi/TestNextcloudApp</bugs>
<category>tools</category>
<website>https://git.adphi.net/adphi/occweb</website>
<bugs>https://git.adphi.net/adphi/occweb/issues</bugs>
<repository>https://git.adphi.net/adphi/occweb</repository>
<screenshot>https://git.adphi.net/adphi/occweb/raw/master/appinfo/screenshot.png</screenshot>
<dependencies>
<nextcloud min-version="13" max-version="15"/>
<nextcloud min-version="13" max-version="18"/>
</dependencies>
<navigations>
<navigation role="admin">

BIN
appinfo/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

View File

@ -55,10 +55,10 @@
position: absolute;
left: -16px;
top: 0;
width: 16px;
height: 16px;
/*width: 16px;*/
/*height: 16px;*/
/* this seems to work after all on Android */
/*left: -99999px;
left: -99999px;
clip: rect(1px,1px,1px,1px);
/* on desktop textarea appear when paste */
/* opacity is needed for Edge and IE
@ -76,7 +76,7 @@
white-space: pre;
text-indent: -9999em; /* better cursor hiding for Safari and IE */
top: calc(var(--cursor-line, 0) * 1em);
visibility: hidden;
/*visibility: hidden;*/
}
.cmd .noselect, .cmd [role="presentation"]:not(.cursor-line) > span:last-child,
.cmd .cursor-line > span:last-child > span:last-child {

View File

@ -32,7 +32,9 @@
});
}
}, {
greetings: '[[;green;]' + new Date().toString().slice(0, 24) + "]\n\nPress [[;#ff5e99;]Enter] for more information on [[;#009ae3;]occ] commands.\n",
greetings: function (callback) {
callback('[[;green;]' + new Date().toString().slice(0, 24) + "]\n\nPress [[;#ff5e99;]Enter] for more information on [[;#009ae3;]occ] commands.\n")
},
name: 'occ',
prompt: 'occ $ ',
completion: response,
@ -41,5 +43,8 @@
}
});
});
$('html').keypress(function(){
scrollToBottom()
})
});
})(OC, window, jQuery);

Binary file not shown.

View File

@ -1,125 +0,0 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: philippe-adrien
* Date: 2019-01-19
* Time: 12:27
*/
namespace OCA\TestNextcloudApp\Controller;
/**
* Converts an ANSI text to HTML5.
*/
class AnsiToHtmlConverter
{
protected $charset;
protected $inlineStyles;
protected $inlineColors;
protected $colorNames;
public function __construct($inlineStyles = true, $charset = 'UTF-8')
{
$this->inlineStyles = $inlineStyles;
$this->charset = $charset;
$this->colorNames = array(
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white',
'', '',
'brblack', 'brred', 'brgreen', 'bryellow', 'brblue', 'brmagenta', 'brcyan', 'brwhite',
);
}
public function convert($text)
{
// remove cursor movement sequences
$text = preg_replace('#\e\[(K|s|u|2J|2K|\d+(A|B|C|D|E|F|G|J|K|S|T)|\d+;\d+(H|f))#', '', $text);
// remove character set sequences
$text = preg_replace('#\e(\(|\))(A|B|[0-2])#', '', $text);
$text = htmlspecialchars($text, PHP_VERSION_ID >= 50400 ? ENT_QUOTES | ENT_SUBSTITUTE : ENT_QUOTES, $this->charset);
// carriage return
$text = preg_replace('#^.*\r(?!\n)#m', '', $text);
$tokens = $this->tokenize($text);
// a backspace remove the previous character but only from a text token
foreach ($tokens as $i => $token) {
if ('backspace' == $token[0]) {
$j = $i;
while (--$j >= 0) {
if ('text' == $tokens[$j][0] && strlen($tokens[$j][1]) > 0) {
$tokens[$j][1] = substr($tokens[$j][1], 0, -1);
break;
}
}
}
}
$html = '';
foreach ($tokens as $token) {
if ('text' == $token[0]) {
$html .= $token[1];
} elseif ('color' == $token[0]) {
$html .= $this->convertAnsiToColor($token[1]);
}
}
if ($this->inlineStyles) {
$html = sprintf('<span style="background-color: %s; color: %s">%s</span>', $this->inlineColors['black'], $this->inlineColors['white'], $html);
} else {
$html = sprintf('<span class="ansi_color_bg_black ansi_color_fg_white">%s</span>', $html);
}
// remove empty span
$html = preg_replace('#<span[^>]*></span>#', '', $html);
return $html;
}
protected function convertAnsiToColor($ansi)
{
$bg = 0;
$fg = 7;
$as = '';
if ('0' != $ansi && '' != $ansi) {
$options = explode(';', $ansi);
foreach ($options as $option) {
if ($option >= 30 && $option < 38) {
$fg = $option - 30;
} elseif ($option >= 40 && $option < 48) {
$bg = $option - 40;
} elseif (39 == $option) {
$fg = 7;
} elseif (49 == $option) {
$bg = 0;
}
}
// options: bold => 1, underscore => 4, blink => 5, reverse => 7, conceal => 8
if (in_array(1, $options)) {
$fg += 10;
$bg += 10;
}
if (in_array(4, $options)) {
$as = '; text-decoration: underline';
}
if (in_array(7, $options)) {
$tmp = $fg;
$fg = $bg;
$bg = $tmp;
}
}
if ($this->inlineStyles) {
return sprintf('</span><span style="background-color: %s; color: %s%s">', $this->inlineColors[$this->colorNames[$bg]], $this->inlineColors[$this->colorNames[$fg]], $as);
} else {
return sprintf('</span><span class="ansi_color_bg_%s ansi_color_fg_%s">', $this->colorNames[$bg], $this->colorNames[$fg]);
}
}
protected function tokenize($text)
{
$tokens = array();
preg_match_all("/(?:\e\[(.*?)m|(\x08))/", $text, $matches, PREG_OFFSET_CAPTURE);
$offset = 0;
foreach ($matches[0] as $i => $match) {
if ($match[1] - $offset > 0) {
$tokens[] = array('text', substr($text, $offset, $match[1] - $offset));
}
$tokens[] = array("\x08" == $match[0] ? 'backspace' : 'color', $matches[1][$i][0]);
$offset = $match[1] + strlen($match[0]);
}
if ($offset < strlen($text)) {
$tokens[] = array('text', substr($text, $offset));
}
return $tokens;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace OCA\OCCWeb\Controller;
use OC\AppFramework\Http\Request;
class FakeRequest extends Request {
public $server = array(
'argv' => ["occ"],
);
/**
* FakeRequest constructor.
*/
public function __construct() {
}
}

View File

@ -1,363 +0,0 @@
<?php
namespace OCA\OCCWeb\Controller;
use OC\Console\Application;
use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Controller;
use OCP\ILogger;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\OutputInterface;
class OCCController extends Controller implements IRequest
{
private $logger;
private $userId;
private $application;
private $output;
public $server;
public function __construct(ILogger $logger, $AppName, IRequest $request, $UserId)
{
parent::__construct($AppName, $request);
$this->logger = $logger;
$this->userId = $UserId;
$this->server = array(
'argv' => ["occ"],
);
$this->application = new Application(
\OC::$server->getConfig(),
\OC::$server->getEventDispatcher(),
$this,
\OC::$server->getLogger(),
\OC::$server->query(\OC\MemoryInfo::class)
);
$this->application->setAutoExit(false);
// $this->output = new OCCOutput();
$this->output = new OCCOutput(OutputInterface::VERBOSITY_NORMAL, true);
$this->application->loadCommands(new StringInput(""), $this->output);
}
/**
* CAUTION: the @Stuff turns off security checks; for this page no admin is
* required and no CSRF check. If you don't know what CSRF is, read
* it up in the docs or you might create a security hole. This is
* basically the only required method to add this exemption, don't
* add it to any other method if you don't exactly know what it does
*
* @NoCSRFRequired
*/
public function index()
{
return new TemplateResponse('occweb', 'index'); // templates/index.php
}
private function run($input)
{
try {
$this->application->run($input, $this->output);
return $this->output->fetch();
} catch (\Exception $ex) {
exceptionHandler($ex);
} catch (Error $ex) {
exceptionHandler($ex);
}
}
/**
* @NoAdminRequired
* @param string $command
* @return DataResponse
*/
public function cmd($command)
{
$this->logger->info($command);
$input = new StringInput($command);
// TODO : Interactive ?
$response = $this->run($input);
// $this->logger->info($response);
// $converter = new AnsiToHtmlConverter();
// return new DataResponse($converter->convert($response));
return new DataResponse($response);
}
public function list() {
$defs = $this->application->application->all();
$cmds = array();
foreach ($defs as $d) {
array_push($cmds, $d->getName());
}
return new DataResponse($cmds);
}
/**
* Lets you access post and get parameters by the index
* In case of json requests the encoded json body is accessed
*
* @param string $key the key which you want to access in the URL Parameter
* placeholder, $_POST or $_GET array.
* The priority how they're returned is the following:
* 1. URL parameters
* 2. POST parameters
* 3. GET parameters
* @param mixed $default If the key is not found, this value will be returned
* @return mixed the content of the array
* @since 6.0.0
*/
public function getParam(string $key, $default = null)
{
// TODO: Implement getParam() method.
}
/**
* Returns all params that were received, be it from the request
*
* (as GET or POST) or through the URL by the route
*
* @return array the array with all parameters
* @since 6.0.0
*/
public function getParams(): array
{
// TODO: Implement getParams() method.
}
/**
* Returns the method of the request
*
* @return string the method of the request (POST, GET, etc)
* @since 6.0.0
*/
public function getMethod(): string
{
// TODO: Implement getMethod() method.
}
/**
* Shortcut for accessing an uploaded file through the $_FILES array
*
* @param string $key the key that will be taken from the $_FILES array
* @return array the file in the $_FILES element
* @since 6.0.0
*/
public function getUploadedFile(string $key)
{
// TODO: Implement getUploadedFile() method.
}
/**
* Shortcut for getting env variables
*
* @param string $key the key that will be taken from the $_ENV array
* @return array the value in the $_ENV element
* @since 6.0.0
*/
public function getEnv(string $key)
{
// TODO: Implement getEnv() method.
}
/**
* Shortcut for getting cookie variables
*
* @param string $key the key that will be taken from the $_COOKIE array
* @return string|null the value in the $_COOKIE element
* @since 6.0.0
*/
public function getCookie(string $key)
{
// TODO: Implement getCookie() method.
}
/**
* Checks if the CSRF check was correct
*
* @return bool true if CSRF check passed
* @since 6.0.0
*/
public function passesCSRFCheck(): bool
{
// TODO: Implement passesCSRFCheck() method.
}
/**
* Checks if the strict cookie has been sent with the request if the request
* is including any cookies.
*
* @return bool
* @since 9.0.0
*/
public function passesStrictCookieCheck(): bool
{
// TODO: Implement passesStrictCookieCheck() method.
}
/**
* Checks if the lax cookie has been sent with the request if the request
* is including any cookies.
*
* @return bool
* @since 9.0.0
*/
public function passesLaxCookieCheck(): bool
{
// TODO: Implement passesLaxCookieCheck() method.
}
/**
* Returns an ID for the request, value is not guaranteed to be unique and is mostly meant for logging
* If `mod_unique_id` is installed this value will be taken.
*
* @return string
* @since 8.1.0
*/
public function getId(): string
{
// TODO: Implement getId() method.
}
/**
* Returns the remote address, if the connection came from a trusted proxy
* and `forwarded_for_headers` has been configured then the IP address
* specified in this header will be returned instead.
* Do always use this instead of $_SERVER['REMOTE_ADDR']
*
* @return string IP address
* @since 8.1.0
*/
public function getRemoteAddress(): string
{
// TODO: Implement getRemoteAddress() method.
}
/**
* Returns the server protocol. It respects reverse proxy servers and load
* balancers.
*
* @return string Server protocol (http or https)
* @since 8.1.0
*/
public function getServerProtocol(): string
{
// TODO: Implement getServerProtocol() method.
}
/**
* Returns the used HTTP protocol.
*
* @return string HTTP protocol. HTTP/2, HTTP/1.1 or HTTP/1.0.
* @since 8.2.0
*/
public function getHttpProtocol(): string
{
// TODO: Implement getHttpProtocol() method.
}
/**
* Returns the request uri, even if the website uses one or more
* reverse proxies
*
* @return string
* @since 8.1.0
*/
public function getRequestUri(): string
{
// TODO: Implement getRequestUri() method.
}
/**
* Get raw PathInfo from request (not urldecoded)
*
* @throws \Exception
* @return string Path info
* @since 8.1.0
*/
public function getRawPathInfo(): string
{
// TODO: Implement getRawPathInfo() method.
}
/**
* Get PathInfo from request
*
* @throws \Exception
* @return string|false Path info or false when not found
* @since 8.1.0
*/
public function getPathInfo()
{
// TODO: Implement getPathInfo() method.
}
/**
* Returns the script name, even if the website uses one or more
* reverse proxies
*
* @return string the script name
* @since 8.1.0
*/
public function getScriptName(): string
{
// TODO: Implement getScriptName() method.
}
/**
* Checks whether the user agent matches a given regex
*
* @param array $agent array of agent names
* @return bool true if at least one of the given agent matches, false otherwise
* @since 8.1.0
*/
public function isUserAgent(array $agent): bool
{
// TODO: Implement isUserAgent() method.
}
/**
* Returns the unverified server host from the headers without checking
* whether it is a trusted domain
*
* @return string Server host
* @since 8.1.0
*/
public function getInsecureServerHost(): string
{
// TODO: Implement getInsecureServerHost() method.
}
/**
* Returns the server host from the headers, or the first configured
* trusted domain if the host isn't in the trusted list
*
* @return string Server host
* @since 8.1.0
*/
public function getServerHost(): string
{
// TODO: Implement getServerHost() method.
}
/**
* @param string $name
*
* @return string
* @since 6.0.0
*/
public function getHeader(string $name): string
{
// TODO: Implement getHeader() method.
}
}
function exceptionHandler($exception)
{
echo "An unhandled exception has been thrown:" . PHP_EOL;
echo $exception;
exit(1);
}

View File

@ -1,34 +0,0 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: philippe-adrien
* Date: 2019-01-18
* Time: 19:08
*/
namespace OCA\OCCWeb\Controller;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class OCCOutput extends BufferedOutput implements ConsoleOutputInterface
{
/**
* Gets the OutputInterface for errors.
*
* @return OutputInterface
*/
public function getErrorOutput()
{
// TODO: Implement getErrorOutput() method.
return $this;
}
public function setErrorOutput(OutputInterface $error)
{
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace OCA\OCCWeb\Controller;
use Exception;
use OC;
use OC\Console\Application;
use OC\MemoryInfo;
use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Controller;
use OCP\ILogger;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\OutputInterface;
class OccController extends Controller
{
private $logger;
private $userId;
private $application;
private $output;
public function __construct(ILogger $logger, $AppName, IRequest $request, $userId)
{
parent::__construct($AppName, $request);
$this->logger = $logger;
$this->userId = $userId;
$this->application = new Application(
OC::$server->getConfig(),
OC::$server->getEventDispatcher(),
new FakeRequest(),
OC::$server->getLogger(),
OC::$server->query(MemoryInfo::class)
);
$this->application->setAutoExit(false);
$this->output = new OccOutput(OutputInterface::VERBOSITY_NORMAL, true);
$this->application->loadCommands(new StringInput(""), $this->output);
}
/**
* @NoCSRFRequired
*/
public function index()
{
return new TemplateResponse('occweb', 'index');
}
/**
* @param $input
* @return string
*/
private function run($input)
{
try {
$this->application->run($input, $this->output);
return $this->output->fetch();
} catch (Exception $ex) {
$this->logger->logException($ex);
return "error: " . $ex->getMessage();
}
}
/**
* @param string $command
* @return DataResponse
*/
public function cmd($command)
{
$this->logger->debug($command);
$input = new StringInput($command);
$response = $this->run($input);
$this->logger->debug($response);
return new DataResponse($response);
}
public function list() {
$defs = $this->application->application->all();
$cmds = array();
foreach ($defs as $d) {
array_push($cmds, $d->getName());
}
return new DataResponse($cmds);
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace OCA\OCCWeb\Controller;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
class OccOutput extends BufferedOutput implements ConsoleOutputInterface
{
private $consoleSectionOutputs = [];
private $stream;
/**
* Gets the OutputInterface for errors.
*
* @return OutputInterface
*/
public function getErrorOutput()
{
// TODO: Implement getErrorOutput() method.
return $this;
}
public function setErrorOutput(OutputInterface $error)
{
}
/**
* Creates a new output section.
*/
public function section(): ConsoleSectionOutput {
if ($this->stream === null) {
$this->stream = fopen('php://temp','w');
}
return new ConsoleSectionOutput($this->stream, $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter());
}
}