Does AdminDirectory.Users.list support query with showDeleted=true? - google-admin-sdk

I'm trying to retrieve data for a deleted user (in order to undelete it) in this way:
var users = AdminDirectory.Users.list({
domain: 'mydomain.com',
showDeleted: 'true',
query: 'email=name.surname#mydomain.com'
});
query parameter seems to be ignored: this code returns a list of all deleted users, while if I run the same code for active users (no showDeleted:'true', and email of active user) it returns the user's email address as expected
am I missing anything? or is this the default behavior when showDeleted:'true' is used?
thank you

Looks like the behavior you are describing might in fact be a bug.
Because of this, I have taken the opportunity to file a report on Google's Issue Tracker here. I suggest you star the issue as all the updates will be posted there.

Related

How can I require an api-token field on requests?

I'm currently building a Google Cloud Endpoints backend with the endpoints-proto-datastore library, and am running into trouble requiring an apikey when you request a user.
Once a user logs in, they receive an APIkey which they send back for successive puts (which works) but how do I require the username/email and apikey on a GET ? Currently if a user does a get like so:
#User.method(request_fields=('id', 'apiToken',), path='users', http_method='GET', name='user.get')
def user_get(self, query):
return query
The user is pulled from the datastore because the ID is correct, and it completely ignores the apiToken. How do I require both fields?
(on a different note, how do I send back the user's ID on a request?)
If you are implementing your own API key scheme, as your code suggests, then you need to manually check if the API key is valid or not yourself.
Your example looks like the one from the 'basic' example, and you've added parameters as per the 'simple_get' example. For some background, the docs in the 'simple_get' example mention that 'id' is one of five special helper properties automatically defined by EndpointsModel for common operations like retrieving by id. This is why your code works automatically without you doing anything 'special' with the 'id' parameter. The example still checks though that the entity exists if you try to get it:
if not my_model.from_datastore:
raise endpoints.NotFoundException('MyModel not found.')
Since there's no special helper property for your 'apiKey' field, you need to add your own code in the method to check if the key is valid and return a 401 or suitable error if it's not. Another option is to also utilize some of Google's built-in authentication as per the 'basic_with_auth' example.
Finally, since endpoints-proto-datastore is just syntactic sugar for the main endpoints library, you'll want to read the full documentation on that for more information on things like how to return values from your endpoints methods.
The easiest way I found to do this is:
#User.method(request_fields=('id', 'apiToken',), path='users', http_method='GET', name='user.get')
def user_get(self, user_model):
user = ndb.Key('User', int(user_model.id)).get()
if user.apiToken != user_model.apiToken:
raise endpoints.UnauthorizedException('You are not authorized to view this data')
return user.clean()
The user_model will have the userId and the apiToken stored in it, so I pull the "real" data from ndb with the key and check if the user_model has the correct token and return the model if it is correct, if not, I refuse

Is it possible to get the current User’s roles accessible in a remote method in Loopback?

Is it possible to get the current User’s roles accessible in a remote method in Loopback?
I’m trying to allow a remote method to either return a subset of data based on a find using a where filter & current userId but in the case of an admin user, I simply want to return a full set of data.
So I have been trying to obtain the list of roles for the current user. But I am struggling to make Role.getRoles() return anything other than:
[ '$unauthenticated', '$everyone' ]
I have tried the context from loopback.getCurrentContext() and the context passed into the beforeRemote method and I have tried ACL.checkAccessForContext().
Any help would be appreciated.
This can happen for many reasons, one is that the Role model is not related to your User model (see here for brief explanation). Can you check that?
Other than that, it's probably that first argument (context) which we need to have better documentation on ( sorry :( ). If you look at the tests for the role class you can see how it might be used.
var RoleMapping = loopback.RoleMapping;
RoleMapping.attachTo(ds); // `ds` is your data source
// ...
Role.getRoles({principalType: RoleMapping.USER, principalId: user.id}, function(err, roles) {
console.log(roles); // everyone, authenticated, etc (hopefully)
});

Ember data entity id generation

When new model is created and saved with RESTAdapter its Id property is undefined, because my backend is responsible for id generation. So when I return to grid there is 2 same entities: first - with empty Id (from RESTAdapter cache, I think) and second - with correct Id returned from backend.
Any ideas? Maybe it is posiible to disable RESTAdapter cache?
UPDATE
My code for entity creation.
submit:function () {
var manager = App.store.createRecord(App.Manager, {
firstName:this.get('firstName'),
lastName:this.get('lastName'),
speciality:this.get('speciality')
});
App.store.commit();
this.get('controller').transitionTo('managers');
return false;
}
NEW UPDATE
Thanks to Mike Grassotti hints. Here some details for my issue.
One antity have Id, another have no Id.
If I remove App.store.commit() code, there is no POST to server and only entity without Id will be displayed.
This entity has isLoaded=false and isError=true.
When new model is created and saved with RESTAdapter its Id property is undefined, because my backend is responsible for id generation.
Right, but there is nothing unusual about this - ember expects id generation to be done by the backend.
So when I return to grid there is 2 same entities: first - with empty Id (from RESTAdapter cache, I think) and second - with correct Id returned from backend.
OK. What do you mean by same 2 entities - surely they are different js objects. Try logging each of them to console like this:
console.log(entityOne.toString());
console.log(entityTwo.toString());
Any ideas?
There are many things that could cause this to happen. Sounds like somehow you are creating two new records and saving just one of them. Or could be the API response does not match what ember expects, causing an extra record to get created.
Try to enable logging on your records, then watch console so you can see what's going on as your model is saved. Hopefully this will give you some insight into when/how the extra record is being created.
record.set("stateManager.enableLogging", true)
Inspect browser communication with your api and compare JSON to see if it matches what the ember rest adapter expects.
Post that JSON and the rest of your source code (model definition, etc.) to Stack Overflow, maybe a second set of eyes will help.
Check this post for some other debugging tips: http://www.akshay.cc/blog/2013-02-22-debugging-ember-js-and-ember-data.html
Maybe it is posiible to disable RESTAdapter cache?
RESTAdapter does not maintain a separate cache of model objects. And since you are not trying to do anything special, there should be no need to take a step like that.
Many thanks to Mike Grassotti, I have found an answer to my question.
The good question was
With App.store.commit() back in, what does the JSON response from
server look like?
+1 for that comment.
I can't find any info in ember-data documentation for that, so some links still would be helpful for me. I change the result returned from backend and everything works fine now.
{
"manager": {
"firstName": "test",
"lastName": "test",
"speciality": "test",
"id": "acd325ac-03eb-419e-be8a-d4ac42e8c235"
}
}

Parameter not supported by web service

I want to validate an opinion with you.
I have to design a web service that searches into a database of restaurants affiliated to a discount program in a specific country around a given address.
The REST call to such a webservice will look like http://server/search?country=<countryCode>&language=<languageCode>&address=<address>&zipcode=<zipcode>
The problem is that some countries do not have zipcodes or do not have them in the entire country.
Now, what would you do if the user passes such a parameter for a country that does not have zipcodes, but he/she passes a valid address?
Return 400 Bad request.
Simply igonre the zipcode parameter and return results based on the valid address
Return an error message in a specific format (e.g. JSON) stating that zipcodes are not supported for that country
Some colleagues are also favoring the following option
4. Simply return no results. And state in the documentation that the zipcode parameter is not supported. Also we have to create a webservice method which returns what fields should be displayed in the user interface.
What option do you think is best and why?
Thanks!
Well the OpenStreetMap Nomination Server returns results even if you dont know the ZIP Code and you can look at the results anyway. What if the user doesnt know the zip code but wants to find hist object?
I would try to search for that specific object anyway, especially because you said that some countries have zip codes partially.
If you simply return nothing te user doesnt know what went wrong and he wont know what to do.
That would depend on the use case. How easy is it for a user of the API to trigger that case? Is it a severe error which the user really should know how to avoid? Or is it something that is not entirely clear, where a user may know (or think he knows) a zipcode where officially there shouldn't be one? Does it come down to trial and error for the user how to retrieve correct results from your API? Is it a bad enough error that the user needs to be informed about it and that he needs to handle this on his side?
If you place this restriction in your API, consider that it will have to be clearly documented when this case is triggered, every user of the API will have to read and understand that documentation, it needs to be clear how to avoid the problem, it needs to be possible for the user to avoid the problem and every user will have to correctly implement extra code on his side to avoid this problem. Is it possible for the user to easily know which areas have zipcodes and which don't?
I think the mantra of "be flexible in what you accept, strict in what you output" applies...

Cookie to log in with Jsoup?

For a project I'm trying to get data from a website only acessible when you're logged in from the site Goodreads.com. I'm new to Jsoup, since I'm using it only for this particular project. Getting the relevant data from the website is not a problem, but I can't seem to get to the particular page I need. The page I'm trying to acces is viewable only when logged in, when not logged in it rederects to the log-in page.
I've looked through the answers here, but the answers given so far have not helped.
What I have now:
String url = "http://www.goodreads.com/friend/user/7493379-judith";
Connection.Response res = Jsoup.connect("http://www.goodreads.com/user/sign_in")
.data("email", "MYEMAIL", "user_password", "MYPASSWORD")
.method(Connection.Method.POST)
.execute();
Document doc2 = res.parse();
String sessionId = res.cookie("_session_id");
Document doc = Jsoup.connect(url)
.cookie("_session_id", sessionId)
.get();
I got this far with help of the answers here, but it doesn't work, I'm still only getting the data from the log-in page it rederects to.
I have several questions:
Most importantly of course; How can I make it work?
The given answers here heve used method.(Method.POST) instead of method.(Connection.Method.POST) . When I use the first one however, I get an error that Method cannot be resolved. Anyone know why this is?
The examples I've seen have used "username" and "password" in .data() . What exactly do these refer to? I've now used the name of the input box. Is it the name, the type, the id, what exactly? Since Goodreads does not refer to the log in as the username, but as the e-mail, I assume I have to change them. (username & password doesn't work either)
Examples also use http://example.com/login.php as example url. Goodreads doesn't have a /login.php page though. Am I correct to assume I have to use the url with the log-in screen?
_session_id is the name of the relevant cookie on Goodreads.
I'd be very grateful if anyone can point me in the right direction!
See carefully what data is posted on login:
user[email]:email#email
remember_me:on
user[password]:plain_pasword
n:667387
So your post must execute exact same keys.
2.Make sure, you make right import: import org.jsoup.Connection.Method;
but Connection.Method.POST is still good.
3.See p1
4.Yes, you are correct
5.what is the question?
Goodreads requires two things when logging in: first, that you have a session ID stored in a cookie, and second, that you have a random generated number. You can get these when first visiting the login page without logging in: it will set a cookie with a session ID, and the form will contain a hidden input form (i.e. ) with the name "n" and value a number. Save these and pass them along as respectively a cookie and a form value when logging in.
Some remarks about the way I found this out:
The first thing you need to realise is that you're trying to recreate the exact same requests your browser does with Jsoup. So, in order to check whether what you have right now will work, you can try to recreate the exact same situation with your browser.
To recreate your code, I went to the login page, then I deleted all my Goodreads cookies (as you don't send along any cookies when you send the login request as well), and attempted to sign in with only passing the username and password form values. It gave an error that my session had timd out. When I first loaded the login page and then deleted all cookies except the session ID and did not remove the "n" form value, I could log in successfully. Therefore, you want to make a general GET request to the sign in page first, retrieve the session ID cookie you get there and the hidden form value, and pass it along with the POST request.
It could be that the API changed or that there just are several ways. Using Connection.Method.POST will do fine, in any case.
Yes, they refer to the names of the input boxes. This should be id, however, since name was used in the past and not all versions of all browsers supported passing the ids as data, most websites are just adding both. Either should be fine.
If you look at the source code of the sign in form, you can see that the "method" attribute of the form element is indeed the sign in page itself, so that's where it sends the request to.
PS. As a general tip, you can use the Firefox extension "Tamper Data" to remove form data or even cookies (though there are easier extensions for that).
You can log in with this code:
public static void main(String[] args) throws Exception {
Connection.Response execute = Jsoup
.connect("https://www.goodreads.com/")
.method(Connection.Method.GET).execute();
Element sign_in = execute.parse().getElementById("sign_in");
String authenticityToken = sign_in.select("input[name=authenticity_token]").first().val();
String n = sign_in.select("input[name=n]").first().val();
Document document = Jsoup.connect("https://www.goodreads.com/user/sign_in")
.data("cookieexists", "✓")
.data("authenticity_token", authenticityToken)
.data("user[email]", "user#email.com")
.data("user[password]", "password")
.data("remember_me", "on")
.data("n", n)
.cookies(execute.cookies())
.post();
}