diff --git a/pkgs/python-packages.nix b/pkgs/python-packages.nix --- a/pkgs/python-packages.nix +++ b/pkgs/python-packages.nix @@ -35,6 +35,20 @@ self: super: { license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; + "apispec" = super.buildPythonPackage { + name = "apispec-1.0.0"; + doCheck = false; + propagatedBuildInputs = [ + self."PyYAML" + ]; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/67/15/346c04988dd67d36007e28145504c520491930c878b1f484a97b27a8f497/apispec-1.0.0.tar.gz"; + sha256 = "1712w1anvqrvadjjpvai84vbaygaxabd3zz5lxihdzwzs4gvi9sp"; + }; + meta = { + license = [ pkgs.lib.licenses.mit ]; + }; + }; "appenlight-client" = super.buildPythonPackage { name = "appenlight-client-0.6.26"; doCheck = false; @@ -236,20 +250,23 @@ self: super: { }; }; "channelstream" = super.buildPythonPackage { - name = "channelstream-0.5.2"; + name = "channelstream-0.6.14"; doCheck = false; propagatedBuildInputs = [ self."gevent" self."ws4py" + self."marshmallow" + self."python-dateutil" self."pyramid" self."pyramid-jinja2" + self."pyramid-apispec" self."itsdangerous" self."requests" self."six" ]; src = fetchurl { - url = "https://files.pythonhosted.org/packages/2b/31/29a8e085cf5bf97fa88e7b947adabfc581a18a3463adf77fb6dada34a65f/channelstream-0.5.2.tar.gz"; - sha256 = "1qbm4xdl5hfkja683x546bncg3rqq8qv79w1m1a1wd48cqqzb6rm"; + url = "https://files.pythonhosted.org/packages/d4/2d/86d6757ccd06ce673ee224123471da3d45251d061da7c580bfc259bad853/channelstream-0.6.14.tar.gz"; + sha256 = "0qgy5j3rj6c8cslzidh32glhkrhbbdxjc008y69v8a0y3zyaz2d3"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -862,11 +879,11 @@ self: super: { }; }; "itsdangerous" = super.buildPythonPackage { - name = "itsdangerous-0.24"; + name = "itsdangerous-1.1.0"; doCheck = false; src = fetchurl { - url = "https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz"; - sha256 = "06856q6x675ly542ig0plbqcyab6ksfzijlyf1hzhgg3sgwgrcyb"; + url = "https://files.pythonhosted.org/packages/68/1a/f27de07a8a304ad5fa817bbe383d1238ac4396da447fa11ed937039fa04b/itsdangerous-1.1.0.tar.gz"; + sha256 = "068zpbksq5q2z4dckh2k1zbcq43ay74ylqn77rni797j0wyh66rj"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -993,6 +1010,17 @@ self: super: { license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd3 ]; }; }; + "marshmallow" = super.buildPythonPackage { + name = "marshmallow-2.18.0"; + doCheck = false; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/ad/0b/5799965d1c6d5f608d684e2c0dce8a828e0309a3bfe8327d9418a89f591c/marshmallow-2.18.0.tar.gz"; + sha256 = "1g0aafpjn7yaxq06yndy8c7rs9n42adxkqq1ayhlr869pr06d3lm"; + }; + meta = { + license = [ pkgs.lib.licenses.mit ]; + }; + }; "mistune" = super.buildPythonPackage { name = "mistune-0.8.4"; doCheck = false; @@ -1522,6 +1550,20 @@ self: super: { license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; }; }; + "pyramid-apispec" = super.buildPythonPackage { + name = "pyramid-apispec-0.3.2"; + doCheck = false; + propagatedBuildInputs = [ + self."apispec" + ]; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/2a/30/1dea5d81ea635449572ba60ec3148310d75ae4530c3c695f54b0991bb8c7/pyramid_apispec-0.3.2.tar.gz"; + sha256 = "0ffrcqp9dkykivhfcq0v9lgy6w0qhwl6x78925vfjmayly9r8da0"; + }; + meta = { + license = [ pkgs.lib.licenses.bsdOriginal ]; + }; + }; "pyramid-mailer" = super.buildPythonPackage { name = "pyramid-mailer-0.15.1"; doCheck = false; @@ -1763,6 +1805,17 @@ self: super: { license = [ pkgs.lib.licenses.bsdOriginal { fullName = "LGPL+BSD"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; }; }; + "PyYAML" = super.buildPythonPackage { + name = "PyYAML-5.3.1"; + doCheck = false; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/64/c2/b80047c7ac2478f9501676c988a5411ed5572f35d1beff9cae07d321512c/PyYAML-5.3.1.tar.gz"; + sha256 = "0pb4zvkfxfijkpgd1b86xjsqql97ssf1knbd1v53wkg1qm9cgsmq"; + }; + meta = { + license = [ pkgs.lib.licenses.mit ]; + }; + }; "redis" = super.buildPythonPackage { name = "redis-3.4.1"; doCheck = false; diff --git a/requirements.txt b/requirements.txt --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ babel==1.3 beaker==1.9.1 bleach==3.1.3 celery==4.3.0 -channelstream==0.5.2 +channelstream==0.6.14 click==7.0 colander==1.7.0 # our custom configobj @@ -22,7 +22,7 @@ future==0.14.3 futures==3.0.2 infrae.cache==1.0.1 iso8601==0.1.12 -itsdangerous==0.24 +itsdangerous==1.1.0 kombu==4.6.6 lxml==4.2.5 mako==1.1.0 diff --git a/requirements_pinned.txt b/requirements_pinned.txt --- a/requirements_pinned.txt +++ b/requirements_pinned.txt @@ -18,10 +18,11 @@ jsonschema==2.6.0 pluggy==0.13.1 pyasn1-modules==0.2.6 pyramid-jinja2==2.7 +pyramid-apispec==0.3.2 scandir==1.10.0 setproctitle==1.1.10 tempita==0.5.2 testpath==0.4.4 transaction==2.4.0 vine==1.3.0 -wcwidth==0.1.9 +wcwidth==0.1.9 \ No newline at end of file diff --git a/rhodecode/apps/channelstream/views.py b/rhodecode/apps/channelstream/views.py --- a/rhodecode/apps/channelstream/views.py +++ b/rhodecode/apps/channelstream/views.py @@ -34,7 +34,7 @@ from rhodecode.lib.channelstream import get_user_data, parse_channels_info, update_history_from_logs, - STATE_PUBLIC_KEYS) + USER_STATE_PUBLIC_KEYS) from rhodecode.lib.auth import NotAnonymous @@ -86,14 +86,16 @@ class ChannelstreamView(BaseAppView): 'display_name': None, 'display_link': None, } - user_data['permissions'] = self._rhodecode_user.permissions_safe + + #user_data['permissions'] = self._rhodecode_user.permissions_safe + payload = { 'username': user.username, 'user_state': user_data, 'conn_id': str(uuid.uuid4()), 'channels': channels, 'channel_configs': {}, - 'state_public_keys': STATE_PUBLIC_KEYS, + 'state_public_keys': USER_STATE_PUBLIC_KEYS, 'info': { 'exclude_channels': ['broadcast'] } @@ -118,10 +120,13 @@ class ChannelstreamView(BaseAppView): 'Channelstream service at {} is down'.format(channelstream_url)) return HTTPBadGateway() + channel_info = connect_result.get('channels_info') + if not channel_info: + raise HTTPBadRequest() + connect_result['channels'] = channels connect_result['channels_info'] = parse_channels_info( - connect_result['channels_info'], - include_channel_info=filtered_channels) + channel_info, include_channel_info=filtered_channels) update_history_from_logs(self.channelstream_config, filtered_channels, connect_result) return connect_result @@ -167,10 +172,15 @@ class ChannelstreamView(BaseAppView): log.exception( 'Channelstream service at {} is down'.format(channelstream_url)) return HTTPBadGateway() + + channel_info = connect_result.get('channels_info') + if not channel_info: + raise HTTPBadRequest() + # include_channel_info will limit history only to new channel # to not overwrite histories on other channels in client connect_result['channels_info'] = parse_channels_info( - connect_result['channels_info'], + channel_info, include_channel_info=filtered_channels) update_history_from_logs( self.channelstream_config, filtered_channels, connect_result) diff --git a/rhodecode/config/licenses.json b/rhodecode/config/licenses.json --- a/rhodecode/config/licenses.json +++ b/rhodecode/config/licenses.json @@ -1890,7 +1890,7 @@ "url": "http://spdx.org/licenses/BSD-4-Clause.html" } ], - "name": "python2.7-channelstream-0.5.2" + "name": "python2.7-channelstream-0.6.14" }, { "license": [ diff --git a/rhodecode/lib/channelstream.py b/rhodecode/lib/channelstream.py --- a/rhodecode/lib/channelstream.py +++ b/rhodecode/lib/channelstream.py @@ -37,8 +37,9 @@ log = logging.getLogger(__name__) LOCK = ReadWriteMutex() -STATE_PUBLIC_KEYS = ['id', 'username', 'first_name', 'last_name', - 'icon_link', 'display_name', 'display_link'] +USER_STATE_PUBLIC_KEYS = [ + 'id', 'username', 'first_name', 'last_name', + 'icon_link', 'display_name', 'display_link'] class ChannelstreamException(Exception): @@ -64,6 +65,8 @@ def channelstream_request(config, payloa 'x-channelstream-endpoint': endpoint, 'Content-Type': 'application/json'} req_url = get_channelstream_server_url(config, endpoint) + + log.debug('Sending a channelstream request to endpoint: `%s`', req_url) response = None try: response = requests.post(req_url, data=json.dumps(payload), @@ -76,6 +79,7 @@ def channelstream_request(config, payloa log.exception('Exception related to Channelstream happened') if raise_exc: raise ChannelstreamConnectionException() + log.debug('Got channelstream response: %s', response) return response @@ -154,7 +158,7 @@ def parse_channels_info(info_result, inc for userinfo in info_result['users']: user_state_dict[userinfo['user']] = { k: v for k, v in userinfo['state'].items() - if k in STATE_PUBLIC_KEYS + if k in USER_STATE_PUBLIC_KEYS } channels_info = {} @@ -163,9 +167,9 @@ def parse_channels_info(info_result, inc if c_name not in include_channel_info: continue connected_list = [] - for userinfo in c_info['users']: + for username in c_info['users']: connected_list.append({ - 'user': userinfo['user'], + 'user': username, 'state': user_state_dict[userinfo['user']] }) channels_info[c_name] = {'users': connected_list, @@ -230,6 +234,14 @@ def get_connection_validators(registry): def post_message(channel, message, username, registry=None): + message_obj = message + if isinstance(message, basestring): + message_obj = { + 'message': message, + 'level': 'success', + 'topic': '/notifications' + } + if not registry: registry = get_current_registry() @@ -243,11 +255,7 @@ def post_message(channel, message, usern 'user': 'system', 'exclude_users': [username], 'channel': channel, - 'message': { - 'message': message, - 'level': 'success', - 'topic': '/notifications' - } + 'message': message_obj } try: