Can I log data in an policy? - laravel

I am new to writing policies. I wanna know if I can see data that comes in an policy function.
I have tried googling if it is possible to log something in an policy but I couldn't find anything about this. Now I am just wandering if there is any other possible option to see the data that comes in an policy.
public function show(User $userIdentity, Client $client) {
\Log::info(['log']);
}
I hope someone has an answer for this or another option for me to see the data that is coming through.

Well, yes, if you use the Illuminate\Support\Facades\Log facade you will log stuff. It's nothing related to the policies "per se", if the code gets executed, the log will trigger. If you are looking for architectural suggestions, it depends on the big picture. If that's a simple scenario, that will be enough AND will be fine. If you plan to have complex/multiple logs, you probably want to delegate the logging logic to a dedicated object/package and intercept the event trough an observer, for example.
Docs related to the facede usage here and here

Sure you can, you have to explicitly call your policy, like
$client = Client::find(1);
auth()->user()->can('view', $client);
This is discussed in details here laravel docs
Dont forget to register your policies
use Illuminate\Foundation\Support\Providers\AuthServiceProvider; // auth service provider extends service provider so make sure you take a note of this one
class ReferralServiceProvider extends AuthServiceProvider
{
protected $policies = [
Client::class => ClientPolicy::class
];
public function boot()
{
$this->registerPolicies();
}
}
-
public function show(User $userIdentity, Client $client) {
logger($userIdentity->toJson());
logger($client->toJson());
}

Related

Using laravel’s policies to delete all users’ posts as an Adnin

