Laravel role based page access - Trying to get property of non-object - Auth::user() - authentication

Still very new to Laravel 3 and working through some issues.
I'm trying to set up a role based access to page. Users are currently able to log in and that part works well but I want to restrict access to certain pages based on the users role eg admin, editor etc.
So, I've created a filter as follows:
Route::filter('check_roles', function () {
$current_url = URI::current(); //get current url excluding the domain.
$current_page = URI::segment(2); //get current page which is stored in the second uri segment. Just a refresher: //the first uri segment is the controller, the second is the method,
//third and up are the parameters that you wish to pass in
$access = 0;
$counter = 1;
//excluded pages are the pages we don't want to execute this filter
//since they should always be accessible for a logged in user
$excluded_pages = array(
'base' => array('login', 'user/authenticate'),
1 => array('user/profile', 'dashboard','dashboard/index','articles','articles/index', 'articles/create', 'articles/preview', 'articles/edit', 'user/profile', 'user/logout'),
2 => array('articles/publish','user/create', 'user/edit'),
3 => array('user/delete')
);
if (!in_array($current_url, $excluded_pages['base']) ) { //if current page is not an excluded pages
if(Auth::user()->level < 4) {
do {
if (in_array($current_url, $excluded_pages[$counter])) {
$access=1;
}
$counter++;
} while ($counter < $user_level AND $counter < 4);
if ($access == 0) { //if user doesn't have access to the page that he's trying to access
//redirect the user to the homepage
return Redirect::to('dashboard')
->with('error', 'You don\'t have permission to access the following page: ' . $current_url);
}
}
}
This is based on tutorial I found https://gist.github.com/anchetaWern/4223764
My thoughts were depending on user access level which is 'level' in the user object I'd filter the pages etc.
However I'm getting an error 'Trying to get property of non-object' this relates to this code:
if(Auth::user()->level < 4) {
testing Auth::user()->level in a view confirms the user is logged in. Can anyone advise why this doesnt work in the routes.php as a filter?
Thank you

Problem solved - I was using the incorrect syntax in my script which I realised once I posted here.
if($user_level = Auth::user()->level < 4) {
Should be:
if(Auth::user()->level < 4) {
Filter works now. However I'm looking at ways to improve as not sure this is the most efficient way now!
Thanks

Related

vBulletin 3.x - How to get custom variable to render template conditionals?

I am trying to make a product that will give me a different header based on the forum I am in, that's no problem and complete. My issue lays with using template conditionals inside of said option.
I am currently using a forum option to insert my custom template additions:
In global_complete hook I am using:
global $vbulletin;
if ($GLOBALS[foruminfo]["forumid"]>0) {
$forum_code = '';
$_fid = $GLOBALS[foruminfo]["forumid"];
$forum_info = $vbulletin->forumcache[$_fid];
if ($forum_info["code"]) {
$forum_code = $forum_info["code"];
} elseif ($forum_info["parentid"]) {
while ($forum_code=='' && $forum_info["parentid"]>0) {
$forum_info = $vbulletin->forumcache[$forum_info["parentid"]];
$forum_code = $forum_info["code"];
}
}
}
Then I place $forum_code into my header temple.
I would like to be able to get the conditionals to work so I can only show things to members or usergroups within the header. Is there a way to get the variable to not ignore the conditions? they are included in the DB entry, just being ignored when rendered to the page.
Sample Conditional:
<if condition="$show['member']">Member<else/>Guest</if>
What is actually being rendered:
MemberGuest

Yii2 ValidatePage to give empty output on wrong page number

I am trying to fetch a list of products from a table using my yii2 app and send it accross as a json to lazyload on scroll from the front end. I am using the searchmodel class. Now when data ends, last page data is being send again, i.e., if i have hundred records, the calls for page numbers above 5 would repeatedly send the same data as page number 4. How do i prevent it.
PS: Confused about the usage of the validatePage flag reading the documentation.
Here is my code of the controller.
public function actionAjaxIndex()
{
$searchModel = new productsS();
$response = (object) ['status' => 0];
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$response->status = 1;
$response->data = array();
foreach($dataProvider->models as $row){
foreach($row as $key=>$value){
$customerDetail[$key] = $value;
}
array_push($response->data, $customerDetail);
}
return json_encode($response);
}
Can somebody help with the best possible solution to go ahead.
You need to disable $validatePage for your data provider. This setting overwrites page if it is outside of range (so if you have 4 pages of records, but you request 5th page, pagination will automatically switch to 4th page - every page outside of range will display results for last page).
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->pagination->validatePage = false;

Restrict data for multiple users

I add multiple users as teacher. And I create a table where every teacher update his data that is documents etc.,but when another teacher login he can also view that data how user to restrict to show that to other users?
You need to read more about Yii, and how you can use it.
For your case you can read this: add condition
For your question you can do this in your action in controller:
0) ensure that user is logged in: \Yii::$app->user->isGuest || //redirect to login page or via Access control filters
1) get user id from user. (\Yii::$app->user->identity->id)
2) set this id in teacher document query. like andWhere(['teacher_id' => $userId]);
public function actionViewDoc()
{ $userId = \Yii::$app->user->identity->id;
$model = TeacherDoc::find()->andWhere(['teacher_id' => $userId]);
return $this->render('viewDoc', [
'model' => $model,
]);
}
This will resolve your issue.
UPD: For more advanced solutions you could use:
1) Access control filters
2) RBAC.

