Compare commits

..

1 Commits

Author SHA1 Message Date
Adphi ea221aa95f build dist 2019-01-19 16:52:40 +01:00
17 changed files with 609 additions and 237 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

2
.gitignore vendored
View File

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

View File

@ -115,59 +115,43 @@ dist:
source:
rm -rf $(source_build_directory)
mkdir -p $(source_build_directory)
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)
tar cvzf $(source_package_name).tar.gz ../$(app_name)
# --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" \
# 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 \
--exclude-vcs \
--exclude="../$(app_name)/build" \
--exclude="../$(app_name)/tests" \
--exclude="../$(app_name)/Makefile" \
--exclude="../$(app_name)/*.log" \
--exclude="../$(app_name)/phpunit*xml" \
--exclude="../$(app_name)/composer.*" \
--exclude="../$(app_name)/js/node_modules" \
--exclude="../$(app_name)/js/tests" \
--exclude="../$(app_name)/js/test" \
--exclude="../$(app_name)/js/*.log" \
--exclude="../$(app_name)/js/package.json" \
--exclude="../$(app_name)/js/bower.json" \
--exclude="../$(app_name)/js/karma.*" \
--exclude="../$(app_name)/js/protractor.*" \
--exclude="../$(app_name)/package.json" \
--exclude="../$(app_name)/bower.json" \
--exclude="../$(app_name)/karma.*" \
--exclude="../$(app_name)/protractor\.*" \
--exclude="../$(app_name)/.*" \
--exclude="../$(app_name)/js/.*" \
-cvzf $(appstore_package_name).tar.gz ../$(app_name)
tar cvzf $(appstore_package_name).tar.gz ../$(app_name)
# --exclude-vcs \
# --exclude="../$(app_name)/build" \
# --exclude="../$(app_name)/tests" \
# --exclude="../$(app_name)/Makefile" \
# --exclude="../$(app_name)/*.log" \
# --exclude="../$(app_name)/phpunit*xml" \
# --exclude="../$(app_name)/composer.*" \
# --exclude="../$(app_name)/js/node_modules" \
# --exclude="../$(app_name)/js/tests" \
# --exclude="../$(app_name)/js/test" \
# --exclude="../$(app_name)/js/*.log" \
# --exclude="../$(app_name)/js/package.json" \
# --exclude="../$(app_name)/js/bower.json" \
# --exclude="../$(app_name)/js/karma.*" \
# --exclude="../$(app_name)/js/protractor.*" \
# --exclude="../$(app_name)/package.json" \
# --exclude="../$(app_name)/bower.json" \
# --exclude="../$(app_name)/karma.*" \
# --exclude="../$(app_name)/protractor\.*" \
# --exclude="../$(app_name)/.*" \
# --exclude="../$(app_name)/js/.*" \
.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,25 +1,52 @@
# ⚠️ 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
# Test Nextcloud App
Place this app in **nextcloud/apps/**
## ⚠️ Warnings ⚠️
## Building the app
- 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...
The app can be built by using the provided Makefile by running:
## TODOs:
See [open issues](https://git.adphi.net/Adphi/OCCWeb/issues)
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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

Binary file not shown.

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

BIN
lib/Controller/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,125 @@
<?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

@ -1,20 +0,0 @@
<?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

@ -0,0 +1,363 @@
<?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

@ -0,0 +1,34 @@
<?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

@ -1,88 +0,0 @@
<?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

@ -1,43 +0,0 @@
<?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());
}
}