Skip to content

Commit 4a5550c

Browse files
committed
chore: update test and append i18n feature
1 parent 9fd97ee commit 4a5550c

58 files changed

Lines changed: 1976 additions & 559 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

composer.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
"platform": {
1818
"php": "7.4.33"
1919
},
20-
"vendor-dir": "lib/vendor",
2120
"sort-packages": true
2221
},
2322
"require": {
@@ -48,14 +47,14 @@
4847
"minimum-stability": "stable",
4948
"prefer-stable": true,
5049
"autoload": {
51-
"classmap": ["lib/"]
50+
"classmap": ["src/lib/"]
5251
},
5352
"scripts": {
5453
"metrics": "php bin/phpmetrics",
55-
"phpstan": "phpstan analyse lib --level 0 --memory-limit=1G",
56-
"phpstan:strict": "phpstan analyse lib --level 1 --memory-limit=1G",
57-
"phpcs": "phpcs --standard=phpcs.xml lib/",
58-
"phpcbf": "phpcbf --standard=phpcs.xml lib/",
54+
"phpstan": "phpstan analyse src --level 0 --memory-limit=1G",
55+
"phpstan:strict": "phpstan analyse src --level 1 --memory-limit=1G",
56+
"phpcs": "phpcs --standard=phpcs.xml src/",
57+
"phpcbf": "phpcbf --standard=phpcs.xml src/",
5958
"csfix": "php-cs-fixer fix --config=.php-cs-fixer.dist.php --dry-run --diff",
6059
"csfix:apply": "php-cs-fixer fix --config=.php-cs-fixer.dist.php",
6160
"test": "phpunit --configuration phpunit.xml",

phpunit.xml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,11 @@
3838

3939
<coverage processUncoveredFiles="false">
4040
<include>
41-
<directory suffix=".php">lib</directory>
41+
<directory suffix=".php">src</directory>
4242
</include>
4343
<exclude>
44-
<directory suffix=".php">lib/vendor</directory>
45-
<directory suffix=".php">lib/core/HTMLPurifier</directory>
46-
<file>lib/utility/db-mysqli.php</file>
44+
<directory suffix=".php">vendor</directory>
45+
<file>src/core/HTMLPurifier</file>
4746
</exclude>
4847
</coverage>
4948
</phpunit>

src/admin/option-api.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
defined('SCRIPTLOG') || die("Direct access not permitted");
4+
5+
$action = isset($_GET['action']) ? htmlentities(strip_tags($_GET['action'])) : "";
6+
$params = isset($_GET['Id']) ? intval($_GET['Id']) : null;
7+
$configDao = class_exists('ConfigurationDao') ? new ConfigurationDao() : "";
8+
$configService = class_exists('ConfigurationService') ? new ConfigurationService($configDao, $app->validator, $app->sanitizer) : "";
9+
$configController = class_exists('ConfigurationController') ? new ConfigurationController($configService) : "";
10+
11+
try {
12+
switch ($action) {
13+
case ActionConst::API_CONFIG:
14+
if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) {
15+
direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403);
16+
} else {
17+
if ((!check_integer($params)) && (gettype($params) !== "integer")) {
18+
header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400);
19+
header("Status: 400 Bad Request");
20+
throw new AppException("Invalid ID data type");
21+
}
22+
23+
if ($params == 0) {
24+
$configController->updateApiSetting();
25+
} else {
26+
direct_page('index.php?load=dashboard', 302);
27+
}
28+
}
29+
30+
break;
31+
32+
default:
33+
if (false === $app->authenticator->userAccessControl(ActionConst::CONFIGURATION)) {
34+
direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403);
35+
} else {
36+
$configController->updateApiSetting();
37+
}
38+
}
39+
} catch (Throwable $th) {
40+
if (class_exists('LogError')) {
41+
LogError::setStatusCode(http_response_code());
42+
LogError::exceptionHandler($th);
43+
}
44+
} catch (AppException $e) {
45+
LogError::setStatusCode(http_response_code());
46+
LogError::exceptionHandler($e);
47+
}

