diff --git a/db/migrations/2020_12_26_000000_news_add_is_pinned.php b/db/migrations/2020_12_26_000000_news_add_is_pinned.php
new file mode 100644
index 00000000..8c8c9f5e
--- /dev/null
+++ b/db/migrations/2020_12_26_000000_news_add_is_pinned.php
@@ -0,0 +1,37 @@
+schema->table(
+ 'news',
+ function (Blueprint $table) {
+ $table->boolean('is_pinned')->default(false)->after('is_meeting');
+ }
+ );
+ }
+
+ /**
+ * Reverse the migration
+ */
+ public function down()
+ {
+ $this->schema->table(
+ 'news',
+ function (Blueprint $table) {
+ $table->dropColumn('is_pinned');
+ }
+ );
+ }
+}
diff --git a/resources/lang/de_DE/default.po b/resources/lang/de_DE/default.po
index 40fcf1f0..87461bed 100644
--- a/resources/lang/de_DE/default.po
+++ b/resources/lang/de_DE/default.po
@@ -2885,6 +2885,9 @@ msgstr "Betreff"
msgid "news.edit.is_meeting"
msgstr "Treffen"
+msgid "news.edit.is_pinned"
+msgstr "Oben anpinnen"
+
msgid "news.edit.message"
msgstr "Nachricht"
diff --git a/resources/lang/en_US/default.po b/resources/lang/en_US/default.po
index c5b7c777..b63f882a 100644
--- a/resources/lang/en_US/default.po
+++ b/resources/lang/en_US/default.po
@@ -171,6 +171,9 @@ msgstr "Subject"
msgid "news.edit.is_meeting"
msgstr "Meeting"
+msgid "news.edit.is_pinned"
+msgstr "Pin to top"
+
msgid "news.edit.message"
msgstr "Message"
diff --git a/resources/views/pages/news/edit.twig b/resources/views/pages/news/edit.twig
index 777d1d39..0e10b883 100644
--- a/resources/views/pages/news/edit.twig
+++ b/resources/views/pages/news/edit.twig
@@ -42,6 +42,7 @@
{{ f.checkbox('is_meeting', __('news.edit.is_meeting'), is_meeting) }}
+ {{ f.checkbox('is_pinned', __('news.edit.is_pinned'), is_pinned) }}
diff --git a/resources/views/pages/news/overview.twig b/resources/views/pages/news/overview.twig
index 3822f81d..b3198427 100644
--- a/resources/views/pages/news/overview.twig
+++ b/resources/views/pages/news/overview.twig
@@ -53,6 +53,7 @@
+ {% if news.is_pinned %}{{ m.glyphicon('pushpin') }}{% endif %}
{% if news.is_meeting %}{{ __('news.is_meeting') }}{% endif %}
{{ news.title }}
diff --git a/src/Controllers/Admin/NewsController.php b/src/Controllers/Admin/NewsController.php
index b7f36940..a1b0e11c 100644
--- a/src/Controllers/Admin/NewsController.php
+++ b/src/Controllers/Admin/NewsController.php
@@ -96,7 +96,8 @@ class NewsController extends BaseController
'pages/news/edit.twig',
[
'news' => $news,
- 'is_meeting' => $news ? $news->is_meeting : $isMeetingDefault
+ 'is_meeting' => $news ? $news->is_meeting : $isMeetingDefault,
+ 'is_pinned' => $news ? $news->is_pinned : false,
] + $this->getNotifications(),
);
}
@@ -116,6 +117,7 @@ class NewsController extends BaseController
'title' => 'required',
'text' => 'required',
'is_meeting' => 'optional|checked',
+ 'is_pinned' => 'optional|checked',
'delete' => 'optional|checked',
'preview' => 'optional|checked',
]);
@@ -146,6 +148,7 @@ class NewsController extends BaseController
$news->title = $data['title'];
$news->text = $data['text'];
$news->is_meeting = !is_null($data['is_meeting']);
+ $news->is_pinned = !is_null($data['is_pinned']);
if (!is_null($data['preview'])) {
return $this->showEdit($news);
@@ -154,11 +157,12 @@ class NewsController extends BaseController
$news->save();
$this->log->info(
- 'Updated {type} "{news}": {text}',
+ 'Updated {pinned}{type} "{news}": {text}',
[
- 'type' => $news->is_meeting ? 'meeting' : 'news',
- 'news' => $news->title,
- 'text' => $news->text,
+ 'pinned' => $news->is_pinned ? 'pinned ' : '',
+ 'type' => $news->is_meeting ? 'meeting' : 'news',
+ 'news' => $news->title,
+ 'text' => $news->text,
]
);
diff --git a/src/Controllers/NewsController.php b/src/Controllers/NewsController.php
index 4d0b6cb8..2d9b540d 100644
--- a/src/Controllers/NewsController.php
+++ b/src/Controllers/NewsController.php
@@ -149,6 +149,7 @@ class NewsController extends BaseController
$news = $query
->with('user')
->withCount('comments')
+ ->orderByDesc('is_pinned')
->orderByDesc('updated_at')
->limit($perPage)
->offset(($page - 1) * $perPage)
diff --git a/src/Models/News.php b/src/Models/News.php
index 19a3208c..4de04cd0 100644
--- a/src/Models/News.php
+++ b/src/Models/News.php
@@ -15,6 +15,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @property string $title
* @property string $text
* @property bool $is_meeting
+ * @property bool $is_pinned
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
*
@@ -25,6 +26,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @method static QueryBuilder|LogEntry[] whereTitle($value)
* @method static QueryBuilder|LogEntry[] whereText($value)
* @method static QueryBuilder|LogEntry[] whereIsMeeting($value)
+ * @method static QueryBuilder|LogEntry[] whereIsPinned($value)
* @method static QueryBuilder|LogEntry[] whereCreatedAt($value)
* @method static QueryBuilder|LogEntry[] whereUpdatedAt($value)
*/
@@ -38,6 +40,7 @@ class News extends BaseModel
/** @var array */
protected $casts = [
'is_meeting' => 'boolean',
+ 'is_pinned' => 'boolean',
];
/** @var array */
@@ -45,6 +48,7 @@ class News extends BaseModel
'title',
'text',
'is_meeting',
+ 'is_pinned',
'user_id',
];
diff --git a/tests/Unit/Controllers/Admin/NewsControllerTest.php b/tests/Unit/Controllers/Admin/NewsControllerTest.php
index 7edee5ae..8f443116 100644
--- a/tests/Unit/Controllers/Admin/NewsControllerTest.php
+++ b/tests/Unit/Controllers/Admin/NewsControllerTest.php
@@ -214,6 +214,7 @@ class NewsControllerTest extends ControllerTest
'title' => 'New title',
'text' => 'New text',
'is_meeting' => '1',
+ 'is_pinned' => '1',
'preview' => '1',
]);
$this->response->expects($this->once())
@@ -225,6 +226,7 @@ class NewsControllerTest extends ControllerTest
$news = $data['news'];
// Contains new text
$this->assertTrue($news->is_meeting);
+ $this->assertTrue($news->is_pinned);
$this->assertEquals('New title', $news->title);
$this->assertEquals('New text', $news->text);
@@ -242,6 +244,7 @@ class NewsControllerTest extends ControllerTest
$this->assertEquals('Foo', $news->title);
$this->assertEquals('foo', $news->text);
$this->assertFalse($news->is_meeting);
+ $this->assertFalse($news->is_pinned);
}
/**
diff --git a/tests/Unit/Controllers/NewsControllerTest.php b/tests/Unit/Controllers/NewsControllerTest.php
index 822d398b..e63abe50 100644
--- a/tests/Unit/Controllers/NewsControllerTest.php
+++ b/tests/Unit/Controllers/NewsControllerTest.php
@@ -44,12 +44,14 @@ class NewsControllerTest extends TestCase
'title' => 'Bar',
'text' => 'bar',
'is_meeting' => false,
+ 'is_pinned' => true,
'user_id' => 1,
],
[
'title' => 'baz',
'text' => 'baz',
'is_meeting' => true,
+ 'is_pinned' => true,
'user_id' => 1,
],
[
@@ -62,6 +64,7 @@ class NewsControllerTest extends TestCase
'title' => 'Ipsum',
'text' => 'ipsum',
'is_meeting' => true,
+ 'is_pinned' => true,
'user_id' => 1,
],
[
@@ -111,6 +114,8 @@ class NewsControllerTest extends TestCase
$this->assertTrue($news->isNotEmpty());
$this->assertEquals(3, $data['pages']);
$this->assertEquals(2, $data['page']);
+ $this->assertTrue($news[0]->is_pinned);
+ $this->assertEquals('Ipsum', $news[0]->title);
break;
case 2:
// Show meetings
diff --git a/tests/Unit/Models/NewsTest.php b/tests/Unit/Models/NewsTest.php
index 40177560..d99a470e 100644
--- a/tests/Unit/Models/NewsTest.php
+++ b/tests/Unit/Models/NewsTest.php
@@ -78,7 +78,7 @@ class NewsTest extends ModelTest
public function testCreate(): void
{
$news = (new News())->create(
- $this->newsData + ['is_meeting' => true]
+ $this->newsData + ['is_meeting' => true, 'is_pinned' => true]
);
$news = $news->find($news->id);
@@ -86,5 +86,6 @@ class NewsTest extends ModelTest
$this->assertSame($this->newsData['title'], $news->title);
$this->assertSame($this->newsData['text'], $news->text);
$this->assertTrue($news->is_meeting);
+ $this->assertTrue($news->is_pinned);
}
}