OHO-7(Entire Fetching Emails)

This commit is contained in:
lokeshramchand-ctrl 2025-08-15 13:57:26 +05:30
parent 0558ae9fd7
commit 185cd14252
3 changed files with 304 additions and 33 deletions

View file

@ -7,6 +7,7 @@ const passport = require('passport');
const session = require('express-session'); const session = require('express-session');
const GoogleStrategy = require('passport-google-oauth20').Strategy; const GoogleStrategy = require('passport-google-oauth20').Strategy;
const { OAuth2Client } = require('google-auth-library'); const { OAuth2Client } = require('google-auth-library');
const { google } = require('googleapis');
const app = express(); const app = express();
app.use(express.json()); app.use(express.json());
@ -203,6 +204,66 @@ app.get('/api/transactions/recent', async (req, res) => {
} }
}); });
// Bank rules (can expand later)
const bankRules = [
{ name: 'HDFC Bank', email: 'alerts@hdfcbank.net' },
// { name: 'ICICI Bank', email: 'alerts@icicibank.com' }, // example expansion
];
// ✅ Gmail fetch function
async function fetchBankEmails(accessToken, bankEmails) {
const oauth2Client = new google.auth.OAuth2();
oauth2Client.setCredentials({ access_token: accessToken });
const gmail = google.gmail({ version: 'v1', auth: oauth2Client });
const allEmails = [];
for (const bankEmail of bankEmails) {
const res = await gmail.users.messages.list({
userId: 'me',
q: `from:${bankEmail}`,
maxResults: 20, // can adjust
});
const messages = res.data.messages || [];
for (const msg of messages) {
const fullMessage = await gmail.users.messages.get({
userId: 'me',
id: msg.id,
});
const snippet = fullMessage.data.snippet || "";
allEmails.push({
from: bankEmail,
snippet,
});
}
}
return allEmails;
}
// ✅ Gmail sync route
app.post('/api/sync-gmail', async (req, res) => {
try {
const { accessToken } = req.body;
if (!accessToken) {
return res.status(400).json({ error: "Missing access token" });
}
const bankEmails = bankRules.map(b => b.email);
const emails = await fetchBankEmails(accessToken, bankEmails);
res.json({ success: true, emails });
} catch (error) {
console.error('❌ Gmail fetch error:', error);
res.status(500).json({ error: 'Failed to fetch Gmail messages' });
}
});
/* ---------- SERVER ---------- */ /* ---------- SERVER ---------- */
mongoose.connect(process.env.MONGO_URI, { mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true, useNewUrlParser: true,

89
Frontend/lib/email.dart Normal file
View file

@ -0,0 +1,89 @@
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class EmailsScreen extends StatefulWidget {
final String accessToken;
final String userId;
const EmailsScreen({
super.key,
required this.accessToken,
required this.userId,
});
@override
State<EmailsScreen> createState() => _EmailsScreenState();
}
class _EmailsScreenState extends State<EmailsScreen> {
List<dynamic> _emails = [];
bool _loading = true;
String? _error;
@override
void initState() {
super.initState();
fetchEmails();
}
Future<void> fetchEmails() async {
try {
final uri = Uri.parse("http://192.168.1.10:3000/api/sync-gmail");
final res = await http.post(
uri,
headers: {"Content-Type": "application/json"},
body: jsonEncode({"accessToken": widget.accessToken}),
);
if (res.statusCode == 200) {
final data = jsonDecode(res.body);
setState(() {
_emails = data['emails'] ?? [];
_loading = false;
});
} else {
setState(() {
_error = "Backend error: ${res.body}";
_loading = false;
});
}
} catch (e) {
setState(() {
_error = "⚠ Error fetching emails: $e";
_loading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Bank Emails"),
actions: [
IconButton(icon: const Icon(Icons.refresh), onPressed: fetchEmails),
],
),
body:
_loading
? const Center(child: CircularProgressIndicator())
: _error != null
? Center(child: Text(_error!))
: _emails.isEmpty
? const Center(child: Text("No bank-related emails found."))
: ListView.builder(
itemCount: _emails.length,
itemBuilder: (context, index) {
final email = _emails[index];
return ListTile(
title: Text(email['subject'] ?? "No subject"),
subtitle: Text(email['snippet'] ?? ""),
leading: const Icon(Icons.email),
);
},
),
);
}
}

View file

@ -1,12 +1,124 @@
// // ignore_for_file: use_build_context_synchronously
// import 'package:flutter/material.dart';
// import 'package:google_sign_in/google_sign_in.dart';
// import 'package:http/http.dart' as http;
// import 'package:monarch/email.dart';
// import 'package:monarch/other_pages/enviroment.dart';
// import 'dart:convert';
// import 'package:shared_preferences/shared_preferences.dart';
// import 'package:monarch/main_pages/HomePage/homepage.dart';
// class LoginScreen extends StatefulWidget {
// const LoginScreen({super.key});
// @override
// State<LoginScreen> createState() => _LoginScreenState();
// }
// class _LoginScreenState extends State<LoginScreen> {
// // GoogleSignIn instance
// final GoogleSignIn _googleSignIn = GoogleSignIn(
// scopes: ['email', 'profile', 'openid'],
// serverClientId: '${Environment.serverClientId}',
// );
// bool _isLoading = false;
// Future<void> _handleGoogleSignIn() async {
// setState(() => _isLoading = true);
// try {
// // Step 1: Trigger the sign-in flow
// final GoogleSignInAccount? account = await _googleSignIn.signIn();
// if (account == null) {
// // User cancelled
// setState(() => _isLoading = false);
// return;
// }
// // Step 2: Get authentication tokens
// final GoogleSignInAuthentication auth = await account.authentication;
// final String? idToken = auth.idToken;
// if (idToken == null) {
// debugPrint("❌ Failed to get ID token");
// return;
// }
// // Step 3: Send token to backend
// final uri = Uri.parse("http://192.168.1.10:3000/auth/google/token");
// final res = await http.post(
// uri,
// headers: {"Content-Type": "application/json"},
// body: jsonEncode({"idToken": idToken}),
// );
// if (res.statusCode == 200) {
// final data = jsonDecode(res.body);
// if (data['success'] == true) {
// debugPrint("✅ User logged in: ${data['user']}");
// final prefs = await SharedPreferences.getInstance();
// prefs.setString('userId', data['user']['_id']);
// Navigator.pushReplacement(
// context,
// MaterialPageRoute(builder: (_) => const EmailsScreen(accessToken: '', userId: 'userId',)),
// );
// } else {
// debugPrint("❌ Login failed: ${data['error']}");
// }
// } else {
// debugPrint("❌ Backend error: ${res.body}");
// }
// } catch (e) {
// debugPrint("⚠ Google Sign-In error: $e");
// } finally {
// setState(() => _isLoading = false);
// }
// }
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// backgroundColor: Colors.white,
// body: Center(
// child:
// _isLoading
// ? const CircularProgressIndicator()
// : ElevatedButton.icon(
// style: ElevatedButton.styleFrom(
// backgroundColor: Colors.white,
// foregroundColor: Colors.black,
// padding: const EdgeInsets.symmetric(
// vertical: 12,
// horizontal: 20,
// ),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(30),
// side: const BorderSide(color: Colors.grey),
// ),
// ),
// label: const Text(
// 'Sign in with Google',
// style: TextStyle(fontSize: 16),
// ),
// onPressed: _handleGoogleSignIn,
// ),
// ),
// );
// }
// }
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart'; import 'package:google_sign_in/google_sign_in.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:monarch/email.dart';
import 'package:monarch/other_pages/enviroment.dart'; import 'package:monarch/other_pages/enviroment.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:monarch/main_pages/HomePage/homepage.dart';
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
const LoginScreen({super.key}); const LoginScreen({super.key});
@ -16,10 +128,14 @@ class LoginScreen extends StatefulWidget {
} }
class _LoginScreenState extends State<LoginScreen> { class _LoginScreenState extends State<LoginScreen> {
// GoogleSignIn instance
final GoogleSignIn _googleSignIn = GoogleSignIn( final GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: ['email', 'profile', 'openid'], scopes: [
serverClientId: '${Environment.serverClientId}', 'email',
'profile',
'openid',
'https://www.googleapis.com/auth/gmail.readonly'
],
serverClientId: Environment.serverClientId,
); );
bool _isLoading = false; bool _isLoading = false;
@ -28,25 +144,24 @@ class _LoginScreenState extends State<LoginScreen> {
setState(() => _isLoading = true); setState(() => _isLoading = true);
try { try {
// Step 1: Trigger the sign-in flow
final GoogleSignInAccount? account = await _googleSignIn.signIn(); final GoogleSignInAccount? account = await _googleSignIn.signIn();
if (account == null) { if (account == null) {
// User cancelled
setState(() => _isLoading = false); setState(() => _isLoading = false);
return; return;
} }
// Step 2: Get authentication tokens
final GoogleSignInAuthentication auth = await account.authentication; final GoogleSignInAuthentication auth = await account.authentication;
final String? idToken = auth.idToken;
if (idToken == null) { final String? idToken = auth.idToken;
debugPrint("❌ Failed to get ID token"); final String? accessToken = auth.accessToken;
if (idToken == null || accessToken == null) {
debugPrint("❌ Failed to get tokens");
return; return;
} }
// Step 3: Send token to backend // Send idToken to backend for login
final uri = Uri.parse("http://192.168.1.10:3000/auth/google/token"); final uri = Uri.parse("http://192.168.1.10:3000/auth/google/token");
final res = await http.post( final res = await http.post(
uri, uri,
@ -57,12 +172,19 @@ class _LoginScreenState extends State<LoginScreen> {
if (res.statusCode == 200) { if (res.statusCode == 200) {
final data = jsonDecode(res.body); final data = jsonDecode(res.body);
if (data['success'] == true) { if (data['success'] == true) {
debugPrint("✅ User logged in: ${data['user']}");
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setString('userId', data['user']['_id']); prefs.setString('userId', data['user']['_id']);
prefs.setString('accessToken', accessToken);
// Navigate directly to EmailsScreen with accessToken
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
MaterialPageRoute(builder: (_) => const FinTrackHomePage()), MaterialPageRoute(
builder: (_) => EmailsScreen(
accessToken: accessToken,
userId: data['user']['_id'],
),
),
); );
} else { } else {
debugPrint("❌ Login failed: ${data['error']}"); debugPrint("❌ Login failed: ${data['error']}");
@ -82,30 +204,29 @@ class _LoginScreenState extends State<LoginScreen> {
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: Center( body: Center(
child: child: _isLoading
_isLoading ? const CircularProgressIndicator()
? const CircularProgressIndicator() : ElevatedButton.icon(
: ElevatedButton.icon( style: ElevatedButton.styleFrom(
style: ElevatedButton.styleFrom( backgroundColor: Colors.white,
backgroundColor: Colors.white, foregroundColor: Colors.black,
foregroundColor: Colors.black, padding: const EdgeInsets.symmetric(
padding: const EdgeInsets.symmetric( vertical: 12,
vertical: 12, horizontal: 20,
horizontal: 20,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
side: const BorderSide(color: Colors.grey),
),
), ),
shape: RoundedRectangleBorder(
label: const Text( borderRadius: BorderRadius.circular(30),
'Sign in with Google', side: const BorderSide(color: Colors.grey),
style: TextStyle(fontSize: 16),
), ),
onPressed: _handleGoogleSignIn,
), ),
label: const Text(
'Sign in with Google',
style: TextStyle(fontSize: 16),
),
onPressed: _handleGoogleSignIn,
),
), ),
); );
} }
} }