diff --git a/.gitignore b/.gitignore index 7ea4bdde..19120a93 100755 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ jtwitter.jar boblog bin doc +/.settings +/binlocal diff --git a/src/winterwell/jtwitter/Twitter.java b/src/winterwell/jtwitter/Twitter.java index cd1ea4ae..d0474978 100755 --- a/src/winterwell/jtwitter/Twitter.java +++ b/src/winterwell/jtwitter/Twitter.java @@ -847,7 +847,7 @@ public Twitter_Analytics analytics() { * @param vars * @return vars */ - private Map addStandardishParameters( + Map addStandardishParameters( Map vars) { if (sinceId != null) { vars.put("since_id", sinceId.toString()); @@ -1188,62 +1188,27 @@ public IHttpClient getHttpClient() { } /** - * @return your lists, ie. the one's you made. + * @deprecated use {@link Twitter_Lists#getLists(String)} or {@link Twitter_Lists#getLists(Long)} */ + @Deprecated public List getLists() { - return getLists(name); + return lists().getLists(name); } /** - * - Returns all lists the authenticating or specified user subscribes to, - including their own. - @param user can be null for the authenticating user. - @see #getLists(String) + * @deprecated use {@link Twitter_Lists#getListsAll(String)} or {@link Twitter_Lists#getListsAll(Long)} */ - public List getListsAll(User user) { - assert user!=null || http.canAuthenticate() : "No authenticating user"; - try { - String url = TWITTER_URL + "/lists/all.json"; - Map vars = user.screenName==null? - InternalUtils.asMap("user_id", user.id) - : InternalUtils.asMap("screen_name", user.screenName); - String listsJson = http.getPage(url, vars, http.canAuthenticate()); - JSONObject wrapper = new JSONObject(listsJson); - JSONArray jarr = (JSONArray) wrapper.get("lists"); - List lists = new ArrayList(); - for (int i = 0; i < jarr.length(); i++) { - JSONObject li = jarr.getJSONObject(i); - TwitterList twList = new TwitterList(li, this); - lists.add(twList); - } - return lists; - } catch (JSONException e) { - throw new TwitterException.Parsing(null, e); - } + @Deprecated + public List getListsAll(User user) { + return user.screenName==null? lists().getListsAll(user.id) : lists().getListsAll(user.screenName); } /** - * @param screenName - * @return the (first 20) lists created by the given user + * @deprecated use {@link Twitter_Lists#getLists(String)} or {@link Twitter_Lists#getLists(Long)} */ + @Deprecated public List getLists(String screenName) { - assert screenName != null; - try { - String url = TWITTER_URL + "/" + screenName + "/lists.json"; - String listsJson = http.getPage(url, null, true); - JSONObject wrapper = new JSONObject(listsJson); - JSONArray jarr = (JSONArray) wrapper.get("lists"); - List lists = new ArrayList(); - for (int i = 0; i < jarr.length(); i++) { - JSONObject li = jarr.getJSONObject(i); - TwitterList twList = new TwitterList(li, this); - lists.add(twList); - } - return lists; - } catch (JSONException e) { - throw new TwitterException.Parsing(null, e); - } + return lists().getLists(screenName); } /** @@ -1253,6 +1218,7 @@ public List getLists(String screenName) { * @return lists of which screenName is a member. NOTE: currently limited to * a maximum of 20 lists! */ + // TODO: move to Twitter_Lists! public List getListsContaining(String screenName, boolean filterToOwned) { assert screenName != null; @@ -1270,7 +1236,7 @@ public List getListsContaining(String screenName, List lists = new ArrayList(); for (int i = 0; i < jarr.length(); i++) { JSONObject li = jarr.getJSONObject(i); - TwitterList twList = new TwitterList(li, this); + TwitterList twList = new TwitterList(li); lists.add(twList); } return lists; @@ -1285,6 +1251,7 @@ public List getListsContaining(String screenName, * @return lists that you are a member of. Warning: currently limited to a * maximum of 20 results. */ + // TODO: move to Twitter_Lists! public List getListsContainingMe() { return getListsContaining(name, false); } @@ -1674,7 +1641,7 @@ public Status getStatus(String username) throws TwitterException { * @param authenticate * @return */ - private List getStatuses(final String url, Map var, + List getStatuses(final String url, Map var, boolean authenticate) { // Default: 1 page if (maxResults < 1) { @@ -2912,4 +2879,11 @@ public Twitter_Users users() { return new Twitter_Users(this); } + /** + * List and membership/subscription related API methods. + */ + public Twitter_Lists lists() { + return new Twitter_Lists(this); + } + } diff --git a/src/winterwell/jtwitter/TwitterEvent.java b/src/winterwell/jtwitter/TwitterEvent.java index 8adfdfff..74b876fe 100755 --- a/src/winterwell/jtwitter/TwitterEvent.java +++ b/src/winterwell/jtwitter/TwitterEvent.java @@ -68,7 +68,7 @@ public TwitterEvent(JSONObject jo, Twitter jtwit) throws JSONException { if (to == null) return; if (to.has("member_count")) { - targetObject = new TwitterList(to, jtwit); + targetObject = new TwitterList(to); } else { targetObject = to; } diff --git a/src/winterwell/jtwitter/TwitterList.java b/src/winterwell/jtwitter/TwitterList.java index e488372d..58e5dfb8 100755 --- a/src/winterwell/jtwitter/TwitterList.java +++ b/src/winterwell/jtwitter/TwitterList.java @@ -1,19 +1,14 @@ package winterwell.jtwitter; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.AbstractList; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; +import java.util.Collections; import java.util.List; -import java.util.Map; import winterwell.json.JSONArray; import winterwell.json.JSONException; import winterwell.json.JSONObject; -import winterwell.jtwitter.Twitter.IHttpClient; +//TODO: update this description /** * A Twitter list, which uses lazy-fetching of its members. *

@@ -34,278 +29,73 @@ * @author daniel * */ -public class TwitterList extends AbstractList { - - /** - * A lazy-loading list viewer. This will fetch details from Twitter when you - * call it's methods. This is for access to an existing list - it does NOT - * create a new list on Twitter. - * - * @param ownerScreenName - * - * @param owner - * .screenName The Twitter screen-name for the list's owner. - * @param slug - * The list's name. Technically the slug and the name needn't be - * the same, but they usually are. - * @param jtwit - * a JTwitter object (this must be able to authenticate). - * @throws Twitter.Exception.E404 - * if the list does not exist - */ - public static TwitterList get(String ownerScreenName, String slug, - Twitter jtwit) { - return new TwitterList(ownerScreenName, slug, jtwit); - } - - /** - * A lazy-loading list viewer. This will fetch details from Twitter when you - * call it's methods. This is for access to an existing list - it does NOT - * create a new list on Twitter. - * - * @param id - * @param jtwit - * a JTwitter object (this must be able to authenticate). - * @throws Twitter.Exception.E404 - * if the list does not exist - */ - public static TwitterList get(Number id, Twitter jtwit) { - return new TwitterList(id, jtwit); +public class TwitterList { + + static List getLists(final String listsJson) throws JSONException { + final JSONArray jarr; + if (listsJson.charAt(0) == '{') { + final JSONObject wrapper = new JSONObject(listsJson); + jarr = wrapper.getJSONArray("lists"); + } else + jarr = new JSONArray(listsJson); + if (jarr.length() == 0) + return Collections.emptyList(); + final List lists = new ArrayList(jarr.length()); + for (int i = 0; i < jarr.length(); i++) { + final JSONObject li = jarr.getJSONObject(i); + final TwitterList twList = new TwitterList(li); + lists.add(twList); + } + return lists; } - private boolean _private; + private final boolean _private; - /** - * cursor for paging through the members of the list - */ - private long cursor = -1; + private final String description; - private String description; + private final long id; - /** - * The same client as the JTwitter object used in the constructor. - */ - private final IHttpClient http; + private final int memberCount; - private Number id; - - private final Twitter jtwit; - - private int memberCount = -1; - - private String name; + private final String name; /** * never null (but may be a dummy object) */ - private User owner; - - private String slug; - - private int subscriberCount; - - private final List users = new ArrayList(); - - /** - * Used by {@link Twitter#getLists(String)} - * - * @param json - * @param jtwit - * @throws JSONException - */ - TwitterList(JSONObject json, Twitter jtwit) throws JSONException { - this.jtwit = jtwit; - this.http = jtwit.getHttpClient(); - init2(json); - } - - /** - * A lazy-loading list viewer. This will fetch some details here, but the - * list of members will be loaded from Twitter on demand (to minimise the - * API calls). This is for access to an existing list - it does NOT - * create a new list on Twitter. - * - * @see #TwitterList(String, Twitter, boolean, String) which creates new - * lists. - * - * @param owner - * .screenName The Twitter screen-name for the list's owner. - * @param slug - * The list's name. Technically the slug and the name needn't be - * the same, but they usually are. - * @param jtwit - * a JTwitter object (this must be able to authenticate). - * @throws Twitter.Exception.E404 - * if the list does not exist - * @deprecated Due to the potential for confusion with - * {@link #TwitterList(String, Twitter, boolean, String)} Use - * {@link #get(String, String, Twitter)} instead. - */ - @Deprecated - public TwitterList(String ownerScreenName, String slug, Twitter jtwit) { - assert ownerScreenName != null && slug != null && jtwit != null; - this.jtwit = jtwit; - this.owner = new User(ownerScreenName); // use a dummy here - this.name = slug; - this.slug = slug; - this.http = jtwit.getHttpClient(); - init(); - } + private final User owner; - /** - * CREATE a brand new Twitter list. Accounts are limited to 20 lists. - * - * @see #TwitterList(String, String, Twitter) which views existing lists. - * - * @param listName - * The list's name. - * @param jtwit - * a JTwitter object (this must be able to authenticate). - * @param description - * A description for this list. Can be null. - */ - public TwitterList(String listName, Twitter jtwit, boolean isPublic, - String description) { - assert listName != null && jtwit != null; - this.jtwit = jtwit; - String ownerScreenName = jtwit.getScreenName(); - assert ownerScreenName != null; - this.name = listName; - this.slug = listName; - this.http = jtwit.getHttpClient(); - // create! - String url = jtwit.TWITTER_URL + "/lists/create.json"; - Map vars = InternalUtils.asMap("name", listName, - "mode", isPublic ? "public" : "private", "description", - description); - String json = http.post(url, vars, true); - try { - JSONObject jobj = new JSONObject(json); - init2(jobj); - } catch (JSONException e) { - throw new TwitterException("Could not parse response: " + e); - } - } + private final String slug; - public TwitterList(Number id, Twitter jtwit) { - assert id != null && jtwit != null; - this.jtwit = jtwit; - this.id = id; - this.http = jtwit.getHttpClient(); - init(); - } + private final int subscriberCount; - /** - * Add a user to the list. List size is limited to 500 users. - * - * @return testing for membership could be slow, so this is usually true. - */ - @Override - public boolean add(User user) { - if (users.contains(user)) - return false; - String url = jtwit.TWITTER_URL + "/lists/members/create.json"; - Map map = getListVars(); - map.put("screen_name", user.screenName); - String json = http.post(url, map, true); - // adjust size - try { - JSONObject jobj = new JSONObject(json); - memberCount = jobj.getInt("member_count"); - // update local - users.add(user); - return true; - } catch (JSONException e) { - throw new TwitterException("Could not parse response: " + e); - } + TwitterList(final JSONObject jobj) throws JSONException { + this.memberCount = jobj.getInt("member_count"); + this.subscriberCount = jobj.getInt("subscriber_count"); + this.name = jobj.getString("name"); + this.slug = jobj.getString("slug"); + this.id = jobj.getLong("id"); + this._private = "private".equals(jobj.optString("mode")); + this.description = jobj.optString("description"); + final JSONObject user = jobj.getJSONObject("user"); + this.owner = new User(user, null); } - @Override - public boolean addAll(Collection newUsers) { - List newUsersList = new ArrayList(newUsers); - newUsersList.removeAll(users); - if (newUsersList.size() == 0) - return false; - String url = jtwit.TWITTER_URL + "/lists/members/create_all.json"; - Map map = getListVars(); - int batchSize = 100; - for (int i = 0; i < users.size(); i += batchSize) { - int last = i + batchSize; - String names = InternalUtils.join(newUsersList, i, last); - map.put("screen_name", names); - String json = http.post(url, map, true); - // adjust size - try { - JSONObject jobj = new JSONObject(json); - memberCount = jobj.getInt("member_count"); - } catch (JSONException e) { - throw new TwitterException("Could not parse response: " + e); - } - } - // error messages? - return true; + public long getId() { + return id; } - /** - * Delete this list! - * - * @throws TwitterException - * on failure - */ - public void delete() { - try { - String URL = jtwit.TWITTER_URL + "/" + owner.screenName + "/lists/" - + URLEncoder.encode(slug, "utf-8") + ".json?_method=DELETE"; - http.post(URL, null, http.canAuthenticate()); - } catch (UnsupportedEncodingException e) { - throw new TwitterException(e); - } + public int getMemberCount() { + return memberCount; } - @Override - public User get(int index) { - // pull from Twitter as needed - String url = jtwit.TWITTER_URL + "/lists/members.json"; - Map vars = getListVars(); - while (users.size() < index + 1 && cursor != 0) { - vars.put("cursor", Long.toString(cursor)); - String json = http.getPage(url, vars, true); - try { - JSONObject jobj = new JSONObject(json); - JSONArray jarr = (JSONArray) jobj.get("users"); - List users1page = User.getUsers(jarr.toString()); - users.addAll(users1page); - cursor = new Long(jobj.getString("next_cursor")); - } catch (JSONException e) { - throw new TwitterException("Could not parse user list" + e); - } - } - return users.get(index); + public String getSlug() { + return slug; } public String getDescription() { - init(); return description; } - /** - * @return vars identifying the list in question - */ - private Map getListVars() { - Map vars = new HashMap(); - if (id != null) { - vars.put("list_id", id); - return vars; - } - vars.put("owner_screen_name", owner.screenName); - vars.put("slug", slug); - return vars; - } - - public Number getId() { - return id; - } - public String getName() { return name; } @@ -314,142 +104,18 @@ public User getOwner() { return owner; } - /** - * Returns a list of statuses from this list. - * - * @return List a list of Status objects for the list - * @throws TwitterException - */ - // Added TG 3/31/10 - public List getStatuses() throws TwitterException { - try { - String jsonListStatuses = http.getPage( - jtwit.TWITTER_URL + "/" + owner.screenName + "/lists/" - + URLEncoder.encode(slug, "UTF-8") - + "/statuses.json", null, http.canAuthenticate()); - List msgs = Status.getStatuses(jsonListStatuses); - return msgs; - } catch (UnsupportedEncodingException e) { - throw new TwitterException(e); - } - } - public int getSubscriberCount() { - init(); return subscriberCount; } - /** - * @return users who follow this list. Currently this is just the first 20 - * users. TODO cursor support for more than 20 users. - */ - public List getSubscribers() { - String url = jtwit.TWITTER_URL + "/lists/subscribers.json"; - Map vars = getListVars(); - String json = http.getPage(url, vars, true); - try { - JSONObject jobj = new JSONObject(json); - JSONArray jsonUsers = jobj.getJSONArray("users"); - return User.getUsers2(jsonUsers); - } catch (JSONException e) { - throw new TwitterException("Could not parse response: " + e); - } - } - - /** - * Fetch list info from Twitter - */ - private void init() { - if (memberCount != -1) - return; - String url = jtwit.TWITTER_URL + "/lists/show.json"; - Map vars = getListVars(); - String json = http.getPage(url, vars, true); - try { - JSONObject jobj = new JSONObject(json); - init2(jobj); - } catch (JSONException e) { - throw new TwitterException("Could not parse response: " + e); - } - } - - private void init2(JSONObject jobj) throws JSONException { - // owner.screenName = ; - memberCount = jobj.getInt("member_count"); - subscriberCount = jobj.getInt("subscriber_count"); - name = jobj.getString("name"); - slug = jobj.getString("slug"); - id = jobj.getLong("id"); - _private = "private".equals(jobj.optString("mode")); - description = jobj.optString("description"); - JSONObject user = jobj.getJSONObject("user"); - owner = new User(user, null); - } - public boolean isPrivate() { - init(); return _private; } - /** - * Remove a user from the list. - * - * @return testing for membership could be slow, so this is always true. - */ - @Override - public boolean remove(Object o) { - try { - User user = (User) o; - String url = jtwit.TWITTER_URL + "/lists/members/destroy.json"; - Map map = getListVars(); - map.put("screen_name", user.screenName); - String json = http.post(url, map, true); - // adjust size - JSONObject jobj = new JSONObject(json); - memberCount = jobj.getInt("member_count"); - // update local - users.remove(user); - return true; - } catch (JSONException e) { - throw new TwitterException("Could not parse response: " + e); - } - } - - public void setDescription(String description) { - String url = jtwit.TWITTER_URL + "/lists/update.json"; - Map vars = getListVars(); - vars.put("description", description); - String json = http.getPage(url, vars, true); - try { - JSONObject jobj = new JSONObject(json); - init2(jobj); - } catch (JSONException e) { - throw new TwitterException("Could not parse response: " + e); - } - } - - public void setPrivate(boolean isPrivate) { - String url = jtwit.TWITTER_URL + "/lists/update.json"; - Map vars = getListVars(); - vars.put("mode", isPrivate ? "private" : "public"); - String json = http.getPage(url, vars, true); - try { - JSONObject jobj = new JSONObject(json); - init2(jobj); - } catch (JSONException e) { - throw new TwitterException("Could not parse response: " + e); - } - } - - @Override - public int size() { - init(); - return memberCount; - } - @Override public String toString() { return getClass().getSimpleName() + "[" + owner + "." + name + "]"; } } + diff --git a/src/winterwell/jtwitter/Twitter_Lists.java b/src/winterwell/jtwitter/Twitter_Lists.java new file mode 100644 index 00000000..b3fdfd99 --- /dev/null +++ b/src/winterwell/jtwitter/Twitter_Lists.java @@ -0,0 +1,352 @@ +package winterwell.jtwitter; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import winterwell.json.JSONArray; +import winterwell.json.JSONException; +import winterwell.json.JSONObject; +import winterwell.jtwitter.Twitter.IHttpClient; + +/** + * API calls relating to twitter lists and memberships/subscriptions.
+ * TODO: work in progress, move the rest of the methods from {@link Twitter} related to lists to this class! + * @author azeef + */ +public class Twitter_Lists { + + private final Twitter jtwit; + private final IHttpClient http; + + Twitter_Lists(final Twitter jtwit) { + this.jtwit = jtwit; + this.http = jtwit.getHttpClient(); + } + + // GET METHODS ///////////////////////////////////////////////////////// + + /** + * gets the lists the user identified by the {@code userId} owns + * @deprecated use {@link #getListsAll(Long)} since version 1.1 twitter no longer supports getting only the list the user is subscribed to... + */ + @Deprecated + public List getLists(final Long userId) { + return getListsAll(userId); + } + + /** + * gets the lists the user identified by the {@code screenName} owns + * @deprecated use {@link #getListsAll(String)} since version 1.1 twitter no longer supports getting only the list the user is subscribed to... + */ + @Deprecated + public List getLists(final String screenName) { + return getListsAll(screenName); + } + + /** gets all the lists the user identified by the {@code userId} subscribes to */ + public List getListsAll(final Long userId) { + final String url = jtwit.TWITTER_URL + (isAPI11(jtwit) ? "/lists/list.json" : "/lists.json"); + final Map vars = InternalUtils.asMap("user_id", userId.toString()); + return getTwitterLists(url, vars); + } + + /** gets the lists the user identified by the {@code screenName} subscribes to */ + public List getListsAll(final String screenName) { + final String url = jtwit.TWITTER_URL + (isAPI11(jtwit) ? "/lists/list.json" : "/lists.json"); + final Map vars = InternalUtils.asMap("screen_name", screenName); + return getTwitterLists(url, vars); + } + + /** + * returns the list members for the list identified by the {@code listId} + *

+ * WARNING: twitter returns members in batches of 20, so this method can call twitter up to 25 times (500 max list size) + *

+ */ + public List getListMembers(final Long listId) { + final String url = jtwit.TWITTER_URL + "/lists/members.json"; + final Map vars = getListVars(listId); + long cursor = -1; + final List users = new LinkedList(); + while (cursor != 0) { + vars.put("cursor", Long.toString(cursor)); + final String json = http.getPage(url, vars, true); + try { + final JSONObject jobj = new JSONObject(json); + final JSONArray jarr = jobj.getJSONArray("users"); + final List users1page = User.getUsers2(jarr); + users.addAll(users1page); + cursor = jobj.getLong("next_cursor"); + } catch (final JSONException e) { + throw new TwitterException.Parsing("Could not parse user list", e); + } + } + return users; + } + + /** + * returns the subscribers to the list identified by the {@code listId} + *

+ * WARNING: twitter returns subscribers in batches of 20, so this method can call twitter a lot of times! + *

+ */ + public List getListSubscribers(final Long listId) { + final String url = jtwit.TWITTER_URL + "/lists/subscribers.json"; + final Map vars = getListVars(listId); + long cursor = -1; + final List users = new LinkedList(); + while (cursor != 0) { + vars.put("cursor", Long.toString(cursor)); + final String json = http.getPage(url, vars, true); + try { + final JSONObject jobj = new JSONObject(json); + final JSONArray jarr = jobj.getJSONArray("users"); + final List users1page = User.getUsers2(jarr); + users.addAll(users1page); + cursor = jobj.getLong("next_cursor"); + } catch (final JSONException e) { + throw new TwitterException.Parsing("Could not parse user list", e); + } + } + return users; + } + + /** + * returns the timeline for the list identified by the {@code listId}; all standard parameters for loading timelines apply, so + * {@link Twitter#setCount(Integer)}, {@link Twitter#setIncludeRTs(boolean)}, {@link Twitter#setIncludeTweetEntities(boolean)}, + * {@link Twitter#setMaxResults(int)}, {@link Twitter#setSinceId(Number)} and {@link Twitter#setUntilId(Number)} can all be called before + * calling this method to influence the tweets fetched + */ + public List getListTimeline(final Long listId) { + final Map vars = getListVars(listId); + jtwit.addStandardishParameters(vars); + return jtwit.getStatuses(jtwit.TWITTER_URL + "/lists/statuses.json", vars, true); // getting statuses for a twitter list requires authentication + } + + /** retrieves the list identified by the {@code listId} */ + public TwitterList show(final Long listId) { + final String url = jtwit.TWITTER_URL + "/lists/show.json"; + final Map vars = getListVars(listId); + return getTwitterList(url, vars); + } + + /** retrieves the list identified by the {@code slug} and {@code ownerScreenName} */ + public TwitterList show(final String slug, String ownerScreenName) { + final String url = jtwit.TWITTER_URL + "/lists/show.json"; + final Map vars = getListVars(slug, ownerScreenName, null); + return getTwitterList(url, vars); + } + + /** retrieves the list identified by the {@code slug} and {@code ownerId} */ + public TwitterList show(final String slug, long ownerId) { + final String url = jtwit.TWITTER_URL + "/lists/show.json"; + final Map vars = getListVars(slug, null, ownerId); + return getTwitterList(url, vars); + } + + // POST METHODS //////////////////////////////////////////////////////// + + /** + * updates the description for the list identified by the {@code listId}; the authenticated user should own the list + */ + public TwitterList setDescription(final Long listId, final String description) { + final String url = jtwit.TWITTER_URL + "/lists/update.json"; + final Map vars = getListVars(listId); + vars.put("description", description); + return postTwitterList(url, vars); + } + + /** + * sets the list identified by the {@code listId} to private or public, depending on the value of {@code isPrivate}; the authenticated user + * should own the list + */ + public TwitterList setPrivate(final Long listId, final boolean isPrivate) { + final String url = jtwit.TWITTER_URL + "/lists/update.json"; + final Map vars = getListVars(listId); + vars.put("mode", isPrivate ? "private" : "public"); + return postTwitterList(url, vars); + } + + /** + * deletes the list identified by the {@code listId}; the authenticated user should own the list + * @return + */ + public TwitterList delete(final Long listId) { + final String url = jtwit.TWITTER_URL + "/lists/destroy.json"; + final Map vars = getListVars(listId); + return postTwitterList(url, vars); + } + + /** creates a new twitterlist for the authenticated user */ + public TwitterList create(final String listName, final boolean isPrivate, final String description) { + final String url = jtwit.TWITTER_URL + "/lists/create.json"; + final Map listVars = InternalUtils.asMap("name", listName, "mode", isPrivate ? "private" : "public", "description", description); + return postTwitterList(url, listVars); + } + + /** + * add a user identified by the {@code userId} to the list identified by the {@code listId}. the authenticated user should own the list and + * list size is limited to 500 users + */ + public TwitterList addMember(final Long listId, final Long userId) { + final String url = jtwit.TWITTER_URL + "/lists/members/create.json"; + final Map listVars = getListVars(listId); + listVars.put("user_id", userId.toString()); + return postTwitterList(url, listVars); + } + + /** + * add a user identified by the {@code screenName} to the list identified by the {@code listId}. the authenticated user should own the list and + * list size is limited to 500 users + */ + public TwitterList addMember(final Long listId, final String screenName) { + final String url = jtwit.TWITTER_URL + "/lists/members/create.json"; + final Map listVars = getListVars(listId); + listVars.put("screen_name", screenName); + return postTwitterList(url, listVars); + } + + /** + * adds all users identified by the {@code userIds} to the list identified by the {@code listId}. the authenticated user should own the list + * and list size is limited to 500 users. this method will call twitter with at most 100 users at a time. + */ + public TwitterList addAllById(final Long listId, final List userIds) { + final String url = jtwit.TWITTER_URL + "/lists/members/create_all.json"; + final Map listVars = getListVars(listId); + final int batchSize = 100; + TwitterList theList = null; + for (int i = 0; i < userIds.size(); i += batchSize) { + final String userIdsStr = InternalUtils.join(userIds, i, i + batchSize); + listVars.put("user_id", userIdsStr); + theList = postTwitterList(url, listVars); + } + return theList; + } + + /** + * adds all users identified by the {@code screenNames} to the list identified by the {@code listId}. the authenticated user should own the + * list and list size is limited to 500 users. this method will call twitter with at most 100 users at a time. + */ + public TwitterList addAllByScreenName(final Long listId, final List screenNames) { + final String url = jtwit.TWITTER_URL + "/lists/members/create_all.json"; + final Map listVars = getListVars(listId); + final int batchSize = 100; + TwitterList theList = null; + for (int i = 0; i < screenNames.size(); i += batchSize) { + final String screenNamesStr = InternalUtils.join(screenNames, i, i + batchSize); + listVars.put("screen_name", screenNamesStr); + theList = postTwitterList(url, listVars); + } + return theList; + } + + /** + * remove a user identified by the {@code userId} from the list identified by the {@code listId}. the authenticated user should own the list + */ + public TwitterList removeMember(final Long listId, final Long userId) { + final String url = jtwit.TWITTER_URL + "/lists/members/destroy.json"; + final Map map = getListVars(listId); + map.put("user_id", userId.toString()); + return postTwitterList(url, map); + + } + + /** + * remove a user identified by the {@code screenName} from the list identified by the {@code listId}. the authenticated user should own the + * list + */ + public TwitterList removeMember(final Long listId, final String screenName) { + final String url = jtwit.TWITTER_URL + "/lists/members/destroy.json"; + final Map map = getListVars(listId); + map.put("screen_name", screenName); + return postTwitterList(url, map); + } + + /** + * removes all users identified by the {@code userIds} from the list identified by the {@code listId}. the authenticated user should own the + * list. this method will call twitter with at most 100 users at a time. + */ + public TwitterList removeAllById(final Long listId, final List userIds) { + final String url = jtwit.TWITTER_URL + "/lists/members/destroy_all.json"; + final Map listVars = getListVars(listId); + final int batchSize = 100; + TwitterList theList = null; + for (int i = 0; i < userIds.size(); i += batchSize) { + final String userIdsStr = InternalUtils.join(userIds, i, i + batchSize); + listVars.put("user_id", userIdsStr); + theList = postTwitterList(url, listVars); + } + return theList; + } + + /** + * removes all users identified by the {@code userIds} from the list identified by the {@code listId}. the authenticated user should own the + * list. this method will call twitter with at most 100 users at a time. + */ + public TwitterList removeAllByScreenName(final Long listId, final List screenNames) { + final String url = jtwit.TWITTER_URL + "/lists/members/destroy_all.json"; + final Map listVars = getListVars(listId); + final int batchSize = 100; + TwitterList theList = null; + for (int i = 0; i < screenNames.size(); i += batchSize) { + final String screenNamesStr = InternalUtils.join(screenNames, i, i + batchSize); + listVars.put("screen_name", screenNamesStr); + theList = postTwitterList(url, listVars); + } + return theList; + } + + private List getTwitterLists(final String url, final Map vars) { + final String listsJson = http.getPage(url, vars, http.canAuthenticate()); + try { + return TwitterList.getLists(listsJson); + } catch (final JSONException e) { + throw new TwitterException.Parsing("Could not parse response", e); + } + } + + private Map getListVars(final Long listId) { + final Map vars = InternalUtils.asMap("list_id", listId); + return vars; + } + + private Map getListVars(final String listSlug, final String ownerScreenName, final Long ownerId) { + if (listSlug == null || (ownerScreenName == null && ownerId == null)) { + throw new IllegalArgumentException("both listSlug and one of ownerScreenName or ownerId need to be provided"); + } + if (ownerScreenName != null && ownerId != null) + throw new IllegalArgumentException("only one of ownerScreenName or ownerId can be provided"); + final Map vars = InternalUtils.asMap("slug", listSlug); + if (ownerScreenName != null) { + vars.put("owner_screen_name", ownerScreenName); + } else if (ownerId != null) { + vars.put("owner_id", Long.toString(ownerId.longValue())); + } + return vars; + } + + private TwitterList getTwitterList(final String url, final Map listVars) { + final String json = http.getPage(url, listVars, http.canAuthenticate()); + return toTwitterList(json); + } + + private TwitterList postTwitterList(final String url, final Map listVars) { + final String json = http.post(url, listVars, true); + return toTwitterList(json); + } + + private TwitterList toTwitterList(final String json) { + try { + final JSONObject jobj = new JSONObject(json); + return new TwitterList(jobj); + } catch (final JSONException e) { + throw new TwitterException.Parsing("Could not parse response", e); + } + } + + /** test if the twitter api we're talking to is the new v1.1 API; some endpoints are changed in that new api */ + private static boolean isAPI11(Twitter jtwit) { + return jtwit.TWITTER_URL.endsWith("1.1"); + } +} diff --git a/test/winterwell/jtwitter/TwitterListTest.java b/test/winterwell/jtwitter/TwitterListTest.java index 18b3d53b..a9231389 100755 --- a/test/winterwell/jtwitter/TwitterListTest.java +++ b/test/winterwell/jtwitter/TwitterListTest.java @@ -39,24 +39,16 @@ public static void main(String[] args) { public void testGetLists() { Twitter jtwit = TwitterTest.newTestTwitter(); - List lists = jtwit.getLists("tweetminster"); + List lists = jtwit.lists().getListsAll("tweetminster"); assert ! lists.isEmpty(); } public void testTwitterList() { Twitter jtwit = TwitterTest.newTestTwitter(); - TwitterList list = new TwitterList("tweetminster", "guardian", jtwit); - assert list.size() > 0; + TwitterList list = jtwit.lists().show("tweetminster", "guardian"); + assert list.getMemberCount() > 0; } - public void testGetInt() { - Twitter jtwit = TwitterTest.newTestTwitter(); - TwitterList list = new TwitterList("tweetminster", "guardian", jtwit); - User user0 = list.get(0); - User user25 = list.get(25); - assert user25 != null; - } - /** * WARNING: this deletes all the test users' lists!! */ @@ -64,55 +56,56 @@ public void testDelete() { Twitter jtwit = TwitterTest.newTestTwitter(); List myLists = jtwit.getLists(); for (TwitterList twitterList : myLists) { - twitterList.delete(); + // AZ: getLists now returns ALL lists the user is subscribed to, including his own, so need to test for ownership here... + if (twitterList.getOwner().getName().equals(TwitterTest.TEST_USER)) + jtwit.lists().delete(twitterList.getId()); } } public void testMakeList() { Twitter jtwit = TwitterTest.newTestTwitter(); int salt = new Random().nextInt(1000); - TwitterList list = new TwitterList("testlist"+salt, jtwit, - true, "This is a test of the JTwitter library"); - List ss = list.getStatuses(); + Twitter_Lists lists = jtwit.lists(); + TwitterList list = lists.create("testlist"+salt, true, "This is a test of the JTwitter library"); + List ss = lists.getListTimeline(list.getId()); assert ss != null; - list.delete(); + lists.delete(list.getId()); } public void testEditList() { Twitter jtwit = TwitterTest.newTestTwitter(); - List lists = jtwit.getLists(); - TwitterList list = - new TwitterList("testlist", jtwit, true, "test list"); // create -// new TwitterList(TwitterTest.TEST_USER, "testlist", jtwit); // access existing - list.add(new User("winterstein")); - assert list.size() > 0; + Twitter_Lists lists = jtwit.lists(); + TwitterList list = lists.create("testlist", true, "test list"); // create +// TwitterList list = lists.show(TwitterTest.TEST_USER, "testlist"); // access existing + list = lists.addMember(list.getId(), "winterstein"); + assert list.getMemberCount() > 0; } public void testAdd() { Twitter jtwit = TwitterTest.newTestTwitter(); + Twitter_Lists lists = jtwit.lists(); String sn = jtwit.getScreenName(); assert sn != null; TwitterList twitterList; try { - twitterList = TwitterList.get(sn, "just-added", jtwit); + twitterList = lists.show(sn, "just-added"); } catch (E404 e) { - twitterList = new TwitterList("just-added", jtwit, true, "list test"); + twitterList = lists.create("just-added", true, "list test"); } - twitterList.add(new User("apigee")); - twitterList.add(new User("docusign")); + twitterList = lists.addMember(twitterList.getId(), "apigee"); + twitterList = lists.addMember(twitterList.getId(), "docusign"); // fetch - TwitterList list2 = TwitterList.get(sn, "just-added", jtwit); - assert list2.size() > 0; + TwitterList list2 = lists.show(sn, "just-added"); + assert list2.getMemberCount() == twitterList.getMemberCount(); } public void testSubscribers() { Twitter jtwit = TwitterTest.newTestTwitter(); - TwitterList list = -// new TwitterList("testlist", jtwit, true, "test list"); - new TwitterList(TwitterTest.TEST_USER, "testlist", jtwit); - List subs = list.getSubscribers(); + Twitter_Lists lists = jtwit.lists(); + TwitterList list = lists.show(TwitterTest.TEST_USER, "testlist"); + List subs = lists.getListSubscribers(list.getId()); assert subs.size() > 0 : subs; - assert list.size() > 0 : list; + assert list.getMemberCount() > 0 : list; } }