Skip to content

Commit

Permalink
feat: write a post (monicahq/chandler#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
djaiss authored Oct 5, 2022
1 parent 993ff4e commit c51fee3
Show file tree
Hide file tree
Showing 26 changed files with 910 additions and 62 deletions.
4 changes: 3 additions & 1 deletion app/Console/Commands/SetupDummyAccount.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use App\Models\ContactImportantDate;
use App\Models\Group;
use App\Models\Note;
use App\Models\PostTemplate;
use App\Models\User;
use App\Models\Vault;
use App\Settings\CreateAccount\Services\CreateAccount;
Expand Down Expand Up @@ -287,8 +288,9 @@ private function createJournals(): void
'author_id' => $this->firstUser->id,
'vault_id' => $vault->id,
'journal_id' => $journal->id,
'post_template_id' => PostTemplate::where('account_id', $this->firstUser->account_id)->inRandomOrder()->first()->id,
'title' => $this->faker->sentence(),
'content' => $this->faker->paragraphs(rand(1, 30), true),
'published' => false,
'written_at' => $this->faker->dateTimeThisYear()->format('Y-m-d'),
]);
}
Expand Down
38 changes: 38 additions & 0 deletions app/Helpers/PostHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace App\Helpers;

use App\Models\Post;
use Illuminate\Support\Str;

class PostHelper
{
/**
* Get the statistics of the post.
*
* @param Post $post
* @return array
*/
public static function statistics(Post $post): array
{
$wordCount = 0;
$duration = 0;

$postSections = $post->postSections()
->whereNotNull('content')
->get();

foreach ($postSections as $postSection) {
$wordCount = $wordCount + Str::of($postSection->content)->wordCount();
}

// human read around 200 words per minute
$minutesToRead = round($wordCount / 200);
$duration = (int) max(1, $minutesToRead);

return [
'word_count' => $wordCount,
'time_to_read_in_minute' => $duration,
];
}
}
24 changes: 23 additions & 1 deletion app/Models/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Post extends Model
{
Expand All @@ -20,8 +21,9 @@ class Post extends Model
protected $fillable = [
'journal_id',
'title',
'content',
'published',
'written_at',
'updated_at',
];

/**
Expand All @@ -31,6 +33,16 @@ class Post extends Model
*/
protected $dates = [
'written_at',
'updated_at',
];

/**
* The attributes that should be cast to native types.
*
* @var array<string, string>
*/
protected $casts = [
'published' => 'boolean',
];

/**
Expand All @@ -42,4 +54,14 @@ public function journal(): BelongsTo
{
return $this->belongsTo(Journal::class);
}

/**
* Get the post sections associated with the post.
*
* @return HasMany
*/
public function postSections(): HasMany
{
return $this->hasMany(PostSection::class);
}
}
36 changes: 36 additions & 0 deletions app/Models/PostSection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class PostSection extends Model
{
use HasFactory;

protected $table = 'post_sections';

/**
* The attributes that are mass assignable.
*
* @var array<string>
*/
protected $fillable = [
'post_id',
'label',
'position',
'content',
];

/**
* Get the post associated with the post section.
*
* @return BelongsTo
*/
public function post(): BelongsTo
{
return $this->belongsTo(Post::class);
}
}
2 changes: 1 addition & 1 deletion database/factories/PostFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function definition()
return [
'journal_id' => Journal::factory(),
'title' => $this->faker->sentence(),
'content' => $this->faker->name(),
'published' => false,
'written_at' => $this->faker->dateTimeThisCentury(),
];
}
Expand Down
32 changes: 32 additions & 0 deletions database/factories/PostSectionFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Database\Factories;

use App\Models\Post;
use App\Models\PostSection;
use Illuminate\Database\Eloquent\Factories\Factory;

class PostSectionFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var class-string<\Illuminate\Database\Eloquent\Model>
*/
protected $model = PostSection::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'post_id' => Post::factory(),
'label' => 'label',
'position' => $this->faker->numberBetween(1, 10),
'content' => $this->faker->sentence(),
];
}
}
14 changes: 12 additions & 2 deletions database/migrations/2022_09_22_111510_create_posts_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,22 @@ public function up()
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('journal_id');
$table->string('title');
$table->text('content');
$table->boolean('published')->default(false);
$table->string('title')->nullable();
$table->datetime('written_at');
$table->timestamps();
$table->foreign('journal_id')->references('id')->on('journals')->onDelete('cascade');
});

