Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
6db4879
Merge pull request #9 from BitwisePushkar/development
BitwisePushkar Oct 15, 2025
ab4594b
Merge pull request #11 from Arnavonawhim/main
Arnavonawhim Oct 16, 2025
99d10ec
Merge pull request #16 from BitwisePushkar/authentication
BitwisePushkar Oct 18, 2025
822491d
created a new app for chat system
psinghal0135-bot Oct 18, 2025
3adb224
made a new feature branch
psinghal0135-bot Oct 18, 2025
8ceca4b
Merge pull request #17 from BitwisePushkar/pushkar
BitwisePushkar Oct 18, 2025
680e2a9
Merge pull request #18 from BitwisePushkar/chat
BitwisePushkar Oct 18, 2025
cd61d34
Merge pull request #19 from BitwisePushkar/main
BitwisePushkar Oct 19, 2025
4c1b31d
resolved ci cd error code 1
psinghal0135-bot Oct 19, 2025
60434cf
resolved ci cd error code 1
psinghal0135-bot Oct 19, 2025
4803866
made model for my chat feature
psinghal0135-bot Oct 19, 2025
e50432b
created serializer,views and more for chat feature
psinghal0135-bot Oct 21, 2025
7029a51
made model for one -one communication and also for a group chat now a…
psinghal0135-bot Oct 22, 2025
871c4e5
Merge pull request #20 from BitwisePushkar/pushkar
BitwisePushkar Oct 22, 2025
507f8e9
added ci cd
psinghal0135-bot Oct 23, 2025
16db177
updated ci cd
psinghal0135-bot Oct 23, 2025
6aae44b
Merge branch 'development' into chat
psinghal0135-bot Oct 23, 2025
3548669
Merge pull request #21 from BitwisePushkar/chat
BitwisePushkar Oct 23, 2025
0a42951
made changes in deploy.yml
psinghal0135-bot Oct 23, 2025
a769c0f
made change in asgi.py
psinghal0135-bot Oct 23, 2025
66d256d
made change in asgi.py
psinghal0135-bot Oct 23, 2025
2204503
made change in asgi.py
psinghal0135-bot Oct 23, 2025
070a481
made change in asgi.py
psinghal0135-bot Oct 23, 2025
0d7a6f5
made changes in setting.py
psinghal0135-bot Oct 23, 2025
8bd4ec8
made changes in setting.py
psinghal0135-bot Oct 23, 2025
619b162
made changes in setting.py
psinghal0135-bot Oct 23, 2025
bb306ef
made changes in setting.py
psinghal0135-bot Oct 23, 2025
609b5ff
made changes in setting.py
psinghal0135-bot Oct 23, 2025
075a3ab
made changes for channel connection
psinghal0135-bot Oct 23, 2025
fb95761
made changes for channel connection
psinghal0135-bot Oct 23, 2025
ea4e9ab
Merge branch 'chat' into development
BitwisePushkar Oct 23, 2025
afd80d7
Merge pull request #22 from BitwisePushkar/development
BitwisePushkar Oct 23, 2025
8dee36b
changes in setting.py
psinghal0135-bot Oct 24, 2025
d1cb4fd
Merge pull request #23 from BitwisePushkar/chat
BitwisePushkar Oct 24, 2025
6a942ab
changes in setting.py
psinghal0135-bot Oct 24, 2025
832db0c
changes in setting.py
psinghal0135-bot Oct 24, 2025
ef951ee
changes in setting.py
psinghal0135-bot Oct 24, 2025
3ac6b00
forgot to git add
Arnavonawhim Oct 24, 2025
cfc3dca
Merge branch 'main' of https://github.com/Arnavonawhim/tripsync
Arnavonawhim Oct 24, 2025
7ed243d
Merge pull request #24 from Arnavonawhim/main
Arnavonawhim Oct 24, 2025
0ecf2d0
added changes
psinghal0135-bot Oct 24, 2025
21e8e4f
removed all old code
psinghal0135-bot Oct 24, 2025
2c43496
Resolved conflicts: took all files from Arnav branch
psinghal0135-bot Oct 24, 2025
7eef4e3
added db lite modification
psinghal0135-bot Oct 24, 2025
7a20086
added aws ip address to allowed host
psinghal0135-bot Oct 24, 2025
7682549
add code of chat feature
psinghal0135-bot Oct 24, 2025
a410efb
made changes in channel layers
psinghal0135-bot Oct 25, 2025
a8d7021
Merge pull request #26 from BitwisePushkar/pushkar
BitwisePushkar Oct 25, 2025
9d98f5e
forgot to add count in it
psinghal0135-bot Oct 25, 2025
6afc940
fixed a bug
psinghal0135-bot Oct 25, 2025
1530e42
Merge pull request #27 from BitwisePushkar/pushkar
BitwisePushkar Oct 25, 2025
a890e39
Merge branch 'development' into chat
BitwisePushkar Oct 26, 2025
e1edbdc
Merge pull request #28 from BitwisePushkar/chat
BitwisePushkar Oct 26, 2025
2d4d8eb
removed static files
psinghal0135-bot Oct 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ on:
- authentication
- pushkar
- Arnav
- feature/* # future feature branches
- chat
- feature/*

jobs:
ci-cd:
Expand Down Expand Up @@ -39,7 +40,8 @@ jobs:
github.ref == 'refs/heads/development' ||
github.ref == 'refs/heads/authentication' ||
github.ref == 'refs/heads/pushkar' ||
github.ref == 'refs/heads/Arnav'
github.ref == 'refs/heads/Arnav' ||
github.ref == 'refs/heads/chat'
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.EC2_HOST }}
Expand All @@ -49,7 +51,7 @@ jobs:
# Navigate to Django project folder
cd /home/ubuntu/tripsync-backend/auth

# Pull latest code from the branch
# Pull latest code
git pull origin $GITHUB_REF_NAME

# Activate virtual environment
Expand All @@ -58,10 +60,14 @@ jobs:
# Install requirements
pip install -r ../requirements.txt

# Run migrations and collect static files
# Apply migrations and collect static files
python manage.py migrate
python manage.py collectstatic --noinput

# Restart Gunicorn and Nginx
# Restart Redis (if managed manually)
sudo systemctl restart redis-server

# Restart Daphne and Nginx
sudo systemctl restart daphne
sudo systemctl restart gunicorn
sudo systemctl restart nginx
8 changes: 0 additions & 8 deletions auth/.dockerignore

This file was deleted.

14 changes: 0 additions & 14 deletions auth/Dockerfile

This file was deleted.

Binary file modified auth/account/migrations/__pycache__/0001_initial.cpython-310.pyc
Binary file not shown.
151 changes: 27 additions & 124 deletions auth/account/utils.py
Original file line number Diff line number Diff line change
@@ -1,162 +1,65 @@
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, Email, To, Content
from django.conf import settings
import logging

logger = logging.getLogger(__name__)

def send_otp_email(email, otp, purpose="verification"):
"""
Send OTP email using SendGrid HTTP API (works on Render Free tier)
"""
try:
sendgrid_api_key = getattr(settings, 'SENDGRID_API_KEY', None)
if not sendgrid_api_key:
logger.error("SENDGRID_API_KEY not configured in settings")
return False

from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@tripsync.com')
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail

if purpose == "verification":
subject = "Email Verification OTP - TripSync"
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
.header {{ background-color: #4F46E5; color: white; padding: 20px; text-align: center; border-radius: 5px 5px 0 0; }}
.content {{ background-color: #f9fafb; padding: 30px; border: 1px solid #e5e7eb; }}
.otp-box {{ background-color: #fff; border: 2px dashed #4F46E5; padding: 20px; text-align: center; margin: 20px 0; border-radius: 5px; }}
.otp-code {{ font-size: 32px; font-weight: bold; color: #4F46E5; letter-spacing: 5px; }}
.footer {{ background-color: #f3f4f6; padding: 15px; text-align: center; font-size: 12px; color: #6b7280; border-radius: 0 0 5px 5px; }}
.warning {{ color: #dc2626; font-weight: bold; }}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Welcome to TripSync!</h1>
</div>
<div class="content">
<h2>Email Verification</h2>
<p>Hello,</p>
<p>Thank you for registering with TripSync - Your Travel Planning Companion!</p>
<p>To verify your email address, please use the following OTP code:</p>

<div class="otp-box">
<div class="otp-code">{otp}</div>
</div>

<p><strong>This OTP is valid for 10 minutes.</strong></p>
<p class="warning">⚠️ Please do not share this OTP with anyone.</p>
<p>If you did not request this verification, please ignore this email.</p>
</div>
<div class="footer">
<p>© 2024 TripSync. All rights reserved.</p>
<p>This is an automated email, please do not reply.</p>
</div>
</div>
<h2>Welcome to TripSync!</h2>
<p>Your email verification OTP is:</p>
<h1 style="color: #4CAF50; font-size: 32px; letter-spacing: 5px;">{otp}</h1>
<p>This OTP is valid for 10 minutes.</p>
<p><small>If you didn't request this, please ignore this email.</small></p>
<br>
<p>Best regards,<br>TripSync Team</p>
</body>
</html>
"""
plain_content = f"""
Hello,

Welcome to TripSync - Your Travel Planning Companion!

Your OTP for email verification is: {otp}

This OTP is valid for 10 minutes. Please do not share this OTP with anyone.

If you did not request this, please ignore this email.

Best regards,
TripSync Team
"""
else:
subject = "Password Reset OTP - TripSync"
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
.header {{ background-color: #dc2626; color: white; padding: 20px; text-align: center; border-radius: 5px 5px 0 0; }}
.content {{ background-color: #f9fafb; padding: 30px; border: 1px solid #e5e7eb; }}
.otp-box {{ background-color: #fff; border: 2px dashed #dc2626; padding: 20px; text-align: center; margin: 20px 0; border-radius: 5px; }}
.otp-code {{ font-size: 32px; font-weight: bold; color: #dc2626; letter-spacing: 5px; }}
.footer {{ background-color: #f3f4f6; padding: 15px; text-align: center; font-size: 12px; color: #6b7280; border-radius: 0 0 5px 5px; }}
.warning {{ color: #dc2626; font-weight: bold; }}
.security-notice {{ background-color: #fef2f2; border-left: 4px solid #dc2626; padding: 10px; margin: 15px 0; }}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Password Reset Request</h1>
</div>
<div class="content">
<h2>Reset Your Password</h2>
<p>Hello,</p>
<p>You have requested to reset your password for your TripSync account.</p>
<p>Your OTP for password reset is:</p>

<div class="otp-box">
<div class="otp-code">{otp}</div>
</div>

<p><strong>This OTP is valid for 10 minutes.</strong></p>

<div class="security-notice">
<p class="warning">🔒 Security Notice</p>
<p>If you did not request this password reset, please secure your account immediately and contact our support team.</p>
</div>

<p class="warning">⚠️ Never share this OTP with anyone, including TripSync staff.</p>
</div>
<div class="footer">
<p>© 2024 TripSync. All rights reserved.</p>
<p>This is an automated email, please do not reply.</p>
</div>
</div>
<h2>Password Reset Request</h2>
<p>Your password reset OTP is:</p>
<h1 style="color: #FF5722; font-size: 32px; letter-spacing: 5px;">{otp}</h1>
<p>This OTP is valid for 10 minutes.</p>
<p><small>If you didn't request this, please secure your account immediately.</small></p>
<br>
<p>Best regards,<br>TripSync Team</p>
</body>
</html>
"""
plain_content = f"""
Hello,

You have requested to reset your password for your TripSync account.

Your OTP for password reset is: {otp}

This OTP is valid for 10 minutes. Please do not share this OTP with anyone.

If you did not request this, please secure your account immediately and contact support.

Best regards,
TripSync Team
"""

message = Mail(
from_email=Email(from_email),
to_emails=To(email),
from_email=settings.DEFAULT_FROM_EMAIL,
to_emails=email,
subject=subject,
plain_text_content=Content("text/plain", plain_content),
html_content=Content("text/html", html_content)
html_content=html_content
)

sg = SendGridAPIClient(sendgrid_api_key)
sg = SendGridAPIClient(settings.SENDGRID_API_KEY)
response = sg.send(message)

if response.status_code in [200, 201, 202]:
logger.info(f"OTP email sent successfully to {email} via SendGrid")
logger.info(f"OTP email sent successfully to {email} via SendGrid API")
return True
else:
logger.error(f"SendGrid returned status code {response.status_code}")
logger.error(f"SendGrid API returned status {response.status_code}")
return False

except Exception as e:
logger.error(f"Error sending email via SendGrid: {str(e)}")
import traceback
logger.error(traceback.format_exc())
logger.error(f"✗ SendGrid API error for {email}: {str(e)}")
logger.exception("Full traceback:")
return False
23 changes: 23 additions & 0 deletions auth/auth/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""
ASGI config for chatsystemproj project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'auth.settings')

from chat.routing import websocket_urlpatterns

application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket':AuthMiddlewareStack(
URLRouter(websocket_urlpatterns)
),
})
44 changes: 34 additions & 10 deletions auth/auth/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@

SECRET_KEY = os.environ.get("SECRET_KEY", "unsafe-dev-secret-key")

DEBUG = config('DEBUG', default=False, cast=bool)
# DEBUG = config('DEBUG', default=False, cast=bool)
DEBUG = True

ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1,51.20.254.52").split(',')

INSTALLED_APPS = ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'account.apps.AccountConfig', 'rest_framework', 'rest_framework_simplejwt', 'rest_framework_simplejwt.token_blacklist', 'corsheaders', 'drf_spectacular']
# ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1,51.20.254.52").split(',')
ALLOWED_HOSTS = ["*"]
INSTALLED_APPS = ['channels','daphne','django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'account.apps.AccountConfig', 'rest_framework', 'rest_framework_simplejwt', 'rest_framework_simplejwt.token_blacklist', 'corsheaders', 'drf_spectacular','chat.apps.ChatConfig']

MIDDLEWARE = ['django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware']

Expand All @@ -22,14 +23,31 @@

WSGI_APPLICATION = 'auth.wsgi.application'

database_url = os.environ.get("DATABASE_URL","postgresql://arnav_db_user:FupuhQQOsNLTkJKNEp2EA6Q8Kia7hvCu@dpg-d3mk6mvdiees73c95o2g-a.singapore-postgres.render.com/arnav_db")
if database_url.startswith("postgres://"):
database_url = database_url.replace("postgres://", "postgresql://", 1)
DATABASES = {'default': dj_database_url.parse(database_url, conn_max_age=600, ssl_require=True)}
ASGI_APPLICATION = 'auth.asgi.application'

REDIS_HOST = config('REDIS_HOST', default='127.0.0.1')
REDIS_PORT = config('REDIS_PORT', default=6379, cast=int)

CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [(REDIS_HOST, REDIS_PORT)],
},
},
}

database_url = os.environ.get("DATABASE_URL")
if database_url:
if database_url.startswith("postgres://"):
database_url = database_url.replace("postgres://", "postgresql://", 1)
DATABASES = {'default': dj_database_url.parse(database_url, conn_max_age=600, ssl_require=True)}
else:
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3'}}

REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_simplejwt.authentication.JWTAuthentication',), 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', 'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer']}

SPECTACULAR_SETTINGS = {'TITLE': 'TripSync API', 'DESCRIPTION': 'TripSync - API Documentation', 'VERSION': '1.0.0', 'SERVE_INCLUDE_SCHEMA': False, 'CONTACT': {'name': 'TripSync Support', 'email': 'support@tripsync.com'}, 'LICENSE': {'name': 'MIT License'}, 'TAGS': [{'name': 'Authentication', 'description': 'User registration, login and token management'}, {'name': 'Password Reset', 'description': 'Password reset functionality with OTP'}, {'name': 'User Management', 'description': 'User profile and management endpoints'}], 'SERVERS': [{'url': 'http://127.0.0.1:8000', 'description': 'Development server'}, {'url': 'https://tripsync-backend-ruak.onrender.com', 'description': 'Production server'}], 'COMPONENT_SPLIT_REQUEST': True, 'SWAGGER_UI_SETTINGS': {'deepLinking': True, 'persistAuthorization': True, 'displayOperationId': False, 'filter': True}}
SPECTACULAR_SETTINGS = {'TITLE': 'TripSync API', 'DESCRIPTION': 'TripSync - API Documentation', 'VERSION': '1.0.0', 'SERVE_INCLUDE_SCHEMA': False, 'CONTACT': {'name': 'TripSync Support', 'email': 'support@tripsync.com'}, 'LICENSE': {'name': 'MIT License'}, 'TAGS': [{'name': 'Authentication', 'description': 'User registration, login and token management'}, {'name': 'Password Reset', 'description': 'Password reset functionality with OTP'}], 'SERVERS': [{'url': 'http://127.0.0.1:8000', 'description': 'Development server'}, {'url': 'https://tripsync-backend-ruak.onrender.com', 'description': 'Production server'}], 'COMPONENT_SPLIT_REQUEST': True, 'SWAGGER_UI_SETTINGS': {'deepLinking': True, 'persistAuthorization': True, 'displayOperationId': False, 'filter': True}}

AUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': {'min_length': 8}}, {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}]

Expand Down Expand Up @@ -58,7 +76,7 @@

CORS_ALLOW_METHODS = ['DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT']

CORS_ALLOW_HEADERS = ['accept', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with']
CORS_ALLOW_HEADERS = ['accept', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with','sec-websocket-key','sec-websocket-version','sec-websocket-extensions' ]

if not DEBUG:
SECURE_SSL_REDIRECT = False
Expand All @@ -75,6 +93,12 @@
CSRF_COOKIE_SECURE = False
SESSION_COOKIE_SECURE = False

CSRF_TRUSTED_ORIGINS = [
'http://127.0.0.1:8000',
'http://localhost:8000',
'http://51.20.254.52'
]

SENDGRID_API_KEY = config('SENDGRID_API_KEY', default='')
DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', default='TripSync <noreply@example.com>')
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
Expand Down
6 changes: 1 addition & 5 deletions auth/auth/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.http import JsonResponse
from django.conf import settings
from django.conf.urls.static import static

@api_view(['GET'])
def root_redirect(request):
Expand All @@ -22,10 +20,8 @@ def health_check(request):
path('health/', health_check, name='health-check'),
path('admin/', admin.site.urls),
path('api/account/', include('account.urls')),
path('api/chat/', include('chat.urls')),
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root = settings.STATIC_URL)
Empty file added auth/chat/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions auth/chat/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.contrib import admin
from .models import *

admin.site.register(Conversation)
admin.site.register(Message)
6 changes: 6 additions & 0 deletions auth/chat/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ChatConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'chat'
Loading