Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
38 changes: 37 additions & 1 deletion backend/rewire/admin/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
'rest_framework',
'core',
'rest_framework_simplejwt',
'corsheaders'

]

Expand All @@ -60,6 +61,7 @@
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware'
]

ROOT_URLCONF = 'admin.urls'
Expand Down Expand Up @@ -146,7 +148,7 @@

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Email settings
# Email settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
Expand All @@ -160,3 +162,37 @@
'rest_framework.authentication.SessionAuthentication',
]
}

# CORS Settings
CORS_ALLOW_ALL_ORIGINS = False

CORS_ALLOWED_ORIGINS = [
"http://localhost:8081",
"http://127.0.0.1:8081",
"http://localhost:8000",
"http://127.0.0.1:8000",
]

CORS_ALLOW_CREDENTIALS = True


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",
]
4 changes: 2 additions & 2 deletions backend/rewire/admin/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
path('login', login_user),
path('delete-user', delete_user),
path('update-user', update_user),
path('forget-password', forget_password),
path('reset-password', reset_password),
path('forget-password/', forget_password),
path('reset-password/<str:uidb64>/<str:token>/', reset_password, name='password_reset_confirm'),
path('questionnaire/', include('questionnaire.urls')),
path('recommendations/', include('recommendations.urls')),
path('aiprofile/', include('aiprofile.urls')),
Expand Down
53 changes: 40 additions & 13 deletions backend/rewire/admin/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,51 @@ def signup_step_two(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
email = data['email']
password = data['password']
confirm_password = data['confirm_password']

# Get all fields from the request
first_name = data.get('first_name')
last_name = data.get('last_name')
user_name = data.get('user_name')
email = data.get('email')
password = data.get('password')
confirm_password = data.get('confirm_password')

# Validate all required fields
if not all([first_name, last_name, user_name, email, password, confirm_password]):
return JsonResponse({'error': 'All fields are required'}, status=400)

if password != confirm_password:
return JsonResponse({'error': 'Passwords do not match'}, status=400)

signup_data = request.session.get('signup_data')
if not signup_data:
return JsonResponse({'error': 'No data from step one'}, status=400)
# Check if username exists
if User.objects.filter(user_name=user_name).exists():
return JsonResponse({'error': 'Username already exists'}, status=400)

# Check if email exists
if User.objects.filter(email=email).exists():
return JsonResponse({'error': 'Email already exists'}, status=400)

# Create user
user = User.objects.create(
first_name=signup_data['first_name'],
last_name=signup_data['last_name'],
user_name=signup_data['user_name'],
first_name=first_name,
last_name=last_name,
user_name=user_name,
email=email,
password=make_password(password)
)

user.save()

return JsonResponse({'message': 'User created successfully'}, status=201)

except KeyError as e:
print(e)
return JsonResponse({'error': 'Invalid data'}, status=400)
return JsonResponse({'error': f'Missing field: {str(e)}'}, status=400)
except json.JSONDecodeError:
return JsonResponse({'error': 'Invalid JSON format'}, status=400)
except Exception as e:
print(f"Error in signup step two: {str(e)}")
return JsonResponse({'error': str(e)}, status=500)
else:
return JsonResponse({'error': 'Invalid HTTP method'}, status=405)

Expand Down Expand Up @@ -153,7 +173,8 @@ def forget_password(request):
user = User.objects.filter(email=email).first()
token = default_token_generator.make_token(user)
uid = urlsafe_base64_encode(force_bytes(user.pk))
reset_link = f"http://localhost:8000/reset_password/{uid}/{token}/"

reset_link = f"http://localhost:8081/reset_password/{uid}/{token}/"

send_mail(
'Reset your password for rewire',
Expand All @@ -173,8 +194,14 @@ def forget_password(request):

@api_view(['POST'])
@csrf_exempt
def reset_password(request, uidb64, token):
if request.method == 'POST':
def reset_password(request, uidb64=None, token=None):
# Now the function can handle both the form submission and the link validation
if request.method == 'GET':
# This is when the user clicks the link
# You can return a response or redirect to frontend
return JsonResponse({'valid': True, 'uidb64': uidb64, 'token': token})
elif request.method == 'POST':
# Original password reset logic
try:
data = json.loads(request.body)
new_password = data['new_password']
Expand Down
1 change: 1 addition & 0 deletions backend/rewire/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ cryptography==44.0.2
daphne==4.1.2
distro==1.9.0
Django==5.1.6
django-cors-headers==4.2.0
djangorestframework==3.15.2
djangorestframework_simplejwt==5.4.0
h11==0.14.0
Expand Down
82 changes: 76 additions & 6 deletions frontend/App.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from 'react';
import React, { useEffect, useRef } from 'react';
import { Icon } from './app/fragments/icon';
import { useLogin } from './app/hooks/login-service';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { ThemeProvider, useThemeToggle } from './app/hooks/theme-service';
import { SafeAreaView, Platform, StatusBar } from 'react-native';
import { SafeAreaView, Platform, StatusBar, Linking } from 'react-native';

import Home from './app/screens/tabs/Home';
import Login from './app/screens/Login';
Expand All @@ -16,23 +16,88 @@ import RebotWelcome from './app/screens/RebotWelcome';
import SignupStepOne from './app/screens/signupStepOne';
import SignupStepTwo from './app/screens/signupStepTwo';
import ForgotPassword from './app/screens/ForgotPassword';
import ResetPassword from './app/screens/ResetPassword';
import RebotChatInterface from './app/screens/RebotChatInterface';
import Settings from './app/screens/Settings';
import About from './app/screens/About';
import PrivacyPolicy from './app/screens/PrivacyPolicy';
import TermsAndConditions from './app/screens/TermsAndConditions';
import { AuthProvider } from './app/hooks/login-service';

export default function App() {
return (
<ThemeProvider>
<AppContent />
</ThemeProvider>
<AuthProvider>
<ThemeProvider>
<AppContent />
</ThemeProvider>
</AuthProvider>
);
}

function AppContent() {
const { loggedIn } = useLogin();
const { theme } = useThemeToggle();
const navigationRef = useRef(null);

// Configuration for linking
const linking = {
prefixes: ['rewire://', 'https://rewire.app', 'http://localhost:8000'],
config: {
screens: {
ResetPassword: {
path: 'reset_password/:uidb64/:token',
parse: {
uidb64: (uidb64) => uidb64,
token: (token) => token,
},
},
},
},
};

// Handle deep links manually for more control (optional)
useEffect(() => {
// Function to handle incoming links
const handleDeepLink = ({ url }) => {
if (!url) return;

// Parse the URL to extract the path and parameters
try {
const parsedUrl = new URL(url);
const pathSegments = parsedUrl.pathname.split('/').filter(Boolean);

// Check if this is a reset password link
if (pathSegments.length >= 3 && pathSegments[0] === 'reset_password') {
const uidb64 = pathSegments[1];
const token = pathSegments[2];

// Navigate to the ResetPassword screen with extracted parameters
if (navigationRef.current) {
navigationRef.current.navigate('ResetPassword', { uidb64, token });
}
}
} catch (error) {
console.error('Error handling deep link:', error);
}
};

// Listen for incoming links when the app is already running
const subscription = Linking.addEventListener('url', handleDeepLink);

// Check for any initial URL used to open the app
Linking.getInitialURL().then(url => {
if (url) {
handleDeepLink({ url });
}
}).catch(err => {
console.error('Error getting initial URL:', err);
});

// Clean up the event listener on unmount
return () => {
subscription.remove();
};
}, []);

return (
<SafeAreaView
Expand All @@ -42,7 +107,11 @@ function AppContent() {
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
}}
>
<NavigationContainer theme={theme}>
<NavigationContainer
ref={navigationRef}
theme={theme}
linking={linking}
>
{loggedIn ? <BottomTabNavigator /> : <LoginNavigator />}
</NavigationContainer>
</SafeAreaView>
Expand Down Expand Up @@ -101,6 +170,7 @@ function LoginNavigator() {
<LoginStack.Screen name="Welcome" component={Welcome} />
<LoginStack.Screen name="Login" component={Login} />
<LoginStack.Screen name="ForgotPassword" component={ForgotPassword} />
<LoginStack.Screen name="ResetPassword" component={ResetPassword} />
<LoginStack.Screen name="SignupStepOne" component={SignupStepOne} />
<LoginStack.Screen name="SignupStepTwo" component={SignupStepTwo} />
<LoginStack.Screen name="MainApp" component={BottomTabNavigator} />
Expand Down
41 changes: 18 additions & 23 deletions frontend/app/app.settings.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
/**
* App Configuration
* -----------------
* This file contains all development-level app configurations.
* Not to be confused with user-configurable app settings like theme preferences.
*
* Note:
* To connect to a local backend instead of production: Set isProduction to false
*/
Comment on lines -1 to -9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to remove this


const isProduction = false;

const DOMAINS = {
Expand All @@ -16,26 +6,31 @@ const DOMAINS = {
};

const PORTS = {
production: 8000,
production: 8081,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be 8000

local: 8000
};

const BACKEND_DOMAIN = isProduction ? DOMAINS.production : DOMAINS.local;
const BACKEND_PORT = isProduction ? PORTS.production : PORTS.local;
const BACKEND_URL = `${BACKEND_DOMAIN}:${BACKEND_PORT}`;

interface Setting {
isUserVisible: boolean;
value: string | number | object;
}
const BACKEND_URL = `http://${BACKEND_DOMAIN}:${BACKEND_PORT}`;

interface Settings {
[key: string]: Setting;
}

export const settings: Settings = {
export const settings = {
rebotWebsocket: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interfaces should not be removed, since this is typescript file

isUserVisible: false,
value: `ws://${BACKEND_URL}/ws/rebot`
Copy link
Member

@isuruK2003 isuruK2003 Mar 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 15 change affects line 20. So change it to ws://${BACKEND_DOMAIN}:${BACKEND_PORT}/ws/rebot

},
};
apiBaseUrl: {
isUserVisible: false,
value: BACKEND_URL
},
authEndpoints: {
isUserVisible: false,
value: {
login: "/login",
signupStepOne: "/signup/step-one",
signupStepTwo: "/signup/step-two",
forgotPassword: "/forget-password/",
resetPassword: "/reset-password"
Comment on lines +29 to +33
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to be prefixed with the port and backend url. Like login: '${BACKEND_URL}/login'

}
}
};
Binary file added frontend/app/assets/eye-closed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/app/assets/eye-open.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading