From aa54e250fd836ee1c6ae3d1d427a4cd98fe94bd4 Mon Sep 17 00:00:00 2001 From: Dean Rasheed <dar17@cam.ac.uk> Date: Mon, 30 Mar 2020 14:00:28 +0100 Subject: [PATCH] New API methods to query Lookup for changes. --- src/application.wadl | 189 +++++++++++++ src/generate-client-methods.py | 12 +- .../ac/cam/ucs/ibis/methods/GroupMethods.java | 61 +++++ .../ac/cam/ucs/ibis/methods/IbisMethods.java | 28 ++ .../ucs/ibis/methods/InstitutionMethods.java | 67 +++++ .../cam/ucs/ibis/methods/PersonMethods.java | 68 +++++ src/php/ibisclient/methods/GroupMethods.php | 60 ++++ src/php/ibisclient/methods/IbisMethods.php | 27 ++ .../ibisclient/methods/InstitutionMethods.php | 66 +++++ src/php/ibisclient/methods/PersonMethods.php | 67 +++++ src/php/test/UnitTests.php | 256 ++++++++++++++++- src/python/ibisclient/methods.py | 258 ++++++++++++++++++ src/python/test/unittests.py | 205 +++++++++++++- src/python3/ibisclient/methods.py | 258 ++++++++++++++++++ src/python3/test/unittests.py | 205 +++++++++++++- 15 files changed, 1799 insertions(+), 28 deletions(-) diff --git a/src/application.wadl b/src/application.wadl index 004c2a6..313620d 100644 --- a/src/application.wadl +++ b/src/application.wadl @@ -9,6 +9,28 @@ * * @author Dean Rasheed (dev-group@ucs.cam.ac.uk) */</doc> + <resource path="last-transaction"> + <method id="getLastTransactionId" name="GET" resultField="value:long"> + <doc> + /** + * Get the ID of the last (most recent) transaction. + * <p> + * A transaction represents an edit made to data in Lookup. Each + * transaction is assigned a unique, sequential, numeric ID. Thus + * this last transaction ID will increase each time some data in + * Lookup is changed. + * + * @return The ID of the latest transaction. + */</doc> + <response> + <representation mediaType="text/plain"/> + <representation mediaType="application/xml"/> + <representation mediaType="application/json"/> + <representation mediaType="text/xml"/> + <representation mediaType="text/x-json"/> + </response> + </method> + </resource> <resource path="version"> <method id="getVersion" name="GET" resultField="value:String"> <doc> @@ -152,6 +174,58 @@ </response> </method> </resource> + <resource path="modified-groups"> + <method id="modifiedGroups" name="GET" resultField="groups:java.util.List<IbisGroup>"> + <doc> + /** + * Find all groups modified between the specified pair of transactions. + * <p> + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) groups were affected. + * <p> + * By default, only a few basic details about each group are returned, + * but the optional <code>fetch</code> parameter may be used to fetch + * additional attributes or references. + * <p> + * NOTE: All data returned reflects the latest available data about each + * group. It is not possible to query for old data, or more detailed + * information about the specific changes made. + * + * @param minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param groupids [optional] Only include groups with IDs or names in + * this list. By default, all modified groups will be included. + * @param includeCancelled [optional] Include cancelled groups. By + * default, cancelled groups are excluded. + * @param membershipChanges [optional] Include groups whose members have + * changed. By default, changes to group memberships are not taken into + * consideration. + * @param fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return The modified groups (in groupid order). + */</doc> + <request> + <param name="minTxId" style="query" type="xs:long" javaType="long" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="maxTxId" style="query" type="xs:long" javaType="long" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="groupids" style="query" type="xs:string" javaType="java.util.List" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="includeCancelled" style="query" type="xs:boolean" javaType="boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="membershipChanges" style="query" type="xs:boolean" javaType="boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="fetch" style="query" type="xs:string" javaType="java.util.List" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + </request> + <response> + <representation mediaType="application/xml"/> + <representation mediaType="application/json"/> + <representation mediaType="text/xml"/> + <representation mediaType="text/x-json"/> + </response> + </method> + </resource> <resource path="search"> <method id="search" name="GET" resultField="groups:java.util.List<IbisGroup>"> <doc> @@ -585,6 +659,63 @@ </response> </method> </resource> + <resource path="modified-insts"> + <method id="modifiedInsts" name="GET" resultField="institutions:java.util.List<IbisInstitution>"> + <doc> + /** + * Find all institutions modified between the specified pair of + * transactions. + * <p> + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) institutions were affected. + * <p> + * By default, only a few basic details about each institution are + * returned, but the optional <code>fetch</code> parameter may be used + * to fetch additional attributes or references. + * <p> + * NOTE: All data returned reflects the latest available data about each + * institution. It is not possible to query for old data, or more + * detailed information about the specific changes made. + * + * @param minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param instids [optional] Only include institutions with instids in + * this list. By default, all modified institutions will be included. + * @param includeCancelled [optional] Include cancelled institutions. By + * default, cancelled institutions are excluded. + * @param contactRowChanges [optional] Include institutions whose contact + * rows have changed. By default, changes to institution contact rows are + * not taken into consideration. + * @param membershipChanges [optional] Include institutions whose members + * have changed. By default, changes to institutional memberships are not + * taken into consideration. + * @param fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return The modified institutions (in instid order). + */</doc> + <request> + <param name="minTxId" style="query" type="xs:long" javaType="long" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="maxTxId" style="query" type="xs:long" javaType="long" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="instids" style="query" type="xs:string" javaType="java.util.List" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="includeCancelled" style="query" type="xs:boolean" javaType="boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="contactRowChanges" style="query" type="xs:boolean" javaType="boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="membershipChanges" style="query" type="xs:boolean" javaType="boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="fetch" style="query" type="xs:string" javaType="java.util.List" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + </request> + <response> + <representation mediaType="application/xml"/> + <representation mediaType="application/json"/> + <representation mediaType="text/xml"/> + <representation mediaType="text/x-json"/> + </response> + </method> + </resource> <resource path="search"> <method id="search" name="GET" resultField="institutions:java.util.List<IbisInstitution>"> <doc> @@ -1190,6 +1321,64 @@ </response> </method> </resource> + <resource path="modified-people"> + <method id="modifiedPeople" name="GET" resultField="people:java.util.List<IbisPerson>"> + <doc> + /** + * Find all people modified between the specified pair of transactions. + * <p> + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) people were affected. + * <p> + * By default, only a few basic details about each person are returned, + * but the optional <code>fetch</code> parameter may be used to fetch + * additional attributes or references. + * <p> + * NOTE: All data returned reflects the latest available data about each + * person. It is not possible to query for old data, or more detailed + * information about the specific changes made. + * + * @param minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param crsids [optional] Only include people with identifiers in this + * list. By default, all modified people will be included. + * @param includeCancelled [optional] Include cancelled people (people + * who are no longer members of the University). By default, cancelled + * people are excluded. + * @param membershipChanges [optional] Include people whose group or + * institutional memberships have changed. By default, only people whose + * attributes have been directly modified are included. + * @param instNameChanges [optional] Include people who are members of + * instituions whose names have changed. This will also cause people + * whose group or institutional memberships have changed to be included. + * By default, changes to institution names do not propagate to people. + * @param fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return The modified people (in identifier order). + */</doc> + <request> + <param name="minTxId" style="query" type="xs:long" javaType="long" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="maxTxId" style="query" type="xs:long" javaType="long" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="crsids" style="query" type="xs:string" javaType="java.util.List" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="includeCancelled" style="query" type="xs:boolean" javaType="boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="membershipChanges" style="query" type="xs:boolean" javaType="boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="instNameChanges" style="query" type="xs:boolean" javaType="boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + <param name="fetch" style="query" type="xs:string" javaType="java.util.List" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> + </request> + <response> + <representation mediaType="application/xml"/> + <representation mediaType="application/json"/> + <representation mediaType="text/xml"/> + <representation mediaType="text/x-json"/> + </response> + </method> + </resource> <resource path="search"> <method id="search" name="GET" resultField="people:java.util.List<IbisPerson>"> <doc> diff --git a/src/generate-client-methods.py b/src/generate-client-methods.py index cf6df94..e10e1fa 100755 --- a/src/generate-client-methods.py +++ b/src/generate-client-methods.py @@ -532,12 +532,14 @@ def generate_java_method(method): path = re.sub("[{][^}]+[}]", "%%%d$s" % param_number, path, 1) param_number += 1 - # Final method result (only int and boolean value fields need to be + # Final method result (only boolean, int and long value fields need to be # coerced into the required type) if method.result_type == "boolean": result = "Boolean.parseBoolean(result.value)" elif method.result_type == "int": result = "Integer.parseInt(result.value)" + elif method.result_type == "long": + result = "Long.parseLong(result.value)" else: result = "result.%s" % method.result_field @@ -873,12 +875,14 @@ def generate_python_method(cls, method): # Method path - replace any placeholders with Python format specifiers path = re.sub("[{]([^}]+)[}]", "%(\\1)s", method.path) - # Final method result (only int and boolean value fields need to be - # coerced into the required type) + # Final method result (only boolean, int and long value fields need to + # be coerced into the required type) if method.result_type == "boolean": result = "result.value and result.value.lower() == \"true\"" elif method.result_type == "int": result = "int(result.value)" + elif method.result_type == "long": + result = "int(result.value)" # int works in Python 2 and 3 else: result = "result.%s" % method.result_field @@ -1138,6 +1142,8 @@ def generate_php_method(method): result = 'strcasecmp($result->value, "true") == 0' elif method.result_type == "int": result = "intval($result->value)" + elif method.result_type == "long": + result = "intval($result->value)" # PHP doesn't have longval() else: result = "$result->%s" % method.result_field.replace(".", "->") diff --git a/src/java/uk/ac/cam/ucs/ibis/methods/GroupMethods.java b/src/java/uk/ac/cam/ucs/ibis/methods/GroupMethods.java index 726e282..be22165 100644 --- a/src/java/uk/ac/cam/ucs/ibis/methods/GroupMethods.java +++ b/src/java/uk/ac/cam/ucs/ibis/methods/GroupMethods.java @@ -178,6 +178,67 @@ public class GroupMethods return result.groups; } + /** + * Find all groups modified between the specified pair of transactions. + * <p> + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) groups were affected. + * <p> + * By default, only a few basic details about each group are returned, + * but the optional <code>fetch</code> parameter may be used to fetch + * additional attributes or references. + * <p> + * NOTE: All data returned reflects the latest available data about each + * group. It is not possible to query for old data, or more detailed + * information about the specific changes made. + * <p> + * <code style="background-color: #eec;">[ HTTP: GET /api/v1/group/modified-groups?minTxId=...&maxTxId=... ]</code> + * + * @param minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param groupids [optional] Only include groups with IDs or names in + * this list. By default, all modified groups will be included. + * @param includeCancelled [optional] Include cancelled groups. By + * default, cancelled groups are excluded. + * @param membershipChanges [optional] Include groups whose members have + * changed. By default, changes to group memberships are not taken into + * consideration. + * @param fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return The modified groups (in groupid order). + */ + public java.util.List<IbisGroup> modifiedGroups(long minTxId, + long maxTxId, + String groupids, + boolean includeCancelled, + boolean membershipChanges, + String fetch) + throws IbisException, IOException, JAXBException + { + String[] pathParams = { }; + Object[] queryParams = { "minTxId", minTxId, + "maxTxId", maxTxId, + "groupids", groupids, + "includeCancelled", includeCancelled, + "membershipChanges", membershipChanges, + "fetch", fetch }; + Object[] formParams = { }; + IbisResult result = conn.invokeMethod(Method.GET, + "api/v1/group/modified-groups", + pathParams, + queryParams, + formParams); + if (result.error != null) + throw new IbisException(result.error); + return result.groups; + } + /** * Search for groups using a free text query string. This is the same * search function that is used in the Lookup web application. diff --git a/src/java/uk/ac/cam/ucs/ibis/methods/IbisMethods.java b/src/java/uk/ac/cam/ucs/ibis/methods/IbisMethods.java index ca61517..b3a678b 100644 --- a/src/java/uk/ac/cam/ucs/ibis/methods/IbisMethods.java +++ b/src/java/uk/ac/cam/ucs/ibis/methods/IbisMethods.java @@ -50,6 +50,34 @@ public class IbisMethods this.conn = conn; } + /** + * Get the ID of the last (most recent) transaction. + * <p> + * A transaction represents an edit made to data in Lookup. Each + * transaction is assigned a unique, sequential, numeric ID. Thus + * this last transaction ID will increase each time some data in + * Lookup is changed. + * <p> + * <code style="background-color: #eec;">[ HTTP: GET /api/v1/last-transaction ]</code> + * + * @return The ID of the latest transaction. + */ + public long getLastTransactionId() + throws IbisException, IOException, JAXBException + { + String[] pathParams = { }; + Object[] queryParams = { }; + Object[] formParams = { }; + IbisResult result = conn.invokeMethod(Method.GET, + "api/v1/last-transaction", + pathParams, + queryParams, + formParams); + if (result.error != null) + throw new IbisException(result.error); + return Long.parseLong(result.value); + } + /** * Get the current API version number. * <p> diff --git a/src/java/uk/ac/cam/ucs/ibis/methods/InstitutionMethods.java b/src/java/uk/ac/cam/ucs/ibis/methods/InstitutionMethods.java index 1657ddf..03cdfcb 100644 --- a/src/java/uk/ac/cam/ucs/ibis/methods/InstitutionMethods.java +++ b/src/java/uk/ac/cam/ucs/ibis/methods/InstitutionMethods.java @@ -208,6 +208,73 @@ public class InstitutionMethods return result.institutions; } + /** + * Find all institutions modified between the specified pair of + * transactions. + * <p> + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) institutions were affected. + * <p> + * By default, only a few basic details about each institution are + * returned, but the optional <code>fetch</code> parameter may be used + * to fetch additional attributes or references. + * <p> + * NOTE: All data returned reflects the latest available data about each + * institution. It is not possible to query for old data, or more + * detailed information about the specific changes made. + * <p> + * <code style="background-color: #eec;">[ HTTP: GET /api/v1/inst/modified-insts?minTxId=...&maxTxId=... ]</code> + * + * @param minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param instids [optional] Only include institutions with instids in + * this list. By default, all modified institutions will be included. + * @param includeCancelled [optional] Include cancelled institutions. By + * default, cancelled institutions are excluded. + * @param contactRowChanges [optional] Include institutions whose contact + * rows have changed. By default, changes to institution contact rows are + * not taken into consideration. + * @param membershipChanges [optional] Include institutions whose members + * have changed. By default, changes to institutional memberships are not + * taken into consideration. + * @param fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return The modified institutions (in instid order). + */ + public java.util.List<IbisInstitution> modifiedInsts(long minTxId, + long maxTxId, + String instids, + boolean includeCancelled, + boolean contactRowChanges, + boolean membershipChanges, + String fetch) + throws IbisException, IOException, JAXBException + { + String[] pathParams = { }; + Object[] queryParams = { "minTxId", minTxId, + "maxTxId", maxTxId, + "instids", instids, + "includeCancelled", includeCancelled, + "contactRowChanges", contactRowChanges, + "membershipChanges", membershipChanges, + "fetch", fetch }; + Object[] formParams = { }; + IbisResult result = conn.invokeMethod(Method.GET, + "api/v1/inst/modified-insts", + pathParams, + queryParams, + formParams); + if (result.error != null) + throw new IbisException(result.error); + return result.institutions; + } + /** * Search for institutions using a free text query string. This is the * same search function that is used in the Lookup web application. diff --git a/src/java/uk/ac/cam/ucs/ibis/methods/PersonMethods.java b/src/java/uk/ac/cam/ucs/ibis/methods/PersonMethods.java index 8414449..09c1827 100644 --- a/src/java/uk/ac/cam/ucs/ibis/methods/PersonMethods.java +++ b/src/java/uk/ac/cam/ucs/ibis/methods/PersonMethods.java @@ -273,6 +273,74 @@ public class PersonMethods return result.people; } + /** + * Find all people modified between the specified pair of transactions. + * <p> + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) people were affected. + * <p> + * By default, only a few basic details about each person are returned, + * but the optional <code>fetch</code> parameter may be used to fetch + * additional attributes or references. + * <p> + * NOTE: All data returned reflects the latest available data about each + * person. It is not possible to query for old data, or more detailed + * information about the specific changes made. + * <p> + * <code style="background-color: #eec;">[ HTTP: GET /api/v1/person/modified-people?minTxId=...&maxTxId=... ]</code> + * + * @param minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param crsids [optional] Only include people with identifiers in this + * list. By default, all modified people will be included. + * @param includeCancelled [optional] Include cancelled people (people + * who are no longer members of the University). By default, cancelled + * people are excluded. + * @param membershipChanges [optional] Include people whose group or + * institutional memberships have changed. By default, only people whose + * attributes have been directly modified are included. + * @param instNameChanges [optional] Include people who are members of + * instituions whose names have changed. This will also cause people + * whose group or institutional memberships have changed to be included. + * By default, changes to institution names do not propagate to people. + * @param fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return The modified people (in identifier order). + */ + public java.util.List<IbisPerson> modifiedPeople(long minTxId, + long maxTxId, + String crsids, + boolean includeCancelled, + boolean membershipChanges, + boolean instNameChanges, + String fetch) + throws IbisException, IOException, JAXBException + { + String[] pathParams = { }; + Object[] queryParams = { "minTxId", minTxId, + "maxTxId", maxTxId, + "crsids", crsids, + "includeCancelled", includeCancelled, + "membershipChanges", membershipChanges, + "instNameChanges", instNameChanges, + "fetch", fetch }; + Object[] formParams = { }; + IbisResult result = conn.invokeMethod(Method.GET, + "api/v1/person/modified-people", + pathParams, + queryParams, + formParams); + if (result.error != null) + throw new IbisException(result.error); + return result.people; + } + /** * Search for people using a free text query string. This is the same * search function that is used in the Lookup web application. diff --git a/src/php/ibisclient/methods/GroupMethods.php b/src/php/ibisclient/methods/GroupMethods.php index 5e5b339..631e4e6 100644 --- a/src/php/ibisclient/methods/GroupMethods.php +++ b/src/php/ibisclient/methods/GroupMethods.php @@ -178,6 +178,66 @@ class GroupMethods return $result->groups; } + /** + * Find all groups modified between the specified pair of transactions. + * + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) groups were affected. + * + * By default, only a few basic details about each group are returned, + * but the optional ``fetch`` parameter may be used to fetch + * additional attributes or references. + * + * NOTE: All data returned reflects the latest available data about each + * group. It is not possible to query for old data, or more detailed + * information about the specific changes made. + * + * ``[ HTTP: GET /api/v1/group/modified-groups?minTxId=...&maxTxId=... ]`` + * + * @param long $minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param long $maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param string $groupids [optional] Only include groups with IDs or names in + * this list. By default, all modified groups will be included. + * @param boolean $includeCancelled [optional] Include cancelled groups. By + * default, cancelled groups are excluded. + * @param boolean $membershipChanges [optional] Include groups whose members have + * changed. By default, changes to group memberships are not taken into + * consideration. + * @param string $fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return IbisGroup[] The modified groups (in groupid order). + */ + public function modifiedGroups($minTxId, + $maxTxId, + $groupids=null, + $includeCancelled=null, + $membershipChanges=null, + $fetch=null) + { + $pathParams = array(); + $queryParams = array("minTxId" => $minTxId, + "maxTxId" => $maxTxId, + "groupids" => $groupids, + "includeCancelled" => $includeCancelled, + "membershipChanges" => $membershipChanges, + "fetch" => $fetch); + $formParams = array(); + $result = $this->conn->invokeMethod("GET", + 'api/v1/group/modified-groups', + $pathParams, + $queryParams, + $formParams); + if (isset($result->error)) + throw new IbisException($result->error); + return $result->groups; + } + /** * Search for groups using a free text query string. This is the same * search function that is used in the Lookup web application. diff --git a/src/php/ibisclient/methods/IbisMethods.php b/src/php/ibisclient/methods/IbisMethods.php index 783e455..0595fd0 100644 --- a/src/php/ibisclient/methods/IbisMethods.php +++ b/src/php/ibisclient/methods/IbisMethods.php @@ -43,6 +43,33 @@ class IbisMethods $this->conn = $conn; } + /** + * Get the ID of the last (most recent) transaction. + * + * A transaction represents an edit made to data in Lookup. Each + * transaction is assigned a unique, sequential, numeric ID. Thus + * this last transaction ID will increase each time some data in + * Lookup is changed. + * + * ``[ HTTP: GET /api/v1/last-transaction ]`` + * + * @return long The ID of the latest transaction. + */ + public function getLastTransactionId() + { + $pathParams = array(); + $queryParams = array(); + $formParams = array(); + $result = $this->conn->invokeMethod("GET", + 'api/v1/last-transaction', + $pathParams, + $queryParams, + $formParams); + if (isset($result->error)) + throw new IbisException($result->error); + return intval($result->value); + } + /** * Get the current API version number. * diff --git a/src/php/ibisclient/methods/InstitutionMethods.php b/src/php/ibisclient/methods/InstitutionMethods.php index f5122a7..7e0032b 100644 --- a/src/php/ibisclient/methods/InstitutionMethods.php +++ b/src/php/ibisclient/methods/InstitutionMethods.php @@ -203,6 +203,72 @@ class InstitutionMethods return $result->institutions; } + /** + * Find all institutions modified between the specified pair of + * transactions. + * + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) institutions were affected. + * + * By default, only a few basic details about each institution are + * returned, but the optional ``fetch`` parameter may be used + * to fetch additional attributes or references. + * + * NOTE: All data returned reflects the latest available data about each + * institution. It is not possible to query for old data, or more + * detailed information about the specific changes made. + * + * ``[ HTTP: GET /api/v1/inst/modified-insts?minTxId=...&maxTxId=... ]`` + * + * @param long $minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param long $maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param string $instids [optional] Only include institutions with instids in + * this list. By default, all modified institutions will be included. + * @param boolean $includeCancelled [optional] Include cancelled institutions. By + * default, cancelled institutions are excluded. + * @param boolean $contactRowChanges [optional] Include institutions whose contact + * rows have changed. By default, changes to institution contact rows are + * not taken into consideration. + * @param boolean $membershipChanges [optional] Include institutions whose members + * have changed. By default, changes to institutional memberships are not + * taken into consideration. + * @param string $fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return IbisInstitution[] The modified institutions (in instid order). + */ + public function modifiedInsts($minTxId, + $maxTxId, + $instids=null, + $includeCancelled=null, + $contactRowChanges=null, + $membershipChanges=null, + $fetch=null) + { + $pathParams = array(); + $queryParams = array("minTxId" => $minTxId, + "maxTxId" => $maxTxId, + "instids" => $instids, + "includeCancelled" => $includeCancelled, + "contactRowChanges" => $contactRowChanges, + "membershipChanges" => $membershipChanges, + "fetch" => $fetch); + $formParams = array(); + $result = $this->conn->invokeMethod("GET", + 'api/v1/inst/modified-insts', + $pathParams, + $queryParams, + $formParams); + if (isset($result->error)) + throw new IbisException($result->error); + return $result->institutions; + } + /** * Search for institutions using a free text query string. This is the * same search function that is used in the Lookup web application. diff --git a/src/php/ibisclient/methods/PersonMethods.php b/src/php/ibisclient/methods/PersonMethods.php index 8f95428..7dc1e38 100644 --- a/src/php/ibisclient/methods/PersonMethods.php +++ b/src/php/ibisclient/methods/PersonMethods.php @@ -251,6 +251,73 @@ class PersonMethods return $result->people; } + /** + * Find all people modified between the specified pair of transactions. + * + * The transaction IDs specified should be the IDs from two different + * requests for the last (most recent) transaction ID, made at different + * times, that returned different values, indicating that some Lookup + * data was modified in the period between the two requests. This method + * then determines which (if any) people were affected. + * + * By default, only a few basic details about each person are returned, + * but the optional ``fetch`` parameter may be used to fetch + * additional attributes or references. + * + * NOTE: All data returned reflects the latest available data about each + * person. It is not possible to query for old data, or more detailed + * information about the specific changes made. + * + * ``[ HTTP: GET /api/v1/person/modified-people?minTxId=...&maxTxId=... ]`` + * + * @param long $minTxId [required] Include modifications made in transactions + * after (but not including) this one. + * @param long $maxTxId [required] Include modifications made in transactions + * up to and including this one. + * @param string $crsids [optional] Only include people with identifiers in this + * list. By default, all modified people will be included. + * @param boolean $includeCancelled [optional] Include cancelled people (people + * who are no longer members of the University). By default, cancelled + * people are excluded. + * @param boolean $membershipChanges [optional] Include people whose group or + * institutional memberships have changed. By default, only people whose + * attributes have been directly modified are included. + * @param boolean $instNameChanges [optional] Include people who are members of + * instituions whose names have changed. This will also cause people + * whose group or institutional memberships have changed to be included. + * By default, changes to institution names do not propagate to people. + * @param string $fetch [optional] A comma-separated list of any additional + * attributes or references to fetch. + * + * @return IbisPerson[] The modified people (in identifier order). + */ + public function modifiedPeople($minTxId, + $maxTxId, + $crsids=null, + $includeCancelled=null, + $membershipChanges=null, + $instNameChanges=null, + $fetch=null) + { + $pathParams = array(); + $queryParams = array("minTxId" => $minTxId, + "maxTxId" => $maxTxId, + "crsids" => $crsids, + "includeCancelled" => $includeCancelled, + "membershipChanges" => $membershipChanges, + "instNameChanges" => $instNameChanges, + "fetch" => $fetch); + $formParams = array(); + $result = $this->conn->invokeMethod("GET", + 'api/v1/person/modified-people', + $pathParams, + $queryParams, + $formParams); + if (isset($result->error)) + throw new IbisException($result->error); + return $result->people; + } + /** * Search for people using a free text query string. This is the same * search function that is used in the Lookup web application. diff --git a/src/php/test/UnitTests.php b/src/php/test/UnitTests.php index 648401a..e88c717 100644 --- a/src/php/test/UnitTests.php +++ b/src/php/test/UnitTests.php @@ -18,31 +18,34 @@ You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <http://www.gnu.org/licenses/>. */ -require_once 'PHPUnit/Autoload.php'; - require_once dirname(__FILE__) . "/../ibisclient/client/IbisClientConnection.php"; require_once dirname(__FILE__) . "/../ibisclient/client/IbisException.php"; require_once dirname(__FILE__) . "/../ibisclient/methods/GroupMethods.php"; +require_once dirname(__FILE__) . "/../ibisclient/methods/IbisMethods.php"; require_once dirname(__FILE__) . "/../ibisclient/methods/InstitutionMethods.php"; require_once dirname(__FILE__) . "/../ibisclient/methods/PersonMethods.php"; -class UnitTests extends PHPUnit_Framework_TestCase +use PHPUnit\Framework\TestCase; + +class UnitTests extends TestCase { private static $localConnection = false; private static $runEditTests = false; private static $initialised = false; private static $conn = null; + private static $m = null; private static $pm = null; private static $im = null; private static $gm = null; - public function setUp() + public function setUp(): void { if (!UnitTests::$initialised) { UnitTests::$conn = UnitTests::$localConnection ? IbisClientConnection::createLocalConnection() : IbisClientConnection::createTestConnection(); + UnitTests::$m = new IbisMethods(UnitTests::$conn); UnitTests::$pm = new PersonMethods(UnitTests::$conn); UnitTests::$im = new InstitutionMethods(UnitTests::$conn); UnitTests::$gm = new GroupMethods(UnitTests::$conn); @@ -52,6 +55,23 @@ class UnitTests extends PHPUnit_Framework_TestCase print(" " . $this->getName() . "()\n"); } + // -------------------------------------------------------------------- + // Ibis tests. + // -------------------------------------------------------------------- + + public function testGetVersion() + { + $version = UnitTests::$m->getVersion(); + $this->assertNotNull($version); + $this->assertEquals(1, preg_match("/^[0-9]+[.][0-9]+\$/", $version)); + } + + public function testGetLastTransactionId() + { + $lastTransactionId = UnitTests::$m->getLastTransactionId(); + $this->assertTrue($lastTransactionId > 900000); + } + // -------------------------------------------------------------------- // Person tests. // -------------------------------------------------------------------- @@ -64,6 +84,24 @@ class UnitTests extends PHPUnit_Framework_TestCase $this->assertEquals("displayName", $schemes[0]->schemeid); } + public function testAllPeople() + { + $people = UnitTests::$pm->allPeople(false, null, 10, null); + + $this->assertEquals(10, sizeof($people)); + $this->assertEquals("aa", substr($people[0]->identifier->value, 0, 2)); + + $people = UnitTests::$pm->allPeople(false, "dar17", 10, null); + $this->assertEquals(10, sizeof($people)); + $this->assertTrue(strcmp($people[0]->identifier->value, "dar17") > 0); + + $id8 = $people[8]->identifier->value; + $id9 = $people[9]->identifier->value; + $people = UnitTests::$pm->allPeople(false, $id8, 10, null); + $this->assertEquals(10, sizeof($people)); + $this->assertEquals($id9, $people[0]->identifier->value); + } + public function testNoSuchPerson() { $person = UnitTests::$pm->getPerson("crsid", "dar1734toolong"); @@ -166,6 +204,36 @@ class UnitTests extends PHPUnit_Framework_TestCase $this->assertTrue($count > 10); } + public function testPersonLqlSearch() + { + $people = UnitTests::$pm->search("person: in inst(uis) and surname=Rasheed", false, false, + null, null, 0, 100, null, "title"); + $this->assertEquals(1, sizeof($people)); + $this->assertEquals("dar17", $people[0]->identifier->value); + $this->assertEquals("Database administrator and developer", $people[0]->attributes[0]->value); + + $people = UnitTests::$pm->search("person: dar54", false, false, + null, null, 0, 100, null, null); + $this->assertEquals(0, sizeof($people)); + + $people = UnitTests::$pm->search("person: dar54", false, true, + null, null, 0, 100, null, null); + $this->assertEquals(1, sizeof($people)); + $this->assertEquals("dar54", $people[0]->identifier->value); + } + + public function testPersonLqlSearchCount() + { + $count = UnitTests::$pm->searchCount("person: dar17", false, false, null, null); + $this->assertEquals(1, $count); + + $count = UnitTests::$pm->searchCount("person: dar54", false, false, null, null); + $this->assertEquals(0, $count); + + $count = UnitTests::$pm->searchCount("person: dar54", false, true, null, null); + $this->assertEquals(1, $count); + } + public function testIsPersonMemberOfInst() { $this->assertTrue(UnitTests::$pm->isMemberOfInst("crsid", "dar17", "UIS")); @@ -264,7 +332,12 @@ class UnitTests extends PHPUnit_Framework_TestCase public function testPersonEdit() { - if (!UnitTests::$runEditTests) return; + if (!UnitTests::$runEditTests) + { + $this->assertTrue(true); // Keep PHPUnit happy + return; + } + $ex = null; try { @@ -377,7 +450,12 @@ class UnitTests extends PHPUnit_Framework_TestCase public function testPersonEditImage() { - if (!UnitTests::$runEditTests) return; + if (!UnitTests::$runEditTests) + { + $this->assertTrue(true); // Keep PHPUnit happy + return; + } + $ex = null; try { @@ -453,6 +531,32 @@ class UnitTests extends PHPUnit_Framework_TestCase if ($ex) throw $ex; } + public function testModifiedPeople() + { + // Note: transactions 2..1047 are the same on Lookup and lookup-test + $people = UnitTests::$pm->modifiedPeople(937, 938, null, false, false, false, null); + $this->assertEquals(1, sizeof($people)); + $this->assertEquals("v4500", $people[0]->identifier->value); + + $people = UnitTests::$pm->modifiedPeople(752, 753, null, false, false, false, null); + $this->assertEquals(0, sizeof($people)); + + $people = UnitTests::$pm->modifiedPeople(752, 753, null, true, false, false, null); + $this->assertEquals(2, sizeof($people)); + $this->assertEquals("cr10001", $people[0]->identifier->value); + $this->assertEquals("gar34", $people[1]->identifier->value); + + $people = UnitTests::$pm->modifiedPeople(752, 753, "cr10001", false, false, false, null); + $this->assertEquals(0, sizeof($people)); + + $people = UnitTests::$pm->modifiedPeople(752, 753, "cr10001", true, false, false, null); + $this->assertEquals(1, sizeof($people)); + $this->assertEquals("cr10001", $people[0]->identifier->value); + + $people = UnitTests::$pm->modifiedPeople(752, 753, "cr10002", true, false, false, null); + $this->assertEquals(0, sizeof($people)); + } + // -------------------------------------------------------------------- // Institution tests. // -------------------------------------------------------------------- @@ -656,6 +760,31 @@ class UnitTests extends PHPUnit_Framework_TestCase $this->assertTrue($count > 5); } + public function testInstLqlSearch() + { + $insts = UnitTests::$im->search("inst: parent of (uistest)", false, false, + null, 0, 100, null, null); + $this->assertEquals("UIS", $insts[0]->instid); + + $insts = UnitTests::$im->search("inst: address ~ CB3 0JG", false, false, + null, 0, 100, null, "phone_numbers"); + $this->assertEquals(1, sizeof($insts)); + $this->assertEquals("GIRTON", $insts[0]->instid); + $this->assertEquals("38999", $insts[0]->attributes[0]->value); + } + + public function testInstLqlSearchCount() + { + $count = UnitTests::$im->searchCount("inst: UIS", false, false, null); + $this->assertEquals(1, $count); + + $count = UnitTests::$im->searchCount("inst: CS", false, false, null); + $this->assertEquals(0, $count); + + $count = UnitTests::$im->searchCount("inst: CS", false, true, null); + $this->assertEquals(1, $count); + } + public function testGetInstContactRows() { $inst = UnitTests::$im->getInst("CS", "contact_rows.jdInstid"); @@ -714,7 +843,12 @@ class UnitTests extends PHPUnit_Framework_TestCase public function testInstEdit() { - if (!UnitTests::$runEditTests) return; + if (!UnitTests::$runEditTests) + { + $this->assertTrue(true); // Keep PHPUnit happy + return; + } + $ex = null; try { @@ -805,7 +939,12 @@ class UnitTests extends PHPUnit_Framework_TestCase public function testInstEditImage() { - if (!UnitTests::$runEditTests) return; + if (!UnitTests::$runEditTests) + { + $this->assertTrue(true); // Keep PHPUnit happy + return; + } + $ex = null; try { @@ -869,6 +1008,36 @@ class UnitTests extends PHPUnit_Framework_TestCase if ($ex) throw $ex; } + public function testModifiedInsts() + { + // Note: transactions 2..1047 are the same on Lookup and lookup-test + $insts = UnitTests::$im->modifiedInsts(491, 492, null, false, false, false, null); + + $this->assertEquals(1, sizeof($insts)); + $this->assertEquals("AUT", $insts[0]->instid); + + $insts = UnitTests::$im->modifiedInsts(438, 439, null, false, false, false, null); + $this->assertEquals(0, sizeof($insts)); + + $insts = UnitTests::$im->modifiedInsts(438, 439, null, true, false, false, null); + $this->assertEquals(1, sizeof($insts)); + $this->assertEquals("SPVSR04", $insts[0]->instid); + + $insts = UnitTests::$im->modifiedInsts(764, 765, "IUSCMED", false, false, false, null); + $this->assertEquals(1, sizeof($insts)); + $this->assertEquals("IUSCMED", $insts[0]->instid); + + $insts = UnitTests::$im->modifiedInsts(764, 765, "IUSCMED2", false, false, false, null); + $this->assertEquals(0, sizeof($insts)); + + $insts = UnitTests::$im->modifiedInsts(45, 46, null, false, false, false, null); + $this->assertEquals(0, sizeof($insts)); + + $insts = UnitTests::$im->modifiedInsts(45, 46, null, false, true, false, null); + $this->assertEquals(1, sizeof($insts)); + $this->assertEquals("Clare Hall", $insts[0]->name); + } + // -------------------------------------------------------------------- // Group tests. // -------------------------------------------------------------------- @@ -996,9 +1165,45 @@ class UnitTests extends PHPUnit_Framework_TestCase $this->assertEquals(6, $count); } + public function testGroupLqlSearch() + { + $groups = UnitTests::$gm->search("group: title='Editors group for \"UIS\"'", + false, false, 0, 100, null, null); + $this->assertEquals("uis-editors", $groups[0]->name); + + $groups = UnitTests::$gm->search("group: uistest-members", false, false, + 0, 1, null, "all_members"); + $this->assertEquals(1, sizeof($groups)); + $this->assertEquals("uistest-members", $groups[0]->name); + $this->assertTrue(sizeof($groups[0]->members) > 10); + $this->assertEquals("abc123", $groups[0]->members[0]->identifier->value); + + $groups = UnitTests::$gm->search("group: biotec-editors", false, false, + 0, 1, null, null); + $this->assertEquals(0, sizeof($groups)); + + $groups = UnitTests::$gm->search("group: biotec-editors", false, true, + 0, 1, null, null); + $this->assertEquals(1, sizeof($groups)); + } + + public function testGroupLqlSearchCount() + { + $count = UnitTests::$gm->searchCount("group: biotec-editors", false, false); + $this->assertEquals(0, $count); + + $count = UnitTests::$gm->searchCount("group: biotec-editors", false, true); + $this->assertEquals(1, $count); + } + public function testEditGroupMembers() { - if (!UnitTests::$runEditTests) return; + if (!UnitTests::$runEditTests) + { + $this->assertTrue(true); // Keep PHPUnit happy + return; + } + $ex = null; try { @@ -1061,4 +1266,37 @@ class UnitTests extends PHPUnit_Framework_TestCase if ($ex) throw $ex; } + + public function testModifiedGroups() + { + // Note: transactions 2..1047 are the same on Lookup and lookup-test + $groups = UnitTests::$gm->modifiedGroups(492, 493, null, false, false, null); + + $this->assertEquals(1, sizeof($groups)); + $this->assertEquals("100426", $groups[0]->groupid); + $this->assertEquals("maths-intakes-editors", $groups[0]->name); + + $groups = UnitTests::$gm->modifiedGroups(487, 488, null, false, false, null); + $this->assertEquals(0, sizeof($groups)); + + $groups = UnitTests::$gm->modifiedGroups(487, 488, null, true, false, null); + $this->assertEquals(1, sizeof($groups)); + $this->assertEquals("100855", $groups[0]->groupid); + $this->assertEquals("cstest-foofoo", $groups[0]->name); + + $groups = UnitTests::$gm->modifiedGroups(743, 744, "100259", false, false, null); + $this->assertEquals(1, sizeof($groups)); + $this->assertEquals("100259", $groups[0]->groupid); + $this->assertEquals("biol-managers", $groups[0]->name); + + $groups = UnitTests::$gm->modifiedGroups(743, 744, "biol-managers", false, false, null); + $this->assertEquals(1, sizeof($groups)); + $this->assertEquals("100259", $groups[0]->groupid); + $this->assertEquals("biol-managers", $groups[0]->name); + + $groups = UnitTests::$gm->modifiedGroups(743, 744, "100260", false, false, null); + $this->assertEquals(0, sizeof($groups)); + $groups = UnitTests::$gm->modifiedGroups(743, 744, "biol-editors", false, false, null); + $this->assertEquals(0, sizeof($groups)); + } } diff --git a/src/python/ibisclient/methods.py b/src/python/ibisclient/methods.py index 8736859..0aa65df 100644 --- a/src/python/ibisclient/methods.py +++ b/src/python/ibisclient/methods.py @@ -36,6 +36,31 @@ class IbisMethods: def __init__(self, conn): self.conn = conn + def getLastTransactionId(self): + """ + Get the ID of the last (most recent) transaction. + + A transaction represents an edit made to data in Lookup. Each + transaction is assigned a unique, sequential, numeric ID. Thus + this last transaction ID will increase each time some data in + Lookup is changed. + + ``[ HTTP: GET /api/v1/last-transaction ]`` + + **Returns** + long + The ID of the latest transaction. + """ + path = "api/v1/last-transaction" + path_params = {} + query_params = {} + form_params = {} + result = self.conn.invoke_method("GET", path, path_params, + query_params, form_params) + if result.error: + raise IbisException(result.error) + return int(result.value) + def getVersion(self): """ Get the current API version number. @@ -208,6 +233,78 @@ class GroupMethods: raise IbisException(result.error) return result.groups + def modifiedGroups(self, + minTxId, + maxTxId, + groupids=None, + includeCancelled=None, + membershipChanges=None, + fetch=None): + """ + Find all groups modified between the specified pair of transactions. + + The transaction IDs specified should be the IDs from two different + requests for the last (most recent) transaction ID, made at different + times, that returned different values, indicating that some Lookup + data was modified in the period between the two requests. This method + then determines which (if any) groups were affected. + + By default, only a few basic details about each group are returned, + but the optional `fetch` parameter may be used to fetch + additional attributes or references. + + .. note:: + All data returned reflects the latest available data about each + group. It is not possible to query for old data, or more detailed + information about the specific changes made. + + ``[ HTTP: GET /api/v1/group/modified-groups?minTxId=...&maxTxId=... ]`` + + **Parameters** + `minTxId` : long + [required] Include modifications made in transactions + after (but not including) this one. + + `maxTxId` : long + [required] Include modifications made in transactions + up to and including this one. + + `groupids` : str + [optional] Only include groups with IDs or names in + this list. By default, all modified groups will be included. + + `includeCancelled` : bool + [optional] Include cancelled groups. By + default, cancelled groups are excluded. + + `membershipChanges` : bool + [optional] Include groups whose members have + changed. By default, changes to group memberships are not taken into + consideration. + + `fetch` : str + [optional] A comma-separated list of any additional + attributes or references to fetch. + + **Returns** + list of :any:`IbisGroup` + The modified groups (in groupid order). + """ + path = "api/v1/group/modified-groups" + path_params = {} + query_params = {"minTxId": minTxId, + "maxTxId": maxTxId, + "groupids": groupids, + "includeCancelled": includeCancelled, + "membershipChanges": membershipChanges, + "fetch": fetch} + form_params = {} + result = self.conn.invoke_method("GET", path, path_params, + query_params, form_params) + if result.error: + raise IbisException(result.error) + return result.groups + def search(self, query, approxMatches=None, @@ -743,6 +840,86 @@ class InstitutionMethods: raise IbisException(result.error) return result.institutions + def modifiedInsts(self, + minTxId, + maxTxId, + instids=None, + includeCancelled=None, + contactRowChanges=None, + membershipChanges=None, + fetch=None): + """ + Find all institutions modified between the specified pair of + transactions. + + The transaction IDs specified should be the IDs from two different + requests for the last (most recent) transaction ID, made at different + times, that returned different values, indicating that some Lookup + data was modified in the period between the two requests. This method + then determines which (if any) institutions were affected. + + By default, only a few basic details about each institution are + returned, but the optional `fetch` parameter may be used + to fetch additional attributes or references. + + .. note:: + All data returned reflects the latest available data about each + institution. It is not possible to query for old data, or more + detailed information about the specific changes made. + + ``[ HTTP: GET /api/v1/inst/modified-insts?minTxId=...&maxTxId=... ]`` + + **Parameters** + `minTxId` : long + [required] Include modifications made in transactions + after (but not including) this one. + + `maxTxId` : long + [required] Include modifications made in transactions + up to and including this one. + + `instids` : str + [optional] Only include institutions with instids in + this list. By default, all modified institutions will be included. + + `includeCancelled` : bool + [optional] Include cancelled institutions. By + default, cancelled institutions are excluded. + + `contactRowChanges` : bool + [optional] Include institutions whose contact + rows have changed. By default, changes to institution contact rows are + not taken into consideration. + + `membershipChanges` : bool + [optional] Include institutions whose members + have changed. By default, changes to institutional memberships are not + taken into consideration. + + `fetch` : str + [optional] A comma-separated list of any additional + attributes or references to fetch. + + **Returns** + list of :any:`IbisInstitution` + The modified institutions (in instid order). + """ + path = "api/v1/inst/modified-insts" + path_params = {} + query_params = {"minTxId": minTxId, + "maxTxId": maxTxId, + "instids": instids, + "includeCancelled": includeCancelled, + "contactRowChanges": contactRowChanges, + "membershipChanges": membershipChanges, + "fetch": fetch} + form_params = {} + result = self.conn.invoke_method("GET", path, path_params, + query_params, form_params) + if result.error: + raise IbisException(result.error) + return result.institutions + def search(self, query, approxMatches=None, @@ -1485,6 +1662,87 @@ class PersonMethods: raise IbisException(result.error) return result.people + def modifiedPeople(self, + minTxId, + maxTxId, + crsids=None, + includeCancelled=None, + membershipChanges=None, + instNameChanges=None, + fetch=None): + """ + Find all people modified between the specified pair of transactions. + + The transaction IDs specified should be the IDs from two different + requests for the last (most recent) transaction ID, made at different + times, that returned different values, indicating that some Lookup + data was modified in the period between the two requests. This method + then determines which (if any) people were affected. + + By default, only a few basic details about each person are returned, + but the optional `fetch` parameter may be used to fetch + additional attributes or references. + + .. note:: + All data returned reflects the latest available data about each + person. It is not possible to query for old data, or more detailed + information about the specific changes made. + + ``[ HTTP: GET /api/v1/person/modified-people?minTxId=...&maxTxId=... ]`` + + **Parameters** + `minTxId` : long + [required] Include modifications made in transactions + after (but not including) this one. + + `maxTxId` : long + [required] Include modifications made in transactions + up to and including this one. + + `crsids` : str + [optional] Only include people with identifiers in this + list. By default, all modified people will be included. + + `includeCancelled` : bool + [optional] Include cancelled people (people + who are no longer members of the University). By default, cancelled + people are excluded. + + `membershipChanges` : bool + [optional] Include people whose group or + institutional memberships have changed. By default, only people whose + attributes have been directly modified are included. + + `instNameChanges` : bool + [optional] Include people who are members of + instituions whose names have changed. This will also cause people + whose group or institutional memberships have changed to be included. + By default, changes to institution names do not propagate to people. + + `fetch` : str + [optional] A comma-separated list of any additional + attributes or references to fetch. + + **Returns** + list of :any:`IbisPerson` + The modified people (in identifier order). + """ + path = "api/v1/person/modified-people" + path_params = {} + query_params = {"minTxId": minTxId, + "maxTxId": maxTxId, + "crsids": crsids, + "includeCancelled": includeCancelled, + "membershipChanges": membershipChanges, + "instNameChanges": instNameChanges, + "fetch": fetch} + form_params = {} + result = self.conn.invoke_method("GET", path, path_params, + query_params, form_params) + if result.error: + raise IbisException(result.error) + return result.people + def search(self, query, approxMatches=None, diff --git a/src/python/test/unittests.py b/src/python/test/unittests.py index fef81b6..5c50a67 100644 --- a/src/python/test/unittests.py +++ b/src/python/test/unittests.py @@ -22,6 +22,7 @@ # -------------------------------------------------------------------------- from datetime import date +import re import unittest import urllib @@ -43,6 +44,7 @@ run_edit_tests = False # Globals initialised once and re-used in each test conn = None +m = None pm = None im = None gm = None @@ -50,7 +52,7 @@ initialised = False class IbisUnitTests(unittest.TestCase): def setUp(self): - global conn, pm, im, gm, initialised + global conn, m, pm, im, gm, initialised if not initialised: if local: @@ -58,11 +60,25 @@ class IbisUnitTests(unittest.TestCase): else: conn = createTestConnection() + m = IbisMethods(conn) pm = PersonMethods(conn) im = InstitutionMethods(conn) gm = GroupMethods(conn) initialised = True + # -------------------------------------------------------------------- + # Ibis tests. + # -------------------------------------------------------------------- + + def test_get_version(self): + version = m.getVersion() + self.assertIsNotNone(version) + self.assertTrue(re.match("^[0-9]+[.][0-9]+$", version)) + + def test_get_last_transaction_id(self): + lastTransactionId = m.getLastTransactionId() + self.assertTrue(lastTransactionId > 900000) + # -------------------------------------------------------------------- # Person tests. # -------------------------------------------------------------------- @@ -72,6 +88,22 @@ class IbisUnitTests(unittest.TestCase): self.assertTrue(len(schemes) > 10) self.assertEqual("displayName", schemes[0].schemeid) + def test_all_people(self): + people = pm.allPeople(False, None, 10, None) + + self.assertEquals(10, len(people)) + self.assertEquals("aa", people[0].identifier.value[0:2]) + + people = pm.allPeople(False, "dar17", 10, None) + self.assertEquals(10, len(people)) + self.assertTrue(people[0].identifier.value > "dar17") + + id8 = people[8].identifier.value + id9 = people[9].identifier.value + people = pm.allPeople(False, id8, 10, None) + self.assertEquals(10, len(people)) + self.assertEquals(id9, people[0].identifier.value) + def test_no_such_person(self): person = pm.getPerson("crsid", "dar1734toolong") self.assertIsNone(person) @@ -99,9 +131,9 @@ class IbisUnitTests(unittest.TestCase): def test_get_person_attributes(self): attrs = pm.getAttributes("crsid", "dar17", "email,title") - self.assertEqual("title", attrs[0].scheme); - self.assertEqual("Database administrator and developer", attrs[0].value); - self.assertEqual("email", attrs[1].scheme); + self.assertEqual("title", attrs[0].scheme) + self.assertEqual("Database administrator and developer", attrs[0].value) + self.assertEqual("email", attrs[1].scheme) attr = pm.getAttribute("crsid", "dar17", attrs[1].attrid) self.assertEqual(attrs[1].scheme, attr.scheme) @@ -152,6 +184,32 @@ class IbisUnitTests(unittest.TestCase): count = pm.searchCount("j smith", False, False) self.assertTrue(count > 10) + def test_person_lql_search(self): + people = pm.search("person: in inst(uis) and surname=Rasheed", False, False, + None, None, 0, 100, None, "title") + self.assertEquals(1, len(people)) + self.assertEquals("dar17", people[0].identifier.value) + self.assertEquals("Database administrator and developer", people[0].attributes[0].value) + + people = pm.search("person: dar54", False, False, + None, None, 0, 100, None, None) + self.assertEquals(0, len(people)) + + people = pm.search("person: dar54", False, True, + None, None, 0, 100, None, None) + self.assertEquals(1, len(people)) + self.assertEquals("dar54", people[0].identifier.value) + + def test_person_lql_search_count(self): + count = pm.searchCount("person: dar17", False, False, None, None) + self.assertEquals(1, count) + + count = pm.searchCount("person: dar54", False, False, None, None) + self.assertEquals(0, count) + + count = pm.searchCount("person: dar54", False, True, None, None) + self.assertEquals(1, count) + def test_is_person_member_of_inst(self): self.assertTrue(pm.isMemberOfInst("crsid", "dar17", "UIS")) self.assertFalse(pm.isMemberOfInst("crsid", "dar17", "ENG")) @@ -391,6 +449,30 @@ class IbisUnitTests(unittest.TestCase): conn.set_username("anonymous") conn.set_password("") + def test_modified_people(self): + # Note: transactions 2..1047 are the same on Lookup and lookup-test + people = pm.modifiedPeople(937, 938, None, False, False, False, None) + self.assertEquals(1, len(people)) + self.assertEquals("v4500", people[0].identifier.value) + + people = pm.modifiedPeople(752, 753, None, False, False, False, None) + self.assertEquals(0, len(people)) + + people = pm.modifiedPeople(752, 753, None, True, False, False, None) + self.assertEquals(2, len(people)) + self.assertEquals("cr10001", people[0].identifier.value) + self.assertEquals("gar34", people[1].identifier.value) + + people = pm.modifiedPeople(752, 753, "cr10001", False, False, False, None) + self.assertEquals(0, len(people)) + + people = pm.modifiedPeople(752, 753, "cr10001", True, False, False, None) + self.assertEquals(1, len(people)) + self.assertEquals("cr10001", people[0].identifier.value) + + people = pm.modifiedPeople(752, 753, "cr10002", True, False, False, None) + self.assertEquals(0, len(people)) + # -------------------------------------------------------------------- # Institution tests. # -------------------------------------------------------------------- @@ -426,9 +508,9 @@ class IbisUnitTests(unittest.TestCase): def test_get_inst_attributes(self): attrs = im.getAttributes("CS", "acronym,email") - self.assertEqual("acronym", attrs[0].scheme); - self.assertEqual("UCS", attrs[0].value); - self.assertEqual("email", attrs[1].scheme); + self.assertEqual("acronym", attrs[0].scheme) + self.assertEqual("UCS", attrs[0].value) + self.assertEqual("email", attrs[1].scheme) attr = im.getAttribute("CS", attrs[0].attrid) self.assertEqual(attrs[0].scheme, attr.scheme) @@ -549,6 +631,27 @@ class IbisUnitTests(unittest.TestCase): count = im.searchCount("computing") self.assertTrue(count > 5) + def test_inst_lql_search(self): + insts = im.search("inst: parent of (uistest)", False, False, + None, 0, 100, None, None) + self.assertEquals("UIS", insts[0].instid) + + insts = im.search("inst: address ~ CB3 0JG", False, False, + None, 0, 100, None, "phone_numbers") + self.assertEquals(1, len(insts)) + self.assertEquals("GIRTON", insts[0].instid) + self.assertEquals("38999", insts[0].attributes[0].value) + + def test_inst_lql_search_count(self): + count = im.searchCount("inst: UIS", False, False, None) + self.assertEquals(1, count) + + count = im.searchCount("inst: CS", False, False, None) + self.assertEquals(0, count) + + count = im.searchCount("inst: CS", False, True, None) + self.assertEquals(1, count) + def test_get_inst_contact_rows(self): inst = im.getInst("CS", "contact_rows.jdInstid") contactRows = im.getContactRows("CS", "jdInstid") @@ -734,6 +837,34 @@ class IbisUnitTests(unittest.TestCase): conn.set_username("anonymous") conn.set_password("") + def test_modified_insts(self): + # Note: transactions 2..1047 are the same on Lookup and lookup-test + insts = im.modifiedInsts(491, 492, None, False, False, False, None) + + self.assertEquals(1, len(insts)) + self.assertEquals("AUT", insts[0].instid) + + insts = im.modifiedInsts(438, 439, None, False, False, False, None) + self.assertEquals(0, len(insts)) + + insts = im.modifiedInsts(438, 439, None, True, False, False, None) + self.assertEquals(1, len(insts)) + self.assertEquals("SPVSR04", insts[0].instid) + + insts = im.modifiedInsts(764, 765, "IUSCMED", False, False, False, None) + self.assertEquals(1, len(insts)) + self.assertEquals("IUSCMED", insts[0].instid) + + insts = im.modifiedInsts(764, 765, "IUSCMED2", False, False, False, None) + self.assertEquals(0, len(insts)) + + insts = im.modifiedInsts(45, 46, None, False, False, False, None) + self.assertEquals(0, len(insts)) + + insts = im.modifiedInsts(45, 46, None, False, True, False, None) + self.assertEquals(1, len(insts)) + self.assertEquals("Clare Hall", insts[0].name) + # -------------------------------------------------------------------- # Group tests. # -------------------------------------------------------------------- @@ -787,7 +918,7 @@ class IbisUnitTests(unittest.TestCase): if person.identifier.scheme == "crsid" and\ person.identifier.value == "dar54": self.assertEquals("Dr D.A. Rasheed", person.registeredName) - found = True; + found = True self.assertTrue(found) def test_get_group_insts(self): @@ -829,6 +960,33 @@ class IbisUnitTests(unittest.TestCase): count = gm.searchCount("maths editors") self.assertEqual(6, count) + def test_group_lql_search(self): + groups = gm.search("group: title='Editors group for \"UIS\"'", + False, False, 0, 100, None, None) + self.assertEquals("uis-editors", groups[0].name) + + groups = gm.search("group: uistest-members", False, False, + 0, 1, None, "all_members") + self.assertEquals(1, len(groups)) + self.assertEquals("uistest-members", groups[0].name) + self.assertTrue(len(groups[0].members) > 10) + self.assertEquals("abc123", groups[0].members[0].identifier.value) + + groups = gm.search("group: biotec-editors", False, False, + 0, 1, None, None) + self.assertEquals(0, len(groups)) + + groups = gm.search("group: biotec-editors", False, True, + 0, 1, None, None) + self.assertEquals(1, len(groups)) + + def test_group_lql_search_count(self): + count = gm.searchCount("group: biotec-editors", False, False) + self.assertEquals(0, count) + + count = gm.searchCount("group: biotec-editors", False, True) + self.assertEquals(1, count) + def test_edit_group_members(self): if not run_edit_tests: return @@ -882,6 +1040,37 @@ class IbisUnitTests(unittest.TestCase): conn.set_username("anonymous") conn.set_password("") + def test_modified_groups(self): + # Note: transactions 2..1047 are the same on Lookup and lookup-test + groups = gm.modifiedGroups(492, 493, None, False, False, None) + + self.assertEquals(1, len(groups)) + self.assertEquals("100426", groups[0].groupid) + self.assertEquals("maths-intakes-editors", groups[0].name) + + groups = gm.modifiedGroups(487, 488, None, False, False, None) + self.assertEquals(0, len(groups)) + + groups = gm.modifiedGroups(487, 488, None, True, False, None) + self.assertEquals(1, len(groups)) + self.assertEquals("100855", groups[0].groupid) + self.assertEquals("cstest-foofoo", groups[0].name) + + groups = gm.modifiedGroups(743, 744, "100259", False, False, None) + self.assertEquals(1, len(groups)) + self.assertEquals("100259", groups[0].groupid) + self.assertEquals("biol-managers", groups[0].name) + + groups = gm.modifiedGroups(743, 744, "biol-managers", False, False, None) + self.assertEquals(1, len(groups)) + self.assertEquals("100259", groups[0].groupid) + self.assertEquals("biol-managers", groups[0].name) + + groups = gm.modifiedGroups(743, 744, "100260", False, False, None) + self.assertEquals(0, len(groups)) + groups = gm.modifiedGroups(743, 744, "biol-editors", False, False, None) + self.assertEquals(0, len(groups)) + if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(IbisUnitTests) unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/src/python3/ibisclient/methods.py b/src/python3/ibisclient/methods.py index 7c37913..556fe0f 100644 --- a/src/python3/ibisclient/methods.py +++ b/src/python3/ibisclient/methods.py @@ -36,6 +36,31 @@ class IbisMethods: def __init__(self, conn): self.conn = conn + def getLastTransactionId(self): + """ + Get the ID of the last (most recent) transaction. + + A transaction represents an edit made to data in Lookup. Each + transaction is assigned a unique, sequential, numeric ID. Thus + this last transaction ID will increase each time some data in + Lookup is changed. + + ``[ HTTP: GET /api/v1/last-transaction ]`` + + **Returns** + long + The ID of the latest transaction. + """ + path = "api/v1/last-transaction" + path_params = {} + query_params = {} + form_params = {} + result = self.conn.invoke_method("GET", path, path_params, + query_params, form_params) + if result.error: + raise IbisException(result.error) + return int(result.value) + def getVersion(self): """ Get the current API version number. @@ -208,6 +233,78 @@ class GroupMethods: raise IbisException(result.error) return result.groups + def modifiedGroups(self, + minTxId, + maxTxId, + groupids=None, + includeCancelled=None, + membershipChanges=None, + fetch=None): + """ + Find all groups modified between the specified pair of transactions. + + The transaction IDs specified should be the IDs from two different + requests for the last (most recent) transaction ID, made at different + times, that returned different values, indicating that some Lookup + data was modified in the period between the two requests. This method + then determines which (if any) groups were affected. + + By default, only a few basic details about each group are returned, + but the optional `fetch` parameter may be used to fetch + additional attributes or references. + + .. note:: + All data returned reflects the latest available data about each + group. It is not possible to query for old data, or more detailed + information about the specific changes made. + + ``[ HTTP: GET /api/v1/group/modified-groups?minTxId=...&maxTxId=... ]`` + + **Parameters** + `minTxId` : long + [required] Include modifications made in transactions + after (but not including) this one. + + `maxTxId` : long + [required] Include modifications made in transactions + up to and including this one. + + `groupids` : str + [optional] Only include groups with IDs or names in + this list. By default, all modified groups will be included. + + `includeCancelled` : bool + [optional] Include cancelled groups. By + default, cancelled groups are excluded. + + `membershipChanges` : bool + [optional] Include groups whose members have + changed. By default, changes to group memberships are not taken into + consideration. + + `fetch` : str + [optional] A comma-separated list of any additional + attributes or references to fetch. + + **Returns** + list of :any:`IbisGroup` + The modified groups (in groupid order). + """ + path = "api/v1/group/modified-groups" + path_params = {} + query_params = {"minTxId": minTxId, + "maxTxId": maxTxId, + "groupids": groupids, + "includeCancelled": includeCancelled, + "membershipChanges": membershipChanges, + "fetch": fetch} + form_params = {} + result = self.conn.invoke_method("GET", path, path_params, + query_params, form_params) + if result.error: + raise IbisException(result.error) + return result.groups + def search(self, query, approxMatches=None, @@ -743,6 +840,86 @@ class InstitutionMethods: raise IbisException(result.error) return result.institutions + def modifiedInsts(self, + minTxId, + maxTxId, + instids=None, + includeCancelled=None, + contactRowChanges=None, + membershipChanges=None, + fetch=None): + """ + Find all institutions modified between the specified pair of + transactions. + + The transaction IDs specified should be the IDs from two different + requests for the last (most recent) transaction ID, made at different + times, that returned different values, indicating that some Lookup + data was modified in the period between the two requests. This method + then determines which (if any) institutions were affected. + + By default, only a few basic details about each institution are + returned, but the optional `fetch` parameter may be used + to fetch additional attributes or references. + + .. note:: + All data returned reflects the latest available data about each + institution. It is not possible to query for old data, or more + detailed information about the specific changes made. + + ``[ HTTP: GET /api/v1/inst/modified-insts?minTxId=...&maxTxId=... ]`` + + **Parameters** + `minTxId` : long + [required] Include modifications made in transactions + after (but not including) this one. + + `maxTxId` : long + [required] Include modifications made in transactions + up to and including this one. + + `instids` : str + [optional] Only include institutions with instids in + this list. By default, all modified institutions will be included. + + `includeCancelled` : bool + [optional] Include cancelled institutions. By + default, cancelled institutions are excluded. + + `contactRowChanges` : bool + [optional] Include institutions whose contact + rows have changed. By default, changes to institution contact rows are + not taken into consideration. + + `membershipChanges` : bool + [optional] Include institutions whose members + have changed. By default, changes to institutional memberships are not + taken into consideration. + + `fetch` : str + [optional] A comma-separated list of any additional + attributes or references to fetch. + + **Returns** + list of :any:`IbisInstitution` + The modified institutions (in instid order). + """ + path = "api/v1/inst/modified-insts" + path_params = {} + query_params = {"minTxId": minTxId, + "maxTxId": maxTxId, + "instids": instids, + "includeCancelled": includeCancelled, + "contactRowChanges": contactRowChanges, + "membershipChanges": membershipChanges, + "fetch": fetch} + form_params = {} + result = self.conn.invoke_method("GET", path, path_params, + query_params, form_params) + if result.error: + raise IbisException(result.error) + return result.institutions + def search(self, query, approxMatches=None, @@ -1485,6 +1662,87 @@ class PersonMethods: raise IbisException(result.error) return result.people + def modifiedPeople(self, + minTxId, + maxTxId, + crsids=None, + includeCancelled=None, + membershipChanges=None, + instNameChanges=None, + fetch=None): + """ + Find all people modified between the specified pair of transactions. + + The transaction IDs specified should be the IDs from two different + requests for the last (most recent) transaction ID, made at different + times, that returned different values, indicating that some Lookup + data was modified in the period between the two requests. This method + then determines which (if any) people were affected. + + By default, only a few basic details about each person are returned, + but the optional `fetch` parameter may be used to fetch + additional attributes or references. + + .. note:: + All data returned reflects the latest available data about each + person. It is not possible to query for old data, or more detailed + information about the specific changes made. + + ``[ HTTP: GET /api/v1/person/modified-people?minTxId=...&maxTxId=... ]`` + + **Parameters** + `minTxId` : long + [required] Include modifications made in transactions + after (but not including) this one. + + `maxTxId` : long + [required] Include modifications made in transactions + up to and including this one. + + `crsids` : str + [optional] Only include people with identifiers in this + list. By default, all modified people will be included. + + `includeCancelled` : bool + [optional] Include cancelled people (people + who are no longer members of the University). By default, cancelled + people are excluded. + + `membershipChanges` : bool + [optional] Include people whose group or + institutional memberships have changed. By default, only people whose + attributes have been directly modified are included. + + `instNameChanges` : bool + [optional] Include people who are members of + instituions whose names have changed. This will also cause people + whose group or institutional memberships have changed to be included. + By default, changes to institution names do not propagate to people. + + `fetch` : str + [optional] A comma-separated list of any additional + attributes or references to fetch. + + **Returns** + list of :any:`IbisPerson` + The modified people (in identifier order). + """ + path = "api/v1/person/modified-people" + path_params = {} + query_params = {"minTxId": minTxId, + "maxTxId": maxTxId, + "crsids": crsids, + "includeCancelled": includeCancelled, + "membershipChanges": membershipChanges, + "instNameChanges": instNameChanges, + "fetch": fetch} + form_params = {} + result = self.conn.invoke_method("GET", path, path_params, + query_params, form_params) + if result.error: + raise IbisException(result.error) + return result.people + def search(self, query, approxMatches=None, diff --git a/src/python3/test/unittests.py b/src/python3/test/unittests.py index f2e19bb..f56c59d 100644 --- a/src/python3/test/unittests.py +++ b/src/python3/test/unittests.py @@ -22,6 +22,7 @@ # -------------------------------------------------------------------------- from datetime import date +import re import unittest import urllib.request @@ -43,6 +44,7 @@ run_edit_tests = False # Globals initialised once and re-used in each test conn = None +m = None pm = None im = None gm = None @@ -50,7 +52,7 @@ initialised = False class IbisUnitTests(unittest.TestCase): def setUp(self): - global conn, pm, im, gm, initialised + global conn, m, pm, im, gm, initialised if not initialised: if local: @@ -58,11 +60,25 @@ class IbisUnitTests(unittest.TestCase): else: conn = createTestConnection() + m = IbisMethods(conn) pm = PersonMethods(conn) im = InstitutionMethods(conn) gm = GroupMethods(conn) initialised = True + # -------------------------------------------------------------------- + # Ibis tests. + # -------------------------------------------------------------------- + + def test_get_version(self): + version = m.getVersion() + self.assertIsNotNone(version) + self.assertTrue(re.match("^[0-9]+[.][0-9]+$", version)) + + def test_get_last_transaction_id(self): + lastTransactionId = m.getLastTransactionId() + self.assertTrue(lastTransactionId > 900000) + # -------------------------------------------------------------------- # Person tests. # -------------------------------------------------------------------- @@ -72,6 +88,22 @@ class IbisUnitTests(unittest.TestCase): self.assertTrue(len(schemes) > 10) self.assertEqual("displayName", schemes[0].schemeid) + def test_all_people(self): + people = pm.allPeople(False, None, 10, None) + + self.assertEquals(10, len(people)) + self.assertEquals("aa", people[0].identifier.value[0:2]) + + people = pm.allPeople(False, "dar17", 10, None) + self.assertEquals(10, len(people)) + self.assertTrue(people[0].identifier.value > "dar17") + + id8 = people[8].identifier.value + id9 = people[9].identifier.value + people = pm.allPeople(False, id8, 10, None) + self.assertEquals(10, len(people)) + self.assertEquals(id9, people[0].identifier.value) + def test_no_such_person(self): person = pm.getPerson("crsid", "dar1734toolong") self.assertIsNone(person) @@ -99,9 +131,9 @@ class IbisUnitTests(unittest.TestCase): def test_get_person_attributes(self): attrs = pm.getAttributes("crsid", "dar17", "email,title") - self.assertEqual("title", attrs[0].scheme); - self.assertEqual("Database administrator and developer", attrs[0].value); - self.assertEqual("email", attrs[1].scheme); + self.assertEqual("title", attrs[0].scheme) + self.assertEqual("Database administrator and developer", attrs[0].value) + self.assertEqual("email", attrs[1].scheme) attr = pm.getAttribute("crsid", "dar17", attrs[1].attrid) self.assertEqual(attrs[1].scheme, attr.scheme) @@ -152,6 +184,32 @@ class IbisUnitTests(unittest.TestCase): count = pm.searchCount("j smith", False, False) self.assertTrue(count > 10) + def test_person_lql_search(self): + people = pm.search("person: in inst(uis) and surname=Rasheed", False, False, + None, None, 0, 100, None, "title") + self.assertEquals(1, len(people)) + self.assertEquals("dar17", people[0].identifier.value) + self.assertEquals("Database administrator and developer", people[0].attributes[0].value) + + people = pm.search("person: dar54", False, False, + None, None, 0, 100, None, None) + self.assertEquals(0, len(people)) + + people = pm.search("person: dar54", False, True, + None, None, 0, 100, None, None) + self.assertEquals(1, len(people)) + self.assertEquals("dar54", people[0].identifier.value) + + def test_person_lql_search_count(self): + count = pm.searchCount("person: dar17", False, False, None, None) + self.assertEquals(1, count) + + count = pm.searchCount("person: dar54", False, False, None, None) + self.assertEquals(0, count) + + count = pm.searchCount("person: dar54", False, True, None, None) + self.assertEquals(1, count) + def test_is_person_member_of_inst(self): self.assertTrue(pm.isMemberOfInst("crsid", "dar17", "UIS")) self.assertFalse(pm.isMemberOfInst("crsid", "dar17", "ENG")) @@ -391,6 +449,30 @@ class IbisUnitTests(unittest.TestCase): conn.set_username("anonymous") conn.set_password("") + def test_modified_people(self): + # Note: transactions 2..1047 are the same on Lookup and lookup-test + people = pm.modifiedPeople(937, 938, None, False, False, False, None) + self.assertEquals(1, len(people)) + self.assertEquals("v4500", people[0].identifier.value) + + people = pm.modifiedPeople(752, 753, None, False, False, False, None) + self.assertEquals(0, len(people)) + + people = pm.modifiedPeople(752, 753, None, True, False, False, None) + self.assertEquals(2, len(people)) + self.assertEquals("cr10001", people[0].identifier.value) + self.assertEquals("gar34", people[1].identifier.value) + + people = pm.modifiedPeople(752, 753, "cr10001", False, False, False, None) + self.assertEquals(0, len(people)) + + people = pm.modifiedPeople(752, 753, "cr10001", True, False, False, None) + self.assertEquals(1, len(people)) + self.assertEquals("cr10001", people[0].identifier.value) + + people = pm.modifiedPeople(752, 753, "cr10002", True, False, False, None) + self.assertEquals(0, len(people)) + # -------------------------------------------------------------------- # Institution tests. # -------------------------------------------------------------------- @@ -426,9 +508,9 @@ class IbisUnitTests(unittest.TestCase): def test_get_inst_attributes(self): attrs = im.getAttributes("CS", "acronym,email") - self.assertEqual("acronym", attrs[0].scheme); - self.assertEqual("UCS", attrs[0].value); - self.assertEqual("email", attrs[1].scheme); + self.assertEqual("acronym", attrs[0].scheme) + self.assertEqual("UCS", attrs[0].value) + self.assertEqual("email", attrs[1].scheme) attr = im.getAttribute("CS", attrs[0].attrid) self.assertEqual(attrs[0].scheme, attr.scheme) @@ -549,6 +631,27 @@ class IbisUnitTests(unittest.TestCase): count = im.searchCount("computing") self.assertTrue(count > 5) + def test_inst_lql_search(self): + insts = im.search("inst: parent of (uistest)", False, False, + None, 0, 100, None, None) + self.assertEquals("UIS", insts[0].instid) + + insts = im.search("inst: address ~ CB3 0JG", False, False, + None, 0, 100, None, "phone_numbers") + self.assertEquals(1, len(insts)) + self.assertEquals("GIRTON", insts[0].instid) + self.assertEquals("38999", insts[0].attributes[0].value) + + def test_inst_lql_search_count(self): + count = im.searchCount("inst: UIS", False, False, None) + self.assertEquals(1, count) + + count = im.searchCount("inst: CS", False, False, None) + self.assertEquals(0, count) + + count = im.searchCount("inst: CS", False, True, None) + self.assertEquals(1, count) + def test_get_inst_contact_rows(self): inst = im.getInst("CS", "contact_rows.jdInstid") contactRows = im.getContactRows("CS", "jdInstid") @@ -734,6 +837,34 @@ class IbisUnitTests(unittest.TestCase): conn.set_username("anonymous") conn.set_password("") + def test_modified_insts(self): + # Note: transactions 2..1047 are the same on Lookup and lookup-test + insts = im.modifiedInsts(491, 492, None, False, False, False, None) + + self.assertEquals(1, len(insts)) + self.assertEquals("AUT", insts[0].instid) + + insts = im.modifiedInsts(438, 439, None, False, False, False, None) + self.assertEquals(0, len(insts)) + + insts = im.modifiedInsts(438, 439, None, True, False, False, None) + self.assertEquals(1, len(insts)) + self.assertEquals("SPVSR04", insts[0].instid) + + insts = im.modifiedInsts(764, 765, "IUSCMED", False, False, False, None) + self.assertEquals(1, len(insts)) + self.assertEquals("IUSCMED", insts[0].instid) + + insts = im.modifiedInsts(764, 765, "IUSCMED2", False, False, False, None) + self.assertEquals(0, len(insts)) + + insts = im.modifiedInsts(45, 46, None, False, False, False, None) + self.assertEquals(0, len(insts)) + + insts = im.modifiedInsts(45, 46, None, False, True, False, None) + self.assertEquals(1, len(insts)) + self.assertEquals("Clare Hall", insts[0].name) + # -------------------------------------------------------------------- # Group tests. # -------------------------------------------------------------------- @@ -787,7 +918,7 @@ class IbisUnitTests(unittest.TestCase): if person.identifier.scheme == "crsid" and\ person.identifier.value == "dar54": self.assertEquals("Dr D.A. Rasheed", person.registeredName) - found = True; + found = True self.assertTrue(found) def test_get_group_insts(self): @@ -829,6 +960,33 @@ class IbisUnitTests(unittest.TestCase): count = gm.searchCount("maths editors") self.assertEqual(6, count) + def test_group_lql_search(self): + groups = gm.search("group: title='Editors group for \"UIS\"'", + False, False, 0, 100, None, None) + self.assertEquals("uis-editors", groups[0].name) + + groups = gm.search("group: uistest-members", False, False, + 0, 1, None, "all_members") + self.assertEquals(1, len(groups)) + self.assertEquals("uistest-members", groups[0].name) + self.assertTrue(len(groups[0].members) > 10) + self.assertEquals("abc123", groups[0].members[0].identifier.value) + + groups = gm.search("group: biotec-editors", False, False, + 0, 1, None, None) + self.assertEquals(0, len(groups)) + + groups = gm.search("group: biotec-editors", False, True, + 0, 1, None, None) + self.assertEquals(1, len(groups)) + + def test_group_lql_search_count(self): + count = gm.searchCount("group: biotec-editors", False, False) + self.assertEquals(0, count) + + count = gm.searchCount("group: biotec-editors", False, True) + self.assertEquals(1, count) + def test_edit_group_members(self): if not run_edit_tests: return @@ -882,6 +1040,37 @@ class IbisUnitTests(unittest.TestCase): conn.set_username("anonymous") conn.set_password("") + def test_modified_groups(self): + # Note: transactions 2..1047 are the same on Lookup and lookup-test + groups = gm.modifiedGroups(492, 493, None, False, False, None) + + self.assertEquals(1, len(groups)) + self.assertEquals("100426", groups[0].groupid) + self.assertEquals("maths-intakes-editors", groups[0].name) + + groups = gm.modifiedGroups(487, 488, None, False, False, None) + self.assertEquals(0, len(groups)) + + groups = gm.modifiedGroups(487, 488, None, True, False, None) + self.assertEquals(1, len(groups)) + self.assertEquals("100855", groups[0].groupid) + self.assertEquals("cstest-foofoo", groups[0].name) + + groups = gm.modifiedGroups(743, 744, "100259", False, False, None) + self.assertEquals(1, len(groups)) + self.assertEquals("100259", groups[0].groupid) + self.assertEquals("biol-managers", groups[0].name) + + groups = gm.modifiedGroups(743, 744, "biol-managers", False, False, None) + self.assertEquals(1, len(groups)) + self.assertEquals("100259", groups[0].groupid) + self.assertEquals("biol-managers", groups[0].name) + + groups = gm.modifiedGroups(743, 744, "100260", False, False, None) + self.assertEquals(0, len(groups)) + groups = gm.modifiedGroups(743, 744, "biol-editors", False, False, None) + self.assertEquals(0, len(groups)) + if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(IbisUnitTests) unittest.TextTestRunner(verbosity=2).run(suite) -- GitLab