Please I need help with Laravel’s policy. I have two guards (Admin and Users with two models of same guards). I’m able to fetch all users posts inside admin’s dashboard. However, I can’t view them since I’m not logged in as a user (show post view is still locked into auth user’s profile for now). Can I possibly use Laravel’s policy from admin’s dashboard to delete a user’s post without logging in as a user? Here is my code so far....
use App\AdminPost;
use App\UserPost;
{
protected $policies = [
AdminPost::class => AdminPostPolicy::class,
UserPost::class => UserPostPolicy::class,
]:
public function boot()
{
$this->registerPolicies();
}
class AdminPolicy
{
public function delete(what goes in here ????)
return $......
}
This is all I can think of so far. I really need help please. Thanks

In Laravel, Where I should fire events and emails in repo or in controller?

I am using repository pattern in develop an application using laravel, my question is where I have to write code for fire events, send email or send an notification? and why?
This is really a broad question and many will come with their own opinions. In my opinion, form the context of Laravel, I would define types of my events depending on the operations.
So for example, as you mentioned email/notification events, I would like to think this way (This is a hypothetical example):
class UserController
{
public function register(Request $request, UserRepository $user)
{
if ($user = $user->register($request->all())) {
Email::send(...);
}
}
}
In this case, an email should be sent to the user after the registration so I can use an event to do the same thing within the controller for example:
class UserController
{
public function register(Request $request, UserRepository $user)
{
try {
$user = $user->register($request->all());
Event::fire('user_registered', $user);
} catch(RegistrationException $e) {
// Handle the exception
}
}
}
In this case, I think, the event dispatching should be in the controller because it's the part of my application layer to control the application flow so, email sending event should be dispatched from controller. The UserRepository should not care about your application's flow, sending email to the user is not part of your UserRepository, so that's it.
Now, think about another hypothetical example, say you've a delete method in your UserController as given below:
class UserController
{
public function delete(UserRepository $user, $id)
{
if($user->findOrFail($id)->delete()) {
Post::where('user_id', $id)->delete();
}
}
}
Well, in this case, the deletion of the user involves some domain related operations so I would rewrite the method as given below:
public function delete(UserRepository $user, $id)
{
try {
$user->delete($id);
return redirect('/users'); // show users index page
} catch (InvalidOperationException $e) {
// Handle the custom exception thrown from UserRepository
}
}
Notice that, there is no related operations took place in the delete method because I would probably fire an event inside the UserRepository because this delete action involves some other domain/business related operation and application layer should not care about it (in this case) because the deleting an user effects some other domain objects so I'll handle that event this way.
Anyways, this is just my way of thinking and it's just an opinion. Maybe in a real world situation, I could come up with a different idea so it's up to you, depending on the context you should think about it and finally there's no recommended way in Laravel, you can even use Models to fire events, so just keep it simple, make the decision depending on your context that fits well.

Controller constructor to check Auth middleware for two different guards

I have a dashboard view that shows certain contain depending on which user is viewing, whether it be an admin or just a regular user.
I can get my admins onto that page, but regular users aren't able to currently because of my middleware guard.
class DashboardController extends Controller {
public function __construct()
{
$this->middleware('auth:admin');
}
public function index()
{
return view('dashboard.index');
}
}
The following code checks on each DashboardController call for auth:admins, but I want regular users to access this too, is there a way to check the auth middleware twice like so?
$this->middleware(['auth:admin','auth']);
So ideally it will check if you're an admin or just a regular auth user.
Also on my view page, when accessing properties of an admin I'm using:
{{ Auth::user()->admin_username }}
Is this normal? I have an admin Model but I'm still accessing it via Auth::user() which feels strange to me, shouldn't it be Auth::admin()->admin_username
Accessing a particular page for users with differing roles is more suited for laravels gates and policy authorization mechanisms.
https://laravel.com/docs/5.5/authorization#writing-gates
These allow you to write fine tuned rules for each use case you have. Simple gates can be defined as closures within your application AuthServiceProvider. For example:
public function boot()
{
$this->registerPolicies();
Gate::define('access-dashboard', function ($user, $post) {
return auth()->check() && (auth()->user()->hasRole('admin') || auth()->user()->hasRole('regular'));
});
}
Then you can use the gate facade wherever necessary, for instance a controller method or constructor.
if (Gate::allows('access-dashboard', $model)) {
// The current user can access dashboard, load their data
}
Alternatively use the can or cant helpers on the user model directly.
if (auth()->user()->can('access-dashboard')) {
//
}
Of course, you can achieve similar via middleware, the advantage of using the above is you can authorize actions at specific points in your code as well as reusability.
As for for last question, as you have it written is correct.
{{ Auth::user()->admin_username }}
Auth::user() or auth()->user() simply returns the currently authenticated user, regardless of their role.
Policies will never work without auth middleware

Laravel getStream - How to follow or add activity to a Company (non user)

an app I am creating needs to follow Companies, aside from users. And let the companies have their own activities. How is this configured in Laravel getStream. Seems the feeds are only for user types.
timelineFeed = FeedManager::getNewsFeed($user->id)['timeline'];
$aggregatedTimelineFeed = FeedManager::getNewsFeed($user->id)['timeline_aggregated'];
sample model i have is this:
namespace App;
use Illuminate\Database\Eloquent\Model;
class CompanyPost extends Model
{
use \GetStream\StreamLaravel\Eloquent\ActivityTrait;
public function company()
{
return $this->belongsTo('App\Company', 'company_id', 'id');
}
public function activityVerb()
{
return 'company_post';
}
public function activityActorMethodName()
{
return 'company';
}
}
but i have noticed the feed is still saved on the user activities instead of the company activities.
Thanks in advance guys.
Ian seems to have confused you with me in his link to the Github issue which brought this post to my attention.
The reason this is still showing up on the user feed is that this isn't a configurable option at least on a case by case (or model by model) level. You can override what Stream Laravel uses as the "user feed" in the main configuration but as far as I can tell you are stuck posting to the active logged in user's feed unless you build out the functionality yourself with the Stream-PHP libs and abstain from using the StreamLaravel Activity trait.
You can see here starting at Line: 73 of StreamLaravelManager.php what's happening when an activity is created.
public function activityCreated($instance)
{
$activity = $instance->createActivity();
$feed = $this->getFeed($this->userFeed, $instance->activityActorId());
$feed->addActivity($activity);
}
Unfortunately "$this->userFeed" ultimately is pulled from the configuration file and I don't think there is a way to override it.
Personally, I ran into this when creating "like" functionality. I didn't really want people to have to see what everyone "likes" on their timeline since most of it would be irrelevant and it would get cluttered fast so I ended up not even creating a "like" activity. Instead I'm only added it to a users notification feed when someone likes something of theirs. Of course this may not be desirable for everyone to handle it that way but I noticed you had the "like" activity in your screenshot so I figured I'd mention it.
Good luck on your app!
Our stream-laravel project has some documentation on how to change the model
class Pin extends Eloquent {
use GetStream\StreamLaravel\Eloquent\ActivityTrait;
public function author()
{
return $this->belongsTo('Author');
}
public function activityActorMethodName()
{
return 'author';
}
As far as letting volunteers follow companies and users, we have some documentation in the main README.
(edited to remove my mistaken github reference)
sorry for the late reply. I have managed to follow a company creating
a feed group:
company flat On
and the using sample code below to follow:
$feed = FeedManager::getClient()->feed('timeline', $user->id);
$feed->followFeed('company', $companyId);
Unfollow:
$feed->unfollowFeed('company', $companyId);
Add activity:
$companyFeed = FeedManager::getClient()->feed('company', $company->id);
$companyFeed->addActivity([
"actor" => "App\Company:{$company->id}",
"verb" => "company_post",
"object" => "App\CompanyPost:{$post->id}",
"foreign_id" => "App\CompanyPost:{$post->id}"
]);

Laravel 5 route protection

Assume we´ve got a User and Conversation model with a many-to-many relation.
class User extends Model ... {
public function conversations()
{
return $this->belongsToMany('App\Conversation');
}
}
class Conversation extends Model {
public function users()
{
return $this->belongsToMany('App\User');
}
}
Besides authentication (logging in) which comes out of the box with laravel: How can I protect a specific conversation route for it´s related users?
Which would be the most maintainable way to achieve this? Middleware? Guard? Route model binding? ... right now I´m a bit lost ...
Good question. In this case you'd be best off using Laravel's authorization features. Here are the differences:
Middleware: used to run logic based on either routes or logged in / logged out state. So, if you want to block the conversations entirely from non-logged in users, use a middleware.
Authorization (policies): not to be confused with authentication, is intended for cases where the rules to block someone is not based on route but on some other, more specific reason. These reasons can be anything from roles, to teams, entity ownership, and so on. If you wanted to hide a conversation to only those in the conversation, you can create a policy that kicks the user back to their previous page if they were not in the conversation.
Here's a quick policy you might create:
class ConversationPolicy {
public function view(User $user, Conversation $conv) {
return in_array($user->id, $conv->users->pluck('id'));
}
}
You could check your policy in a controller like the following:
if($request->user()->can('view', $conversation))
{
return view('conversation', ['conversation' => $conversation]);
}
return back()->withError('You are not authorized to view this conversation');
Just be aware you'll have to bind this policy in the AuthServiceProvider before it can be used.

Resources