Skip to content

Commit a3530ef

Browse files
committed
Add article status
1 parent 3d7b245 commit a3530ef

File tree

12 files changed

+294
-15
lines changed

12 files changed

+294
-15
lines changed

app/Http/Controllers/Articles/ArticlesController.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use App\Models\Tag;
1414
use App\Policies\ArticlePolicy;
1515
use Illuminate\Http\Request;
16+
use Illuminate\Support\Facades\Auth;
1617

1718
class ArticlesController extends Controller
1819
{
@@ -27,9 +28,13 @@ public function index()
2728

2829
public function show(Article $article)
2930
{
30-
return view('articles.show', [
31-
'article' => $article,
32-
]);
31+
if ($article->isPublished() || (Auth::check() && $article->isAuthoredBy(Auth::user()))) {
32+
return view('articles.show', [
33+
'article' => $article,
34+
]);
35+
}
36+
37+
abort(404);
3338
}
3439

3540
public function create(Request $request)

app/Http/Requests/ArticleRequest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public function rules()
1717
'tags.*' => 'exists:tags,id',
1818
'original_url' => 'url|nullable',
1919
'series' => ['nullable', new AuthorOwnsSeriesRule],
20+
'status' => ['required', 'in:draft,publish'],
2021
];
2122
}
2223

@@ -49,4 +50,9 @@ public function originalUrl(): ?string
4950
{
5051
return $this->get('original_url');
5152
}
53+
54+
public function shouldBePublished(): bool
55+
{
56+
return $this->get('status') === 'publish';
57+
}
5258
}

app/Jobs/CreateArticle.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@ final class CreateArticle
1515

1616
private $author;
1717

18+
private $shouldBePublished;
19+
1820
private $originalUrl;
1921

2022
private $tags;
2123

2224
private $series;
2325

24-
public function __construct(string $title, string $body, User $author, array $options = [])
26+
public function __construct(string $title, string $body, User $author, bool $shouldBePublished, array $options = [])
2527
{
2628
$this->title = $title;
2729
$this->body = $body;
2830
$this->author = $author;
31+
$this->shouldBePublished = $shouldBePublished;
2932
$this->originalUrl = $options['original_url'] ?? null;
3033
$this->tags = $options['tags'] ?? [];
3134
$this->series = $options['series'] ?? null;
@@ -37,6 +40,7 @@ public static function fromRequest(ArticleRequest $request): self
3740
$request->title(),
3841
$request->body(),
3942
$request->author(),
43+
$request->shouldBePublished(),
4044
[
4145
'original_url' => $request->originalUrl(),
4246
'tags' => $request->tags(),
@@ -52,6 +56,7 @@ public function handle(): Article
5256
'body' => $this->body,
5357
'original_url' => $this->originalUrl,
5458
'slug' => $this->title,
59+
'published_at' => $this->shouldBePublished ? now() : null,
5560
]);
5661
$article->authoredBy($this->author);
5762
$article->syncTags($this->tags);

app/Jobs/UpdateArticle.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,20 @@ final class UpdateArticle
1414

1515
private $body;
1616

17+
private $shouldBePublished;
18+
1719
private $originalUrl;
1820

1921
private $tags;
2022

2123
private $series;
2224

23-
public function __construct(Article $article, string $title, string $body, array $options = [])
25+
public function __construct(Article $article, string $title, string $body, bool $shouldBePublished, array $options = [])
2426
{
2527
$this->article = $article;
2628
$this->title = $title;
2729
$this->body = $body;
30+
$this->shouldBePublished = $shouldBePublished;
2831
$this->originalUrl = $options['original_url'] ?? null;
2932
$this->tags = $options['tags'] ?? [];
3033
$this->series = $options['series'] ?? null;
@@ -36,6 +39,7 @@ public static function fromRequest(Article $article, ArticleRequest $request): s
3639
$article,
3740
$request->title(),
3841
$request->body(),
42+
$request->shouldBePublished(),
3943
[
4044
'original_url' => $request->originalUrl(),
4145
'tags' => $request->tags(),
@@ -51,6 +55,7 @@ public function handle(): Article
5155
'body' => $this->body,
5256
'original_url' => $this->originalUrl,
5357
'slug' => $this->title,
58+
'published_at' => $this->shouldBePublished ? now() : null,
5459
]);
5560
$this->article->syncTags($this->tags);
5661
$this->article->updateSeries(Series::find($this->series));

app/Models/Article.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use App\Helpers\HasSlug;
88
use App\Helpers\HasTags;
99
use App\Helpers\HasTimestamps;
10+
use Carbon\Carbon;
11+
use Illuminate\Database\Eloquent\Builder;
1012
use Illuminate\Database\Eloquent\Model;
1113

