Port admin settings to vue (#1880)

* Port admin settings to vue

Co-authored-by: anoy. <anoymouserver@users.noreply.github.com>
Co-authored-by: Benjamin Brahmer <info@b-brahmer.de>
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
This commit is contained in:
Carl Schwan 2022-08-30 18:07:25 +02:00 committed by GitHub
parent 39ac02c034
commit 753e88793e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 21164 additions and 473 deletions

7
.eslintrc.js Normal file
View File

@ -0,0 +1,7 @@
// SPDX-FileCopyrightText: Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: AGPL-3.0-or-later
module.exports = {
extends: [
'@nextcloud',
]
}

47
.github/workflows/lint-eslint.yml vendored Normal file
View File

@ -0,0 +1,47 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
# SPDX-FileCopyrightText: Nextcloud contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
name: Lint
on:
pull_request:
push:
branches:
- main
- master
- stable*
jobs:
lint:
runs-on: ubuntu-latest
name: eslint
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Read package.json node and npm engines version
uses: skjnldsv/read-package-engines-version-actions@v1.2
id: versions
with:
fallbackNode: '^12'
fallbackNpm: '^6'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@v3
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}
- name: Set up npm ${{ steps.versions.outputs.npmVersion }}
run: npm i -g npm@"${{ steps.versions.outputs.npmVersion }}"
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint

View File

@ -5,6 +5,7 @@ The format is mostly based on [Keep a Changelog](https://keepachangelog.com/en/1
# Unreleased
## [18.x.x]
### Changed
- Ported the admin settings to vue (#2353)
### Fixed
- Fix PHP 8.1 deprecations (#1861)

View File

@ -83,6 +83,8 @@ endif
# Installs npm dependencies
.PHONY: npm
npm:
$(npm) ci
$(npm) run build
ifneq (, $(npm))
cd js && $(npm) run build
else
@ -171,7 +173,7 @@ appstore:
# on macOS there is no option "--parents" for the "cp" command
mkdir -p $(appstore_sign_dir)/$(app_name)/js/build $(appstore_sign_dir)/$(app_name)/js/admin
cp js/build/app.min.js $(appstore_sign_dir)/$(app_name)/js/build
cp js/admin/Admin.js $(appstore_sign_dir)/$(app_name)/js/admin
cp js/build/news-admin-settings.js* $(appstore_sign_dir)/$(app_name)/js/build
# export the key and cert to a file
mkdir -p $(cert_dir)

5
babel.config.js Normal file
View File

@ -0,0 +1,5 @@
// SPDX-FileCopyrightText: Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: AGPL-3.0-or-later
const babelConfig = require('@nextcloud/babel-config')
module.exports = babelConfig

57
css/explore.css Normal file
View File

@ -0,0 +1,57 @@
/**
* Nextcloud - News
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @copyright 2020, Jan C. Borchardt, https://jancborchardt.net
* @copyright Bernhard Posselt 2014
*/
/**
* Explore styles
*/
.explore #app-content-wrapper {
height: 100%;
}
#explore {
height: 100%;
width: 100%;
padding: 45px 0 45px 45px;
}
#explore .grid-item {
width: 300px;
border: 2px solid var(--color-border);
border-radius: var(--border-radius-large);
margin: 0 24px 24px 0;
padding: 24px;
}
#explore .grid-item .explore-title {
background-repeat: no-repeat;
background-position: 0 center;
background-size: 24px;
padding-left: 32px;
}
#explore .grid-item .explore-title a {
word-wrap: break-word;
}
#explore .grid-item .explore-title a:hover, #explore .grid-item .explore-title a:focus {
text-decoration: underline;
}
#explore .grid-item .explore-logo {
text-align: center;
margin-top: 25px;
}
#explore .grid-item .explore-logo img {
width: 100%;
}
#explore .grid-item .explore-subscribe {
margin-top: 16px;
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/*# sourceMappingURL=explore.css.map */

View File