src/admin/posts.php

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@
1414
if (false === $app->authenticator->userAccessControl(ActionConst::POSTS)) {
1515
direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403);
1616
} else {
17-
if ((!check_integer($postId)) && (gettype($postId) !== "integer")) {
18-
header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400);
19-
header("Status: 400 Bad Request");
20-
throw new AppException("Invalid ID data type!");
21-
}
22-
2317
if ($postId == 0) {
2418
$postController->insert();
2519
} else {
@@ -33,12 +27,6 @@
3327
if (false === $app->authenticator->userAccessControl(ActionConst::POSTS)) {
3428
direct_page('index.php?load=403&forbidden=' . forbidden_id(), 403);
3529
} else {
36-
if ((!check_integer($postId)) && (gettype($postId) !== "integer")) {
37-
header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400);
38-
header("Status: 400 Bad Request");
39-
throw new AppException("Invalid ID data type!");
40-
}
41-
4230
if ($postDao->checkPostId($postId, $app->sanitizer)) {
4331
$postController->update((int)$postId);
4432
} else {
@@ -49,7 +37,7 @@
4937
break;
5038

5139
case ActionConst::DELETEPOST:
52-
if ((!check_integer($postId)) && (gettype($postId) !== "integer")) {
40+
if ($postId <= 0) {
5341
header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad Request", true, 400);
5442
header("Status: 400 Bad Request");
5543
throw new AppException("Invalid ID data type!");

src/admin/sidebar-nav.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ function sidebar_navigation($module, $url, $user_id = null, $user_session = null
195195
<?php endif; ?>
196196

197197
<?php if (access_control_list(ActionConst::CONFIGURATION)) : ?>
198-
<li <?= ($module === 'option-general' || $module === 'option-permalink' || $module === 'option-reading' || $module === 'option-timezone' || $module === 'option-memberships') ? 'class="treeview active"' : 'class="treeview"'; ?>>
198+
<li <?= ($module === 'option-general' || $module === 'option-permalink' || $module === 'option-reading' || $module === 'option-timezone' || $module === 'option-memberships' || $module === 'option-api') ? 'class="treeview active"' : 'class="treeview"'; ?>>
199199
<a href="#">
200200
<i class="fa fa-sliders fa-fw"></i>
201201
<span><?= admin_translate('nav.settings'); ?></span>
@@ -211,6 +211,7 @@ function sidebar_navigation($module, $url, $user_id = null, $user_session = null
211211
<li><a href="<?= $url . '/' . generate_request('index.php', 'get', ['option-memberships', ActionConst::MEMBERSHIP_CONFIG, 0])['link']; ?>"><?= admin_translate('nav.membership'); ?></a></li>
212212
<li><a href="<?= $url . '/' . generate_request('index.php', 'get', ['option-mail', ActionConst::MAIL_CONFIG, 0])['link']; ?>"><?= admin_translate('nav.mail_settings'); ?></a></li>
213213
<li><a href="<?= $url . '/' . generate_request('index.php', 'get', ['option-downloads', ActionConst::DOWNLOAD_CONFIG, 0])['link']; ?>"><?= admin_translate('nav.download_settings'); ?></a></li>
214+
<li><a href="<?= $url . '/' . generate_request('index.php', 'get', ['option-api', ActionConst::API_CONFIG, 0])['link']; ?>">RESTful API</a></li>
214215
</ul>
215216
</li>
216217
<?php endif; ?>

src/admin/ui/posts/edit-post.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363

6464
<div class="form-group">
6565
<label for="summernote">Content <span class="text-red" title="required">*</span></label>
66-
<textarea class="form-control" id="summernote" name="post_content" rows="10" cols="80" maxlength="50000" required aria-required="true"><?= (isset($postData['post_content']) ? safe_html($postData['post_content']) : ""); ?><?= (isset($formData['post_content']) ? safe_html($formData['post_content']) : ""); ?></textarea>
66+
<textarea class="form-control" id="summernote" name="post_content" rows="10" cols="80" maxlength="50000" required aria-required="true"><?= (isset($postContent) ? $postContent : ""); ?><?= (isset($formData['post_content']) ? safe_html($formData['post_content']) : ""); ?></textarea>
6767
</div>
6868

6969
<div class="form-group">
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
defined('SCRIPTLOG') || die("Direct access not permitted");
3+
4+
$api = $this->api ?? [];
5+
$errors = $this->errors ?? [];
6+
$status = isset($_GET['status']) ? $_GET['status'] : "";
7+
$csrfToken = $this->csrfToken ?? csrf_generate_token('csrfToken');
8+
?>
9+
10+
<?php if ($status === 'apiConfigUpdated'): ?>
11+
<div class="alert alert-success alert-dismissible">
12+
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
13+
<h4><i class="icon fa fa-check"></i> Success!</h4>
14+
API settings have been updated successfully.
15+
</div>
16+
<?php endif; ?>
17+
18+
<?php if (!empty($errors)): ?>
19+
<div class="alert alert-danger alert-dismissible">
20+
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
21+
<h4><i class="icon fa fa-ban"></i> Error!</h4>
22+
<?php foreach ($errors as $error): ?>
23+
<p><?= safe_html($error) ?></p>
24+
<?php endforeach; ?>
25+
</div>
26+
<?php endif; ?>
27+
28+
<div class="row">
29+
<div class="col-md-12">
30+
<div class="box box-primary">
31+
<div class="box-header with-border">
32+
<h3 class="box-title">RESTful API Settings</h3>
33+
</div>
34+
35+
<form method="post" action="<?= generate_request('index.php', 'get', ['option-api', 'apiConfig', 0])['link']; ?>">
36+
<input type="hidden" name="csrfToken" value="<?= $csrfToken ?>">
37+
38+
<div class="box-body">
39+
<!-- Rate Limiting Toggle -->
40+
<div class="form-group">
41+
<label>
42+
<input type="checkbox" name="api_rate_limit_enabled" value="1" <?= ($api['api_rate_limit_enabled'] ?? '1') === '1' ? 'checked' : '' ?>>
43+
Enable Rate Limiting
44+
</label>
45+
<p class="help-block">Protect your API from abuse by limiting the number of requests per client.</p>
46+
</div>
47+
48+
<div class="row">
49+
<div class="col-md-6">
50+
<!-- Read Rate Limit -->
51+
<div class="form-group">
52+
<label for="api_rate_limit_read">Read Rate Limit (requests per minute)</label>
53+
<input type="number" id="api_rate_limit_read" name="api_rate_limit_read"
54+
class="form-control" value="<?= safe_html($api['api_rate_limit_read'] ?? '60') ?>"
55+
min="1" max="1000">
56+
<p class="help-block">Maximum GET requests per client per minute. Default: 60</p>
57+
</div>
58+
</div>
59+
60+
<div class="col-md-6">
61+
<!-- Write Rate Limit -->
62+
<div class="form-group">
63+
<label for="api_rate_limit_write">Write Rate Limit (requests per minute)</label>
64+
<input type="number" id="api_rate_limit_write" name="api_rate_limit_write"
65+
class="form-control" value="<?= safe_html($api['api_rate_limit_write'] ?? '20') ?>"
66+
min="1" max="500">
67+
<p class="help-block">Maximum POST/PUT/DELETE/PATCH requests per client per minute. Default: 20</p>
68+
</div>
69+
</div>
70+
</div>
71+
72+
<!-- Info Box -->
73+
<div class="callout callout-info">
74+
<h4>How Rate Limiting Works</h4>
75+
<p>Rate limits are tracked per client using the following priority:</p>
76+
<ol>
77+
<li><strong>API Key</strong> (X-API-Key header)</li>
78+
<li><strong>Bearer Token</strong> (Authorization header)</li>
79+
<li><strong>IP Address</strong> (fallback)</li>
80+
</ol>
81+
<p>When a client exceeds the rate limit, they receive a <code>429 Too Many Requests</code> response with a <code>Retry-After</code> header.</p>
82+
</div>
83+
</div>
84+
85+
<div class="box-footer">
86+
<button type="submit" name="apiConfigSubmit" class="btn btn-primary">
87+
<i class="fa fa-save"></i> Update API Settings
88+
</button>
89+
</div>
90+
</form>
91+
</div>
92+
</div>
93+
</div>

0 commit comments

Comments
 (0)