Skip to content

Commit 0b72eb2

Browse files
committed
updates
1 parent 61cd971 commit 0b72eb2

9 files changed

Lines changed: 191 additions & 34 deletions

File tree

core/api/bookings/events/artisan.py

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import sys
33
import json
4+
import uuid
45

56
from flask import (
67
request,
@@ -19,9 +20,8 @@
1920
LOG_FORMAT, _level, send_notification
2021
)
2122
from models import (
22-
Artisan,
23-
Booking,
24-
User
23+
Artisan, Booking, User,
24+
ChatMessage, Chat
2525
)
2626
from .utils import (
2727
error_response,
@@ -80,9 +80,12 @@
8080

8181

8282
@socketio.on('connect', namespace='/chat')
83-
@auth_param_required
84-
def enter_chat_namespace(data):
85-
emit('message', 'welcome to chat')
83+
@valid_auth_required
84+
def enter_chat_namespace(uid):
85+
redis_4.hset(
86+
"user_to_chat_sid",
87+
mapping={uid: request.sid}
88+
)
8689

8790

8891
@socketio.on('join_chat', namespace='/chat')
@@ -252,7 +255,11 @@ def handle_updates(msg):
252255
fcm_token = redis_4.hget("user_to_fcm_token", uid)
253256
send_notification(
254257
notification_payload,
255-
fcm_token
258+
fcm_token,
259+
notification_object={
260+
'body': 'A client near you needs your service',
261+
'title': 'New Service Request Alert! 🚨'
262+
}
256263
)
257264

258265
psub.subscribe(**{geo_fence_key: handle_updates})
@@ -656,13 +663,28 @@ def customer_approval(uid, data):
656663

657664

658665
@socketio.on('message', namespace='/chat')
659-
@parse_event_data
660666
@valid_auth_required
667+
@parse_event_data
661668
def send_chat_msg(uid, data):
662669
"""sends message to chat room"""
663-
msg = data['msg']
664-
room = data['booking_id']
665-
socketio.send(msg, to=room, namespace='/chat')
670+
# check if chat exists in db if not create one
671+
with db.session() as sess:
672+
bk_id = data['booking_id']
673+
new_msg = ChatMessage(**data['chat_object'])
674+
sid = redis_4.hget('user_to_chat_sid', uid)
675+
chat_id = redis_4.hget('booking_id_to_chat_id', bk_id)
676+
if not chat_id:
677+
new_chat = Chat(booking_id=bk_id)
678+
sess.add(new_chat)
679+
chat_id = uuid.uuid4().hex
680+
new_chat.id = chat_id
681+
# set in cache
682+
redis_4.hset('booking_id_to_chat_id', bk_id, chat_id)
683+
sess.add(new_msg)
684+
sess.commit()
685+
room = data['booking_id']
686+
msg = json.dumps(data['chat_object'])
687+
socketio.send(msg, to=room, skip_sid=sid, namespace='/chat')
666688

667689

668690
@socketio.on('clock_in', namespace='/artisan')

core/api/bookings/events/customer.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
from core import socketio
1+
import json
2+
import uuid
3+
4+
from core import socketio, db
25
from add_extensions import (
36
redis_,
47
redis_2,
58
redis_4,
69
redis_7
710
)
8-
from models import User
11+
from models import User, Chat, ChatMessage
912
from models.bookings import BookingStatusEnum
1013
from core.api.auth.auth_helper import (
1114
auth_param_required,
@@ -73,9 +76,12 @@ def connect(auth):
7376

7477

7578
@socketio.on('connect', namespace='/chat')
76-
@auth_param_required
77-
def enter_chat_namespace(data):
78-
emit('message', 'welcome to chat')
79+
@valid_auth_required
80+
def enter_chat_namespace(uid):
81+
redis_4.hset(
82+
"user_to_chat_sid",
83+
mapping={uid: request.sid}
84+
)
7985

8086

8187
@socketio.on('disconnect', namespace='/customer')
@@ -164,12 +170,28 @@ def cancel_offer(uid, data):
164170

165171

166172
@socketio.on('message', namespace='/chat')
173+
@valid_auth_required
167174
@parse_event_data
168-
def send_chat_msg(data):
175+
def send_chat_msg(uid, data):
169176
"""sends message to chat room"""
170-
msg = data['msg']
171-
room = data['booking_id']
172-
socketio.send(msg, to=room, namespace='/chat')
177+
# check if chat exists in db if not create one
178+
with db.session() as sess:
179+
bk_id = data['booking_id']
180+
new_msg = ChatMessage(**data['chat_object'])
181+
sid = redis_4.hget('user_to_chat_sid', uid)
182+
chat_id = redis_4.hget('booking_id_to_chat_id', bk_id)
183+
if not chat_id:
184+
new_chat = Chat(booking_id=bk_id)
185+
sess.add(new_chat)
186+
chat_id = uuid.uuid4().hex
187+
new_chat.id = chat_id
188+
# set in cache
189+
redis_4.hset('booking_id_to_chat_id', bk_id, chat_id)
190+
sess.add(new_msg)
191+
sess.commit()
192+
room = data['booking_id']
193+
msg = json.dumps(data['chat_object'])
194+
socketio.send(msg, to=room, skip_sid=sid, namespace='/chat')
173195

174196

175197
@socketio.on('test', namespace='/customer')
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""empty message
2+
3+
Revision ID: 94f1cc79bb84
4+
Revises: 42f4aaaab1a1
5+
Create Date: 2026-01-13 01:33:39.975178
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '94f1cc79bb84'
14+
down_revision = '42f4aaaab1a1'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table('chat',
22+
sa.Column('id', sa.String(), nullable=False),
23+
sa.Column('booking_id', sa.String(), nullable=True),
24+
sa.Column('closed_at', sa.DateTime(), nullable=True),
25+
sa.Column('created_at', sa.DateTime(), nullable=False),
26+
sa.Column('updated_at', sa.DateTime(), nullable=True),
27+
sa.ForeignKeyConstraint(['booking_id'], ['booking.booking_id'], ),
28+
sa.PrimaryKeyConstraint('id'),
29+
sa.UniqueConstraint('id')
30+
)
31+
op.create_table('chat_message',
32+
sa.Column('message_id', sa.String(), nullable=True),
33+
sa.Column('content', sa.Text(), nullable=False),
34+
sa.Column('chat_id', sa.String(), nullable=True),
35+
sa.Column('sent_by', sa.String(), nullable=True),
36+
sa.Column('is_flagged', sa.Boolean(), nullable=True),
37+
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
38+
sa.Column('created_at', sa.DateTime(), nullable=False),
39+
sa.Column('updated_at', sa.DateTime(), nullable=True),
40+
sa.ForeignKeyConstraint(['chat_id'], ['chat.id'], ),
41+
sa.ForeignKeyConstraint(['sent_by'], ['user.user_id'], ),
42+
sa.PrimaryKeyConstraint('id')
43+
)
44+
with op.batch_alter_table('chat_message', schema=None) as batch_op:
45+
batch_op.create_index(batch_op.f('ix_chat_message_chat_id'), ['chat_id'], unique=False)
46+
batch_op.create_index(batch_op.f('ix_chat_message_sent_by'), ['sent_by'], unique=False)
47+
# ### end Alembic commands ###
48+
49+
50+
def downgrade():
51+
# ### commands auto generated by Alembic - please adjust! ###
52+
with op.batch_alter_table('chat_message', schema=None) as batch_op:
53+
batch_op.drop_index(batch_op.f('ix_chat_message_sent_by'))
54+
batch_op.drop_index(batch_op.f('ix_chat_message_chat_id'))
55+
56+
op.drop_table('chat_message')
57+
op.drop_table('chat')
58+
# ### end Alembic commands ###

models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
from .location import Landmark, City
1010
from .payments import Payment, CardAuth
1111
from .ratings import Rating
12+
from .chat import Chat, ChatMessage

models/bookings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ class Booking(TimestampMixin, db.Model):
211211
)
212212
images = db.relationship('Blob', backref='booking')
213213
working_days = db.relationship('BookingWorkDay', backref='booking')
214+
chat = db.relationship('Chat', uselist=False, backref='booking')
214215

215216
def update_start_time(self):
216217
self.start_time = dt.utcnow()

models/chat.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from core import db
2+
3+
from .base import TimestampMixin, BaseModelPR
4+
5+
6+
class Chat(TimestampMixin, db.Model):
7+
id = db.Column(db.String, primary_key=True, unique=True)
8+
booking_id = db.Column(db.String, db.ForeignKey('booking.booking_id'))
9+
closed_at = db.Column(db.DateTime)
10+
chats = db.relationship('ChatMessage', backref='chat')
11+
12+
13+
class ChatMessage(BaseModelPR, TimestampMixin, db.Model):
14+
message_id = db.Column(db.String)
15+
content = db.Column(db.Text, nullable=False)
16+
chat_id = db.Column(db.String, db.ForeignKey('chat.id'), index=True)
17+
sent_by = db.Column(db.String, db.ForeignKey('user.user_id'), index=True)
18+
is_flagged = db.Column(db.Boolean)

supervisord-dev.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ environment=HOME="/home/handeesofficial"
7878
# stderr_logfile_backups=0
7979

8080
[program:huey]
81-
command=/home/handeesofficial/backend/env/bin/huey_consumer.py huey_worker.huey -w 2 -n
81+
command=/home/handeesofficial/backend/env/bin/python3 huey_worker.py
8282
directory=/home/handeesofficial/backend
8383
user=handeesofficial
8484
autostart=true

tasks/events.py

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,44 @@
1919
redis_pass = os.getenv('REDIS_PASS')
2020
redis_port = os.getenv('REDIS_PORT', 6378)
2121

22-
IMPORTANT_NOTIFICATIONS = [
23-
'approve_booking_details', 'new_offer',
24-
'job_completed',
25-
'booking_offer_accepted',
26-
'offer_cancelled',
27-
'artisan_arrived', 'job_details_rejected',
28-
'artisan_clocked_in', 'artisan_clock_out',
29-
'job_started', 'approve_booking_details'
30-
]
22+
NOTIFICATONS_MAP = {
23+
'approve_booking_details': {
24+
'body': 'Kindly review service request details',
25+
'title': 'Approve Service Request Details'
26+
},
27+
'job_completed': {
28+
'body': "Artisan says their done with the work 😊",
29+
'title': 'Job Completed'
30+
},
31+
'booking_offer_accepted': {
32+
'body': "Hey you've been matched with an artisan near you!",
33+
'title': 'Booking Request Accepted'
34+
},
35+
'offer_cancelled': {
36+
'body': "Service request canceled💀",
37+
'title': 'Offer Has Been Canceled'
38+
},
39+
'artisan_arrived': {
40+
'body': "Good news! You have a visitor!🔥 Your artisan has arrived",
41+
'title': 'Artisan Has Arrived'
42+
},
43+
'job_details_rejected': {
44+
'body': "Customer rejected booking details💀 - contact them!",
45+
'title': 'Service Request Detail Rejected'
46+
},
47+
'artisan_clocked_in': {
48+
'body': 'Artisan clocked in for a work session',
49+
'title': 'Artisan Clocked In'
50+
},
51+
'artisan_clocked_out': {
52+
'body': 'Artisan clocked out from a work session',
53+
'title': 'Artisan Clocked Out'
54+
},
55+
'job_started': {
56+
'body': 'Service rendering has officialy begun✅',
57+
'title': 'Artisan Started Working'
58+
}
59+
}
3160

3261

3362
def exp_backoff_task(retries, retry_backoff):
@@ -96,10 +125,15 @@ def send_event(event, data, namespace):
96125
namespace=namespace
97126
)
98127
print(f"SOCKET EMIT RESPONSE {resp}")
99-
if event in IMPORTANT_NOTIFICATIONS:
128+
if event in NOTIFICATONS_MAP:
100129
notification_payload = {
101130
k: json.dumps(v) for k, v in data['payload'].items()
102131
}
103132
fcm_token = redis_4.hget("user_to_fcm_token", data['recipient'])
104-
res = send_notification(notification_payload, fcm_token, app_instance)
133+
res = send_notification(
134+
notification_payload,
135+
fcm_token,
136+
app_instance,
137+
NOTIFICATONS_MAP[event]
138+
)
105139
logger.error(f"Sent push notification request, with resp: {res}")

utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,12 +322,13 @@ def decode_file_id(encoded_id: str):
322322
return user_id_int, decoded_blob_type, decoded_hash_hex
323323

324324

325-
def send_notification(data, token, app=None):
325+
def send_notification(data, token, app=None, notification_object=None):
326326
print("FCM TOKEN IS::", token)
327327
print("Input data", data)
328328
push_notification = messaging.Message(
329329
data=data,
330-
token=token
330+
token=token,
331+
notification=messaging.Notification(**notification_object)
331332
)
332333
response = messaging.send(
333334
push_notification,

0 commit comments

Comments
 (0)