diff --git a/app/Domains/Contact/ManageContact/Web/ViewHelpers/ContactShowViewHelper.php b/app/Domains/Contact/ManageContact/Web/ViewHelpers/ContactShowViewHelper.php index 59af6d505..04c9b87e0 100644 --- a/app/Domains/Contact/ManageContact/Web/ViewHelpers/ContactShowViewHelper.php +++ b/app/Domains/Contact/ManageContact/Web/ViewHelpers/ContactShowViewHelper.php @@ -24,6 +24,7 @@ use App\Domains\Contact\ManageRelationships\Web\ViewHelpers\ModuleRelationshipVi use App\Domains\Contact\ManageReligion\Web\ViewHelpers\ModuleReligionViewHelper; use App\Domains\Contact\ManageReminders\Web\ViewHelpers\ModuleRemindersViewHelper; use App\Domains\Contact\ManageTasks\Web\ViewHelpers\ModuleContactTasksViewHelper; +use App\Domains\Vault\ManageJournals\Web\ViewHelpers\ModulePostsViewHelper; use App\Helpers\StorageHelper; use App\Models\Contact; use App\Models\Module; @@ -285,6 +286,10 @@ class ContactShowViewHelper $data = ModulePhotosViewHelper::data($contact); } + if ($module->type == Module::TYPE_POSTS) { + $data = ModulePostsViewHelper::data($contact, $user); + } + $modulesCollection->push([ 'id' => $module->id, 'type' => $module->type, diff --git a/app/Domains/Settings/CreateAccount/Jobs/SetupAccount.php b/app/Domains/Settings/CreateAccount/Jobs/SetupAccount.php index d2cf83351..260da85f3 100644 --- a/app/Domains/Settings/CreateAccount/Jobs/SetupAccount.php +++ b/app/Domains/Settings/CreateAccount/Jobs/SetupAccount.php @@ -561,6 +561,22 @@ class SetupAccount extends QueuableService implements ServiceInterface 'template_page_id' => $templatePageInformation->id, 'module_id' => $module->id, ]); + + // Posts + $module = (new CreateModule())->execute([ + 'account_id' => $this->author->account_id, + 'author_id' => $this->author->id, + 'name' => trans('app.module_posts'), + 'type' => Module::TYPE_POSTS, + 'can_be_deleted' => false, + ]); + (new AssociateModuleToTemplatePage())->execute([ + 'account_id' => $this->author->account_id, + 'author_id' => $this->author->id, + 'template_id' => $this->template->id, + 'template_page_id' => $templatePageInformation->id, + 'module_id' => $module->id, + ]); } private function addFirstInformation(): void diff --git a/app/Domains/Vault/ManageJournals/Services/AddContactToPost.php b/app/Domains/Vault/ManageJournals/Services/AddContactToPost.php new file mode 100644 index 000000000..fc1916739 --- /dev/null +++ b/app/Domains/Vault/ManageJournals/Services/AddContactToPost.php @@ -0,0 +1,96 @@ + 'required|integer|exists:accounts,id', + 'vault_id' => 'required|integer|exists:vaults,id', + 'author_id' => 'required|integer|exists:users,id', + 'journal_id' => 'required|integer|exists:journals,id', + 'post_id' => 'required|integer|exists:posts,id', + 'contact_id' => 'required|integer|exists:contacts,id', + ]; + } + + /** + * Get the permissions that apply to the user calling the service. + * + * @return array + */ + public function permissions(): array + { + return [ + 'author_must_belong_to_account', + 'vault_must_belong_to_account', + 'author_must_be_vault_editor', + 'contact_must_belong_to_vault', + ]; + } + + /** + * Add a contact to a post. + * + * @param array $data + * @return Post + */ + public function execute(array $data): Post + { + $this->data = $data; + $this->validate(); + + $this->post->contacts()->syncWithoutDetaching($this->contact); + + $this->createFeedItem(); + $this->updateLastEditedDate(); + + return $this->post; + } + + private function validate(): void + { + $this->validateRules($this->data); + + $journal = $this->vault->journals() + ->findOrFail($this->data['journal_id']); + + $this->post = $journal->posts() + ->findOrFail($this->data['post_id']); + } + + private function updateLastEditedDate(): void + { + $this->contact->last_updated_at = Carbon::now(); + $this->contact->save(); + } + + private function createFeedItem(): void + { + $feedItem = ContactFeedItem::create([ + 'author_id' => $this->author->id, + 'contact_id' => $this->contact->id, + 'action' => ContactFeedItem::ACTION_ADDED_TO_POST, + 'description' => $this->post->title, + ]); + $this->post->feedItem()->save($feedItem); + } +} diff --git a/app/Domains/Vault/ManageJournals/Services/RemoveContactFromPost.php b/app/Domains/Vault/ManageJournals/Services/RemoveContactFromPost.php new file mode 100644 index 000000000..a87df6a54 --- /dev/null +++ b/app/Domains/Vault/ManageJournals/Services/RemoveContactFromPost.php @@ -0,0 +1,98 @@ + 'required|integer|exists:accounts,id', + 'vault_id' => 'required|integer|exists:vaults,id', + 'author_id' => 'required|integer|exists:users,id', + 'journal_id' => 'required|integer|exists:journals,id', + 'post_id' => 'required|integer|exists:posts,id', + 'contact_id' => 'required|integer|exists:contacts,id', + ]; + } + + /** + * Get the permissions that apply to the user calling the service. + * + * @return array + */ + public function permissions(): array + { + return [ + 'author_must_belong_to_account', + 'vault_must_belong_to_account', + 'author_must_be_vault_editor', + 'contact_must_belong_to_vault', + ]; + } + + /** + * Remove a contact from a post. + * + * @param array $data + * @return Post + */ + public function execute(array $data): Post + { + $this->data = $data; + $this->validate(); + + $this->post->contacts()->detach([ + $this->contact->id, + ]); + + $this->updateLastEditedDate(); + $this->createFeedItem(); + + return $this->post; + } + + private function validate(): void + { + $this->validateRules($this->data); + + $journal = $this->vault->journals() + ->findOrFail($this->data['journal_id']); + + $this->post = $journal->posts() + ->findOrFail($this->data['post_id']); + } + + private function updateLastEditedDate(): void + { + $this->contact->last_updated_at = Carbon::now(); + $this->contact->save(); + } + + private function createFeedItem(): void + { + $feedItem = ContactFeedItem::create([ + 'author_id' => $this->author->id, + 'contact_id' => $this->contact->id, + 'action' => ContactFeedItem::ACTION_REMOVED_FROM_POST, + 'description' => $this->post->title, + ]); + $this->post->feedItem()->save($feedItem); + } +} diff --git a/app/Domains/Vault/ManageJournals/Web/Controllers/PostController.php b/app/Domains/Vault/ManageJournals/Web/Controllers/PostController.php index e1e386085..46436f11d 100644 --- a/app/Domains/Vault/ManageJournals/Web/Controllers/PostController.php +++ b/app/Domains/Vault/ManageJournals/Web/Controllers/PostController.php @@ -2,6 +2,7 @@ namespace App\Domains\Vault\ManageJournals\Web\Controllers; +use App\Domains\Vault\ManageJournals\Services\AddContactToPost; use App\Domains\Vault\ManageJournals\Services\CreatePost; use App\Domains\Vault\ManageJournals\Services\DestroyPost; use App\Domains\Vault\ManageJournals\Services\IncrementPostReadCounter; @@ -125,6 +126,25 @@ class PostController extends Controller 'written_at' => Carbon::now()->format('Y-m-d'), ]); + $post->contacts()->detach(); + + if ($request->input('contacts')) { + if (count($request->input('contacts')) > 0) { + foreach ($request->input('contacts') as $contact) { + $data = [ + 'account_id' => Auth::user()->account_id, + 'author_id' => Auth::user()->id, + 'vault_id' => $vaultId, + 'journal_id' => $journalId, + 'post_id' => $postId, + 'contact_id' => $contact['id'], + ]; + + (new AddContactToPost())->execute($data); + } + } + } + return response()->json([ 'data' => PostHelper::statistics($post), ], 200); diff --git a/app/Domains/Vault/ManageJournals/Web/ViewHelpers/ModuleContactPostViewHelper.php b/app/Domains/Vault/ManageJournals/Web/ViewHelpers/ModuleContactPostViewHelper.php new file mode 100644 index 000000000..1c7e34b1c --- /dev/null +++ b/app/Domains/Vault/ManageJournals/Web/ViewHelpers/ModuleContactPostViewHelper.php @@ -0,0 +1,29 @@ +posts() + ->orderBy('written_at', 'desc') + ->get() + ->map(fn (Post $post) => [ + 'id' => $post->id, + 'title' => $post->title, + 'excerpt' => $post->excerpt, + 'url' => [ + 'show' => route('post.show', [ + 'vault' => $contact->vault_id, + 'journal' => $post->journal_id, + 'post' => $post->id, + ]), + ], + ]); + } +} diff --git a/app/Domains/Vault/ManageJournals/Web/ViewHelpers/ModulePostsViewHelper.php b/app/Domains/Vault/ManageJournals/Web/ViewHelpers/ModulePostsViewHelper.php new file mode 100644 index 000000000..fff308c3f --- /dev/null +++ b/app/Domains/Vault/ManageJournals/Web/ViewHelpers/ModulePostsViewHelper.php @@ -0,0 +1,46 @@ +posts() + ->orderBy('created_at', 'desc') + ->get() + ->map(fn (Post $post) => self::dto($post, $user)); + } + + public static function dto(Post $post, User $user): array + { + return [ + 'id' => $post->id, + 'title' => $post->title, + 'journal' => [ + 'id' => $post->journal->id, + 'name' => $post->journal->name, + 'url' => [ + 'show' => route('journal.show', [ + 'vault' => $post->journal->vault->id, + 'journal' => $post->journal->id, + ]), + ], + ], + 'written_at' => DateHelper::formatDate($post->written_at, $user->timezone), + 'url' => [ + 'show' => route('post.show', [ + 'vault' => $post->journal->vault_id, + 'journal' => $post->journal->id, + 'post' => $post->id, + ]), + ], + ]; + } +} diff --git a/app/Domains/Vault/ManageJournals/Web/ViewHelpers/PostEditViewHelper.php b/app/Domains/Vault/ManageJournals/Web/ViewHelpers/PostEditViewHelper.php index d5a3c9a40..5bc8aabcc 100644 --- a/app/Domains/Vault/ManageJournals/Web/ViewHelpers/PostEditViewHelper.php +++ b/app/Domains/Vault/ManageJournals/Web/ViewHelpers/PostEditViewHelper.php @@ -3,6 +3,7 @@ namespace App\Domains\Vault\ManageJournals\Web\ViewHelpers; use App\Helpers\PostHelper; +use App\Models\Contact; use App\Models\Journal; use App\Models\Post; use App\Models\PostSection; @@ -37,10 +38,15 @@ class PostEditViewHelper return self::dtoTag($journal, $post, $tag); }); + $contacts = $post->contacts() + ->get() + ->map(fn (Contact $contact) => self::dtoContact($contact)); + return [ 'id' => $post->id, 'title' => $post->title, 'sections' => $sectionsCollection, + 'contacts' => $contacts, 'statistics' => PostHelper::statistics($post), 'tags_in_post' => $tagsAssociatedWithPostCollection, 'tags_in_vault' => $tagsInVaultCollection, @@ -98,4 +104,19 @@ class PostEditViewHelper ], ]; } + + public static function dtoContact(Contact $contact): array + { + return [ + 'id' => $contact->id, + 'name' => $contact->name, + 'avatar' => $contact->avatar, + 'url' => [ + 'show' => route('contact.show', [ + 'vault' => $contact->vault_id, + 'contact' => $contact->id, + ]), + ], + ]; + } } diff --git a/app/Domains/Vault/ManageJournals/Web/ViewHelpers/PostShowViewHelper.php b/app/Domains/Vault/ManageJournals/Web/ViewHelpers/PostShowViewHelper.php index 99ac2d212..7f63f2edb 100644 --- a/app/Domains/Vault/ManageJournals/Web/ViewHelpers/PostShowViewHelper.php +++ b/app/Domains/Vault/ManageJournals/Web/ViewHelpers/PostShowViewHelper.php @@ -2,7 +2,9 @@ namespace App\Domains\Vault\ManageJournals\Web\ViewHelpers; +use App\Helpers\ContactCardHelper; use App\Helpers\DateHelper; +use App\Models\Contact; use App\Models\Post; use App\Models\PostSection; use App\Models\Tag; @@ -30,6 +32,10 @@ class PostShowViewHelper 'name' => $tag->name, ]); + $contacts = $post->contacts() + ->get() + ->map(fn (Contact $contact) => ContactCardHelper::data($contact, $user)); + return [ 'id' => $post->id, 'title' => $post->title, @@ -38,6 +44,7 @@ class PostShowViewHelper 'published' => $post->published, 'sections' => $sections, 'tags' => $tags, + 'contacts' => $contacts, 'journal' => [ 'name' => $post->journal->name, 'url' => [ diff --git a/app/Models/Contact.php b/app/Models/Contact.php index 3738c8687..d2db5829f 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -362,6 +362,16 @@ class Contact extends Model return $this->belongsToMany(Group::class, 'contact_group'); } + /** + * Get the posts associated with the contact. + * + * @return BelongsToMany + */ + public function posts(): BelongsToMany + { + return $this->belongsToMany(Post::class, 'contact_post'); + } + /** * Get the religion associated with the contact. * diff --git a/app/Models/ContactFeedItem.php b/app/Models/ContactFeedItem.php index 0d9f64f64..9b8c5b829 100644 --- a/app/Models/ContactFeedItem.php +++ b/app/Models/ContactFeedItem.php @@ -84,6 +84,10 @@ class ContactFeedItem extends Model public const ACTION_REMOVED_FROM_GROUP = 'removed_from_group'; + public const ACTION_ADDED_TO_POST = 'added_to_post'; + + public const ACTION_REMOVED_FROM_POST = 'removed_from_post'; + public const ACTION_ARCHIVED_CONTACT = 'archived'; public const ACTION_UNARCHIVED_CONTACT = 'unarchived'; diff --git a/app/Models/Module.php b/app/Models/Module.php index 4ae23598e..5997a0106 100644 --- a/app/Models/Module.php +++ b/app/Models/Module.php @@ -57,6 +57,8 @@ class Module extends Model public const TYPE_PHOTOS = 'photos'; + public const TYPE_POSTS = 'posts'; + public const TYPE_RELIGIONS = 'religions'; /** diff --git a/app/Models/Post.php b/app/Models/Post.php index 8dd200ef2..0984d81f4 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\MorphOne; use Illuminate\Support\Str; class Post extends Model @@ -69,6 +70,26 @@ class Post extends Model return $this->hasMany(PostSection::class); } + /** + * Get the contacts associated with the post. + * + * @return BelongsToMany + */ + public function contacts(): BelongsToMany + { + return $this->belongsToMany(Contact::class); + } + + /** + * Get the post's feed item. + * + * @return MorphOne + */ + public function feedItem(): MorphOne + { + return $this->morphOne(ContactFeedItem::class, 'feedable'); + } + /** * Get the tags associated with the post. * @@ -106,7 +127,7 @@ class Post extends Model protected function excerpt(): Attribute { return Attribute::make( - get: fn () => Str::limit(optional($this->postSections()->first())->content, 200) + get: fn () => Str::limit(optional($this->postSections()->whereNotNull('content')->first())->content, 200) ); } } diff --git a/database/migrations/2022_09_22_111510_create_posts_table.php b/database/migrations/2022_09_22_111510_create_posts_table.php index 5940a93ed..188a6cfc1 100644 --- a/database/migrations/2022_09_22_111510_create_posts_table.php +++ b/database/migrations/2022_09_22_111510_create_posts_table.php @@ -53,6 +53,14 @@ return new class extends Migration $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade'); }); + Schema::create('contact_post', function (Blueprint $table) { + $table->unsignedBigInteger('post_id'); + $table->unsignedBigInteger('contact_id'); + $table->timestamps(); + $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade'); + $table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + }); + Schema::create('tags', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('vault_id'); @@ -81,6 +89,9 @@ return new class extends Migration Schema::dropIfExists('post_templates'); Schema::dropIfExists('post_template_sections'); Schema::dropIfExists('posts'); - Schema::dropIfExists('journal_tags'); + Schema::dropIfExists('post_sections'); + Schema::dropIfExists('contact_post'); + Schema::dropIfExists('tags'); + Schema::dropIfExists('post_tag'); } }; diff --git a/lang/en/app.php b/lang/en/app.php index f9888a52c..15138b9af 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -115,6 +115,7 @@ return [ 'module_contact_information' => 'Contact information', 'module_documents' => 'Documents', 'module_photos' => 'Photos', + 'module_posts' => 'Posts about the contact', 'module_religions' => 'Religions', 'module_option_default_number_of_items_to_display' => 'Default number of items to display', diff --git a/lang/en/contact.php b/lang/en/contact.php index fe4775503..bb5d8fc84 100644 --- a/lang/en/contact.php +++ b/lang/en/contact.php @@ -45,6 +45,8 @@ return [ 'feed_item_goal_destroyed' => 'deleted a goal', 'feed_item_added_to_group' => 'added the contact to a group', 'feed_item_removed_from_group' => 'removed the contact from a group', + 'feed_item_added_to_post' => 'added the contact to a post', + 'feed_item_removed_from_post' => 'removed the contact from a post', 'feed_item_archived' => 'archived the contact', 'feed_item_unarchived' => 'unarchived the contact', 'feed_item_favorited' => 'added the contact to the favorites', diff --git a/lang/en/vault.php b/lang/en/vault.php index a4a6a7170..c1b8325c5 100644 --- a/lang/en/vault.php +++ b/lang/en/vault.php @@ -114,6 +114,7 @@ return [ 'journal_show_cta' => 'Create a post', 'journal_show_years' => 'Years', 'journal_show_tags' => 'All tags', + 'journal_show_contacts' => 'Contacts in this post', 'journal_show_options' => 'Options', 'journal_show_blank' => 'The journal lets you document your life with your own words.', 'journal_post_edit_tags' => 'Tags', diff --git a/public/img/contact_blank_posts.svg b/public/img/contact_blank_posts.svg new file mode 100644 index 000000000..cf97323f0 --- /dev/null +++ b/public/img/contact_blank_posts.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/js/Pages/Vault/Contact/Relationships/Create.vue b/resources/js/Pages/Vault/Contact/Relationships/Create.vue index 3b201c03b..54f7e3028 100644 --- a/resources/js/Pages/Vault/Contact/Relationships/Create.vue +++ b/resources/js/Pages/Vault/Contact/Relationships/Create.vue @@ -222,7 +222,7 @@ :display-most-consulted-contacts="false" :add-multiple-contacts="false" :required="true" - :div-outer-class="'flex-1 border-r border-gray-200 dark:border-gray-700'" /> + :div-outer-class="'flex-1 border-gray-200 dark:border-gray-700'" /> diff --git a/resources/js/Pages/Vault/Contact/Show.vue b/resources/js/Pages/Vault/Contact/Show.vue index 990ca24d1..946acfaf4 100644 --- a/resources/js/Pages/Vault/Contact/Show.vue +++ b/resources/js/Pages/Vault/Contact/Show.vue @@ -31,6 +31,7 @@ import ContactInformation from '@/Shared/Modules/ContactInformation.vue'; import Documents from '@/Shared/Modules/Documents.vue'; import Photos from '@/Shared/Modules/Photos.vue'; import Religion from '@/Shared/Modules/Religion.vue'; +import Posts from '@/Shared/Modules/Posts.vue'; import Uploadcare from '@/Components/Uploadcare.vue'; const props = defineProps({ @@ -324,6 +325,8 @@ const destroyAvatar = () => { + + diff --git a/resources/js/Pages/Vault/Journal/Post/Edit.vue b/resources/js/Pages/Vault/Journal/Post/Edit.vue index 2709fc4e4..deea8ff7b 100644 --- a/resources/js/Pages/Vault/Journal/Post/Edit.vue +++ b/resources/js/Pages/Vault/Journal/Post/Edit.vue @@ -7,6 +7,7 @@ import Tags from '@/Pages/Vault/Journal/Post/Partials/Tags.vue'; import { useForm } from '@inertiajs/inertia-vue3'; import { onMounted, watch, ref } from 'vue'; import { debounce } from 'lodash'; +import ContactSelector from '@/Shared/Form/ContactSelector.vue'; const props = defineProps({ layoutData: Object, @@ -16,6 +17,7 @@ const props = defineProps({ const form = useForm({ title: '', sections: [], + contacts: [], }); const saveInProgress = ref(false); @@ -24,6 +26,7 @@ const statistics = ref([]); onMounted(() => { form.title = props.data.title; statistics.value = props.data.statistics; + form.contacts = props.data.contacts; props.data.sections.forEach((section) => { form.sections.push({ @@ -48,6 +51,13 @@ watch( }, ); +watch( + () => _.cloneDeep(form.contacts), + () => { + debouncedWatch(form.contacts); + }, +); + const debouncedWatch = debounce(() => { update(); }, 500); @@ -207,6 +217,19 @@ const destroy = () => { + +

