Skip to content

Commit 20d66b3

Browse files
committed
feat: settings page logic
1 parent da7d201 commit 20d66b3

7 files changed

Lines changed: 290 additions & 114 deletions

File tree

css/autocurrency-style.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/Controller/ApiController.php

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,62 @@
44

55
namespace OCA\AutoCurrency\Controller;
66

7+
use OCA\AutoCurrency\Service\FetchCurrenciesService;
78
use OCP\AppFramework\Http;
89
use OCP\AppFramework\Http\Attribute\ApiRoute;
910
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
1011
use OCP\AppFramework\Http\DataResponse;
1112
use OCP\AppFramework\OCSController;
13+
use OCP\IConfig;
14+
use OCP\IDateTimeFormatter;
15+
use OCP\IL10N;
16+
use OCP\IRequest;
1217

1318
/**
1419
* @psalm-suppress UnusedClass
1520
*/
1621
class ApiController extends OCSController {
22+
/** @var IConfig */
23+
private $config;
24+
25+
/** @var IL10N */
26+
private $l;
27+
28+
/** @var FetchCurrenciesService */
29+
private $service;
30+
31+
/** @var IDateTimeFormatter */
32+
// private $dateTimeFormatter;
33+
34+
/** @var IJobList */
35+
// private $jobList;
36+
37+
/**
38+
* Admin constructor.
39+
*
40+
* @param Collector $collector
41+
* @param IConfig $config
42+
* @param IL10N $l
43+
* @param IDateTimeFormatter $dateTimeFormatter
44+
* @param IJobList $jobList
45+
*/
46+
public function __construct(
47+
string $appName,
48+
IRequest $request,
49+
IConfig $config,
50+
IL10N $l,
51+
FetchCurrenciesService $service,
52+
// IDateTimeFormatter $dateTimeFormatter,
53+
// IJobList $jobList,
54+
) {
55+
parent::__construct($appName, $request);
56+
$this->config = $config;
57+
$this->l = $l;
58+
$this->service = $service;
59+
// $this->dateTimeFormatter = $dateTimeFormatter;
60+
// $this->jobList = $jobList;
61+
}
62+
1763
/**
1864
* An example API endpoint
1965
*
@@ -36,11 +82,55 @@ class ApiController extends OCSController {
3682
*
3783
* 200: Data returned
3884
*/
39-
#[NoAdminRequired]
85+
// #[NoAdminRequired]
4086
#[ApiRoute(verb: 'GET', url: '/api/cron')]
4187
public function getCronInfo(): DataResponse {
88+
$lastUpdate = $this->config->getAppValue('autocurrency', 'last_update', '');
89+
if ($lastUpdate === '') {
90+
$lastUpdate = null;
91+
}
92+
93+
$interval = intval($this->config->getAppValue('autocurrency', 'cron_interval', '24'));
94+
// if ($lastUpdate !== null) {
95+
// $lastUpdate = $this->dateTimeFormatter->formatDate($lastUpdate)
96+
// }
97+
98+
return new DataResponse(
99+
['last_update' => $lastUpdate, 'interval' => $interval]
100+
);
101+
}
102+
103+
/**
104+
* Run cron immediately.
105+
*
106+
* @return DataResponse<Http::STATUS_OK, array{status:string}, array{}>
107+
*
108+
* 200: Data returned
109+
*/
110+
// #[NoAdminRequired]
111+
#[ApiRoute(verb: 'POST', url: '/api/cron/run')]
112+
public function runCron(): DataResponse {
113+
$this->service->doCron();
114+
115+
return new DataResponse(
116+
['status' => 'OK']
117+
);
118+
}
119+
120+
/**
121+
* Update auto currency settings.
122+
*
123+
* @return DataResponse<Http::STATUS_OK, array{status:string}, array{}>
124+
*
125+
* 200: Data returned
126+
*/
127+
// #[NoAdminRequired]
128+
#[ApiRoute(verb: 'PUT', url: '/api/cron')]
129+
public function updateSettings(): DataResponse {
130+
$interval = $this->request->getParam('data')['interval'];
131+
$this->config->setAppValue('autocurrency', 'cron_interval', "$interval");
42132
return new DataResponse(
43-
['last_update' => '2021-09-01 00:00:00', 'interval' => 24]
133+
['status' => 'OK']
44134
);
45135
}
46136
}

lib/Cron/FetchCurrenciesJob.php

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
<?php
2+
23
namespace OCA\AutoCurrency\Cron;
34

45
use OCA\AutoCurrency\Service\FetchCurrenciesService;
5-
use OCP\BackgroundJob\TimedJob;
66
use OCP\AppFramework\Utility\ITimeFactory;
7-
use OCP\ILogger;
7+
use OCP\BackgroundJob\TimedJob;
8+
use Psr\Log\LoggerInterface;
89

