Skip to content

Commit 3cac635

Browse files
committed
first start
1 parent f5f1a38 commit 3cac635

7 files changed

Lines changed: 172 additions & 149 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ client = stream.connect('YOUR_API_KEY', 'API_KEY_SECRET')
2525
# Find your API keys here https://getstream.io/dashboard/
2626

2727
# Instantiate a feed object
28-
user_feed_1 = client.feed('user:1')
28+
user_feed_1 = client.feed('user', '1')
2929

3030
# Get activities from 5 to 10 (slow pagination)
3131
result = user_feed_1.get(limit=5, offset=5)
@@ -36,7 +36,7 @@ result = user_feed_1.get(limit=5, id_lt="e561de8f-00f1-11e4-b400-0cc47a024be0")
3636
activity_data = {'actor': 1, 'verb': 'tweet', 'object': 1, 'foreign_id': 'tweet:1'}
3737
activity_response = user_feed_1.add_activity(activity_data)
3838
# Create a bit more complex activity
39-
activity_data = {'actor': 1, 'verb': 'run', 'object': 1, 'foreign_id': 'run:1',
39+
activity_data = {'actor': 1, 'verb': 'run', 'object': 1, 'foreign_id': 'run', '1',
4040
'course': {'name': 'Golden Gate park', 'distance': 10},
4141
'participants': ['Thierry', 'Tommaso'],
4242
'started_at': datetime.datetime.now()
@@ -49,10 +49,10 @@ user_feed_1.remove("e561de8f-00f1-11e4-b400-0cc47a024be0")
4949
user_feed_1.remove(foreign_id='tweet:1')
5050

5151
# Follow another feed
52-
user_feed_1.follow('flat:42')
52+
user_feed_1.follow('flat', '42')
5353

5454
# Stop following another feed
55-
user_feed_1.unfollow('flat:42')
55+
user_feed_1.unfollow('flat', '42')
5656

5757
# List followers/following
5858
following = user_feed_1.following(offset=0, limit=2)
@@ -77,7 +77,7 @@ user_feed_1.add_activity(activity);
7777
# Generating tokens for client side usage
7878
token = user_feed_1.token
7979
# Javascript client side feed initialization
80-
# user1 = client.feed('user:1', '{{ token }}');
80+
# user1 = client.feed('user', '1', '{{ token }}');
8181
```
8282

8383
Docs are available on [GetStream.io](http://getstream.io/docs/).

stream/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,33 @@
22
import os
33

44
__author__ = 'Thierry Schellenbach'
5-
__copyright__ = 'Copyright 2012, Thierry Schellenbach'
5+
__copyright__ = 'Copyright 2014, Thierry Schellenbach'
66
__credits__ = ['Thierry Schellenbach, mellowmorning.com, @tschellenbach']
77
__license__ = 'BSD'
8-
__version__ = '1.1.1'
8+
__version__ = '1.2.0'
99
__maintainer__ = 'Thierry Schellenbach'
1010
__email__ = 'thierryschellenbach@gmail.com'
1111
__status__ = 'Production'
1212

1313

14-
def connect(api_key=None, api_secret=None, site_id=None):
14+
def connect(api_key=None, api_secret=None, app_id=None, version='v1.0', timeout=3.0):
1515
'''
1616
Returns a Client object
1717
1818
:param api_key: your api key or heroku url
1919
:param api_secret: the api secret
20-
:param site_id: the site id (used for listening to feed changes)
20+
:param app_id: the site id (used for listening to feed changes)
2121
'''
2222
from stream.client import StreamClient
2323
stream_url = os.environ.get('STREAM_URL')
2424
# support for the heroku STREAM_URL syntax
2525
if stream_url and not api_key:
2626
pattern = re.compile(
27-
'https\:\/\/(\w+)\:(\w+).*site=(\d+)', re.IGNORECASE)
27+
'https\:\/\/(\w+)\:(\w+).*app=(\d+)', re.IGNORECASE)
2828
result = pattern.match(stream_url)
2929
if result and len(result.groups()) == 3:
30-
api_key, api_secret, site_id = result.groups()
30+
api_key, api_secret, app_id = result.groups()
3131
else:
3232
raise ValueError('Invalid api key or heroku url')
3333

34-
return StreamClient(api_key, api_secret, site_id)
34+
return StreamClient(api_key, api_secret, app_id, version, timeout)

stream/client.py

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import logging
2-
import os
3-
import requests
41
from requests.adapters import HTTPAdapter
52
from stream import exceptions, serializer
63
from stream.signing import sign
7-
from stream.utils import validate_feed
4+
import logging
5+
import os
6+
import requests
87

98

109
logger = logging.getLogger(__name__)
@@ -13,7 +12,7 @@
1312
class StreamClient(object):
1413
base_url = 'https://getstream.io/api/'
1514

16-
def __init__(self, api_key, api_secret, site_id, base_url=None):
15+
def __init__(self, api_key, api_secret, site_id, version='v1.0', timeout=3.0, base_url=None):
1716
'''
1817
Initialize the client with the given api key and secret
1918
@@ -41,50 +40,57 @@ def __init__(self, api_key, api_secret, site_id, base_url=None):
4140
self.api_key = api_key
4241
self.api_secret = api_secret
4342
self.site_id = site_id
43+
self.version = version
44+
self.timeout = timeout
4445
if base_url is not None:
4546
self.base_url = base_url
4647
if os.environ.get('LOCAL'):
4748
self.base_url = 'http://localhost:8000/api/'
4849
self.session = requests.Session()
49-
self.session.mount(self.base_url, HTTPAdapter(max_retries=3))
50+
self.session.mount(self.base_url, HTTPAdapter(max_retries=0))
5051

51-
def feed(self, feed_id):
52+
def feed(self, feed_slug, user_id):
5253
'''
5354
Returns a Feed object
5455
5556
:param feed_id: the feed object
5657
'''
57-
validate_feed(feed_id)
5858
from stream.feed import Feed
5959

6060
# generate the token
61-
feed_together = feed_id.replace(':', '')
62-
token = sign(self.api_secret, feed_together)
61+
feed_id = '%s%s' % (feed_slug, user_id)
62+
token = sign(self.api_secret, feed_id)
6363

64-
return Feed(self, feed_id, token)
64+
return Feed(self, feed_slug, user_id, token)
6565

6666
def get_default_params(self):
6767
'''
6868
Returns the params with the API key present
6969
'''
7070
params = dict(api_key=self.api_key)
7171
return params
72-
73-
def _make_request(self, method, relative_url, authorization, params=None, data=None):
72+
73+
def get_full_url(self, relative_url):
74+
url = self.base_url + self.version + '/' + relative_url
75+
return url
76+
77+
def get_user_agent(self):
78+
from stream import __version__
79+
agent = 'stream-javascript-client-%s' % __version__
80+
return agent
81+
82+
def _make_request(self, method, relative_url, signature, params=None, data=None):
7483
params = params or {}
7584
data = data or {}
76-
7785
default_params = self.get_default_params()
7886
default_params.update(params)
79-
80-
headers = {'Authorization': authorization}
87+
headers = {'Authorization': signature}
8188
headers['Content-type'] = 'application/json'
82-
83-
url = self.base_url + relative_url
84-
89+
headers['User-Agent'] = self.get_user_agent()
90+
url = self.get_full_url(relative_url)
8591
serialized = serializer.dumps(data)
8692
response = method(url, data=serialized, headers=headers,
87-
params=default_params)
93+
params=default_params, timeout=self.timeout)
8894
logger.debug('stream api call %s, headers %s data %s',
8995
response.url, headers, data)
9096
result = serializer.loads(response.content)
@@ -102,7 +108,7 @@ def raise_exception(self, result, status_code):
102108
if exception_fields is not None:
103109
errors = []
104110
for field, errors in exception_fields.items():
105-
errors.append('Field "%s" errors: %s' %
111+
errors.append('Field "%s" errors: %s' %
106112
(field, repr(errors)))
107113
error_message = '\n'.join(errors)
108114
error_code = result.get('code')

stream/feed.py

Lines changed: 75 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,24 @@
33

44
class Feed(object):
55

6-
def __init__(self, client, feed_id, token):
6+
def __init__(self, client, feed_slug, user_id, token):
77
'''
88
Initializes the Feed class
99
1010
:param client: the api client
11-
:param feed_id: the feed id (string)
12-
13-
11+
:param feed_slug: the slug of the feed, ie user, flat, notification
12+
:param user_id: the id of the user
13+
:param token: the token
1414
'''
1515
self.client = client
16-
# TODO: rename feed_id to feed.id everywhere
17-
self.id = feed_id
18-
self.feed_id = feed_id
19-
self.feed_url = 'feed/%s/' % feed_id.replace(':', '/')
20-
self.feed_together = feed_id.replace(':', '')
16+
self.feed_slug = feed_slug
17+
self.user_id = user_id
18+
self.id = '%s:%s' % (feed_slug, user_id)
2119
self.token = token
22-
self.authorization = self.feed_together + ' ' + self.token
23-
24-
def add_to_signature(self, recipients):
25-
data = []
26-
for recipient in recipients:
27-
feed = self.client.feed(recipient)
28-
data.append("%s %s" % (recipient, feed.token))
29-
return data
20+
21+
self.feed_url = 'feed/%s/' % self.id.replace(':', '/')
22+
self.feed_together = self.id.replace(':', '')
23+
self.signature = self.feed_together + ' ' + self.token
3024

3125
def add_activity(self, activity_data):
3226
'''
@@ -44,7 +38,7 @@ def add_activity(self, activity_data):
4438
activity_data['to'] = self.add_to_signature(activity_data['to'])
4539

4640
result = self.client.post(
47-
self.feed_url, data=activity_data, authorization=self.authorization)
41+
self.feed_url, data=activity_data, signature=self.signature)
4842
return result
4943

5044
def add_activities(self, activity_list):
@@ -68,7 +62,7 @@ def add_activities(self, activity_list):
6862

6963
data = dict(activities=activity_list)
7064
result = self.client.post(
71-
self.feed_url, data=data, authorization=self.authorization)
65+
self.feed_url, data=data, signature=self.signature)
7266
return result
7367

7468
def remove_activity(self, activity_id=None, foreign_id=None):
@@ -87,70 +81,94 @@ def remove_activity(self, activity_id=None, foreign_id=None):
8781
if foreign_id is not None:
8882
params['foreign_id'] = '1'
8983
result = self.client.delete(
90-
url, authorization=self.authorization, params=params)
84+
url, signature=self.signature, params=params)
9185
return result
86+
87+
def get(self, **params):
88+
'''
89+
Get the activities in this feed
90+
91+
**Example**::
92+
93+
# fast pagination using id filtering
94+
feed.get(limit=10, id_lte=100292310)
9295
93-
def follow(self, target_feed):
96+
# slow pagination using offset
97+
feed.get(limit=10, offset=10)
98+
'''
99+
mark_read = params.get('mark_read')
100+
if isinstance(mark_read, (list, tuple)):
101+
params['mark_read'] = ','.join(mark_read)
102+
response = self.client.get(
103+
self.feed_url, params=params, signature=self.signature)
104+
return response
105+
106+
def follow(self, target_feed_slug, target_user_id):
94107
'''
95108
Follows the given feed
96109
97-
:param target_feed: the feed to follow, ie flat:3
110+
:param target_feed_slug: the slug of the target feed
111+
:param target_user_id: the user id
98112
'''
113+
target_feed_id = '%s:%s' % (target_feed_slug, target_user_id)
99114
url = self.feed_url + 'follows/'
100115
data = {
101-
'target': target_feed,
102-
'target_token': self.client.feed(target_feed).token
116+
'target': target_feed_id,
117+
'target_token': self.client.feed(target_feed_slug, target_user_id).token
103118
}
104119
response = self.client.post(
105-
url, data=data, authorization=self.authorization)
120+
url, data=data, signature=self.signature)
121+
return response
122+
123+
def unfollow(self, target_feed_slug, target_user_id):
124+
'''
125+
Unfollow the given feed
126+
'''
127+
target_feed_id = '%s:%s' % (target_feed_slug, target_user_id)
128+
url = self.feed_url + 'follows/%s/' % target_feed_id
129+
response = self.client.delete(url, signature=self.signature)
106130
return response
107131

108-
def followers(self, offset=0, limit=25):
132+
def followers(self, offset=0, limit=25, filter=None):
133+
'''
134+
Lists the followers for the given feed
135+
'''
136+
filter = filter is not None and ','.join(filter) or ''
109137
params = {
110138
'limit': limit,
111-
'offset': offset
139+
'offset': offset,
140+
'filter': filter
112141
}
113142
url = self.feed_url + 'followers/'
114143
response = self.client.get(
115-
url, params=params, authorization=self.authorization)
144+
url, params=params, signature=self.signature)
116145
return response
117146

118-
def following(self, offset=0, limit=25, feeds=None):
119-
feeds = feeds is not None and ','.join(feeds) or ''
147+
def following(self, offset=0, limit=25, filter=None):
148+
'''
149+
List the feeds which this feed is following
150+
'''
151+
filter = filter is not None and ','.join(filter) or ''
120152
params = {
121153
'offset': offset,
122154
'limit': limit,
123-
'filter': feeds
155+
'filter': filter
124156
}
125157
url = self.feed_url + 'follows/'
126158
response = self.client.get(
127-
url, params=params, authorization=self.authorization)
159+
url, params=params, signature=self.signature)
128160
return response
129161

130-
def unfollow(self, target_feed):
162+
def add_to_signature(self, recipients):
131163
'''
132-
Unfollow the given feed
164+
Takes a list of recipients such as ['user:1', 'user:2']
165+
and turns it into a list with the tokens included
166+
['user:1 token', 'user:2 token']
133167
'''
134-
validate_feed(target_feed)
135-
url = self.feed_url + 'follows/%s/' % target_feed
136-
response = self.client.delete(url, authorization=self.authorization)
137-
return response
138-
139-
def get(self, **params):
140-
'''
141-
Get the activities in this feed
142-
143-
**Example**::
144-
145-
# fast pagination using id filtering
146-
feed.get(limit=10, id_lte=100292310)
147-
148-
# slow pagination using offset
149-
feed.get(limit=10, offset=10)
150-
'''
151-
mark_read = params.get('mark_read')
152-
if isinstance(mark_read, (list, tuple)):
153-
params['mark_read'] = ','.join(mark_read)
154-
response = self.client.get(
155-
self.feed_url, params=params, authorization=self.authorization)
156-
return response
168+
data = []
169+
for recipient in recipients:
170+
validate_feed(recipient)
171+
feed_slug, user_id = recipient.split(':')
172+
feed = self.client.feed(feed_slug, user_id)
173+
data.append("%s %s" % (recipient, feed.token))
174+
return data

0 commit comments

Comments
 (0)