Skip to content
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

RESTWS-562 Improve Resource Definition Documentation #288

Merged
merged 2 commits into from
Aug 25, 2017

Conversation

gayanW
Copy link
Member

@gayanW gayanW commented Jul 14, 2017

  • adds swagger-core library
    • uses its Java API and model classes to construct and generate the swagger json.
  • introudce new methods which model objects used in constructing the definitions section:
    • getGETModel(Representation) : returns a object represting GET representation schema of resource
    • getCREATEModel(Representation) : returns a object representing CREATE representation shema of a resource
    • getUPDATEModel(Representation) : returns a object representing POST Update representation schema of a resource

ex: PersonGet, PersonCreate, PersonUpdate

  • adds new test cases to: SwaggerSpecificationCreatorTest.java

  • adds support for multiple representation types
    GET schemas have support for representations: DEFAULT, REF, and FULL
    CREATE schemas have support for representations: DEFAULT, and FULL
    POST_UPDATE schemas have support for representations: DEFAULT

    • uses default schema for the shema of responses and parameters

Swagger before: http://www.jsoneditoronline.org/?id=6ac2d0c797f5e8e4060d09b62b300b04
Swagger after: http://jsoneditoronline.org/?id=d692754b9b4543f7388572317dc10400

@mention-bot
Copy link

@gayanW, thanks for your PR! By analyzing the history of the files in this pull request, we identified @teleivo, @tmarzeion and @psbrandt to be potential reviewers.

@dkayiwa
Copy link
Member

dkayiwa commented Jul 14, 2017

@gayanW did you see the travis failure?

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.199% when pulling 9e900e6 on gayanW:restws-662 into 41d46ef on openmrs:master.

@gayanW
Copy link
Member Author

gayanW commented Jul 15, 2017

@dkayiwa minor mistake : ) please check now

@psbrandt
Copy link
Member

@bholagabbar, are you reviewing this PR?

For this to work, do developers have to implement the getGETModel, getCREATEModel and getUPDATEModel methods in their resources? I haven't taken a look at the code, but is this enforced somewhere? What happens if these methods aren't implemented?

@gayanW
Copy link
Member Author

gayanW commented Jul 17, 2017

@psbrandt @bholagabbar

For this to work, do developers have to implement the getGETModel, getCREATEModel and getUPDATEModel methods in their resources? I haven't taken a look at the code, but is this enforced somewhere? What happens if these methods aren't implemented?

Unless introducing a new resource, it is not mandatory to implement those methods. However if not, their definitions won't appear in the swagger doc. But it will not affect the program in any other way.

I've updated almost all the resources within the rest module. Methods such as getRepresentationDescription(..) is no longer being used to generate the documentation. However I did not remove any of these existing code in case they are being accessed by other modules.

@bholagabbar
Copy link
Member

@psbrandt @dkayiwa Sorry, I've been away on the Google trip. I am trying to make an attempt to yes, but reviewing 117 files changes !? There probably was a better way to break it into subtasks

Copy link
Member

@bholagabbar bholagabbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have reviewed a few files. Can't possibly go through them all at once. Will get back to it in a while. Do resolve/provide justifications for the ones I have marked meanwhile

boolean limit = false, startIndex = false;

