Skip to content

Commit

Permalink
✨ Set the visibility for statuses individually (#410)
Browse files Browse the repository at this point in the history
* added migration

* Visibility-logic implemented.

* Now like creation is only possible with a visibleToMe-Status!

* icons to show the visibility of a status

* Translations!!!1
Also visibility in events

* Yay, the visibility-dropdown does now exist

* check in with visibility

* updates work now too (not in the api)

* codacy, etc.

* fixed tests.

* fixed dropdown to btn-group

* fixes

* fixes

* enum!

* format

* user

Co-authored-by: Kris <[email protected]>
  • Loading branch information
HerrLevin and MrKrisKrisu authored Jun 8, 2021
1 parent 1cbc518 commit 5ba8789
Show file tree
Hide file tree
Showing 24 changed files with 336 additions and 149 deletions.
12 changes: 12 additions & 0 deletions app/Enum/StatusVisibility.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
declare(strict_types=0);

namespace App\Enum;

final class StatusVisibility extends BasicEnum
{
public const PUBLIC = 0;
public const UNLISTED = 1;
public const FOLLOWERS = 2;
public const PRIVATE = 3;
}
3 changes: 2 additions & 1 deletion app/Http/Controllers/API/StatusController.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ public function update(Request $request) {
Auth::user(),
$request['statusId'],
$request['body'],
$request['businessCheck']
$request['businessCheck'],
null
);
if ($editStatusResponse === null) {
return $this->sendError('Not found');
Expand Down
2 changes: 2 additions & 0 deletions app/Http/Controllers/API/TransportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Controllers\API;

use App\Enum\StatusVisibility;
use App\Enum\TravelType;
use App\Exceptions\CheckInCollisionException;
use App\Exceptions\HafasException;
Expand Down Expand Up @@ -127,6 +128,7 @@ public function TrainCheckin(Request $request) {
0,
$request->input('tweet'),
$request->input('toot'),
StatusVisibility::PUBLIC,
0,
isset($request->departure) ? Carbon::parse($request->input('departure')) : null,
isset($request->arrival) ? Carbon::parse($request->input('arrival')) : null,
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/API/v1/StatusController.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function getPolyline(string $parameters): JsonResponse {
->with('trainCheckin.HafasTrip.getPolyLine')
->get()
->reject(function($status) {
return $status->user->userInvisibleToMe;
return ($status->user->userInvisibleToMe || $status->statusInvisibleToMe);
})
->mapWithKeys(function($status) {
return [ $status->id => $status->trainCheckin->getMapLines() ];
Expand Down
12 changes: 8 additions & 4 deletions app/Http/Controllers/FrontendStatusController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Controllers;

use App\Enum\StatusVisibility;
use App\Exceptions\PermissionException;
use App\Exceptions\StatusAlreadyLikedException;
use App\Http\Controllers\Backend\EventController as EventBackend;
Expand Down Expand Up @@ -67,14 +68,17 @@ public function DeleteStatus(Request $request): JsonResponse|RedirectResponse {

public function EditStatus(Request $request): JsonResponse|RedirectResponse {
$this->validate($request, [
'body' => ['max:280'],
'business_check' => ['required', 'digits_between:0,2'],
'body' => ['max:280'],
'business_check' => ['required', 'digits_between:0,2'],
'checkinVisibility' => ['required', Rule::in(StatusVisibility::getList())],
]);

$editStatusResponse = StatusBackend::EditStatus(
Auth::user(),
$request['statusId'],
$request['body'],
$request['business_check']
$request['business_check'],
$request['checkinVisibility']
);
if ($editStatusResponse === false) {
return redirect()->back();
Expand All @@ -93,7 +97,7 @@ public function createLike(Request $request) {
return response(__('controller.status.like-ok'), 201);
} catch (StatusAlreadyLikedException $e) {
return response(__('controller.status.like-already'), 409);
} catch (PermissionException $e) {
} catch (PermissionException) {
abort(403);
}
}
Expand Down
17 changes: 10 additions & 7 deletions app/Http/Controllers/FrontendTransportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Controllers;

use App\Enum\StatusVisibility;
use App\Enum\TravelType;
use App\Exceptions\CheckInCollisionException;
use App\Exceptions\HafasException;
Expand Down Expand Up @@ -126,13 +127,14 @@ public function TrainTrip(Request $request): Renderable|RedirectResponse {

public function TrainCheckin(Request $request): RedirectResponse {
$this->validate($request, [
'body' => 'max:280',
'business_check' => 'digits_between:0,2',
'tweet_check' => 'max:2',
'toot_check' => 'max:2',
'event' => 'integer',
'departure' => ['required', 'date'],
'arrival' => ['required', 'date'],
'body' => 'max:280',
'business_check' => 'digits_between:0,2',
'checkinVisibility' => Rule::in(StatusVisibility::getList()),
'tweet_check' => 'max:2',
'toot_check' => 'max:2',
'event' => 'integer',
'departure' => ['required', 'date'],
'arrival' => ['required', 'date'],
]);
try {
$trainCheckin = TransportBackend::TrainCheckin(
Expand All @@ -144,6 +146,7 @@ public function TrainCheckin(Request $request): RedirectResponse {
$request->business_check,
$request->tweet_check,
$request->toot_check,
$request->checkinVisibility,
$request->event,
Carbon::parse($request->departure),
Carbon::parse($request->arrival),
Expand Down
50 changes: 34 additions & 16 deletions app/Http/Controllers/StatusController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Controllers;

use App\Enum\StatusVisibility;
use App\Exceptions\PermissionException;
use App\Exceptions\StatusAlreadyLikedException;
use App\Models\Event;
Expand All @@ -24,12 +25,12 @@
class StatusController extends Controller
{
/**
* @api v1
* @frontend
* @param int $statusId
* @return Status
* @throws HttpException
* @throws ModelNotFoundException
* @api v1
* @frontend
*/
public static function getStatus(int $statusId): Status {
$status = Status::where('id', $statusId)->with('user',
Expand All @@ -38,7 +39,7 @@ public static function getStatus(int $statusId): Status {
'trainCheckin.Destination',
'trainCheckin.HafasTrip',
'event')->withCount('likes')->firstOrFail();
if (!$status->user->userInvisibleToMe) {
if (!$status->user->userInvisibleToMe && (!$status->statusInvisibleToMe || $status->visibility == StatusVisibility::UNLISTED)) {
return $status;
}

Expand All @@ -48,11 +49,11 @@ public static function getStatus(int $statusId): Status {
/**
* This Method returns the current active status(es) for all users or a specific user.
*
* @api v1
* @frontend
* @param null $userId UserId to get the current active status for a user. Defaults to null.
* @param bool $array This parameter is a temporary solution until the frontend is no more dependend on blade.
* @return Status|array|Builder|Model|object|null
* @api v1
* @frontend
*/
public static function getActiveStatuses($userId = null, bool $array = true) {
if ($userId === null) {
Expand All @@ -71,7 +72,7 @@ public static function getActiveStatuses($userId = null, bool $array = true) {
})
->get()
->filter(function($status) {
return !$status->user->userInvisibleToMe;
return (!$status->user->userInvisibleToMe && !$status->statusInvisibleToMe);
})
->sortByDesc(function($status) {
return $status->trainCheckin->departure;
Expand All @@ -90,7 +91,7 @@ public static function getActiveStatuses($userId = null, bool $array = true) {
})
->where('user_id', $userId)
->first();
if ($status?->user?->userInvisibleToMe) {
if ($status?->user?->userInvisibleToMe || $status?->statusInvisibleToMe) {
return null;
}
return $status;
Expand Down Expand Up @@ -126,6 +127,8 @@ public static function getDashboard(User $user): Paginator {
->select('statuses.*')
->orderBy('train_checkins.departure', 'desc')
->whereIn('user_id', $followingIDs)
->whereIn('visibility', [StatusVisibility::PUBLIC, StatusVisibility::FOLLOWERS])
->orWhere('user_id', $user->id)
->withCount('likes')
->latest()
->simplePaginate(15);
Expand All @@ -141,9 +144,16 @@ public static function getGlobalDashboard(): Paginator {
->join('train_checkins', 'train_checkins.status_id', '=', 'statuses.id')
->join('users', 'statuses.user_id', '=', 'users.id')
->where(function($query) {
$user = Auth::check() ? auth()->user() : null;
$query->where('users.private_profile', 0)
->orWhere('users.id', auth()->user()->id)
->orWhereIn('users.id', auth()->user()->follows()->select('follow_id'));
->where('visibility', StatusVisibility::PUBLIC)
->orWhere('users.id', $user->id)
->orWhere(function($query) {
$followings = Auth::check() ? auth()->user()->follows()->select('follow_id') : [];
$query->where('visibility', StatusVisibility::FOLLOWERS)
->whereIn('users.id', $followings)
->orWhere('visibility', StatusVisibility::PUBLIC);
});
})
->whereHas('trainCheckin', function($query) {
$query->where('departure', '<', date('Y-m-d H:i:s', strtotime("+20min")));
Expand All @@ -168,7 +178,7 @@ public static function DeleteStatus($user, $statusId): ?bool {
return true;
}

public static function EditStatus($user, $statusId, $body, $businessCheck): bool|string|null {
public static function EditStatus($user, $statusId, $body, $businessCheck, $visibility): bool|string|null {
$status = Status::find($statusId);
if ($status === null) {
return null;
Expand All @@ -179,6 +189,9 @@ public static function EditStatus($user, $statusId, $body, $businessCheck): bool

$status->body = $body;
$status->business = $businessCheck;
if ($visibility != null) {
$status->visibility = $visibility;
}
$status->update();
return $status->body;
}
Expand All @@ -192,7 +205,7 @@ public static function EditStatus($user, $statusId, $body, $businessCheck): bool
*/
public static function createLike(User $user, Status $status): Like {

if ($status->user->UserInvisibleToMe) {
if (($status->StatusInvisibleToMe && $status->visibility != StatusVisibility::UNLISTED) || $status->user->UserInvisibleToMe) {
throw new PermissionException();
}

Expand Down Expand Up @@ -362,11 +375,16 @@ public static function getStatusesByEvent(?string $slug, ?int $id): array {
->select('statuses.*')
->join('users', 'statuses.user_id', '=', 'users.id')
->where(function($query) {
$query->where('users.private_profile', 0);
if (auth()->check()) {
$query->orWhere('users.id', auth()->user()->id)
->orWhereIn('users.id', auth()->user()->follows()->select('follow_id'));
}
$query->where('users.private_profile', 0)
->where('visibility', StatusVisibility::PUBLIC);
if (auth()->check()) {
$query->orWhere('users.id', auth()->user()->id)
->orWhere(function($query) {
$query->where('visibility', StatusVisibility::FOLLOWERS)
->whereIn('users.id', auth()->user()->follows()->select('follow_id'))
->orWhere('visibility', StatusVisibility::PUBLIC);
});
}
});

if (auth()->check()) {
Expand Down
8 changes: 5 additions & 3 deletions app/Http/Controllers/TransportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ public static function TrainCheckin($tripId,
$businessCheck,
$tweetCheck,
$tootCheck,
$visibility,
$eventId = 0,
Carbon $departure = null,
Carbon $arrival = null): array {
Expand Down Expand Up @@ -367,9 +368,10 @@ public static function TrainCheckin($tripId,
}

$status = Status::create([
'user_id' => $user->id,
'body' => $body,
'business' => $businessCheck
'user_id' => $user->id,
'body' => $body,
'business' => $businessCheck,
'visibility' => $visibility
]);

$plannedDeparture = Carbon::parse(
Expand Down
14 changes: 12 additions & 2 deletions app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

namespace App\Http\Controllers;

use App\Enum\StatusVisibility;
use App\Exceptions\AlreadyFollowingException;
use App\Exceptions\PermissionException;
use App\Models\Follow;
use App\Models\FollowRequest;
use App\Models\Status;
use App\Models\User;
use App\Notifications\FollowRequestApproved;
use App\Notifications\FollowRequestIssued;
Expand Down Expand Up @@ -156,8 +158,16 @@ public static function statusesForUser(User $user): ?LengthAwarePaginator {
'user', 'likes', 'trainCheckin.Origin', 'trainCheckin.Destination',
'trainCheckin.HafasTrip.stopoversNEW', 'event'
])
->orderByDesc('created_at')
->paginate(15);
->where(function($query) {
$user = Auth::check() ? auth()->user() : null;
$query->whereIn('visibility', [StatusVisibility::PUBLIC, StatusVisibility::UNLISTED])
->orWhere('user_id', $user->id)
->orWhere(function($query) {
$followings = Auth::check() ? auth()->user()->follows()->select('follow_id') : [];
$query->where('visibility', StatusVisibility::FOLLOWERS)
->whereIn('user_id', $followings);
});
})->orderByDesc('created_at')->paginate(15);
}

public static function getProfilePage($username): ?array {
Expand Down
27 changes: 25 additions & 2 deletions app/Models/Status.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@

namespace App\Models;

use App\Enum\StatusVisibility;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\Auth;

/**
* @property int user_id
* @property string body
* @property int business
* @property int visibility
*/
class Status extends Model
{

use HasFactory;

protected $fillable = ['user_id', 'body', 'business', 'event_id'];
protected $fillable = ['user_id', 'body', 'business', 'event_id', 'visibility'];
protected $hidden = ['user_id', 'business'];
protected $appends = ['favorited', 'socialText'];
protected $appends = ['favorited', 'socialText', 'statusInvisibleToMe'];

public function user(): BelongsTo {
return $this->belongsTo(User::class);
Expand Down Expand Up @@ -83,4 +90,20 @@ public function getSocialTextAttribute(): string {

return $postText;
}

/**
* When is a status invisible?
* 0=public, 1=unlisted, 2=Followers, 3=Private
* @return bool
*/
public function getStatusInvisibleToMeAttribute(): bool {
if (Auth::check() && Auth::id() == $this->user_id || $this->visibility == StatusVisibility::PUBLIC) {
return false;
}
$visible = false;
if ($this->visibility == StatusVisibility::FOLLOWERS) {
$visible = (Auth::check() && Auth::user()->follows->contains('id', $this->user_id));
}
return !$visible;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

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

class AddVisibilityToStatuses extends Migration
{
public function up(): void {
Schema::table('statuses', function(Blueprint $table) {
$table->unsignedTinyInteger('visibility')
->default(0)
->after('business');
});
}

public function down(): void {
Schema::table('statuses', function(Blueprint $table) {
$table->dropColumn('visibility');
});
}
}
Loading

0 comments on commit 5ba8789

Please sign in to comment.