lucene query filter not working

I am using this filter hook in my Auth0 Delegated Administration Extension.
function(ctx, callback) {
// Get the company from the current user's metadata.
var company = ctx.request.user.app_metadata && ctx.request.user.app_metadata.company;
if (!company || !company.length) {
return callback(new Error('The current user is not part of any company.'));
}
// The GREEN company can see all users.
if (company === 'GREEN') {
return callback();
}
// Return the lucene query.
return callback(null, 'app_metadata.company:"' + company + '"');
}
When user logged in whose company is GREEN can see all users. But when user logged in whose company is RED can't see any users whose company is RED.
I need to make this when user logged in, user should only be able to access users within his company. (except users from GREEN company).
But above code is not giving expected result. What could be the issue?
This might be related to a little warning note on the User Search documentation page
Basically they don't let you search for properties in the app_metadata field anymore. Unfortunately, this change was breaking and unannounced.
We had to make changes to our API so that we keep a copy of the app_metadatas in a separate database and convert lucene syntax to MongoDB queries, so that we can query by a chain of user_id:"<>" OR user_id:"<>" OR ....
One caveat though, you can't pass a query that's longer than 72 user_ids long. This number is so far undocumented and obtained empirically.
Also, you can't rely on Auth0's hooks to add new users to your database, as these don't fire for social logins, only for Username-Password-Authentication connections.
I hope this gave you some explanation as for why it wasn't working as well as a possible solution.
If I were you, I would look for an alternative for Auth0, which is what we are currently doing.
I finally ended up with this solution.
Used search functionality to filter users. I had to change below two files.
fetchUsers function in client\actions\user.js
changed
export function fetchUsers(search = '', reset = false, page = 0)
to
export function fetchUsers(search = '#red.com', reset = false,
page = 0)
AND
onReset function in client\containers\Users\Users.jsx
changed
onReset = () => { this.props.fetchUsers('', true); }
to
onReset = () => { this.props.fetchUsers('#red.com', true); }

Instagram API: How to get all user media?

