Added important news (#1096)

This commit is contained in:
xuwhite 2023-02-13 21:19:45 +01:00 committed by GitHub
parent 713f8222e4
commit 6fcb656299
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 176 additions and 51 deletions

View File

@ -20,6 +20,7 @@ class NewsFactory extends Factory
'text' => $this->faker->realText(), 'text' => $this->faker->realText(),
'is_meeting' => $this->faker->boolean(), 'is_meeting' => $this->faker->boolean(),
'is_pinned' => $this->faker->boolean(.1), 'is_pinned' => $this->faker->boolean(.1),
'is_important' => $this->faker->boolean(.1),
'user_id' => User::factory(), 'user_id' => User::factory(),
]; ];
} }

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
class AddSetNewsFlagImportantPermissions extends Migration
{
/**
* Run the migration
*/
public function up(): void
{
$db = $this->schema->getConnection();
$db->table('privileges')
->insert(['name' => 'news.important', 'description' => 'Make News Important']);
$newsImportant = $db->table('privileges')
->where('name', 'news.important')
->get(['id'])
->first();
$buerocrat = 80;
$db->table('group_privileges')
->insertOrIgnore([
['group_id' => $buerocrat, 'privilege_id' => $newsImportant->id],
]);
}
/**
* Reverse the migration
*/
public function down(): void
{
$db = $this->schema->getConnection();
$db->table('privileges')
->where(['name' => 'news.important'])
->delete();
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddIsImportantToNews extends Migration
{
/**
* Run the migration
*/
public function up(): void
{
$this->schema->table('news', function (Blueprint $table): void {
$table->boolean('is_important')->default(false)->after('is_pinned');
});
}
/**
* Reverse the migration
*/
public function down(): void
{
$this->schema->table('news', function (Blueprint $table): void {
$table->dropColumn('is_important');
});
}
}

View File

@ -1,6 +1,7 @@
<?php <?php
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\News;
use Engelsystem\Models\Shifts\Shift; use Engelsystem\Models\Shifts\Shift;
use Engelsystem\ShiftsFilter; use Engelsystem\ShiftsFilter;
@ -55,9 +56,14 @@ function public_dashboard_controller()
} }
} }
$important_news = News::whereIsImportant(true)
->orderBy('updated_at')
->limit(1)
->get();
return [ return [
__('Public Dashboard'), __('Public Dashboard'),
public_dashboard_view($stats, $free_shifts), public_dashboard_view($stats, $free_shifts, $important_news),
]; ];
} }

View File

@ -1,15 +1,27 @@
<?php <?php
use Engelsystem\Models\News;
use Illuminate\Support\Collection;
/** /**
* Public dashboard (formerly known as angel news hub) * Public dashboard (formerly known as angel news hub)
* *
* @param array $stats * @param array $stats
* @param array[] $free_shifts * @param array[] $free_shifts
* @param News[]|Collection $important_news
* @return string * @return string
*/ */
function public_dashboard_view($stats, $free_shifts) function public_dashboard_view($stats, $free_shifts, $important_news)
{ {
$needed_angels = ''; $needed_angels = '';
$news = '';
if ($important_news->isNotEmpty()) {
$first_news = $important_news->first();
$news = div('alert alert-warning text-center', [
'<a href="' . url('/news/' . $first_news->id) . '"><strong>' . $first_news->title . '</strong></a>',
]);
}
if (count($free_shifts) > 0) { if (count($free_shifts) > 0) {
$shift_panels = [ $shift_panels = [
'<div class="row">', '<div class="row">',
@ -42,6 +54,7 @@ function public_dashboard_view($stats, $free_shifts)
stats(__('Angels currently working'), $stats['angels-working'], 'default'), stats(__('Angels currently working'), $stats['angels-working'], 'default'),
stats(__('Hours to be worked'), $stats['hours-to-work'], 'default'), stats(__('Hours to be worked'), $stats['hours-to-work'], 'default'),
], 'statistics'), ], 'statistics'),
$news,
$needed_angels, $needed_angels,
], 'public-dashboard'), ], 'public-dashboard'),
]), ]),

View File

