Skip to content

Commit ebc0d5d

Browse files
author
Hieu Lam - TMA
authored
feature-9029: Chat rooms: Add info to form and chat options to virtua… (#9048)
* feature-9029: Chat rooms: Add info to form and chat options to virtual event room * feature-9029: Chat rooms: Add info to form and chat options to virtual event room * feature-9029: Chat rooms: Add info to form and chat options to virtual event room * feature-9029: Fix bug create room for virtual room * feature-9029: Fix bug create room for virtual room * feature-9029: Chat rooms: Add info to form and chat options to virtual event room * feature-9029: Merge code development
1 parent fb11f31 commit ebc0d5d

File tree

5 files changed

+214
-1
lines changed

5 files changed

+214
-1
lines changed

app/api/chat/rocket_chat.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from app.models.event import Event
1212
from app.models.microlocation import Microlocation
1313
from app.models.user import User
14+
from app.models.video_stream import VideoStream
1415
from app.settings import get_settings
1516

1617
logger = logging.getLogger(__name__)
@@ -142,6 +143,53 @@ def get_token(
142143

143144
return self.register(user, event)
144145

146+
def get_token_virtual_room(
147+
self,
148+
user: User,
149+
event: Optional[Event] = None,
150+
retried=False,
151+
videoStream: Optional[VideoStream] = None,
152+
):
153+
if user.rocket_chat_token:
154+
res = requests.post(self.login_url, json=dict(resume=user.rocket_chat_token))
155+
156+
data = res.json()
157+
if res.status_code == 200:
158+
if event:
159+
self.add_in_room_virtual_room(
160+
event, data['data']['userId'], videoStream
161+
)
162+
return dict(method='resumed', token=user.rocket_chat_token, res=data)
163+
elif res.status_code == 401:
164+
# Token Expired. Login again
165+
166+
try:
167+
return self.login(user, event, 'login')
168+
except RocketChatException as rce:
169+
if (
170+
not retried
171+
and rce.response is not None
172+
and rce.response.status_code == 401
173+
):
174+
# Invalid credentials stored. Reset credentials and retry
175+
# If we have already retried, give up
176+
user.rocket_chat_token = None
177+
db.session.add(user)
178+
db.session.commit()
179+
return self.get_token_virtual_room(user, event, retried=True)
180+
else:
181+
raise rce
182+
else:
183+
# Unhandled Case
184+
logger.error('Error while rocket chat resume or login: %s', data)
185+
raise RocketChatException(
186+
'Error while resume or logging in', response=res
187+
)
188+
else:
189+
# No token. Try creating profile, else login
190+
191+
return self.register(user, event)
192+
145193
def check_or_create_bot(self):
146194
bot_email = '[email protected]'
147195
bot_user, _ = get_or_create(
@@ -184,6 +232,40 @@ def create_room(self, event: Event, microlocation: Optional[Microlocation], data
184232
db.session.add(event)
185233
db.session.commit()
186234

235+
def create_room_virtual_room(
236+
self, event: Event, videoStream: Optional[VideoStream], data
237+
):
238+
bot_token = data['token']
239+
bot_id = data['res']['data']['userId']
240+
if videoStream:
241+
chat_room_name = videoStream.chat_room_name
242+
else:
243+
chat_room_name = event.chat_room_name
244+
245+
res = requests.post(
246+
self.api_url + '/api/v1/groups.create',
247+
json=dict(
248+
name=chat_room_name,
249+
members=[bot_id],
250+
),
251+
headers={
252+
'X-Auth-Token': bot_token,
253+
'X-User-Id': bot_id,
254+
},
255+
)
256+
if not res.status_code == 200:
257+
logger.error('Error while creating room : %s', res.json())
258+
raise RocketChatException('Error while creating room', response=res)
259+
else:
260+
group_data = res.json()
261+
if videoStream:
262+
videoStream.chat_room_id = group_data['group']['_id']
263+
db.session.add(videoStream)
264+
else:
265+
event.chat_room_id = group_data['group']['_id']
266+
db.session.add(event)
267+
db.session.commit()
268+
187269
def add_in_room(
188270
self, event: Event, rocket_user_id, microlocation: Optional[Microlocation] = None
189271
):
@@ -215,6 +297,36 @@ def add_in_room(
215297
logger.error('Error while adding user : %s', res.json())
216298
raise RocketChatException('Error while adding user', response=res)
217299

300+
def add_in_room_virtual_room(
301+
self, event: Event, rocket_user_id, videoStream: Optional[VideoStream] = None
302+
):
303+
bot = self.check_or_create_bot()
304+
data = self.get_token_virtual_room(bot, videoStream=videoStream)
305+
if (not event.chat_room_id) or (videoStream and not videoStream.chat_room_id):
306+
self.create_room_virtual_room(event=event, videoStream=videoStream, data=data)
307+
308+
if videoStream is not None:
309+
chat_room_id = videoStream.chat_room_id
310+
else:
311+
chat_room_id = event.chat_room_id
312+
313+
bot_token = data['token']
314+
bot_id = data['res']['data']['userId']
315+
room_info = {'roomId': chat_room_id, 'userId': rocket_user_id}
316+
317+
res = requests.post(
318+
self.api_url + '/api/v1/groups.invite',
319+
json=room_info,
320+
headers={
321+
'X-Auth-Token': bot_token,
322+
'X-User-Id': bot_id,
323+
},
324+
)
325+
326+
if res.status_code != 200:
327+
logger.error('Error while adding user : %s', res.json())
328+
raise RocketChatException('Error while adding user', response=res)
329+
218330

219331
def generate_pass(size=10, chars=string.ascii_lowercase + string.digits):
220332
return ''.join(random.choice(chars) for _ in range(size))
@@ -235,6 +347,21 @@ def get_rocket_chat_token(
235347
return rocket_chat.get_token(user, event, microlocation=microlocation)
236348

237349

350+
def get_rocket_chat_token_virtual_room(
351+
user: User,
352+
event: Optional[Event] = None,
353+
videoStream: Optional[VideoStream] = None,
354+
):
355+
settings = get_settings()
356+
if not (api_url := settings['rocket_chat_url']):
357+
raise RocketChatException(
358+
'Rocket Chat Integration is not enabled', RocketChatException.CODES.DISABLED
359+
)
360+
361+
rocket_chat = RocketChat(api_url)
362+
return rocket_chat.get_token_virtual_room(user, event, videoStream=videoStream)
363+
364+
238365
def rename_rocketchat_room(event: Event):
239366
settings = get_settings()
240367
if not event.chat_room_id or not (api_url := settings['rocket_chat_url']):

app/api/events.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
from sqlalchemy import and_, or_
1414

1515
from app.api.bootstrap import api
16-
from app.api.chat.rocket_chat import RocketChatException, get_rocket_chat_token
16+
from app.api.chat.rocket_chat import (
17+
RocketChatException,
18+
get_rocket_chat_token,
19+
get_rocket_chat_token_virtual_room,
20+
)
1721
from app.api.data_layers.EventCopyLayer import EventCopyLayer
1822
from app.api.helpers.db import safe_query, safe_query_kwargs, save_to_db
1923
from app.api.helpers.errors import (
@@ -162,6 +166,45 @@ def get_room_chat_token(event_id: int, microlocation_id: int):
162166
)
163167

164168

169+
@events_blueprint.route(
170+
'/<string:event_identifier>/virtual-room/<int:video_stream_id>/chat-token',
171+
)
172+
@jwt_required
173+
@to_event_id
174+
def get_virtual_room_chat_token(event_id: int, video_stream_id: int):
175+
"""
176+
Get room chat token for specific room
177+
@param event_id: event identifier
178+
@param video_stream_id: microlocation id
179+
@return: room chat token
180+
"""
181+
event = Event.query.get_or_404(event_id)
182+
videoStream = VideoStream.query.get_or_404(video_stream_id)
183+
184+
if not VideoStream(event_id=event.id).user_can_access:
185+
raise NotFoundError({'source': ''}, 'Video Stream Not Found')
186+
187+
if not event.is_chat_enabled:
188+
raise NotFoundError({'source': ''}, 'Chat Not Enabled')
189+
190+
if not videoStream.is_chat_enabled and not videoStream.is_global_event_room:
191+
raise NotFoundError({'source': ''}, 'Chat Not Enabled For This Room')
192+
193+
try:
194+
data = get_rocket_chat_token_virtual_room(current_user, event, videoStream)
195+
return jsonify({'success': True, 'token': data['token']})
196+
except RocketChatException as rce:
197+
if rce.code == RocketChatException.CODES.DISABLED:
198+
return jsonify({'success': False, 'code': rce.code})
199+
return jsonify(
200+
{
201+
'success': False,
202+
'code': rce.code,
203+
'response': rce.response is not None and rce.response.json(),
204+
}
205+
)
206+
207+
165208
def validate_event(user, data):
166209
if not user.can_create_event():
167210
raise ForbiddenError({'source': ''}, "Please verify your Email")

app/api/schema/video_stream.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ class Meta:
4747
bg_img_url = fields.Str(required=False, allow_none=True)
4848
additional_information = fields.Str(required=False, allow_none=True)
4949
extra = fields.Nested(VideoStreamExtraSchema, allow_none=True)
50+
is_chat_enabled = fields.Boolean(default=False, allow_none=True)
51+
is_global_event_room = fields.Boolean(default=False, allow_none=True)
52+
chat_room_name = fields.Str(dump_only=True)
5053
rooms = Relationship(
5154
many=True,
5255
self_view='v1.video_stream_rooms',

app/models/video_stream.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import re
2+
13
from flask_jwt_extended import current_user
24
from sqlalchemy import or_
35
from sqlalchemy.orm import backref
@@ -41,6 +43,9 @@ class VideoStream(db.Model):
4143
db.Integer, db.ForeignKey('video_channels.id', ondelete='CASCADE')
4244
)
4345
channel = db.relationship(VideoChannel, backref='streams')
46+
is_chat_enabled = db.Column(db.Boolean, default=False, nullable=True)
47+
is_global_event_room = db.Column(db.Boolean, default=False, nullable=True)
48+
chat_room_id = db.Column(db.String, nullable=True)
4449

4550
def __repr__(self):
4651
return f'<VideoStream {self.name!r} {self.url!r}>'
@@ -99,3 +104,7 @@ def user_can_access(self):
99104
.exists()
100105
).scalar()
101106
)
107+
108+
@property
109+
def chat_room_name(self):
110+
return re.sub('[^0-9a-zA-Z!]', '-', self.name) + '-' + str(self.id)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""empty message
2+
3+
Revision ID: c27a61850a11
4+
Revises: 7e91153d66b0
5+
Create Date: 2023-08-07 11:37:30.000148
6+
7+
"""
8+
9+
from alembic import op
10+
import sqlalchemy as sa
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = 'c27a61850a11'
15+
down_revision = '7e91153d66b0'
16+
17+
18+
def upgrade():
19+
# ### commands auto generated by Alembic - please adjust! ###
20+
op.add_column('video_streams', sa.Column('is_chat_enabled', sa.Boolean(), nullable=True))
21+
op.add_column('video_streams', sa.Column('is_global_event_room', sa.Boolean(), nullable=True))
22+
op.add_column('video_streams', sa.Column('chat_room_id', sa.String(), nullable=True))
23+
# ### end Alembic commands ###
24+
25+
26+
def downgrade():
27+
# ### commands auto generated by Alembic - please adjust! ###
28+
op.drop_column('video_streams', 'chat_room_id')
29+
op.drop_column('video_streams', 'is_global_event_room')
30+
op.drop_column('video_streams', 'is_chat_enabled')
31+
# ### end Alembic commands ###

0 commit comments

Comments
 (0)