In general I need to get all user media.
User has more than 250 photos.
I do /users/1/media/recent/?access_token=...&count=250
But it returns only 20 photos.
Maybe instagram has a limit for getting media.
If it is, response has a pagination to solve it.
But there are only max ID photo. How to know the first (min) ID photo to paginate it then?
You're right, the Instagram API will only return 20 images per call. So you'll have to use the pagination feature.
If you're trying to use the API console. You'll want to first allow the API console to authenticate via your Instagram login. To do this you'll want to select OAUTH2 under the Authentication dropdown.
Once Authenticated, use the left hand side menu to select the users/{user-id}/media/recent endpoint. So for the sake of this post for {user-id} you can just replace it with self. This will then use your account to retrieve information.
At a bare minimum that is what's needed to do a GET for this endpoint. Once you send, you'll get some json returned to you. At the very top of the returned information after all the server info, you'll see a pagination portion with next_url and next_max_id.
next_max_id is what you'll use as a parameter for your query. Remember max_id is the id of the image that is the oldest of the 20 that was first returned. This will be used to return images earlier than this image.
You don't have to use the max_id if you don't want to. You can actually just grab the id of the image where you'd like to start querying more images from.
So from the returned data, copy the max_id into the parameter max_id. The request URL should look something like this https://api.instagram.com/v1/users/self/media/recent?max_id=XXXXXXXXXXX where XXXXXXXXXXX is the max_id. Hit send again and you should get the next 20 photos.
From there you'll also receive an updated max_id. You can then use that again to get the next set of 20 photos until eventually going through all of the user's photos.
What I've done in the project I'm working on is to load the first 20 photos returned from the initial recent media request. I then, assign the images with a data-id (-id can actually be whatever you'd like it to be). Then added a load more button on the bottom of the photo set.
When the button is clicked, I use jQuery to grab the last image and it's data-id attribute and use that to create a get call via ajax and append the results to the end of the photos already on the page. Instead of a button you could just replace it to have a infinite scrolling effect.
Hope that helps.
I've solved this issue with the optional parameter count set to -1.
It was a problem in Instagram Developer Console. max_id and min_id doesn't work there.
See http://instagram.com/developer/endpoints/ for information on pagination. You need to subsequentially step through the result pages, each time requesting the next part with the next_url that the result specifies in the pagination object.
In June 2016 Instagram made most of the functionality of their API available only to applications that have passed a review process. They still however provide JSON data through the web interface, and you can add the parameter __a=1 to a URL to only include the JSON data.
max=
while :;do
c=$(curl -s "https://www.instagram.com/username/?__a=1&max_id=$max")
jq -r '.user.media.nodes[]?|.display_src'<<<"$c"
max=$(jq -r .user.media.page_info.end_cursor<<<"$c")
jq -e .user.media.page_info.has_next_page<<<"$c">/dev/null||break
done
Edit: As mentioned in the comment by alnorth29, the max_id parameter is now ignored. Instagram also changed the format of the response, and you need to perform additional requests to get the full-size URLs of images in the new-style posts with multiple images per post. You can now do something like this to list the full-size URLs of images on the first page of results:
c=$(curl -s "https://www.instagram.com/username/?__a=1")
jq -r '.graphql.user.edge_owner_to_timeline_media.edges[]?|.node|select(.__typename!="GraphSidecar").display_url'<<<"$c"
jq -r '.graphql.user.edge_owner_to_timeline_media.edges[]?|.node|select(.__typename=="GraphSidecar")|.shortcode'<<<"$c"|while read l;do
curl -s "https://www.instagram.com/p/$l?__a=1"|jq -r '.graphql.shortcode_media|.edge_sidecar_to_children.edges[]?.node|.display_url'
done
To make a list of the shortcodes of each post made by the user whose profile is opened in the frontmost tab in Safari, I use a script like this:
sjs(){ osascript -e'{on run{a}','tell app"safari"to do javascript a in document 1',end} -- "$1";}
while :;do
sjs 'o="";a=document.querySelectorAll(".v1Nh3 a");for(i=0;e=a[i];i++){o+=e.href+"\n"};o'>>/tmp/a
sjs 'window.scrollBy(0,window.innerHeight)'
sleep 1
done
What I had to do is (in Javascript) is go through all pages by using a recursive function. It's dangerouse as instagram users could have thousands of pictures i a part from that (so your have to controle it) I use this code: (count parameter I think , doesn't do much)
instagramLoadDashboard = function(hash)
{
code = hash.split('=')[1];
$('#instagram-pictures .images-list .container').html('').addClass('loading');
ts = Math.round((new Date()).getTime() / 1000);
url = 'https://api.instagram.com/v1/users/self/media/recent?count=200&min_timestamp=0&max_timestamp='+ts+'&access_token='+code;
instagramLoadMediaPage(url, function(){
galleryHTML = instagramLoadGallery(instagramData);
//console.log(galleryHTML);
$('#instagram-pictures .images-list .container').html(galleryHTML).removeClass('loading');
initImages('#instagram-pictures');
IGStatus = 'loaded';
});
};
instagramLoadMediaPage = function (url, callback)
{
$.ajax({
url : url,
dataType : 'jsonp',
cache : false,
success: function(response){
console.log(response);
if(response.code == '400')
{
alert(response.error_message);
return false;
}
if(response.pagination.next_url !== undefined) {
instagramData = instagramData.concat(response.data);
return instagramLoadMediaPage(response.pagination.next_url,callback);
}
instagramData = instagramData.concat(response.data);
callback.apply();
}
});
};
instagramLoadGallery = function(images)
{
galleryHTML ='<ul>';
for(var i=0;i<images.length;i++)
{
galleryHTML += '<li><img src="'+images[i].images.thumbnail.url+'" width="120" id="instagram-'+images[i].id+' data-type="instagram" data-source="'+images[i].images.standard_resolution.url+'" class="image"/></li>';
}
galleryHTML +='</ul>';
return galleryHTML;
};
There some stuff related to print out a gallery of picture.
Use the best recursion function for getting all posts of users.
<?php
set_time_limit(0);
function getPost($url,$i)
{
static $posts=array();
$json=file_get_contents($url);
$data = json_decode($json);
$ins_links=array();
$page=$data->pagination;
$pagearray=json_decode(json_encode($page),true);
$pagecount=count($pagearray);
foreach( $data->data as $user_data )
{
$posts[$i++]=$user_data->link;
}
if($pagecount>0)
return getPost($page->next_url,$i);
else
return $posts;
}
$posts=getPost("https://api.instagram.com/v1/users/CLIENT-ACCOUNT-NUMBER/media/recent?client_id=CLIENT-ID&count=33",0);
print_r($posts);
?>
You can user pagination of Instagram PHP API: https://github.com/cosenary/Instagram-PHP-API/wiki/Using-Pagination
Something like that:
$Instagram = new MetzWeb\Instagram\Instagram(array(
"apiKey" => IG_APP_KEY,
"apiSecret" => IG_APP_SECRET,
"apiCallback" => IG_APP_CALLBACK
));
$Instagram->setSignedHeader(true);
$pictures = $Instagram->getUserMedia(123);
do {
foreach ($pictures->data as $picture_data):
echo '<img src="'.$picture_data->images->low_resolution->url.'">';
endforeach;
} while ($pictures = $instagram->pagination($pictures));
Use the next_url object to get the next 20 images.
In the JSON response there is an pagination array:
"pagination":{
"next_max_tag_id":"1411892342253728",
"deprecation_warning":"next_max_id and min_id are deprecated for this endpoint; use min_tag_id and max_tag_id instead",
"next_max_id":"1411892342253728",
"next_min_id":"1414849145899763",
"min_tag_id":"1414849145899763",
"next_url":"https:\/\/api.instagram.com\/v1\/tags\/lemonbarclub\/media\/recent?client_id=xxxxxxxxxxxxxxxxxx\u0026max_tag_id=1411892342253728"
}
This is the information on specific API call and the object next_url shows the URL to get the next 20 pictures so just take that URL and call it for the next 20 pictures.
For more information about the Instagram API check out this blogpost: Getting Friendly With Instagram’s API
Instagram developer console has provided the solution for it. https://www.instagram.com/developer/endpoints/
To use this in PHP, here is the code snippet,
/**
**
** Add this code snippet after your first curl call
** assume the response of the first call is stored in $userdata
** $access_token have your access token
*/
$maximumNumberOfPost = 33; // it can be 20, depends on your instagram application
$no_of_images = 50 // Enter the number of images you want
if ($no_of_images > $maximumNumberOfPost) {
$ImageArray = [];
$next_url = $userdata->pagination->next_url;
while ($no_of_images > $maximumNumberOfPost) {
$originalNumbersOfImage = $no_of_images;
$no_of_images = $no_of_images - $maximumNumberOfPost;
$next_url = str_replace("count=" . $originalNumbersOfImage, "count=" . $no_of_images, $next_url);
$chRepeat = curl_init();
curl_setopt_array($chRepeat, [
CURLOPT_URL => $next_url,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $access_token"
],
CURLOPT_RETURNTRANSFER => true
]);
$userRepeatdata = curl_exec($chRepeat);
curl_close($chRepeat);
if ($userRepeatdata) {
$userRepeatdata = json_decode($userRepeatdata);
$next_url = $userRepeatdata->pagination->next_url;
if (isset($userRepeatdata->data) && $userRepeatdata->data) {
$ImageArray = $userRepeatdata->data;
}
}
}
}