910
class FetchCurrenciesJob extends TimedJob {
10-
private FetchCurrenciesService $service;
11-
private ILogger $logger;
11+
private FetchCurrenciesService $service;
12+
private LoggerInterface $logger;
1213

13-
public function __construct(ITimeFactory $time, FetchCurrenciesService $service, ILogger $logger) {
14-
parent::__construct($time);
15-
$this->service = $service;
16-
$this->logger = $logger;
14+
public function __construct(ITimeFactory $time, FetchCurrenciesService $service, LoggerInterface $logger) {
15+
parent::__construct($time);
16+
$this->service = $service;
17+
$this->logger = $logger;
1718

18-
// Run once a day
19-
$this->setInterval(3600 * 24);
20-
$this->setTimeSensitivity(\OCP\BackgroundJob\IJob::TIME_INSENSITIVE);
21-
}
19+
// Run once a day
20+
$interval = intval($this->config->getAppValue('autocurrency', 'cron_interval', '24'));
21+
$this->setInterval(3600 * $interval);
22+
$this->setTimeSensitivity(\OCP\BackgroundJob\IJob::TIME_INSENSITIVE);
23+
}
2224

23-
protected function run($arguments) {
24-
$this->logger->info('Running cron job for FetchCurrenciesTask - args: ' . json_encode($arguments));
25-
$this->service->doCron();
26-
}
25+
protected function run($arguments): void {
26+
$this->logger->info('Running cron job for FetchCurrenciesTask - args: ' . json_encode($arguments));
27+
$this->service->doCron();
28+
}
2729
}
Lines changed: 95 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
declare(strict_types=1);
34
// SPDX-FileCopyrightText: Chen Asraf <contact@casraf.dev>
45
// SPDX-License-Identifier: AGPL-3.0-or-later
@@ -7,92 +8,103 @@
78

89
use Exception;
910

10-
use OCA\AutoCurrency\Service\CurrencyNotFound;
1111
use OCA\AutoCurrency\Db\CospendProjectMapper;
12-
use OCP\AppFramework\Db\DoesNotExistException;
13-
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
14-
1512
use OCA\AutoCurrency\Db\Currency;
1613
use OCA\AutoCurrency\Db\CurrencyMapper;
17-
use OCP\ILogger;
14+
15+
use OCP\AppFramework\Db\DoesNotExistException;
16+
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
17+
use OCP\IConfig;
18+
use Psr\Log\LoggerInterface;
1819

