#4: It's now possible to reply to a comment in threaded comments. Also started implementing validation.
This commit is contained in:
parent
c9ab590afe
commit
9702366d11
@ -2,9 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers\Gallery;
|
||||
|
||||
use App\Facade\Theme;
|
||||
use App\Facade\UserConfig;
|
||||
use App\Helpers\DbHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\StorePhotoCommentRequest;
|
||||
use App\PhotoComment;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
@ -12,7 +14,38 @@ use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class PhotoCommentController extends Controller
|
||||
{
|
||||
public function store(Request $request, $albumUrlAlias, $photoFilename)
|
||||
public function reply(Request $request, $albumUrlAlias, $photoFilename, $commentID)
|
||||
{
|
||||
$album = DbHelper::getAlbumByPath($albumUrlAlias);
|
||||
if (is_null($album))
|
||||
{
|
||||
App::abort(404);
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->authorizeForUser($this->getUser(), 'view', $album);
|
||||
|
||||
$photo = PhotoController::loadPhotoByAlbumAndFilename($album, $photoFilename);
|
||||
|
||||
if (!UserConfig::get('allow_photo_comments'))
|
||||
{
|
||||
// Not allowed to post comments
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$comment = $photo->comments()->where('id', $commentID)->first();
|
||||
if (is_null($comment))
|
||||
{
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
return Theme::render('partials.photo_comments_reply_form', [
|
||||
'photo' => $photo,
|
||||
'reply_comment' => $comment
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(StorePhotoCommentRequest $request, $albumUrlAlias, $photoFilename)
|
||||
{
|
||||
$album = DbHelper::getAlbumByPath($albumUrlAlias);
|
||||
if (is_null($album))
|
||||
@ -35,6 +68,20 @@ class PhotoCommentController extends Controller
|
||||
$comment->photo_id = $photo->id;
|
||||
$comment->fill($request->only(['commentor_email', 'commentor_name', 'comment_text']));
|
||||
|
||||
// Validate and link the parent comment, if provided
|
||||
if ($request->has('parent_comment_id'))
|
||||
{
|
||||
$parentComment = $photo->comments()->where('id', intval($request->get('parent_comment_id')))->first();
|
||||
|
||||
if (is_null($parentComment))
|
||||
{
|
||||
$request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully'));
|
||||
return redirect($photo->url());
|
||||
}
|
||||
|
||||
$comment->parent_comment_id = $parentComment->id;
|
||||
}
|
||||
|
||||
$user = $this->getUser();
|
||||
if (!is_null($user) && !$user->isAnonymous())
|
||||
{
|
||||
@ -45,6 +92,13 @@ class PhotoCommentController extends Controller
|
||||
|
||||
$request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully'));
|
||||
|
||||
return redirect($photo->url());
|
||||
if ($request->isXmlHttpRequest())
|
||||
{
|
||||
return response()->json(['redirect_url' => $photo->url()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return redirect($photo->url());
|
||||
}
|
||||
}
|
||||
}
|
32
app/Http/Requests/StorePhotoCommentRequest.php
Normal file
32
app/Http/Requests/StorePhotoCommentRequest.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StorePhotoCommentRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'commentor_name' => 'required|max:255',
|
||||
'commentor_email' => 'sometimes|max:255|email',
|
||||
'comment_text' => 'required'
|
||||
];
|
||||
}
|
||||
}
|
@ -54,7 +54,14 @@ class Photo extends Model
|
||||
|
||||
public function approvedComments()
|
||||
{
|
||||
return $this->hasMany(PhotoComment::class)->whereNotNull('approved_at');
|
||||
return $this->hasMany(PhotoComment::class)
|
||||
->whereNull('parent_comment_id')
|
||||
->whereNotNull('approved_at');
|
||||
}
|
||||
|
||||
public function comments()
|
||||
{
|
||||
return $this->hasMany(PhotoComment::class);
|
||||
}
|
||||
|
||||
public function exifUrl()
|
||||
@ -90,6 +97,15 @@ class Photo extends Model
|
||||
]);
|
||||
}
|
||||
|
||||
public function replyToCommentFormUrl($commentID = -1)
|
||||
{
|
||||
return route('replyPhotoComment', [
|
||||
'albumUrlAlias' => $this->album->url_path,
|
||||
'photoFilename' => $this->storage_file_name,
|
||||
'commentID' => $commentID
|
||||
]);
|
||||
}
|
||||
|
||||
public function thumbnailUrl($thumbnailName = null, $cacheBust = true)
|
||||
{
|
||||
$url = $this->album->getAlbumSource()->getUrlToPhoto($this, $thumbnailName);
|
||||
|
@ -2,7 +2,7 @@
|
||||
* This model is used by gallery/photo.blade.php, to handle comments and individual photo actions.
|
||||
* @constructor
|
||||
*/
|
||||
function PhotoViewModel() {
|
||||
function PhotoViewModel(urls) {
|
||||
this.el = '#photo-app';
|
||||
|
||||
this.data = {
|
||||
@ -10,7 +10,39 @@ function PhotoViewModel() {
|
||||
reply_comment_id: 0
|
||||
};
|
||||
|
||||
this.computed = {
|
||||
replyFormStyle: function()
|
||||
{
|
||||
return {
|
||||
'display': this.is_reply_form_loading ? 'none' : 'block'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
this.methods = {
|
||||
init: function() {
|
||||
var self = this;
|
||||
|
||||
// Load the right comment reply form
|
||||
$('#comment-reply-modal').on('show.bs.modal', function (event) {
|
||||
var url = urls.reply_comment_form.replace(/-1$/, self.reply_comment_id);
|
||||
$.get(url, function(result)
|
||||
{
|
||||
$('#comment-reply-form-content').html(result);
|
||||
self.is_reply_form_loading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
postCommentReply: function() {
|
||||
var form = $('form', '#comment-reply-form-content');
|
||||
var formUrl = $(form).attr('action');
|
||||
|
||||
var formData = form.serialize();
|
||||
$.post(formUrl, formData, function(result)
|
||||
{
|
||||
window.location = result.redirect_url;
|
||||
});
|
||||
},
|
||||
replyToComment: function(e) {
|
||||
var replyButton = $(e.target).closest('.photo-comment');
|
||||
this.reply_comment_id = replyButton.data('comment-id');
|
||||
|
@ -36,6 +36,7 @@ return [
|
||||
'parent_album_placeholder' => 'None (top-level album)',
|
||||
'password_label' => 'Password:',
|
||||
'password_confirm_label' => 'Confirm password:',
|
||||
'photo_comment_reply_action' => 'Post reply',
|
||||
'photo_comment_submit_action' => 'Post comment',
|
||||
'photo_comment_text_label' => 'Your message/comments:',
|
||||
'please_select' => '- Select an Option -',
|
||||
|
@ -161,10 +161,14 @@
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
var photoViewModel = new PhotoViewModel();
|
||||
var app = null;
|
||||
var photoViewModel = new PhotoViewModel({
|
||||
reply_comment_form: '{{ $photo->replyToCommentFormUrl() }}'
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
var app = new Vue(photoViewModel);
|
||||
app = new Vue(photoViewModel);
|
||||
app.init();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -31,10 +31,9 @@
|
||||
<p class="m-2"><img src="{{ asset('ripple.svg') }}" alt="@lang('global.please_wait')" title="@lang('global.please_wait')"></p>
|
||||
<p>@lang('global.please_wait')</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer" v-if="!is_reply_form_loading">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary">Save changes</button>
|
||||
|
||||
<div id="comment-reply-form-content" v-bind:style="replyFormStyle">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,22 +1,59 @@
|
||||
@php
|
||||
$is_reply = isset($reply_comment);
|
||||
@endphp
|
||||
|
||||
{{-- Show a previous of the comment we're replying to --}}
|
||||
@if ($is_reply)
|
||||
<ul class="mb-3">
|
||||
@include (Theme::viewName('partials.photo_single_comment'), ['comment' => $reply_comment, 'is_reply' => true])
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
<form action="{{ $photo->postCommentUrl() }}" method="post">
|
||||
{{ csrf_field() }}
|
||||
|
||||
@if ($is_reply)
|
||||
<input type="hidden" name="parent_comment_id" value="{{ $reply_comment->id }}"/>
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label for="commentor-name">@lang('forms.name_label')</label>
|
||||
<input type="text" class="form-control" id="commentor-name" name="commentor_name"/>
|
||||
<input type="text" class="form-control{{ $errors->has('commentor_name') ? ' is-invalid' : '' }}" id="commentor-name" name="commentor_name"/>
|
||||
|
||||
@if ($errors->has('commentor_name'))
|
||||
<div class="invalid-feedback">
|
||||
<strong>{{ $errors->first('commentor_name') }}</strong>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="commentor-email">@lang('forms.email_label')</label>
|
||||
<input type="email" class="form-control" id="commentor-email" name="commentor_email" placeholder="@lang('forms.email_placeholder')"/>
|
||||
<input type="text" class="form-control{{ $errors->has('commentor_email') ? ' is-invalid' : '' }}" id="commentor-email" name="commentor_email" placeholder="@lang('forms.email_placeholder')"/>
|
||||
|
||||
@if ($errors->has('commentor_email'))
|
||||
<div class="invalid-feedback">
|
||||
<strong>{{ $errors->first('commentor_email') }}</strong>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="comment-text">@lang('forms.photo_comment_text_label')</label>
|
||||
<textarea class="form-control" id="comment-text" name="comment_text" rows="10"></textarea>
|
||||
<textarea class="form-control{{ $errors->has('comment_text') ? ' is-invalid' : '' }}" id="comment-text" name="comment_text" rows="10"></textarea>
|
||||
|
||||
@if ($errors->has('comment_text'))
|
||||
<div class="invalid-feedback">
|
||||
<strong>{{ $errors->first('comment_text') }}</strong>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="form-group text-right">
|
||||
<button type="submit" class="btn btn-success">@lang('forms.photo_comment_submit_action')</button>
|
||||
@if ($is_reply)
|
||||
<button type="button" class="btn btn-success" onclick="app.postCommentReply();">@lang('forms.photo_comment_reply_action')</button>
|
||||
@else
|
||||
<button type="submit" class="btn btn-success">@lang('forms.photo_comment_submit_action')</button>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
@ -1,8 +1,12 @@
|
||||
@php
|
||||
$is_reply = (isset($is_reply) && $is_reply);
|
||||
@endphp
|
||||
|
||||
<li class="photo-comment" data-comment-id="{{ $comment->id }}">
|
||||
Comment by <b>{{ $comment->createdBy->name }}</b>:<br/>
|
||||
{{ $comment->comment_text }}
|
||||
|
||||
@if ($comment->depth() < UserConfig::get('photo_comments_thread_depth'))
|
||||
@if (!$is_reply && $comment->depth() < UserConfig::get('photo_comments_thread_depth'))
|
||||
<p><button v-on:click="replyToComment" class="btn btn-sm btn-outline-primary">@lang('gallery.photo_comments_reply_action')</button></p>
|
||||
@endif
|
||||
</li>
|
@ -109,6 +109,9 @@ Route::get('exif/{albumUrlAlias}/{photoFilename}', 'Gallery\PhotoController@show
|
||||
Route::post('p/{albumUrlAlias}/{photoFilename}/comments', 'Gallery\PhotoCommentController@store')
|
||||
->name('postPhotoComment')
|
||||
->where('albumUrlAlias', '.*');
|
||||
Route::get('p/{albumUrlAlias}/{photoFilename}/comments/reply/{commentID}', 'Gallery\PhotoCommentController@reply')
|
||||
->name('replyPhotoComment')
|
||||
->where('albumUrlAlias', '.*');
|
||||
Route::get('p/{albumUrlAlias}/{photoFilename}', 'Gallery\PhotoController@show')
|
||||
->name('viewPhoto')
|
||||
->where('albumUrlAlias', '.*');
|
||||
|
Loading…
Reference in New Issue
Block a user