-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for bulk user exports #152
Conversation
This PR addresses issue #95 . Please let me know if you have questions, comments, concerns, or suggestions on this PR, I'm happy to assist. Thank you! |
f01153d
to
096c30e
Compare
final String payload = body.string(); | ||
return new JobError(response.code(), payload); | ||
} catch (final IOException e) { | ||
throw new APIException("Failed to parse response", response.code(), e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having a tough time mocking an appropriate response object that will force a throw on this line. This is causing CI coverage checks to fail due to insufficient coverage. Response
and MockResponse
are final classes, so they can't be sub-classed or modified to produce an IOException
in order to fall into this block.
Thoughts?
Any suggestions on ways to proceed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Skipping since class will disappear
@JsonProperty("limit") | ||
private int limit; | ||
@JsonProperty("fields") | ||
private List<List<Map<String, String>>> fields = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize this structure is a bit yucky... This is due to the spec provided by Auth0's API docs; the sample JSON response has an array within an array, which in turn contains a collection of objects that represent the field information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to move this into a new class. Lets create the UserExportField
class with two string properties:
- name (required, should be part of the constructor)
- export_as (optional, available via setter).
Then this class (let's rename it to UserExportOptions
) will have as fields: List<UserExportField> fields
. I'm confident the double array schema you see in the API docs is wrong. But will need to try this manually once you make the changes to be sure.
|
||
import java.io.IOException; | ||
|
||
public class StatusCodeRequest extends EmptyBodyRequest<JobError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a new request type and corresponding JobError
object in order to provide the ability to inspect the HTTP status code returned by the job_error
API endpoint. There didn't appear to be any other way to get that info aside from manually mapping the HTTP status code into the field directly as part of the response parsing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The http status code is irrelevant. It will be a 200
plus the error description (if job failed) in the body of the response.
This class should be deleted and instead the caller method should return a Request<JobError>
This commit adds the ability to create bulk user exports. With this update, a new request type of `StatusCodeRequest` was added in order to handle queries against the `job_error` endpoint which report the error result of a given job. Please note: With this change, consumers of the API will be responsible for fetching and decompressing the `gzip` file produced from the job request via the URL provided in the response.
096c30e
to
d859dfc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution and sorry for the delay. I've left you my initial assessment of the export functionality. I had to check with the backend team to ensure the API docs were correct. Anyway, I'll wait to hear back from you before reviewing in detail the tests.
* | ||
* @return A request to execute the job. | ||
*/ | ||
public Request<Job> exportUsers() { return this.exportUsers(new UsersExport()); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This signature is not needed. I can't imagine a scenario where I'd call the endpoint without any parameters
final int limit = usersExport.getLimit(); | ||
final List<List<Map<String, String>>> fields = usersExport.getFields(); | ||
|
||
if (this.isValued(connectionId)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the null-checks below this line should belong to the UserExport
class. Any required properties should be set on instantiation and the constructor should validate them. Here you only need to check that the UserExport
instance is not null like you're doing in the first line. Later when constructing the request, null values would be ignored by the function that inserts the values into the request.
return request; | ||
} | ||
|
||
private StatusCodeRequest generateJobErrorRequest(final String url) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is called only once. I don't see the point on extracting it into a new method.
request.addHeader("Authorization", "Bearer " + apiToken); | ||
request.setBody(requestBody); | ||
return request; | ||
} | ||
|
||
private CustomRequest<Job> generateJobRequest(final String url) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is called only once. I don't see the point on extracting it into a new method.
.toString(); | ||
} | ||
|
||
private boolean isValued(final String string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this method and use Asserts.assertNotNull(propertyValue, "property description")
instead. Any invalid value further than a null can be considered user error and will be ultimately validated by the server.
final String payload = body.string(); | ||
return new JobError(response.code(), payload); | ||
} catch (final IOException e) { | ||
throw new APIException("Failed to parse response", response.code(), e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Skipping since class will disappear
final Map<String, Object> body = bodyFromRequest(recordedRequest); | ||
assertThat(body.size(), is(4)); | ||
assertThat(body, hasEntry("connection_id", CONNECTION_ID)); | ||
assertThat(body, hasEntry("format", CSV)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should check that the fields
and limit
properties are also present with the correct values (Applies to all similar tests)
* @param usersExport Object containing the parameters by which the user export job will be run. | ||
* @return A request to execute the job. | ||
*/ | ||
public Request<Job> exportUsers(final UsersExport usersExport) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's name it requestUsersExport
* @param jobId Id of the job to be retrieved | ||
* @return A request to execute the job details retrieval. | ||
*/ | ||
public Request<Job> getJob(final String jobId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally I'd say get
is enough but since this class is handling many types of errors and requests, I think you made a good call here.
@JsonProperty("limit") | ||
private int limit; | ||
@JsonProperty("fields") | ||
private List<List<Map<String, String>>> fields = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to move this into a new class. Lets create the UserExportField
class with two string properties:
- name (required, should be part of the constructor)
- export_as (optional, available via setter).
Then this class (let's rename it to UserExportOptions
) will have as fields: List<UserExportField> fields
. I'm confident the double array schema you see in the API docs is wrong. But will need to try this manually once you make the changes to be sure.
Hey @mfb2, are you still interested in this feature? Don't hesitate asking any follow up questions. |
I am still interested in the feature. I had been waiting for this PR to be reviewed since September last year, and my project has since moved on. We had to fork this project at an earlier version in order to finish our work. I do not have time to address the volume of feedback as I am no longer funded to do development on this product. I believe in open source and a vibrant community of contributions; our challenge here appears to be in aligning expectations. When resources permit, I will push an update to incorporate your feedback. In the meantime, I encourage you to leverage my contribution as a quick-start for completing the feature. |
@mfb2 We appreciate your contribution, apologise for the time taken to action it originally. I agree it may make a good quick-start as you put it. However, we have a lot of repos and don't typically pick up and continue another authors work unless it aligns with our own priorities. I'm happy to leave this PR open for a while as it would be great to see you complete your contribution 👍 |
Closed due to inactivity. |
This commit adds the ability to create bulk user exports. With this
update, a new request type of
StatusCodeRequest
was added in order tohandle queries against the
job_error
endpoint which report the errorresult of a given job.
Please note: With this change, consumers of the API will be responsible
for fetching and decompressing the
gzip
file produced from the jobrequest via the URL provided in the response.