Compare commits
9 Commits
v1.0.0-alp
...
v1.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35571760d6 | ||
|
|
a4d4418963 | ||
|
|
b2ee8a1036 | ||
|
|
fd5bc5271b | ||
|
|
43b66f60f3 | ||
|
|
0c13d589d8 | ||
|
|
2c7c44ecbc | ||
|
|
12470a1d8b | ||
|
|
42e95a83f5 |
1
.github/workflows/pint.yml
vendored
1
.github/workflows/pint.yml
vendored
@@ -2,6 +2,7 @@ name: Pint
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches: [1.x]
|
||||||
paths:
|
paths:
|
||||||
- '**.php'
|
- '**.php'
|
||||||
|
|
||||||
|
|||||||
24
README.md
24
README.md
@@ -61,12 +61,12 @@ class Project extends Model implements Commentable
|
|||||||
Add the commenter trait to your User model:
|
Add the commenter trait to your User model:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use Relaticle\Comments\Concerns\IsCommenter;
|
use Relaticle\Comments\Concerns\CanComment;
|
||||||
use Relaticle\Comments\Contracts\Commenter;
|
use Relaticle\Comments\Contracts\Commentator;
|
||||||
|
|
||||||
class User extends Authenticatable implements Commenter
|
class User extends Authenticatable implements Commentator
|
||||||
{
|
{
|
||||||
use IsCommenter;
|
use CanComment;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -134,20 +134,20 @@ public static function infolist(Infolist $infolist): Infolist
|
|||||||
<tr>
|
<tr>
|
||||||
<td width="50%" valign="top">
|
<td width="50%" valign="top">
|
||||||
|
|
||||||
### Custom Fields
|
### FilaForms
|
||||||
[<img src="https://github.com/Relaticle/custom-fields/raw/2.x/art/preview.png" width="100%" />](https://relaticle.github.io/custom-fields)
|
[<img src="https://filaforms.app/img/og-image.png" width="100%" />](https://filaforms.app/)
|
||||||
|
|
||||||
Let users add custom fields to any model without code changes.
|
Visual form builder for all your public-facing forms.
|
||||||
[Learn more ->](https://relaticle.github.io/custom-fields)
|
[Learn more ->](https://filaforms.app)
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td width="50%" valign="top">
|
<td width="50%" valign="top">
|
||||||
|
|
||||||
### Flowforge
|
### Custom Fields
|
||||||
[<img src="https://github.com/Relaticle/flowforge/raw/4.x/art/preview.png" width="100%" />](https://relaticle.github.io/flowforge)
|
[<img src="https://github.com/Relaticle/custom-fields/raw/3.x/art/preview.png" width="100%" />](https://relaticle.github.io/custom-fields)
|
||||||
|
|
||||||
Transform any Laravel model into a drag-and-drop Kanban board.
|
Let users add custom fields to any model without code changes.
|
||||||
[Learn more ->](https://relaticle.github.io/flowforge)
|
[Learn more ->](https://relaticle.github.io/custom-fields)
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,19 +1,29 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Mentions\DefaultMentionResolver;
|
use Relaticle\Comments\Mentions\DefaultMentionResolver;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Policies\CommentPolicy;
|
use Relaticle\Comments\Policies\CommentPolicy;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'tables' => [
|
|
||||||
'comments' => 'comments',
|
|
||||||
],
|
|
||||||
|
|
||||||
'models' => [
|
'models' => [
|
||||||
'comment' => Comment::class,
|
'comment' => Comment::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'table_names' => [
|
||||||
|
'comments' => 'comments',
|
||||||
|
'reactions' => 'comment_reactions',
|
||||||
|
'mentions' => 'comment_mentions',
|
||||||
|
'subscriptions' => 'comment_subscriptions',
|
||||||
|
'attachments' => 'comment_attachments',
|
||||||
|
],
|
||||||
|
|
||||||
|
'column_names' => [
|
||||||
|
'commenter_morph' => 'commenter',
|
||||||
|
],
|
||||||
|
|
||||||
'commenter' => [
|
'commenter' => [
|
||||||
'model' => User::class,
|
'model' => User::class,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace Relaticle\Comments\Database\Factories;
|
namespace Relaticle\Comments\Database\Factories;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentFactory extends Factory
|
class CommentFactory extends Factory
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ return new class extends Migration
|
|||||||
{
|
{
|
||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
Schema::create('comment_attachments', function (Blueprint $table) {
|
Schema::create(config('comments.table_names.attachments', 'comment_attachments'), function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('comment_id')
|
$table->foreignId('comment_id')
|
||||||
->constrained(config('comments.tables.comments', 'comments'))
|
->constrained(config('comments.table_names.comments', 'comments'))
|
||||||
->cascadeOnDelete();
|
->cascadeOnDelete();
|
||||||
$table->string('file_path');
|
$table->string('file_path');
|
||||||
$table->string('original_name');
|
$table->string('original_name');
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ return new class extends Migration
|
|||||||
{
|
{
|
||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
Schema::create('comment_mentions', function (Blueprint $table) {
|
Schema::create(config('comments.table_names.mentions', 'comment_mentions'), function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('comment_id')
|
$table->foreignId('comment_id')
|
||||||
->constrained(config('comments.tables.comments', 'comments'))
|
->constrained(config('comments.table_names.comments', 'comments'))
|
||||||
->cascadeOnDelete();
|
->cascadeOnDelete();
|
||||||
$table->morphs('user');
|
$table->morphs('commenter');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
$table->unique(['comment_id', 'user_id', 'user_type']);
|
$table->unique(['comment_id', 'commenter_id', 'commenter_type']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ return new class extends Migration
|
|||||||
{
|
{
|
||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
Schema::create('comment_reactions', function (Blueprint $table) {
|
Schema::create(config('comments.table_names.reactions', 'comment_reactions'), function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('comment_id')
|
$table->foreignId('comment_id')
|
||||||
->constrained(config('comments.tables.comments', 'comments'))
|
->constrained(config('comments.table_names.comments', 'comments'))
|
||||||
->cascadeOnDelete();
|
->cascadeOnDelete();
|
||||||
$table->morphs('user');
|
$table->morphs('commenter');
|
||||||
$table->string('reaction');
|
$table->string('reaction');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
$table->unique(['comment_id', 'user_id', 'user_type', 'reaction']);
|
$table->unique(['comment_id', 'commenter_id', 'commenter_type', 'reaction']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ return new class extends Migration
|
|||||||
{
|
{
|
||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
Schema::create('comment_subscriptions', function (Blueprint $table) {
|
Schema::create(config('comments.table_names.subscriptions', 'comment_subscriptions'), function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->morphs('commentable');
|
$table->morphs('commentable');
|
||||||
$table->morphs('user');
|
$table->morphs('commenter');
|
||||||
$table->timestamp('created_at')->nullable();
|
$table->timestamp('created_at')->nullable();
|
||||||
|
|
||||||
$table->unique(['commentable_type', 'commentable_id', 'user_type', 'user_id'], 'comment_subscriptions_unique');
|
$table->unique(['commentable_type', 'commentable_id', 'commenter_type', 'commenter_id'], 'comment_subscriptions_unique');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ return new class extends Migration
|
|||||||
{
|
{
|
||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
Schema::create(config('comments.tables.comments', 'comments'), function (Blueprint $table) {
|
Schema::create(config('comments.table_names.comments', 'comments'), function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->morphs('commentable');
|
$table->morphs('commentable');
|
||||||
$table->morphs('user');
|
$table->morphs('commenter');
|
||||||
$table->foreignId('parent_id')
|
$table->foreignId('parent_id')
|
||||||
->nullable()
|
->nullable()
|
||||||
->constrained(config('comments.tables.comments', 'comments'))
|
->constrained(config('comments.table_names.comments', 'comments'))
|
||||||
->cascadeOnDelete();
|
->cascadeOnDelete();
|
||||||
$table->text('body');
|
$table->text('body');
|
||||||
$table->timestamp('edited_at')->nullable();
|
$table->timestamp('edited_at')->nullable();
|
||||||
|
|||||||
BIN
docs/.data/content/contents.sqlite
Normal file
BIN
docs/.data/content/contents.sqlite
Normal file
Binary file not shown.
103
docs/components/AppHeader.vue
Normal file
103
docs/components/AppHeader.vue
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useDocusI18n } from '#imports'
|
||||||
|
|
||||||
|
const appConfig = useAppConfig()
|
||||||
|
const site = useSiteConfig()
|
||||||
|
|
||||||
|
const { localePath, isEnabled, locales } = useDocusI18n()
|
||||||
|
const { currentVersion, isOldVersion, loadVersions } = useVersions()
|
||||||
|
|
||||||
|
onMounted(() => loadVersions())
|
||||||
|
|
||||||
|
const links = computed(() => appConfig.github && appConfig.github.url
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
'icon': 'i-simple-icons-github',
|
||||||
|
'to': appConfig.github.url,
|
||||||
|
'target': '_blank',
|
||||||
|
'aria-label': 'GitHub',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sticky top-0 z-50">
|
||||||
|
<!-- Version Warning Banner -->
|
||||||
|
<div
|
||||||
|
v-if="isOldVersion"
|
||||||
|
class="bg-amber-100 dark:bg-amber-900/50 text-amber-800 dark:text-amber-200 px-4 py-2 text-center text-sm border-b border-amber-200 dark:border-amber-800"
|
||||||
|
>
|
||||||
|
You are viewing documentation for Comments {{ currentVersion }}.
|
||||||
|
<a
|
||||||
|
href="/comments/"
|
||||||
|
class="underline font-medium hover:text-amber-900 dark:hover:text-amber-100"
|
||||||
|
>
|
||||||
|
View the latest version →
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Original Docus Header -->
|
||||||
|
<UHeader
|
||||||
|
:ui="{ center: 'flex-1' }"
|
||||||
|
:to="localePath('/')"
|
||||||
|
:title="appConfig.header?.title || site.name"
|
||||||
|
>
|
||||||
|
<AppHeaderCenter />
|
||||||
|
|
||||||
|
<template #title>
|
||||||
|
<AppHeaderLogo class="h-6 w-auto shrink-0" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #right>
|
||||||
|
<AppVersionSwitcher />
|
||||||
|
<AppHeaderCTA />
|
||||||
|
|
||||||
|
<template v-if="isEnabled && locales.length > 1">
|
||||||
|
<ClientOnly>
|
||||||
|
<LanguageSelect />
|
||||||
|
|
||||||
|
<template #fallback>
|
||||||
|
<div class="h-8 w-8 animate-pulse bg-neutral-200 dark:bg-neutral-800 rounded-md" />
|
||||||
|
</template>
|
||||||
|
</ClientOnly>
|
||||||
|
|
||||||
|
<USeparator
|
||||||
|
orientation="vertical"
|
||||||
|
class="h-8"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<UContentSearchButton class="lg:hidden" />
|
||||||
|
|
||||||
|
<ClientOnly>
|
||||||
|
<UColorModeButton />
|
||||||
|
|
||||||
|
<template #fallback>
|
||||||
|
<div class="h-8 w-8 animate-pulse bg-neutral-200 dark:bg-neutral-800 rounded-md" />
|
||||||
|
</template>
|
||||||
|
</ClientOnly>
|
||||||
|
|
||||||
|
<template v-if="links?.length">
|
||||||
|
<UButton
|
||||||
|
v-for="(link, index) of links"
|
||||||
|
:key="index"
|
||||||
|
v-bind="{ color: 'neutral', variant: 'ghost', ...link }"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #toggle="{ open, toggle }">
|
||||||
|
<IconMenuToggle
|
||||||
|
:open="open"
|
||||||
|
class="lg:hidden"
|
||||||
|
@click="toggle"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body>
|
||||||
|
<AppHeaderBody />
|
||||||
|
</template>
|
||||||
|
</UHeader>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
16
docs/components/AppHeaderLogo.vue
Normal file
16
docs/components/AppHeaderLogo.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const appConfig = useAppConfig()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UColorModeImage
|
||||||
|
v-if="appConfig.docus?.header?.logo?.dark || appConfig.docus?.header?.logo?.light"
|
||||||
|
:light="appConfig.docus?.header?.logo?.light || appConfig.docus?.header?.logo?.dark"
|
||||||
|
:dark="appConfig.docus?.header?.logo?.dark || appConfig.docus?.header?.logo?.light"
|
||||||
|
:alt="appConfig.docus?.header?.logo?.alt || appConfig.docus?.title"
|
||||||
|
class="h-8 w-auto shrink-0"
|
||||||
|
/>
|
||||||
|
<span v-else class="text-lg font-semibold">
|
||||||
|
{{ appConfig.docus?.title || 'Comments' }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
38
docs/components/AppVersionSwitcher.vue
Normal file
38
docs/components/AppVersionSwitcher.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { versions, currentVersion, currentTitle, loadVersions } = useVersions()
|
||||||
|
|
||||||
|
onMounted(() => loadVersions())
|
||||||
|
|
||||||
|
function switchVersion(version: { version: string; path: string }): void {
|
||||||
|
if (version.version !== currentVersion) {
|
||||||
|
window.location.href = version.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="versions.length > 1" class="relative" @click.stop>
|
||||||
|
<UPopover>
|
||||||
|
<UButton
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
:label="currentTitle"
|
||||||
|
trailing-icon="i-lucide-chevron-down"
|
||||||
|
/>
|
||||||
|
<template #content>
|
||||||
|
<div class="p-1">
|
||||||
|
<button
|
||||||
|
v-for="version in versions"
|
||||||
|
:key="version.version"
|
||||||
|
class="w-full px-3 py-2 text-left text-sm rounded hover:bg-gray-100 dark:hover:bg-gray-800 flex items-center gap-2"
|
||||||
|
:class="{ 'font-medium text-primary': version.version === currentVersion }"
|
||||||
|
@click="switchVersion(version)"
|
||||||
|
>
|
||||||
|
{{ version.title }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UPopover>
|
||||||
|
</div>
|
||||||
|
<UBadge v-else-if="currentVersion" variant="subtle" color="neutral">{{ currentVersion }}</UBadge>
|
||||||
|
</template>
|
||||||
60
docs/composables/useVersions.ts
Normal file
60
docs/composables/useVersions.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
interface Version {
|
||||||
|
version: string
|
||||||
|
title: string
|
||||||
|
path: string
|
||||||
|
branch: string
|
||||||
|
isLatest: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const versions = ref<Version[]>([])
|
||||||
|
const isLoaded = ref(false)
|
||||||
|
const isLoading = ref(false)
|
||||||
|
|
||||||
|
export function useVersions() {
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const currentVersion = config.public.docsVersion || '1.x'
|
||||||
|
|
||||||
|
async function loadVersions() {
|
||||||
|
if (isLoaded.value || isLoading.value) return
|
||||||
|
isLoading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/comments/versions.json')
|
||||||
|
if (res.ok) {
|
||||||
|
versions.value = await res.json()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to load versions.json:', e)
|
||||||
|
} finally {
|
||||||
|
isLoaded.value = true
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const latestVersion = computed(() =>
|
||||||
|
versions.value.find(v => v.isLatest)
|
||||||
|
)
|
||||||
|
|
||||||
|
const currentVersionInfo = computed(() =>
|
||||||
|
versions.value.find(v => v.version === currentVersion)
|
||||||
|
)
|
||||||
|
|
||||||
|
const isOldVersion = computed(() => {
|
||||||
|
if (!isLoaded.value) return false
|
||||||
|
return currentVersionInfo.value?.isLatest === false
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentTitle = computed(() =>
|
||||||
|
currentVersionInfo.value?.title || currentVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
versions,
|
||||||
|
currentVersion,
|
||||||
|
currentTitle,
|
||||||
|
latestVersion,
|
||||||
|
isOldVersion,
|
||||||
|
isLoaded,
|
||||||
|
loadVersions,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -73,15 +73,15 @@ class Project extends Model implements Commentable
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Add the `IsCommenter` trait to your User model:
|
Add the `CanComment` trait to your User model:
|
||||||
|
|
||||||
```php [app/Models/User.php]
|
```php [app/Models/User.php]
|
||||||
use Relaticle\Comments\Concerns\IsCommenter;
|
use Relaticle\Comments\Concerns\CanComment;
|
||||||
use Relaticle\Comments\Contracts\Commenter;
|
use Relaticle\Comments\Contracts\Commentator;
|
||||||
|
|
||||||
class User extends Authenticatable implements Commenter
|
class User extends Authenticatable implements Commentator
|
||||||
{
|
{
|
||||||
use IsCommenter;
|
use CanComment;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
---
|
|
||||||
title: Introduction
|
|
||||||
description: A full-featured commenting system for Filament panels.
|
|
||||||
navigation:
|
|
||||||
icon: i-lucide-home
|
|
||||||
seo:
|
|
||||||
title: Introduction
|
|
||||||
description: Learn about Comments - a full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.
|
|
||||||
ogImage: /preview.png
|
|
||||||
---
|
|
||||||
|
|
||||||
Welcome to **Comments**, a powerful Laravel package that adds a full-featured commenting system to any Filament panel.
|
|
||||||
|
|
||||||
## What is Comments?
|
|
||||||
|
|
||||||
Comments provides polymorphic commenting on any Eloquent model with deep Filament integration. Add threaded discussions, @mentions, emoji reactions, file attachments, and real-time notifications to your admin panel with minimal setup.
|
|
||||||
|
|
||||||
## Why Choose Comments?
|
|
||||||
|
|
||||||
::card-group
|
|
||||||
:::card
|
|
||||||
---
|
|
||||||
icon: i-lucide-messages-square
|
|
||||||
title: Threaded Discussions
|
|
||||||
---
|
|
||||||
Nested replies with configurable depth limits keep conversations organized and easy to follow.
|
|
||||||
:::
|
|
||||||
|
|
||||||
:::card
|
|
||||||
---
|
|
||||||
icon: i-lucide-clock
|
|
||||||
title: Quick Setup
|
|
||||||
---
|
|
||||||
Add traits to your models, register the plugin, and you have a working comment system in minutes.
|
|
||||||
:::
|
|
||||||
|
|
||||||
:::card
|
|
||||||
---
|
|
||||||
icon: i-lucide-puzzle
|
|
||||||
title: 3 Integration Patterns
|
|
||||||
---
|
|
||||||
Use as a slide-over action, table row action, or inline infolist entry - whatever fits your resource.
|
|
||||||
:::
|
|
||||||
|
|
||||||
:::card
|
|
||||||
---
|
|
||||||
icon: i-lucide-bell
|
|
||||||
title: Built-in Notifications
|
|
||||||
---
|
|
||||||
Database and mail notifications with subscription management and auto-subscribe for authors and mentioned users.
|
|
||||||
:::
|
|
||||||
::
|
|
||||||
@@ -15,21 +15,34 @@ php artisan vendor:publish --tag=comments-config
|
|||||||
|
|
||||||
This creates `config/comments.php` with all available options.
|
This creates `config/comments.php` with all available options.
|
||||||
|
|
||||||
## Table Name
|
## Table Names
|
||||||
|
|
||||||
```php
|
```php
|
||||||
'tables' => [
|
'table_names' => [
|
||||||
'comments' => 'comments',
|
'comments' => 'comments',
|
||||||
|
'reactions' => 'comment_reactions',
|
||||||
|
'mentions' => 'comment_mentions',
|
||||||
|
'subscriptions' => 'comment_subscriptions',
|
||||||
|
'attachments' => 'comment_attachments',
|
||||||
],
|
],
|
||||||
```
|
```
|
||||||
|
|
||||||
Change the table name if it conflicts with your application.
|
Change the table names if they conflict with your application.
|
||||||
|
|
||||||
|
## Column Names
|
||||||
|
|
||||||
|
```php
|
||||||
|
'column_names' => [
|
||||||
|
'commenter_id' => 'commenter_id',
|
||||||
|
'commenter_type' => 'commenter_type',
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
## Models
|
## Models
|
||||||
|
|
||||||
```php
|
```php
|
||||||
'models' => [
|
'models' => [
|
||||||
'comment' => \Relaticle\Comments\Comment::class,
|
'comment' => \Relaticle\Comments\Models\Comment::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'commenter' => [
|
'commenter' => [
|
||||||
@@ -178,10 +191,10 @@ When broadcasting is disabled, the Livewire component polls for new comments at
|
|||||||
Override how the authenticated user is resolved:
|
Override how the authenticated user is resolved:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
|
|
||||||
// In AppServiceProvider::boot()
|
// In AppServiceProvider::boot()
|
||||||
Config::resolveAuthenticatedUserUsing(function () {
|
CommentsConfig::resolveAuthenticatedUserUsing(function () {
|
||||||
return auth()->user();
|
return auth()->user();
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -26,34 +26,34 @@ Create your own policy to customize authorization:
|
|||||||
```php
|
```php
|
||||||
namespace App\Policies;
|
namespace App\Policies;
|
||||||
|
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Contracts\Commenter;
|
use Relaticle\Comments\Contracts\Commentator;
|
||||||
|
|
||||||
class CustomCommentPolicy
|
class CustomCommentPolicy
|
||||||
{
|
{
|
||||||
public function viewAny(Commenter $user): bool
|
public function viewAny(Commentator $user): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(Commenter $user): bool
|
public function create(Commentator $user): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Commenter $user, Comment $comment): bool
|
public function update(Commentator $user, Comment $comment): bool
|
||||||
{
|
{
|
||||||
return $comment->user_id === $user->getKey()
|
return $comment->commenter_id === $user->getKey()
|
||||||
&& $comment->user_type === $user->getMorphClass();
|
&& $comment->commenter_type === $user->getMorphClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Commenter $user, Comment $comment): bool
|
public function delete(Commentator $user, Comment $comment): bool
|
||||||
{
|
{
|
||||||
return $comment->user_id === $user->getKey()
|
return $comment->commenter_id === $user->getKey()
|
||||||
|| $user->hasRole('admin');
|
|| $user->hasRole('admin');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reply(Commenter $user, Comment $comment): bool
|
public function reply(Commentator $user, Comment $comment): bool
|
||||||
{
|
{
|
||||||
return $comment->canReply();
|
return $comment->canReply();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,4 +48,4 @@ Keys are stored in the database. If you change a key, existing reactions with th
|
|||||||
|
|
||||||
## Storage
|
## Storage
|
||||||
|
|
||||||
Reactions are stored in the `comment_reactions` table with a unique constraint on `(comment_id, user_id, user_type, reaction)`, ensuring one reaction of each type per user per comment.
|
Reactions are stored in the `comment_reactions` table with a unique constraint on `(comment_id, commenter_id, commenter_type, reaction)`, ensuring one reaction of each type per user per comment.
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ When a comment is deleted, its attachments are cascade deleted from the database
|
|||||||
|
|
||||||
## Helper Methods
|
## Helper Methods
|
||||||
|
|
||||||
The `CommentAttachment` model provides:
|
The `Attachment` model (`Relaticle\Comments\Models\Attachment`) provides:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$attachment->isImage(); // Check if attachment is an image
|
$attachment->isImage(); // Check if attachment is an image
|
||||||
|
|||||||
@@ -61,17 +61,17 @@ Users can toggle their subscription using the subscribe/unsubscribe button in th
|
|||||||
### Programmatic Access
|
### Programmatic Access
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use Relaticle\Comments\CommentSubscription;
|
use Relaticle\Comments\Models\Subscription;
|
||||||
|
|
||||||
// Check subscription status
|
// Check subscription status
|
||||||
CommentSubscription::isSubscribed($commentable, $user);
|
Subscription::isSubscribed($commentable, $user);
|
||||||
|
|
||||||
// Subscribe/unsubscribe
|
// Subscribe/unsubscribe
|
||||||
CommentSubscription::subscribe($commentable, $user);
|
Subscription::subscribe($commentable, $user);
|
||||||
CommentSubscription::unsubscribe($commentable, $user);
|
Subscription::unsubscribe($commentable, $user);
|
||||||
|
|
||||||
// Get all subscribers for a commentable
|
// Get all subscribers for a commentable
|
||||||
$subscribers = CommentSubscription::subscribersFor($commentable);
|
$subscribers = Subscription::subscribersFor($commentable);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ The main comments table with polymorphic relationships and threading support.
|
|||||||
| `id` | bigint | Primary key |
|
| `id` | bigint | Primary key |
|
||||||
| `commentable_type` | string | Polymorphic model type |
|
| `commentable_type` | string | Polymorphic model type |
|
||||||
| `commentable_id` | bigint | Polymorphic model ID |
|
| `commentable_id` | bigint | Polymorphic model ID |
|
||||||
| `user_type` | string | Commenter model type |
|
| `commenter_type` | string | Commenter model type |
|
||||||
| `user_id` | bigint | Commenter model ID |
|
| `commenter_id` | bigint | Commenter model ID |
|
||||||
| `parent_id` | bigint (nullable) | Parent comment for replies |
|
| `parent_id` | bigint (nullable) | Parent comment for replies |
|
||||||
| `body` | text | HTML comment content |
|
| `body` | text | HTML comment content |
|
||||||
| `edited_at` | timestamp (nullable) | When the comment was last edited |
|
| `edited_at` | timestamp (nullable) | When the comment was last edited |
|
||||||
@@ -39,12 +39,12 @@ Tracks emoji reactions per user per comment.
|
|||||||
|--------|------|-------------|
|
|--------|------|-------------|
|
||||||
| `id` | bigint | Primary key |
|
| `id` | bigint | Primary key |
|
||||||
| `comment_id` | bigint | Foreign key to comments |
|
| `comment_id` | bigint | Foreign key to comments |
|
||||||
| `user_type` | string | Reactor model type |
|
| `commenter_type` | string | Reactor model type |
|
||||||
| `user_id` | bigint | Reactor model ID |
|
| `commenter_id` | bigint | Reactor model ID |
|
||||||
| `reaction` | string | Reaction key (e.g., `thumbs_up`) |
|
| `reaction` | string | Reaction key (e.g., `thumbs_up`) |
|
||||||
| `created_at` | timestamp | |
|
| `created_at` | timestamp | |
|
||||||
|
|
||||||
**Unique constraint:** `(comment_id, user_id, user_type, reaction)`
|
**Unique constraint:** `(comment_id, commenter_id, commenter_type, reaction)`
|
||||||
|
|
||||||
### comment_mentions
|
### comment_mentions
|
||||||
|
|
||||||
@@ -54,11 +54,11 @@ Tracks @mentioned users per comment.
|
|||||||
|--------|------|-------------|
|
|--------|------|-------------|
|
||||||
| `id` | bigint | Primary key |
|
| `id` | bigint | Primary key |
|
||||||
| `comment_id` | bigint | Foreign key to comments |
|
| `comment_id` | bigint | Foreign key to comments |
|
||||||
| `user_type` | string | Mentioned user model type |
|
| `commenter_type` | string | Mentioned user model type |
|
||||||
| `user_id` | bigint | Mentioned user model ID |
|
| `commenter_id` | bigint | Mentioned user model ID |
|
||||||
| `created_at` | timestamp | |
|
| `created_at` | timestamp | |
|
||||||
|
|
||||||
**Unique constraint:** `(comment_id, user_id, user_type)`
|
**Unique constraint:** `(comment_id, commenter_id, commenter_type)`
|
||||||
|
|
||||||
### comment_subscriptions
|
### comment_subscriptions
|
||||||
|
|
||||||
@@ -69,11 +69,11 @@ Tracks which users are subscribed to comment threads on specific models.
|
|||||||
| `id` | bigint | Primary key |
|
| `id` | bigint | Primary key |
|
||||||
| `commentable_type` | string | Subscribed model type |
|
| `commentable_type` | string | Subscribed model type |
|
||||||
| `commentable_id` | bigint | Subscribed model ID |
|
| `commentable_id` | bigint | Subscribed model ID |
|
||||||
| `user_type` | string | Subscriber model type |
|
| `commenter_type` | string | Subscriber model type |
|
||||||
| `user_id` | bigint | Subscriber model ID |
|
| `commenter_id` | bigint | Subscriber model ID |
|
||||||
| `created_at` | timestamp | |
|
| `created_at` | timestamp | |
|
||||||
|
|
||||||
**Unique constraint:** `(commentable_type, commentable_id, user_type, user_id)`
|
**Unique constraint:** `(commentable_type, commentable_id, commenter_type, commenter_id)`
|
||||||
|
|
||||||
### comment_attachments
|
### comment_attachments
|
||||||
|
|
||||||
@@ -96,11 +96,11 @@ Stores file attachment metadata for comments.
|
|||||||
```
|
```
|
||||||
Commentable Model (e.g., Project)
|
Commentable Model (e.g., Project)
|
||||||
└── comments (morphMany)
|
└── comments (morphMany)
|
||||||
├── user (morphTo → User)
|
├── commenter (morphTo → User)
|
||||||
├── parent (belongsTo → Comment)
|
├── parent (belongsTo → Comment)
|
||||||
├── replies (hasMany → Comment)
|
├── replies (hasMany → Comment)
|
||||||
├── reactions (hasMany → CommentReaction)
|
├── reactions (hasMany → Reaction)
|
||||||
├── attachments (hasMany → CommentAttachment)
|
├── attachments (hasMany → Attachment)
|
||||||
└── mentions (morphToMany → User)
|
└── mentions (morphToMany → User)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,14 @@ Drop-in integration with any Filament resource.
|
|||||||
:::
|
:::
|
||||||
::
|
::
|
||||||
|
|
||||||
|
::callout{icon="i-lucide-triangle-alert" color="amber"}
|
||||||
|
**Alpha Software** -- This package is currently in alpha. The API is not stable and breaking changes may occur between releases without prior notice. Do not use in production unless you are prepared to handle upgrades manually.
|
||||||
|
::
|
||||||
|
|
||||||
|
<div class="max-w-5xl mx-auto mt-8">
|
||||||
|
<img src="/preview.png" alt="Comments - threaded discussions in Filament" class="rounded-lg shadow-lg w-full" />
|
||||||
|
</div>
|
||||||
|
|
||||||
::u-page-section
|
::u-page-section
|
||||||
#title
|
#title
|
||||||
Why choose Comments?
|
Why choose Comments?
|
||||||
@@ -125,6 +133,8 @@ Extend your Laravel applications with our ecosystem of complementary tools
|
|||||||
to: https://filaforms.app
|
to: https://filaforms.app
|
||||||
target: _blank
|
target: _blank
|
||||||
---
|
---
|
||||||
|
:img{src="https://filaforms.app/img/og-image.png" alt="FilaForms" class="mb-4 rounded-lg w-full pointer-events-none"}
|
||||||
|
|
||||||
Visual form builder for all your public-facing forms.
|
Visual form builder for all your public-facing forms.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
@@ -135,17 +145,9 @@ Extend your Laravel applications with our ecosystem of complementary tools
|
|||||||
to: https://relaticle.github.io/custom-fields
|
to: https://relaticle.github.io/custom-fields
|
||||||
target: _blank
|
target: _blank
|
||||||
---
|
---
|
||||||
Let users add custom fields to any model without code changes.
|
:img{src="https://relaticle.github.io/custom-fields/og-image.png" alt="Custom Fields" class="mb-4 rounded-lg w-full pointer-events-none"}
|
||||||
:::
|
|
||||||
|
|
||||||
:::card
|
Let users add custom fields to any model without code changes.
|
||||||
---
|
|
||||||
title: Flowforge
|
|
||||||
icon: i-lucide-kanban
|
|
||||||
to: https://relaticle.github.io/flowforge
|
|
||||||
target: _blank
|
|
||||||
---
|
|
||||||
Transform any Laravel model into a drag-and-drop Kanban board.
|
|
||||||
:::
|
:::
|
||||||
::
|
::
|
||||||
::
|
::
|
||||||
|
|||||||
13
docs/public/logo-dark.svg
Normal file
13
docs/public/logo-dark.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.9 KiB |
13
docs/public/logo-light.svg
Normal file
13
docs/public/logo-light.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.9 KiB |
BIN
docs/public/preview.png
Normal file
BIN
docs/public/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 330 KiB |
@@ -31,12 +31,12 @@ class Project extends Model implements Commentable
|
|||||||
```
|
```
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use Relaticle\Comments\Concerns\IsCommenter;
|
use Relaticle\Comments\Concerns\CanComment;
|
||||||
use Relaticle\Comments\Contracts\Commenter;
|
use Relaticle\Comments\Contracts\Commentator;
|
||||||
|
|
||||||
class User extends Authenticatable implements Commenter
|
class User extends Authenticatable implements Commentator
|
||||||
{
|
{
|
||||||
use IsCommenter;
|
use CanComment;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ Publish config: `php artisan vendor:publish --tag=comments-config`
|
|||||||
|
|
||||||
| Key | Default | Purpose |
|
| Key | Default | Purpose |
|
||||||
|-----|---------|---------|
|
|-----|---------|---------|
|
||||||
| `tables.comments` | `'comments'` | Main comments table name |
|
| `table_names.comments` | `'comments'` | Main comments table name |
|
||||||
| `models.comment` | `Comment::class` | Comment model class |
|
| `models.comment` | `Comment::class` | Comment model class |
|
||||||
| `commenter.model` | `User::class` | Commenter (user) model class |
|
| `commenter.model` | `User::class` | Commenter (user) model class |
|
||||||
| `policy` | `CommentPolicy::class` | Authorization policy class |
|
| `policy` | `CommentPolicy::class` | Authorization policy class |
|
||||||
@@ -183,14 +183,14 @@ Default `CommentPolicy` methods:
|
|||||||
```php
|
```php
|
||||||
namespace App\Policies;
|
namespace App\Policies;
|
||||||
|
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Contracts\Commenter;
|
use Relaticle\Comments\Contracts\Commentator;
|
||||||
|
|
||||||
class CustomCommentPolicy
|
class CustomCommentPolicy
|
||||||
{
|
{
|
||||||
public function delete(Commenter $user, Comment $comment): bool
|
public function delete(Commentator $user, Comment $comment): bool
|
||||||
{
|
{
|
||||||
return $comment->user_id === $user->getKey()
|
return $comment->commenter_id === $user->getKey()
|
||||||
|| $user->hasRole('admin');
|
|| $user->hasRole('admin');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,10 +201,10 @@ class CustomCommentPolicy
|
|||||||
### Scoped Comments (Multi-tenancy)
|
### Scoped Comments (Multi-tenancy)
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
|
|
||||||
// In AppServiceProvider::boot()
|
// In AppServiceProvider::boot()
|
||||||
Config::resolveAuthenticatedUserUsing(function () {
|
CommentsConfig::resolveAuthenticatedUserUsing(function () {
|
||||||
return auth()->user();
|
return auth()->user();
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@@ -276,7 +276,7 @@ $model->commentCount(); // Total count
|
|||||||
|
|
||||||
// On Comment model
|
// On Comment model
|
||||||
$comment->commentable(); // Parent model (morphTo)
|
$comment->commentable(); // Parent model (morphTo)
|
||||||
$comment->user(); // Commenter (morphTo)
|
$comment->commenter(); // Commenter (morphTo)
|
||||||
$comment->parent(); // Parent comment (belongsTo)
|
$comment->parent(); // Parent comment (belongsTo)
|
||||||
$comment->replies(); // Child comments (hasMany)
|
$comment->replies(); // Child comments (hasMany)
|
||||||
$comment->reactions(); // Reactions (hasMany)
|
$comment->reactions(); // Reactions (hasMany)
|
||||||
|
|||||||
@@ -1,9 +1,58 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'deleted_comment' => 'This comment was deleted.',
|
'comments' => [
|
||||||
'edited' => 'edited',
|
'deleted' => 'This comment was deleted.',
|
||||||
'load_more' => 'Load more comments',
|
'edited' => 'edited',
|
||||||
'no_comments' => 'No comments yet.',
|
'no_comments' => 'No comments yet.',
|
||||||
'comment_placeholder' => 'Write a comment...',
|
'placeholder' => 'Write a comment...',
|
||||||
|
'load_more' => 'Load more comments',
|
||||||
|
'sort_newest' => 'Newest first',
|
||||||
|
'sort_oldest' => 'Oldest first',
|
||||||
|
],
|
||||||
|
|
||||||
|
'actions' => [
|
||||||
|
'reply' => 'Reply',
|
||||||
|
'edit' => 'Edit',
|
||||||
|
'delete' => 'Delete',
|
||||||
|
'cancel' => 'Cancel',
|
||||||
|
'save' => 'Save',
|
||||||
|
'submit' => 'Submit',
|
||||||
|
],
|
||||||
|
|
||||||
|
'reactions' => [
|
||||||
|
'thumbs_up' => 'Thumbs up',
|
||||||
|
'heart' => 'Heart',
|
||||||
|
'celebrate' => 'Celebrate',
|
||||||
|
'laugh' => 'Laugh',
|
||||||
|
'thinking' => 'Thinking',
|
||||||
|
'sad' => 'Sad',
|
||||||
|
'reacted_by' => ':names reacted with :reaction',
|
||||||
|
'and_others' => 'and :count others',
|
||||||
|
],
|
||||||
|
|
||||||
|
'subscriptions' => [
|
||||||
|
'subscribe' => 'Subscribe to replies',
|
||||||
|
'unsubscribe' => 'Unsubscribe from replies',
|
||||||
|
'subscribed' => 'You will be notified of new replies.',
|
||||||
|
'unsubscribed' => 'You will no longer be notified.',
|
||||||
|
],
|
||||||
|
|
||||||
|
'mentions' => [
|
||||||
|
'no_results' => 'No users found',
|
||||||
|
],
|
||||||
|
|
||||||
|
'attachments' => [
|
||||||
|
'add' => 'Add attachment',
|
||||||
|
'remove' => 'Remove',
|
||||||
|
'too_large' => 'File is too large. Maximum size: :max KB.',
|
||||||
|
'invalid_type' => 'File type not allowed.',
|
||||||
|
],
|
||||||
|
|
||||||
|
'notifications' => [
|
||||||
|
'reply_subject' => 'New reply to your comment',
|
||||||
|
'reply_body' => ':name replied to your comment.',
|
||||||
|
'mention_subject' => 'You were mentioned in a comment',
|
||||||
|
'mention_body' => ':name mentioned you in a comment.',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
<div class="shrink-0">
|
<div class="shrink-0">
|
||||||
@if ($comment->trashed())
|
@if ($comment->trashed())
|
||||||
<div class="h-8 w-8 rounded-full bg-gray-200 dark:bg-gray-700"></div>
|
<div class="h-8 w-8 rounded-full bg-gray-200 dark:bg-gray-700"></div>
|
||||||
@elseif ($comment->user?->getCommentAvatarUrl())
|
@elseif ($comment->commenter?->getCommentAvatarUrl())
|
||||||
<img src="{{ $comment->user->getCommentAvatarUrl() }}" alt="{{ $comment->user->getCommentName() }}" class="h-8 w-8 rounded-full object-cover">
|
<img src="{{ $comment->commenter->getCommentAvatarUrl() }}" alt="{{ $comment->commenter->getCommentDisplayName() }}" class="h-8 w-8 rounded-full object-cover">
|
||||||
@else
|
@else
|
||||||
<div class="flex h-8 w-8 items-center justify-center rounded-full bg-primary-100 text-sm font-medium text-primary-700 dark:bg-primary-800 dark:text-primary-300">
|
<div class="flex h-8 w-8 items-center justify-center rounded-full bg-primary-100 text-sm font-medium text-primary-700 dark:bg-primary-800 dark:text-primary-300">
|
||||||
{{ str($comment->user?->getCommentName() ?? '?')->substr(0, 1)->upper() }}
|
{{ str($comment->commenter?->getCommentDisplayName() ?? '?')->substr(0, 1)->upper() }}
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
{{-- Header: name + timestamp --}}
|
{{-- Header: name + timestamp --}}
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||||
{{ $comment->user?->getCommentName() ?? 'Unknown' }}
|
{{ $comment->commenter?->getCommentDisplayName() ?? 'Unknown' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-xs text-gray-500 dark:text-gray-400" title="{{ $comment->created_at->format('M j, Y g:i A') }}">
|
<span class="text-xs text-gray-500 dark:text-gray-400" title="{{ $comment->created_at->format('M j, Y g:i A') }}">
|
||||||
{{ $comment->created_at->diffForHumans() }}
|
{{ $comment->created_at->diffForHumans() }}
|
||||||
@@ -33,9 +33,11 @@
|
|||||||
{{-- Body or edit form --}}
|
{{-- Body or edit form --}}
|
||||||
@if ($isEditing)
|
@if ($isEditing)
|
||||||
<form wire:submit="saveEdit" class="mt-1">
|
<form wire:submit="saveEdit" class="mt-1">
|
||||||
<textarea wire:model="editBody" rows="3"
|
<x-filament::input.wrapper>
|
||||||
class="block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 sm:text-sm"
|
<textarea wire:model="editBody" rows="3"
|
||||||
></textarea>
|
class="block w-full border-none bg-transparent px-3 py-1.5 text-sm leading-6 text-gray-950 outline-none transition duration-75 placeholder:text-gray-400 focus:ring-0 dark:text-white dark:placeholder:text-gray-500"
|
||||||
|
></textarea>
|
||||||
|
</x-filament::input.wrapper>
|
||||||
@error('editBody')
|
@error('editBody')
|
||||||
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
||||||
@enderror
|
@enderror
|
||||||
@@ -167,14 +169,16 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}">
|
}">
|
||||||
<textarea x-ref="replyInput"
|
<x-filament::input.wrapper>
|
||||||
wire:model="replyBody"
|
<textarea x-ref="replyInput"
|
||||||
@input="handleInput($event)"
|
wire:model="replyBody"
|
||||||
@keydown="handleKeydown($event)"
|
@input="handleInput($event)"
|
||||||
rows="2"
|
@keydown="handleKeydown($event)"
|
||||||
placeholder="Write a reply..."
|
rows="2"
|
||||||
class="block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 dark:placeholder-gray-400 sm:text-sm"
|
placeholder="Write a reply..."
|
||||||
></textarea>
|
class="block w-full border-none bg-transparent px-3 py-1.5 text-sm leading-6 text-gray-950 outline-none transition duration-75 placeholder:text-gray-400 focus:ring-0 dark:text-white dark:placeholder:text-gray-500"
|
||||||
|
></textarea>
|
||||||
|
</x-filament::input.wrapper>
|
||||||
|
|
||||||
{{-- Mention autocomplete dropdown --}}
|
{{-- Mention autocomplete dropdown --}}
|
||||||
<div x-show="showMentions" x-cloak
|
<div x-show="showMentions" x-cloak
|
||||||
@@ -200,14 +204,14 @@
|
|||||||
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
||||||
@enderror
|
@enderror
|
||||||
|
|
||||||
@if (\Relaticle\Comments\Config::areAttachmentsEnabled())
|
@if (\Relaticle\Comments\CommentsConfig::areAttachmentsEnabled())
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<label class="flex cursor-pointer items-center gap-2 text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
<label class="flex cursor-pointer items-center gap-2 text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
||||||
<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13" />
|
||||||
</svg>
|
</svg>
|
||||||
Attach files
|
Attach files
|
||||||
<input type="file" wire:model="replyAttachments" multiple class="hidden" accept="{{ implode(',', \Relaticle\Comments\Config::getAttachmentAllowedTypes()) }}" />
|
<input type="file" wire:model="replyAttachments" multiple class="hidden" accept="{{ implode(',', \Relaticle\Comments\CommentsConfig::getAttachmentAllowedTypes()) }}" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="space-y-4"
|
<div class="space-y-4"
|
||||||
@if (!\Relaticle\Comments\Config::isBroadcastingEnabled())
|
@if (!\Relaticle\Comments\CommentsConfig::isBroadcastingEnabled())
|
||||||
wire:poll.{{ \Relaticle\Comments\Config::getPollingInterval() }}
|
wire:poll.{{ \Relaticle\Comments\CommentsConfig::getPollingInterval() }}
|
||||||
@endif
|
@endif
|
||||||
>
|
>
|
||||||
{{-- Sort toggle --}}
|
{{-- Sort toggle --}}
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
{{-- New comment form - only for authorized users --}}
|
{{-- New comment form - only for authorized users --}}
|
||||||
@auth
|
@auth
|
||||||
@can('create', \Relaticle\Comments\Config::getCommentModel())
|
@can('create', \Relaticle\Comments\CommentsConfig::getCommentModel())
|
||||||
<form wire:submit="addComment" class="relative mt-4"
|
<form wire:submit="addComment" class="relative mt-4"
|
||||||
x-data="{
|
x-data="{
|
||||||
showMentions: false,
|
showMentions: false,
|
||||||
@@ -118,15 +118,17 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}">
|
}">
|
||||||
<textarea
|
<x-filament::input.wrapper>
|
||||||
x-ref="commentInput"
|
<textarea
|
||||||
wire:model="newComment"
|
x-ref="commentInput"
|
||||||
@input="handleInput($event)"
|
wire:model="newComment"
|
||||||
@keydown="handleKeydown($event)"
|
@input="handleInput($event)"
|
||||||
rows="3"
|
@keydown="handleKeydown($event)"
|
||||||
placeholder="Write a comment..."
|
rows="3"
|
||||||
class="block w-full rounded-lg border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 dark:placeholder-gray-400 sm:text-sm"
|
placeholder="Write a comment..."
|
||||||
></textarea>
|
class="block w-full border-none bg-transparent px-3 py-1.5 text-sm leading-6 text-gray-950 outline-none transition duration-75 placeholder:text-gray-400 focus:ring-0 dark:text-white dark:placeholder:text-gray-500"
|
||||||
|
></textarea>
|
||||||
|
</x-filament::input.wrapper>
|
||||||
|
|
||||||
{{-- Mention autocomplete dropdown --}}
|
{{-- Mention autocomplete dropdown --}}
|
||||||
<div x-show="showMentions" x-cloak
|
<div x-show="showMentions" x-cloak
|
||||||
@@ -152,14 +154,14 @@
|
|||||||
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
||||||
@enderror
|
@enderror
|
||||||
|
|
||||||
@if (\Relaticle\Comments\Config::areAttachmentsEnabled())
|
@if (\Relaticle\Comments\CommentsConfig::areAttachmentsEnabled())
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<label class="flex cursor-pointer items-center gap-2 text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
<label class="flex cursor-pointer items-center gap-2 text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
||||||
<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13" />
|
||||||
</svg>
|
</svg>
|
||||||
Attach files
|
Attach files
|
||||||
<input type="file" wire:model="attachments" multiple class="hidden" accept="{{ implode(',', \Relaticle\Comments\Config::getAttachmentAllowedTypes()) }}" />
|
<input type="file" wire:model="attachments" multiple class="hidden" accept="{{ implode(',', \Relaticle\Comments\CommentsConfig::getAttachmentAllowedTypes()) }}" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
{{-- Emoji picker dropdown --}}
|
{{-- Emoji picker dropdown --}}
|
||||||
<div x-show="open" x-cloak @click.outside="open = false"
|
<div x-show="open" x-cloak @click.outside="open = false"
|
||||||
class="absolute bottom-full left-0 z-50 mb-1 flex gap-1 rounded-lg border border-gray-200 bg-white p-2 shadow-lg dark:border-gray-600 dark:bg-gray-800">
|
class="absolute bottom-full left-0 z-50 mb-1 flex gap-1 rounded-lg border border-gray-200 bg-white p-2 shadow-lg dark:border-gray-600 dark:bg-gray-800">
|
||||||
@foreach (\Relaticle\Comments\Config::getReactionEmojiSet() as $key => $emoji)
|
@foreach (\Relaticle\Comments\CommentsConfig::getReactionEmojiSet() as $key => $emoji)
|
||||||
<button wire:click="toggleReaction('{{ $key }}')" type="button"
|
<button wire:click="toggleReaction('{{ $key }}')" type="button"
|
||||||
class="rounded p-1 text-base hover:bg-gray-100 dark:hover:bg-gray-700"
|
class="rounded p-1 text-base hover:bg-gray-100 dark:hover:bg-gray-700"
|
||||||
title="{{ str_replace('_', ' ', $key) }}">
|
title="{{ str_replace('_', ' ', $key) }}">
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ namespace Relaticle\Comments;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Relaticle\Comments\Mentions\DefaultMentionResolver;
|
use Relaticle\Comments\Mentions\DefaultMentionResolver;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Policies\CommentPolicy;
|
use Relaticle\Comments\Policies\CommentPolicy;
|
||||||
|
|
||||||
class Config
|
class CommentsConfig
|
||||||
{
|
{
|
||||||
protected static ?Closure $resolveAuthenticatedUser = null;
|
protected static ?Closure $resolveAuthenticatedUser = null;
|
||||||
|
|
||||||
@@ -23,7 +24,25 @@ class Config
|
|||||||
|
|
||||||
public static function getCommentTable(): string
|
public static function getCommentTable(): string
|
||||||
{
|
{
|
||||||
return config('comments.tables.comments', 'comments');
|
return static::getTableName('comments');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTableName(string $table): string
|
||||||
|
{
|
||||||
|
$defaults = [
|
||||||
|
'comments' => 'comments',
|
||||||
|
'reactions' => 'comment_reactions',
|
||||||
|
'mentions' => 'comment_mentions',
|
||||||
|
'subscriptions' => 'comment_subscriptions',
|
||||||
|
'attachments' => 'comment_attachments',
|
||||||
|
];
|
||||||
|
|
||||||
|
return config("comments.table_names.{$table}", $defaults[$table] ?? $table);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getCommenterMorphName(): string
|
||||||
|
{
|
||||||
|
return config('comments.column_names.commenter_morph', 'commenter');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getMaxDepth(): int
|
public static function getMaxDepth(): int
|
||||||
@@ -42,20 +42,20 @@ class CommentsServiceProvider extends PackageServiceProvider
|
|||||||
public function packageRegistered(): void
|
public function packageRegistered(): void
|
||||||
{
|
{
|
||||||
Relation::morphMap([
|
Relation::morphMap([
|
||||||
'comment' => Config::getCommentModel(),
|
'comment' => CommentsConfig::getCommentModel(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->app->bind(
|
$this->app->bind(
|
||||||
MentionResolver::class,
|
MentionResolver::class,
|
||||||
fn () => new (Config::getMentionResolver())
|
fn () => new (CommentsConfig::getMentionResolver())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function packageBooted(): void
|
public function packageBooted(): void
|
||||||
{
|
{
|
||||||
Gate::policy(
|
Gate::policy(
|
||||||
Config::getCommentModel(),
|
CommentsConfig::getCommentModel(),
|
||||||
Config::getPolicyClass(),
|
CommentsConfig::getPolicyClass(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Event::listen(CommentCreated::class, SendCommentRepliedNotification::class);
|
Event::listen(CommentCreated::class, SendCommentRepliedNotification::class);
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ namespace Relaticle\Comments\Concerns;
|
|||||||
use Filament\Models\Contracts\HasAvatar;
|
use Filament\Models\Contracts\HasAvatar;
|
||||||
use Filament\Models\Contracts\HasName;
|
use Filament\Models\Contracts\HasName;
|
||||||
|
|
||||||
trait IsCommenter
|
trait CanComment
|
||||||
{
|
{
|
||||||
public function getCommentName(): string
|
public function getCommentDisplayName(): string
|
||||||
{
|
{
|
||||||
if ($this instanceof HasName) {
|
if ($this instanceof HasName) {
|
||||||
return $this->getFilamentName();
|
return $this->getFilamentName();
|
||||||
@@ -3,13 +3,13 @@
|
|||||||
namespace Relaticle\Comments\Concerns;
|
namespace Relaticle\Comments\Concerns;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
|
|
||||||
trait HasComments
|
trait HasComments
|
||||||
{
|
{
|
||||||
public function comments(): MorphMany
|
public function comments(): MorphMany
|
||||||
{
|
{
|
||||||
return $this->morphMany(Config::getCommentModel(), 'commentable');
|
return $this->morphMany(CommentsConfig::getCommentModel(), 'commentable');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function topLevelComments(): MorphMany
|
public function topLevelComments(): MorphMany
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
namespace Relaticle\Comments\Contracts;
|
namespace Relaticle\Comments\Contracts;
|
||||||
|
|
||||||
interface Commenter
|
interface Commentator
|
||||||
{
|
{
|
||||||
public function getKey();
|
public function getKey();
|
||||||
|
|
||||||
public function getMorphClass();
|
public function getMorphClass();
|
||||||
|
|
||||||
public function getCommentName(): string;
|
public function getCommentDisplayName(): string;
|
||||||
|
|
||||||
public function getCommentAvatarUrl(): ?string;
|
public function getCommentAvatarUrl(): ?string;
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,8 @@ use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentCreated implements ShouldBroadcast
|
class CommentCreated implements ShouldBroadcast
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ class CommentCreated implements ShouldBroadcast
|
|||||||
/** @return array<int, PrivateChannel> */
|
/** @return array<int, PrivateChannel> */
|
||||||
public function broadcastOn(): array
|
public function broadcastOn(): array
|
||||||
{
|
{
|
||||||
$prefix = Config::getBroadcastChannelPrefix();
|
$prefix = CommentsConfig::getBroadcastChannelPrefix();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new PrivateChannel("{$prefix}.{$this->comment->commentable_type}.{$this->comment->commentable_id}"),
|
new PrivateChannel("{$prefix}.{$this->comment->commentable_type}.{$this->comment->commentable_id}"),
|
||||||
@@ -36,7 +36,7 @@ class CommentCreated implements ShouldBroadcast
|
|||||||
|
|
||||||
public function broadcastWhen(): bool
|
public function broadcastWhen(): bool
|
||||||
{
|
{
|
||||||
return Config::isBroadcastingEnabled();
|
return CommentsConfig::isBroadcastingEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{comment_id: int|string, commentable_type: string, commentable_id: int|string} */
|
/** @return array{comment_id: int|string, commentable_type: string, commentable_id: int|string} */
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentDeleted implements ShouldBroadcast
|
class CommentDeleted implements ShouldBroadcast
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ class CommentDeleted implements ShouldBroadcast
|
|||||||
/** @return array<int, PrivateChannel> */
|
/** @return array<int, PrivateChannel> */
|
||||||
public function broadcastOn(): array
|
public function broadcastOn(): array
|
||||||
{
|
{
|
||||||
$prefix = Config::getBroadcastChannelPrefix();
|
$prefix = CommentsConfig::getBroadcastChannelPrefix();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new PrivateChannel("{$prefix}.{$this->comment->commentable_type}.{$this->comment->commentable_id}"),
|
new PrivateChannel("{$prefix}.{$this->comment->commentable_type}.{$this->comment->commentable_id}"),
|
||||||
@@ -36,7 +36,7 @@ class CommentDeleted implements ShouldBroadcast
|
|||||||
|
|
||||||
public function broadcastWhen(): bool
|
public function broadcastWhen(): bool
|
||||||
{
|
{
|
||||||
return Config::isBroadcastingEnabled();
|
return CommentsConfig::isBroadcastingEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{comment_id: int|string, commentable_type: string, commentable_id: int|string} */
|
/** @return array{comment_id: int|string, commentable_type: string, commentable_id: int|string} */
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use Illuminate\Broadcasting\PrivateChannel;
|
|||||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentReacted implements ShouldBroadcast
|
class CommentReacted implements ShouldBroadcast
|
||||||
{
|
{
|
||||||
@@ -26,7 +26,7 @@ class CommentReacted implements ShouldBroadcast
|
|||||||
/** @return array<int, PrivateChannel> */
|
/** @return array<int, PrivateChannel> */
|
||||||
public function broadcastOn(): array
|
public function broadcastOn(): array
|
||||||
{
|
{
|
||||||
$prefix = Config::getBroadcastChannelPrefix();
|
$prefix = CommentsConfig::getBroadcastChannelPrefix();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new PrivateChannel("{$prefix}.{$this->comment->commentable_type}.{$this->comment->commentable_id}"),
|
new PrivateChannel("{$prefix}.{$this->comment->commentable_type}.{$this->comment->commentable_id}"),
|
||||||
@@ -35,7 +35,7 @@ class CommentReacted implements ShouldBroadcast
|
|||||||
|
|
||||||
public function broadcastWhen(): bool
|
public function broadcastWhen(): bool
|
||||||
{
|
{
|
||||||
return Config::isBroadcastingEnabled();
|
return CommentsConfig::isBroadcastingEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{comment_id: int|string, reaction: string, action: string} */
|
/** @return array{comment_id: int|string, reaction: string, action: string} */
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentUpdated implements ShouldBroadcast
|
class CommentUpdated implements ShouldBroadcast
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ class CommentUpdated implements ShouldBroadcast
|
|||||||
/** @return array<int, PrivateChannel> */
|
/** @return array<int, PrivateChannel> */
|
||||||
public function broadcastOn(): array
|
public function broadcastOn(): array
|
||||||
{
|
{
|
||||||
$prefix = Config::getBroadcastChannelPrefix();
|
$prefix = CommentsConfig::getBroadcastChannelPrefix();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new PrivateChannel("{$prefix}.{$this->comment->commentable_type}.{$this->comment->commentable_id}"),
|
new PrivateChannel("{$prefix}.{$this->comment->commentable_type}.{$this->comment->commentable_id}"),
|
||||||
@@ -36,7 +36,7 @@ class CommentUpdated implements ShouldBroadcast
|
|||||||
|
|
||||||
public function broadcastWhen(): bool
|
public function broadcastWhen(): bool
|
||||||
{
|
{
|
||||||
return Config::isBroadcastingEnabled();
|
return CommentsConfig::isBroadcastingEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{comment_id: int|string, commentable_type: string, commentable_id: int|string} */
|
/** @return array{comment_id: int|string, commentable_type: string, commentable_id: int|string} */
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace Relaticle\Comments\Events;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class UserMentioned
|
class UserMentioned
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,35 +3,35 @@
|
|||||||
namespace Relaticle\Comments\Listeners;
|
namespace Relaticle\Comments\Listeners;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Notification;
|
use Illuminate\Support\Facades\Notification;
|
||||||
use Relaticle\Comments\CommentSubscription;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Events\CommentCreated;
|
use Relaticle\Comments\Events\CommentCreated;
|
||||||
|
use Relaticle\Comments\Models\Subscription;
|
||||||
use Relaticle\Comments\Notifications\CommentRepliedNotification;
|
use Relaticle\Comments\Notifications\CommentRepliedNotification;
|
||||||
|
|
||||||
class SendCommentRepliedNotification
|
class SendCommentRepliedNotification
|
||||||
{
|
{
|
||||||
public function handle(CommentCreated $event): void
|
public function handle(CommentCreated $event): void
|
||||||
{
|
{
|
||||||
if (! Config::areNotificationsEnabled()) {
|
if (! CommentsConfig::areNotificationsEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$comment = $event->comment;
|
$comment = $event->comment;
|
||||||
$commentable = $event->commentable;
|
$commentable = $event->commentable;
|
||||||
|
|
||||||
if (Config::shouldAutoSubscribe()) {
|
if (CommentsConfig::shouldAutoSubscribe()) {
|
||||||
CommentSubscription::subscribe($commentable, $comment->user);
|
Subscription::subscribe($commentable, $comment->commenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $comment->isReply()) {
|
if (! $comment->isReply()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$subscribers = CommentSubscription::subscribersFor($commentable);
|
$subscribers = Subscription::subscribersFor($commentable);
|
||||||
|
|
||||||
$recipients = $subscribers->filter(function ($user) use ($comment) {
|
$recipients = $subscribers->filter(function ($user) use ($comment) {
|
||||||
return ! ($user->getMorphClass() === $comment->user->getMorphClass()
|
return ! ($user->getMorphClass() === $comment->commenter->getMorphClass()
|
||||||
&& $user->getKey() === $comment->user->getKey());
|
&& $user->getKey() === $comment->commenter->getKey());
|
||||||
});
|
});
|
||||||
|
|
||||||
if ($recipients->isEmpty()) {
|
if ($recipients->isEmpty()) {
|
||||||
|
|||||||
@@ -2,33 +2,33 @@
|
|||||||
|
|
||||||
namespace Relaticle\Comments\Listeners;
|
namespace Relaticle\Comments\Listeners;
|
||||||
|
|
||||||
use Relaticle\Comments\CommentSubscription;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Events\UserMentioned;
|
use Relaticle\Comments\Events\UserMentioned;
|
||||||
|
use Relaticle\Comments\Models\Subscription;
|
||||||
use Relaticle\Comments\Notifications\UserMentionedNotification;
|
use Relaticle\Comments\Notifications\UserMentionedNotification;
|
||||||
|
|
||||||
class SendUserMentionedNotification
|
class SendUserMentionedNotification
|
||||||
{
|
{
|
||||||
public function handle(UserMentioned $event): void
|
public function handle(UserMentioned $event): void
|
||||||
{
|
{
|
||||||
if (! Config::areNotificationsEnabled()) {
|
if (! CommentsConfig::areNotificationsEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$comment = $event->comment;
|
$comment = $event->comment;
|
||||||
$mentionedUser = $event->mentionedUser;
|
$mentionedUser = $event->mentionedUser;
|
||||||
|
|
||||||
if (Config::shouldAutoSubscribe()) {
|
if (CommentsConfig::shouldAutoSubscribe()) {
|
||||||
CommentSubscription::subscribe($comment->commentable, $mentionedUser);
|
Subscription::subscribe($comment->commentable, $mentionedUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
$isSelf = $mentionedUser->getMorphClass() === $comment->user->getMorphClass()
|
$isSelf = $mentionedUser->getMorphClass() === $comment->commenter->getMorphClass()
|
||||||
&& $mentionedUser->getKey() === $comment->user->getKey();
|
&& $mentionedUser->getKey() === $comment->commenter->getKey();
|
||||||
|
|
||||||
if ($isSelf) {
|
if ($isSelf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$mentionedUser->notify(new UserMentionedNotification($comment, $comment->user));
|
$mentionedUser->notify(new UserMentionedNotification($comment, $comment->commenter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use Illuminate\Contracts\View\View;
|
|||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
||||||
use Livewire\WithFileUploads;
|
use Livewire\WithFileUploads;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Contracts\MentionResolver;
|
use Relaticle\Comments\Contracts\MentionResolver;
|
||||||
use Relaticle\Comments\Events\CommentCreated;
|
use Relaticle\Comments\Events\CommentCreated;
|
||||||
use Relaticle\Comments\Events\CommentDeleted;
|
use Relaticle\Comments\Events\CommentDeleted;
|
||||||
use Relaticle\Comments\Events\CommentUpdated;
|
use Relaticle\Comments\Events\CommentUpdated;
|
||||||
use Relaticle\Comments\Mentions\MentionParser;
|
use Relaticle\Comments\Mentions\MentionParser;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentItem extends Component
|
class CommentItem extends Component
|
||||||
{
|
{
|
||||||
@@ -106,25 +106,25 @@ class CommentItem extends Component
|
|||||||
|
|
||||||
$rules = ['replyBody' => ['required', 'string', 'min:1']];
|
$rules = ['replyBody' => ['required', 'string', 'min:1']];
|
||||||
|
|
||||||
if (Config::areAttachmentsEnabled()) {
|
if (CommentsConfig::areAttachmentsEnabled()) {
|
||||||
$maxSize = Config::getAttachmentMaxSize();
|
$maxSize = CommentsConfig::getAttachmentMaxSize();
|
||||||
$allowedTypes = implode(',', Config::getAttachmentAllowedTypes());
|
$allowedTypes = implode(',', CommentsConfig::getAttachmentAllowedTypes());
|
||||||
$rules['replyAttachments.*'] = ['nullable', 'file', "max:{$maxSize}", "mimetypes:{$allowedTypes}"];
|
$rules['replyAttachments.*'] = ['nullable', 'file', "max:{$maxSize}", "mimetypes:{$allowedTypes}"];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->validate($rules);
|
$this->validate($rules);
|
||||||
|
|
||||||
$user = Config::resolveAuthenticatedUser();
|
$user = CommentsConfig::resolveAuthenticatedUser();
|
||||||
|
|
||||||
$reply = $this->comment->commentable->comments()->create([
|
$reply = $this->comment->commentable->comments()->create([
|
||||||
'body' => $this->replyBody,
|
'body' => $this->replyBody,
|
||||||
'parent_id' => $this->comment->id,
|
'parent_id' => $this->comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (Config::areAttachmentsEnabled() && ! empty($this->replyAttachments)) {
|
if (CommentsConfig::areAttachmentsEnabled() && ! empty($this->replyAttachments)) {
|
||||||
$disk = Config::getAttachmentDisk();
|
$disk = CommentsConfig::getAttachmentDisk();
|
||||||
|
|
||||||
foreach ($this->replyAttachments as $file) {
|
foreach ($this->replyAttachments as $file) {
|
||||||
$path = $file->store("comments/attachments/{$reply->id}", $disk);
|
$path = $file->store("comments/attachments/{$reply->id}", $disk);
|
||||||
@@ -169,7 +169,7 @@ class CommentItem extends Component
|
|||||||
return $resolver->search($query)
|
return $resolver->search($query)
|
||||||
->map(fn ($user) => [
|
->map(fn ($user) => [
|
||||||
'id' => $user->getKey(),
|
'id' => $user->getKey(),
|
||||||
'name' => $user->getCommentName(),
|
'name' => $user->getCommentDisplayName(),
|
||||||
'avatar_url' => $user->getCommentAvatarUrl(),
|
'avatar_url' => $user->getCommentAvatarUrl(),
|
||||||
])
|
])
|
||||||
->values()
|
->values()
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ use Livewire\Attributes\Computed;
|
|||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
||||||
use Livewire\WithFileUploads;
|
use Livewire\WithFileUploads;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\CommentSubscription;
|
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Contracts\MentionResolver;
|
use Relaticle\Comments\Contracts\MentionResolver;
|
||||||
use Relaticle\Comments\Events\CommentCreated;
|
use Relaticle\Comments\Events\CommentCreated;
|
||||||
use Relaticle\Comments\Mentions\MentionParser;
|
use Relaticle\Comments\Mentions\MentionParser;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
use Relaticle\Comments\Models\Subscription;
|
||||||
|
|
||||||
class Comments extends Component
|
class Comments extends Component
|
||||||
{
|
{
|
||||||
@@ -36,7 +36,7 @@ class Comments extends Component
|
|||||||
public function mount(Model $model): void
|
public function mount(Model $model): void
|
||||||
{
|
{
|
||||||
$this->model = $model;
|
$this->model = $model;
|
||||||
$this->perPage = Config::getPerPage();
|
$this->perPage = CommentsConfig::getPerPage();
|
||||||
$this->loadedCount = $this->perPage;
|
$this->loadedCount = $this->perPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ class Comments extends Component
|
|||||||
{
|
{
|
||||||
return $this->model
|
return $this->model
|
||||||
->topLevelComments()
|
->topLevelComments()
|
||||||
->with(['user', 'mentions', 'attachments', 'reactions.user', 'replies.user', 'replies.mentions', 'replies.attachments', 'replies.reactions.user'])
|
->with(['commenter', 'mentions', 'attachments', 'reactions.commenter', 'replies.commenter', 'replies.mentions', 'replies.attachments', 'replies.reactions.commenter'])
|
||||||
->orderBy('created_at', $this->sortDirection)
|
->orderBy('created_at', $this->sortDirection)
|
||||||
->take($this->loadedCount)
|
->take($this->loadedCount)
|
||||||
->get();
|
->get();
|
||||||
@@ -67,27 +67,27 @@ class Comments extends Component
|
|||||||
#[Computed]
|
#[Computed]
|
||||||
public function isSubscribed(): bool
|
public function isSubscribed(): bool
|
||||||
{
|
{
|
||||||
$user = Config::resolveAuthenticatedUser();
|
$user = CommentsConfig::resolveAuthenticatedUser();
|
||||||
|
|
||||||
if (! $user) {
|
if (! $user) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CommentSubscription::isSubscribed($this->model, $user);
|
return Subscription::isSubscribed($this->model, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toggleSubscription(): void
|
public function toggleSubscription(): void
|
||||||
{
|
{
|
||||||
$user = Config::resolveAuthenticatedUser();
|
$user = CommentsConfig::resolveAuthenticatedUser();
|
||||||
|
|
||||||
if (! $user) {
|
if (! $user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isSubscribed) {
|
if ($this->isSubscribed) {
|
||||||
CommentSubscription::unsubscribe($this->model, $user);
|
Subscription::unsubscribe($this->model, $user);
|
||||||
} else {
|
} else {
|
||||||
CommentSubscription::subscribe($this->model, $user);
|
Subscription::subscribe($this->model, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($this->isSubscribed);
|
unset($this->isSubscribed);
|
||||||
@@ -97,26 +97,26 @@ class Comments extends Component
|
|||||||
{
|
{
|
||||||
$rules = ['newComment' => ['required', 'string', 'min:1']];
|
$rules = ['newComment' => ['required', 'string', 'min:1']];
|
||||||
|
|
||||||
if (Config::areAttachmentsEnabled()) {
|
if (CommentsConfig::areAttachmentsEnabled()) {
|
||||||
$maxSize = Config::getAttachmentMaxSize();
|
$maxSize = CommentsConfig::getAttachmentMaxSize();
|
||||||
$allowedTypes = implode(',', Config::getAttachmentAllowedTypes());
|
$allowedTypes = implode(',', CommentsConfig::getAttachmentAllowedTypes());
|
||||||
$rules['attachments.*'] = ['nullable', 'file', "max:{$maxSize}", "mimetypes:{$allowedTypes}"];
|
$rules['attachments.*'] = ['nullable', 'file', "max:{$maxSize}", "mimetypes:{$allowedTypes}"];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->validate($rules);
|
$this->validate($rules);
|
||||||
|
|
||||||
$this->authorize('create', Config::getCommentModel());
|
$this->authorize('create', CommentsConfig::getCommentModel());
|
||||||
|
|
||||||
$user = Config::resolveAuthenticatedUser();
|
$user = CommentsConfig::resolveAuthenticatedUser();
|
||||||
|
|
||||||
$comment = $this->model->comments()->create([
|
$comment = $this->model->comments()->create([
|
||||||
'body' => $this->newComment,
|
'body' => $this->newComment,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (Config::areAttachmentsEnabled() && ! empty($this->attachments)) {
|
if (CommentsConfig::areAttachmentsEnabled() && ! empty($this->attachments)) {
|
||||||
$disk = Config::getAttachmentDisk();
|
$disk = CommentsConfig::getAttachmentDisk();
|
||||||
|
|
||||||
foreach ($this->attachments as $file) {
|
foreach ($this->attachments as $file) {
|
||||||
$path = $file->store("comments/attachments/{$comment->id}", $disk);
|
$path = $file->store("comments/attachments/{$comment->id}", $disk);
|
||||||
@@ -163,8 +163,8 @@ class Comments extends Component
|
|||||||
'commentUpdated' => 'refreshComments',
|
'commentUpdated' => 'refreshComments',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Config::isBroadcastingEnabled()) {
|
if (CommentsConfig::isBroadcastingEnabled()) {
|
||||||
$prefix = Config::getBroadcastChannelPrefix();
|
$prefix = CommentsConfig::getBroadcastChannelPrefix();
|
||||||
$type = $this->model->getMorphClass();
|
$type = $this->model->getMorphClass();
|
||||||
$id = $this->model->getKey();
|
$id = $this->model->getKey();
|
||||||
$channel = "echo-private:{$prefix}.{$type}.{$id}";
|
$channel = "echo-private:{$prefix}.{$type}.{$id}";
|
||||||
@@ -195,7 +195,7 @@ class Comments extends Component
|
|||||||
return $resolver->search($query)
|
return $resolver->search($query)
|
||||||
->map(fn ($user) => [
|
->map(fn ($user) => [
|
||||||
'id' => $user->getKey(),
|
'id' => $user->getKey(),
|
||||||
'name' => $user->getCommentName(),
|
'name' => $user->getCommentDisplayName(),
|
||||||
'avatar_url' => $user->getCommentAvatarUrl(),
|
'avatar_url' => $user->getCommentAvatarUrl(),
|
||||||
])
|
])
|
||||||
->values()
|
->values()
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ namespace Relaticle\Comments\Livewire;
|
|||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Livewire\Attributes\Computed;
|
use Livewire\Attributes\Computed;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Events\CommentReacted;
|
use Relaticle\Comments\Events\CommentReacted;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class Reactions extends Component
|
class Reactions extends Component
|
||||||
{
|
{
|
||||||
@@ -22,19 +22,19 @@ class Reactions extends Component
|
|||||||
|
|
||||||
public function toggleReaction(string $reaction): void
|
public function toggleReaction(string $reaction): void
|
||||||
{
|
{
|
||||||
$user = Config::resolveAuthenticatedUser();
|
$user = CommentsConfig::resolveAuthenticatedUser();
|
||||||
|
|
||||||
if (! $user) {
|
if (! $user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! in_array($reaction, Config::getAllowedReactions())) {
|
if (! in_array($reaction, CommentsConfig::getAllowedReactions())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$existing = $this->comment->reactions()
|
$existing = $this->comment->reactions()
|
||||||
->where('user_id', $user->getKey())
|
->where('commenter_id', $user->getKey())
|
||||||
->where('user_type', $user->getMorphClass())
|
->where('commenter_type', $user->getMorphClass())
|
||||||
->where('reaction', $reaction)
|
->where('reaction', $reaction)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
@@ -44,8 +44,8 @@ class Reactions extends Component
|
|||||||
event(new CommentReacted($this->comment, $user, $reaction, 'removed'));
|
event(new CommentReacted($this->comment, $user, $reaction, 'removed'));
|
||||||
} else {
|
} else {
|
||||||
$this->comment->reactions()->create([
|
$this->comment->reactions()->create([
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => $reaction,
|
'reaction' => $reaction,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -66,13 +66,13 @@ class Reactions extends Component
|
|||||||
#[Computed]
|
#[Computed]
|
||||||
public function reactionSummary(): array
|
public function reactionSummary(): array
|
||||||
{
|
{
|
||||||
$user = Config::resolveAuthenticatedUser();
|
$user = CommentsConfig::resolveAuthenticatedUser();
|
||||||
$userId = $user?->getKey();
|
$userId = $user?->getKey();
|
||||||
$userType = $user?->getMorphClass();
|
$userType = $user?->getMorphClass();
|
||||||
|
|
||||||
$reactions = $this->comment->reactions()->with('user')->get();
|
$reactions = $this->comment->reactions()->with('commenter')->get();
|
||||||
|
|
||||||
$emojiSet = Config::getReactionEmojiSet();
|
$emojiSet = CommentsConfig::getReactionEmojiSet();
|
||||||
|
|
||||||
return $reactions
|
return $reactions
|
||||||
->groupBy('reaction')
|
->groupBy('reaction')
|
||||||
@@ -81,10 +81,10 @@ class Reactions extends Component
|
|||||||
'reaction' => $key,
|
'reaction' => $key,
|
||||||
'emoji' => $emojiSet[$key] ?? $key,
|
'emoji' => $emojiSet[$key] ?? $key,
|
||||||
'count' => $group->count(),
|
'count' => $group->count(),
|
||||||
'names' => $group->pluck('user.name')->filter()->take(3)->values()->all(),
|
'names' => $group->pluck('commenter.name')->filter()->take(3)->values()->all(),
|
||||||
'total_reactors' => $group->count(),
|
'total_reactors' => $group->count(),
|
||||||
'reacted_by_user' => $group->contains(
|
'reacted_by_user' => $group->contains(
|
||||||
fn ($r) => $r->user_id == $userId && $r->user_type === $userType
|
fn ($r) => $r->commenter_id == $userId && $r->commenter_type === $userType
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace Relaticle\Comments\Mentions;
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Contracts\MentionResolver;
|
use Relaticle\Comments\Contracts\MentionResolver;
|
||||||
|
|
||||||
class DefaultMentionResolver implements MentionResolver
|
class DefaultMentionResolver implements MentionResolver
|
||||||
@@ -12,18 +12,18 @@ class DefaultMentionResolver implements MentionResolver
|
|||||||
/** @return Collection<int, Model> */
|
/** @return Collection<int, Model> */
|
||||||
public function search(string $query): Collection
|
public function search(string $query): Collection
|
||||||
{
|
{
|
||||||
$model = Config::getCommenterModel();
|
$model = CommentsConfig::getCommenterModel();
|
||||||
|
|
||||||
return $model::query()
|
return $model::query()
|
||||||
->where('name', 'like', "{$query}%")
|
->where('name', 'like', "{$query}%")
|
||||||
->limit(Config::getMentionMaxResults())
|
->limit(CommentsConfig::getMentionMaxResults())
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return Collection<int, Model> */
|
/** @return Collection<int, Model> */
|
||||||
public function resolveByNames(array $names): Collection
|
public function resolveByNames(array $names): Collection
|
||||||
{
|
{
|
||||||
$model = Config::getCommenterModel();
|
$model = CommentsConfig::getCommenterModel();
|
||||||
|
|
||||||
return $model::query()
|
return $model::query()
|
||||||
->whereIn('name', $names)
|
->whereIn('name', $names)
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
namespace Relaticle\Comments\Mentions;
|
namespace Relaticle\Comments\Mentions;
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Contracts\MentionResolver;
|
use Relaticle\Comments\Contracts\MentionResolver;
|
||||||
use Relaticle\Comments\Events\UserMentioned;
|
use Relaticle\Comments\Events\UserMentioned;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class MentionParser
|
class MentionParser
|
||||||
{
|
{
|
||||||
@@ -33,13 +33,13 @@ class MentionParser
|
|||||||
public function syncMentions(Comment $comment): void
|
public function syncMentions(Comment $comment): void
|
||||||
{
|
{
|
||||||
$newMentionIds = $this->parse($comment->body);
|
$newMentionIds = $this->parse($comment->body);
|
||||||
$existingMentionIds = $comment->mentions()->pluck('comment_mentions.user_id');
|
$existingMentionIds = $comment->mentions()->pluck('comment_mentions.commenter_id');
|
||||||
|
|
||||||
$addedIds = $newMentionIds->diff($existingMentionIds);
|
$addedIds = $newMentionIds->diff($existingMentionIds);
|
||||||
|
|
||||||
$comment->mentions()->sync($newMentionIds->all());
|
$comment->mentions()->sync($newMentionIds->all());
|
||||||
|
|
||||||
$commenterModel = Config::getCommenterModel();
|
$commenterModel = CommentsConfig::getCommenterModel();
|
||||||
|
|
||||||
$addedIds->each(function ($userId) use ($comment, $commenterModel) {
|
$addedIds->each(function ($userId) use ($comment, $commenterModel) {
|
||||||
$mentionedUser = $commenterModel::find($userId);
|
$mentionedUser = $commenterModel::find($userId);
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Relaticle\Comments;
|
namespace Relaticle\Comments\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Number;
|
use Illuminate\Support\Number;
|
||||||
|
use Relaticle\Comments\CommentsConfig;
|
||||||
|
|
||||||
class CommentAttachment extends Model
|
class Attachment extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'comment_id',
|
'comment_id',
|
||||||
@@ -20,12 +21,12 @@ class CommentAttachment extends Model
|
|||||||
|
|
||||||
public function getTable(): string
|
public function getTable(): string
|
||||||
{
|
{
|
||||||
return 'comment_attachments';
|
return CommentsConfig::getTableName('attachments');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function comment(): BelongsTo
|
public function comment(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Config::getCommentModel());
|
return $this->belongsTo(CommentsConfig::getCommentModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isImage(): bool
|
public function isImage(): bool
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Relaticle\Comments;
|
namespace Relaticle\Comments\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
@@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|||||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Database\Factories\CommentFactory;
|
use Relaticle\Comments\Database\Factories\CommentFactory;
|
||||||
|
|
||||||
class Comment extends Model
|
class Comment extends Model
|
||||||
@@ -35,14 +36,14 @@ class Comment extends Model
|
|||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'body',
|
'body',
|
||||||
'parent_id',
|
'parent_id',
|
||||||
'user_id',
|
'commenter_id',
|
||||||
'user_type',
|
'commenter_type',
|
||||||
'edited_at',
|
'edited_at',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getTable(): string
|
public function getTable(): string
|
||||||
{
|
{
|
||||||
return Config::getCommentTable();
|
return CommentsConfig::getCommentTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, string> */
|
/** @return array<string, string> */
|
||||||
@@ -63,39 +64,39 @@ class Comment extends Model
|
|||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function user(): MorphTo
|
public function commenter(): MorphTo
|
||||||
{
|
{
|
||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function parent(): BelongsTo
|
public function parent(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Config::getCommentModel(), 'parent_id');
|
return $this->belongsTo(CommentsConfig::getCommentModel(), 'parent_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function replies(): HasMany
|
public function replies(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Config::getCommentModel(), 'parent_id');
|
return $this->hasMany(CommentsConfig::getCommentModel(), 'parent_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reactions(): HasMany
|
public function reactions(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(CommentReaction::class);
|
return $this->hasMany(Reaction::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function attachments(): HasMany
|
public function attachments(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(CommentAttachment::class);
|
return $this->hasMany(Attachment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mentions(): MorphToMany
|
public function mentions(): MorphToMany
|
||||||
{
|
{
|
||||||
return $this->morphedByMany(
|
return $this->morphedByMany(
|
||||||
Config::getCommenterModel(),
|
CommentsConfig::getCommenterModel(),
|
||||||
'user',
|
'commenter',
|
||||||
'comment_mentions',
|
CommentsConfig::getTableName('mentions'),
|
||||||
'comment_id',
|
'comment_id',
|
||||||
'user_id',
|
'commenter_id',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ class Comment extends Model
|
|||||||
|
|
||||||
public function canReply(): bool
|
public function canReply(): bool
|
||||||
{
|
{
|
||||||
return $this->depth() < Config::getMaxDepth();
|
return $this->depth() < CommentsConfig::getMaxDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function depth(): int
|
public function depth(): int
|
||||||
@@ -133,8 +134,8 @@ class Comment extends Model
|
|||||||
$comment = $comment->parent;
|
$comment = $comment->parent;
|
||||||
$depth++;
|
$depth++;
|
||||||
|
|
||||||
if ($depth >= Config::getMaxDepth()) {
|
if ($depth >= CommentsConfig::getMaxDepth()) {
|
||||||
return Config::getMaxDepth();
|
return CommentsConfig::getMaxDepth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,31 +1,32 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Relaticle\Comments;
|
namespace Relaticle\Comments\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
|
use Relaticle\Comments\CommentsConfig;
|
||||||
|
|
||||||
class CommentReaction extends Model
|
class Reaction extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'comment_id',
|
'comment_id',
|
||||||
'user_id',
|
'commenter_id',
|
||||||
'user_type',
|
'commenter_type',
|
||||||
'reaction',
|
'reaction',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getTable(): string
|
public function getTable(): string
|
||||||
{
|
{
|
||||||
return 'comment_reactions';
|
return CommentsConfig::getTableName('reactions');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function comment(): BelongsTo
|
public function comment(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Config::getCommentModel());
|
return $this->belongsTo(CommentsConfig::getCommentModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function user(): MorphTo
|
public function commenter(): MorphTo
|
||||||
{
|
{
|
||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Relaticle\Comments;
|
namespace Relaticle\Comments\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Relaticle\Comments\CommentsConfig;
|
||||||
|
|
||||||
class CommentSubscription extends Model
|
class Subscription extends Model
|
||||||
{
|
{
|
||||||
public const UPDATED_AT = null;
|
public const UPDATED_AT = null;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'commentable_type',
|
'commentable_type',
|
||||||
'commentable_id',
|
'commentable_id',
|
||||||
'user_type',
|
'commenter_type',
|
||||||
'user_id',
|
'commenter_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getTable(): string
|
public function getTable(): string
|
||||||
{
|
{
|
||||||
return 'comment_subscriptions';
|
return CommentsConfig::getTableName('subscriptions');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function commentable(): MorphTo
|
public function commentable(): MorphTo
|
||||||
@@ -27,7 +28,7 @@ class CommentSubscription extends Model
|
|||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function user(): MorphTo
|
public function commenter(): MorphTo
|
||||||
{
|
{
|
||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
}
|
}
|
||||||
@@ -37,8 +38,8 @@ class CommentSubscription extends Model
|
|||||||
return static::where([
|
return static::where([
|
||||||
'commentable_type' => $commentable->getMorphClass(),
|
'commentable_type' => $commentable->getMorphClass(),
|
||||||
'commentable_id' => $commentable->getKey(),
|
'commentable_id' => $commentable->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
])->exists();
|
])->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,8 +48,8 @@ class CommentSubscription extends Model
|
|||||||
static::firstOrCreate([
|
static::firstOrCreate([
|
||||||
'commentable_type' => $commentable->getMorphClass(),
|
'commentable_type' => $commentable->getMorphClass(),
|
||||||
'commentable_id' => $commentable->getKey(),
|
'commentable_id' => $commentable->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,8 +58,8 @@ class CommentSubscription extends Model
|
|||||||
static::where([
|
static::where([
|
||||||
'commentable_type' => $commentable->getMorphClass(),
|
'commentable_type' => $commentable->getMorphClass(),
|
||||||
'commentable_id' => $commentable->getKey(),
|
'commentable_id' => $commentable->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
])->delete();
|
])->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +69,6 @@ class CommentSubscription extends Model
|
|||||||
return static::where([
|
return static::where([
|
||||||
'commentable_type' => $commentable->getMorphClass(),
|
'commentable_type' => $commentable->getMorphClass(),
|
||||||
'commentable_id' => $commentable->getKey(),
|
'commentable_id' => $commentable->getKey(),
|
||||||
])->with('user')->get()->pluck('user')->filter()->values();
|
])->with('commenter')->get()->pluck('commenter')->filter()->values();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,8 +5,8 @@ namespace Relaticle\Comments\Notifications;
|
|||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentRepliedNotification extends Notification
|
class CommentRepliedNotification extends Notification
|
||||||
{
|
{
|
||||||
@@ -15,7 +15,7 @@ class CommentRepliedNotification extends Notification
|
|||||||
/** @return array<int, string> */
|
/** @return array<int, string> */
|
||||||
public function via(mixed $notifiable): array
|
public function via(mixed $notifiable): array
|
||||||
{
|
{
|
||||||
return Config::getNotificationChannels();
|
return CommentsConfig::getNotificationChannels();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
@@ -25,14 +25,14 @@ class CommentRepliedNotification extends Notification
|
|||||||
'comment_id' => $this->comment->id,
|
'comment_id' => $this->comment->id,
|
||||||
'commentable_type' => $this->comment->commentable_type,
|
'commentable_type' => $this->comment->commentable_type,
|
||||||
'commentable_id' => $this->comment->commentable_id,
|
'commentable_id' => $this->comment->commentable_id,
|
||||||
'commenter_name' => $this->comment->user->getCommentName(),
|
'commenter_name' => $this->comment->commenter->getCommentDisplayName(),
|
||||||
'body' => Str::limit(strip_tags($this->comment->body), 100),
|
'body' => Str::limit(strip_tags($this->comment->body), 100),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toMail(mixed $notifiable): MailMessage
|
public function toMail(mixed $notifiable): MailMessage
|
||||||
{
|
{
|
||||||
$commenterName = $this->comment->user->getCommentName();
|
$commenterName = $this->comment->commenter->getCommentDisplayName();
|
||||||
|
|
||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject('New reply to your comment')
|
->subject('New reply to your comment')
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class UserMentionedNotification extends Notification
|
class UserMentionedNotification extends Notification
|
||||||
{
|
{
|
||||||
@@ -19,7 +19,7 @@ class UserMentionedNotification extends Notification
|
|||||||
/** @return array<int, string> */
|
/** @return array<int, string> */
|
||||||
public function via(mixed $notifiable): array
|
public function via(mixed $notifiable): array
|
||||||
{
|
{
|
||||||
return Config::getNotificationChannels();
|
return CommentsConfig::getNotificationChannels();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
@@ -29,14 +29,14 @@ class UserMentionedNotification extends Notification
|
|||||||
'comment_id' => $this->comment->id,
|
'comment_id' => $this->comment->id,
|
||||||
'commentable_type' => $this->comment->commentable_type,
|
'commentable_type' => $this->comment->commentable_type,
|
||||||
'commentable_id' => $this->comment->commentable_id,
|
'commentable_id' => $this->comment->commentable_id,
|
||||||
'mentioner_name' => $this->mentionedBy->getCommentName(),
|
'mentioner_name' => $this->mentionedBy->getCommentDisplayName(),
|
||||||
'body' => Str::limit(strip_tags($this->comment->body), 100),
|
'body' => Str::limit(strip_tags($this->comment->body), 100),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toMail(mixed $notifiable): MailMessage
|
public function toMail(mixed $notifiable): MailMessage
|
||||||
{
|
{
|
||||||
$mentionerName = $this->mentionedBy->getCommentName();
|
$mentionerName = $this->mentionedBy->getCommentDisplayName();
|
||||||
|
|
||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject('You were mentioned in a comment')
|
->subject('You were mentioned in a comment')
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace Relaticle\Comments\Policies;
|
namespace Relaticle\Comments\Policies;
|
||||||
|
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentPolicy
|
class CommentPolicy
|
||||||
{
|
{
|
||||||
@@ -19,14 +19,14 @@ class CommentPolicy
|
|||||||
|
|
||||||
public function update(Authenticatable $user, Comment $comment): bool
|
public function update(Authenticatable $user, Comment $comment): bool
|
||||||
{
|
{
|
||||||
return $user->getKey() === $comment->user_id
|
return $user->getKey() === $comment->commenter_id
|
||||||
&& $user->getMorphClass() === $comment->user_type;
|
&& $user->getMorphClass() === $comment->commenter_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Authenticatable $user, Comment $comment): bool
|
public function delete(Authenticatable $user, Comment $comment): bool
|
||||||
{
|
{
|
||||||
return $user->getKey() === $comment->user_id
|
return $user->getKey() === $comment->commenter_id
|
||||||
&& $user->getMorphClass() === $comment->user_type;
|
&& $user->getMorphClass() === $comment->commenter_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reply(Authenticatable $user, Comment $comment): bool
|
public function reply(Authenticatable $user, Comment $comment): bool
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\CommentAttachment;
|
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Livewire\CommentItem;
|
use Relaticle\Comments\Livewire\CommentItem;
|
||||||
use Relaticle\Comments\Livewire\Comments;
|
use Relaticle\Comments\Livewire\Comments;
|
||||||
|
use Relaticle\Comments\Models\Attachment;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ it('creates comment with file attachment via Livewire component', function () {
|
|||||||
->assertSet('attachments', []);
|
->assertSet('attachments', []);
|
||||||
|
|
||||||
expect(Comment::count())->toBe(1);
|
expect(Comment::count())->toBe(1);
|
||||||
expect(CommentAttachment::count())->toBe(1);
|
expect(Attachment::count())->toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('stores attachment with correct metadata', function () {
|
it('stores attachment with correct metadata', function () {
|
||||||
@@ -47,7 +47,7 @@ it('stores attachment with correct metadata', function () {
|
|||||||
->set('attachments', [$file])
|
->set('attachments', [$file])
|
||||||
->call('addComment');
|
->call('addComment');
|
||||||
|
|
||||||
$attachment = CommentAttachment::first();
|
$attachment = Attachment::first();
|
||||||
$comment = Comment::first();
|
$comment = Comment::first();
|
||||||
|
|
||||||
expect($attachment->original_name)->toBe('vacation.jpg')
|
expect($attachment->original_name)->toBe('vacation.jpg')
|
||||||
@@ -73,7 +73,7 @@ it('stores file on configured disk at comments/attachments/{comment_id}/ path',
|
|||||||
->set('attachments', [$file])
|
->set('attachments', [$file])
|
||||||
->call('addComment');
|
->call('addComment');
|
||||||
|
|
||||||
$attachment = CommentAttachment::first();
|
$attachment = Attachment::first();
|
||||||
|
|
||||||
Storage::disk('public')->assertExists($attachment->file_path);
|
Storage::disk('public')->assertExists($attachment->file_path);
|
||||||
expect($attachment->file_path)->toContain("comments/attachments/{$attachment->comment_id}/");
|
expect($attachment->file_path)->toContain("comments/attachments/{$attachment->comment_id}/");
|
||||||
@@ -88,15 +88,15 @@ it('displays image attachment thumbnail in comment item view', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Image comment</p>',
|
'body' => '<p>Image comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$file = UploadedFile::fake()->image('photo.jpg', 100, 100);
|
$file = UploadedFile::fake()->image('photo.jpg', 100, 100);
|
||||||
$path = $file->store("comments/attachments/{$comment->id}", 'public');
|
$path = $file->store("comments/attachments/{$comment->id}", 'public');
|
||||||
|
|
||||||
CommentAttachment::create([
|
Attachment::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'file_path' => $path,
|
'file_path' => $path,
|
||||||
'original_name' => 'photo.jpg',
|
'original_name' => 'photo.jpg',
|
||||||
@@ -123,15 +123,15 @@ it('displays non-image attachment as download link', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>PDF comment</p>',
|
'body' => '<p>PDF comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$file = UploadedFile::fake()->create('document.pdf', 2048, 'application/pdf');
|
$file = UploadedFile::fake()->create('document.pdf', 2048, 'application/pdf');
|
||||||
$path = $file->store("comments/attachments/{$comment->id}", 'public');
|
$path = $file->store("comments/attachments/{$comment->id}", 'public');
|
||||||
|
|
||||||
CommentAttachment::create([
|
Attachment::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'file_path' => $path,
|
'file_path' => $path,
|
||||||
'original_name' => 'document.pdf',
|
'original_name' => 'document.pdf',
|
||||||
@@ -157,7 +157,7 @@ it('rejects file exceeding max size', function () {
|
|||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
|
|
||||||
$oversizedFile = UploadedFile::fake()->create('big.pdf', Config::getAttachmentMaxSize() + 1, 'application/pdf');
|
$oversizedFile = UploadedFile::fake()->create('big.pdf', CommentsConfig::getAttachmentMaxSize() + 1, 'application/pdf');
|
||||||
|
|
||||||
Livewire::test(Comments::class, ['model' => $post])
|
Livewire::test(Comments::class, ['model' => $post])
|
||||||
->set('newComment', '<p>Oversized file</p>')
|
->set('newComment', '<p>Oversized file</p>')
|
||||||
@@ -166,7 +166,7 @@ it('rejects file exceeding max size', function () {
|
|||||||
->assertHasErrors('attachments.0');
|
->assertHasErrors('attachments.0');
|
||||||
|
|
||||||
expect(Comment::count())->toBe(0);
|
expect(Comment::count())->toBe(0);
|
||||||
expect(CommentAttachment::count())->toBe(0);
|
expect(Attachment::count())->toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects disallowed file type', function () {
|
it('rejects disallowed file type', function () {
|
||||||
@@ -186,7 +186,7 @@ it('rejects disallowed file type', function () {
|
|||||||
->assertHasErrors('attachments.0');
|
->assertHasErrors('attachments.0');
|
||||||
|
|
||||||
expect(Comment::count())->toBe(0);
|
expect(Comment::count())->toBe(0);
|
||||||
expect(CommentAttachment::count())->toBe(0);
|
expect(Attachment::count())->toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts allowed file types', function () {
|
it('accepts allowed file types', function () {
|
||||||
@@ -206,7 +206,7 @@ it('accepts allowed file types', function () {
|
|||||||
->assertHasNoErrors('attachments.0');
|
->assertHasNoErrors('attachments.0');
|
||||||
|
|
||||||
expect(Comment::count())->toBe(1);
|
expect(Comment::count())->toBe(1);
|
||||||
expect(CommentAttachment::count())->toBe(1);
|
expect(Attachment::count())->toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides upload UI when attachments disabled', function () {
|
it('hides upload UI when attachments disabled', function () {
|
||||||
@@ -248,9 +248,9 @@ it('creates comment with multiple file attachments', function () {
|
|||||||
->call('addComment');
|
->call('addComment');
|
||||||
|
|
||||||
expect(Comment::count())->toBe(1);
|
expect(Comment::count())->toBe(1);
|
||||||
expect(CommentAttachment::count())->toBe(2);
|
expect(Attachment::count())->toBe(2);
|
||||||
|
|
||||||
$attachments = CommentAttachment::all();
|
$attachments = Attachment::all();
|
||||||
expect($attachments->pluck('original_name')->toArray())
|
expect($attachments->pluck('original_name')->toArray())
|
||||||
->toContain('photo1.jpg')
|
->toContain('photo1.jpg')
|
||||||
->toContain('notes.pdf');
|
->toContain('notes.pdf');
|
||||||
@@ -265,8 +265,8 @@ it('creates reply with file attachment via CommentItem component', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Parent comment</p>',
|
'body' => '<p>Parent comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
use Illuminate\Broadcasting\PrivateChannel;
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Events\CommentCreated;
|
use Relaticle\Comments\Events\CommentCreated;
|
||||||
use Relaticle\Comments\Events\CommentDeleted;
|
use Relaticle\Comments\Events\CommentDeleted;
|
||||||
use Relaticle\Comments\Events\CommentReacted;
|
use Relaticle\Comments\Events\CommentReacted;
|
||||||
use Relaticle\Comments\Events\CommentUpdated;
|
use Relaticle\Comments\Events\CommentUpdated;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -17,8 +17,8 @@ it('CommentCreated event implements ShouldBroadcast', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentCreated($comment);
|
$event = new CommentCreated($comment);
|
||||||
@@ -33,8 +33,8 @@ it('CommentUpdated event implements ShouldBroadcast', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentUpdated($comment);
|
$event = new CommentUpdated($comment);
|
||||||
@@ -49,8 +49,8 @@ it('CommentDeleted event implements ShouldBroadcast', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentDeleted($comment);
|
$event = new CommentDeleted($comment);
|
||||||
@@ -65,8 +65,8 @@ it('CommentReacted event implements ShouldBroadcast', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentReacted($comment, $user, 'thumbs_up', 'added');
|
$event = new CommentReacted($comment, $user, 'thumbs_up', 'added');
|
||||||
@@ -81,8 +81,8 @@ it('broadcastOn returns PrivateChannel with correct channel name', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentCreated($comment);
|
$event = new CommentCreated($comment);
|
||||||
@@ -100,8 +100,8 @@ it('broadcastWhen returns false when broadcasting is disabled', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentCreated($comment);
|
$event = new CommentCreated($comment);
|
||||||
@@ -118,8 +118,8 @@ it('broadcastWhen returns true when broadcasting is enabled', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentCreated($comment);
|
$event = new CommentCreated($comment);
|
||||||
@@ -134,8 +134,8 @@ it('broadcastWith returns array with comment_id for CommentCreated', function ()
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentCreated($comment);
|
$event = new CommentCreated($comment);
|
||||||
@@ -154,8 +154,8 @@ it('broadcastWith returns array with comment_id, reaction, and action for Commen
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentReacted($comment, $user, 'thumbs_up', 'added');
|
$event = new CommentReacted($comment, $user, 'thumbs_up', 'added');
|
||||||
@@ -176,8 +176,8 @@ it('uses custom channel prefix from config in broadcastOn', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$event = new CommentCreated($comment);
|
$event = new CommentCreated($comment);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\CommentAttachment;
|
use Relaticle\Comments\Models\Attachment;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -13,12 +13,12 @@ it('creates a comment attachment with all metadata fields', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test comment</p>',
|
'body' => '<p>Test comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$attachment = CommentAttachment::create([
|
$attachment = Attachment::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'file_path' => 'comments/attachments/1/photo.jpg',
|
'file_path' => 'comments/attachments/1/photo.jpg',
|
||||||
'original_name' => 'photo.jpg',
|
'original_name' => 'photo.jpg',
|
||||||
@@ -27,7 +27,7 @@ it('creates a comment attachment with all metadata fields', function () {
|
|||||||
'disk' => 'public',
|
'disk' => 'public',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($attachment)->toBeInstanceOf(CommentAttachment::class)
|
expect($attachment)->toBeInstanceOf(Attachment::class)
|
||||||
->and($attachment->file_path)->toBe('comments/attachments/1/photo.jpg')
|
->and($attachment->file_path)->toBe('comments/attachments/1/photo.jpg')
|
||||||
->and($attachment->original_name)->toBe('photo.jpg')
|
->and($attachment->original_name)->toBe('photo.jpg')
|
||||||
->and($attachment->mime_type)->toBe('image/jpeg')
|
->and($attachment->mime_type)->toBe('image/jpeg')
|
||||||
@@ -42,12 +42,12 @@ it('belongs to a comment via comment() relationship', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test</p>',
|
'body' => '<p>Test</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$attachment = CommentAttachment::create([
|
$attachment = Attachment::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'file_path' => 'comments/attachments/1/test.png',
|
'file_path' => 'comments/attachments/1/test.png',
|
||||||
'original_name' => 'test.png',
|
'original_name' => 'test.png',
|
||||||
@@ -67,12 +67,12 @@ it('has attachments() hasMany relationship on Comment', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test</p>',
|
'body' => '<p>Test</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentAttachment::create([
|
Attachment::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'file_path' => 'comments/attachments/1/file1.png',
|
'file_path' => 'comments/attachments/1/file1.png',
|
||||||
'original_name' => 'file1.png',
|
'original_name' => 'file1.png',
|
||||||
@@ -81,7 +81,7 @@ it('has attachments() hasMany relationship on Comment', function () {
|
|||||||
'disk' => 'public',
|
'disk' => 'public',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentAttachment::create([
|
Attachment::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'file_path' => 'comments/attachments/1/file2.pdf',
|
'file_path' => 'comments/attachments/1/file2.pdf',
|
||||||
'original_name' => 'file2.pdf',
|
'original_name' => 'file2.pdf',
|
||||||
@@ -91,7 +91,7 @@ it('has attachments() hasMany relationship on Comment', function () {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
expect($comment->attachments)->toHaveCount(2)
|
expect($comment->attachments)->toHaveCount(2)
|
||||||
->and($comment->attachments->first())->toBeInstanceOf(CommentAttachment::class);
|
->and($comment->attachments->first())->toBeInstanceOf(Attachment::class);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cascade deletes attachments when comment is force deleted', function () {
|
it('cascade deletes attachments when comment is force deleted', function () {
|
||||||
@@ -101,12 +101,12 @@ it('cascade deletes attachments when comment is force deleted', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test</p>',
|
'body' => '<p>Test</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentAttachment::create([
|
Attachment::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'file_path' => 'comments/attachments/1/photo.jpg',
|
'file_path' => 'comments/attachments/1/photo.jpg',
|
||||||
'original_name' => 'photo.jpg',
|
'original_name' => 'photo.jpg',
|
||||||
@@ -115,15 +115,15 @@ it('cascade deletes attachments when comment is force deleted', function () {
|
|||||||
'disk' => 'public',
|
'disk' => 'public',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(CommentAttachment::where('comment_id', $comment->id)->count())->toBe(1);
|
expect(Attachment::where('comment_id', $comment->id)->count())->toBe(1);
|
||||||
|
|
||||||
$comment->forceDelete();
|
$comment->forceDelete();
|
||||||
|
|
||||||
expect(CommentAttachment::where('comment_id', $comment->id)->count())->toBe(0);
|
expect(Attachment::where('comment_id', $comment->id)->count())->toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('correctly identifies image and non-image mime types via isImage()', function (string $mimeType, bool $expected) {
|
it('correctly identifies image and non-image mime types via isImage()', function (string $mimeType, bool $expected) {
|
||||||
$attachment = new CommentAttachment(['mime_type' => $mimeType]);
|
$attachment = new Attachment(['mime_type' => $mimeType]);
|
||||||
|
|
||||||
expect($attachment->isImage())->toBe($expected);
|
expect($attachment->isImage())->toBe($expected);
|
||||||
})->with([
|
})->with([
|
||||||
@@ -142,12 +142,12 @@ it('formats bytes into human-readable size via formattedSize()', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test</p>',
|
'body' => '<p>Test</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$attachment = CommentAttachment::create([
|
$attachment = Attachment::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'file_path' => 'comments/attachments/1/file.pdf',
|
'file_path' => 'comments/attachments/1/file.pdf',
|
||||||
'original_name' => 'file.pdf',
|
'original_name' => 'file.pdf',
|
||||||
@@ -160,15 +160,15 @@ it('formats bytes into human-readable size via formattedSize()', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns default attachment disk as public', function () {
|
it('returns default attachment disk as public', function () {
|
||||||
expect(Config::getAttachmentDisk())->toBe('public');
|
expect(CommentsConfig::getAttachmentDisk())->toBe('public');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns default attachment max size as 10240', function () {
|
it('returns default attachment max size as 10240', function () {
|
||||||
expect(Config::getAttachmentMaxSize())->toBe(10240);
|
expect(CommentsConfig::getAttachmentMaxSize())->toBe(10240);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns default allowed attachment types', function () {
|
it('returns default allowed attachment types', function () {
|
||||||
$allowedTypes = Config::getAttachmentAllowedTypes();
|
$allowedTypes = CommentsConfig::getAttachmentAllowedTypes();
|
||||||
|
|
||||||
expect($allowedTypes)->toBeArray()
|
expect($allowedTypes)->toBeArray()
|
||||||
->toContain('image/jpeg')
|
->toContain('image/jpeg')
|
||||||
@@ -181,17 +181,17 @@ it('respects custom config overrides for attachment settings', function () {
|
|||||||
config(['comments.attachments.max_size' => 5120]);
|
config(['comments.attachments.max_size' => 5120]);
|
||||||
config(['comments.attachments.allowed_types' => ['image/png']]);
|
config(['comments.attachments.allowed_types' => ['image/png']]);
|
||||||
|
|
||||||
expect(Config::getAttachmentDisk())->toBe('s3')
|
expect(CommentsConfig::getAttachmentDisk())->toBe('s3')
|
||||||
->and(Config::getAttachmentMaxSize())->toBe(5120)
|
->and(CommentsConfig::getAttachmentMaxSize())->toBe(5120)
|
||||||
->and(Config::getAttachmentAllowedTypes())->toBe(['image/png']);
|
->and(CommentsConfig::getAttachmentAllowedTypes())->toBe(['image/png']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reports attachments as enabled by default', function () {
|
it('reports attachments as enabled by default', function () {
|
||||||
expect(Config::areAttachmentsEnabled())->toBeTrue();
|
expect(CommentsConfig::areAttachmentsEnabled())->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('respects disabled attachments config', function () {
|
it('respects disabled attachments config', function () {
|
||||||
config(['comments.attachments.enabled' => false]);
|
config(['comments.attachments.enabled' => false]);
|
||||||
|
|
||||||
expect(Config::areAttachmentsEnabled())->toBeFalse();
|
expect(CommentsConfig::areAttachmentsEnabled())->toBeFalse();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Events\CommentCreated;
|
use Relaticle\Comments\Events\CommentCreated;
|
||||||
use Relaticle\Comments\Events\CommentDeleted;
|
use Relaticle\Comments\Events\CommentDeleted;
|
||||||
use Relaticle\Comments\Events\CommentUpdated;
|
use Relaticle\Comments\Events\CommentUpdated;
|
||||||
use Relaticle\Comments\Livewire\CommentItem;
|
use Relaticle\Comments\Livewire\CommentItem;
|
||||||
use Relaticle\Comments\Livewire\Comments;
|
use Relaticle\Comments\Livewire\Comments;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -38,8 +38,8 @@ it('fires CommentUpdated event when editing a comment', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Original</p>',
|
'body' => '<p>Original</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -64,8 +64,8 @@ it('fires CommentDeleted event when deleting a comment', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -87,8 +87,8 @@ it('fires CommentCreated event when adding a reply', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -119,6 +119,6 @@ it('carries correct comment and commentable in event payload', function () {
|
|||||||
Event::assertDispatched(CommentCreated::class, function (CommentCreated $event) use ($post, $user) {
|
Event::assertDispatched(CommentCreated::class, function (CommentCreated $event) use ($post, $user) {
|
||||||
return $event->comment instanceof Comment
|
return $event->comment instanceof Comment
|
||||||
&& $event->commentable->id === $post->id
|
&& $event->commentable->id === $post->id
|
||||||
&& $event->comment->user_id === $user->id;
|
&& $event->comment->commenter_id === $user->id;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Livewire\CommentItem;
|
use Relaticle\Comments\Livewire\CommentItem;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -13,8 +13,8 @@ it('allows author to start and save edit on their comment', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Original body</p>',
|
'body' => '<p>Original body</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -42,8 +42,8 @@ it('marks edited comment with edited indicator', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Original</p>',
|
'body' => '<p>Original</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -70,8 +70,8 @@ it('prevents non-author from editing a comment', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Author comment</p>',
|
'body' => '<p>Author comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -89,8 +89,8 @@ it('allows author to delete their own comment', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -108,8 +108,8 @@ it('preserves replies when parent comment is deleted', function () {
|
|||||||
$attrs = [
|
$attrs = [
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$parent = Comment::factory()->create($attrs);
|
$parent = Comment::factory()->create($attrs);
|
||||||
@@ -133,8 +133,8 @@ it('prevents non-author from deleting a comment', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($otherUser);
|
$this->actingAs($otherUser);
|
||||||
@@ -151,8 +151,8 @@ it('allows user to reply to a comment', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -169,7 +169,7 @@ it('allows user to reply to a comment', function () {
|
|||||||
|
|
||||||
expect($reply)->not->toBeNull();
|
expect($reply)->not->toBeNull();
|
||||||
expect($reply->body)->toBe('<p>My reply</p>');
|
expect($reply->body)->toBe('<p>My reply</p>');
|
||||||
expect($reply->user_id)->toBe($user->id);
|
expect($reply->commenter_id)->toBe($user->id);
|
||||||
expect($reply->commentable_id)->toBe($post->id);
|
expect($reply->commentable_id)->toBe($post->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -179,8 +179,8 @@ it('respects max depth for replies', function () {
|
|||||||
$attrs = [
|
$attrs = [
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
];
|
];
|
||||||
|
|
||||||
config(['comments.threading.max_depth' => 1]);
|
config(['comments.threading.max_depth' => 1]);
|
||||||
@@ -202,8 +202,8 @@ it('resets state when cancelling edit', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Some body</p>',
|
'body' => '<p>Some body</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -224,8 +224,8 @@ it('resets state when cancelling reply', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -245,14 +245,14 @@ it('loads all replies within a thread eagerly', function () {
|
|||||||
$attrs = [
|
$attrs = [
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$parent = Comment::factory()->create($attrs);
|
$parent = Comment::factory()->create($attrs);
|
||||||
Comment::factory()->count(3)->withParent($parent)->create($attrs);
|
Comment::factory()->count(3)->withParent($parent)->create($attrs);
|
||||||
|
|
||||||
$parentWithReplies = Comment::with('replies.user')->find($parent->id);
|
$parentWithReplies = Comment::with('replies.commenter')->find($parent->id);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\CommentReaction;
|
|
||||||
use Relaticle\Comments\Events\CommentReacted;
|
use Relaticle\Comments\Events\CommentReacted;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
use Relaticle\Comments\Models\Reaction;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -14,15 +14,15 @@ it('belongs to a comment via comment() relationship', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test</p>',
|
'body' => '<p>Test</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reaction = CommentReaction::create([
|
$reaction = Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -30,27 +30,27 @@ it('belongs to a comment via comment() relationship', function () {
|
|||||||
->and($reaction->comment->id)->toBe($comment->id);
|
->and($reaction->comment->id)->toBe($comment->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('belongs to a user via polymorphic user() relationship', function () {
|
it('belongs to a commenter via polymorphic commenter() relationship', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test</p>',
|
'body' => '<p>Test</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reaction = CommentReaction::create([
|
$reaction = Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'heart',
|
'reaction' => 'heart',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($reaction->user)->toBeInstanceOf(User::class)
|
expect($reaction->commenter)->toBeInstanceOf(User::class)
|
||||||
->and($reaction->user->id)->toBe($user->id);
|
->and($reaction->commenter->id)->toBe($user->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('prevents duplicate reactions with unique constraint', function () {
|
it('prevents duplicate reactions with unique constraint', function () {
|
||||||
@@ -60,22 +60,22 @@ it('prevents duplicate reactions with unique constraint', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test</p>',
|
'body' => '<p>Test</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentReaction::create([
|
Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(fn () => CommentReaction::create([
|
expect(fn () => Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
]))->toThrow(QueryException::class);
|
]))->toThrow(QueryException::class);
|
||||||
});
|
});
|
||||||
@@ -87,8 +87,8 @@ it('carries comment, user, reaction key, and action in CommentReacted event', fu
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Test</p>',
|
'body' => '<p>Test</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\CommentSubscription;
|
use Relaticle\Comments\Models\Subscription;
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -10,98 +9,98 @@ it('has commentable morphTo relationship', function () {
|
|||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
$subscription = CommentSubscription::create([
|
$subscription = Subscription::create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($subscription->commentable)->toBeInstanceOf(Post::class)
|
expect($subscription->commentable)->toBeInstanceOf(Post::class)
|
||||||
->and($subscription->commentable->id)->toBe($post->id);
|
->and($subscription->commentable->id)->toBe($post->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has user morphTo relationship', function () {
|
it('has commenter morphTo relationship', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
$subscription = CommentSubscription::create([
|
$subscription = Subscription::create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($subscription->user)->toBeInstanceOf(User::class)
|
expect($subscription->commenter)->toBeInstanceOf(User::class)
|
||||||
->and($subscription->user->id)->toBe($user->id);
|
->and($subscription->commenter->id)->toBe($user->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns database as default notification channel', function () {
|
it('returns database as default notification channel', function () {
|
||||||
expect(Config::getNotificationChannels())->toBe(['database']);
|
expect(CommentsConfig::getNotificationChannels())->toBe(['database']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns custom channels when configured', function () {
|
it('returns custom channels when configured', function () {
|
||||||
config()->set('comments.notifications.channels', ['database', 'mail']);
|
config()->set('comments.notifications.channels', ['database', 'mail']);
|
||||||
|
|
||||||
expect(Config::getNotificationChannels())->toBe(['database', 'mail']);
|
expect(CommentsConfig::getNotificationChannels())->toBe(['database', 'mail']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for shouldAutoSubscribe by default', function () {
|
it('returns true for shouldAutoSubscribe by default', function () {
|
||||||
expect(Config::shouldAutoSubscribe())->toBeTrue();
|
expect(CommentsConfig::shouldAutoSubscribe())->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false for shouldAutoSubscribe when configured', function () {
|
it('returns false for shouldAutoSubscribe when configured', function () {
|
||||||
config()->set('comments.subscriptions.auto_subscribe', false);
|
config()->set('comments.subscriptions.auto_subscribe', false);
|
||||||
|
|
||||||
expect(Config::shouldAutoSubscribe())->toBeFalse();
|
expect(CommentsConfig::shouldAutoSubscribe())->toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('checks if user is subscribed to a commentable via isSubscribed()', function () {
|
it('checks if user is subscribed to a commentable via isSubscribed()', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $user))->toBeFalse();
|
expect(Subscription::isSubscribed($post, $user))->toBeFalse();
|
||||||
|
|
||||||
CommentSubscription::create([
|
Subscription::create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $user))->toBeTrue();
|
expect(Subscription::isSubscribed($post, $user))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates subscription via subscribe() static method', function () {
|
it('creates subscription via subscribe() static method', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $user))->toBeTrue();
|
expect(Subscription::isSubscribed($post, $user))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('removes subscription via unsubscribe() static method', function () {
|
it('removes subscription via unsubscribe() static method', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
CommentSubscription::unsubscribe($post, $user);
|
Subscription::unsubscribe($post, $user);
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $user))->toBeFalse();
|
expect(Subscription::isSubscribed($post, $user))->toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is idempotent when subscribing twice', function () {
|
it('is idempotent when subscribing twice', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
|
|
||||||
expect(CommentSubscription::where([
|
expect(Subscription::where([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
])->count())->toBe(1);
|
])->count())->toBe(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -12,14 +12,14 @@ it('can be created with factory', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($comment)->toBeInstanceOf(Comment::class);
|
expect($comment)->toBeInstanceOf(Comment::class);
|
||||||
expect($comment->body)->toBeString();
|
expect($comment->body)->toBeString();
|
||||||
expect($comment->commentable_id)->toBe($post->id);
|
expect($comment->commentable_id)->toBe($post->id);
|
||||||
expect($comment->user_id)->toBe($user->id);
|
expect($comment->commenter_id)->toBe($user->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('belongs to a commentable model via morphTo', function () {
|
it('belongs to a commentable model via morphTo', function () {
|
||||||
@@ -29,27 +29,27 @@ it('belongs to a commentable model via morphTo', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($comment->commentable)->toBeInstanceOf(Post::class);
|
expect($comment->commentable)->toBeInstanceOf(Post::class);
|
||||||
expect($comment->commentable->id)->toBe($post->id);
|
expect($comment->commentable->id)->toBe($post->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('belongs to a user via morphTo', function () {
|
it('belongs to a commenter via morphTo', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($comment->user)->toBeInstanceOf(User::class);
|
expect($comment->commenter)->toBeInstanceOf(User::class);
|
||||||
expect($comment->user->id)->toBe($user->id);
|
expect($comment->commenter->id)->toBe($user->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports threading with parent and replies', function () {
|
it('supports threading with parent and replies', function () {
|
||||||
@@ -59,15 +59,15 @@ it('supports threading with parent and replies', function () {
|
|||||||
$parent = Comment::factory()->create([
|
$parent = Comment::factory()->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->withParent($parent)->create([
|
$reply = Comment::factory()->withParent($parent)->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($reply->parent->id)->toBe($parent->id);
|
expect($reply->parent->id)->toBe($parent->id);
|
||||||
@@ -82,15 +82,15 @@ it('identifies top-level vs reply comments', function () {
|
|||||||
$topLevel = Comment::factory()->create([
|
$topLevel = Comment::factory()->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->withParent($topLevel)->create([
|
$reply = Comment::factory()->withParent($topLevel)->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($topLevel->isTopLevel())->toBeTrue();
|
expect($topLevel->isTopLevel())->toBeTrue();
|
||||||
@@ -105,8 +105,8 @@ it('calculates depth correctly', function () {
|
|||||||
$attrs = [
|
$attrs = [
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
];
|
];
|
||||||
|
|
||||||
$level0 = Comment::factory()->create($attrs);
|
$level0 = Comment::factory()->create($attrs);
|
||||||
@@ -124,8 +124,8 @@ it('checks canReply based on max depth', function () {
|
|||||||
$attrs = [
|
$attrs = [
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
];
|
];
|
||||||
|
|
||||||
$level0 = Comment::factory()->create($attrs);
|
$level0 = Comment::factory()->create($attrs);
|
||||||
@@ -144,8 +144,8 @@ it('supports soft deletes', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$comment->delete();
|
$comment->delete();
|
||||||
@@ -162,8 +162,8 @@ it('tracks edited state', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($comment->isEdited())->toBeFalse();
|
expect($comment->isEdited())->toBeFalse();
|
||||||
@@ -171,8 +171,8 @@ it('tracks edited state', function () {
|
|||||||
$edited = Comment::factory()->edited()->create([
|
$edited = Comment::factory()->edited()->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($edited->isEdited())->toBeTrue();
|
expect($edited->isEdited())->toBeTrue();
|
||||||
@@ -185,8 +185,8 @@ it('detects when it has replies', function () {
|
|||||||
$attrs = [
|
$attrs = [
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
];
|
];
|
||||||
|
|
||||||
$parent = Comment::factory()->create($attrs);
|
$parent = Comment::factory()->create($attrs);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Filament\Actions\CommentsAction;
|
use Relaticle\Comments\Filament\Actions\CommentsAction;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -42,8 +42,8 @@ it('shows badge with comment count when comments exist', function () {
|
|||||||
Comment::factory()->count(3)->create([
|
Comment::factory()->count(3)->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$action = CommentsAction::make('comments');
|
$action = CommentsAction::make('comments');
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Livewire\Comments;
|
use Relaticle\Comments\Livewire\Comments;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -33,8 +33,8 @@ it('associates new comment with the authenticated user', function () {
|
|||||||
|
|
||||||
$comment = Comment::first();
|
$comment = Comment::first();
|
||||||
|
|
||||||
expect($comment->user_id)->toBe($user->id);
|
expect($comment->commenter_id)->toBe($user->id);
|
||||||
expect($comment->user_type)->toBe($user->getMorphClass());
|
expect($comment->commenter_type)->toBe($user->getMorphClass());
|
||||||
expect($comment->commentable_id)->toBe($post->id);
|
expect($comment->commentable_id)->toBe($post->id);
|
||||||
expect($comment->commentable_type)->toBe($post->getMorphClass());
|
expect($comment->commentable_type)->toBe($post->getMorphClass());
|
||||||
});
|
});
|
||||||
@@ -71,8 +71,8 @@ it('paginates top-level comments with load more', function () {
|
|||||||
Comment::factory()->count(12)->create([
|
Comment::factory()->count(12)->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -99,8 +99,8 @@ it('hides load more button when all comments are loaded', function () {
|
|||||||
Comment::factory()->count(5)->create([
|
Comment::factory()->count(5)->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -130,8 +130,8 @@ it('returns comments in correct sort order via computed property', function () {
|
|||||||
$older = Comment::factory()->create([
|
$older = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Older comment</p>',
|
'body' => '<p>Older comment</p>',
|
||||||
'created_at' => now()->subHour(),
|
'created_at' => now()->subHour(),
|
||||||
]);
|
]);
|
||||||
@@ -139,8 +139,8 @@ it('returns comments in correct sort order via computed property', function () {
|
|||||||
$newer = Comment::factory()->create([
|
$newer = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Newer comment</p>',
|
'body' => '<p>Newer comment</p>',
|
||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
]);
|
]);
|
||||||
@@ -167,8 +167,8 @@ it('displays total comment count', function () {
|
|||||||
Comment::factory()->count(3)->create([
|
Comment::factory()->count(3)->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Filament\Actions\CommentsTableAction;
|
use Relaticle\Comments\Filament\Actions\CommentsTableAction;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -30,8 +30,8 @@ it('shows badge with comment count for the record', function () {
|
|||||||
Comment::factory()->count(5)->create([
|
Comment::factory()->count(5)->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$action = CommentsTableAction::make('comments');
|
$action = CommentsTableAction::make('comments');
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Livewire\Comments;
|
use Relaticle\Comments\Livewire\Comments;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -13,8 +13,8 @@ it('strips script tags from comment body on create', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hello</p><script>alert(1)</script>',
|
'body' => '<p>Hello</p><script>alert(1)</script>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -29,8 +29,8 @@ it('strips event handler attributes from comment body', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<img onerror="alert(1)" src="x">',
|
'body' => '<img onerror="alert(1)" src="x">',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -45,8 +45,8 @@ it('strips style tags from comment body', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hi</p><style>body{display:none}</style>',
|
'body' => '<p>Hi</p><style>body{display:none}</style>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -61,8 +61,8 @@ it('strips iframe tags from comment body', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hi</p><iframe src="evil.com"></iframe>',
|
'body' => '<p>Hi</p><iframe src="evil.com"></iframe>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -85,8 +85,8 @@ it('preserves safe HTML formatting through sanitization', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => $safeHtml,
|
'body' => $safeHtml,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -108,8 +108,8 @@ it('sanitizes comment body on update', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Clean content</p>',
|
'body' => '<p>Clean content</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -130,8 +130,8 @@ it('strips javascript protocol from link href', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<a href="javascript:alert(1)">click me</a>',
|
'body' => '<a href="javascript:alert(1)">click me</a>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -146,8 +146,8 @@ it('strips onclick handler from elements', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<div onclick="alert(1)">click me</div>',
|
'body' => '<div onclick="alert(1)">click me</div>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ it('provides comments relationship on commentable model', function () {
|
|||||||
Comment::factory()->count(3)->create([
|
Comment::factory()->count(3)->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($post->comments)->toHaveCount(3);
|
expect($post->comments)->toHaveCount(3);
|
||||||
@@ -25,8 +25,8 @@ it('provides topLevelComments excluding replies', function () {
|
|||||||
$attrs = [
|
$attrs = [
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
];
|
];
|
||||||
|
|
||||||
$topLevel = Comment::factory()->create($attrs);
|
$topLevel = Comment::factory()->create($attrs);
|
||||||
@@ -46,8 +46,8 @@ it('provides comment count', function () {
|
|||||||
Comment::factory()->count(5)->create([
|
Comment::factory()->count(5)->create([
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($post->commentCount())->toBe(5);
|
expect($post->commentCount())->toBe(5);
|
||||||
@@ -61,15 +61,15 @@ it('scopes comments to the specific commentable', function () {
|
|||||||
Comment::factory()->count(3)->create([
|
Comment::factory()->count(3)->create([
|
||||||
'commentable_type' => $post1->getMorphClass(),
|
'commentable_type' => $post1->getMorphClass(),
|
||||||
'commentable_id' => $post1->id,
|
'commentable_id' => $post1->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Comment::factory()->count(2)->create([
|
Comment::factory()->count(2)->create([
|
||||||
'commentable_type' => $post2->getMorphClass(),
|
'commentable_type' => $post2->getMorphClass(),
|
||||||
'commentable_id' => $post2->id,
|
'commentable_id' => $post2->id,
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'user_id' => $user->id,
|
'commenter_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect($post1->commentCount())->toBe(3);
|
expect($post1->commentCount())->toBe(3);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Livewire\CommentItem;
|
use Relaticle\Comments\Livewire\CommentItem;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -14,12 +14,12 @@ it('renders mention with styled span', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>@Alice said hi</p>',
|
'body' => '<p>@Alice said hi</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$comment->mentions()->attach($alice->id, ['user_type' => $alice->getMorphClass()]);
|
$comment->mentions()->attach($alice->id, ['commenter_type' => $alice->getMorphClass()]);
|
||||||
|
|
||||||
$rendered = $comment->renderBodyWithMentions();
|
$rendered = $comment->renderBodyWithMentions();
|
||||||
|
|
||||||
@@ -36,13 +36,13 @@ it('renders multiple mentions with styled spans', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>@Alice and @Bob</p>',
|
'body' => '<p>@Alice and @Bob</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$comment->mentions()->attach($alice->id, ['user_type' => $alice->getMorphClass()]);
|
$comment->mentions()->attach($alice->id, ['commenter_type' => $alice->getMorphClass()]);
|
||||||
$comment->mentions()->attach($bob->id, ['user_type' => $bob->getMorphClass()]);
|
$comment->mentions()->attach($bob->id, ['commenter_type' => $bob->getMorphClass()]);
|
||||||
|
|
||||||
$rendered = $comment->renderBodyWithMentions();
|
$rendered = $comment->renderBodyWithMentions();
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ it('does not style non-mentioned @text', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>@ghost is not here</p>',
|
'body' => '<p>@ghost is not here</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -76,12 +76,12 @@ it('renders comment-mention class in Livewire component', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hello @Alice</p>',
|
'body' => '<p>Hello @Alice</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$comment->mentions()->attach($alice->id, ['user_type' => $alice->getMorphClass()]);
|
$comment->mentions()->attach($alice->id, ['commenter_type' => $alice->getMorphClass()]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Contracts\MentionResolver;
|
use Relaticle\Comments\Contracts\MentionResolver;
|
||||||
use Relaticle\Comments\Events\UserMentioned;
|
use Relaticle\Comments\Events\UserMentioned;
|
||||||
use Relaticle\Comments\Mentions\DefaultMentionResolver;
|
use Relaticle\Comments\Mentions\DefaultMentionResolver;
|
||||||
use Relaticle\Comments\Mentions\MentionParser;
|
use Relaticle\Comments\Mentions\MentionParser;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ it('stores mentions in comment_mentions table on create', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hello @john and @jane</p>',
|
'body' => '<p>Hello @john and @jane</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -85,8 +85,8 @@ it('dispatches UserMentioned event for each mentioned user', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hello @john and @jane</p>',
|
'body' => '<p>Hello @john and @jane</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -116,8 +116,8 @@ it('only dispatches UserMentioned for newly added mentions on update', function
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hello @john</p>',
|
'body' => '<p>Hello @john</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -146,8 +146,8 @@ it('removes mentions from pivot when user removed from body', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hello @john and @jane</p>',
|
'body' => '<p>Hello @john and @jane</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Livewire\CommentItem;
|
use Relaticle\Comments\Livewire\CommentItem;
|
||||||
use Relaticle\Comments\Livewire\Comments;
|
use Relaticle\Comments\Livewire\Comments;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -92,8 +92,8 @@ it('stores mentions when editing comment with @mention', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Original comment</p>',
|
'body' => '<p>Original comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Notification;
|
use Illuminate\Support\Facades\Notification;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\CommentSubscription;
|
|
||||||
use Relaticle\Comments\Events\CommentCreated;
|
use Relaticle\Comments\Events\CommentCreated;
|
||||||
use Relaticle\Comments\Events\UserMentioned;
|
use Relaticle\Comments\Events\UserMentioned;
|
||||||
use Relaticle\Comments\Listeners\SendCommentRepliedNotification;
|
use Relaticle\Comments\Listeners\SendCommentRepliedNotification;
|
||||||
use Relaticle\Comments\Listeners\SendUserMentionedNotification;
|
use Relaticle\Comments\Listeners\SendUserMentionedNotification;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
use Relaticle\Comments\Models\Subscription;
|
||||||
use Relaticle\Comments\Notifications\CommentRepliedNotification;
|
use Relaticle\Comments\Notifications\CommentRepliedNotification;
|
||||||
use Relaticle\Comments\Notifications\UserMentionedNotification;
|
use Relaticle\Comments\Notifications\UserMentionedNotification;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
@@ -19,21 +19,21 @@ it('sends CommentRepliedNotification to parent comment author when reply is crea
|
|||||||
$replyAuthor = User::factory()->create();
|
$replyAuthor = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $parentAuthor);
|
Subscription::subscribe($post, $parentAuthor);
|
||||||
|
|
||||||
$parentComment = Comment::factory()->create([
|
$parentComment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $parentAuthor->getKey(),
|
'commenter_id' => $parentAuthor->getKey(),
|
||||||
'user_type' => $parentAuthor->getMorphClass(),
|
'commenter_type' => $parentAuthor->getMorphClass(),
|
||||||
'body' => '<p>Parent comment</p>',
|
'body' => '<p>Parent comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->create([
|
$reply = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $replyAuthor->getKey(),
|
'commenter_id' => $replyAuthor->getKey(),
|
||||||
'user_type' => $replyAuthor->getMorphClass(),
|
'commenter_type' => $replyAuthor->getMorphClass(),
|
||||||
'parent_id' => $parentComment->id,
|
'parent_id' => $parentComment->id,
|
||||||
'body' => '<p>A reply</p>',
|
'body' => '<p>A reply</p>',
|
||||||
]);
|
]);
|
||||||
@@ -51,13 +51,13 @@ it('does NOT send reply notification for top-level comments', function () {
|
|||||||
$subscriber = User::factory()->create();
|
$subscriber = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $subscriber);
|
Subscription::subscribe($post, $subscriber);
|
||||||
|
|
||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Top-level comment</p>',
|
'body' => '<p>Top-level comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -73,21 +73,21 @@ it('does NOT send reply notification to the reply author', function () {
|
|||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
|
|
||||||
$parentComment = Comment::factory()->create([
|
$parentComment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>My comment</p>',
|
'body' => '<p>My comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->create([
|
$reply = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'parent_id' => $parentComment->id,
|
'parent_id' => $parentComment->id,
|
||||||
'body' => '<p>My own reply</p>',
|
'body' => '<p>My own reply</p>',
|
||||||
]);
|
]);
|
||||||
@@ -108,8 +108,8 @@ it('sends UserMentionedNotification when a user is mentioned', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Hey @someone</p>',
|
'body' => '<p>Hey @someone</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -128,8 +128,8 @@ it('does NOT send mention notification to the comment author', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Hey @myself</p>',
|
'body' => '<p>Hey @myself</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -146,22 +146,22 @@ it('does NOT send reply notification to unsubscribed user', function () {
|
|||||||
$unsubscribedUser = User::factory()->create();
|
$unsubscribedUser = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $unsubscribedUser);
|
Subscription::subscribe($post, $unsubscribedUser);
|
||||||
CommentSubscription::unsubscribe($post, $unsubscribedUser);
|
Subscription::unsubscribe($post, $unsubscribedUser);
|
||||||
|
|
||||||
$parentComment = Comment::factory()->create([
|
$parentComment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $unsubscribedUser->getKey(),
|
'commenter_id' => $unsubscribedUser->getKey(),
|
||||||
'user_type' => $unsubscribedUser->getMorphClass(),
|
'commenter_type' => $unsubscribedUser->getMorphClass(),
|
||||||
'body' => '<p>Original</p>',
|
'body' => '<p>Original</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->create([
|
$reply = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'parent_id' => $parentComment->id,
|
'parent_id' => $parentComment->id,
|
||||||
'body' => '<p>Reply</p>',
|
'body' => '<p>Reply</p>',
|
||||||
]);
|
]);
|
||||||
@@ -178,20 +178,20 @@ it('auto-subscribes the comment author when creating a comment', function () {
|
|||||||
$author = User::factory()->create();
|
$author = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $author))->toBeFalse();
|
expect(Subscription::isSubscribed($post, $author))->toBeFalse();
|
||||||
|
|
||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>My comment</p>',
|
'body' => '<p>My comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$listener = new SendCommentRepliedNotification;
|
$listener = new SendCommentRepliedNotification;
|
||||||
$listener->handle(new CommentCreated($comment));
|
$listener->handle(new CommentCreated($comment));
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $author))->toBeTrue();
|
expect(Subscription::isSubscribed($post, $author))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('suppresses all notifications when notifications are disabled via config', function () {
|
it('suppresses all notifications when notifications are disabled via config', function () {
|
||||||
@@ -203,21 +203,21 @@ it('suppresses all notifications when notifications are disabled via config', fu
|
|||||||
$mentioned = User::factory()->create();
|
$mentioned = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $subscriber);
|
Subscription::subscribe($post, $subscriber);
|
||||||
|
|
||||||
$parentComment = Comment::factory()->create([
|
$parentComment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $subscriber->getKey(),
|
'commenter_id' => $subscriber->getKey(),
|
||||||
'user_type' => $subscriber->getMorphClass(),
|
'commenter_type' => $subscriber->getMorphClass(),
|
||||||
'body' => '<p>Original</p>',
|
'body' => '<p>Original</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->create([
|
$reply = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'parent_id' => $parentComment->id,
|
'parent_id' => $parentComment->id,
|
||||||
'body' => '<p>Reply</p>',
|
'body' => '<p>Reply</p>',
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Notification;
|
use Illuminate\Support\Facades\Notification;
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\CommentSubscription;
|
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Events\CommentCreated;
|
use Relaticle\Comments\Events\CommentCreated;
|
||||||
use Relaticle\Comments\Events\UserMentioned;
|
use Relaticle\Comments\Events\UserMentioned;
|
||||||
use Relaticle\Comments\Listeners\SendCommentRepliedNotification;
|
use Relaticle\Comments\Listeners\SendCommentRepliedNotification;
|
||||||
use Relaticle\Comments\Listeners\SendUserMentionedNotification;
|
use Relaticle\Comments\Listeners\SendUserMentionedNotification;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
use Relaticle\Comments\Models\Subscription;
|
||||||
use Relaticle\Comments\Notifications\CommentRepliedNotification;
|
use Relaticle\Comments\Notifications\CommentRepliedNotification;
|
||||||
use Relaticle\Comments\Notifications\UserMentionedNotification;
|
use Relaticle\Comments\Notifications\UserMentionedNotification;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
@@ -22,8 +21,8 @@ it('returns correct via channels from config for CommentRepliedNotification', fu
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Hello</p>',
|
'body' => '<p>Hello</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -39,8 +38,8 @@ it('returns toDatabase array with comment data for CommentRepliedNotification',
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>This is a reply body</p>',
|
'body' => '<p>This is a reply body</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -51,7 +50,7 @@ it('returns toDatabase array with comment data for CommentRepliedNotification',
|
|||||||
->and($data['comment_id'])->toBe($comment->id)
|
->and($data['comment_id'])->toBe($comment->id)
|
||||||
->and($data['commentable_type'])->toBe($post->getMorphClass())
|
->and($data['commentable_type'])->toBe($post->getMorphClass())
|
||||||
->and($data['commentable_id'])->toBe($post->id)
|
->and($data['commentable_id'])->toBe($post->id)
|
||||||
->and($data['commenter_name'])->toBe($user->getCommentName());
|
->and($data['commenter_name'])->toBe($user->getCommentDisplayName());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns correct via channels from config for UserMentionedNotification', function () {
|
it('returns correct via channels from config for UserMentionedNotification', function () {
|
||||||
@@ -64,8 +63,8 @@ it('returns correct via channels from config for UserMentionedNotification', fun
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $mentionedBy->getKey(),
|
'commenter_id' => $mentionedBy->getKey(),
|
||||||
'user_type' => $mentionedBy->getMorphClass(),
|
'commenter_type' => $mentionedBy->getMorphClass(),
|
||||||
'body' => '<p>Hey @someone</p>',
|
'body' => '<p>Hey @someone</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -82,8 +81,8 @@ it('returns toDatabase array with mention data for UserMentionedNotification', f
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $mentioner->getKey(),
|
'commenter_id' => $mentioner->getKey(),
|
||||||
'user_type' => $mentioner->getMorphClass(),
|
'commenter_type' => $mentioner->getMorphClass(),
|
||||||
'body' => '<p>Hey @mentioned</p>',
|
'body' => '<p>Hey @mentioned</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -92,7 +91,7 @@ it('returns toDatabase array with mention data for UserMentionedNotification', f
|
|||||||
|
|
||||||
expect($data)->toHaveKeys(['comment_id', 'commentable_type', 'commentable_id', 'mentioner_name', 'body'])
|
expect($data)->toHaveKeys(['comment_id', 'commentable_type', 'commentable_id', 'mentioner_name', 'body'])
|
||||||
->and($data['comment_id'])->toBe($comment->id)
|
->and($data['comment_id'])->toBe($comment->id)
|
||||||
->and($data['mentioner_name'])->toBe($mentioner->getCommentName());
|
->and($data['mentioner_name'])->toBe($mentioner->getCommentDisplayName());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends notification to subscribers when reply comment is created', function () {
|
it('sends notification to subscribers when reply comment is created', function () {
|
||||||
@@ -102,21 +101,21 @@ it('sends notification to subscribers when reply comment is created', function (
|
|||||||
$subscriber = User::factory()->create();
|
$subscriber = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $subscriber);
|
Subscription::subscribe($post, $subscriber);
|
||||||
|
|
||||||
$parentComment = Comment::factory()->create([
|
$parentComment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $subscriber->getKey(),
|
'commenter_id' => $subscriber->getKey(),
|
||||||
'user_type' => $subscriber->getMorphClass(),
|
'commenter_type' => $subscriber->getMorphClass(),
|
||||||
'body' => '<p>Original comment</p>',
|
'body' => '<p>Original comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->create([
|
$reply = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'parent_id' => $parentComment->id,
|
'parent_id' => $parentComment->id,
|
||||||
'body' => '<p>Reply to original</p>',
|
'body' => '<p>Reply to original</p>',
|
||||||
]);
|
]);
|
||||||
@@ -134,13 +133,13 @@ it('does NOT send notification for top-level comments', function () {
|
|||||||
$subscriber = User::factory()->create();
|
$subscriber = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $subscriber);
|
Subscription::subscribe($post, $subscriber);
|
||||||
|
|
||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Top-level comment</p>',
|
'body' => '<p>Top-level comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -156,21 +155,21 @@ it('does NOT notify the reply author themselves', function () {
|
|||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
|
|
||||||
$parentComment = Comment::factory()->create([
|
$parentComment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>My comment</p>',
|
'body' => '<p>My comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->create([
|
$reply = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'parent_id' => $parentComment->id,
|
'parent_id' => $parentComment->id,
|
||||||
'body' => '<p>My own reply</p>',
|
'body' => '<p>My own reply</p>',
|
||||||
]);
|
]);
|
||||||
@@ -187,20 +186,20 @@ it('auto-subscribes comment author to the thread', function () {
|
|||||||
$author = User::factory()->create();
|
$author = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $author))->toBeFalse();
|
expect(Subscription::isSubscribed($post, $author))->toBeFalse();
|
||||||
|
|
||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Comment</p>',
|
'body' => '<p>Comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$listener = new SendCommentRepliedNotification;
|
$listener = new SendCommentRepliedNotification;
|
||||||
$listener->handle(new CommentCreated($comment));
|
$listener->handle(new CommentCreated($comment));
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $author))->toBeTrue();
|
expect(Subscription::isSubscribed($post, $author))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('only notifies subscribed users for reply notifications', function () {
|
it('only notifies subscribed users for reply notifications', function () {
|
||||||
@@ -211,21 +210,21 @@ it('only notifies subscribed users for reply notifications', function () {
|
|||||||
$nonSubscriber = User::factory()->create();
|
$nonSubscriber = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $subscriber);
|
Subscription::subscribe($post, $subscriber);
|
||||||
|
|
||||||
$parentComment = Comment::factory()->create([
|
$parentComment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $subscriber->getKey(),
|
'commenter_id' => $subscriber->getKey(),
|
||||||
'user_type' => $subscriber->getMorphClass(),
|
'commenter_type' => $subscriber->getMorphClass(),
|
||||||
'body' => '<p>Original</p>',
|
'body' => '<p>Original</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->create([
|
$reply = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'parent_id' => $parentComment->id,
|
'parent_id' => $parentComment->id,
|
||||||
'body' => '<p>Reply</p>',
|
'body' => '<p>Reply</p>',
|
||||||
]);
|
]);
|
||||||
@@ -247,8 +246,8 @@ it('sends mention notification to mentioned user', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Hey @mentioned</p>',
|
'body' => '<p>Hey @mentioned</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -268,8 +267,8 @@ it('does NOT send mention notification to the comment author', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Hey @myself</p>',
|
'body' => '<p>Hey @myself</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -287,13 +286,13 @@ it('auto-subscribes mentioned user to the thread', function () {
|
|||||||
$mentioned = User::factory()->create();
|
$mentioned = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $mentioned))->toBeFalse();
|
expect(Subscription::isSubscribed($post, $mentioned))->toBeFalse();
|
||||||
|
|
||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'body' => '<p>Hey @mentioned</p>',
|
'body' => '<p>Hey @mentioned</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -301,7 +300,7 @@ it('auto-subscribes mentioned user to the thread', function () {
|
|||||||
$listener = new SendUserMentionedNotification;
|
$listener = new SendUserMentionedNotification;
|
||||||
$listener->handle($event);
|
$listener->handle($event);
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $mentioned))->toBeTrue();
|
expect(Subscription::isSubscribed($post, $mentioned))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not send notifications when notifications are disabled', function () {
|
it('does not send notifications when notifications are disabled', function () {
|
||||||
@@ -313,21 +312,21 @@ it('does not send notifications when notifications are disabled', function () {
|
|||||||
$mentioned = User::factory()->create();
|
$mentioned = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $subscriber);
|
Subscription::subscribe($post, $subscriber);
|
||||||
|
|
||||||
$parentComment = Comment::factory()->create([
|
$parentComment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $subscriber->getKey(),
|
'commenter_id' => $subscriber->getKey(),
|
||||||
'user_type' => $subscriber->getMorphClass(),
|
'commenter_type' => $subscriber->getMorphClass(),
|
||||||
'body' => '<p>Original</p>',
|
'body' => '<p>Original</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$reply = Comment::factory()->create([
|
$reply = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $author->getKey(),
|
'commenter_id' => $author->getKey(),
|
||||||
'user_type' => $author->getMorphClass(),
|
'commenter_type' => $author->getMorphClass(),
|
||||||
'parent_id' => $parentComment->id,
|
'parent_id' => $parentComment->id,
|
||||||
'body' => '<p>Reply</p>',
|
'body' => '<p>Reply</p>',
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
|
|
||||||
it('returns false for isBroadcastingEnabled by default', function () {
|
it('returns false for isBroadcastingEnabled by default', function () {
|
||||||
expect(Config::isBroadcastingEnabled())->toBeFalse();
|
expect(CommentsConfig::isBroadcastingEnabled())->toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for isBroadcastingEnabled when config overridden', function () {
|
it('returns true for isBroadcastingEnabled when config overridden', function () {
|
||||||
config()->set('comments.broadcasting.enabled', true);
|
config()->set('comments.broadcasting.enabled', true);
|
||||||
|
|
||||||
expect(Config::isBroadcastingEnabled())->toBeTrue();
|
expect(CommentsConfig::isBroadcastingEnabled())->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns comments as default broadcast channel prefix', function () {
|
it('returns comments as default broadcast channel prefix', function () {
|
||||||
expect(Config::getBroadcastChannelPrefix())->toBe('comments');
|
expect(CommentsConfig::getBroadcastChannelPrefix())->toBe('comments');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns custom broadcast channel prefix when overridden', function () {
|
it('returns custom broadcast channel prefix when overridden', function () {
|
||||||
config()->set('comments.broadcasting.channel_prefix', 'my-app-comments');
|
config()->set('comments.broadcasting.channel_prefix', 'my-app-comments');
|
||||||
|
|
||||||
expect(Config::getBroadcastChannelPrefix())->toBe('my-app-comments');
|
expect(CommentsConfig::getBroadcastChannelPrefix())->toBe('my-app-comments');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns 10s as default polling interval', function () {
|
it('returns 10s as default polling interval', function () {
|
||||||
expect(Config::getPollingInterval())->toBe('10s');
|
expect(CommentsConfig::getPollingInterval())->toBe('10s');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns custom polling interval when overridden', function () {
|
it('returns custom polling interval when overridden', function () {
|
||||||
config()->set('comments.polling.interval', '30s');
|
config()->set('comments.polling.interval', '30s');
|
||||||
|
|
||||||
expect(Config::getPollingInterval())->toBe('30s');
|
expect(CommentsConfig::getPollingInterval())->toBe('30s');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\CommentReaction;
|
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Events\CommentReacted;
|
use Relaticle\Comments\Events\CommentReacted;
|
||||||
use Relaticle\Comments\Livewire\Reactions;
|
use Relaticle\Comments\Livewire\Reactions;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
use Relaticle\Comments\Models\Reaction;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -17,8 +17,8 @@ it('adds a reaction when user clicks an emoji', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -26,10 +26,10 @@ it('adds a reaction when user clicks an emoji', function () {
|
|||||||
Livewire::test(Reactions::class, ['comment' => $comment])
|
Livewire::test(Reactions::class, ['comment' => $comment])
|
||||||
->call('toggleReaction', 'thumbs_up');
|
->call('toggleReaction', 'thumbs_up');
|
||||||
|
|
||||||
expect(CommentReaction::where([
|
expect(Reaction::where([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
])->exists())->toBeTrue();
|
])->exists())->toBeTrue();
|
||||||
});
|
});
|
||||||
@@ -41,14 +41,14 @@ it('removes a reaction when toggling same emoji', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentReaction::create([
|
Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -57,10 +57,10 @@ it('removes a reaction when toggling same emoji', function () {
|
|||||||
Livewire::test(Reactions::class, ['comment' => $comment])
|
Livewire::test(Reactions::class, ['comment' => $comment])
|
||||||
->call('toggleReaction', 'thumbs_up');
|
->call('toggleReaction', 'thumbs_up');
|
||||||
|
|
||||||
expect(CommentReaction::where([
|
expect(Reaction::where([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
])->exists())->toBeFalse();
|
])->exists())->toBeFalse();
|
||||||
});
|
});
|
||||||
@@ -74,8 +74,8 @@ it('fires CommentReacted event with added action', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -98,14 +98,14 @@ it('fires CommentReacted event with removed action', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentReaction::create([
|
Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'heart',
|
'reaction' => 'heart',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -133,35 +133,35 @@ it('returns correct reaction summary with counts', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user1->getKey(),
|
'commenter_id' => $user1->getKey(),
|
||||||
'user_type' => $user1->getMorphClass(),
|
'commenter_type' => $user1->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentReaction::create([
|
Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user1->getKey(),
|
'commenter_id' => $user1->getKey(),
|
||||||
'user_type' => $user1->getMorphClass(),
|
'commenter_type' => $user1->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentReaction::create([
|
Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user2->getKey(),
|
'commenter_id' => $user2->getKey(),
|
||||||
'user_type' => $user2->getMorphClass(),
|
'commenter_type' => $user2->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentReaction::create([
|
Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user3->getKey(),
|
'commenter_id' => $user3->getKey(),
|
||||||
'user_type' => $user3->getMorphClass(),
|
'commenter_type' => $user3->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentReaction::create([
|
Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user1->getKey(),
|
'commenter_id' => $user1->getKey(),
|
||||||
'user_type' => $user1->getMorphClass(),
|
'commenter_type' => $user1->getMorphClass(),
|
||||||
'reaction' => 'heart',
|
'reaction' => 'heart',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -187,14 +187,14 @@ it('requires authentication to react', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Livewire::test(Reactions::class, ['comment' => $comment])
|
Livewire::test(Reactions::class, ['comment' => $comment])
|
||||||
->call('toggleReaction', 'thumbs_up');
|
->call('toggleReaction', 'thumbs_up');
|
||||||
|
|
||||||
expect(CommentReaction::count())->toBe(0);
|
expect(Reaction::count())->toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows multiple reaction types from same user', function () {
|
it('allows multiple reaction types from same user', function () {
|
||||||
@@ -204,8 +204,8 @@ it('allows multiple reaction types from same user', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -215,17 +215,17 @@ it('allows multiple reaction types from same user', function () {
|
|||||||
$component->call('toggleReaction', 'thumbs_up');
|
$component->call('toggleReaction', 'thumbs_up');
|
||||||
$component->call('toggleReaction', 'heart');
|
$component->call('toggleReaction', 'heart');
|
||||||
|
|
||||||
expect(CommentReaction::where([
|
expect(Reaction::where([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
])->exists())->toBeTrue();
|
])->exists())->toBeTrue();
|
||||||
|
|
||||||
expect(CommentReaction::where([
|
expect(Reaction::where([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'reaction' => 'heart',
|
'reaction' => 'heart',
|
||||||
])->exists())->toBeTrue();
|
])->exists())->toBeTrue();
|
||||||
});
|
});
|
||||||
@@ -238,8 +238,8 @@ it('allows same reaction from multiple users', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user1->getKey(),
|
'commenter_id' => $user1->getKey(),
|
||||||
'user_type' => $user1->getMorphClass(),
|
'commenter_type' => $user1->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user1);
|
$this->actingAs($user1);
|
||||||
@@ -250,7 +250,7 @@ it('allows same reaction from multiple users', function () {
|
|||||||
Livewire::test(Reactions::class, ['comment' => $comment])
|
Livewire::test(Reactions::class, ['comment' => $comment])
|
||||||
->call('toggleReaction', 'thumbs_up');
|
->call('toggleReaction', 'thumbs_up');
|
||||||
|
|
||||||
expect(CommentReaction::where([
|
expect(Reaction::where([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
])->count())->toBe(2);
|
])->count())->toBe(2);
|
||||||
@@ -263,8 +263,8 @@ it('rejects invalid reaction keys', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -272,7 +272,7 @@ it('rejects invalid reaction keys', function () {
|
|||||||
Livewire::test(Reactions::class, ['comment' => $comment])
|
Livewire::test(Reactions::class, ['comment' => $comment])
|
||||||
->call('toggleReaction', 'invalid_emoji');
|
->call('toggleReaction', 'invalid_emoji');
|
||||||
|
|
||||||
expect(CommentReaction::count())->toBe(0);
|
expect(Reaction::count())->toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('marks reacted_by_user correctly in summary', function () {
|
it('marks reacted_by_user correctly in summary', function () {
|
||||||
@@ -283,14 +283,14 @@ it('marks reacted_by_user correctly in summary', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $userA->getKey(),
|
'commenter_id' => $userA->getKey(),
|
||||||
'user_type' => $userA->getMorphClass(),
|
'commenter_type' => $userA->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CommentReaction::create([
|
Reaction::create([
|
||||||
'comment_id' => $comment->id,
|
'comment_id' => $comment->id,
|
||||||
'user_id' => $userA->getKey(),
|
'commenter_id' => $userA->getKey(),
|
||||||
'user_type' => $userA->getMorphClass(),
|
'commenter_type' => $userA->getMorphClass(),
|
||||||
'reaction' => 'thumbs_up',
|
'reaction' => 'thumbs_up',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -310,7 +310,7 @@ it('marks reacted_by_user correctly in summary', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns configured emoji set from config', function () {
|
it('returns configured emoji set from config', function () {
|
||||||
$emojiSet = Config::getReactionEmojiSet();
|
$emojiSet = CommentsConfig::getReactionEmojiSet();
|
||||||
|
|
||||||
expect($emojiSet)->toBeArray();
|
expect($emojiSet)->toBeArray();
|
||||||
expect($emojiSet)->toHaveKey('thumbs_up');
|
expect($emojiSet)->toHaveKey('thumbs_up');
|
||||||
@@ -322,7 +322,7 @@ it('returns configured emoji set from config', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns allowed reaction keys from config', function () {
|
it('returns allowed reaction keys from config', function () {
|
||||||
$allowed = Config::getAllowedReactions();
|
$allowed = CommentsConfig::getAllowedReactions();
|
||||||
|
|
||||||
expect($allowed)->toBeArray();
|
expect($allowed)->toBeArray();
|
||||||
expect($allowed)->toContain('thumbs_up');
|
expect($allowed)->toContain('thumbs_up');
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
|
||||||
use Relaticle\Comments\Livewire\CommentItem;
|
use Relaticle\Comments\Livewire\CommentItem;
|
||||||
use Relaticle\Comments\Livewire\Comments;
|
use Relaticle\Comments\Livewire\Comments;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@ it('pre-fills editBody with existing comment HTML when starting edit', function
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => $originalHtml,
|
'body' => $originalHtml,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -54,8 +54,8 @@ it('saves edited HTML content through edit form', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Original</p>',
|
'body' => '<p>Original</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -81,8 +81,8 @@ it('creates reply with rich HTML content', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -108,8 +108,8 @@ it('renders comment body with fi-prose class', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>Styled comment</p>',
|
'body' => '<p>Styled comment</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ it('renders comment body with fi-prose class', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns editor toolbar configuration as nested array', function () {
|
it('returns editor toolbar configuration as nested array', function () {
|
||||||
$toolbar = Config::getEditorToolbar();
|
$toolbar = CommentsConfig::getEditorToolbar();
|
||||||
|
|
||||||
expect($toolbar)->toBeArray();
|
expect($toolbar)->toBeArray();
|
||||||
expect($toolbar)->not->toBeEmpty();
|
expect($toolbar)->not->toBeEmpty();
|
||||||
@@ -134,7 +134,7 @@ it('uses custom toolbar config when overridden', function () {
|
|||||||
['bold', 'italic'],
|
['bold', 'italic'],
|
||||||
]]);
|
]]);
|
||||||
|
|
||||||
$toolbar = Config::getEditorToolbar();
|
$toolbar = CommentsConfig::getEditorToolbar();
|
||||||
|
|
||||||
expect($toolbar)->toHaveCount(1);
|
expect($toolbar)->toHaveCount(1);
|
||||||
expect($toolbar[0])->toBe(['bold', 'italic']);
|
expect($toolbar[0])->toBe(['bold', 'italic']);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||||
use Relaticle\Comments\Comment;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Config;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
it('registers the config file', function () {
|
it('registers the config file', function () {
|
||||||
expect(config('comments'))->toBeArray();
|
expect(config('comments'))->toBeArray();
|
||||||
@@ -11,15 +11,15 @@ it('registers the config file', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('resolves the comment model from config', function () {
|
it('resolves the comment model from config', function () {
|
||||||
expect(Config::getCommentModel())->toBe(Comment::class);
|
expect(CommentsConfig::getCommentModel())->toBe(Comment::class);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resolves the comment table from config', function () {
|
it('resolves the comment table from config', function () {
|
||||||
expect(Config::getCommentTable())->toBe('comments');
|
expect(CommentsConfig::getCommentTable())->toBe('comments');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resolves max depth from config', function () {
|
it('resolves max depth from config', function () {
|
||||||
expect(Config::getMaxDepth())->toBe(2);
|
expect(CommentsConfig::getMaxDepth())->toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registers the morph map for comment', function () {
|
it('registers the morph map for comment', function () {
|
||||||
@@ -32,7 +32,7 @@ it('creates the comments table via migration', function () {
|
|||||||
expect(Schema::hasTable('comments'))->toBeTrue();
|
expect(Schema::hasTable('comments'))->toBeTrue();
|
||||||
expect(Schema::hasColumns('comments', [
|
expect(Schema::hasColumns('comments', [
|
||||||
'id', 'commentable_type', 'commentable_id',
|
'id', 'commentable_type', 'commentable_id',
|
||||||
'user_type', 'user_id', 'parent_id', 'body',
|
'commenter_type', 'commenter_id', 'parent_id', 'body',
|
||||||
'edited_at', 'deleted_at', 'created_at', 'updated_at',
|
'edited_at', 'deleted_at', 'created_at', 'updated_at',
|
||||||
]))->toBeTrue();
|
]))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Relaticle\Comments\CommentSubscription;
|
|
||||||
use Relaticle\Comments\Livewire\Comments;
|
use Relaticle\Comments\Livewire\Comments;
|
||||||
|
use Relaticle\Comments\Models\Subscription;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -12,35 +12,35 @@ it('subscribes user when toggling from unsubscribed state', function () {
|
|||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $user))->toBeFalse();
|
expect(Subscription::isSubscribed($post, $user))->toBeFalse();
|
||||||
|
|
||||||
Livewire::test(Comments::class, ['model' => $post])
|
Livewire::test(Comments::class, ['model' => $post])
|
||||||
->call('toggleSubscription');
|
->call('toggleSubscription');
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $user))->toBeTrue();
|
expect(Subscription::isSubscribed($post, $user))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('unsubscribes user when toggling from subscribed state', function () {
|
it('unsubscribes user when toggling from subscribed state', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $user))->toBeTrue();
|
expect(Subscription::isSubscribed($post, $user))->toBeTrue();
|
||||||
|
|
||||||
Livewire::test(Comments::class, ['model' => $post])
|
Livewire::test(Comments::class, ['model' => $post])
|
||||||
->call('toggleSubscription');
|
->call('toggleSubscription');
|
||||||
|
|
||||||
expect(CommentSubscription::isSubscribed($post, $user))->toBeFalse();
|
expect(Subscription::isSubscribed($post, $user))->toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for isSubscribed computed when user is subscribed', function () {
|
it('returns true for isSubscribed computed when user is subscribed', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ it('renders Subscribed text for subscribed user', function () {
|
|||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
CommentSubscription::subscribe($post, $user);
|
Subscription::subscribe($post, $user);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Relaticle\Comments\Comment;
|
|
||||||
use Relaticle\Comments\Events\UserMentioned;
|
use Relaticle\Comments\Events\UserMentioned;
|
||||||
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
@@ -13,8 +13,8 @@ it('carries correct comment and mentioned user in payload', function () {
|
|||||||
$comment = Comment::factory()->create([
|
$comment = Comment::factory()->create([
|
||||||
'commentable_id' => $post->id,
|
'commentable_id' => $post->id,
|
||||||
'commentable_type' => $post->getMorphClass(),
|
'commentable_type' => $post->getMorphClass(),
|
||||||
'user_id' => $user->getKey(),
|
'commenter_id' => $user->getKey(),
|
||||||
'user_type' => $user->getMorphClass(),
|
'commenter_type' => $user->getMorphClass(),
|
||||||
'body' => '<p>@john</p>',
|
'body' => '<p>@john</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ namespace Relaticle\Comments\Tests\Models;
|
|||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Relaticle\Comments\Concerns\IsCommenter;
|
use Relaticle\Comments\Concerns\CanComment;
|
||||||
use Relaticle\Comments\Contracts\Commenter;
|
use Relaticle\Comments\Contracts\Commentator;
|
||||||
use Relaticle\Comments\Tests\Database\Factories\UserFactory;
|
use Relaticle\Comments\Tests\Database\Factories\UserFactory;
|
||||||
|
|
||||||
class User extends Authenticatable implements Commenter
|
class User extends Authenticatable implements Commentator
|
||||||
{
|
{
|
||||||
|
use CanComment;
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
use IsCommenter;
|
|
||||||
use Notifiable;
|
use Notifiable;
|
||||||
|
|
||||||
protected $table = 'users';
|
protected $table = 'users';
|
||||||
|
|||||||
@@ -48,13 +48,13 @@ abstract class TestCase extends Orchestra
|
|||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
|
||||||
Schema::create(config('comments.tables.comments', 'comments'), function (Blueprint $table) {
|
Schema::create(config('comments.table_names.comments', 'comments'), function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->morphs('commentable');
|
$table->morphs('commentable');
|
||||||
$table->morphs('user');
|
$table->morphs('commenter');
|
||||||
$table->foreignId('parent_id')
|
$table->foreignId('parent_id')
|
||||||
->nullable()
|
->nullable()
|
||||||
->constrained(config('comments.tables.comments', 'comments'))
|
->constrained(config('comments.table_names.comments', 'comments'))
|
||||||
->cascadeOnDelete();
|
->cascadeOnDelete();
|
||||||
$table->text('body');
|
$table->text('body');
|
||||||
$table->timestamp('edited_at')->nullable();
|
$table->timestamp('edited_at')->nullable();
|
||||||
@@ -67,30 +67,30 @@ abstract class TestCase extends Orchestra
|
|||||||
Schema::create('comment_mentions', function (Blueprint $table) {
|
Schema::create('comment_mentions', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('comment_id')
|
$table->foreignId('comment_id')
|
||||||
->constrained(config('comments.tables.comments', 'comments'))
|
->constrained(config('comments.table_names.comments', 'comments'))
|
||||||
->cascadeOnDelete();
|
->cascadeOnDelete();
|
||||||
$table->morphs('user');
|
$table->morphs('commenter');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
$table->unique(['comment_id', 'user_id', 'user_type']);
|
$table->unique(['comment_id', 'commenter_id', 'commenter_type']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Schema::create('comment_reactions', function (Blueprint $table) {
|
Schema::create('comment_reactions', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('comment_id')
|
$table->foreignId('comment_id')
|
||||||
->constrained(config('comments.tables.comments', 'comments'))
|
->constrained(config('comments.table_names.comments', 'comments'))
|
||||||
->cascadeOnDelete();
|
->cascadeOnDelete();
|
||||||
$table->morphs('user');
|
$table->morphs('commenter');
|
||||||
$table->string('reaction');
|
$table->string('reaction');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
$table->unique(['comment_id', 'user_id', 'user_type', 'reaction']);
|
$table->unique(['comment_id', 'commenter_id', 'commenter_type', 'reaction']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Schema::create('comment_attachments', function (Blueprint $table) {
|
Schema::create('comment_attachments', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('comment_id')
|
$table->foreignId('comment_id')
|
||||||
->constrained(config('comments.tables.comments', 'comments'))
|
->constrained(config('comments.table_names.comments', 'comments'))
|
||||||
->cascadeOnDelete();
|
->cascadeOnDelete();
|
||||||
$table->string('file_path');
|
$table->string('file_path');
|
||||||
$table->string('original_name');
|
$table->string('original_name');
|
||||||
@@ -112,10 +112,10 @@ abstract class TestCase extends Orchestra
|
|||||||
Schema::create('comment_subscriptions', function (Blueprint $table) {
|
Schema::create('comment_subscriptions', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->morphs('commentable');
|
$table->morphs('commentable');
|
||||||
$table->morphs('user');
|
$table->morphs('commenter');
|
||||||
$table->timestamp('created_at')->nullable();
|
$table->timestamp('created_at')->nullable();
|
||||||
|
|
||||||
$table->unique(['commentable_type', 'commentable_id', 'user_type', 'user_id'], 'comment_subscriptions_unique');
|
$table->unique(['commentable_type', 'commentable_id', 'commenter_type', 'commenter_id'], 'comment_subscriptions_unique');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user