for (Parameter p : o.getParameters()) {
for (io.swagger.models.parameters.Parameter p : o.getParameters()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gayanW Not good coding practice IMO. import io.swagger.models.parameters.Parameter and then use it. You've removed import org.openmrs.module.webservices.docs.swagger.Parameter so it shouldn't cause a conflict right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll replace all possible fully qualified class names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -9,6 +9,7 @@
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gayanW AnimalResource? Are you using tests for the stock swagger project? The animal store one? We need to have tests with patients and other proper openmrs classes

@@ -9,6 +9,7 @@
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gayanW It seems as though all the animal tests have just been stashed here. We can't have that. Can you justify your decision? It doesn't make sense to me

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They have always been there. I only implemented the missing methods. It seems that they are only used by RestServiceImplTest

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa What do you think? Should we have these tests? On the surface, AnimalClassResource doesn't seem right inside an OpenMRS webservices module. Ideally we should be replacing these tests?

import java.util.Map.Entry;
import java.util.Set;

import io.swagger.models.*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gayanW No wildcard imports. Period. Remove all of them and replace them with individual classes

<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error in XML formatting. Indentation is off

.property("endDate", new DateProperty())
.property("patientUuid", new StringProperty());
}
//FIXME missing props
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gayanW did you see the above question mark?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa IMO. lines marked FIXME that'll update the swagger properties will be better fix in a new separate issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -9,12 +9,14 @@
*/
package org.openmrs.module.webservices.rest.web.v1_0.resource.openmrs1_9;

import io.swagger.models.Model;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this import being used here? Get rid of all unused imports in all the files if they exist

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.202% when pulling 5e2e234 on gayanW:restws-662 into 41d46ef on openmrs:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.202% when pulling 5e2e234 on gayanW:restws-662 into 41d46ef on openmrs:master.

@gayanW
Copy link
Member Author

gayanW commented Jul 19, 2017

FYI: IMO reviewing all resource classes is not going to be practical. It takes a lot of effort to find right attributes, and their respective types of a resource. I had to go through ones' parent classes, supportedClass, respective tests and so on. So I think It will suffice therefore to review SwaggerSpecificationCreator and the generated json spec. And may be just go through the resource classes.

@bholagabbar
Copy link
Member

@dkayiwa @psbrandt I've asked gayan to push commits as he fixes issues so it makes it easier for us to review PRs. Once we review everything and give him the go ahead, he can squash and then merge. Reviewing 280 files changes is insanity!

@dkayiwa
Copy link
Member

dkayiwa commented Aug 7, 2017

@gayanW did you see the merge conflicts on this?

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.261% when pulling 7b4e50d on gayanW:restws-662 into 7a39d69 on openmrs:master.

@gayanW
Copy link
Member Author

gayanW commented Aug 8, 2017

@dkayiwa The pr was gone stale. I just rebased it.

@dkayiwa
Copy link
Member

dkayiwa commented Aug 11, 2017

@gayanW your pull request deals with a lot of things, formatting, imports, classname changes, etc.
I would recommend a separate pull request for each of these. That way, we do not have to deal with a huge pull request whose changes are unrelated.

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.261% when pulling 2811451 on gayanW:restws-662 into 7a39d69 on openmrs:master.

@gayanW
Copy link
Member Author

gayanW commented Aug 12, 2017

@bholagabbar @dkayiwa
Thanks for the inputs :)

I squashed, and eliminated those formats/fix done on classes that are not directly relevant to our use case. So now we have only the changes made to the SwaggerSpecificationCreator and the resource classes.

To my understanding, it's inevitable not to update all the resources, because then it would result in a partial swagger spec.

Copy link
Member

@bholagabbar bholagabbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa I have had a cursory glance at the changes. With most of these as swagger spec definitions, I believe merging the PR and further testing it on the QA instance would be the right way to go.

.property("previousOrder", new RefProperty("#/definitions/OrderCreate"))
.property("orderReason", new RefProperty("#/definitions/ConceptCreate"));
}
//FIXME missing prop: type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gayanW is this comment relevant?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 1_8, orderType is marked required. But in 1_10 it seems that this property is no longer required to place a new order. For those that I thought would need extra testing, and research, I put FIXME. May we fix these in a new PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention this in the next issue you create where you will be fixing the changes you removed formatting, etc not directly relevant to this issue

@@ -102,6 +108,43 @@ public DelegatingResourceDescription getRepresentationDescription(Representation
}
}

@Override
public Model getCREATEModel(Representation rep) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intentionally name this as getCREATEModel instead of getCreateModel?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be I thought that it was more readable. Anyway I could change that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do your mentors prefer getCREATEModel to getCreateModel?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think they commented on this. If you prefer getCreateModel over getCREATEModel, I can refactor.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you ask them and tell me what they prefer?

Copy link
Member

@bholagabbar bholagabbar Aug 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since GET, CREATE and UPDATE are actions that are being documented, captial cases indicating the action makes sense. I understand the deviation from camelCase but this makes the code more readable. I am fine with this. @dkayiwa I leave the final decision upto you

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just wanted to make sure that you are aware of this. 😊


