diff --git a/framework/core/js/admin/dist/app.js b/framework/core/js/admin/dist/app.js
index 8b1773d2c..5f9409750 100644
--- a/framework/core/js/admin/dist/app.js
+++ b/framework/core/js/admin/dist/app.js
@@ -19887,6 +19887,12 @@ System.register('flarum/components/PermissionGrid', ['flarum/Component', 'flarum
value: function moderateItems() {
var items = new ItemList();
+ items.add('viewPostIps', {
+ icon: 'bullseye',
+ label: app.translator.trans('core.admin.permissions.view_post_ips_label'),
+ permission: 'discussion.viewPostIps'
+ }, 110);
+
items.add('renameDiscussions', {
icon: 'i-cursor',
label: app.translator.trans('core.admin.permissions.rename_discussions_label'),
diff --git a/framework/core/js/admin/src/components/PermissionGrid.js b/framework/core/js/admin/src/components/PermissionGrid.js
index bbacaebe5..b34261565 100644
--- a/framework/core/js/admin/src/components/PermissionGrid.js
+++ b/framework/core/js/admin/src/components/PermissionGrid.js
@@ -173,6 +173,12 @@ export default class PermissionGrid extends Component {
moderateItems() {
const items = new ItemList();
+ items.add('viewPostIps', {
+ icon: 'bullseye',
+ label: app.translator.trans('core.admin.permissions.view_post_ips_label'),
+ permission: 'discussion.viewPostIps'
+ }, 110);
+
items.add('renameDiscussions', {
icon: 'i-cursor',
label: app.translator.trans('core.admin.permissions.rename_discussions_label'),
diff --git a/framework/core/js/forum/dist/app.js b/framework/core/js/forum/dist/app.js
index 66b512267..6c38641eb 100644
--- a/framework/core/js/forum/dist/app.js
+++ b/framework/core/js/forum/dist/app.js
@@ -24456,7 +24456,17 @@ System.register('flarum/components/PostMeta', ['flarum/Component', 'flarum/helpe
app.translator.trans('core.forum.post.number_tooltip', { number: post.number() })
),
' ',
- fullTime(time),
+ m(
+ 'span',
+ { className: 'PostMeta-time' },
+ fullTime(time)
+ ),
+ ' ',
+ m(
+ 'span',
+ { className: 'PostMeta-ip' },
+ post.data.attributes.ipAddress
+ ),
touch ? m(
'a',
{ className: 'Button PostMeta-permalink', href: permalink },
diff --git a/framework/core/js/forum/src/components/PostMeta.js b/framework/core/js/forum/src/components/PostMeta.js
index c73a76e19..0ae9b9a22 100644
--- a/framework/core/js/forum/src/components/PostMeta.js
+++ b/framework/core/js/forum/src/components/PostMeta.js
@@ -34,7 +34,8 @@ export default class PostMeta extends Component {
{app.translator.trans('core.forum.post.number_tooltip', {number: post.number()})}{' '}
- {fullTime(time)}
+
{fullTime(time)}{' '}
+
{post.data.attributes.ipAddress}
{touch
?
{permalink}
:
e.stopPropagation()} />}
diff --git a/framework/core/less/forum/Post.less b/framework/core/less/forum/Post.less
index 269d6dc9f..2b05a56a8 100644
--- a/framework/core/less/forum/Post.less
+++ b/framework/core/less/forum/Post.less
@@ -201,7 +201,7 @@
display: inline;
}
.PostMeta .Dropdown-menu {
- width: 400px;
+ width: 420px;
padding: 10px;
color: @muted-color;
@@ -213,7 +213,7 @@
color: @text-color;
font-weight: bold;
}
-.PostMeta-time {
+.PostMeta-time, .PostMeta-ip {
margin-left: 5px;
}
.PostMeta-permalink {
diff --git a/framework/core/src/Api/Controller/CreateDiscussionController.php b/framework/core/src/Api/Controller/CreateDiscussionController.php
index 0f4fb949a..e6d576c81 100644
--- a/framework/core/src/Api/Controller/CreateDiscussionController.php
+++ b/framework/core/src/Api/Controller/CreateDiscussionController.php
@@ -61,13 +61,14 @@ class CreateDiscussionController extends AbstractCreateController
protected function data(ServerRequestInterface $request, Document $document)
{
$actor = $request->getAttribute('actor');
+ $ipAddress = array_get($request->getServerParams(), 'REMOTE_ADDR', '127.0.0.1');
if (! $request->getAttribute('bypassFloodgate')) {
$this->floodgate->assertNotFlooding($actor);
}
$discussion = $this->bus->dispatch(
- new StartDiscussion($actor, array_get($request->getParsedBody(), 'data', []))
+ new StartDiscussion($actor, array_get($request->getParsedBody(), 'data', []), $ipAddress)
);
// After creating the discussion, we assume that the user has seen all
diff --git a/framework/core/src/Api/Serializer/PostSerializer.php b/framework/core/src/Api/Serializer/PostSerializer.php
index 43941f72c..3eb0054dd 100644
--- a/framework/core/src/Api/Serializer/PostSerializer.php
+++ b/framework/core/src/Api/Serializer/PostSerializer.php
@@ -47,6 +47,9 @@ class PostSerializer extends PostBasicSerializer
if ($canEdit) {
$attributes['content'] = $post->content;
}
+ if ($gate->allows('viewPostIps', $post)) {
+ $attributes['ipAddress'] = $post->ip_address;
+ }
} else {
$attributes['content'] = $post->content;
}
diff --git a/framework/core/src/Core/Command/StartDiscussion.php b/framework/core/src/Core/Command/StartDiscussion.php
index 2410f851b..f60a54c14 100644
--- a/framework/core/src/Core/Command/StartDiscussion.php
+++ b/framework/core/src/Core/Command/StartDiscussion.php
@@ -32,9 +32,10 @@ class StartDiscussion
* @param User $actor The user authoring the discussion.
* @param array $data The discussion attributes.
*/
- public function __construct(User $actor, array $data)
+ public function __construct(User $actor, array $data, $ipAddress)
{
$this->actor = $actor;
$this->data = $data;
+ $this->ipAddress = $ipAddress;
}
}
diff --git a/framework/core/src/Core/Command/StartDiscussionHandler.php b/framework/core/src/Core/Command/StartDiscussionHandler.php
index 527a8a2ab..b2b8acfe4 100644
--- a/framework/core/src/Core/Command/StartDiscussionHandler.php
+++ b/framework/core/src/Core/Command/StartDiscussionHandler.php
@@ -55,6 +55,7 @@ class StartDiscussionHandler
{
$actor = $command->actor;
$data = $command->data;
+ $ipAddress = $command->ipAddress;
$this->assertCan($actor, 'startDiscussion');
@@ -79,7 +80,7 @@ class StartDiscussionHandler
// We will do this by running the PostReply command.
try {
$post = $this->bus->dispatch(
- new PostReply($discussion->id, $actor, $data)
+ new PostReply($discussion->id, $actor, $data, $ipAddress)
);
} catch (Exception $e) {
$discussion->delete();