@ -1,64 +0,0 @@
/**
* Nextcloud - News
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @copyright 2020, Jan C. Borchardt, https://jancborchardt.net
* @copyright Bernhard Posselt 2014
*/
/**
* Explore styles
*/
.explore #app-content-wrapper {
height: 100%;
}
#explore {
height: 100%;
width: 100%;
padding: 45px 0 45px 45px;
.grid-item {
width: 300px;
border: 2px solid var(--color-border);
border-radius: var(--border-radius-large);
margin: 0 24px 24px 0;
padding: 24px;
.explore-title {
background-repeat: no-repeat;
background-position: 0 center;
background-size: 24px;
padding-left: 32px;
a {
word-wrap: break-word;
&:hover,
&:focus {
text-decoration: underline;
}
}
}
.explore-logo {
text-align: center;
margin-top: 25px;
img {
width: 100%;
}
}
.explore-subscribe {
margin-top: 16px;
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}

View File

@ -1,4 +1,4 @@
@media only screen and (max-width: $breakpoint_mobile) {
@media only screen and (max-width: 1024px) {
#app-content .utils .date {
display: none;
}

View File

@ -39,7 +39,7 @@ const sources = [
'directive/**/*.js'
];
const testSources = ['tests/**/*.js'];
const watchSources = sources.concat(testSources).concat(['*.js']);
const watchSources = sources.concat(testSources).concat(['*.js', '!news-admin-settings.js']);
const lintSources = watchSources;
// tasks

View File

@ -1,114 +0,0 @@
<?php
/**
* Nextcloud - News
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Alessandro Cosentino <cosenal@gmail.com>
* @author Bernhard Posselt <dev@bernhard-posselt.com>
*
* @copyright 2012 Alessandro Cosentino
* @copyright 2012-2014 Bernhard Posselt
*/
namespace OCA\News\Controller;
use OCA\News\AppInfo\Application;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\IRequest;
use OCP\AppFramework\Controller;
/**
* Class AdminController
*
* @package OCA\News\Controller
*/
class AdminController extends Controller
{
/**
* @var IConfig
*/
private $config;
/**
* AdminController constructor.
*
* @param IRequest $request The request
* @param IConfig $config Config for nextcloud
*/
public function __construct(IRequest $request, IConfig $config)
{
parent::__construct(Application::NAME, $request);
$this->config = $config;
}
/**
* Controller main entry.
*
* There are no checks for the index method since the output is
* rendered in admin/admin.php
*
* @return TemplateResponse
*/
public function index(): TemplateResponse
{
return new TemplateResponse($this->appName, 'admin', $this->getData(), 'blank');
}
/**
* Get admin data.
*
* @return array
*/
private function getData(): array
{
$data = [];
foreach (array_keys(Application::DEFAULT_SETTINGS) as $setting) {
$data[$setting] = $this->config->getAppValue(
Application::NAME,
$setting,
Application::DEFAULT_SETTINGS[$setting]
);
}
return $data;
}
/**
* Update the app config.
*
* @param int $autoPurgeMinimumInterval New minimum interval for auto-purge
* @param int $autoPurgeCount New value of auto-purge count
* @param int $maxRedirects New value for max amount of redirects
* @param int $feedFetcherTimeout New timeout value for feed fetcher
* @param bool $useCronUpdates Whether or not to use cron updates
* @param string $exploreUrl URL to use for the explore feed
* @param int $updateInterval Interval in which the feeds will be updated
*
* @return array with the updated values
*/
public function update(
int $autoPurgeMinimumInterval,
int $autoPurgeCount,
int $maxRedirects,
int $feedFetcherTimeout,
bool $useCronUpdates,
string $exploreUrl,
int $updateInterval
): array {
$this->config->setAppValue($this->appName, 'autoPurgeMinimumInterval', $autoPurgeMinimumInterval);
$this->config->setAppValue($this->appName, 'autoPurgeCount', $autoPurgeCount);
$this->config->setAppValue($this->appName, 'maxRedirects', $maxRedirects);
$this->config->setAppValue($this->appName, 'feedFetcherTimeout', $feedFetcherTimeout);
$this->config->setAppValue($this->appName, 'useCronUpdates', $useCronUpdates);
$this->config->setAppValue($this->appName, 'exploreUrl', $exploreUrl);
$this->config->setAppValue($this->appName, 'updateInterval', $updateInterval);
return $this->getData();
}
}

View File

@ -6,6 +6,7 @@ use OCA\News\AppInfo\Application;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\Settings\ISettings;
use OCP\AppFramework\Services\IInitialState;
class AdminSettings implements ISettings
{
@ -14,25 +15,26 @@ class AdminSettings implements ISettings
* @var IConfig
*/
private $config;
/** @var IInitialState */
private $initialState;
public function __construct(IConfig $config)
public function __construct(IConfig $config, IInitialState $initialState)
{
$this->config = $config;
$this->initialState = $initialState;
}
public function getForm()
{
$data = [];
foreach (array_keys(Application::DEFAULT_SETTINGS) as $setting) {
$data[$setting] = $this->config->getAppValue(
$this->initialState->provideInitialState($setting, $this->config->getAppValue(
Application::NAME,
$setting,
Application::DEFAULT_SETTINGS[$setting]
);
(string)Application::DEFAULT_SETTINGS[$setting]
));
}
return new TemplateResponse(Application::NAME, 'admin', $data);
return new TemplateResponse(Application::NAME, 'admin', []);
}
public function getSection()

20794
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

49
package.json Normal file
View File

@ -0,0 +1,49 @@
{
"name": "news",
"description": "News",
"version": "0.0.1",
"author": "Carl Schwan <carl@carlschwan.eu>",
"contributors": [],
"bugs": {
"url": "https://github.com/nextcloud/news/issues"
},
"license": "agpl",
"private": true,
"scripts": {
"build": "webpack --node-env production --progress",
"dev": "webpack --node-env development --progress",
"watch": "webpack --node-env development --progress --watch",
"serve": "webpack --node-env development serve --progress",
"lint": "eslint --ext .js,.vue src",
"lint:fix": "eslint --ext .js,.vue src --fix",
"stylelint": "stylelint css/*.css css/*.scss src/**/*.scss src/**/*.vue",
"stylelint:fix": "stylelint css/*.css css/*.scss src/**/*.scss src/**/*.vue --fix",
"sass": "sass css",
"sass:watch": "sass --watch css"
},
"dependencies": {
"@nextcloud/auth": "^2.0.0",
"@nextcloud/axios": "^1.10.0",
"@nextcloud/dialogs": "^3.1.4",
"@nextcloud/initial-state": "^2.0.0",
"@nextcloud/l10n": "^1.6.0",
"@nextcloud/password-confirmation": "^1.0.1",
"@nextcloud/router": "^2.0.0",
"@nextcloud/vue": "^6.0.0-beta.4",
"vue": "^2.7.0"
},
"browserslist": [
"extends @nextcloud/browserslist-config"
],
"engines": {
"node": "^16.0.0",
"npm": "^7.0.0 || ^8.0.0"
},
"devDependencies": {
"@nextcloud/babel-config": "^1.0.0",
"@nextcloud/browserslist-config": "^2.2.0",
"@nextcloud/eslint-config": "^8.0.0",
"@nextcloud/stylelint-config": "^2.1.2",
"@nextcloud/webpack-vue-config": "^5.2.1"
}
}

View File

@ -0,0 +1,147 @@
<!--
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
SPDX-Licence-Identifier: AGPL-3.0-or-later
-->
<template>
<NcSettingsSection :title="t('news', 'News')"
class="news-settings"
doc-url="https://nextcloud.github.io/news/admin/">
<NcCheckboxRadioSwitch type="switch"
:checked.sync="useCronUpdates"
@update:checked="update('useCronUpdates', useCronUpdates)">
{{ t('news', 'Use system cron for updates') }}
</NcCheckboxRadioSwitch>
<p><em>{{ t('news', 'Disable this if you use a custom updater.') }}</em></p>
<NcTextField :value.sync="autoPurgeMinimumInterval"
:label="t('news', 'Purge interval')"
:label-visible="true"
@update:value="update('autoPurgeMinimumInterval', autoPurgeMinimumInterval)" />
<p><em>{{ t('news', 'Minimum amount of seconds after deleted feeds and folders are removed from the database; values below 60 seconds are ignored.') }}</em></p>
<NcTextField :value.sync="autoPurgeCount"
:label="t('news', 'Maximum read count per feed')"
:label-visible="true"
@update:value="update('autoPurgeCount', autoPurgeCount)" />
<p><em>{{ t('news', `Defines the maximum amount of articles that can be read per feed which won't be deleted by the cleanup job; if old articles reappear after being read, increase this value; negative values such as -1 will turn this feature off.`) }}</em></p>
<NcTextField :value.sync="maxRedirects"
:label="t('news', 'Maximum redirects')"
:label-visible="true"
@update:value="update('maxRedirects', maxRedirects)" />
<p><em>{{ t('news', 'How many redirects the feed fetcher should follow.') }}</em></p>
<NcTextField :value.sync="feedFetcherTimeout"
:label="t('news', 'Feed fetcher timeout')"
:label-visible="true"
@update:value="update('feedFetcherTimeout', feedFetcherTimeout)" />
<p><em>{{ t('news', 'Maximum number of seconds to wait for an RSS or Atom feed to load; if it takes longer the update will be aborted.') }}</em></p>
<NcTextField :value.sync="exploreUrl"
:label="t('news', 'Explore Service URL')"
:label-visible="true"
@update:value="update('exploreUrl', exploreUrl)" />
<p><em>{{ t('news', 'If given, this service\'s URL will be queried for displaying the feeds in the explore feed section. To fall back to the built in explore service, leave this input empty.') }}</em></p>
<NcTextField :value.sync="updateInterval"
:label="t('news', 'Update interval')"
:label-visible="true"
@update:value="update('updateInterval', updateInterval)" />
<p><em>{{ t('news', 'Interval in seconds in which the feeds will be updated.') }}</em></p>
</NcSettingsSection>
</template>
<script>
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import { loadState } from '@nextcloud/initial-state'
import { showError, showSuccess } from '@nextcloud/dialogs'
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import confirmPassword from '@nextcloud/password-confirmation'
/**
*
* @param func
* @param wait
*/
function debounce(func, wait) {
let timeout
return function executedFunction(...args) {
clearTimeout(timeout)
timeout = setTimeout(() => { func.apply(this, args) }, wait)
}
}
const successMessage = debounce(() => showSuccess(t('news', 'Successfuly updated news configuration')), 500)
export default {
name: 'AdminSettings',
components: {
NcCheckboxRadioSwitch,
NcSettingsSection,
NcTextField,
},
data() {
return {
useCronUpdates: loadState('news', 'useCronUpdates') === '1',
autoPurgeMinimumInterval: loadState('news', 'autoPurgeMinimumInterval'),
autoPurgeCount: loadState('news', 'autoPurgeCount'),
maxRedirects: loadState('news', 'maxRedirects'),
feedFetcherTimeout: loadState('news', 'feedFetcherTimeout'),
exploreUrl: loadState('news', 'exploreUrl'),
updateInterval: loadState('news', 'updateInterval'),
}
},
methods: {
async update(key, value) {
await confirmPassword()
const url = generateOcsUrl('/apps/provisioning_api/api/v1/config/apps/{appId}/{key}', {
appId: 'news',
key,
})
if (key === 'useCronUpdates') {
value = value ? '1' : '0'
}
try {
const { data } = await axios.post(url, {
value,
})
this.handleResponse({
status: data.ocs?.meta?.status,
})
} catch (e) {
this.handleResponse({
errorMessage: t('news', 'Unable to update news config'),
error: e,
})
}
},
async handleResponse({ status, errorMessage, error }) {
if (status !== 'ok') {
showError(errorMessage)
console.error(errorMessage, error)
} else {
successMessage()
}
},
},
}
</script>
<style lang="scss" scoped>
.news-settings {
p {
max-width: 700px;
margin-top: .25rem;
margin-bottom: 1rem;
}
.input-field {
max-width: 350px;
}
}
</style>

20
src/main-admin.js Normal file
View File

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
// SPDX-Licence-Identifier: AGPL-3.0-or-later
import Vue from 'vue'
import { getRequestToken } from '@nextcloud/auth'
import { translate as t } from '@nextcloud/l10n'
import AdminSettings from './components/AdminSettings.vue'
// eslint-disable-next-line
__webpack_nonce__ = btoa(getRequestToken())
Vue.mixin({
methods: {
t,
},
})
const AdminSettingsView = Vue.extend(AdminSettings)
new AdminSettingsView().$mount('#vue-admin-news')

5
stylelint.config.js Normal file
View File

@ -0,0 +1,5 @@
// SPDX-FileCopyrightText: Nextcloud contributors
// SPDX-License-Identifier: AGPL-3.0-or-later
const stylelintConfig = require('@nextcloud/stylelint-config')
module.exports = stylelintConfig

View File

@ -1,132 +1,8 @@
<?php
script('news', 'admin/Admin');
style('news', 'admin');
declare(strict_types=1);
// SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
// SPDX-Licence-Identifier: AGPL-3.0-or-later
\OCP\Util::addScript('news', 'build/news-admin-settings');
?>
<div class="section" id="news">
<h2>News</h2>
<div class="form-line">
<p><input type="checkbox" name="news-use-cron-updates"
<?php if ($_['useCronUpdates']) p('checked'); ?>>
<label for="news-use-cron-updates">
<?php p($l->t('Use system cron for updates')); ?>
</label>
</p>
<p>
<em><?php p($l->t(
'Disable this if you use a custom updater.'
)); ?></em>
</p>
</div>
<div class="form-line">
<p>
<label for="news-auto-purge-minimum-interval">
<?php p($l->t('Purge interval')); ?></p>
</label>
<p>
<em>
<?php p($l->t(
'Minimum amount of seconds after deleted feeds and folders ' .
'are removed from the database; values below 60 seconds are ' .
'ignored.'
)); ?></em>
</p>
<p><input type="text" name="news-auto-purge-minimum-interval"
value="<?php p($_['autoPurgeMinimumInterval']); ?>"></p>
</div>
<div class="form-line">
<p>
<label for="news-auto-purge-count">
<?php p($l->t('Maximum read count per feed')); ?>
</label>
</p>
<p>
<em>
<?php p($l->t(
'Defines the maximum amount of articles that can be read per ' .
"feed which won't be deleted by the cleanup job; ".
'if old articles reappear after being read, increase ' .
'this value; negative values such as -1 will turn this ' .
'feature off.'
)); ?></em>
</p>
<p><input type="text" name="news-auto-purge-count"
value="<?php p($_['autoPurgeCount']); ?>"></p>
</div>
<div class="form-line">
<p>
<label for="news-max-redirects">
<?php p($l->t('Maximum redirects')); ?>
</label>
</p>
<p>
<em>
<?php p($l->t(
'How many redirects the feed fetcher should follow.'
)); ?>
</em>
</p>
<p><input type="text" name="news-max-redirects"
value="<?php p($_['maxRedirects']); ?>"></p>
</div>
<div class="form-line">
<p>
<label for="news-feed-fetcher-timeout">
<?php p($l->t('Feed fetcher timeout')); ?>
</label>
</p>
<p>
<em>
<?php p($l->t(
'Maximum number of seconds to wait for an RSS or Atom feed ' .
'to load; if it takes longer the update will be aborted.'
)); ?></em>
</p>
<p><input type="text" name="news-feed-fetcher-timeout"
value="<?php p($_['feedFetcherTimeout']); ?>"></p>
</div>
<div class="form-line">
<p>
<label for="news-explore-url">
<?php p($l->t('Explore Service URL')); ?>
</label>
</p>
<p>
<em>
<?php p($l->t(
'If given, this service\'s URL will be queried for ' .
'displaying the feeds in the explore feed section. To ' .
'fall back to the built in explore service, leave this ' .
'input empty.'
)); ?>
</em>
<a href="https://nextcloud.github.io/news/admin/"><?php p($l->t(
'For more information check the wiki.'
)); ?></a>
</p>
<p><input type="text" name="news-explore-url"
value="<?php p($_['exploreUrl']); ?>"></p>
</div>
<div class="form-line">
<p>
<label for="news-updater-interval">
<?php p($l->t('Update interval')); ?>
</label>
</p>
<p>
<em>
<?php p($l->t(
'Interval in seconds in which the feeds will be updated.'
)); ?>
</em>
<a href="https://nextcloud.github.io/news/admin/"><?php p($l->t(
'For more information check the documentation.'
)); ?></a>
</p>
<p><input type="text" name="news-update-interval"
value="<?php p($_['updateInterval']); ?>"></p>
</div>
<div id="news-saved-message">
<span class="msg success"><?php p($l->t('Saved')); ?></span>
</div>
</div>
<div id="vue-admin-news"></div>

View File

@ -1,156 +0,0 @@
<?php
/**
* Nextcloud - News
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Alessandro Cosentino <cosenal@gmail.com>
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @copyright 2012 Alessandro Cosentino
* @copyright 2012-2014 Bernhard Posselt
*/
namespace OCA\News\Tests\Unit\Controller;
use OCA\News\Controller\AdminController;
use OCA\News\Service\ItemService;
use OCP\IConfig;
use OCP\IRequest;
use PHPUnit\Framework\TestCase;
class AdminControllerTest extends TestCase
{
/**
* @var string
*/
private $appName;
/**
* @var \PHPUnit\Framework\MockObject\MockObject|IRequest
*/
private $request;
/**
* @var AdminController
*/
private $controller;
/**
* @var \PHPUnit\Framework\MockObject\MockObject|IConfig
*/
private $config;
/**
* @var \PHPUnit\Framework\MockObject\MockObject|ItemService
*/
private $itemService;
/**
* Gets run before each test
*/
public function setUp(): void
{
$this->appName = 'news';
$this->request = $this->getMockBuilder(IRequest::class)
->disableOriginalConstructor()
->getMock();
$this->config = $this->getMockBuilder(IConfig::class)
->disableOriginalConstructor()
->getMock();
$this->itemService = $this->getMockBuilder(ItemService::class)
->disableOriginalConstructor()
->getMock();
$this->controller = new AdminController($this->request, $this->config, $this->itemService);
}
/**
* Test \OCA\News\Controller\AdminController::index
*/
public function testIndex()
{
$expected = [
'autoPurgeMinimumInterval' => 1,
'autoPurgeCount' => 2,
'maxRedirects' => 3,
'feedFetcherTimeout' => 4,
'useCronUpdates' => false,
'exploreUrl' => 'test',
'updateInterval' => 3601
];
$map = [
['news','autoPurgeMinimumInterval', 60, 1],
['news','autoPurgeCount', 200, 2],
['news','maxRedirects', 10, 3],
['news','feedFetcherTimeout', 60, 4],
['news','useCronUpdates', true, false,],
['news','exploreUrl', '', 'test'],
['news','updateInterval', 3600, 3601]
];
$this->config->expects($this->exactly(count($map)))
->method('getAppValue')
->will($this->returnValueMap($map));
$response = $this->controller->index();
$data = $response->getParams();
$name = $response->getTemplateName();
$type = $response->getRenderAs();
$this->assertEquals($type, 'blank');
$this->assertEquals($name, 'admin');
$this->assertEquals($expected, $data);
}
public function testUpdate()
{
$expected = [
'autoPurgeMinimumInterval' => 1,
'autoPurgeCount' => 2,
'maxRedirects' => 3,
'feedFetcherTimeout' => 4,
'useCronUpdates' => false,
'exploreUrl' => 'test',
'updateInterval' => 3601
];
$this->config->expects($this->exactly(count($expected)))
->method('setAppValue')
->withConsecutive(
['news','autoPurgeMinimumInterval', 1],
['news','autoPurgeCount', 2],
['news','maxRedirects', 3],
['news','feedFetcherTimeout', 4],
['news','useCronUpdates', false],
['news','exploreUrl', 'test'],
['news','updateInterval', 3601]
);
$map = [
['news','autoPurgeMinimumInterval', 60, 1],
['news','autoPurgeCount', 200, 2],
['news','maxRedirects', 10, 3],
['news','feedFetcherTimeout', 60, 4],
['news','useCronUpdates', true, false,],
['news','exploreUrl', '', 'test'],
['news','updateInterval', 3600, 3601]
];
$this->config->expects($this->exactly(count($map)))
->method('getAppValue')
->will($this->returnValueMap($map));
$response = $this->controller->update(
$expected['autoPurgeMinimumInterval'],
$expected['autoPurgeCount'],
$expected['maxRedirects'],
$expected['feedFetcherTimeout'],
$expected['useCronUpdates'],
$expected['exploreUrl'],
$expected['updateInterval']
);
$this->assertEquals($expected, $response);
}
}

13
webpack.config.js Normal file
View File

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: AGPL-3.0-or-later
const path = require('path')
const webpackConfig = require('@nextcloud/webpack-vue-config')
webpackConfig.entry = {
'admin-settings': path.join(__dirname, 'src', 'main-admin.js'),
}
webpackConfig.output.path = path.resolve('./js/build/')
webpackConfig.output.publicPath = path.join('/apps/', process.env.npm_package_name, '/js/build/')
module.exports = webpackConfig