Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: submission pinning #310

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
37 changes: 37 additions & 0 deletions app/Events/SubmissionWasPinned.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class SubmissionWasPinned
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public $submission;
public $user_id;

/**
* Create a new event instance.
*
* @return void
*/
public function __construct($submission, $user_id)
{
$this->submission = $submission;
$this->user_id = $user_id;
}

/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
// return new PrivateChannel('channel-name');
}
}
37 changes: 37 additions & 0 deletions app/Events/SubmissionWasUnpinned.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class SubmissionWasUnpinned
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public $submission;
public $user_id;

/**
* Create a new event instance.
*
* @return void
*/
public function __construct($submission, $user_id)
{
$this->submission = $submission;
$this->user_id = $user_id;
}

/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
// return new PrivateChannel('channel-name');
}
}
8 changes: 4 additions & 4 deletions app/Http/Controllers/ChannelController.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,17 @@ protected function getSubmissions($channel, $sort)

switch ($sort) {
case 'new':
$submissions->orderBy('created_at', 'desc');
$submissions->orderBy('pinned_until' ,'created_at', 'desc');
break;

case 'rising':
$submissions->where('created_at', '>=', Carbon::now()->subHour())
->orderBy('rate', 'desc');
$submissions->where('pinned_until','created_at', '>=', Carbon::now()->subHour())
->orderBy('priority' ,'rate', 'desc');
break;

default:
// hot
$submissions->orderBy('rate', 'desc');
$submissions->orderBy('pinned_until', 'rate', 'desc');
break;
}

Expand Down
89 changes: 87 additions & 2 deletions app/Http/Controllers/ModeratorController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
use App\Comment;
use App\Events\CommentWasDeleted;
use App\Events\SubmissionWasDeleted;
use App\Events\SubmissionWasPinned;
use App\Events\SubmissionWasUnpinned;
use App\Http\Resources\ModeratorResource;
use App\Notifications\BecameModerator;
use App\RecordsActivity;
use App\Report;
use App\Rules\NotSelfUsername;
use App\Submission;
Expand All @@ -19,10 +22,9 @@
use Carbon\Carbon;
use DB;
use Illuminate\Http\Request;