1920
class FetchCurrenciesService {
20-
private static $EXCHANGE_URL = 'https://api.exchangerate.host/latest?base={base}';
21-
private CurrencyMapper $currencyMapper;
22-
private CospendProjectMapper $projectMapper;
23-
private ILogger $logger;
24-
25-
public function __construct(CurrencyMapper $currencyMapper, CospendProjectMapper $projectMapper, ILogger $logger) {
26-
$this->currencyMapper = $currencyMapper;
27-
$this->projectMapper = $projectMapper;
28-
$this->logger = $logger;
29-
}
30-
31-
public function doCron(): void {
32-
$projects = $this->projectMapper->findAll();
33-
$currencyMap = [];
34-
35-
foreach ($projects as $project) {
36-
$base = $this->getCurrencyName($project->getCurrencyname());
37-
38-
if (isset($currencyMap[$base])) {
39-
$json = $currencyMap[$base];
40-
} else {
41-
// request currency exchange rates from the API
42-
$this->logger->info('Fetching exchange rates for base currency ' . $base);
43-
$fp = fopen(str_replace('{base}', $base, FetchCurrenciesService::$EXCHANGE_URL), 'r');
44-
$data = stream_get_contents($fp);
45-
fclose($fp);
46-
$json = json_decode($data, true);
47-
$this->logger->info('Fetched exchange rates for base currency: ' . json_encode($json));
48-
if ($json['success'] == false) {
49-
$this->logger->error(new \Error('Failed to fetch exchange rates for base currency ' . $base));
50-
continue;
51-
}
52-
$currencyMap[$base] = $json;
53-
}
54-
55-
$currencies = $this->findAll($project->id);
56-
57-
foreach ($currencies as $currency) {
58-
$cur = $this->getCurrencyName($currency->getName());
59-
$newRate = floatval(number_format(1 / $json['rates'][$cur], 2));
60-
$currency->setExchangeRate($newRate);
61-
$this->logger->info('Setting exchange rate for currency ' . $cur . ' to ' . $newRate);
62-
$this->currencyMapper->update($currency);
63-
}
64-
}
65-
}
66-
67-
private function getCurrencyName(string $name): string {
68-
// find 3-letter currency code for the base currency
69-
preg_match('/([A-Z]{3})/', $name, $matches);
70-
71-
$this->logger->info('Matches: ' . json_encode($matches));
72-
73-
if (count($matches) === 2) {
74-
$name = $matches[1];
75-
}
76-
77-
return $name;
78-
}
79-
80-
/**
81-
* @return list<Currency>
82-
*/
83-
public function findAll(string $projectId): array {
84-
return $this->currencyMapper->findAll($projectId);
85-
}
86-
87-
/**
88-
* @return never
89-
*/
90-
private function handleException(Exception $e) {
91-
if ($e instanceof DoesNotExistException ||
92-
$e instanceof MultipleObjectsReturnedException) {
93-
throw new CurrencyNotFound($e->getMessage());
94-
} else {
95-
throw $e;
96-
}
97-
}
21+
private static $EXCHANGE_URL = 'https://api.exchangerate.host/latest?base={base}';
22+
private IConfig $config;
23+
private CurrencyMapper $currencyMapper;
24+
private CospendProjectMapper $projectMapper;
25+
private LoggerInterface $logger;
26+
27+
public function __construct(
28+
IConfig $config,
29+
CurrencyMapper $currencyMapper,
30+
CospendProjectMapper $projectMapper,
31+
LoggerInterface $logger,
32+
) {
33+
$this->config = $config;
34+
$this->currencyMapper = $currencyMapper;
35+
$this->projectMapper = $projectMapper;
36+
$this->logger = $logger;
37+
}
38+
39+
public function doCron(): void {
40+
$this->logger->info('Starting cron job to fetch currencies');
41+
$projects = $this->projectMapper->findAll();
42+
$currencyMap = [];
43+
44+
foreach ($projects as $project) {
45+
$base = $this->getCurrencyName($project->getCurrencyname());
46+
47+
if (isset($currencyMap[$base])) {
48+
$json = $currencyMap[$base];
49+
} else {
50+
// request currency exchange rates from the API
51+
$this->logger->info('Fetching exchange rates for base currency ' . $base);
52+
$fp = fopen(str_replace('{base}', $base, FetchCurrenciesService::$EXCHANGE_URL), 'r');
53+
$data = stream_get_contents($fp);
54+
fclose($fp);
55+
$json = json_decode($data, true);
56+
$this->logger->info('Fetched exchange rates for base currency: ' . json_encode($json));
57+
if ($json['success'] == false) {
58+
$this->logger->error(new \Error('Failed to fetch exchange rates for base currency ' . $base));
59+
continue;
60+
}
61+
$currencyMap[$base] = $json;
62+
}
63+
64+
$currencies = $this->findAll($project->id);
65+
66+
foreach ($currencies as $currency) {
67+
$cur = $this->getCurrencyName($currency->getName());
68+
$newRate = floatval(number_format(1 / $json['rates'][$cur], 2));
69+
$currency->setExchangeRate($newRate);
70+
$this->logger->info('Setting exchange rate for currency ' . $cur . ' to ' . $newRate);
71+
$this->currencyMapper->update($currency);
72+
}
73+
}
74+
75+
$lastUpdate = date('c');
76+
$this->config->setAppValue('autocurrency', 'last_update', $lastUpdate);
77+
}
78+
79+
private function getCurrencyName(string $name): string {
80+
// find 3-letter currency code for the base currency
81+
preg_match('/([A-Z]{3})/', $name, $matches);
82+
83+
$this->logger->info('Matches: ' . json_encode($matches));
84+
85+
if (count($matches) === 2) {
86+
$name = $matches[1];
87+
}
88+
89+
return $name;
90+
}
91+
92+
/**
93+
* @return list<Currency>
94+
*/
95+
public function findAll(string $projectId): array {
96+
return $this->currencyMapper->findAll($projectId);
97+
}
98+
99+
/**
100+
* @return never
101+
*/
102+
private function handleException(Exception $e) {
103+
if ($e instanceof DoesNotExistException ||
104+
$e instanceof MultipleObjectsReturnedException) {
105+
throw new CurrencyNotFound($e->getMessage());
106+
} else {
107+
throw $e;
108+
}
109+
}
98110
}

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@nextcloud/router": "^3.0.1",
2424
"@nextcloud/vite-config": "^2.2.2",
2525
"@nextcloud/vue": "^9.0.0-alpha.5",
26+
"date-fns": "^4.1.0",
2627
"linkifyjs": "^4.1.4",
2728
"vue": "^3.5.13"
2829
},

0 commit comments

Comments
 (0)