mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-02 11:01:43 +00:00
Compare commits
12 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84b4ab0cc2 | ||
|
|
eb808a0fbc | ||
|
|
d25ae50d30 | ||
|
|
c43821e29c | ||
|
|
b7570b2651 | ||
|
|
cb77609f27 | ||
|
|
99651bb61e | ||
|
|
bf1e14f66d | ||
|
|
d0e55804f8 | ||
|
|
0a9715b8c1 | ||
|
|
61390e67f6 | ||
|
|
536d25980f |
@@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\DestroyRequest;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
@@ -75,6 +76,9 @@ class DestroyController extends Controller
|
||||
if ($exchangeRate instanceof CurrencyExchangeRate) {
|
||||
$this->repository->deleteRate($exchangeRate);
|
||||
}
|
||||
if (!$exchangeRate instanceof CurrencyExchangeRate) {
|
||||
throw new FireflyException('Bla');
|
||||
}
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,6 @@ class UpdateController extends Controller
|
||||
$exchangeRate = $this->repository->updateExchangeRate($exchangeRate, $rate, $date);
|
||||
|
||||
$transformer = new ExchangeRateTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()
|
||||
->api($this->jsonApiObject(self::RESOURCE_KEY, $exchangeRate, $transformer))
|
||||
|
||||
@@ -81,11 +81,11 @@ class DebugController extends Controller
|
||||
*/
|
||||
public function displayError(): void
|
||||
{
|
||||
app('log')->debug('This is a test message at the DEBUG level.');
|
||||
app('log')->info('This is a test message at the INFO level.');
|
||||
Log::debug('This is a test message at the DEBUG level.');
|
||||
Log::info('This is a test message at the INFO level.');
|
||||
Log::notice('This is a test message at the NOTICE level.');
|
||||
app('log')->warning('This is a test message at the WARNING level.');
|
||||
app('log')->error('This is a test message at the ERROR level.');
|
||||
Log::warning('This is a test message at the WARNING level.');
|
||||
Log::error('This is a test message at the ERROR level.');
|
||||
Log::critical('This is a test message at the CRITICAL level.');
|
||||
Log::alert('This is a test message at the ALERT level.');
|
||||
Log::emergency('This is a test message at the EMERGENCY level.');
|
||||
@@ -187,6 +187,8 @@ class DebugController extends Controller
|
||||
return [
|
||||
'php_version' => PHP_VERSION,
|
||||
'php_os' => PHP_OS,
|
||||
'build_time' => config('firefly.build_time'),
|
||||
'build_time_nice' => Carbon::parse(config('firefly.build_time'), 'Europe/Amsterdam')->setTimezone('Europe/Amsterdam')->format('Y-m-d H:i:s e'),
|
||||
'uname' => php_uname('m'),
|
||||
'interface' => PHP_SAPI,
|
||||
'bits' => PHP_INT_SIZE * 8,
|
||||
@@ -212,11 +214,11 @@ class DebugController extends Controller
|
||||
try {
|
||||
if (file_exists('/var/www/counter-main.txt')) {
|
||||
$return['build'] = trim(file_get_contents('/var/www/counter-main.txt'));
|
||||
app('log')->debug(sprintf('build is now "%s"', $return['build']));
|
||||
Log::debug(sprintf('build is now "%s"', $return['build']));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
app('log')->debug('Could not check build counter, but thats ok.');
|
||||
app('log')->warning($e->getMessage());
|
||||
Log::debug('Could not check build counter, but thats ok.');
|
||||
Log::warning($e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -224,8 +226,8 @@ class DebugController extends Controller
|
||||
$return['build_date'] = trim(file_get_contents('/var/www/build-date-main.txt'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
app('log')->debug('Could not check build date, but thats ok.');
|
||||
app('log')->warning($e->getMessage());
|
||||
Log::debug('Could not check build date, but thats ok.');
|
||||
Log::warning($e->getMessage());
|
||||
}
|
||||
if ('' !== (string) env('BASE_IMAGE_BUILD')) { // @phpstan-ignore-line
|
||||
$return['base_build'] = env('BASE_IMAGE_BUILD'); // @phpstan-ignore-line
|
||||
@@ -282,7 +284,7 @@ class DebugController extends Controller
|
||||
$parts = Steam::getLocaleArray(Steam::getLocale());
|
||||
foreach ($parts as $code) {
|
||||
$code = trim($code);
|
||||
app('log')->debug(sprintf('Trying to set %s', $code));
|
||||
Log::debug(sprintf('Trying to set %s', $code));
|
||||
$result = setlocale(LC_ALL, $code);
|
||||
$localeAttempts[$code] = $result === $code;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Safe\Exceptions\FilesystemException;
|
||||
use Safe\Exceptions\JsonException;
|
||||
use Symfony\Component\Mailer\Exception\TransportException;
|
||||
|
||||
use function Safe\file_get_contents;
|
||||
@@ -125,11 +127,25 @@ class MailError extends Job implements ShouldQueue
|
||||
|
||||
if (!file_exists($file)) {
|
||||
Log::debug(sprintf('Wrote new file in "%s"', $file));
|
||||
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
|
||||
|
||||
try {
|
||||
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
|
||||
} catch (FilesystemException $e) {
|
||||
Log::warning(sprintf('[a] Could not write file "%s": %s', $file, $e->getMessage()));
|
||||
} catch (JsonException $e) {
|
||||
Log::warning(sprintf('[b] Could not parse file "%s": %s', $file, $e->getMessage()));
|
||||
}
|
||||
}
|
||||
if (file_exists($file)) {
|
||||
Log::debug(sprintf('Read file in "%s"', $file));
|
||||
$limits = json_decode(file_get_contents($file), true);
|
||||
|
||||
try {
|
||||
$limits = json_decode(file_get_contents($file), true);
|
||||
} catch (FilesystemException $e) {
|
||||
Log::warning(sprintf('[c] Could not read file "%s": %s', $file, $e->getMessage()));
|
||||
} catch (JsonException $e) {
|
||||
Log::warning(sprintf('[d] Could not parse file "%s": %s', $file, $e->getMessage()));
|
||||
}
|
||||
}
|
||||
// limit reached?
|
||||
foreach ($types as $type => $info) {
|
||||
@@ -157,7 +173,14 @@ class MailError extends Job implements ShouldQueue
|
||||
}
|
||||
++$limits[$type]['sent'];
|
||||
}
|
||||
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
|
||||
|
||||
try {
|
||||
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
|
||||
} catch (FilesystemException $e) {
|
||||
Log::warning(sprintf('[c] Could not write file "%s": %s', $file, $e->getMessage()));
|
||||
} catch (JsonException $e) {
|
||||
Log::warning(sprintf('[c] Could not parse file "%s": %s', $file, $e->getMessage()));
|
||||
}
|
||||
Log::debug('No limits reached, return FALSE.');
|
||||
|
||||
return false;
|
||||
|
||||
@@ -88,7 +88,7 @@ trait UserGroupTrait
|
||||
public function setUserGroup(UserGroup $userGroup): void
|
||||
{
|
||||
if (null === $this->user) {
|
||||
Log::warning(sprintf('User is not set in repository %s', static::class));
|
||||
Log::warning(sprintf('User is not set in repository %s. This does not have to be a problem.', static::class));
|
||||
}
|
||||
$this->userGroup = $userGroup;
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ return [
|
||||
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2025-10-25',
|
||||
'build_time' => 1761395572,
|
||||
'version' => 'develop/2025-10-26',
|
||||
'build_time' => 1761469988,
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 28, // field is no longer used.
|
||||
|
||||
|
||||
@@ -44,20 +44,29 @@
|
||||
<div class="box-body no-padding">
|
||||
<nav v-if="totalPages > 1">
|
||||
<ul class="pagination">
|
||||
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.previous')">
|
||||
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true"
|
||||
:aria-label="$t('pagination.previous')">
|
||||
<span class="page-link" aria-hidden="true">‹</span>
|
||||
</li>
|
||||
<li class="page-item" v-if="1 !== this.page">
|
||||
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)" rel="prev" :aria-label="$t('pagination.next')">‹</a>
|
||||
<a class="page-link"
|
||||
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)"
|
||||
rel="prev" :aria-label="$t('pagination.next')">‹</a>
|
||||
</li>
|
||||
<li v-for="item in this.totalPages" :class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
|
||||
<li v-for="item in this.totalPages"
|
||||
:class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
|
||||
<span v-if="item === page" class="page-link" v-text="item"></span>
|
||||
<a v-if="item !== page" class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item" v-text="item"></a>
|
||||
<a v-if="item !== page" class="page-link"
|
||||
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item"
|
||||
v-text="item"></a>
|
||||
</li>
|
||||
<li v-if="totalPages !== page" class="page-item">
|
||||
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)" rel="next" :aria-label="$t('pagination.next')">›</a>
|
||||
<a class="page-link"
|
||||
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)"
|
||||
rel="next" :aria-label="$t('pagination.next')">›</a>
|
||||
</li>
|
||||
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.next')">
|
||||
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true"
|
||||
:aria-label="$t('pagination.next')">
|
||||
<span class="page-link" aria-hidden="true">›</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -97,9 +106,11 @@
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<!-- (<span v-text="rate.rate_id"></span>) -->
|
||||
<input type="number" class="form-control" min="0" step="any" v-model="rate.rate">
|
||||
</td>
|
||||
<td>
|
||||
<!-- (<span v-text="rate.inverse_id"></span>) -->
|
||||
<input type="number" class="form-control" min="0" step="any" v-model="rate.inverse">
|
||||
</td>
|
||||
<td>
|
||||
@@ -122,20 +133,29 @@
|
||||
|
||||
<nav v-if="totalPages > 1">
|
||||
<ul class="pagination">
|
||||
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.previous')">
|
||||
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true"
|
||||
:aria-label="$t('pagination.previous')">
|
||||
<span class="page-link" aria-hidden="true">‹</span>
|
||||
</li>
|
||||
<li class="page-item" v-if="1 !== this.page">
|
||||
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)" rel="prev" :aria-label="$t('pagination.next')">‹</a>
|
||||
<a class="page-link"
|
||||
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)"
|
||||
rel="prev" :aria-label="$t('pagination.next')">‹</a>
|
||||
</li>
|
||||
<li v-for="item in this.totalPages" :class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
|
||||
<li v-for="item in this.totalPages"
|
||||
:class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
|
||||
<span v-if="item === page" class="page-link" v-text="item"></span>
|
||||
<a v-if="item !== page" class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item" v-text="item"></a>
|
||||
<a v-if="item !== page" class="page-link"
|
||||
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item"
|
||||
v-text="item"></a>
|
||||
</li>
|
||||
<li v-if="totalPages !== page" class="page-item">
|
||||
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)" rel="next" :aria-label="$t('pagination.next')">›</a>
|
||||
<a class="page-link"
|
||||
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)"
|
||||
rel="next" :aria-label="$t('pagination.next')">›</a>
|
||||
</li>
|
||||
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.next')">
|
||||
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true"
|
||||
:aria-label="$t('pagination.next')">
|
||||
<span class="page-link" aria-hidden="true">›</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -160,7 +180,8 @@
|
||||
<label for="ffInput_date" class="col-sm-4 control-label"
|
||||
v-text="$t('form.date')"></label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="date" name="date" id="ffInput_date" :disabled="posting"
|
||||
<input class="form-control" type="date" name="date" id="ffInput_date"
|
||||
:disabled="posting"
|
||||
autocomplete="off" spellcheck="false" v-model="newDate">
|
||||
</div>
|
||||
</div>
|
||||
@@ -168,16 +189,19 @@
|
||||
<label for="ffInput_rate" class="col-sm-4 control-label"
|
||||
v-text="$t('form.rate')"></label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="number" name="rate" id="ffInput_rate" :disabled="posting"
|
||||
<input class="form-control" type="number" name="rate" id="ffInput_rate"
|
||||
:disabled="posting"
|
||||
autocomplete="off" spellcheck="false" v-model="newRate" step="any">
|
||||
<p class="help-block" v-text="$t('firefly.help_rate_form', {from: from_code, to: to_code})">
|
||||
<p class="help-block"
|
||||
v-text="$t('firefly.help_rate_form', {from: from_code, to: to_code})">
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="nodisablebutton btn pull-right btn-success" v-text="$t('firefly.save_new_rate')"></button>
|
||||
<button type="submit" class="nodisablebutton btn pull-right btn-success"
|
||||
v-text="$t('firefly.save_new_rate')"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -217,9 +241,9 @@ export default {
|
||||
mounted() {
|
||||
// get from and to code from URL
|
||||
this.newDate = format(new Date, 'yyyy-MM-dd');
|
||||
let parts = window.location.href.split('/');
|
||||
this.from_code = parts[parts.length - 2];
|
||||
this.to_code = parts[parts.length - 1];
|
||||
let parts = window.location.pathname.split('/');
|
||||
this.from_code = parts[parts.length - 2].toUpperCase();
|
||||
this.to_code = parts[parts.length - 1].toUpperCase();
|
||||
|
||||
const params = new Proxy(new URLSearchParams(window.location.search), {
|
||||
get: (searchParams, prop) => searchParams.get(prop),
|
||||
@@ -232,8 +256,8 @@ export default {
|
||||
this.downloadRates(this.page);
|
||||
},
|
||||
methods: {
|
||||
submitRate: function(e) {
|
||||
if(e) e.preventDefault();
|
||||
submitRate: function (e) {
|
||||
if (e) e.preventDefault();
|
||||
this.posting = true;
|
||||
|
||||
axios.post("./api/v1/exchange-rates", {
|
||||
@@ -260,33 +284,74 @@ export default {
|
||||
if (0 === parts.length) {
|
||||
return;
|
||||
}
|
||||
console.log('These are the parts', parts);
|
||||
if ('' !== this.rates[index].rate) {
|
||||
//console.log('[a] Rate info is', this.rates[index]);
|
||||
this.updating = true;
|
||||
axios.put("./api/v1/exchange-rates/" + this.rates[index].rate_id, {rate: this.rates[index].rate})
|
||||
.then(() => {
|
||||
this.updating = false;
|
||||
});
|
||||
if (0 === parseInt(this.rates[index].rate_id)) {
|
||||
console.log('[a] POST, not PUT.');
|
||||
axios.post('./api/v1/exchange-rates',
|
||||
{
|
||||
from: this.from_code,
|
||||
to: this.to_code,
|
||||
rate: this.rates[index].rate,
|
||||
date: this.rates[index].date_field
|
||||
})
|
||||
.then(() => {
|
||||
this.updating = false;
|
||||
});
|
||||
}
|
||||
if (0 !== parseInt(this.rates[index].rate_id)) {
|
||||
console.log('[a] PUT, not POST.');
|
||||
axios.put('./api/v1/exchange-rates/' + this.rates[index].rate_id, {rate: this.rates[index].rate})
|
||||
.then(() => {
|
||||
this.updating = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
if ('' !== this.rates[index].inverse) {
|
||||
//console.log('[b] Rate info is', this.rates[index]);
|
||||
this.updating = true;
|
||||
axios.put("./api/v1/exchange-rates/" + this.rates[index].inverse_id, {rate: this.rates[index].inverse})
|
||||
.then(() => {
|
||||
this.updating = false;
|
||||
});
|
||||
if (0 === parseInt(this.rates[index].inverse_id)) {
|
||||
console.log('[b] POST, not PUT.');
|
||||
// post, not put
|
||||
axios.post('./api/v1/exchange-rates',
|
||||
{
|
||||
// remember, this is in reverse.
|
||||
from: this.to_code,
|
||||
to: this.from_code,
|
||||
rate: this.rates[index].inverse,
|
||||
date: this.rates[index].date_field
|
||||
})
|
||||
.then(() => {
|
||||
this.updating = false;
|
||||
});
|
||||
}
|
||||
if (0 !== parseInt(this.rates[index].inverse_id)) {
|
||||
console.log('[b] PUT, not POST.');
|
||||
axios.put('./api/v1/exchange-rates/' + this.rates[index].inverse_id, {rate: this.rates[index].inverse})
|
||||
.then(() => {
|
||||
this.updating = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
deleteRate: function (index) {
|
||||
// console.log(this.rates[index].key);
|
||||
let parts = this.spliceKey(this.rates[index].key);
|
||||
|
||||
if (0 === parts.length) {
|
||||
return;
|
||||
}
|
||||
// console.log(parts);
|
||||
|
||||
let rateId = parseInt(this.rates[index].rate_id);
|
||||
let inverseId = parseInt(this.rates[index].inverse_id);
|
||||
// delete A to B
|
||||
axios.delete("./api/v1/exchange-rates/" + parts.from + '/' + parts.to + '/' + format(parts.date, 'yyyy-MM-dd'));
|
||||
// delete B to A.
|
||||
axios.delete("./api/v1/exchange-rates/" + parts.to + '/' + parts.from + '/' + format(parts.date, 'yyyy-MM-dd'));
|
||||
if (rateId > 0) {
|
||||
axios.delete('./api/v1/exchange-rates/' + rateId);
|
||||
}
|
||||
if (inverseId > 0) {
|
||||
axios.delete('./api/v1/exchange-rates/' + inverseId);
|
||||
}
|
||||
|
||||
this.rates.splice(index, 1);
|
||||
},
|
||||
@@ -307,6 +372,7 @@ export default {
|
||||
};
|
||||
},
|
||||
downloadCurrencies: function () {
|
||||
console.log('Now downloading currencies.');
|
||||
this.loading = true;
|
||||
axios.get("./api/v1/currencies/" + this.from_code).then((response) => {
|
||||
this.from = {
|
||||
@@ -327,31 +393,36 @@ export default {
|
||||
downloadRates: function (page) {
|
||||
this.tempRates = {};
|
||||
this.loading = true;
|
||||
axios.get("./api/v1/exchange-rates/" + this.from_code + '/' + this.to_code + '?page=' + page).then((response) => {
|
||||
console.log('Now downloading rates.', page);
|
||||
axios.get('./api/v1/exchange-rates/' + this.from_code + '/' + this.to_code + '?page=' + page).then((response) => {
|
||||
for (let i in response.data.data) {
|
||||
if (response.data.data.hasOwnProperty(i)) {
|
||||
console.log('Downloaded entry #' + i);
|
||||
let current = response.data.data[i];
|
||||
let date = new Date(current.attributes.date);
|
||||
let from_code = current.attributes.from_currency_code;
|
||||
let to_code = current.attributes.to_currency_code;
|
||||
let from_code = current.attributes.from_currency_code.toUpperCase();
|
||||
let to_code = current.attributes.to_currency_code.toUpperCase();
|
||||
let rate = current.attributes.rate;
|
||||
let inverse = '';
|
||||
let rate_id = current.id;
|
||||
let inverse_id = '0';
|
||||
let key = from_code + '_' + to_code + '_' + format(date, 'yyyy-MM-dd');
|
||||
// console.log('Key is now "' + key + '"');
|
||||
console.log('Key is now "' + key + '"');
|
||||
|
||||
// perhaps the returned rate is actually the inverse rate.
|
||||
if (from_code === this.to_code && to_code === this.from_code) {
|
||||
// console.log('Inverse rate found!');
|
||||
key = to_code + '_' + from_code + '_' + format(date, 'yyyy-MM-dd');
|
||||
rate = '';
|
||||
// new: set rate id to zero.
|
||||
rate_id = '0';
|
||||
inverse = current.attributes.rate;
|
||||
inverse_id = current.id;
|
||||
// console.log('Key updated to "' + key + '"');
|
||||
console.log('Key updated to "' + key + '"');
|
||||
}
|
||||
|
||||
if (!this.tempRates.hasOwnProperty(key)) {
|
||||
console.log('New entry stored');
|
||||
this.tempRates[key] = {
|
||||
key: key,
|
||||
date: date,
|
||||
@@ -374,6 +445,7 @@ export default {
|
||||
this.tempRates[key].rate = rate;
|
||||
this.tempRates[key].rate_id = rate_id;
|
||||
}
|
||||
console.log('Found exchange rate #' + this.tempRates[key].rate_id + ' with inverse #' + this.tempRates[key].inverse_id);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -35,5 +35,5 @@ return [
|
||||
'currencies-index' => 'Firefly III supports multiple currencies. Although it defaults to the Euro it can be set to the US Dollar and many other currencies. As you can see a small selection of currencies has been included but you can add your own if you wish to. Changing the default currency will not change the currency of existing transactions however: Firefly III supports the use of multiple currencies at the same time.',
|
||||
'transactions-index' => 'These expenses, deposits and transfers are not particularly imaginative. They have been generated automatically.',
|
||||
'piggy-banks-index' => 'As you can see, there are three piggy banks. Use the plus and minus buttons to influence the amount of money in each piggy bank. Click the name of the piggy bank to see the administration for each piggy bank.',
|
||||
'profile-index' => 'Keep in mind that the demo site resets every four hours. Your access may be revoked at any time. This happens automatically and is not a bug.',
|
||||
'profile-index' => 'Keep in mind that the demo site resets every four hours. Standard user agents (curl, Postman, wget) are blocked. Your access may be revoked at any time. This happens automatically and is not a bug.',
|
||||
];
|
||||
|
||||
@@ -32,6 +32,7 @@ return [
|
||||
'webhook_account_info' => 'Cannot deliver account information for budget related webhooks.',
|
||||
'webhook_transaction_info' => 'Cannot deliver transaction information for budget related webhooks.',
|
||||
'invalid_account_type' => 'A piggy bank can only be linked to asset accounts and liabilities',
|
||||
'unique_currency_code' => 'This currency code is already in use',
|
||||
'invalid_account_currency' => 'This account does not use the currency you have selected',
|
||||
'current_amount_too_much' => 'The combined amount in "current_amount" cannot exceed the "target_amount".',
|
||||
'filter_must_be_in' => 'Filter ":filter" must be one of: :values',
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
<td>Firefly III</td>
|
||||
<td>{% if FF_IS_DEVELOP %}<!-- .Z9JBCmw64Zkx1pQw -->{% endif %}{% if not FF_IS_DEVELOP %}v{% endif %}{{ FF_VERSION }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Build time</td>
|
||||
<td>{{ system.build_time_nice }} ({{ system.build_time }})</td>
|
||||
</tr>
|
||||
{# PHP version + settings #}
|
||||
<tr>
|
||||
<td>PHP version</td>
|
||||
|
||||
@@ -121,11 +121,11 @@ Route::group(
|
||||
Route::post('logout', ['uses' => 'Auth\LoginController@logout', 'as' => 'logout']);
|
||||
Route::get('flush', ['uses' => 'DebugController@flush', 'as' => 'flush']);
|
||||
Route::get('routes', ['uses' => 'DebugController@routes', 'as' => 'routes']);
|
||||
Route::get('debug', 'DebugController@index')->name('debug');
|
||||
Route::get('debug/api-test', 'DebugController@apiTest')->name('api-test');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
// For the two factor routes, the user must be logged in, but NOT 2FA. Account confirmation does not matter here.
|
||||
Route::group(
|
||||
['middleware' => 'user-logged-in-no-2fa', 'prefix' => 'two-factor', 'as' => 'two-factor.', 'namespace' => 'FireflyIII\Http\Controllers\Auth'],
|
||||
@@ -137,6 +137,16 @@ Route::group(
|
||||
|
||||
// For all other routes, the user must be fully authenticated and have an activated account.
|
||||
|
||||
// For some other routes, it is only relevant that the user is authenticated.
|
||||
Route::group(
|
||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers'],
|
||||
static function (): void {
|
||||
Route::get('debug', 'DebugController@index')->name('debug');
|
||||
Route::get('debug/api-test', 'DebugController@apiTest')->name('api-test');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// Home Controller.
|
||||
Route::group(
|
||||
['middleware' => ['user-full-auth'], 'namespace' => 'FireflyIII\Http\Controllers'],
|
||||
|
||||
Reference in New Issue
Block a user