class ModeratorController extends Controller
{
use CachableSubmission, CachableChannel, CachableComment;
use CachableSubmission, CachableChannel, CachableComment, RecordsActivity;

public function __construct()
{
Expand Down Expand Up @@ -227,4 +229,87 @@ public function destroy(Request $request)

return response($request->username.' is no longer a moderator at #'.$request->channel_name, 200);
}

/**
* pins the submission
*
* @param \Illuminate\Http\Request $request
*
* @return response
*/
public function pinSubmission(Request $request)
{
$this->validate($request, [
'submission_id' => 'required|integer',
'months' => 'integer|min:0',
'weeks' => 'integer|min:0',
'days' => 'integer|min:0',
'hours' => 'integer|min:0',
]);

$submission = Submission::withTrashed()->findOrFail($request->submission_id);

abort_unless($this->mustBeModerator($submission->channel_id), 403);

$now = Carbon::now();
$pinUntil = clone $now;

if ($request->months) {
$pinUntil = $pinUntil->addMonths($request->months);
}
if ($request->weeks) {
$pinUntil = $pinUntil->addWeeks($request->weeks);
}
if ($request->days) {
$pinUntil = $pinUntil->addDays($request->days);
}
if ($request->hours) {
$pinUntil = $pinUntil->addHours($request->hours);
}

//If not specified, assuming infinite
if ($pinUntil <= $now) {
$pinUntil = Carbon::maxValue();
}
//or throw 400
//abort_unless($pinUntil > $now, 400);
$submission->update([
'pinned_until' => $pinUntil,
]);

event(new SubmissionWasPinned($submission, Auth::user()->id));

$this->putSubmissionInTheCache($submission);

return response(['pinned_until' => optional($pinUntil)->toDateTimeString()], 200);
}

/**
* unpins the submission
*
* @param \Illuminate\Http\Request $request
*
* @return response
*/
public function unpinSubmission(Request $request)
{
$this->validate($request, [
'submission_id' => 'required|integer',
]);

$submission = Submission::withTrashed()->findOrFail($request->submission_id);

abort_unless($this->mustBeModerator($submission->channel_id), 403);

$submission->update([
'pinned_until' => null,
]);

$this->putSubmissionInTheCache($submission);

event(new SubmissionWasUnpinned($submission, Auth::user()->id));

return response('Submission unpinned successfully', 200);
}

}
7 changes: 7 additions & 0 deletions app/Http/Resources/SubmissionResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class SubmissionResource extends Resource
*/
public function toArray($request)
{

return [
'id' => $this->id,
'slug' => $this->slug,
Expand All @@ -34,6 +35,12 @@ public function toArray($request)
'created_at' => optional($this->created_at)->toDateTimeString(),
'url' => $this->url,
'domain' => $this->domain,
//using ::Collection serializes Carbon Datetime array into DateTimeString
//in conjunction with separate toDateTimeString here
//leads to nulls being returned
//possibly connected: https://github.com/laravel/framework/issues/21703
'pinned_until' => is_string($this->pinned_until)?
$this->pinned_until : optional($this->pinned_until)->toDateTimeString(),

'channel' => $this->when((bool) request('with_channel') == true, new ChannelResource($this->channel)),

Expand Down
40 changes: 40 additions & 0 deletions app/Listeners/SubmissionPinned.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace App\Listeners;

use App\Activity;
use App\Events\SubmissionWasPinned;
use Illuminate\Auth\Events\Registered;

class SubmissionPinned
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}

/**
* Handle the event.
*
* @param SubmissionWasPinned $event
*
* @return void
*/
public function handle(SubmissionWasPinned $event)
{
Activity::create([
'subject_id' => $event->submission->id,
'ip_address' => getRequestIpAddress(),
'user_agent' => getRequestUserAgent(),
'country' => getRequestCountry(),
'subject_type' => 'App\Submission',
'name' => 'pinned_submission',
'user_id' => $event->user_id,
]);
}
}
40 changes: 40 additions & 0 deletions app/Listeners/SubmissionUnpinned.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace App\Listeners;

use App\Activity;
use App\Events\SubmissionWasUnpinned;
use Illuminate\Auth\Events\Registered;

class SubmissionUnpinned
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}

/**
* Handle the event.
*
* @param SubmissionWasUnpinned $event
*
* @return void
*/
public function handle(SubmissionWasUnpinned $event)
{
Activity::create([
'subject_id' => $event->submission->id,
'ip_address' => getRequestIpAddress(),
'user_agent' => getRequestUserAgent(),
'country' => getRequestCountry(),
'subject_type' => 'App\Submission',
'name' => 'unpinned_submission',
'user_id' => $event->user_id,
]);
}
}
8 changes: 8 additions & 0 deletions app/Providers/EventServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ class EventServiceProvider extends ServiceProvider
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\UserLoggedOut',
],

'Illuminate\Auth\Events\SubmissionWasPinned' => [
'App\Listeners\SubmissionPinned',
],

'Illuminate\Auth\Events\SubmissionWasUnpinned' => [
'App\Listeners\SubmissionUnpinned',
],
];

/**
Expand Down
2 changes: 1 addition & 1 deletion app/Submission.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Submission extends Model
protected $fillable = [
'data', 'title', 'slug', 'type', 'channel_id', 'channel_name', 'rate',
'upvotes', 'downvotes', 'user_id', 'data', 'nsfw', 'approved_at',
'deleted_at', 'comments_number', 'url', 'domain',
'deleted_at', 'comments_number', 'url', 'domain', 'pinned_until',
];

protected $casts = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddPinnedUntilToSubmissionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('submissions', function (Blueprint $table) {
$table->dateTimeTz('pinned_until')->nullable();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}
Loading