@ -137,6 +137,10 @@ table a > .icon-icon_angel {
} }
} }
.public-dashboard .alert a {
text-decoration: inherit;
}
.dashboard-card { .dashboard-card {
position: relative; position: relative;
font-size: 20px; font-size: 20px;

View File

@ -2910,6 +2910,9 @@ msgstr "+"
msgid "news.is_meeting" msgid "news.is_meeting"
msgstr "[Treffen]" msgstr "[Treffen]"
msgid "news.edit.is_important"
msgstr "Wichtig"
msgid "news.read_more" msgid "news.read_more"
msgstr "Weiterlesen" msgstr "Weiterlesen"

View File

@ -187,6 +187,9 @@ msgstr "Subject"
msgid "news.edit.is_meeting" msgid "news.edit.is_meeting"
msgstr "Meeting" msgstr "Meeting"
msgid "news.edit.is_important"
msgstr "Important"
msgid "news.edit.is_pinned" msgid "news.edit.is_pinned"
msgstr "Pin to top" msgstr "Pin to top"

View File

@ -43,6 +43,7 @@
<div class="col-md-6"> <div class="col-md-6">
{{ f.checkbox('is_meeting', __('news.edit.is_meeting'), is_meeting) }} {{ f.checkbox('is_meeting', __('news.edit.is_meeting'), is_meeting) }}
{{ f.checkbox('is_pinned', __('news.edit.is_pinned'), is_pinned) }} {{ f.checkbox('is_pinned', __('news.edit.is_pinned'), is_pinned) }}
{% if has_permission_to('news.important') %} {{ f.checkbox('is_important', __('news.edit.is_important'), is_important) }}{% endif %}
</div> </div>
</div> </div>
@ -67,7 +68,7 @@
<div class="col-md-12"> <div class="col-md-12">
<h2>{{ __('form.preview') }}</h2> <h2>{{ __('form.preview') }}</h2>
<div class="card {% if news.is_meeting %}bg-info{% else %}{% if theme.type =='light' %}bg-light{% else %}bg-secondary{% endif %}{% endif %} mb-4"> <div class="card {% if news.is_important %}bg-warning{% elseif news.is_meeting %}bg-info{% elseif theme.type =='light' %}bg-light{% else %}bg-secondary{% endif %} mb-4">
<div class="card-header {% if news.is_meeting and theme.type == 'dark' %}text-white{% endif %}"> <div class="card-header {% if news.is_meeting and theme.type == 'dark' %}text-white{% endif %}">
{% if news.is_meeting %}{{ __('news.is_meeting') }}{% endif %} {% if news.is_meeting %}{{ __('news.is_meeting') }}{% endif %}
{{ news.title }} {{ news.title }}

View File

@ -48,7 +48,7 @@
{% endblock %} {% endblock %}
{% macro news(news, show_comments_link, is_overview) %} {% macro news(news, show_comments_link, is_overview) %}
<div class="card {% if news.is_meeting %}bg-info{% else %}{% if theme.type =='light' %}bg-light{% else %}bg-dark{% endif %}{% endif %} mb-4"> <div class="card {% if news.is_important %}bg-warning{% elseif news.is_meeting %}bg-info{% elseif theme.type =='light' %}bg-light{% else %}bg-dark{% endif %} mb-4">
{% if is_overview|default(false) %} {% if is_overview|default(false) %}
<div class="card-header {% if news.is_meeting and theme.type == 'dark' %}text-white{% endif %}"> <div class="card-header {% if news.is_meeting and theme.type == 'dark' %}text-white{% endif %}">
<a href="{{ url('news/' ~ news.id) }}" class="text-inherit"> <a href="{{ url('news/' ~ news.id) }}" class="text-inherit">

View File

@ -49,6 +49,7 @@ class NewsController extends BaseController
'news' => $news, 'news' => $news,
'is_meeting' => $news ? $news->is_meeting : $isMeetingDefault, 'is_meeting' => $news ? $news->is_meeting : $isMeetingDefault,
'is_pinned' => $news ? $news->is_pinned : false, 'is_pinned' => $news ? $news->is_pinned : false,
'is_important' => $news ? $news->is_important : false,
], ],
); );
} }
@ -65,6 +66,7 @@ class NewsController extends BaseController
'text' => 'required', 'text' => 'required',
'is_meeting' => 'optional|checked', 'is_meeting' => 'optional|checked',
'is_pinned' => 'optional|checked', 'is_pinned' => 'optional|checked',
'is_important' => 'optional|checked',
'delete' => 'optional|checked', 'delete' => 'optional|checked',
'preview' => 'optional|checked', 'preview' => 'optional|checked',
]); ]);
@ -93,6 +95,10 @@ class NewsController extends BaseController
$news->is_meeting = !is_null($data['is_meeting']); $news->is_meeting = !is_null($data['is_meeting']);
$news->is_pinned = !is_null($data['is_pinned']); $news->is_pinned = !is_null($data['is_pinned']);
if ($this->auth->can('news.important')) {
$news->is_important = !is_null($data['is_important']);
}
if (!is_null($data['preview'])) { if (!is_null($data['preview'])) {
return $this->showEdit($news); return $this->showEdit($news);
} }
@ -108,6 +114,7 @@ class NewsController extends BaseController
'Updated {pinned}{type} "{news}": {text}', 'Updated {pinned}{type} "{news}": {text}',
[ [
'pinned' => $news->is_pinned ? 'pinned ' : '', 'pinned' => $news->is_pinned ? 'pinned ' : '',
'important' => $news->is_important ? 'important ' : '',
'type' => $news->is_meeting ? 'meeting' : 'news', 'type' => $news->is_meeting ? 'meeting' : 'news',
'news' => $news->title, 'news' => $news->title,
'text' => $news->text, 'text' => $news->text,

View File

@ -134,6 +134,7 @@ class NewsController extends BaseController
->with('user') ->with('user')
->withCount('comments') ->withCount('comments')
->orderByDesc('is_pinned') ->orderByDesc('is_pinned')
->orderByDesc('is_important')
->orderByDesc('updated_at') ->orderByDesc('updated_at')
->limit($perPage) ->limit($perPage)
->offset(($page - 1) * $perPage) ->offset(($page - 1) * $perPage)

View File

@ -18,19 +18,21 @@ use Illuminate\Support\Str;
* @property string $text * @property string $text
* @property bool $is_meeting * @property bool $is_meeting
* @property bool $is_pinned * @property bool $is_pinned
* @property bool $is_important
* @property Carbon|null $created_at * @property Carbon|null $created_at
* @property Carbon|null $updated_at * @property Carbon|null $updated_at
* *
* @property-read Collection|NewsComment[] $comments * @property-read Collection|NewsComment[] $comments
* @property-read int|null $comments_count * @property-read int|null $comments_count
* *
* @method static QueryBuilder|LogEntry[] whereId($value) * @method static QueryBuilder|News[] whereId($value)
* @method static QueryBuilder|LogEntry[] whereTitle($value) * @method static QueryBuilder|News[] whereTitle($value)
* @method static QueryBuilder|LogEntry[] whereText($value) * @method static QueryBuilder|News[] whereText($value)
* @method static QueryBuilder|LogEntry[] whereIsMeeting($value) * @method static QueryBuilder|News[] whereIsMeeting($value)
* @method static QueryBuilder|LogEntry[] whereIsPinned($value) * @method static QueryBuilder|News[] whereIsPinned($value)
* @method static QueryBuilder|LogEntry[] whereCreatedAt($value) * @method static QueryBuilder|News[] whereIsImportant($value)
* @method static QueryBuilder|LogEntry[] whereUpdatedAt($value) * @method static QueryBuilder|News[] whereCreatedAt($value)
* @method static QueryBuilder|News[] whereUpdatedAt($value)
*/ */
class News extends BaseModel class News extends BaseModel
{ {
@ -45,12 +47,14 @@ class News extends BaseModel
'user_id' => 'integer', 'user_id' => 'integer',
'is_meeting' => 'boolean', 'is_meeting' => 'boolean',
'is_pinned' => 'boolean', 'is_pinned' => 'boolean',
'is_important' => 'boolean',
]; ];
/** @var array<string, bool> Default attributes */ /** @var array<string, bool> Default attributes */
protected $attributes = [ // phpcs:ignore protected $attributes = [ // phpcs:ignore
'is_meeting' => false, 'is_meeting' => false,
'is_pinned' => false, 'is_pinned' => false,
'is_important' => false,
]; ];
/** @var array<string> */ /** @var array<string> */
@ -59,6 +63,7 @@ class News extends BaseModel
'text', 'text',
'is_meeting', 'is_meeting',
'is_pinned', 'is_pinned',
'is_important',
'user_id', 'user_id',
]; ];

