using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Web; using System.Web.Mvc; using instavibe.Models; using InstaVibe.Models; using System.Configuration; using MailKit.Net.Smtp; using MailKit.Security; using MimeKit; using MimeKit.Text; namespace InstaVibe.Controllers { public class AccountController : Controller { public string connectionString = ConfigurationManager.ConnectionStrings["InstaVibe"].ConnectionString.ToString(); private DatabaseHelper db = new DatabaseHelper(); public ActionResult Index() { return View("~/Views/Account/Login.cshtml"); } public ActionResult Login(string role) { ViewBag.Role = string.IsNullOrWhiteSpace(role) ? "Student" : role; return View("~/Views/Account/Login.cshtml"); } // User login process [HttpPost] public ActionResult UserLogin(User model) { if (model != null) { if (string.IsNullOrEmpty(model.LoginInput)) { TempData["ErrorMessage"] = "Email or Username cannot be empty."; return View(model); } User user = db.GetUserByEmailOrUsername(model.LoginInput); if (user != null && user.Password == model.Password) { // Check if user is approved by admin if (!user.IsApproved) { TempData["ErrorMessage"] = "Your account is pending admin approval. Please wait for approval to login."; return View("Login", model); } // Login success - user is approved // 🔥 Student → Alumni auto update UpdateStudentAlumniStatus(user); Session["UserId"] = user.UserId; Session["Username"] = user.Username; Session["FullName"] = user.FullName; UpdateUserStatus(user.UserId, true); TempData["SuccessMessage"] = "Welcome, " + user.Username + "!"; return RedirectToAction("Index", "Home"); } // If not found in Users, try Staff login (so staff can login from same screen) using (SqlConnection con = new SqlConnection(connectionString)) { string staffQuery = @"SELECT staff_id, username, assigned_roles FROM Staffs WHERE (username=@input OR email=@input) AND password=@pass"; using (SqlCommand cmd = new SqlCommand(staffQuery, con)) { cmd.Parameters.AddWithValue("@input", model.LoginInput.Trim()); cmd.Parameters.AddWithValue("@pass", model.Password); con.Open(); using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { Session["StaffId"] = Convert.ToInt32(reader["staff_id"]); Session["StaffUsername"] = reader["username"].ToString(); Session["StaffRoles"] = reader["assigned_roles"] == DBNull.Value ? "" : reader["assigned_roles"].ToString(); return RedirectToAction("Dashboard", "Staff"); } } } } TempData["ErrorMessage"] = "Invalid username/email or password."; } return View("Login", model); } // ============================================= // STAFF SIGNUP + LOGIN // ============================================= [HttpGet] public ActionResult StaffRegister() { return View("~/Views/Account/StaffRegister.cshtml"); } [HttpPost] public ActionResult StaffRegister(string username, string email, string password, string confirmPassword) { if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password)) { TempData["ErrorMessage"] = "All fields are required."; return RedirectToAction("StaffRegister"); } if (password != confirmPassword) { TempData["ErrorMessage"] = "Passwords do not match."; return RedirectToAction("StaffRegister"); } using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); // Ensure unique username/email in Staffs string check = "SELECT COUNT(*) FROM Staffs WHERE username=@u OR email=@e"; using (SqlCommand checkCmd = new SqlCommand(check, con)) { checkCmd.Parameters.AddWithValue("@u", username.Trim()); checkCmd.Parameters.AddWithValue("@e", email.Trim()); int exists = Convert.ToInt32(checkCmd.ExecuteScalar()); if (exists > 0) { TempData["ErrorMessage"] = "Username or email already exists."; return RedirectToAction("StaffRegister"); } } string insert = @"INSERT INTO Staffs (username, email, password, assigned_roles, created_at) VALUES (@u, @e, @p, NULL, GETDATE())"; using (SqlCommand cmd = new SqlCommand(insert, con)) { cmd.Parameters.AddWithValue("@u", username.Trim()); cmd.Parameters.AddWithValue("@e", email.Trim()); cmd.Parameters.AddWithValue("@p", password); cmd.ExecuteNonQuery(); } } TempData["SuccessMessage"] = "Staff account created successfully. Please login."; return RedirectToAction("Login", new { role = "Staff" }); } [HttpPost] public ActionResult StaffLogin(string username, string password) { if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)) { TempData["ErrorMessage"] = "Username and password are required."; return RedirectToAction("Login", new { role = "Staff" }); } using (SqlConnection con = new SqlConnection(connectionString)) { string query = @"SELECT staff_id, username, assigned_roles FROM Staffs WHERE username=@u AND password=@p"; using (SqlCommand cmd = new SqlCommand(query, con)) { cmd.Parameters.AddWithValue("@u", username.Trim()); cmd.Parameters.AddWithValue("@p", password); con.Open(); using (var reader = cmd.ExecuteReader()) { if (!reader.Read()) { TempData["ErrorMessage"] = "Invalid staff username or password."; return RedirectToAction("Login", new { role = "Staff" }); } Session["StaffId"] = Convert.ToInt32(reader["staff_id"]); Session["StaffUsername"] = reader["username"].ToString(); Session["StaffRoles"] = reader["assigned_roles"] == DBNull.Value ? "" : reader["assigned_roles"].ToString(); } } } return RedirectToAction("Dashboard", "Staff"); } [HttpGet] public ActionResult ForgetPassword() { return View(); } // Send Reset link [HttpPost] public ActionResult ForgetPassword(ForgetPasswordViewModel model) { if (ModelState.IsValid) { string token = Guid.NewGuid().ToString(); using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); // Verify if email exists string query = "SELECT COUNT(*) FROM Users WHERE email = @Email"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@Email", model.Email); int exists = (int)cmd.ExecuteScalar(); if (exists > 0) { // Save token string updateQuery = @"UPDATE Users SET ResetToken = @Token WHERE email = @Email"; SqlCommand updateCmd = new SqlCommand(updateQuery, con); updateCmd.Parameters.AddWithValue("@Token", token); updateCmd.Parameters.AddWithValue("@Email", model.Email); updateCmd.ExecuteNonQuery(); // Generate reset link string resetLink = Url.Action("ResetPassword", "Account", new { email = model.Email, token = token }, protocol: Request.Url.Scheme); // Send email using MailKit var email = new MimeMessage(); email.From.Add(new MailboxAddress("Insta Vibe", "zayyanali297@gmail.com")); email.To.Add(MailboxAddress.Parse(model.Email)); email.Subject = "Password Reset Request"; email.Body = new TextPart(TextFormat.Plain) { Text = $"Click the link to reset your password:\n{resetLink}" }; using (var smtp = new SmtpClient()) { smtp.Connect("smtp.gmail.com", 587, MailKit.Security.SecureSocketOptions.StartTls); smtp.Authenticate("zayyanali297@gmail.com", "agarwydycpmpnbeo"); smtp.Send(email); smtp.Disconnect(true); } ViewBag.Message = "A reset link has been sent to your email."; } else { ViewBag.Message = "Email not found."; } } } return View(model); } [HttpGet] public ActionResult ResetPassword(string email, string token) { return View(new ResetPasswordViewModel { Email = email, Token = token }); } [HttpPost] public ActionResult ResetPassword(ResetPasswordViewModel model) { if (model.NewPassword != model.ConfirmPassword) { ViewBag.Message = "Passwords do not match!"; return View(model); } using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); SqlCommand cmd = new SqlCommand("UPDATE Users SET Password=@Password, ResetToken=NULL WHERE Email=@Email AND ResetToken=@Token", con); cmd.Parameters.AddWithValue("@Password", model.NewPassword); cmd.Parameters.AddWithValue("@Email", model.Email); cmd.Parameters.AddWithValue("@Token", model.Token); int rows = cmd.ExecuteNonQuery(); if (rows > 0) { ViewBag.Message = "Password updated successfully."; } else { ViewBag.Message = "Invalid or expired token."; } } return RedirectToAction("Login"); } public ActionResult Register() { return View(); } //insert new user into database [HttpPost] public ActionResult Register(User model) { if (model != null) { // 1️⃣ Admin approval default false model.IsApproved = false; // 2️⃣ Registration No se Joining Year nikaalo // Example: 2021-cwr-12 string regNo = model.RegistrationNo; int joiningYear = Convert.ToInt32(regNo.Substring(0, 4)); // 3️⃣ Degree logic (4 years) int currentYear = DateTime.Now.Year; int degreeEndYear = joiningYear + 4; // 4️⃣ Student ya Alumni decide karo string userType; if (currentYear <= degreeEndYear) { userType = "Student"; } else { userType = "Alumni"; } // 5️⃣ Model me values set karo model.JoiningYear = joiningYear; model.UserType = userType; // 6️⃣ Insert user bool isInserted = db.InsertUser(model); if (isInserted) { NotifyAdminNewUser(model); TempData["SuccessMessage"] = "Registration successful! Please wait for admin approval before logging in."; return RedirectToAction("Login", "Account"); } else { TempData["ErrorMessage"] = "Error: Registration failed."; } } return View("Login", model); } // AJAX call to check email availability [HttpPost] public JsonResult IsEmailAvailable(string email) { var existingUser = db.GetUserByEmailOrUsername(email); if (existingUser != null) { return Json(false); // Email already exists } return Json(true); // Email is available } [HttpPost] public JsonResult IsStaffEmailAvailable(string email) { if (string.IsNullOrWhiteSpace(email)) return Json(true); using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); string q = "SELECT COUNT(*) FROM Staffs WHERE email=@e"; using (SqlCommand cmd = new SqlCommand(q, con)) { cmd.Parameters.AddWithValue("@e", email.Trim()); int exists = Convert.ToInt32(cmd.ExecuteScalar()); return Json(exists == 0); } } } public ActionResult Logout() { // Set user offline int userId = Convert.ToInt32(Session["UserId"]); using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); string query = "UPDATE Users SET is_online = 0 WHERE user_id = @userId"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@userId", userId); cmd.ExecuteNonQuery(); } // Clear session Session.Clear(); Session.Abandon(); // Redirect to login return RedirectToAction("Login", "Account"); } // User Online/Offline status private void UpdateUserStatus(int userId, bool isOnline) { using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); SqlCommand cmd = new SqlCommand("UPDATE Users SET is_online = @IsOnline WHERE user_id = @UserId", con); cmd.Parameters.AddWithValue("@IsOnline", isOnline); cmd.Parameters.AddWithValue("@UserId", userId); cmd.ExecuteNonQuery(); } } private void NotifyAdminNewUser(User newUser) { try { // You can implement email notification to admin here // Or add a notification to admin dashboard using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); string query = @"INSERT INTO AdminNotifications (message, created_at, is_read) VALUES (@Message, GETDATE(), 0)"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@Message", $"New user registration: {newUser.Username} ({newUser.Email})"); cmd.ExecuteNonQuery(); } } catch (Exception ex) { // Log error but don't fail registration Console.WriteLine("Failed to notify admin: " + ex.Message); } } // 🔥 AUTO Student → Alumni updater private void UpdateStudentAlumniStatus(User user) { int joiningYear = user.JoiningYear; if (joiningYear <= 0) { joiningYear = ParseJoiningYearFromRegistrationNo(user.RegistrationNo); } // Agar joining year mil hi na paye to galat auto-convert na karo. if (joiningYear <= 0) { return; } int degreeEndYear = joiningYear + 4; string updatedType = DateTime.Now.Year <= degreeEndYear ? "Student" : "Alumni"; if (!string.Equals((user.UserType ?? "").Trim(), updatedType, StringComparison.OrdinalIgnoreCase)) { using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); string updateQuery = @"UPDATE Users SET user_type = @Type WHERE user_id = @Id"; SqlCommand cmd = new SqlCommand(updateQuery, con); cmd.Parameters.AddWithValue("@Type", updatedType); cmd.Parameters.AddWithValue("@Id", user.UserId); cmd.ExecuteNonQuery(); } } } private int ParseJoiningYearFromRegistrationNo(string registrationNo) { if (string.IsNullOrWhiteSpace(registrationNo) || registrationNo.Length < 4) return 0; int year; return int.TryParse(registrationNo.Substring(0, 4), out year) ? year : 0; } } }