AngularJS - permission directive - permissions

I am trying to write directive that will evaluate user permissions.
In case user is not permitted to see given content
the content will not be displayed (done, working fine)
requests from controllers inside permission directive will not get
fired.
Example:
Controller:
function MyController ($scope){
// performing imediately server request, witch is allowed only for admin
// therefore i will get error when non admin user access this page
}
Permission directive:
return {
priority: 1000,
restrict: 'E',
link: (scope, element, attrs) => {
var permission = attrs.permission;
if (/*evaluating permission*/) {
// user has permission, no work for me
return;
}
element.remove();
}
};
All together:
<permission permission="isAdmin">
<div ng-controller="MyController">
</div>
</permission>
This version is removing elements from DOM, but request in MyController still gets executed. Off course, I can make check for permissions in MyController, but I don't want to.
Thank for help.

Your issue is that the controller will always be called before the link function executes. See this fiddle.
function MyCtrl($scope) {
console.log('in controller');
}
myApp.directive('permission', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
console.log('in link');
Log shows:
in controller
in link

I tried another approach and put removal of element into compile function. According to log, it is executed BEFORE controller, so it is right place. Anyway the request was still fired. So I tried just as a blind shot remove element children (I know, it does not make sense, removal of element should be sufficient and should remove children also).
But it worked!
compile: function(element) {
var children = element.children();
children.remove(); element.remove();
}
It is working, but I am not sure how much OK it is (e.g. future version Ang.)

If I were you I would make a call to the server and check if they are authorised for access.
Doing this with a directive does not really make sense.
Directives are generally for manipulating dom and this is authorisation confirmation should generally be handled in the controller and then have the result of that trigger an event.
Then have your directive be listening for that event and manipulate the dom if they got access from the server.
Otherwise anyone could easily just inject whatever they wanted and see your admin panel.
If your not sure what I mean let me know I can expand the answer if you need me to.

Related

How to a hide a page

I have a pop up that is called through a java script, the same pop up without a JavaScript is an ctp page in cakephp. How can I hide that page from users and search engines going to access it like: /users/register
Is there anything that can be done in .htaccess or cakephp to prevent access to it through /users/register
Remove register.ctp file from users folder and create one in ajax folder users/ajax/register.ctp, then use RequestHandler component to inspect request type:
public function register()
{
if($this->request->is('ajax')){
// add registration code here
} else {
//Throw new error
}
}

Meteor IronRouter onBeforeAction causes exception in defer callback

I'm trying to secure my meteor app with iron-router, here's my onBeforeAction function:
this.route('manageUsers', {
path: '/panel/user_management',
layoutTemplate: 'panel',
onBeforeAction: function(){
if((Meteor.user() === null)||(Meteor.user().role !== 'superAdmin')){
Router.go('signIn');
throwAlert('You dont have access to see this page', 'notification');
}
}
});
When I'm trying to go to /panel/user_management subpage by pressing a link button everything goes fine (user is redirected etc.), but when I type the path directly in my browser (localhost:3000/panel/user_management) and hit enter user is not getting redirected and I receive in console Exception in defer callback error. Anyone know what I'm doing wrong?
For additional information, this view lists me all users registered. When I go to this path normally (without error) I see complete user list. When I receive error template doesn't appear in > yield.
Finally, I've solved this - the problem was wrong if statement, here's the correct one:
if((!Meteor.user())||(Meteor.user().role !== 'superAdmin')){}

kendo ui editorfor imagebrowser returns 403

I'm new to web development and I'm trying to implement the Kendo UI editor with an image browser to insert into the document on an MVC 4.5 page. the editor is working fine, however, when i click the insert image button i gt a 403 forbidden popup message.
I've created a custom image browser controller pointing to ~/Content/images.
and in my view, i am using the custom browser controller within my code
#(Html.Kendo().EditorFor(m => m.QuestionText)
.Encode(false)
.HtmlAttributes(new { style = "width: 100%; height: 200px" })
.Name("EditQuestionText")
.Tools(tools => tools.Clear().InsertImage())
.ImageBrowser(imageBrowser => imageBrowser
.Image("~/JFA/QuestionImages/{0}")
.Read("Read", "JFAImageBrowser"))
)
I've compared my code to the sample project from Kendo for the EditorFor (which will browse the folder) but can find no discernible differences... I also cannot find much in the way of other people who are having this problem so i suspect there is a setting that i cannot find that is causing my issue, any help would be GREATLY appreicated
my image browser (taken directly from the demo)
public class JFAImageBrowserController : EditorImageBrowserController
{
private const string contentFolderRoot = "~/Content/images";
public override string ContentPath
{
get
{
return contentFolderRoot;
}
}
additionally, using Fiddler the click event for the "Insert Image" button is
GET /JFA/JFAImageBrowser/Read?path=%2F HTTP/1.1
where as the demo is
POST /ImageBrowser/Read HTTP/1.1
I don't know why the demo is using a POST where as mine is using a GET, unless this is because of the overridden image browswer
That code looks fine. Can you make sure your JFAImageBrowser controller looks something like this?
public class BlogImagesController : EditorImageBrowserController
{
//
// GET: /BlogImage/
public ActionResult Index()
{
return View();
}
public override string ContentPath
{
get { return AssetFilePaths.BlogContentPath; }
}
}
It's important that it inherits from EditorImageBrowserController
Also, a 403 may mean that the user doesn't have permission to access the directory. Check the permissions for the user you're running as.
It turns out my problem was in the _Layout page. I was using bundling and either
A) I made some error when setting up the bundling
-or-
b) the bundling didn't work as expected/intended.
either way i added the individual script/java script references and it works as expected.
Here is the solution to this problem
the page this issue fixed was it kendo forum
http://www.telerik.com/forums/implementing-image-browser-for-editor
and the direct link for the demo
http://www.telerik.com/clientsfiles/e3e38f54-7bb7-4bec-b637-7c30c7841dd1_KendoEditorImageBrowser.zip?sfvrsn=0
and if this demo didn't work you can see this sample i made from above
https://www.mediafire.com/?9hy728ht4cnevxt
you can browse the editor through HomeController and the action name is homepage (home/homepage)
& I think that the error was in different uses of paths between the base controller & child controller you make.