View File

@ -23,10 +23,10 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @property-read AngelType $angelType * @property-read AngelType $angelType
* @property-read User $confirmUser * @property-read User $confirmUser
* *
* @method static QueryBuilder|AngelType[] whereId($value) * @method static QueryBuilder|UserAngelType[] whereId($value)
* @method static QueryBuilder|AngelType[] whereAngelTypeId($value) * @method static QueryBuilder|UserAngelType[] whereAngelTypeId($value)
* @method static QueryBuilder|AngelType[] whereConfirmUserId($value) * @method static QueryBuilder|UserAngelType[] whereConfirmUserId($value)
* @method static QueryBuilder|AngelType[] whereSupporter($value) * @method static QueryBuilder|UserAngelType[] whereSupporter($value)
*/ */
class UserAngelType extends Pivot class UserAngelType extends Pivot
{ {

View File

@ -162,6 +162,7 @@ class NewsControllerTest extends ControllerTest
'text' => 'New text', 'text' => 'New text',
'is_meeting' => '1', 'is_meeting' => '1',
'is_pinned' => '1', 'is_pinned' => '1',
'is_important' => '1',
'preview' => '1', 'preview' => '1',
]); ]);
$this->response->expects($this->once()) $this->response->expects($this->once())
@ -174,11 +175,16 @@ class NewsControllerTest extends ControllerTest
// Contains new text // Contains new text
$this->assertTrue($news->is_meeting); $this->assertTrue($news->is_meeting);
$this->assertTrue($news->is_pinned); $this->assertTrue($news->is_pinned);
$this->assertTrue($news->is_important);
$this->assertEquals('New title', $news->title); $this->assertEquals('New title', $news->title);
$this->assertEquals('New text', $news->text); $this->assertEquals('New text', $news->text);
return $this->response; return $this->response;
}); });
$this->auth->expects($this->atLeastOnce())
->method('can')
->with('news.important')
->willReturn(true);
/** @var NewsController $controller */ /** @var NewsController $controller */
$controller = $this->app->make(NewsController::class); $controller = $this->app->make(NewsController::class);
@ -192,6 +198,7 @@ class NewsControllerTest extends ControllerTest
$this->assertEquals('**foo**', $news->text); $this->assertEquals('**foo**', $news->text);
$this->assertFalse($news->is_meeting); $this->assertFalse($news->is_meeting);
$this->assertFalse($news->is_pinned); $this->assertFalse($news->is_pinned);
$this->assertFalse($news->is_important);
} }
/** /**

View File

@ -43,6 +43,7 @@ class NewsControllerTest extends ControllerTest
'text' => 'baz', 'text' => 'baz',
'is_meeting' => true, 'is_meeting' => true,
'is_pinned' => true, 'is_pinned' => true,
'is_important' => true,
'user_id' => 1, 'user_id' => 1,
], ],
[ [

View File

@ -28,7 +28,7 @@ class PrivilegeTest extends ModelTest
$model->groups()->attach($group2); $model->groups()->attach($group2);
/** @var Privilege $savedModel */ /** @var Privilege $savedModel */
$savedModel = Privilege::first(); $savedModel = Privilege::whereName('Some Privilege')->first();
$this->assertEquals('Some Privilege', $savedModel->name); $this->assertEquals('Some Privilege', $savedModel->name);
$this->assertEquals('Some long description', $savedModel->description); $this->assertEquals('Some long description', $savedModel->description);
$this->assertEquals($group1->name, $savedModel->groups[0]->name); $this->assertEquals($group1->name, $savedModel->groups[0]->name);