From 2d4ef59f6847c2ff258821dd6a82e429cc6aa6a6 Mon Sep 17 00:00:00 2001 From: Luke Faraone Date: Wed, 30 Jan 2013 16:40:00 -0500 Subject: [PATCH] Fix InviteOnlyStreamTest to call public API Previously we made calls to the JSON api, which means that the API key was being ignored. (imported from commit 46d8d0e5ac7926e824f300fd846ec42bc939e2c0) --- zephyr/tests.py | 9 +++---- zephyr/views.py | 68 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/zephyr/tests.py b/zephyr/tests.py index 0077c3e62b..51e3a2f189 100644 --- a/zephyr/tests.py +++ b/zephyr/tests.py @@ -822,7 +822,7 @@ class SubscriptionAPITest(AuthedTestCase): streams_to_remove = random_streams[:1] # pick only one fake stream, to make checking the error message easy result = self.client.post("/json/subscriptions/remove", {"subscriptions": simplejson.dumps(streams_to_remove)}) - self.assert_json_error(result, "Stream %s does not exist" % (random_streams[0],)) + self.assert_json_error(result, "Stream(s) (%s) do not exist" % (random_streams[0],)) def helper_subscriptions_exists(self, stream, exists, subscribed): """ @@ -1371,13 +1371,12 @@ class InviteOnlyStreamTest(AuthedTestCase): 'invite_only': simplejson.dumps(invite_only)} post_data.update(extra_post_data) - result = self.client.post("/json/subscriptions/add", post_data) + result = self.client.post("/api/v1/subscriptions/add", post_data) return result def test_inviteonly(self): # Creating an invite-only stream is allowed email = 'hamlet@humbughq.com' - self.login(email) result = self.common_subscribe_to_stream(email, '["Saxony"]', invite_only=True) self.assert_json_success(result) @@ -1390,7 +1389,7 @@ class InviteOnlyStreamTest(AuthedTestCase): email = "othello@humbughq.com" self.login(email) result = self.common_subscribe_to_stream(email, '["Saxony"]') - self.assert_json_error(result, "Unable to join an invite-only stream") + self.assert_json_error(result, 'Unable to access invite-only stream (Saxony).') # Inviting another user to an invite-only stream is allowed email = 'hamlet@humbughq.com' @@ -1403,7 +1402,7 @@ class InviteOnlyStreamTest(AuthedTestCase): self.assertEqual(json["already_subscribed"], {}) # Make sure both users are subscribed to this stream - result = self.client.post("/json/get_subscribers", {'email':email, + result = self.client.post("/api/v1/get_subscribers", {'email':email, 'api-key': self.get_api_key(email), 'stream': 'Saxony'}) self.assert_json_success(result) diff --git a/zephyr/views.py b/zephyr/views.py index 2562e27dff..8e502e935f 100644 --- a/zephyr/views.py +++ b/zephyr/views.py @@ -49,6 +49,54 @@ from collections import defaultdict SERVER_GENERATION = int(time.time()) + +def list_to_streams(streams_raw, user_profile, autocreate=False, invite_only=False): + """Converts plaintext stream names to a list of Streams, validating input in the process + + For each stream name, we validate it to ensure it meets our requirements for a proper + stream name: that is, that it is shorter than 30 characters and passes valid_stream_name. + + We also ensure the stream is visible to the user_profile who made the request; a call + to list_to_streams will fail if one of the streams is invite_only and user_profile + is not already on the stream. + + This function in autocreate mode should be atomic: either an exception will be raised + during a precheck, or all the streams specified will have been created if applicable. + + @param streams_raw The list of stream names to process + @param user_profile The user for whom we are retreiving the streams + @param autocreate Whether we should create streams if they don't already exist + @param invite_only Whether newly created streams should have the invite_only bit set + """ + streams = [] + # Validate all streams, getting extant ones, then get-or-creating the rest. + stream_set = set(stream_name.strip() for stream_name in streams_raw) + rejects = [] + for stream_name in stream_set: + if len(stream_name) > 30: + raise JsonableError("Stream name (%s) too long." % (stream_name,)) + if not valid_stream_name(stream_name): + raise JsonableError("Invalid stream name (%s)." % (stream_name,)) + stream = get_stream(stream_name, user_profile.realm) + + if stream is None: + rejects.append(stream_name) + else: + streams.append(stream) + # Verify we can access the stream + if stream.invite_only and not subscribed_to_stream(user_profile, stream): + raise JsonableError("Unable to access invite-only stream (%s)." % stream.name) + if autocreate: + for stream_name in rejects: + stream, created = create_stream_if_needed(user_profile.realm, + stream_name, + invite_only=invite_only) + streams.append(stream) + elif rejects: + raise JsonableError("Stream(s) (%s) do not exist" % ", ".join(rejects)) + + return streams + def send_signup_message(sender, signups_stream, user_profile, internal=False): if internal: # When this is done using manage.py vs. the web interface @@ -897,12 +945,8 @@ def json_remove_subscriptions(request, user_profile): @has_request_variables def remove_subscriptions_backend(request, user_profile, streams_raw = POST("subscriptions", json_to_list)): - streams = [] - for stream_name in set(stream_name.strip() for stream_name in streams_raw): - stream = get_stream(stream_name, user_profile.realm) - if stream is None: - return json_error("Stream %s does not exist" % stream_name) - streams.append(stream) + + streams = list_to_streams(streams_raw, user_profile) result = dict(removed=[], not_subscribed=[]) for stream in streams: @@ -945,22 +989,18 @@ def add_subscriptions_backend(request, user_profile, else: subscribers = [user_profile] + streams = list_to_streams(streams_raw, user_profile, autocreate=True, invite_only=invite_only) private_streams = {} - result = dict(subscribed=defaultdict(list), already_subscribed=defaultdict(list)) - for stream_name in set(stream_names): - stream, created = create_stream_if_needed(user_profile.realm, stream_name, invite_only = invite_only) - # Users cannot subscribe themselves or other people to an invite-only - # stream they're not on. - if stream.invite_only and not created and not subscribed_to_stream(user_profile, stream): - return json_error("Unable to join an invite-only stream") + result = dict(subscribed=[], already_subscribed=[]) + result = dict(subscribed=defaultdict(list), already_subscribed=defaultdict(list)) + for stream in streams: for subscriber in subscribers: did_subscribe = do_add_subscription(subscriber, stream) if did_subscribe: result["subscribed"][subscriber.user.email].append(stream.name) else: result["already_subscribed"][subscriber.user.email].append(stream.name) - private_streams[stream.name] = stream.invite_only # Inform the user if someone else subscribed them to stuff