@Override
public Model getCREATEModel(Representation rep) {
return super.getCREATEModel(rep); //FIXME missing props
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the FIXME supposed to be addressed in another pull request?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. As discussed with Shreyans they will be fixed in a separate issue. These will require minor to no change at all. But may need testing and discussion.

@@ -74,7 +79,7 @@ public DelegatingResourceDescription getRepresentationDescription(Representation
description.addProperty("validator");
description.addProperty("locationBehavior");
description.addProperty("uniquenessBehavior");
description.addProperty("validator");
description.addProperty("validator"); //FIXME duplicate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you do plan to fix the above?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gayanW create an issue on JIRA and paste a link here for reference

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bholagabbar should I create, before or after this is being merged?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create it now and paste the link, is there an issue with this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public class SwaggerSpecificationCreatorTest extends BaseModuleWebContextSensitiveTest {

@Test
public void mainTest() {
String baseUrl = "localhost:8080/openmrs/ws/rest";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work even when the 8080 port is used by some other process?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested this with different listening and open ports. And it has no effect on where the API is exposed. It changes the baseUrl of the swagger json, and as this is a test it has no much significance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In either case, hard coding a port number is not good practice. Make BaseUrl generic if it doesn't make a difference

Copy link
Member Author

@gayanW gayanW Aug 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm alright. I'm convinced when you tell me that it has no significance/doesn't affect the code but having something like 'http:8080/localhost' is never good practice even if it's in tests. Just assign it as 'base_url/ws/rest` or something if it doesn't have any significance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok this looks good

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.261% when pulling 270edab on gayanW:restws-662 into e12f8c7 on openmrs:master.

public Model getGETModel(Representation representation) {
return null;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a number of these methods simply return null. Shouldn't it be enough not to have them and assume that whichever class does not have them, null it is? Am looking at reducing the amount of code that we have to maintain.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa
Yeah I see. But isn't that good that we enforce them? So when creating a resource class one knows that he should document them? BTW I'm following a similar approach as it's done in old getRepresentationDescription

Copy link
Member Author

@gayanW gayanW Aug 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa It's your call :) ideally only a test resource should return null values. Other resources will either implement or could just inherit from its parent

Copy link
Member

@dkayiwa dkayiwa Aug 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which class or interface are these methods declared?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.29% when pulling b9a970e on gayanW:restws-662 into e12f8c7 on openmrs:master.

@dkayiwa
Copy link
Member

dkayiwa commented Aug 23, 2017

@gayanW i have tried running these changes locally and saw a few more resources show up like "address", "allergy", "answer". Was this an intentional side effect of this pull request? Or is it something else?

@gayanW
Copy link
Member Author

gayanW commented Aug 24, 2017

@dkayiwa Swagger UI separates path operations by their tags. With the changes, subresources were tagged by their resource name instead of their parent name.

"/patient/{parent-uuid}/allergy": {
      "get": {
        "tags": [
          "allergy"
        ],
        "summary": "Fetch all non-retired allergy subresources",

So in the older spec tag is set to patient, but here it's allergy. I didn't give enough thought in to this. May be its better that we use the parent tag..?

Let me know. I'll keep changes ready.

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.286% when pulling 07897dd on gayanW:restws-662 into e12f8c7 on openmrs:master.

@dkayiwa
Copy link
Member

dkayiwa commented Aug 24, 2017

@gayanW can you engage the community to see what others say?

@gayanW
Copy link
Member Author

gayanW commented Aug 24, 2017

I changed it to the old way. (FYI: only these 2 lines were changed - SwaggerSpecificationCreator.java#L602 SwaggerSpecificationCreator.java#L1001)

@dkayiwa
Copy link
Member

dkayiwa commented Aug 24, 2017

Ok let me compile and test it out again.

@gayanW
Copy link
Member Author

gayanW commented Aug 24, 2017

@dkayiwa
You may also have a look at the final json: https://<>/openmrs/module/webservices/rest/swagger.json

The changes will be visible once we upgrade the ui: RESTWS-560

@dkayiwa
Copy link
Member

dkayiwa commented Aug 24, 2017

So how will i see the changes before RESTWS-560 is done?

@gayanW
Copy link
Member Author

gayanW commented Aug 24, 2017

@dkayiwa Some changes are still visible with the old ui. But if you want to see all the changes, you may try this out: http://editor.swagger.io/

And paste the content of the swagger.json there.

@dkayiwa
Copy link
Member

dkayiwa commented Aug 24, 2017

How long would it take to finish the other ticket?

@gayanW
Copy link
Member Author

gayanW commented Aug 24, 2017

@dkayiwa It is better to work on it once this is finished.
BTW it won't take much time to do the ui upgrade. I've already tested locally.

@dkayiwa
Copy link
Member

dkayiwa commented Aug 24, 2017

@gayanW i have just tested again and noticed that the q parameter is not highlighted as required, with your changes. Was that intentional? https://qa-refapp.openmrs.org/openmrs/module/webservices/rest/apiDocs.htm#!/order/getAllOrders

@gayanW
Copy link
Member Author

gayanW commented Aug 24, 2017

@dkayiwa
Are you sure it is not marked required for GET /order?
http://localhost:8080/openmrs/module/webservices/rest/apiDocs.htm#!/order/getAllOrders
I ran locally and it is marked required.

q param is not marked required for resources that supports fetchAll.
/concept Fetch all non-retired concept resources or perform search
http://localhost:8080/openmrs/module/webservices/rest/apiDocs.htm#!/concept/getAllConcepts

If there's more than one query param, then it is not marked required either.
http://localhost:8080/openmrs/module/webservices/rest/apiDocs.htm#!/encounter/getAllEncounters

- adds swagger-core library
  * uses its Java API and model classes to construct and generate the swagger json.
- introudce new methods which model objects used in constructing the definitions section:
  * getGETModel(Representation) :  returns a object represting GET representation schema of resource
  * getCREATEModel(Representation) : returns a object representing CREATE representation shema of a resource
  * getUPDATEModel(Representation) : returns a object representing POST Update representation schema of a resource

ex: PersonGet, PersonCreate, PersonUpdate
- adds new test cases to: SwaggerSpecificationCreatorTest.java

- adds support for multiple representation types
GET schemas have support for representations: DEFAULT, REF, and FULL
CREATE schemas have support for representations: DEFAULT, and FULL
POST_UPDATE schemas have support for representations: DEFAULT

  * uses default schema for the shema of responses and parameters
@dkayiwa
Copy link
Member

dkayiwa commented Aug 24, 2017

@bholagabbar what behavior do you get in regards to the above?

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.9%) to 40.286% when pulling c739c17 on gayanW:restws-662 into e12f8c7 on openmrs:master.

.property("accessionNumber", new StringProperty())
.property("dateActivated", new DateProperty())
.property("scheduledDate", new DateProperty())
.property("patient", new StringProperty().example("uuid"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are these examples displayed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

http://localhost:8080/openmrs/module/webservices/rest/apiDocs.htm#!/order/createOrder
See in the 'Example Value' section.

{
"encounter": "uuid",
"action": "NEW",
"accessionNumber": "string",
"dateActivated": "2017-08-24",
"patient": "uuid",
"concept": "uuid",
...
}

public Model getGETModel(Representation representation) {
return null;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between a resource like this which returns all nulls and those that do not? Or was it simply a lack of time to implement?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it's not due to lack of time. I had enough time :) I've been tracking undocumented resources by validating the swagger. Some how they were missed. I'll check and fix those.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And i found a good number of them.

return null;
}

@Override
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were these intentionally left null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to document handlers? I don't think they appear either as a resource or a property. If needed let me know.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then in that case we should not have these methods in them.

Copy link
Member Author

@gayanW gayanW Aug 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However they implements getRepresentationDescription, getCreatableProperties, and getUpdatableProperties. Is handler considered a resource or can they be a property of some other resource?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not consider it as a resource. But putting this aside, can you ensure that all other non search handlers that should not just return null, are doing what they should?

@@ -99,6 +100,16 @@ public DelegatingResourceDescription getUpdatableProperties() {
}

@Override
public Model getGETModel(Representation representation) {
return null;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were these intentionally left null? And many more others.

Copy link
Member Author

@gayanW gayanW left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SwaggerSpecificationCreator#mainTest() does not detect resources from all versions. This is not really an issue. But it will be useful, if it could detect all, so one can generate the spec just from running this test, instead of having to restart the server.

Can it be done?

@coveralls
Copy link

Coverage Status

Coverage decreased (-6.2%) to 40.023% when pulling 4c74be2 on gayanW:restws-662 into e12f8c7 on openmrs:master.

@gayanW
Copy link
Member Author

gayanW commented Aug 25, 2017

@dkayiwa
ModuleResource1_8, OrderableResource1_10, CustomDatatypeResource1_9, ConceptSearchResource1_9, and CustomDatatypeHandlerResource1_9 returns null for getCREATEModel(rep) because they are documented as not creatable. If you check these classes, you'll see that none of them implement getCreatableProperties() and throws ResourceDoesNotSupportOperationException when invoked.

Test resource classes also returns null, as they are not needed.

Except these, all other classes are documented.

@dkayiwa
Copy link
Member

dkayiwa commented Aug 25, 2017

Ok cool.
Am merging this earlier than later such that you get un blocked.
After merging, i will take a second look and if any more work is needed, you will do that in a new pull request. Otherwise thanks for the work so far done. 😊

@dkayiwa dkayiwa merged commit 639ad02 into openmrs:master Aug 25, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants