On Tue, Dec 7, 2010 at 10:45 AM, Bob Jolliffe <bobjolli...@gmail.com> wrote: > On 6 December 2010 16:24, Knut Staring <knu...@gmail.com> wrote: >> Hello all, with the pagination module one can specify exactly the >> number of items per page, for example 27. However, I think it would be >> slightly more user friendly to replace this input field by a dropdown >> with typical choices, such as 5, 10, 20, 50 and 100 or "All/Single >> page". It would of course constrain the user a bit, but in some cases >> structure is more useful than full freedom. > > Spoken like a true swiss :-)
Indeed ;-) >> >> Knut >> >> On Mon, Dec 6, 2010 at 3:15 PM, <nore...@launchpad.net> wrote: >>> ------------------------------------------------------------ >>> revno: 2297 >>> committer: Quang <qu...@quang-pc> >>> branch nick: trunk >>> timestamp: Mon 2010-12-06 21:13:48 +0700 >>> message: >>> Apply pagination in User and UserRole lists. >>> modified: >>> dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserStore.java >>> dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/hibernate/HibernateUserStore.java >>> dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/GetRoleListAction.java >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/GetUserListAction.java >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/allRole.vm >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/searchUser.vm >>> >>> >>> -- >>> lp:dhis2 >>> https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk >>> >>> Your team DHIS 2 developers is subscribed to branch lp:dhis2. >>> To unsubscribe from this branch go to >>> https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription >>> >>> === modified file >>> 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserStore.java' >>> --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserStore.java >>> 2010-10-30 08:20:17 +0000 >>> +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserStore.java >>> 2010-12-06 14:13:48 +0000 >>> @@ -29,6 +29,7 @@ >>> >>> import java.util.Collection; >>> >>> +import org.hisp.dhis.dataelement.DataElement; >>> import org.hisp.dhis.organisationunit.OrganisationUnit; >>> >>> /** >>> @@ -103,15 +104,16 @@ >>> */ >>> void deleteUser( User user ); >>> >>> - Collection<User> getAllUsers( int from, int to ); >>> - >>> Collection<UserCredentials> searchUsersByName( String key ); >>> >>> - Collection<UserCredentials> searchUsersByName( String key, int from, >>> int to ); >>> - >>> - int countNumberOfSearchUsersByName( String key ); >>> - >>> - int countAllUsers(); >>> + Collection<UserCredentials> getUsersBetween( int first, int max ); >>> + >>> + Collection<UserCredentials> getUsersBetweenByName( String name, int >>> first, int max ); >>> + >>> + int getUserCount(); >>> + >>> + int getUserCountByName( String name ); >>> + >>> >>> // >>> ------------------------------------------------------------------------- >>> // UserCredentials >>> @@ -253,5 +255,13 @@ >>> * @param userSetting the UserSetting to delete. >>> */ >>> void deleteUserSetting( UserSetting userSetting ); >>> - >>> + >>> + Collection<UserAuthorityGroup> getUserRolesBetween( int first, int max >>> ); >>> + >>> + Collection<UserAuthorityGroup> getUserRolesBetweenByName( String name, >>> int first, int max ); >>> + >>> + int getUserRoleCount(); >>> + >>> + int getUserRoleCountByName( String name ); >>> + >>> } >>> >>> === modified file >>> 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/hibernate/HibernateUserStore.java' >>> --- >>> dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/hibernate/HibernateUserStore.java >>> 2010-10-30 08:20:17 +0000 >>> +++ >>> dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/hibernate/HibernateUserStore.java >>> 2010-12-06 14:13:48 +0000 >>> @@ -38,6 +38,8 @@ >>> import org.hibernate.criterion.Order; >>> import org.hibernate.criterion.Projections; >>> import org.hibernate.criterion.Restrictions; >>> +import org.hisp.dhis.common.GenericIdentifiableObjectStore; >>> +import org.hisp.dhis.datadictionary.DataDictionary; >>> import org.hisp.dhis.organisationunit.OrganisationUnit; >>> import org.hisp.dhis.system.util.AuditLogLevel; >>> import org.hisp.dhis.system.util.AuditLogUtil; >>> @@ -76,6 +78,18 @@ >>> { >>> this.currentUserService = currentUserService; >>> } >>> + >>> + private GenericIdentifiableObjectStore<UserAuthorityGroup> >>> userRoleStore; >>> + >>> + public GenericIdentifiableObjectStore<UserAuthorityGroup> >>> getUserRoleStore() >>> + { >>> + return userRoleStore; >>> + } >>> + >>> + public void setUserRoleStore( >>> GenericIdentifiableObjectStore<UserAuthorityGroup> userRoleStore ) >>> + { >>> + this.userRoleStore = userRoleStore; >>> + } >>> >>> // >>> ------------------------------------------------------------------------- >>> // User >>> @@ -122,14 +136,6 @@ >>> return session.createQuery( "from User" ).list(); >>> } >>> >>> - �...@suppresswarnings( "unchecked" ) >>> - public Collection<User> getAllUsers( int from, int to ) >>> - { >>> - Session session = sessionFactory.getCurrentSession(); >>> - >>> - return session.createQuery( "from User" ).setFirstResult( from >>> ).setMaxResults( to ).list(); >>> - } >>> - >>> public Collection<User> getUsersByOrganisationUnit( OrganisationUnit >>> organisationUnit ) >>> { >>> Collection<User> users = getAllUsers(); >>> @@ -188,17 +194,6 @@ >>> User.class.getSimpleName(), >>> user.getName()) ); >>> } >>> - >>> - public int countAllUsers() >>> - { >>> - Session session = sessionFactory.getCurrentSession(); >>> - >>> - Query query = session.createQuery( "select count(*) from User" ); >>> - >>> - Number rs = (Number) query.uniqueResult(); >>> - >>> - return rs != null ? rs.intValue() : 0; >>> - } >>> // >>> ------------------------------------------------------------------------- >>> // UserCredentials >>> // >>> ------------------------------------------------------------------------- >>> @@ -367,28 +362,24 @@ >>> return criteria.list(); >>> } >>> >>> - �...@suppresswarnings( "unchecked" ) >>> - public Collection<UserCredentials> searchUsersByName( String key, int >>> from, int to ){ >>> - >>> + public int getUserCount() >>> + { >>> Session session = sessionFactory.getCurrentSession(); >>> - >>> - Criteria criteria = session.createCriteria( UserCredentials.class >>> ); >>> - >>> - criteria.add( Restrictions.ilike( "username", "%" + key + "%" ) ); >>> - criteria.addOrder( Order.asc( "username" ) ); >>> - criteria.setFirstResult( from ); >>> - criteria.setMaxResults( to ); >>> - >>> - return criteria.list(); >>> + >>> + Query query = session.createQuery( "select count(*) from User" ); >>> + >>> + Number rs = (Number) query.uniqueResult(); >>> + >>> + return rs != null ? rs.intValue() : 0; >>> } >>> - >>> - public int countNumberOfSearchUsersByName( String key ) >>> + >>> + public int getUserCountByName( String name ) >>> { >>> Session session = sessionFactory.getCurrentSession(); >>> >>> Criteria criteria = session.createCriteria( UserCredentials.class ); >>> >>> - criteria.add( Restrictions.ilike( "username", "%" + key + "%" ) ); >>> + criteria.add( Restrictions.ilike( "username", "%" + name + "%" ) ); >>> >>> criteria.setProjection( Projections.rowCount() ).uniqueResult(); >>> >>> @@ -396,4 +387,45 @@ >>> >>> return rs != null ? rs.intValue() : 0; >>> } >>> + >>> + public Collection<UserCredentials> getUsersBetween( int first, int max >>> ) >>> + { >>> + Session session = sessionFactory.getCurrentSession(); >>> + >>> + return session.createQuery( "from UserCredentials" >>> ).setFirstResult( first ).setMaxResults( max ).list(); >>> + } >>> + >>> + public Collection<UserCredentials> getUsersBetweenByName( String name, >>> int first, int max ) >>> + { >>> + Session session = sessionFactory.getCurrentSession(); >>> + >>> + Criteria criteria = session.createCriteria( UserCredentials.class >>> ); >>> + >>> + criteria.add( Restrictions.ilike( "username", "%" + name + "%" ) ); >>> + criteria.addOrder( Order.asc( "username" ) ); >>> + criteria.setFirstResult( first ); >>> + criteria.setMaxResults( max ); >>> + >>> + return criteria.list(); >>> + } >>> + >>> + public int getUserRoleCount() >>> + { >>> + return userRoleStore.getCount(); >>> + } >>> + >>> + public int getUserRoleCountByName( String name ) >>> + { >>> + return userRoleStore.getCountByName( name ); >>> + } >>> + >>> + public Collection<UserAuthorityGroup> getUserRolesBetween( int first, >>> int max ) >>> + { >>> + return userRoleStore.getBetween( first, max ); >>> + } >>> + >>> + public Collection<UserAuthorityGroup> getUserRolesBetweenByName( >>> String name, int first, int max ) >>> + { >>> + return userRoleStore.getBetweenByName( name, first, max ); >>> + } >>> } >>> >>> === modified file >>> 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml' >>> --- >>> dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml >>> 2010-11-27 09:37:29 +0000 >>> +++ >>> dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml >>> 2010-12-06 14:13:48 +0000 >>> @@ -186,6 +186,7 @@ >>> >>> <bean id="org.hisp.dhis.user.UserStore" >>> class="org.hisp.dhis.user.hibernate.HibernateUserStore"> >>> <property name="sessionFactory" ref="sessionFactory"/> >>> + <property name="userRoleStore" >>> ref="org.hisp.dhis.user.UserAuthorityGroupStore" /> >>> <property name="currentUserService" >>> ref="org.hisp.dhis.user.CurrentUserService" /> >>> </bean> >>> >>> @@ -203,6 +204,12 @@ >>> >>> class="org.hisp.dhis.aggregation.jdbc.JdbcAggregatedDataValueStore"> >>> <property name="statementManager" ref="statementManager"/> >>> </bean> >>> + >>> + <bean id="org.hisp.dhis.user.UserAuthorityGroupStore" >>> class="org.hisp.dhis.hibernate.HibernateGenericStore"> >>> + <property name="clazz" >>> value="org.hisp.dhis.user.UserAuthorityGroup" /> >>> + <property name="sessionFactory" ref="sessionFactory" /> >>> + </bean> >>> + >>> >>> <!-- Service definitions --> >>> >>> >>> === modified file >>> 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/GetRoleListAction.java' >>> --- >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/GetRoleListAction.java >>> 2010-04-12 21:23:33 +0000 >>> +++ >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/GetRoleListAction.java >>> 2010-12-06 14:13:48 +0000 >>> @@ -27,10 +27,15 @@ >>> * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >>> */ >>> >>> +import static org.apache.commons.lang.StringUtils.isNotBlank; >>> + >>> import java.util.ArrayList; >>> import java.util.List; >>> >>> +import org.hisp.dhis.paging.ActionPagingSupport; >>> +import org.hisp.dhis.user.User; >>> import org.hisp.dhis.user.UserAuthorityGroup; >>> +import org.hisp.dhis.user.UserCredentials; >>> import org.hisp.dhis.user.UserStore; >>> >>> import com.opensymphony.xwork2.Action; >>> @@ -40,7 +45,7 @@ >>> * @version $Id: GetRoleListAction.java 4079 2007-11-20 11:42:23Z larshelg $ >>> */ >>> public class GetRoleListAction >>> - implements Action >>> + extends ActionPagingSupport<UserAuthorityGroup> >>> { >>> // >>> ------------------------------------------------------------------------- >>> // Dependencies >>> @@ -54,7 +59,7 @@ >>> } >>> >>> // >>> ------------------------------------------------------------------------- >>> - // Output >>> + // Input & Output >>> // >>> ------------------------------------------------------------------------- >>> >>> private List<UserAuthorityGroup> userAuthorityGroups; >>> @@ -63,6 +68,18 @@ >>> { >>> return userAuthorityGroups; >>> } >>> + >>> + private String key; >>> + >>> + public void setKey( String key ) >>> + { >>> + this.key = key; >>> + } >>> + >>> + public String getKey() >>> + { >>> + return key; >>> + } >>> >>> // >>> ------------------------------------------------------------------------- >>> // Action implementation >>> @@ -71,7 +88,19 @@ >>> public String execute() >>> throws Exception >>> { >>> - userAuthorityGroups = new ArrayList<UserAuthorityGroup>( >>> userStore.getAllUserAuthorityGroups() ); >>> + >>> + if ( isNotBlank( key ) ) // Filter on key only if set >>> + { >>> + this.paging = createPaging( userStore.getUserRoleCountByName( >>> key ) ); >>> + >>> + userAuthorityGroups = new ArrayList<UserAuthorityGroup>( >>> userStore.getUserRolesBetweenByName( key, paging.getStartPos(), >>> paging.getPageSize() ) ); >>> + } >>> + else >>> + { >>> + this.paging = createPaging( userStore.getUserRoleCount() ); >>> + >>> + userAuthorityGroups = new ArrayList<UserAuthorityGroup>( >>> userStore.getUserRolesBetween( paging.getStartPos(), paging.getPageSize() ) >>> ); >>> + } >>> >>> return SUCCESS; >>> } >>> >>> === modified file >>> 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/GetUserListAction.java' >>> --- >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/GetUserListAction.java >>> 2010-10-30 08:20:17 +0000 >>> +++ >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/GetUserListAction.java >>> 2010-12-06 14:13:48 +0000 >>> @@ -27,8 +27,9 @@ >>> * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >>> */ >>> >>> +import static org.apache.commons.lang.StringUtils.isNotBlank; >>> + >>> import java.util.ArrayList; >>> -import java.util.Collection; >>> import java.util.Collections; >>> import java.util.List; >>> >>> @@ -65,7 +66,7 @@ >>> } >>> >>> // >>> ------------------------------------------------------------------------- >>> - // Output >>> + // Input & Output >>> // >>> ------------------------------------------------------------------------- >>> >>> private List<UserCredentials> userCredentialsList; >>> @@ -101,47 +102,25 @@ >>> public String execute() >>> throws Exception >>> { >>> - this.paging = createPaging( userStore.countAllUsers() ); >>> - >>> - Collection<User> users = userStore.getAllUsers( >>> paging.getStartPos(), paging.getPageSize() ); >>> - >>> - userCredentialsList = new ArrayList<UserCredentials>(); >>> - >>> - for ( User user : users ) >>> - { >>> - UserCredentials userCredentials = >>> userStore.getUserCredentials( user ); >>> - >>> - userCredentials.getUser(); >>> - >>> - userCredentialsList.add( userCredentials ); >>> - } >>> - >>> - Collections.sort( userCredentialsList, new UsernameComparator() ); >>> - User currentUser = userStore.getUser( >>> currentUserService.getCurrentUser().getId() ); >>> - UserCredentials userCredentials = userStore.getUserCredentials( >>> currentUser ); >>> - >>> - currentUserName = userCredentials.getUsername(); >>> - return SUCCESS; >>> - } >>> - >>> - public String searchUserByName() >>> - { >>> - if ( key.isEmpty() ) >>> - { >>> - return INPUT; >>> - } >>> - >>> - this.paging = createPaging( >>> userStore.countNumberOfSearchUsersByName(key) ); >>> - >>> - userCredentialsList = new >>> ArrayList<UserCredentials>(userStore.searchUsersByName( key, >>> paging.getStartPos(), paging.getPageSize() )); >>> - >>> - Collections.sort( userCredentialsList, new UsernameComparator() ); >>> - User currentUser = userStore.getUser( >>> currentUserService.getCurrentUser().getId() ); >>> - UserCredentials userCredentials = userStore.getUserCredentials( >>> currentUser ); >>> - >>> - currentUserName = userCredentials.getUsername(); >>> - >>> - return SUCCESS; >>> - } >>> - >>> + >>> + if ( isNotBlank( key ) ) // Filter on key only if set >>> + { >>> + this.paging = createPaging( userStore.getUserCountByName( key >>> ) ); >>> + >>> + userCredentialsList = new ArrayList<UserCredentials>( >>> userStore.getUsersBetweenByName( key, paging.getStartPos(), >>> paging.getPageSize() ) ); >>> + } >>> + else >>> + { >>> + this.paging = createPaging( userStore.getUserCount() ); >>> + >>> + userCredentialsList = new ArrayList<UserCredentials>( >>> userStore.getUsersBetween( paging.getStartPos(), paging.getPageSize() ) ); >>> + } >>> + >>> + Collections.sort( userCredentialsList, new UsernameComparator() ); >>> + User currentUser = userStore.getUser( >>> currentUserService.getCurrentUser().getId() ); >>> + UserCredentials userCredentials = userStore.getUserCredentials( >>> currentUser ); >>> + >>> + currentUserName = userCredentials.getUsername(); >>> + return SUCCESS; >>> + } >>> } >>> >>> === modified file >>> 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml' >>> --- >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml >>> 2010-12-03 05:41:34 +0000 >>> +++ >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml >>> 2010-12-06 14:13:48 +0000 >>> @@ -102,6 +102,7 @@ >>> <param name="page">/dhis-web-maintenance-user/allRole.vm</param> >>> <param name="menu">/dhis-web-maintenance-user/menu.vm</param> >>> <param >>> name="javascripts">javascript/role.js,javascript/filterTable.js</param> >>> + <param >>> name="stylesheets">../dhis-web-commons/paging/paging.css</param> >>> </action> >>> >>> <action name="getRole" class="org.hisp.dhis.user.action.GetRoleAction"> >>> >>> === modified file >>> 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/allRole.vm' >>> --- >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/allRole.vm >>> 2010-12-03 05:41:34 +0000 >>> +++ >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/allRole.vm >>> 2010-12-06 14:13:48 +0000 >>> @@ -7,7 +7,7 @@ >>> <td style="vertical-align:top"> >>> <table width="100%"> >>> <tr> >>> - <td>$i18n.getString( >>> "filter_by_role_name" ): <form style="display:inline" action="none" >>> onsubmit="return false"><input type="text" onkeyup="filterValues( >>> this.value )"/></form></td> >>> + <td>#filterDiv( "allRole" )</td> >>> <td colspan="4" >>> style="text-align:right"><input type="button" value="$i18n.getString( >>> 'add_new' )" onclick="window.location.href='showAddRoleForm.action'"/></td> >>> </tr> >>> </table> >>> @@ -33,6 +33,11 @@ >>> #end >>> </tbody> >>> </table> >>> + <p></p> >>> + <div class="paging-container"> >>> + #parse( >>> "/dhis-web-commons/paging/paging.vm" ) >>> + </div> >>> + >>> </td> >>> <td style="width:20em; padding-left:2em; vertical-align:top"> >>> >>> >>> === modified file >>> 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/searchUser.vm' >>> --- >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/searchUser.vm >>> 2010-12-03 05:41:34 +0000 >>> +++ >>> dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/webapp/dhis-web-maintenance-user/searchUser.vm >>> 2010-12-06 14:13:48 +0000 >>> @@ -1,31 +1,9 @@ >>> <table style="width:100%"> >>> <tr> >>> - <td> >>> - <table width='100%'> >>> - <tr> >>> - <td colspan='5'> >>> - <div class="paging-container"> >>> - #parse( >>> "/dhis-web-commons/paging/paging.vm" ) >>> - </div> >>> - </td> >>> - </tr> >>> - </table> >>> - </td> >>> - </tr> >>> - <tr> >>> <td style="vertical-align:top"> >>> <table width='100%'> >>> <tr> >>> - <td>$i18n.getString( >>> "filter_by_username" ): >>> - <form >>> style="display:inline" action="none" onsubmit="return false"> >>> - <div style="inline"> >>> - <input >>> type="text" id='key' value="$!key"> >>> - <input >>> type="button" value="$i18n.getString( "go" )" onclick="searchUserName();" /> >>> - </div> >>> - </form> >>> - </td> >>> - <td></td> >>> - <td></td> >>> + <td>#filterDiv( "alluser" )</td> >>> <td colspan="3" >>> style="text-align:right"><input type="button" value="$i18n.getString( >>> 'add_new' )" onclick="window.location.href='showAddUserForm.action'"/></td> >>> </tr> >>> </table> >>> >>> >>> _______________________________________________ >>> Mailing list: https://launchpad.net/~dhis2-devs >>> Post to : dhis2-devs@lists.launchpad.net >>> Unsubscribe : https://launchpad.net/~dhis2-devs >>> More help : https://help.launchpad.net/ListHelp >>> >>> >> >> >> >> -- >> Cheers, >> Knut Staring >> >> _______________________________________________ >> Mailing list: https://launchpad.net/~dhis2-devs >> Post to : dhis2-devs@lists.launchpad.net >> Unsubscribe : https://launchpad.net/~dhis2-devs >> More help : https://help.launchpad.net/ListHelp >> > -- Cheers, Knut Staring _______________________________________________ Mailing list: https://launchpad.net/~dhis2-devs Post to : dhis2-devs@lists.launchpad.net Unsubscribe : https://launchpad.net/~dhis2-devs More help : https://help.launchpad.net/ListHelp