Schema::create('post_sections', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('post_id');
$table->integer('position');
$table->string('label');
$table->text('content')->nullable();
$table->timestamps();
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
});
}

/**
Expand Down
40 changes: 36 additions & 4 deletions domains/Vault/ManageJournals/Services/CreatePost.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use App\Interfaces\ServiceInterface;
use App\Models\Journal;
use App\Models\Post;
use App\Models\PostSection;
use App\Models\PostTemplate;
use App\Services\BaseService;

class CreatePost extends BaseService implements ServiceInterface
Expand All @@ -13,6 +15,8 @@ class CreatePost extends BaseService implements ServiceInterface

private Post $post;

private PostTemplate $postTemplate;

/**
* Get the validation rules that apply to the service.
*
Expand All @@ -25,8 +29,9 @@ public function rules(): array
'vault_id' => 'required|integer|exists:vaults,id',
'author_id' => 'required|integer|exists:users,id',
'journal_id' => 'required|integer|exists:journals,id',
'title' => 'required|string|max:255',
'content' => 'required|string|max:65535',
'post_template_id' => 'required|integer|exists:post_templates,id',
'title' => 'nullable|string|max:255',
'published' => 'required|boolean',
'written_at' => 'nullable|date_format:Y-m-d',
];
}
Expand Down Expand Up @@ -57,6 +62,7 @@ public function execute(array $data): Post

$this->validate();
$this->create();
$this->createPostSections();

return $this->post;
}
Expand All @@ -67,6 +73,9 @@ private function validate(): void

Journal::where('vault_id', $this->data['vault_id'])
->findOrfail($this->data['journal_id']);

$this->postTemplate = PostTemplate::where('account_id', $this->data['account_id'])
->findOrFail($this->data['post_template_id']);
}

private function create(): void
Expand All @@ -79,9 +88,32 @@ private function create(): void

$this->post = Post::create([
'journal_id' => $this->data['journal_id'],
'title' => $this->data['title'],
'content' => $this->data['content'],
'title' => $this->valueOrNull($this->data, 'title'),
'published' => $this->data['published'],
'written_at' => $writtenAt,
]);
}

/**
* Once the post is created, we also create post sections for this post.
* The post sections are defined by the post template that was chosen upon
* the creation of the post
* All these post sections will be blank until the user fills them.
*
* @return void
*/
private function createPostSections(): void
{
$postTemplateSections = $this->postTemplate->postTemplateSections()
->orderBy('position')
->get();

foreach ($postTemplateSections as $postTemplateSection) {
PostSection::create([
'post_id' => $this->post->id,
'position' => $postTemplateSection->position,
'label' => $postTemplateSection->label,
]);
}
}
}
22 changes: 19 additions & 3 deletions domains/Vault/ManageJournals/Services/UpdatePost.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Interfaces\ServiceInterface;
use App\Models\Journal;
use App\Models\Post;
use App\Models\PostSection;
use App\Services\BaseService;

class UpdatePost extends BaseService implements ServiceInterface
Expand All @@ -26,8 +27,8 @@ public function rules(): array
'author_id' => 'required|integer|exists:users,id',
'journal_id' => 'required|integer|exists:journals,id',
'post_id' => 'required|integer|exists:posts,id',
'content' => 'required|string|max:65535',
'excerpt' => 'nullable|string|max:65535',
'title' => 'nullable|string|max:255',
'sections' => 'required',
'written_at' => 'nullable|date_format:Y-m-d',
];
}
Expand Down Expand Up @@ -58,6 +59,7 @@ public function execute(array $data): Post

$this->validate();
$this->update();
$this->updateSections();

return $this->post;
}
Expand All @@ -82,8 +84,22 @@ private function update(): void
}

$this->post->title = $this->data['title'];
$this->post->content = $this->data['content'];
$this->post->written_at = $writtenAt;
$this->post->save();
}

private function updateSections(): void
{
foreach ($this->data['sections'] as $section) {
if (! array_key_exists('content', $section)) {
continue;
}

PostSection::where('post_id', $this->post->id)
->where('id', $section['id'])
->update([
'content' => $section['content'],
]);
}
}
}
Loading

0 comments on commit c51fee3

Please sign in to comment.