Press submit on Ajax Form from javascript / jquery timer

I would like to automatically click the submit button of an Ajax enabled form, so that the user does not have to click the button (but can optionally).
Right now, I'm working on the first boundary, which is to call the form from Javascript, so that at the very least, once i build my timer, I will have this part figured out.
I've tried many ways to do this, and NONE work. Please keep in mind that this is an ASP.NET MVC 4 Mobile application (which uses jquery.mobile) but I do have the jquery.mobile ajax disabled so that my button works at all (creating manual ajax based forms with updating divs, does not work in a jquery.mobile app because it hooks on the submit of all ajax forms).
So my current button works fine, I just can't seem to fire it programmatically.
I have my form:
<% using (Ajax.BeginForm("SendLocation", null, new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "result", HttpMethod = "POST" }, new { #id = "locationForm" }))
{ %>
<ul data-role="listview" data-inset="true">
<li data-role="list-divider">Navigation</li>
<li><%: Html.ActionLink("About", "About", "Home")%></li>
<li><%: Html.ActionLink("Support", "Support", "Home")%></li>
<li data-role="list-divider">Location</li>
<%: Html.HiddenFor(model => model.GPSLongitude)%>
<%: Html.HiddenFor(model => model.GPSLatitude)%>
<li><input type="submit" id="submitButton" value="Send" /></li>
</ul>
<% } %>
I have tried to do this in javascript:
$.ajax({
type: "POST",
url: action,
success: function () {
alert('success');
}
});
And I do get the server code firing that normally would. However, the DIV is not updated and also, the model was not intact either (it existed with all internal values null, so i assume newly instantiated).
I have also tried different ways to fire the form:
var form = $('#locationForm', $('#myForm'));
if (form == null) {
alert('could not find form');
} else {
alert('firigin on form');
form.submit(function (event) { eval($(this).attr("onsubmit")); return false; });
form.submit();
}
This did not work either:
var f = $('#locationForm', $('#myForm'));
var action = f.attr("action");
var data = f.attr("data");
$.post(action, data, function() { alert('back'); });
Which were all ways to do this that I found throughout the web.
None of them worked to fire the form and have it work the way it would normally as if a user had pressed the submit button themselves. Of course, once this fails, if I hit my submit button, it works perfectly...
Using Chrome Developer Tools, I found that the $.ajax call needs to have valid data before it will even attempt to function.
I was getting a silent Internal 500 Error on the post. But of course because of AJAX it was silent and the controller was not firing because it didn't get past IIS.
So I found out that the data I was sending, saying its JSON, was not and the .serialize() does not use JSON formatting. I tried to incorporate the JSON Javascript libraries to convert the object into JavaScript, however, this does not work either, because the Data Model object (or the form object) seems to not be compatible with those libraries. I would get errors in the JavaScript console and those libraries would crash when trying.
I decided to actually just pass the object I want manually:
var encoded = '{ GPSLongitude: ' + $('#GPSLongitude', $('#myForm')).val() + ',GPSLatitude: ' + $('#GPSLatitude', $('#myForm')).val() + '}';
Which passed the hidden fields i wanted to send (GPS LON/LAT) to the controller, and the model was intact in the controller call!
Now, for anyone that is reading this answer. the actual AJAX update process that is supposed to update the view, failed to work. Although for my purpose, I did not actually need the view to update correctly. Eventhough a partial view is returned, the special AJAX call seems to break the linkage between the form's div to update.
However, since the data was passed to the controller intact, this basically passed the GPS data that I needed to the server which was my ultimate goal.
make sure you are including the proper js libraries.
you need. jquery.js, jquery.unobtrusive-ajax.js
make sure unobtrusivejavascriptenabled = true in the web.confg
<appSettings>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
please try $('#locationForm').submit();
does it give error message?
if you're using i.e. you can look use the develper tools to look at network traffic to make sure nothing is sent.

How to use jQuery's .on with Rails ajax link?

I'm having a bunch of problems getting jQuery's .on to work with my Rails ajax link.
Specifically, I've got this link:
<div id="item_7_tools" class="item_tools">
<a rel="nofollow" id="book_item_7" data-remote="true" data-method="post" class="book_link" href="bookings">Book this item</a>
</div>
I've trimmed some of the text in the HTML, but suffice to say that that, and my controller response work.
I click "Book this item", it goes off to the controller, the controller does its magic, and sends back my partial that replaces the contents of that div.
So I'm now trying to replace the contents with an ajax spinner while the loading is working, and that's where its going pear-shape.
I'm trying this initial bunch of jQuery code just to make sure I've got my javascript working:
$('div.item_tools')
.on('click', 'a', function() {
console.log("clicky click")
})
.on('ajax:beforeSend', "a", function() {
console.log('the a in div.item_tools is sending its ajax command');
})
.on('ajax:complete', "a", function() {
console.log('ajax request completed');
})
My understanding of that, is that when I then click any link (a) that lives within an element with the item_tools class, it will bubble up to this function, and then log the message into the console. Similarly, a link that has triggered an ajax request will get the same treatment...
(And assuming I can get that to work, then I'll go to work doing the ajax loader spinner).
The behaviour I'm seeing instead, is that when I click the link, there are no messages appearing in my console (trying this on both firefox and chrome), and my ajax link goes off and does its stuff correctly. Just completely ignoring the javascript...
Is this because my clicking the ajax link somehow has blocked the click event from bubbling up? I know that there's a way to do that, but I don't think I've done it anywhere knowingly. Unless OOTB rails/ujs does that?
So my questions:
Is there a way to tell what has had a binding attached to it?
What am I doing wrong with my javascript?
Thanks!
I use this all the time... and it seems to work fine.
Have you tried adding one that's .on('ajax:success')?
Besides that try putting the . for each line on the previous line...? It's possible that it gets to $('div.item_tools') and then auto-inserts a semi-colon as per javascript's standard... Although if that were the case I'd expect it to give you a JS error about the . on the next line. In any case try changing it to:
$('div.item_tools').
on('click', 'a', function() {
console.log("clicky click")
}).
on('ajax:beforeSend', "a", function() {
console.log('the a in div.item_tools is sending its ajax command');
}).
on('ajax:complete', "a", function() {
console.log('ajax request completed');
})
If worse comes to worse try just doing:
$("a").on("ajax:success", function(){
console.log('ajax:success done');
})
And see if it works without the event delegation...
Then change it to this:
$(document).on("ajax:success", "a", function(){
console.log("ajax:success with delegation to document");
})
And see if delegation works all the way up to document instead of just your item_tools
Are you sure that you've named everything right? it's div.item_tools a in your markup?
Turns out that the javascript was being triggered before the DOM had loaded, which meant that stuff weren't being bound...
$(function () {
$('div.item_tools')
.on('click', 'a', function itemToolsAjaxy() {
console.log("clicky click");
})
.on('ajax:beforeSend', "a", function() {
console.log('the a in div.item_tools is sending its ajax command');
$(this).closest('div').html('<img src=/assets/ajax-loader.gif>');
})
});
Added the $(function()) right at the beginning and it delayed the binding until after the DOM had loaded, and then it started working.
Figured this out by using the Chrome developer tools to stick a break on the div.item_tools selector and watched as the browser hit that even before the DOM had been loaded. /facepalm
(I removed the .on('ajax:complete') callback, because it turns out that there's a known limitation where the original trigger element no longer exists because it had been replaced, so there's nothing to perform the callback on. Not relevant to my original problem, but I thought I'd mention it.)
As far as i'm aware, you can either do ajax stuff 2 ways:
By using :remote => true
By using jQuery's $.ajax (or $.post).
With number 2, make sure to change your href='#'
My suggeston is to remove the :remote => true and manually make a jQuery ajax call. That way you can use beforeSend, complete, etc.
If i'm way off track here, someone please help clarify things for me as well.