1214
final class Article extends Model
@@ -21,6 +23,14 @@ final class Article extends Model
2123
'body',
2224
'original_url',
2325
'slug',
26+
'published_at',
27+
];
28+
29+
/**
30+
* {@inheritdoc}
31+
*/
32+
protected $dates = [
33+
'published_at',
2434
];
2535

2636
public function id(): int
@@ -77,4 +87,29 @@ public function removeSeries(): self
7787

7888
return $this;
7989
}
90+
91+
public function publishedAt(): ?Carbon
92+
{
93+
return $this->published_at;
94+
}
95+
96+
public function isPublished(): bool
97+
{
98+
return ! $this->isNotPublished();
99+
}
100+
101+
public function isNotPublished(): bool
102+
{
103+
return is_null($this->published_at);
104+
}
105+
106+
public function scopePublished(Builder $query): Builder
107+
{
108+
return $query->whereNotNull('published_at');
109+
}
110+
111+
public function scopeNotPublished(Builder $query): Builder
112+
{
113+
return $query->whereNull('published_at');
114+
}
80115
}

database/migrations/2020_04_07_185543_create_community_articles_table.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function up()
1616
$table->text('body');
1717
$table->string('original_url')->nullable();
1818
$table->string('slug')->unique();
19+
$table->timestamp('published_at')->nullable();
1920
$table->timestamps();
2021

2122
$table->foreign('series_id')

resources/css/buttons.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,12 @@
4848

4949
a.button:hover {
5050
@apply no-underline;
51+
}
52+
53+
.button-dropdown-left {
54+
@apply rounded-r-none px-2;
55+
}
56+
57+
.button-dropdown-right {
58+
@apply rounded-l-none px-2;
5159
}

resources/views/articles/_form.blade.php

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,52 @@ class="text-green-darker"
8080

8181
<div class="flex justify-end items-center">
8282
<a href="{{ isset($article) ? route('articles.show', $article->slug()) : route('articles') }}" class="text-green-darker mr-4">Cancel</a>
83-
<button type="submit" class="button button-primary">{{ isset($article) ? 'Update Article' : 'Create Article' }}</button>
83+
@if(isset($article) && $article->isPublished())
84+
<button
85+
type="submit"
86+
name="status"
87+
value="publish"
88+
class="button button-primary"
89+
>
90+
Save changes
91+
</button>
92+
@else
93+
<span class="relative z-0 inline-flex shadow-sm" x-data="{ showDropdown: false }" @click.away="showDropdown = false">
94+
<button
95+
type="submit"
96+
name="status"
97+
value="draft"
98+
class="button button-primary button-dropdown-left relative inline-flex items-center focus:outline-none"
99+
>
100+
Save draft
101+
</button>
102+
<span class="-ml-px relative block">
103+
<button
104+
@click="showDropdown = !showDropdown"
105+
type="button"
106+
class="button button-primary h-full button-dropdown-right relative inline-flex items-center focus:outline-none"
107+
>
108+
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
109+
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
110+
</svg>
111+
</button>
112+
<div class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg" x-show="showDropdown" x-cloak>
113+
<div class="rounded-md bg-white shadow-xs">
114+
<div class="py-1">
115+
<button
116+
type="submit"
117+
name="status"
118+
value="publish"
119+
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900 w-full text-left"
120+
>
121+
Save and publish
122+
</button>
123+
</div>
124+
</div>
125+
</div>
126+
</span>
127+
</span>
128+
@endif
84129
</div>
85130
</div>
86131
</form>

resources/views/articles/show.blade.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@
77
@section('content')
88
<div class="max-w-screen-md mx-auto p-4 pt-8">
99
<h1 class="text-4xl tracking-tight leading-10 font-extrabold text-gray-900 sm:leading-none mb-4">{{ $article->title() }}</h1>
10+
@if($article->isNotPublished())
11+
<span class="label inline-flex mb-4">
12+
Draft
13+
</span>
14+
@endif
1015
<div class="mr-6 mb-8 text-gray-700 flex items-center">
1116
@include('forum.threads.info.avatar', ['user' => $article->author(), 'size' => 50])
1217
<div>
1318
<a href="{{ route('profile', $article->author()->username()) }}"
1419
class="text-green-darker mr-2">
15-
{{ $article->author()->name() }}
20+
{{ $article->author()->name() }}
1621
</a>
1722
<span class="block text-sm">published {{ $article->createdAt()->format('j M, Y') }}</span>
1823
</div>

0 commit comments

Comments
 (0)