using System.Linq; using System.Threading.Tasks; using System.Security.Claims; using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Mvc; using Microsoft.Extensions.Logging; using Yavsc.Models; using Yavsc.Services; using Yavsc.ViewModels.Manage; using Microsoft.Extensions.OptionsModel; using Microsoft.Data.Entity; using System; using PayPal.PayPalAPIInterfaceService; using System.Collections.Generic; using Yavsc.Helpers; using Yavsc.ViewModels.Calendar; using System.Net; using Microsoft.Extensions.Localization; namespace Yavsc.Controllers { [Authorize, ServiceFilter(typeof(LanguageActionFilter))] public class ManageController : Controller { private readonly UserManager _userManager; private readonly SignInManager _signInManager; private readonly IEmailSender _emailSender; private readonly ILogger _logger; private SiteSettings _siteSettings; private ApplicationDbContext _dbContext; private GoogleAuthSettings _googleSettings; private PayPalSettings _payPalSettings; private IGoogleCloudMessageSender _GCMSender; private SIRENChecker _cchecker; private IStringLocalizer _SR; private CompanyInfoSettings _cinfoSettings; public ManageController( ApplicationDbContext context, UserManager userManager, SignInManager signInManager, IEmailSender emailSender, IGoogleCloudMessageSender GCMSender, IOptions siteSettings, IOptions googleSettings, IOptions paypalSettings, IOptions cinfoSettings, IStringLocalizer SR, ILoggerFactory loggerFactory) { _dbContext = context; _userManager = userManager; _signInManager = signInManager; _emailSender = emailSender; _GCMSender = GCMSender; _siteSettings = siteSettings.Value; _googleSettings = googleSettings.Value; _payPalSettings = paypalSettings.Value; _cinfoSettings = cinfoSettings.Value; _cchecker = new SIRENChecker(cinfoSettings.Value); _SR = SR; _logger = loggerFactory.CreateLogger(); } // // GET: /Manage/Index [HttpGet] public async Task Index(ManageMessageId? message = null) { ViewData["StatusMessage"] = message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." : message == ManageMessageId.Error ? "An error has occurred." : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." : message == ManageMessageId.ChangeNameSuccess ? "Your name was updated." : message == ManageMessageId.SetActivitySuccess ? "Your activity was set." : ""; var user = await GetCurrentUserAsync(); long pc = _dbContext.Blogspot.Count(x => x.AuthorId == user.Id); var model = new IndexViewModel { HasPassword = await _userManager.HasPasswordAsync(user), PhoneNumber = await _userManager.GetPhoneNumberAsync(user), TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user), Logins = await _userManager.GetLoginsAsync(user), BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user), UserName = user.UserName, PostsCounter = pc, Balance = user.AccountBalance, ActiveCommandCount = _dbContext.BookQueries.Count(x => (x.ClientId == user.Id) && (x.EventDate > DateTime.Now)), HasDedicatedCalendar = !string.IsNullOrEmpty(user.DedicatedGoogleCalendar) }; if (_dbContext.Performers.Any(x => x.PerfomerId == user.Id)) { var code = _dbContext.Performers.First(x => x.PerfomerId == user.Id).ActivityCode; model.Activity = _dbContext.Activities.First(x => x.Code == code); } return View(model); } // // POST: /Manage/RemoveLogin [HttpPost] [ValidateAntiForgeryToken] public async Task RemoveLogin(RemoveLoginViewModel account) { ManageMessageId? message = ManageMessageId.Error; var user = await GetCurrentUserAsync(); if (user != null) { var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey); if (result.Succeeded) { await _signInManager.SignInAsync(user, isPersistent: false); message = ManageMessageId.RemoveLoginSuccess; } } return RedirectToAction(nameof(ManageLogins), new { Message = message }); } // // GET: /Manage/AddPhoneNumber public IActionResult AddPhoneNumber() { return View(); } // // POST: /Manage/AddPhoneNumber [HttpPost] [ValidateAntiForgeryToken] public async Task AddPhoneNumber(AddPhoneNumberViewModel model) { if (!ModelState.IsValid) { return View(model); } // Generate the token and send it var user = await GetCurrentUserAsync(); var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber); // TODO await _smsSender.SendSmsAsync(_twilioSettings, model.PhoneNumber, "Your security code is: " + code); return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber }); } // // POST: /Manage/EnableTwoFactorAuthentication [HttpPost] [ValidateAntiForgeryToken] public async Task EnableTwoFactorAuthentication() { var user = await GetCurrentUserAsync(); if (user != null) { await _userManager.SetTwoFactorEnabledAsync(user, true); await _signInManager.SignInAsync(user, isPersistent: false); _logger.LogInformation(1, "User enabled two-factor authentication."); } return RedirectToAction(nameof(Index), "Manage"); } // // POST: /Manage/DisableTwoFactorAuthentication [HttpPost] [ValidateAntiForgeryToken] public async Task DisableTwoFactorAuthentication() { var user = await GetCurrentUserAsync(); if (user != null) { await _userManager.SetTwoFactorEnabledAsync(user, false); await _signInManager.SignInAsync(user, isPersistent: false); _logger.LogInformation(2, "User disabled two-factor authentication."); } return RedirectToAction(nameof(Index), "Manage"); } // // GET: /Manage/VerifyPhoneNumber [HttpGet] public async Task VerifyPhoneNumber(string phoneNumber) { var code = await _userManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber); // Send an SMS to verify the phone number return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); } // // POST: /Manage/VerifyPhoneNumber [HttpPost] [ValidateAntiForgeryToken] public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = await GetCurrentUserAsync(); if (user != null) { var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code); if (result.Succeeded) { await _signInManager.SignInAsync(user, isPersistent: false); return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess }); } } // If we got this far, something failed, redisplay the form ModelState.AddModelError(string.Empty, "Failed to verify phone number"); return View(model); } // // GET: /Manage/RemovePhoneNumber [HttpGet] public async Task RemovePhoneNumber() { var user = await GetCurrentUserAsync(); if (user != null) { var result = await _userManager.SetPhoneNumberAsync(user, null); if (result.Succeeded) { await _signInManager.SignInAsync(user, isPersistent: false); return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess }); } } return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); } // // GET: /Manage/ChangePassword [HttpGet] public IActionResult ChangePassword() { return View(); } [HttpGet] public IActionResult AddMobileApp(GoogleCloudMobileDeclaration model) { return View(); } [HttpGet, Authorize] public async Task SetGoogleCalendar(string returnUrl) { var credential = await _userManager.GetCredentialForGoogleApiAsync( _dbContext, User.GetUserId()); if (credential==null) return RedirectToAction("LinkLogin",new { provider = "Google" }); try { ViewBag.Calendars = new GoogleApis.CalendarApi(_googleSettings.ApiKey) .GetCalendars(credential); } catch (WebException ex) { // a bug _logger.LogError("Google token, an Forbidden calendar"); if (ex.HResult == (int) HttpStatusCode.Forbidden) { return RedirectToAction("LinkLogin",new { provider = "Google" }); } } return View(new SetGoogleCalendarViewModel { ReturnUrl=returnUrl }); } [HttpPost,ValidateAntiForgeryToken, Authorize] public async Task SetGoogleCalendar(SetGoogleCalendarViewModel model) { var user = _dbContext.Users.FirstOrDefault(u=>u.Id == User.GetUserId()); user.DedicatedGoogleCalendar = model.GoogleCalendarId; await _dbContext.SaveChangesAsync(); if (string.IsNullOrEmpty(model.ReturnUrl)) return RedirectToAction("Index"); else return Redirect(model.ReturnUrl); } // // POST: /Manage/ChangePassword [HttpPost] [ValidateAntiForgeryToken] public async Task ChangePassword(ChangePasswordViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = await GetCurrentUserAsync(); if (user != null) { var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); if (result.Succeeded) { await _signInManager.SignInAsync(user, isPersistent: false); _logger.LogInformation(3, "User changed their password successfully."); return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess }); } AddErrors(result); return View(model); } return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); } // // GET: /Manage/ChangeUserName public IActionResult ChangeUserName() { return View(new ChangeUserNameViewModel() { NewUserName = User.Identity.Name }); } public IActionResult CHUN() { return View(new ChangeUserNameViewModel() { NewUserName = User.Identity.Name }); } [HttpPost] public async Task CHUN(ChangeUserNameViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = await GetCurrentUserAsync(); if (user != null) { var oldUserName = user.UserName; var result = await this._userManager.SetUserNameAsync(user, model.NewUserName); if (result.Succeeded) { /* Obsolete : files are no more prefixed using the user name. var userdirinfo = new DirectoryInfo( Path.Combine(_siteSettings.UserFiles.DirName, oldUserName)); var newdir = Path.Combine(_siteSettings.UserFiles.DirName, model.NewUserName); if (userdirinfo.Exists) userdirinfo.MoveTo(newdir); */ await _signInManager.SignInAsync(user, isPersistent: false); _logger.LogInformation(3, "User changed his user name successfully."); return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangeNameSuccess }); } AddErrors(result); return View(model); } return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); } // // GET: /Manage/SetPassword [HttpGet] public IActionResult SetPassword() { return View(); } // // POST: /Manage/SetPassword [HttpPost] [ValidateAntiForgeryToken] public async Task SetPassword(SetPasswordViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = await GetCurrentUserAsync(); if (user != null) { var result = await _userManager.AddPasswordAsync(user, model.NewPassword); if (result.Succeeded) { await _signInManager.SignInAsync(user, isPersistent: false); return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess }); } AddErrors(result); return View(model); } return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); } //GET: /Manage/ManageLogins [HttpGet] public async Task ManageLogins(ManageMessageId? message = null) { ViewData["StatusMessage"] = message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." : message == ManageMessageId.AddLoginSuccess ? "The external login was added." : message == ManageMessageId.Error ? "An error has occurred." : ""; var user = await GetCurrentUserAsync(); if (user == null) { return View("Error"); } var userLogins = await _userManager.GetLoginsAsync(user); var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList(); ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1; return View(new ManageLoginsViewModel { CurrentLogins = userLogins, OtherLogins = otherLogins }); } // // POST: /Manage/LinkLogin [HttpPost] [ValidateAntiForgeryToken] public IActionResult LinkLogin(string provider) { // Request a redirect to the external login provider to link a login for the current user var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, User.GetUserId()); return new ChallengeResult(provider, properties); } // // GET: /Manage/LinkLoginCallback [HttpGet] public async Task LinkLoginCallback() { var user = await GetCurrentUserAsync(); if (user == null) { return View("Error"); } var info = await _signInManager.GetExternalLoginInfoAsync(User.GetUserId()); if (info == null) { return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error }); } var result = await _userManager.AddLoginAsync(user, info); var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error; return RedirectToAction(nameof(ManageLogins), new { Message = message }); } [HttpGet, Authorize] public IActionResult SetActivity() { var user = GetCurrentUserAsync().Result; var uid = user.Id; bool existing = _dbContext.Performers.Any(x => x.PerfomerId == uid); ViewBag.Activities = _dbContext.ActivityItems(null); ViewBag.GoogleSettings = _googleSettings; if (existing) { var currentProfile = _dbContext.Performers.Include(x => x.OrganisationAddress) .First(x => x.PerfomerId == uid); string currentCode = currentProfile.ActivityCode; return View(currentProfile); } return View(new PerformerProfile { PerfomerId = user.Id, OrganisationAddress = new Location() }); } [HttpPost] [ValidateAntiForgeryToken, Authorize] public async Task SetActivity(PerformerProfile model) { var user = GetCurrentUserAsync().Result; var uid = user.Id; if (ModelState.IsValid) { var taskCheck = await _cchecker.CheckAsync(model.SIREN); if (!taskCheck.success) { ModelState.AddModelError( "SIREN", _SR["Invalid company number"]+" ("+taskCheck.errorCode+")" ); _logger.LogWarning("Invalid company number, using key:"+_cinfoSettings.ApiKey); } } if (ModelState.IsValid) { if (uid == model.PerfomerId) { bool addrexists = _dbContext.Map.Any(x => model.OrganisationAddress.Id == x.Id); if (!addrexists) { _dbContext.Map.Add(model.OrganisationAddress); } bool existing = _dbContext.Performers.Any(x => x.PerfomerId == uid); if (existing) { _dbContext.Update(model); } else _dbContext.Performers.Add(model); _dbContext.SaveChanges(); var message = ManageMessageId.SetActivitySuccess; return RedirectToAction(nameof(Index), new { Message = message }); } else ModelState.AddModelError(string.Empty, "Acces denied"); } ViewBag.GoogleSettings = _googleSettings; ViewBag.Activities = _dbContext.ActivityItems(model.ActivityCode); return View(model); } [HttpPost, Authorize] public IActionResult UnsetActivity() { var user = GetCurrentUserAsync().Result; var uid = user.Id; bool existing = _dbContext.Performers.Any(x => x.PerfomerId == uid); if (existing) { _dbContext.Performers.Remove( _dbContext.Performers.First(x => x.PerfomerId == uid) ); _dbContext.SaveChanges(); } var message = ManageMessageId.UnsetActivitySuccess; return RedirectToAction(nameof(Index), new { Message = message }); } [HttpGet, Route("/Manage/Credits")] public IActionResult Credits() { Dictionary config = new Dictionary(); config.Add("mode", "sandbox"); config.Add("account1.apiUsername", _payPalSettings.UserId); config.Add("account1.apiPassword", _payPalSettings.Secret); config.Add("account1.apiSignature", _payPalSettings.Signature); PayPalAPIInterfaceServiceService s = new PayPalAPIInterfaceServiceService(config); return View(); } #region Helpers private void AddErrors(IdentityResult result) { foreach (var error in result.Errors) { ModelState.AddModelError(string.Empty, error.Description); } } public enum ManageMessageId { AddPhoneSuccess, AddLoginSuccess, ChangePasswordSuccess, ChangeNameSuccess, SetTwoFactorSuccess, SetPasswordSuccess, RemoveLoginSuccess, RemovePhoneSuccess, SetActivitySuccess, UnsetActivitySuccess, Error } private async Task GetCurrentUserAsync() { return await _userManager.FindByIdAsync(HttpContext.User.GetUserId()); } #endregion } }