{"action":"created","comment":{"url":"https://api.github.com/repos/dhis2/dhis2-core/pulls/comments/308644046","pull_request_review_id":268293536,"id":308644046,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMwODY0NDA0Ng==","diff_hunk":"@@ -0,0 +1,370 @@\n+package org.hisp.dhis.sms.listener;\n+\n+/*\n+ * Copyright (c) 2004-2018, University of Oslo\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ * Redistributions of source code must retain the above copyright notice, this\n+ * list of conditions and the following disclaimer.\n+ *\n+ * Redistributions in binary form must reproduce the above copyright notice,\n+ * this list of conditions and the following disclaimer in the documentation\n+ * and/or other materials provided with the distribution.\n+ * Neither the name of the HISP project nor the names of its contributors may\n+ * be used to endorse or promote products derived from this software without\n+ * specific prior written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\n+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+import java.util.ArrayList;\n+import java.util.Date;\n+import java.util.HashMap;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.Objects;\n+import java.util.stream.Collectors;\n+\n+import javax.annotation.Resource;\n+\n+import org.apache.commons.lang.StringUtils;\n+import org.hisp.dhis.category.CategoryOptionCombo;\n+import org.hisp.dhis.category.CategoryService;\n+import org.hisp.dhis.common.IdentifiableObject;\n+import org.hisp.dhis.dataelement.DataElement;\n+import org.hisp.dhis.dataelement.DataElementService;\n+import org.hisp.dhis.event.EventStatus;\n+import org.hisp.dhis.eventdatavalue.EventDataValue;\n+import org.hisp.dhis.message.MessageSender;\n+import org.hisp.dhis.organisationunit.OrganisationUnit;\n+import org.hisp.dhis.organisationunit.OrganisationUnitService;\n+import org.hisp.dhis.program.Program;\n+import org.hisp.dhis.program.ProgramInstance;\n+import org.hisp.dhis.program.ProgramService;\n+import org.hisp.dhis.program.ProgramStage;\n+import org.hisp.dhis.program.ProgramStageInstance;\n+import org.hisp.dhis.program.ProgramStageInstanceService;\n+import org.hisp.dhis.sms.incoming.IncomingSms;\n+import org.hisp.dhis.smscompression.SMSConsts.SMSEventStatus;\n+import org.hisp.dhis.smscompression.SMSConsts.SubmissionType;\n+import org.hisp.dhis.smscompression.SMSResponse;\n+import org.hisp.dhis.smscompression.SMSSubmissionReader;\n+import org.hisp.dhis.smscompression.models.SMSDataValue;\n+import org.hisp.dhis.smscompression.models.SMSMetadata;\n+import org.hisp.dhis.smscompression.models.SMSSubmission;\n+import org.hisp.dhis.smscompression.models.SMSSubmissionHeader;\n+import org.hisp.dhis.smscompression.models.UID;\n+import org.hisp.dhis.system.util.SmsUtils;\n+import org.hisp.dhis.trackedentity.TrackedEntityAttribute;\n+import org.hisp.dhis.trackedentity.TrackedEntityAttributeService;\n+import org.hisp.dhis.trackedentity.TrackedEntityType;\n+import org.hisp.dhis.trackedentity.TrackedEntityTypeService;\n+import org.hisp.dhis.user.User;\n+import org.hisp.dhis.user.UserService;\n+import org.jfree.util.Log;\n+import org.springframework.beans.factory.annotation.Autowired;\n+import org.springframework.transaction.annotation.Transactional;\n+\n+import com.google.gson.Gson;\n+import com.google.gson.GsonBuilder;\n+\n+@Transactional\n+public abstract class NewSMSListener\n+    extends\n+    BaseSMSListener\n+{\n+\n+    @Autowired\n+    private ProgramStageInstanceService programStageInstanceService;\n+\n+    protected abstract SMSResponse postProcess( IncomingSms sms, SMSSubmission submission )\n+        throws SMSProcessingException;\n+\n+    protected abstract boolean handlesType( SubmissionType type );\n+\n+    @Resource( name = \"smsMessageSender\" )\n+    private MessageSender smsSender;\n+\n+    @Autowired\n+    private UserService userService;\n+\n+    @Autowired\n+    private TrackedEntityTypeService trackedEntityTypeService;\n+\n+    @Autowired\n+    private TrackedEntityAttributeService trackedEntityAttributeService;\n+\n+    @Autowired\n+    private ProgramService programService;\n+\n+    @Autowired\n+    private OrganisationUnitService organisationUnitService;\n+\n+    @Autowired\n+    private CategoryService categoryService;\n+\n+    @Autowired\n+    private DataElementService dataElementService;\n+\n+    @Override\n+    public boolean accept( IncomingSms sms )\n+    {\n+        if ( sms == null || !SmsUtils.isBase64( sms ) )\n+        {\n+            return false;\n+        }\n+\n+        SMSSubmissionHeader header = getHeader( sms );\n+        if ( header == null )\n+        {\n+            // If the header is null we simply accept any listener\n+            // and handle the error in receive() below\n+            return true;\n+        }\n+        return handlesType( header.getType() );\n+    }\n+\n+    @Override\n+    public void receive( IncomingSms sms )\n+    {\n+        SMSSubmissionReader reader = new SMSSubmissionReader();\n+        SMSSubmissionHeader header = getHeader( sms );\n+        if ( header == null )\n+        {\n+            // Error with the header, we have no message ID, use -1\n+            sendSMSResponse( SMSResponse.HEADER_ERROR, sms, -1 );\n+            return;\n+        }\n+\n+        SMSMetadata meta = getMetadata( header.getLastSyncDate() );\n+        SMSSubmission subm = null;\n+        try\n+        {\n+            subm = reader.readSubmission( SmsUtils.getBytes( sms ), meta );\n+        }\n+        catch ( Exception e )\n+        {\n+            Log.error( e.getMessage() );\n+            sendSMSResponse( SMSResponse.READ_ERROR, sms, header.getSubmissionID() );\n+            return;\n+        }\n+\n+        // TODO: Can be removed - debugging line to check SMS submissions\n+        Gson gson = new GsonBuilder().setPrettyPrinting().create();\n+        Log.info( \"New received SMS submission decoded as: \" + gson.toJson( subm ) );\n+\n+        SMSResponse resp = null;\n+        try\n+        {\n+            checkUser( subm );\n+            resp = postProcess( sms, subm );\n+        }\n+        catch ( SMSProcessingException e )\n+        {\n+            Log.error( e.getMessage() );\n+            sendSMSResponse( e.getResp(), sms, header.getSubmissionID() );\n+            return;\n+        }\n+\n+        Log.info( \"SMS Response: \" + resp.toString() );\n+        sendSMSResponse( resp, sms, header.getSubmissionID() );\n+    }\n+\n+    private void checkUser( SMSSubmission subm )\n+    {\n+        UID userid = subm.getUserID();\n+        User user = userService.getUser( userid.uid );\n+\n+        if ( user == null )\n+        {\n+            throw new SMSProcessingException( SMSResponse.INVALID_USER.set( userid ) );\n+        }\n+    }\n+\n+    private SMSSubmissionHeader getHeader( IncomingSms sms )\n+    {\n+        byte[] smsBytes = SmsUtils.getBytes( sms );\n+        SMSSubmissionReader reader = new SMSSubmissionReader();\n+        try\n+        {\n+            return reader.readHeader( smsBytes );\n+        }\n+        catch ( Exception e )\n+        {\n+            e.printStackTrace();\n+            Log.error( e.getMessage() );\n+            return null;\n+        }\n+    }\n+\n+    private SMSMetadata getMetadata( Date lastSyncDate )\n+    {\n+        SMSMetadata meta = new SMSMetadata();\n+        meta.dataElements = getAllDataElements( lastSyncDate );\n+        meta.categoryOptionCombos = getAllCatOptionCombos( lastSyncDate );\n+        meta.users = getAllUserIds( lastSyncDate );\n+        meta.trackedEntityTypes = getAllTrackedEntityTypeIds( lastSyncDate );\n+        meta.trackedEntityAttributes = getAllTrackedEntityAttributeIds( lastSyncDate );\n+        meta.programs = getAllProgramIds( lastSyncDate );\n+        meta.organisationUnits = getAllOrgUnitIds( lastSyncDate );\n+\n+        return meta;\n+    }\n+\n+    private List<SMSMetadata.ID> getAllUserIds( Date lastSyncDate )\n+    {\n+        List<User> users = userService.getAllUsers();\n+\n+        return users.stream().map( o -> getIdFromMetadata( o, lastSyncDate ) ).filter( Objects::nonNull )\n+            .collect( Collectors.toList() );\n+    }\n+\n+    private List<SMSMetadata.ID> getAllTrackedEntityTypeIds( Date lastSyncDate )\n+    {\n+        List<TrackedEntityType> teTypes = trackedEntityTypeService.getAllTrackedEntityType();\n+\n+        return teTypes.stream().map( o -> getIdFromMetadata( o, lastSyncDate ) ).filter( Objects::nonNull )\n+            .collect( Collectors.toList() );\n+    }\n+\n+    private List<SMSMetadata.ID> getAllTrackedEntityAttributeIds( Date lastSyncDate )\n+    {\n+        List<TrackedEntityAttribute> teiAttributes = trackedEntityAttributeService.getAllTrackedEntityAttributes();\n+\n+        return teiAttributes.stream().map( o -> getIdFromMetadata( o, lastSyncDate ) ).filter( Objects::nonNull )\n+            .collect( Collectors.toList() );\n+    }\n+\n+    private List<SMSMetadata.ID> getAllProgramIds( Date lastSyncDate )\n+    {\n+        List<Program> programs = programService.getAllPrograms();\n+\n+        return programs.stream().map( o -> getIdFromMetadata( o, lastSyncDate ) ).filter( Objects::nonNull )\n+            .collect( Collectors.toList() );\n+    }\n+\n+    private List<SMSMetadata.ID> getAllOrgUnitIds( Date lastSyncDate )\n+    {\n+        List<OrganisationUnit> orgUnits = organisationUnitService.getAllOrganisationUnits();","path":"dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/listener/NewSMSListener.java","position":259,"original_position":259,"commit_id":"14470442d7ba6a90b91584e9f88e95e09a7120bb","original_commit_id":"14470442d7ba6a90b91584e9f88e95e09a7120bb","user":{"login":"zubaira","id":13900328,"node_id":"MDQ6VXNlcjEzOTAwMzI4","avatar_url":"https://avatars3.githubusercontent.com/u/13900328?v=4","gravatar_id":"","url":"https://api.github.com/users/zubaira","html_url":"https://github.com/zubaira","followers_url":"https://api.github.com/users/zubaira/followers","following_url":"https://api.github.com/users/zubaira/following{/other_user}","gists_url":"https://api.github.com/users/zubaira/gists{/gist_id}","starred_url":"https://api.github.com/users/zubaira/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zubaira/subscriptions","organizations_url":"https://api.github.com/users/zubaira/orgs","repos_url":"https://api.github.com/users/zubaira/repos","events_url":"https://api.github.com/users/zubaira/events{/privacy}","received_events_url":"https://api.github.com/users/zubaira/received_events","type":"User","site_admin":false},"body":"Getting all OrganisationUnits is quite a heavy operation. We can move the logic to SQL level in order to fetch only those which are needed.","created_at":"2019-07-30T10:18:58Z","updated_at":"2019-07-30T10:18:59Z","html_url":"https://github.com/dhis2/dhis2-core/pull/3535#discussion_r308644046","pull_request_url":"https://api.github.com/repos/dhis2/dhis2-core/pulls/3535","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/dhis2/dhis2-core/pulls/comments/308644046"},"html":{"href":"https://github.com/dhis2/dhis2-core/pull/3535#discussion_r308644046"},"pull_request":{"href":"https://api.github.com/repos/dhis2/dhis2-core/pulls/3535"}}},"pull_request":{"url":"https://api.github.com/repos/dhis2/dhis2-core/pulls/3535","id":301122055,"node_id":"MDExOlB1bGxSZXF1ZXN0MzAxMTIyMDU1","html_url":"https://github.com/dhis2/dhis2-core/pull/3535","diff_url":"https://github.com/dhis2/dhis2-core/pull/3535.diff","patch_url":"https://github.com/dhis2/dhis2-core/pull/3535.patch","issue_url":"https://api.github.com/repos/dhis2/dhis2-core/issues/3535","number":3535,"state":"open","locked":false,"title":"New SMS Listeners for 2.32","user":{"login":"JasperTimm","id":4495499,"node_id":"MDQ6VXNlcjQ0OTU0OTk=","avatar_url":"https://avatars2.githubusercontent.com/u/4495499?v=4","gravatar_id":"","url":"https://api.github.com/users/JasperTimm","html_url":"https://github.com/JasperTimm","followers_url":"https://api.github.com/users/JasperTimm/followers","following_url":"https://api.github.com/users/JasperTimm/following{/other_user}","gists_url":"https://api.github.com/users/JasperTimm/gists{/gist_id}","starred_url":"https://api.github.com/users/JasperTimm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JasperTimm/subscriptions","organizations_url":"https://api.github.com/users/JasperTimm/orgs","repos_url":"https://api.github.com/users/JasperTimm/repos","events_url":"https://api.github.com/users/JasperTimm/events{/privacy}","received_events_url":"https://api.github.com/users/JasperTimm/received_events","type":"User","site_admin":false},"body":"This PR is to merge the new SMS handling which is being used to send SMS via the new Android Capture App.\r\n\r\nIt uses a shared SMS compression library which is currently hosted in the eHA org, but should be migrated to DHIS2: https://github.com/eHealthAfrica/dhis2-sms-compression\r\n\r\nThis PR is for a special version of 2.32 with SMS that can be used by early adopters to test before 2.33 is released. Another PR will be created to merge into master/2.33.","created_at":"2019-07-25T12:30:52Z","updated_at":"2019-07-30T10:18:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d3d5db98ba620e480d1514c4050fdbb39acdad6f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/dhis2/dhis2-core/pulls/3535/commits","review_comments_url":"https://api.github.com/repos/dhis2/dhis2-core/pulls/3535/comments","review_comment_url":"https://api.github.com/repos/dhis2/dhis2-core/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dhis2/dhis2-core/issues/3535/comments","statuses_url":"https://api.github.com/repos/dhis2/dhis2-core/statuses/14470442d7ba6a90b91584e9f88e95e09a7120bb","head":{"label":"eHealthAfrica:eha-sms-2.32","ref":"eha-sms-2.32","sha":"14470442d7ba6a90b91584e9f88e95e09a7120bb","user":{"login":"eHealthAfrica","id":3214042,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMyMTQwNDI=","avatar_url":"https://avatars0.githubusercontent.com/u/3214042?v=4","gravatar_id":"","url":"https://api.github.com/users/eHealthAfrica","html_url":"https://github.com/eHealthAfrica","followers_url":"https://api.github.com/users/eHealthAfrica/followers","following_url":"https://api.github.com/users/eHealthAfrica/following{/other_user}","gists_url":"https://api.github.com/users/eHealthAfrica/gists{/gist_id}","starred_url":"https://api.github.com/users/eHealthAfrica/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eHealthAfrica/subscriptions","organizations_url":"https://api.github.com/users/eHealthAfrica/orgs","repos_url":"https://api.github.com/users/eHealthAfrica/repos","events_url":"https://api.github.com/users/eHealthAfrica/events{/privacy}","received_events_url":"https://api.github.com/users/eHealthAfrica/received_events","type":"Organization","site_admin":false},"repo":{"id":170337439,"node_id":"MDEwOlJlcG9zaXRvcnkxNzAzMzc0Mzk=","name":"dhis2-core","full_name":"eHealthAfrica/dhis2-core","private":false,"owner":{"login":"eHealthAfrica","id":3214042,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMyMTQwNDI=","avatar_url":"https://avatars0.githubusercontent.com/u/3214042?v=4","gravatar_id":"","url":"https://api.github.com/users/eHealthAfrica","html_url":"https://github.com/eHealthAfrica","followers_url":"https://api.github.com/users/eHealthAfrica/followers","following_url":"https://api.github.com/users/eHealthAfrica/following{/other_user}","gists_url":"https://api.github.com/users/eHealthAfrica/gists{/gist_id}","starred_url":"https://api.github.com/users/eHealthAfrica/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eHealthAfrica/subscriptions","organizations_url":"https://api.github.com/users/eHealthAfrica/orgs","repos_url":"https://api.github.com/users/eHealthAfrica/repos","events_url":"https://api.github.com/users/eHealthAfrica/events{/privacy}","received_events_url":"https://api.github.com/users/eHealthAfrica/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/eHealthAfrica/dhis2-core","description":"DHIS 2 Core. Written in Java. Contains the service layer and Web API.","fork":true,"url":"https://api.github.com/repos/eHealthAfrica/dhis2-core","forks_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/forks","keys_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/teams","hooks_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/hooks","issue_events_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/issues/events{/number}","events_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/events","assignees_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/assignees{/user}","branches_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/branches{/branch}","tags_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/tags","blobs_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/statuses/{sha}","languages_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/languages","stargazers_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/stargazers","contributors_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/contributors","subscribers_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/subscribers","subscription_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/subscription","commits_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/contents/{+path}","compare_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/merges","archive_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/downloads","issues_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/issues{/number}","pulls_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/pulls{/number}","milestones_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/milestones{/number}","notifications_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/labels{/name}","releases_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/releases{/id}","deployments_url":"https://api.github.com/repos/eHealthAfrica/dhis2-core/deployments","created_at":"2019-02-12T15:02:27Z","updated_at":"2019-07-24T11:54:24Z","pushed_at":"2019-07-29T17:19:39Z","git_url":"git://github.com/eHealthAfrica/dhis2-core.git","ssh_url":"git@github.com:eHealthAfrica/dhis2-core.git","clone_url":"https://github.com/eHealthAfrica/dhis2-core.git","svn_url":"https://github.com/eHealthAfrica/dhis2-core","homepage":"","size":67467,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":1,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause","node_id":"MDc6TGljZW5zZTU="},"forks":0,"open_issues":1,"watchers":0,"default_branch":"eha-sms"}},"base":{"label":"dhis2:2.32-sms","ref":"2.32-sms","sha":"34b970d524011c70c23d8188a9720dcfa6475d02","user":{"login":"dhis2","id":1089987,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEwODk5ODc=","avatar_url":"https://avatars2.githubusercontent.com/u/1089987?v=4","gravatar_id":"","url":"https://api.github.com/users/dhis2","html_url":"https://github.com/dhis2","followers_url":"https://api.github.com/users/dhis2/followers","following_url":"https://api.github.com/users/dhis2/following{/other_user}","gists_url":"https://api.github.com/users/dhis2/gists{/gist_id}","starred_url":"https://api.github.com/users/dhis2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dhis2/subscriptions","organizations_url":"https://api.github.com/users/dhis2/orgs","repos_url":"https://api.github.com/users/dhis2/repos","events_url":"https://api.github.com/users/dhis2/events{/privacy}","received_events_url":"https://api.github.com/users/dhis2/received_events","type":"Organization","site_admin":false},"repo":{"id":66940520,"node_id":"MDEwOlJlcG9zaXRvcnk2Njk0MDUyMA==","name":"dhis2-core","full_name":"dhis2/dhis2-core","private":false,"owner":{"login":"dhis2","id":1089987,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEwODk5ODc=","avatar_url":"https://avatars2.githubusercontent.com/u/1089987?v=4","gravatar_id":"","url":"https://api.github.com/users/dhis2","html_url":"https://github.com/dhis2","followers_url":"https://api.github.com/users/dhis2/followers","following_url":"https://api.github.com/users/dhis2/following{/other_user}","gists_url":"https://api.github.com/users/dhis2/gists{/gist_id}","starred_url":"https://api.github.com/users/dhis2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dhis2/subscriptions","organizations_url":"https://api.github.com/users/dhis2/orgs","repos_url":"https://api.github.com/users/dhis2/repos","events_url":"https://api.github.com/users/dhis2/events{/privacy}","received_events_url":"https://api.github.com/users/dhis2/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/dhis2/dhis2-core","description":"DHIS 2 Core. Written in Java. Contains the service layer and Web API.","fork":false,"url":"https://api.github.com/repos/dhis2/dhis2-core","forks_url":"https://api.github.com/repos/dhis2/dhis2-core/forks","keys_url":"https://api.github.com/repos/dhis2/dhis2-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dhis2/dhis2-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dhis2/dhis2-core/teams","hooks_url":"https://api.github.com/repos/dhis2/dhis2-core/hooks","issue_events_url":"https://api.github.com/repos/dhis2/dhis2-core/issues/events{/number}","events_url":"https://api.github.com/repos/dhis2/dhis2-core/events","assignees_url":"https://api.github.com/repos/dhis2/dhis2-core/assignees{/user}","branches_url":"https://api.github.com/repos/dhis2/dhis2-core/branches{/branch}","tags_url":"https://api.github.com/repos/dhis2/dhis2-core/tags","blobs_url":"https://api.github.com/repos/dhis2/dhis2-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dhis2/dhis2-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dhis2/dhis2-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/dhis2/dhis2-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dhis2/dhis2-core/statuses/{sha}","languages_url":"https://api.github.com/repos/dhis2/dhis2-core/languages","stargazers_url":"https://api.github.com/repos/dhis2/dhis2-core/stargazers","contributors_url":"https://api.github.com/repos/dhis2/dhis2-core/contributors","subscribers_url":"https://api.github.com/repos/dhis2/dhis2-core/subscribers","subscription_url":"https://api.github.com/repos/dhis2/dhis2-core/subscription","commits_url":"https://api.github.com/repos/dhis2/dhis2-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/dhis2/dhis2-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/dhis2/dhis2-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/dhis2/dhis2-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/dhis2/dhis2-core/contents/{+path}","compare_url":"https://api.github.com/repos/dhis2/dhis2-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dhis2/dhis2-core/merges","archive_url":"https://api.github.com/repos/dhis2/dhis2-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dhis2/dhis2-core/downloads","issues_url":"https://api.github.com/repos/dhis2/dhis2-core/issues{/number}","pulls_url":"https://api.github.com/repos/dhis2/dhis2-core/pulls{/number}","milestones_url":"https://api.github.com/repos/dhis2/dhis2-core/milestones{/number}","notifications_url":"https://api.github.com/repos/dhis2/dhis2-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dhis2/dhis2-core/labels{/name}","releases_url":"https://api.github.com/repos/dhis2/dhis2-core/releases{/id}","deployments_url":"https://api.github.com/repos/dhis2/dhis2-core/deployments","created_at":"2016-08-30T12:57:05Z","updated_at":"2019-07-30T09:30:02Z","pushed_at":"2019-07-30T09:53:07Z","git_url":"git://github.com/dhis2/dhis2-core.git","ssh_url":"git@github.com:dhis2/dhis2-core.git","clone_url":"https://github.com/dhis2/dhis2-core.git","svn_url":"https://github.com/dhis2/dhis2-core","homepage":"","size":69335,"stargazers_count":137,"watchers_count":137,"language":"Java","has_issues":false,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":147,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":21,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause","node_id":"MDc6TGljZW5zZTU="},"forks":147,"open_issues":21,"watchers":137,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dhis2/dhis2-core/pulls/3535"},"html":{"href":"https://github.com/dhis2/dhis2-core/pull/3535"},"issue":{"href":"https://api.github.com/repos/dhis2/dhis2-core/issues/3535"},"comments":{"href":"https://api.github.com/repos/dhis2/dhis2-core/issues/3535/comments"},"review_comments":{"href":"https://api.github.com/repos/dhis2/dhis2-core/pulls/3535/comments"},"review_comment":{"href":"https://api.github.com/repos/dhis2/dhis2-core/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dhis2/dhis2-core/pulls/3535/commits"},"statuses":{"href":"https://api.github.com/repos/dhis2/dhis2-core/statuses/14470442d7ba6a90b91584e9f88e95e09a7120bb"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"zubaira"}}