+ Contacts in this post +

+ + diff --git a/resources/js/Pages/Vault/Journal/Post/Partials/Tags.vue b/resources/js/Pages/Vault/Journal/Post/Partials/Tags.vue index 7203b859b..95b8a7bd8 100644 --- a/resources/js/Pages/Vault/Journal/Post/Partials/Tags.vue +++ b/resources/js/Pages/Vault/Journal/Post/Partials/Tags.vue @@ -3,19 +3,11 @@

{{ $t('vault.journal_post_edit_tags') }} - - - - + + {{ $t('app.edit') }} diff --git a/resources/js/Pages/Vault/Journal/Post/Show.vue b/resources/js/Pages/Vault/Journal/Post/Show.vue index b81beaa24..d004a4388 100644 --- a/resources/js/Pages/Vault/Journal/Post/Show.vue +++ b/resources/js/Pages/Vault/Journal/Post/Show.vue @@ -1,5 +1,6 @@ + + + + diff --git a/resources/js/Shared/Modules/Relationships.vue b/resources/js/Shared/Modules/Relationships.vue index 04fd0df4d..3f3dbed03 100644 --- a/resources/js/Shared/Modules/Relationships.vue +++ b/resources/js/Shared/Modules/Relationships.vue @@ -65,7 +65,7 @@

  • - Remove + {{ $t('app.remove') }}
diff --git a/routes/web.php b/routes/web.php index 4033ba197..4fc31049e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -291,7 +291,6 @@ Route::middleware([ Route::delete('calls/{call}', [ContactModuleCallController::class, 'destroy'])->name('contact.call.destroy'); // groups - Route::get('groups', [ContactModuleGroupController::class, 'index'])->name('contact.group.index'); Route::post('groups', [ContactModuleGroupController::class, 'store'])->name('contact.group.store'); Route::delete('groups/{group}', [ContactModuleGroupController::class, 'destroy'])->name('contact.group.destroy'); }); diff --git a/tests/Unit/Domains/Settings/CreateAccount/Services/SetupAccountTest.php b/tests/Unit/Domains/Settings/CreateAccount/Services/SetupAccountTest.php index 02e435e18..d8e399ed4 100644 --- a/tests/Unit/Domains/Settings/CreateAccount/Services/SetupAccountTest.php +++ b/tests/Unit/Domains/Settings/CreateAccount/Services/SetupAccountTest.php @@ -125,6 +125,10 @@ class SetupAccountTest extends TestCase 'account_id' => $user->account_id, 'name' => trans('app.module_groups'), ]); + $this->assertDatabaseHas('modules', [ + 'account_id' => $user->account_id, + 'name' => trans('app.module_posts'), + ]); $this->assertDatabaseHas('relationship_group_types', [ 'name' => trans('account.relationship_type_love'), diff --git a/tests/Unit/Domains/Vault/ManageJournals/Services/AddContactToPostTest.php b/tests/Unit/Domains/Vault/ManageJournals/Services/AddContactToPostTest.php new file mode 100644 index 000000000..b85fff6f3 --- /dev/null +++ b/tests/Unit/Domains/Vault/ManageJournals/Services/AddContactToPostTest.php @@ -0,0 +1,150 @@ +createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create([ + 'journal_id' => $journal->id, + ]); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_wrong_parameters_are_given(): void + { + $request = [ + 'title' => 'Ross', + ]; + + $this->expectException(ValidationException::class); + (new AddContactToPost())->execute($request); + } + + /** @test */ + public function it_fails_if_user_doesnt_belong_to_account(): void + { + $this->expectException(ModelNotFoundException::class); + + $regis = $this->createUser(); + $account = Account::factory()->create(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create([ + 'journal_id' => $journal->id, + ]); + + $this->executeService($regis, $account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_journal_doesnt_belong_to_vault(): void + { + $this->expectException(ModelNotFoundException::class); + + $regis = $this->createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(); + $post = Post::factory()->create([ + 'journal_id' => $journal->id, + ]); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_contact_doesnt_belong_to_vault(): void + { + $this->expectException(ModelNotFoundException::class); + + $regis = $this->createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create([ + 'journal_id' => $journal->id, + ]); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_post_doesnt_belong_to_journal(): void + { + $this->expectException(ModelNotFoundException::class); + + $regis = $this->createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create(); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_user_doesnt_have_right_permission_in_vault(): void + { + $this->expectException(NotEnoughPermissionException::class); + + $regis = $this->createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_VIEW, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create([ + 'journal_id' => $journal->id, + ]); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + private function executeService(User $author, Account $account, Vault $vault, Contact $contact, Journal $journal, Post $post): void + { + $request = [ + 'account_id' => $account->id, + 'author_id' => $author->id, + 'vault_id' => $vault->id, + 'journal_id' => $journal->id, + 'post_id' => $post->id, + 'contact_id' => $contact->id, + ]; + + (new AddContactToPost())->execute($request); + + $this->assertDatabaseHas('contact_post', [ + 'contact_id' => $contact->id, + 'post_id' => $post->id, + ]); + } +} diff --git a/tests/Unit/Domains/Vault/ManageJournals/Services/RemoveContactFromPostTest.php b/tests/Unit/Domains/Vault/ManageJournals/Services/RemoveContactFromPostTest.php new file mode 100644 index 000000000..80980871f --- /dev/null +++ b/tests/Unit/Domains/Vault/ManageJournals/Services/RemoveContactFromPostTest.php @@ -0,0 +1,146 @@ +createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create(['journal_id' => $journal->id]); + $post->contacts()->attach($contact->id); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_wrong_parameters_are_given(): void + { + $request = [ + 'title' => 'Ross', + ]; + + $this->expectException(ValidationException::class); + (new RemoveContactFromPost())->execute($request); + } + + /** @test */ + public function it_fails_if_user_doesnt_belong_to_account(): void + { + $this->expectException(ModelNotFoundException::class); + + $regis = $this->createUser(); + $account = Account::factory()->create(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create(['journal_id' => $journal->id]); + $post->contacts()->attach($contact->id); + + $this->executeService($regis, $account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_post_doesnt_belong_to_journal(): void + { + $this->expectException(ModelNotFoundException::class); + + $regis = $this->createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create(); + $post->contacts()->attach($contact->id); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_journal_doesnt_belong_to_vault(): void + { + $this->expectException(ModelNotFoundException::class); + + $regis = $this->createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(); + $post = Post::factory()->create(['journal_id' => $journal->id]); + $post->contacts()->attach($contact->id); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_contact_doesnt_belong_to_vault(): void + { + $this->expectException(ModelNotFoundException::class); + + $regis = $this->createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault); + $contact = Contact::factory()->create(); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create(['journal_id' => $journal->id]); + $post->contacts()->attach($contact->id); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + /** @test */ + public function it_fails_if_user_doesnt_have_right_permission_in_vault(): void + { + $this->expectException(NotEnoughPermissionException::class); + + $regis = $this->createUser(); + $vault = $this->createVault($regis->account); + $vault = $this->setPermissionInVault($regis, Vault::PERMISSION_VIEW, $vault); + $contact = Contact::factory()->create(['vault_id' => $vault->id]); + $journal = Journal::factory()->create(['vault_id' => $vault->id]); + $post = Post::factory()->create(['journal_id' => $journal->id]); + $post->contacts()->attach($contact->id); + + $this->executeService($regis, $regis->account, $vault, $contact, $journal, $post); + } + + private function executeService(User $author, Account $account, Vault $vault, Contact $contact, Journal $journal, Post $post): void + { + $request = [ + 'account_id' => $account->id, + 'author_id' => $author->id, + 'vault_id' => $vault->id, + 'journal_id' => $journal->id, + 'post_id' => $post->id, + 'contact_id' => $contact->id, + ]; + + (new RemoveContactFromPost())->execute($request); + + $this->assertDatabaseMissing('contact_post', [ + 'contact_id' => $contact->id, + 'post_id' => $post->id, + ]); + } +} diff --git a/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/ModulePostsViewHelperTest.php b/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/ModulePostsViewHelperTest.php new file mode 100644 index 000000000..71de1b6f8 --- /dev/null +++ b/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/ModulePostsViewHelperTest.php @@ -0,0 +1,65 @@ +create(); + $vault = Vault::factory()->create(); + $contact = Contact::factory()->create([ + 'vault_id' => $vault->id, + ]); + $journal = Journal::factory()->create([ + 'vault_id' => $vault->id, + 'name' => 'this is a title', + ]); + $post = Post::factory()->create([ + 'journal_id' => $journal->id, + 'title' => 'this is a title', + 'written_at' => '2022-01-01 00:00:00', + ]); + $post->contacts()->attach($contact->id); + + $collection = ModulePostsViewHelper::data($contact, $user); + + $this->assertEquals( + 1, + count($collection) + ); + + $this->assertEquals( + [ + 0 => [ + 'id' => $post->id, + 'title' => 'this is a title', + 'journal' => [ + 'id' => $post->journal->id, + 'name' => 'this is a title', + 'url' => [ + 'show' => env('APP_URL').'/vaults/'.$vault->id.'/journals/'.$journal->id, + ], + ], + 'written_at' => 'Jan 01, 2022', + 'url' => [ + 'show' => env('APP_URL').'/vaults/'.$vault->id.'/journals/'.$journal->id.'/posts/'.$post->id, + ], + ], + ], + $collection->toArray() + ); + } +} diff --git a/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/PostEditViewHelperTest.php b/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/PostEditViewHelperTest.php index 39243a2d2..81949ee69 100644 --- a/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/PostEditViewHelperTest.php +++ b/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/PostEditViewHelperTest.php @@ -3,6 +3,7 @@ namespace Tests\Unit\Domains\Vault\ManageJournals\Web\ViewHelpers; use App\Domains\Vault\ManageJournals\Web\ViewHelpers\PostEditViewHelper; +use App\Models\Contact; use App\Models\Journal; use App\Models\Post; use App\Models\PostSection; @@ -28,10 +29,14 @@ class PostEditViewHelperTest extends TestCase PostSection::factory()->create([ 'post_id' => $post->id, ]); + $contact = Contact::factory()->create([ + 'vault_id' => $vault->id, + ]); + $post->contacts()->attach($contact); $array = PostEditViewHelper::data($journal, $post); - $this->assertCount(8, $array); + $this->assertCount(9, $array); $this->assertEquals( $post->id, $array['id'] @@ -46,6 +51,19 @@ class PostEditViewHelperTest extends TestCase ], $array['journal'] ); + $this->assertEquals( + [ + 0 => [ + 'id' => $contact->id, + 'name' => $contact->name, + 'avatar' => $contact->avatar, + 'url' => [ + 'show' => env('APP_URL').'/vaults/'.$vault->id.'/contacts/'.$contact->id, + ], + ], + ], + $array['contacts']->toArray() + ); $this->assertEquals( [ 'update' => env('APP_URL').'/vaults/'.$vault->id.'/journals/'.$journal->id.'/posts/'.$post->id.'/update', diff --git a/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/PostShowViewHelperTest.php b/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/PostShowViewHelperTest.php index d51894f2e..c28816eaa 100644 --- a/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/PostShowViewHelperTest.php +++ b/tests/Unit/Domains/Vault/ManageJournals/Web/ViewHelpers/PostShowViewHelperTest.php @@ -42,7 +42,7 @@ class PostShowViewHelperTest extends TestCase $array = PostShowViewHelper::data($post, $user); - $this->assertCount(9, $array); + $this->assertCount(10, $array); $this->assertEquals( $post->id, $array['id'] diff --git a/tests/Unit/Models/ContactTest.php b/tests/Unit/Models/ContactTest.php index 04db7ebe2..fc3a8f463 100644 --- a/tests/Unit/Models/ContactTest.php +++ b/tests/Unit/Models/ContactTest.php @@ -19,6 +19,7 @@ use App\Models\Label; use App\Models\Loan; use App\Models\Note; use App\Models\Pet; +use App\Models\Post; use App\Models\Pronoun; use App\Models\RelationshipType; use App\Models\Religion; @@ -260,6 +261,16 @@ class ContactTest extends TestCase $this->assertTrue($contact->groups()->exists()); } + /** @test */ + public function it_has_many_posts(): void + { + $contact = Contact::factory()->create(); + $post = Post::factory()->create(); + $contact->posts()->sync([$post->id]); + + $this->assertTrue($contact->posts()->exists()); + } + /** @test */ public function it_has_one_religion(): void { diff --git a/tests/Unit/Models/PostTest.php b/tests/Unit/Models/PostTest.php index ae7e5fdae..3f70b50c0 100644 --- a/tests/Unit/Models/PostTest.php +++ b/tests/Unit/Models/PostTest.php @@ -2,6 +2,7 @@ namespace Tests\Unit\Models; +use App\Models\Contact; use App\Models\Post; use App\Models\PostSection; use App\Models\Tag; @@ -31,6 +32,17 @@ class PostTest extends TestCase $this->assertTrue($post->postSections()->exists()); } + /** @test */ + public function it_has_many_contacts(): void + { + $ross = Contact::factory()->create([]); + $post = Post::factory()->create(); + + $post->contacts()->sync([$ross->id]); + + $this->assertTrue($post->contacts()->exists()); + } + /** @test */ public function it_has_many_tags(): void { @@ -63,4 +75,31 @@ class PostTest extends TestCase $post->title ); } + + /** @test */ + public function it_gets_the_excerpt(): void + { + $post = Post::factory()->create([ + 'title' => null, + ]); + + $this->assertNull( + $post->excerpt + ); + + PostSection::factory()->create([ + 'post_id' => $post->id, + 'content' => null, + ]); + + PostSection::factory()->create([ + 'post_id' => $post->id, + 'content' => 'this is incredible', + ]); + + $this->assertEquals( + 'this is incredible', + $post->excerpt + ); + } }