commit 69b9e69f00731da48d6565e66b07dfc0239c6ee3 Author: amoussa1229 Date: Sat Sep 28 14:58:36 2024 -0400 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f20ab7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,364 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd +/SeaHavenIndustries/wwwroot/ChromeEx/Win_x64_1000083_chrome-win/chrome-win diff --git a/Api.SeaHavenIndustries/.config/dotnet-tools.json b/Api.SeaHavenIndustries/.config/dotnet-tools.json new file mode 100644 index 0000000..9fab42f --- /dev/null +++ b/Api.SeaHavenIndustries/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "8.0.8", + "commands": [ + "dotnet-ef" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/Api.SeaHavenIndustries/Api.SeaHavenIndustries.csproj b/Api.SeaHavenIndustries/Api.SeaHavenIndustries.csproj new file mode 100644 index 0000000..82190f7 --- /dev/null +++ b/Api.SeaHavenIndustries/Api.SeaHavenIndustries.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/Api.SeaHavenIndustries/Api.SeaHavenIndustries.http b/Api.SeaHavenIndustries/Api.SeaHavenIndustries.http new file mode 100644 index 0000000..d259751 --- /dev/null +++ b/Api.SeaHavenIndustries/Api.SeaHavenIndustries.http @@ -0,0 +1,6 @@ +@Api.SeaHavenIndustries_HostAddress = http://localhost:5141 + +GET {{Api.SeaHavenIndustries_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/Api.SeaHavenIndustries/Controllers/AuthenticationController.cs b/Api.SeaHavenIndustries/Controllers/AuthenticationController.cs new file mode 100644 index 0000000..bc9f44d --- /dev/null +++ b/Api.SeaHavenIndustries/Controllers/AuthenticationController.cs @@ -0,0 +1,253 @@ +using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Net.Mail; +using System.Net; +using System.Security.Claims; +using System.Text; +using Api.SeaHavenIndustries.DTOs; +using Microsoft.EntityFrameworkCore; +using System.Diagnostics; + +namespace Api.SeaHavenIndustries.Controllers +{ + [ApiController] + [Route("[controller]")] + public class AuthenticationController : Controller + { + private readonly UserManager _userManager; + private readonly IConfiguration _configuration; + private readonly ApplicationDbContext _db; + + public AuthenticationController(UserManager userManager, IConfiguration configuration, ApplicationDbContext db, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContext) + { + _userManager = userManager; + _configuration = configuration; + _db = db; + } + + [AllowAnonymous] + [HttpPost] + [Route("login")] + public async Task Login([FromBody] LoginModel model) + { + var user = await _userManager.FindByNameAsync(model.Username ?? ""); + if (user.IsDeleted != true && user != null && await _userManager.CheckPasswordAsync(user, model.Password ?? "")) + { + // Standard login without 2FA + var userRoles = await _userManager.GetRolesAsync(user); + var authClaims = new List + { + new Claim(ClaimTypes.Name, user.UserName ?? ""), + new Claim(ClaimTypes.NameIdentifier, user.Id), + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) + }; + foreach (var userRole in userRoles) + { + authClaims.Add(new Claim(ClaimTypes.Role, userRole)); + } + var token = GetToken(authClaims); + return Ok(new + { + token = new JwtSecurityTokenHandler().WriteToken(token), + expiration = token.ValidTo, + email = user.Email, + userRoles = userRoles.FirstOrDefault(), + phoneNumber = user.PhoneNumber, + fullname = user.FirstName + " " + user.LastName, + id = user.Id + }); + } + + // Invalid credentials + return Unauthorized(); + } + + [Route("ChangePassword")] + [HttpPost] + public async Task ChangePassword(ChangePasswords usermodel) + { + var userid = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? ""; + var user = await _userManager.FindByIdAsync(userid); + var result = await _userManager.ChangePasswordAsync(user, usermodel.Currentpassword ?? "", usermodel.Confirmpassword ?? ""); + if (result.Succeeded) + { + return Ok(new Response { Status = "Success ", Message = "Password successfully changed" }); + } + else + return BadRequest(new Response { Status = "Old Password is incorrect" }); + } + + private JwtSecurityToken GetToken(List authClaims) + { + var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"] ?? "")); + var token = new JwtSecurityToken( + issuer: _configuration["JWT:ValidIssuer"], + audience: _configuration["JWT:ValidAudience"], + expires: DateTime.Now.AddDays(10), + claims: authClaims, + signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256) + ); + return token; + } + + [HttpPost] + [Route("UpdateProfile")] + public async Task UserProfileUpdate([FromForm] User_DTO model) + { + try + { + var userid = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? ""; + ApplicationUser appuser = _db.Users.AsNoTracking().Where(u => u.Id == userid).FirstOrDefault() ?? new ApplicationUser(); + appuser.FirstName = model.Name; + appuser.Email = model.Email; + appuser.Contact = model.Contact; + _db.Users.Update(appuser); + await _db.SaveChangesAsync(); + + return Ok(new DataResponse + { + Message = "Introduction Updated Successfully", + Status = "200", + Data = _db.Users.Where(u => u.Id == userid).Select(s => new + { + s.FirstName, + //s.Location, + s.Email, + s.Contact + }).FirstOrDefault() + }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + #region Forget Password Area + + [AllowAnonymous] + [HttpPost()] + [Route("ForgetPassword")] + public async Task ForgetPassword(string Email) + { + var user = await _db.Users.Where(u => u.Email.ToLower().Trim() == Email.ToLower().ToLower()).FirstOrDefaultAsync(); + if (user != null) + { + if (_db.ForgetPasswordCodes.Where(u => u.Email.ToLower().Trim() == Email.ToLower().Trim()).Any()) + { + _db.ForgetPasswordCodes.Remove(_db.ForgetPasswordCodes.Where(u => u.Email.ToLower().Trim() == Email.ToLower().Trim()).FirstOrDefault()); + _db.SaveChanges(); + } + ForgetPasswordCode forgetPasswordCode = new ForgetPasswordCode(); + forgetPasswordCode.Email = user.Email ?? ""; + forgetPasswordCode.UserId = user.Id; + forgetPasswordCode.Code = GenerateRandomNo(); + + _db.ForgetPasswordCodes.Add(forgetPasswordCode); + _db.SaveChanges(); + string body = $"Your Password Reset Code is: " + forgetPasswordCode.Code; + SendEMail(user.Email, "Forget Password Request.", body); + return Ok(new Response { Status = "Success ", Message = "Please check your email for code" }); + } + else + { + return BadRequest(new Response { Status = "Error", Message = "No such email is registered" }); + } + } + //need email and code + [AllowAnonymous] + [HttpPost()] + [Route("VerificationCode")] + public async Task VerificationCode(string code) + { + try + { + if (await _db.ForgetPasswordCodes.Where(u => u.Code == code).AnyAsync()) + { + + return Ok(new Response { Status = "Success ", Message = "Code Matched" }); + } + else + { + return BadRequest(new Response { Status = "Error", Message = "Code Not Matched" }); + } + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = "Error: " + ex.Message }); + } + } + + // need email, password and code + [AllowAnonymous] + [HttpPost()] + [Route("ResetPassword")] + public async Task ResetPassword(ForgetPassword_Dto fpdto) + { + try + { + if (_db.ForgetPasswordCodes.Where(u => u.Email.ToLower().Trim() == fpdto.Email.ToLower().Trim() && u.Code == fpdto.Code.Trim()).Any()) + { + var GetUser = _db.ForgetPasswordCodes.Where(u => u.Email.ToLower().Trim() == fpdto.Email.ToLower().Trim()).FirstOrDefault(); + var user = await _userManager.FindByIdAsync(GetUser.UserId); + var token = await _userManager.GeneratePasswordResetTokenAsync(user); + var result = await _userManager.ResetPasswordAsync(user, token, fpdto.Password); + return Ok(new Response { Status = "Success ", Message = "password changed" }); + } + else + { + return BadRequest(new Response { Status = "Error", Message = "Your email or code not found please check" }); + } + } + catch (Exception ex) + { + + return BadRequest(new Response { Status = "Error", Message = "Error: " + ex.Message }); + + } + } + + [HttpGet()] + public bool SendEMail(string emailid, string subject, string body) + { + try + { + MailMessage mail = new MailMessage(); + mail.From = new MailAddress("infoesquall@codevoir.com"); //IMPORTANT: This must be same as your smtp authentication address. + mail.To.Add(emailid); + + //set the content + + mail.Subject = subject; + mail.Body = body; + mail.IsBodyHtml = true; + //send the message + SmtpClient smtp = new SmtpClient("mail.codevoir.com"); + + //IMPORANT: Your smtp login email MUST be same as your FROM address. + NetworkCredential Credentials = new NetworkCredential("infoesquall@codevoir.com", "Abc123!@#"); + smtp.UseDefaultCredentials = false; + smtp.Credentials = Credentials; + smtp.Port = 8889; //25 alternative port number is 8889 + smtp.EnableSsl = false; + + smtp.Send(mail); + return true; + } + catch (Exception ex) + { + return false; + } + } + private Random _random = new Random(); + private string GenerateRandomNo() + { + return _random.Next(0, 9999).ToString("D4"); + } + #endregion + } +} diff --git a/Api.SeaHavenIndustries/Controllers/CommonController.cs b/Api.SeaHavenIndustries/Controllers/CommonController.cs new file mode 100644 index 0000000..77b2a33 --- /dev/null +++ b/Api.SeaHavenIndustries/Controllers/CommonController.cs @@ -0,0 +1,136 @@ +using Api.SeaHavenIndustries.DTOs; +using Api.SeaHavenIndustries.Helper.ViewModel; +using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; + +namespace Api.SeaHavenIndustries.Controllers +{ + [Authorize] + [ApiController] + [Route("[controller]")] + + public class CommonController : Controller + { + private readonly UserManager _userManager; + private readonly ApplicationDbContext _db; + public CommonController(UserManager userManager, ApplicationDbContext db) + { + _userManager = userManager; + _db = db; + } + + [HttpGet] + [Route("GetUsers")] + public async Task GetUsers(string? search = "", int page = 1, int pageSize = 10) + { + try + { + var allUsersQuery = _db.Users + .Where(w => w.FirstName.ToLower().Contains(search.ToLower())) + .OrderByDescending(d => d.Id); + + var totalCount = allUsersQuery.Count(); + + var paginatedUsers = allUsersQuery + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToList(); + // Calculate the number of pages + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + var filteredUsers = new List(); + + foreach (var user in paginatedUsers) + { + var roles = await _userManager.GetRolesAsync(user); + if (!roles.Contains("Admin")) + { + filteredUsers.Add(new UserRoleViewModel + { + RoleName = roles.Count()>0?roles.First():"", + Email = user.Email, + UserName = user.FirstName, + Date = user.CreatedDate?.Date.ToString(), + Status = user.UniqueName, + Id = user.Id + }); + } + } + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = filteredUsers, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages + }; + return Ok(viewModel); + } + catch (Exception ex) + { + return BadRequest(new { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("GetRoles")] + public async Task GetRoles() + { + try + { + var data = await _db.Roles.Select(s => new {Id=s.Name,s.Name}).ToListAsync(); + + return Ok(data); + } + catch (Exception ex) + { + return BadRequest(new { Status = "Error", Message = ex.Message }); + } + } + + + [HttpGet] + [Route("GetSitesName")] + public async Task GetSiteName() + { + var data =await _db.Locations.Select(n=> new + { + n.Id, + n.Name, + n.Title + }).ToListAsync(); + return Ok(data); + } + + [HttpGet] + [Route("GetContacts")] + public async Task GetContacts() + { + var data =await _db.Contacts.Select(n=> new + { + n.Id, + n.Name, + email=n.Email, + phone=n.PhoneNumber + }).ToListAsync(); + return Ok(data); + } + + [HttpGet] + [Route("GetCategories")] + public async Task GetCategories() + { + var data = await _db.Categories.Select(s=> new + { + s.Id, + s.Name + }).ToListAsync(); + return Ok(data); + } + } +} diff --git a/Api.SeaHavenIndustries/Controllers/ContactController.cs b/Api.SeaHavenIndustries/Controllers/ContactController.cs new file mode 100644 index 0000000..3310814 --- /dev/null +++ b/Api.SeaHavenIndustries/Controllers/ContactController.cs @@ -0,0 +1,211 @@ +using Api.SeaHavenIndustries.DTOs; +using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Api.SeaHavenIndustries.Controllers +{ + [Authorize] + [ApiController] + [Route("[controller]")] + public class ContactController : Controller + { + private readonly UserManager _userManager; + private readonly ApplicationDbContext _db; + public ContactController(UserManager userManager, ApplicationDbContext db) + { + _userManager = userManager; + _db = db; + } + [HttpPost] + [Route("AddContacts")] + public async Task AddContacts(Contact_DTO contacts) + { + try + { + Contacts model = new Contacts(); + model.Name = contacts.Name; + model.PhoneNumber = contacts.PhoneNumber; + model.Email = contacts.Email; + _db.Contacts.Add(model); + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpPost] + [Route("EditContacts")] + public async Task EditContacts(EditContact_DTO contacts) + { + try + { + var exist = _db.Contacts.Where(w => w.Id == contacts.Id).FirstOrDefault(); + + exist.Name = contacts.Name; + exist.PhoneNumber = contacts.PhoneNumber; + exist.Email = contacts.Email; + _db.Contacts.Update(exist); + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + [HttpGet] + [Route("DeleteContacts")] + public async Task DeleteContacts(int id) + { + try + { + var exist = _db.Contacts.Where(w => w.Id == id).FirstOrDefault(); + if (exist != null) + { + _db.Remove(exist); + } + else + { + return BadRequest(new Response { Status = "Error", Message = "ID not matched!" }); + } + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Removed Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + [HttpGet] + [Route("GetContactList")] + public IActionResult GetContactList(string? search ="", int page = 1, int pageSize = 10) + { + var totalCount = _db.Contacts.Count(); + var data = _db.Contacts.Where(s=> s.Name.ToLower().Contains(search.ToLower()) || s.Email.ToLower().Contains(search.ToLower()) || s.PhoneNumber.Contains(search.ToLower())).Select(n => new + { + n.Id, + n.Name, + email = n.Email, + phone = n.PhoneNumber + }).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize) + .Take(pageSize); + // Calculate the number of pages + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = data, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages + }; + return Ok(viewModel); + } + + [HttpPost] + [Route("AddLocation")] + public async Task AddLocation(Location_DTO model) + { + try + { + Locations locations = new Locations(); + locations.Title = model.Title; + locations.Name = model.Name; + _db.Locations.Add(locations); + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + [HttpPost] + [Route("EditLocation")] + public async Task EditLocation(EditLocation_DTO model) + { + try + { + var exist = _db.Locations.Where(w => w.Id == model.Id).FirstOrDefault(); + if (exist != null) + { + exist.Title = model.Title; + exist.Name = model.Name; + } + else + { + return BadRequest(new Response { Status = "Error", Message = "ID not matched!" }); + } + _db.Locations.Update(exist); + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpPost] + [Route("DeleteLocation")] + public async Task DeleteLocation(int Id) + { + try + { + var data1 = await _db.Templates.ToListAsync(); + _db.Templates.RemoveRange(data1); + var data = await _db.Locations.Where(w => w.Id == Id).FirstOrDefaultAsync(); + if (data != null) + { + _db.Locations.Remove(data ?? new Locations()); + } + else + { + return BadRequest(new Response { Status = "Error", Message = "ID not matched!" }); + } + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("GetAddressbook")] + public IActionResult GetAddressbook(string? search = "", int page = 1, int pageSize = 10) + { + var totalCount = _db.Locations.Count(); + var data = _db.Locations.Where(w=> w.Name.ToLower().Contains(search.ToLower()) || w.Title.ToLower().Contains(search.ToLower())).Select(n => new + { + n.Id, + n.Name, + n.Title + }).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize) + .Take(pageSize); + // Calculate the number of pages + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = data, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages + }; + return Ok(viewModel); + } + + } +} diff --git a/Api.SeaHavenIndustries/Controllers/QuotesController.cs b/Api.SeaHavenIndustries/Controllers/QuotesController.cs new file mode 100644 index 0000000..6fd953c --- /dev/null +++ b/Api.SeaHavenIndustries/Controllers/QuotesController.cs @@ -0,0 +1,249 @@ +using Api.SeaHavenIndustries.DTOs; +using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using System.Linq; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace Api.SeaHavenIndustries.Controllers +{ + [Authorize] + [ApiController] + [Route("[controller]")] + public class QuotesController : Controller + { + private readonly UserManager _userManager; + private readonly ApplicationDbContext _db; + private readonly IWebHostEnvironment _webHostEnvironment; + IHttpContextAccessor _httpContext; + public QuotesController(UserManager userManager, ApplicationDbContext db, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContext) + { + _userManager = userManager; + _db = db; + _webHostEnvironment = webHostEnvironment; + _httpContext = httpContext; + } + [HttpPost] + [Route("AddQuote")] + public async Task AddQuote([FromBody] Quote_DTO model) + { + try + { + Quotes quotes = new Quotes(); + quotes.QuotId = model.QuotId; + quotes.ContactId = model.ContactId; + quotes.PO = model.PO; + quotes.TT = model.TT; + quotes.ProjectName = model.ProjectName; + quotes.Date = DateTime.Parse(model.Date); + quotes.WorkorderId = model.WorkorderId; + quotes.SiteName = model.SiteName; + quotes.SiteId = model.SiteId; + quotes.BillingAddress = model.BillingAddress; + quotes.LineItems = quotes.LineItems == null ? new List() : quotes.LineItems; + if (model.LineItems != null && model.LineItems.Any()) + { + foreach (var lineItemDto in model.LineItems) + { + QuotesLineItems lineItem = new QuotesLineItems() + { + LineitemNumber = lineItemDto.LineitemNumber, + Lineitem = lineItemDto.Lineitem, + Descriptions = lineItemDto.Descriptions + }; + quotes.LineItems.Add(lineItem); + } + } + _db.Quotes.Add(quotes); + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpPost] + [Route("EditQuote")] + public async Task EditQuote([FromBody] EditQuote_DTO model) + { + try + { + var quotes = _db.Quotes.Where(w => w.Id == model.id).FirstOrDefault(); + if (quotes != null) + { + quotes.QuotId = model.QuotId; + quotes.ContactId = model.ContactId; + quotes.PO = model.PO; + quotes.TT = model.TT; + quotes.ProjectName = model.ProjectName; + quotes.Date = DateTime.Parse(model.Date); + quotes.WorkorderId = model.WorkorderId; + quotes.SiteName = model.SiteName; + quotes.SiteId = model.SiteId; + quotes.BillingAddress = model.BillingAddress; + + var existQuoteLine = _db.QuotesLines.Where(w => w.QuoteId == model.id).ToList(); + if (existQuoteLine.Count() > 0) + { + _db.QuotesLines.RemoveRange(existQuoteLine); + } + quotes.LineItems = quotes.LineItems == null ? new List() : quotes.LineItems; + if (model.LineItems != null && model.LineItems.Any()) + { + foreach (var lineItemDto in model.LineItems) + { + QuotesLineItems lineItem = new QuotesLineItems() + { + LineitemNumber = lineItemDto.LineitemNumber, + Lineitem = lineItemDto.Lineitem, + Descriptions = lineItemDto.Descriptions + }; + quotes.LineItems.Add(lineItem); + } + } + _db.Update(quotes); + } + else + { + return BadRequest("ID not matched!"); + } + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("DeleteQuote")] + public IActionResult DeleteQuote(int id) + { + try + { + var data = _db.Quotes.Where(w => w.Id == id).FirstOrDefault(); + if (data != null) + { + var existlineitem = _db.QuotesLines.Where(w => w.QuoteId == id).ToList(); + if (existlineitem.Any()) + { + _db.QuotesLines.RemoveRange(existlineitem); + } + _db.Quotes.Remove(data); + } + else + { + return BadRequest("ID not matched!"); + } + _db.SaveChanges(); + return Ok(new DataResponse { Message = "Removed Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("GetQuoutes")] + public IActionResult GetQuotes(string search = "", int page = 1, int pageSize = 10) + { + var totalCount = _db.Quotes.Count(); + var data = _db.Quotes.Include(s => s.WorkOrder).AsNoTracking().Where(w => w.QuotId.ToLower().Contains(search.ToLower()) || w.SiteName.ToLower().Contains(search.ToLower()) || w.WorkOrder.WorkerOrderTitle.ToLower().Contains(search.ToLower())).Select(s => new + { + s.Id, + QuoteId = "QO-" + s.QuotId, + WOID = s.WorkOrder != null ? s.WorkOrder.WorkerOrderNumber : "", + s.ProjectName, + TotalAmount = "$" + s.LineItems.Sum(s => s.Lineitem.Value).ToString(), + siteName = s.SiteName, + status = s.Status + }).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize) + .Take(pageSize); + + // Calculate the number of pages + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = data, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages + }; + return Ok(viewModel); + } + + [HttpGet] + [Route("GetQuoutesdetailsAgainstWorkOrder")] + public async Task GetQuoutesdetailsAgainstWorkOrder(int woId) + { + var data = await _db.workOrders.Include(s => s.Locations).Where(w => w.Id == woId).Select(s => new + { + s.Id, + s.PO, + s.TT, + s.Locations.Title, + s.Locations.Name + }).ToListAsync(); + return Ok(data); + } + + [HttpGet] + [Route("GetQuoutesById")] + public async Task GetQuoutesById(int id) + { + var data = await _db.Quotes.Where(s => s.Id == id).Include(s => s.WorkOrder).Select(s => new + { + s.Id, + s.QuotId, + s.Date, + s.Contacts.Name, + s.PO, + s.TT, + s.SiteName, + s.ProjectName, + s.SiteId, + s.BillingAddress, + s.ShippingAddress, + lineitems = s.LineItems.Select(q => new { q.Descriptions, q.Lineitem }), + TotalAmount = "$" + s.LineItems.Sum(s => s.Lineitem.Value).ToString() + }).FirstOrDefaultAsync(); + return Ok(data); + } + + [HttpGet] + [Route("GetReporting")] + public async Task GetReporting() + { + var totalCreatedWorkOrder = await _db.workOrders.CountAsync(); + var totalCompleted = _db.workOrders.Count(w => w.Status == "Done"); + var totalSev1 = _db.workOrders.Count(w => w.Priority == "Sev 1"); + var totalSev2 = _db.workOrders.Count(w => w.Priority == "Sev 2"); + var totalSev3 = _db.workOrders.Count(w => w.Priority == "Sev 3"); + var totalSev4 = _db.workOrders.Count(w => w.Priority == "Sev 4"); + var totalSev5 = _db.workOrders.Count(w => w.Priority == "Sev 5"); + + var data = new Reporting_DTO + { + TotalCreatedWorkOrder = totalCreatedWorkOrder, + TotalCompleted = totalCompleted, + TotalSev1 = totalSev1, + TotalSev2 = totalSev2, + TotalSev3 = totalSev3, + TotalSev4 = totalSev4, + TotalSev5 = totalSev5 + }; + + return Ok(data); + } + } +} diff --git a/Api.SeaHavenIndustries/Controllers/SettingsController.cs b/Api.SeaHavenIndustries/Controllers/SettingsController.cs new file mode 100644 index 0000000..6183727 --- /dev/null +++ b/Api.SeaHavenIndustries/Controllers/SettingsController.cs @@ -0,0 +1,239 @@ +using Api.SeaHavenIndustries.DTOs; +using Api.SeaHavenIndustries.Helper.ViewModel; +using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace Api.SeaHavenIndustries.Controllers +{ + [Authorize] + [ApiController] + [Route("[controller]")] + public class SettingsController : Controller + { + private readonly UserManager _userManager; + private readonly ApplicationDbContext _db; + public SettingsController(UserManager userManager, ApplicationDbContext db) + { + _userManager = userManager; + _db = db; + } + + [HttpPost] + [Route("AddCategory")] + public async Task AddCategory(Category_DTO model) + { + try + { + Category category = new Category(); + category.Name = model.Name; + _db.Categories.Add(category); + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Successfully Saved Data", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpPost] + [Route("EditCategory")] + public async Task EditCategory(EditCategory_DTO model) + { + try + { + var exist = _db.Categories.Where(w => w.Id == model.Id).FirstOrDefault(); + exist.Name = model.Name; + _db.Categories.Update(exist); + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("DeleteCategory")] + public async Task DeleteCategory(int id) + { + try + { + var exist = _db.Categories.Where(w => w.Id == id).FirstOrDefault(); + if (exist != null) + { + var chkexist = _db.Templates.Where(w => w.CategoryId == id).ToList(); + if (chkexist != null) + { + _db.RemoveRange(chkexist); + } + var chkworkordercategory = _db.workOrderCategories.Where(w => w.CategoryId == id).ToList(); + if (chkworkordercategory != null) + { + _db.RemoveRange(chkworkordercategory); + } + _db.Remove(exist); + } + else + { + return BadRequest(new Response { Status = "Error", Message = "ID not matched!" }); + } + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Deleted Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + + [HttpGet] + [Route("GetCategoryList")] + public IActionResult GetCategoryList(int page = 1, int pageSize = 10) + { + var totalCount = _db.Categories.Count(); + var data = _db.Categories.Select(s => new + { + s.Id, + s.Name + }).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize) + .Take(pageSize); + + // Calculate the number of pages + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = data, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages + }; + return Ok(viewModel); + } + + [HttpGet] + [Route("GetTemplates")] + public IActionResult GetTemplates(int page = 1, int pageSize = 10) + { + try + { + var totalCount = _db.workOrders.Where(w=> w.istemplate == true).Count(); + var data = _db.workOrders.Where(w => w.istemplate == true).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize) + .Take(pageSize); + + // Calculate the number of pages + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = data, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages + }; + return Ok(viewModel); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("GetUsers")] + public async Task GetUsers(string? search = "", int page = 1, int pageSize = 10) + { + try + { + var totalCount = _db.Users.Count(); + var allUsers = _db.Users.Where(w => w.FirstName.ToLower().Contains(search.ToLower())).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize) + .Take(pageSize); + + // Calculate the number of pages + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + var filteredUsers = new List(); + + foreach (var user in allUsers) + { + var roles = await _userManager.GetRolesAsync(user); + if (!roles.Contains("Admin")) + { + filteredUsers.Add(new UserRoleViewModel + { + RoleName = roles.Count() > 0 ? roles.First() : "", + Email = user.Email, + UserName = user.FirstName, + Date = user.CreatedDate?.Date.ToString(), + Status = user.UniqueName, + Id = user.Id + }); + } + } + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = filteredUsers, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages + }; + return Ok(viewModel); + } + catch (Exception ex) + { + return BadRequest(new { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("GetRoles")] + public async Task GetRoles() + { + try + { + var data = _db.Roles.ToList(); + List roles = new List(); + foreach (var role in data) + { + if (role.Name == "Admin") + { + roles.Add(new Roles_DTO { Name = role.Name, Description = "Full Access" }); + } + else if(role.Name == "Supervisor") + { + roles.Add(new Roles_DTO { Name = role.Name, Description = "Access to Team's Work Orders Only" }); + + } + else if(role.Name == "Manager") + { + roles.Add(new Roles_DTO { Name = role.Name, Description = "Full access accept quotes" }); + + } + else if(role.Name =="User") + { + roles.Add(new Roles_DTO { Name = role.Name, Description = "Access to Assigned Work Orders Only" }); + + } + } + return Ok(roles); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + } +} diff --git a/Api.SeaHavenIndustries/Controllers/UserController.cs b/Api.SeaHavenIndustries/Controllers/UserController.cs new file mode 100644 index 0000000..7b91a01 --- /dev/null +++ b/Api.SeaHavenIndustries/Controllers/UserController.cs @@ -0,0 +1,230 @@ +using Api.SeaHavenIndustries.DTOs; +using Api.SeaHavenIndustries.Helper; +using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using System.Security.Claims; +using System.Security.Cryptography; + +namespace Api.SeaHavenIndustries.Controllers +{ + [Authorize] + [ApiController] + [Route("[controller]")] + public class UserController : Controller + { + private readonly UserManager _userManager; + private readonly ApplicationDbContext _db; + private readonly SendMessage _sendemail; + + public UserController(UserManager userManager, ApplicationDbContext db, SendMessage sendemail) + { + _userManager = userManager; + _db = db; + _sendemail = sendemail; + } + [HttpPost] + [Route("AddUser")] + public async Task AddUser(User_DTO model) + { + try + { + ApplicationUser user = new ApplicationUser(); + user.EmailConfirmed = true; + user.UserName = model.Email; + user.Email = model.Email; + user.FirstName = model.Name; + user.CreatedDate = DateTime.Now; + user.UniqueName = "Active"; + var password = GenerateRandomPassword(8); + var result = await _userManager.CreateAsync(user, password); + if (result.Succeeded) + { + await _userManager.AddToRoleAsync(user, model.Role ?? ""); + } + else + { + return BadRequest(result.Errors.FirstOrDefault()?.Description ?? "error"); + } + //var request = _httpContextAccessor.HttpContext?.Request; + //var domain = $"{request?.Scheme}://{request?.Host}"; + string subject = "Login Information"; + //string greeting = $"Dear {model.FirstName},\n\n"; + //string loginLink = $"Click here to login:{domain}/Login\n"; + string passwordInfo = $"Your password is: {password}\n\n"; + string body = $"{passwordInfo}"; + await _sendemail.SendEMail(model?.Email ?? "", subject, body); + + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + [HttpPost] + [Route("EditUser")] + public async Task EditUser(EditUser_DTO user) + { + try + { + var exist = _db.Users.Where(w => w.Id == user.Id).FirstOrDefault(); + exist.FirstName = user.Name; + exist.EmailConfirmed = true; + exist.UserName = user.Email; + exist.Email = user.Email; + exist.NormalizedEmail = user.Email.ToUpper(); + exist.NormalizedUserName = user.Email.ToUpper(); + exist.CreatedDate = DateTime.Now; + exist.UniqueName = "Active"; + var existingRole = await _userManager.GetRolesAsync(exist); + + if (existingRole != null && existingRole.Any()) + { + await _userManager.RemoveFromRolesAsync(exist, existingRole); + } + await _userManager.AddToRoleAsync(exist, user.Role ?? ""); + + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("DeleteUser")] + public async Task DeleteUser(string id) + { + try + { + var data = await _db.Users.Where(w => w.Id == id).FirstOrDefaultAsync(); + + if (data != null) + { + var existworkorder = _db.workOrders.Where(w => w.AssignTo.Contains(data.Id)).ToList(); + foreach (var workorder in existworkorder) + { + var existdata = _db.workOrders.Where(w => w.Id == workorder.Id).FirstOrDefault(); + existdata.AssignTo = null; + } + var existworkordercomments = _db.Comments.Where(w => w.UserId.Contains(data.Id)).ToList(); + foreach (var workorderc in existworkordercomments) + { + var existdatacomm = _db.Comments.Where(w => w.Id == workorderc.Id).FirstOrDefault(); + existdatacomm.UserId = null; + } + var existtemplate = _db.Templates.Where(w => w.AssignTo.Contains(data.Id)).ToList(); + foreach (var workordert in existtemplate) + { + var existdattem = _db.Templates.Where(w => w.Id == workordert.Id).FirstOrDefault(); + existdattem.AssignTo = null; + } + var existtempexistuserrolelate = _db.UserRoles.Where(w => w.UserId.Contains(data.Id)).ToList(); + if (existtempexistuserrolelate.Count() > 0) + { + _db.UserRoles.RemoveRange(existtempexistuserrolelate); + } + _db.Users.Remove(data); + } + else + { + return BadRequest(new Response { Status = "Error", Message = "ID not matched!" }); + } + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpPost] + [Route("DeleteCurrentUser")] + public async Task DeleteCurrentUser() + { + try + { + var userid = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? ""; + var exist = _db.Users.Where(w => w.Id == userid).FirstOrDefault(); + if(exist != null) + { + exist.IsDeleted = true; + } + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("UserProfile")] + public async Task UserProfile() + { + var userid = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? ""; + + var data = await _db.Users.Where(w => w.Id == userid).Select(s => new + { + s.Id, + Name = s.FirstName, + addeddate = s.CreatedDate, + s.Email, + s.Contact + }).ToListAsync(); + return Ok(data); + } + public static string GenerateRandomPassword(int length = 8) + { + const string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+=<>?"; + const string capitalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const string digits = "1234567890"; + const string symbols = "!@#$%^&*()_-+=<>?"; + + using (var rng = RandomNumberGenerator.Create()) + { + var passwordChars = new char[length]; + + // Ensure at least one capital letter + passwordChars[0] = capitalLetters[GetNextNonNegativeIndex(rng, capitalLetters.Length)]; + + // Ensure at least one digit + passwordChars[1] = digits[GetNextNonNegativeIndex(rng, digits.Length)]; + + // Ensure at least one symbol + passwordChars[2] = symbols[GetNextNonNegativeIndex(rng, symbols.Length)]; + + // Fill the rest of the password with random characters + for (int i = 3; i < length; i++) + { + passwordChars[i] = validChars[GetNextNonNegativeIndex(rng, validChars.Length)]; + } + + // Shuffle the password characters, excluding the initial characters + Random random = new Random(); + for (int i = length - 1; i > 2; i--) + { + int j = random.Next(2, i + 1); + (passwordChars[i], passwordChars[j]) = (passwordChars[j], passwordChars[i]); + } + + return new string(passwordChars); + } + } + + private static int GetNextNonNegativeIndex(RandomNumberGenerator rng, int maxValue) + { + byte[] randomBytes = new byte[4]; + rng.GetBytes(randomBytes); + int nextIndex = BitConverter.ToInt32(randomBytes, 0) % maxValue; + return (nextIndex + maxValue) % maxValue; // Ensure the index is non-negative + } + } +} diff --git a/Api.SeaHavenIndustries/Controllers/WeatherForecastController.cs b/Api.SeaHavenIndustries/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..c756e6c --- /dev/null +++ b/Api.SeaHavenIndustries/Controllers/WeatherForecastController.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Mvc; + +namespace Api.SeaHavenIndustries.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + + } +} diff --git a/Api.SeaHavenIndustries/Controllers/WorkOrderController.cs b/Api.SeaHavenIndustries/Controllers/WorkOrderController.cs new file mode 100644 index 0000000..eddf3c3 --- /dev/null +++ b/Api.SeaHavenIndustries/Controllers/WorkOrderController.cs @@ -0,0 +1,755 @@ +using Api.SeaHavenIndustries.DTOs; +using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Components.Forms; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using System.IO; +using System.Net.Http.Headers; +using System.Security.Claims; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace Api.SeaHavenIndustries.Controllers +{ + [Authorize] + [ApiController] + [Route("[controller]")] + public class WorkOrderController : Controller + { + private readonly UserManager _userManager; + private readonly ApplicationDbContext _db; + private readonly IWebHostEnvironment _webHostEnvironment; + IHttpContextAccessor _httpContext; + public WorkOrderController(UserManager userManager, ApplicationDbContext db, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContext) + { + _userManager = userManager; + _db = db; + _webHostEnvironment = webHostEnvironment; + _httpContext = httpContext; + } + [HttpPost] + [Route("AddWorkorder")] + public async Task Addworkorder([FromForm] Workorder_DTO model) + { + try + { + string userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + WorkOrder workOrder = new WorkOrder(); + workOrder.WorkerOrderNumber = model.WorkerOrderNumber; + workOrder.WorkerOrderTitle = model.WorkerOrderTitle; + workOrder.Description = model.Description; + workOrder.TT = model.TT; + workOrder.PO = model.PO; + workOrder.AssignTo = model.AssignTo; + workOrder.DueDate = model.DueDate; + workOrder.Priority = model.Priority; + workOrder.istemplate = model.istemplate; + //workOrder.CategoryId = model.CategoryId; + workOrder.LocationId = model.LocationId; + workOrder.Status = "Open"; + workOrder.istemplate = model.istemplate; + workOrder.BeforPhotoIssue = model.BeforPhotoIssue; + workOrder.AfterPhotoIssue = model.AfterPhotoIssue; + workOrder.SignOffName = model.SignOffName; + workOrder.SignOffSignature = model.SignOffSignature; + + workOrder.WorkOrderContacts = workOrder.WorkOrderContacts==null? new List(): workOrder.WorkOrderContacts; + List contactIds = model.GetContactIds(); + workOrder.WorkOrderCategories = workOrder.WorkOrderCategories == null ? new List() : workOrder.WorkOrderCategories; + List categoryIds = model.GetCategoryIds(); + + // Create new records for the associations (pseudo-code) + foreach (int contactId in contactIds) + { + // Create association with contact + workOrder.WorkOrderContacts.Add(new WorkOrderContacts { ContactId = contactId }); + } + + foreach (int categoryId in categoryIds) + { + // Create association with category + workOrder.WorkOrderCategories.Add(new WorkOrderCategories { CategoryId = categoryId }); + } + + #region Images of workorder + workOrder.workOrderAttachments = workOrder.workOrderAttachments == null ? new List() : workOrder.workOrderAttachments; + foreach (var attachment in model.Attachments) + { + string fileName = ContentDispositionHeaderValue.Parse(attachment.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await attachment.CopyToAsync(ms); + } + + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + var imagesPath = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + workOrder.workOrderAttachments.Add(new WorkOrderAttachments { Attachments = imagesPath }); + } + + if (model.BeforPhotoAttachment != null) + { + string fileName = ContentDispositionHeaderValue.Parse(model.BeforPhotoAttachment.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await model.BeforPhotoAttachment.CopyToAsync(ms); + } + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + workOrder.BeforPhotoAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + } + if (model.AfterPhotoAttachment != null) + { + string fileName = ContentDispositionHeaderValue.Parse(model.AfterPhotoAttachment.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await model.AfterPhotoAttachment.CopyToAsync(ms); + } + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + workOrder.AfterPhotoAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + } + if (model.SignOffAttachment != null) + { + string fileName = ContentDispositionHeaderValue.Parse(model.SignOffAttachment.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await model.SignOffAttachment.CopyToAsync(ms); + } + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + workOrder.SignOffAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + } + #endregion + _db.Add(workOrder); + _db.SaveChanges(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + + [HttpPost] + [Route("EditWorkorder")] + public async Task Editworkorder([FromForm] EditWorkorder_DTO model) + { + try + { + var workOrder = _db.workOrders.Where(w => w.Id == model.Id).FirstOrDefault(); + workOrder.WorkerOrderNumber = model.WorkerOrderNumber; + workOrder.WorkerOrderTitle = model.WorkerOrderTitle; + workOrder.Description = model.Description; + workOrder.TT = model.TT; + workOrder.PO = model.PO; + workOrder.AssignTo = model.AssignTo; + workOrder.DueDate = model.DueDate; + workOrder.Priority = model.Priority; + //workOrder.CategoryId = model.CategoryId; + workOrder.LocationId = model.LocationId; + workOrder.Status = "Open"; + //workOrder.istemplate = false; + workOrder.BeforPhotoIssue = model.BeforPhotoIssue; + workOrder.AfterPhotoIssue = model.AfterPhotoIssue; + workOrder.SignOffName = model.SignOffName; + workOrder.SignOffSignature = model.SignOffSignature; + var existcontact=_db.WorkOrderContacts.Where(w=>w.WorkorderId==model.Id).ToList(); + if (existcontact.Count()>0) + { + _db.WorkOrderContacts.RemoveRange(existcontact); + } + var existcategory=_db.workOrderCategories.Where(w=>w.WorkorderId==model.Id).ToList(); + if (existcategory.Count()>0) + { + _db.workOrderCategories.RemoveRange(existcategory); + } + workOrder.WorkOrderContacts = workOrder.WorkOrderContacts == null ? new List() : workOrder.WorkOrderContacts; + List contactIds = model.GetContactIds(); + + workOrder.WorkOrderCategories = workOrder.WorkOrderCategories == null ? new List() : workOrder.WorkOrderCategories; + List categoryIds = model.GetCategoryIds(); + + // Create new records for the associations (pseudo-code) + foreach (int contactId in contactIds) + { + // Create association with contact + workOrder.WorkOrderContacts.Add(new WorkOrderContacts { ContactId = contactId }); + } + + foreach (int categoryId in categoryIds) + { + // Create association with category + workOrder.WorkOrderCategories.Add(new WorkOrderCategories { CategoryId = categoryId }); + } + + #region Images of workorder + workOrder.workOrderAttachments = workOrder.workOrderAttachments == null ? new List() : workOrder.workOrderAttachments; + foreach (var attachment in model.Attachments) + { + string fileName = ContentDispositionHeaderValue.Parse(attachment.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await attachment.CopyToAsync(ms); + } + + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + var imagesPath = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + workOrder.workOrderAttachments.Add(new WorkOrderAttachments { Attachments = imagesPath }); + } + + if (model.BeforPhotoAttachment != null) + { + string fileName = ContentDispositionHeaderValue.Parse(model.BeforPhotoAttachment.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await model.BeforPhotoAttachment.CopyToAsync(ms); + } + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + workOrder.BeforPhotoAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + } + if (model.AfterPhotoAttachment != null) + { + string fileName = ContentDispositionHeaderValue.Parse(model.AfterPhotoAttachment.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await model.AfterPhotoAttachment.CopyToAsync(ms); + } + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + workOrder.AfterPhotoAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + } + if (model.SignOffAttachment != null) + { + string fileName = ContentDispositionHeaderValue.Parse(model.SignOffAttachment.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await model.SignOffAttachment.CopyToAsync(ms); + } + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + workOrder.SignOffAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + } + #endregion + _db.SaveChanges(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + //[HttpGet] + //[Route("GetWorkorder")] + //public IActionResult GetWorkorder(int page = 1, int pageSize = 10, string search="") + //{ + // var totalCount = _db.workOrders.Count(); + // var data = _db.workOrders.Include(w => w.Locations).AsNoTracking().Where(w => w.istemplate != true && (w.WorkerOrderTitle.ToLower().Contains(search.ToLower()) || w.WorkerOrderNumber.ToLower().Contains(search.ToLower()) || w.Locations.Title.ToLower().Contains(search.ToLower()))).Select(s => new + // { + // s.Id, + // s.WorkerOrderTitle, + // s.DueDate, + // s.Priority, + // s.Status, + // site = s.Locations.Name + // }).OrderByDescending(d=> d.Id).ToList().Skip((page - 1) * pageSize) + // .Take(pageSize); + + // // Calculate the number of pages + // var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + // // Create a view model containing the paged items and pagination metadata + // var viewModel = new Pagination_DTO + // { + // Data = data, + // PageNumber = page, + // PageSize = pageSize, + // TotalCount = totalCount, + // TotalPages = totalPages + // }; + // return Ok(viewModel); + //} + + + [HttpGet] + [Route("DeleteWorkorder")] + public IActionResult Deleteworkorder(int id) + { + try + { + var exist = _db.workOrders.Where(w => w.Id == id).FirstOrDefault(); + if (exist != null) + { + var quotes = _db.Quotes.Where(w => w.WorkorderId == id).ToList(); + if (quotes.Count() > 0) + { + foreach (var itm in quotes) + { + var existquotes = _db.Quotes.Where(w => w.Id == itm.Id).FirstOrDefault(); + existquotes.WorkorderId = null; + } + } + var attachments = _db.workOrderAttachments.Where(w => w.WorkorderId == id).ToList(); + if (attachments.Count() > 0) + { + _db.RemoveRange(attachments); + } + var contacts = _db.WorkOrderContacts.Where(w => w.WorkorderId == id).ToList(); + if (contacts.Count() > 0) + { + _db.RemoveRange(contacts); + } + var category = _db.workOrderCategories.Where(w => w.WorkorderId == id).ToList(); + if (category.Count() > 0) + { + _db.RemoveRange(category); + } + var comments = _db.Comments.Where(w => w.WorkerOrderId == id).ToList(); + if (comments.Count() > 0) + { + _db.RemoveRange(comments); + } + _db.Remove(exist); + + } + else + { + return BadRequest("ID not matched!"); + } + _db.SaveChanges(); + return Ok(new DataResponse { Message = "Removed Successfully", Status = "200" }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("GetFilteredWorkorder")] + public IActionResult GetFilteredWorkorder( + [FromQuery] string[] assignto, + [FromQuery] int[]? location, + [FromQuery] string[]? priority, + [FromQuery] string[]? status, + [FromQuery] string[]? duedate, + [FromQuery] string search = "", + [FromQuery] string sort = "Sort Order", + [FromQuery] string sortby = "Sort By", + int page = 1, + int pageSize = 10) + { + try + { + IQueryable query = _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations); + + if (!string.IsNullOrEmpty(search)) + { + query = query.Where(w => + w.WorkerOrderTitle.ToLower().Contains(search.ToLower()) || + w.WorkerOrderNumber.ToLower().Contains(search.ToLower()) || + w.Locations.Title.ToLower().Contains(search.ToLower())); + } + + if (assignto != null && assignto.Length > 0) + { + if (assignto[0] != "" && assignto[0]!=null) + query = query.Where(w => assignto.Contains(w.AssignTo)); + } + + if (location != null && location.Length > 0) + { + if (location[0]!=0) + query = query.Where(w => location.Contains(w.LocationId ?? 0)); + } + + if (priority != null && priority.Length > 0) + { + if (priority[0] != "" && priority[0] != null) + query = query.Where(w => priority.Contains(w.Priority)); + } + + if (status != null && status.Length > 0) + { + if (status[0] != "" && status[0] != null) + query = query.Where(w => status.Contains(w.Status)); + } + var data = query.ToList(); + + // Perform client-side filtering for due dates + data = data.Where(w => + duedate == null || duedate.Length == 0 || duedate[0] == null || + duedate.Any(dd => w.DueDate.HasValue && CheckDueDate(dd, w.DueDate.Value.Date, DateTime.UtcNow.Date))).ToList(); + + // Apply sorting + if (!string.IsNullOrEmpty(sort) && !string.IsNullOrEmpty(sortby) && sortby != "") + { + switch (sortby) + { + case "Name": + data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.WorkerOrderTitle).ToList() : data.OrderByDescending(w => w.WorkerOrderTitle).ToList(); + break; + case "Due Date": + data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.DueDate).ToList() : data.OrderByDescending(w => w.DueDate).ToList(); + break; + case "Severity": + data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.Priority).ToList() : data.OrderByDescending(w => w.Priority).ToList(); + break; + default: + // Handle default case or throw an exception + break; + } + } + + var totalCount = data.Count(); + var pagedData = data + .Skip((page - 1) * pageSize) + .Take(pageSize) + .Select(s => new { s.Id, s.WorkerOrderTitle, s.DueDate, s.Status, s.Priority, s.Locations.Name }) + .OrderByDescending(d => d.Name) + .ToList(); + + var totalPages1 = (int)Math.Ceiling(totalCount / (double)pageSize); + + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = pagedData, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages1 + }; + + return Ok(viewModel); + } + catch (Exception ex) + { + // Handle exception and return a default result or an error response + return StatusCode(500, "Internal Server Error"); + } + } + + [HttpGet] + [Route("GetWorkorderById")] + public async Task GetWorkorderById(int id) + { + var exist = await _db.workOrders.Include(w => w.Locations).Include(w => w.Comments).Include(w => w.Quotes).Where(w => w.Id == id).Select(s => new + { + s.Id, + s.WorkerOrderNumber, + title= s.WorkerOrderTitle, + s.DueDate, + s.Status, + assignee = s.AssignToUser.FirstName, + location = s.Locations.Name, + priority = s.Priority, + s.PO, + s.TT, + poc = s.WorkOrderContacts.Select(s => new {s.Id,name=s.POC.Name,email=s.POC.Email,phone=s.POC.PhoneNumber}), + category = s.WorkOrderCategories.Select(s => new {s.Id,name=s.Category.Name}), + Attachments = s.workOrderAttachments.Select(s => new {s.Id,attachment=s.Attachments}), + //category = s.Category.Name, + //s.Attachments, + s.BeforPhotoIssue, + s.BeforPhotoAttachment, + s.AfterPhotoIssue, + s.AfterPhotoAttachment, + s.SignOffName, + s.SignOffAttachment, + s.SignOffSignature, + Comments = s.Comments.Select(s => new { s.Id, s.CreatedDate, s.Commenttext, s.Documents,userName=s.ApplicationUser.FirstName }), + quotes = s.Quotes.Select(q => new { code = q.QuotId, q.Id }) + }).FirstOrDefaultAsync(); + if (exist == null) + { + + return BadRequest(new Response { Status = "Error", Message = "ID not found!" }); + } + else + { + return Ok(exist); + } + } + [HttpGet] + [Route("GetFilteredWorkorder2")] + public IActionResult GetFilteredWorkorder2([FromQuery] string[] assignto, [FromQuery] int[]? location, [FromQuery] string[]? priority, [FromQuery] string[]? status, [FromQuery] string[]? duedate, [FromQuery] string search = "", [FromQuery] string sort = "Sort Order", [FromQuery] string sortby= "Sort By", int page = 1, int pageSize = 10) + { + try + { + var totalCount = _db.workOrders.Where(w => w.istemplate != true).Count(); + if (sort == "Sort Order" && sortby == "Sort By" && assignto.Count() == 0 && (duedate == null || duedate.Count() == 0) && location.Count() == 0 && (priority == null || priority.Count() == 0) && (status == null || status.Count() == 0) && search == "") + { + var data1 = _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations).ToListAsync(); + return Ok(data1); + } + //if (sort == "Sort Order" && sortby == "Sort By" && assignto.Count() == 0 && (duedate == null || duedate.Count() == 0) && location.Count() == 0 && (priority == null || priority.Count() == 0) && (status == null || status.Count() == 0) && search == "") + //{ + // var data1 = _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations).Select(s => new {s.Id, s.WorkerOrderTitle, s.DueDate, s.Status, s.Priority, s.Locations.Name }).OrderByDescending(d => d.Name).ToList().Skip((page - 1) * pageSize) + // .Take(pageSize); + + // // Calculate the number of pages + // var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + // // Create a view model containing the paged items and pagination metadata + // var viewModel1 = new Pagination_DTO + // { + // Data = data1, + // PageNumber = page, + // PageSize = pageSize, + // TotalCount = totalCount, + // TotalPages = totalPages + // }; + // return Ok(viewModel1); + //} + + var currentDate = DateTime.UtcNow.Date; + var data = _db.workOrders.Include(w => w.Locations) + .Where(w => w.istemplate != true && ((w.WorkerOrderTitle.ToLower().Contains(search.ToLower()) || w.WorkerOrderNumber.ToLower().Contains(search.ToLower()) || w.Locations.Title.ToLower().Contains(search.ToLower())) && + (assignto.Count() == 0 || assignto.Contains(w.AssignTo)) && + (location.Count() == 0 || (w.LocationId.HasValue && location.Contains(w.LocationId.Value))) && + (priority.Count() == 0 || priority.Contains(w.Priority)) && + ((status.Count() == 0 || status.Contains(w.Status)) + ))) + .ToList(); + + // Perform client-side filtering for due dates + data = data.Where(w => + duedate.Count() == 0 || + duedate.Any(dd => w.DueDate.HasValue && CheckDueDate(dd, w.DueDate.Value.Date, currentDate))).ToList(); + + // Apply sorting + if (!string.IsNullOrEmpty(sort) && !string.IsNullOrEmpty(sortby) && sortby != "") + { + switch (sortby) + { + case "Name": + data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.WorkerOrderTitle).ToList() : data.OrderByDescending(w => w.WorkerOrderTitle).ToList(); + break; + case "Due Date": + data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.DueDate).ToList() : data.OrderByDescending(w => w.DueDate).ToList(); + break; + case "Severity": + data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.Priority).ToList() : data.OrderByDescending(w => w.Priority).ToList(); + break; + default: + // Handle default case or throw an exception + break; + } + } + var newdata=data.Select(s => new { s.Id, s.WorkerOrderTitle, s.DueDate, s.Status, s.Priority, s.Locations.Name }).OrderByDescending(d => d.Name).ToList().Skip((page - 1) * pageSize) + .Take(pageSize); + var totalPages1 = (int)Math.Ceiling(totalCount / (double)pageSize); + + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = newdata, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages1 + }; + return Ok(viewModel); + } + catch (Exception ex) + { + var totalCount = _db.workOrders.Where(w => w.istemplate != true).Count(); + var data1 = _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations).Select(s=> new + { + s.Id, + s.WorkerOrderTitle, + s.DueDate, + s.Status, + s.Priority, + s.Locations.Name + }).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize) + .Take(pageSize); + + // Calculate the number of pages + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + // Create a view model containing the paged items and pagination metadata + var viewModel = new Pagination_DTO + { + Data = data1, + PageNumber = page, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages + }; + return Ok(viewModel); + } + } + bool CheckDueDate(string dd, DateTime dueDate, DateTime currentDate) + { + return dd switch + { + "Today" => dueDate == currentDate, + "Tomorrow" => dueDate == currentDate.AddDays(1), + "Next Week" => dueDate >= currentDate.AddDays(1) && dueDate <= currentDate.AddDays(7), + "Next Month" => dueDate >= currentDate.AddDays(1) && dueDate <= currentDate.AddMonths(1), + "Over Due" => dueDate < currentDate, + _ => false + }; + } + + [HttpPost] + [Route("ChangeStatus")] + public async Task ChangeStatus(int id, string status) + { + try + { + var data = await _db.workOrders.Where(w => w.Id == id).FirstOrDefaultAsync(); + data.Status = status; + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200", Data = data }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpPost] + [Route("AddComment")] + public async Task AddComment([FromForm] Comments_DTO model) + { + try + { + var userId = _httpContext?.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? ""; + Comments comments = new Comments(); + comments.CreatedDate = DateTime.Now; + comments.UserId = userId; + comments.WorkerOrderId = model.WorkorderId; + comments.Commenttext = model.Text; + if (model.Document != null) + { + string fileName = ContentDispositionHeaderValue.Parse(model.Document.ContentDisposition).FileName.Trim('"'); + string uniqueFileName = $"{Guid.NewGuid()}_{fileName}"; + + string uploadProfilePath = Path.Combine("Assets", "Documents"); + string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + // Copy the file to the server + using (var ms = System.IO.File.Create(fullPath)) + { + await model.Document.CopyToAsync(ms); + } + // Update the user's image URL + var request = _httpContext.HttpContext.Request; + var domain = $"{request.Scheme}://{request.Host}"; + comments.Documents = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName); + } + _db.Comments.Add(comments); + await _db.SaveChangesAsync(); + return Ok(new DataResponse { Message = "Updated Successfully", Status = "200", Data = comments }); + } + catch (Exception ex) + { + return BadRequest(new Response { Status = "Error", Message = ex.Message }); + } + } + + [HttpGet] + [Route("GetComments")] + public async Task GetComments() + { + var data = await _db.Comments.Include(i => i.ApplicationUser).Select(s => new + { + s.Id, + s.Commenttext, + s.ApplicationUser.FirstName, + s.Documents + }).ToListAsync(); + return Ok(data); + } + + [HttpGet] + [Route("GetCommentsByWorkorderId")] + public async Task GetCommentsByWorkorderId(int woid) + { + var data = await _db.Comments.Where(w => w.WorkerOrderId == woid).Include(i => i.ApplicationUser).Select(s => new + { + s.Id, + s.Commenttext, + s.ApplicationUser.FirstName, + s.Documents + }).ToListAsync(); + return Ok(data); + } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Category_DTO.cs b/Api.SeaHavenIndustries/DTOs/Category_DTO.cs new file mode 100644 index 0000000..63e81fe --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Category_DTO.cs @@ -0,0 +1,12 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class Category_DTO + { + public string? Name { get; set; } + } + public class EditCategory_DTO + { + public int? Id { get; set; } + public string? Name { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Comments_DTO.cs b/Api.SeaHavenIndustries/DTOs/Comments_DTO.cs new file mode 100644 index 0000000..23e80d9 --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Comments_DTO.cs @@ -0,0 +1,11 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class Comments_DTO + { + public string Text { get; set; } + public IFormFile? Document { get; set; } + public int WorkorderId { get; set; } + public DateTime CreatedDate { get; set; } + public string UserId { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Contact_DTO.cs b/Api.SeaHavenIndustries/DTOs/Contact_DTO.cs new file mode 100644 index 0000000..6e4079f --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Contact_DTO.cs @@ -0,0 +1,9 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class Contact_DTO + { + public string? Name { get; set; } + public string? PhoneNumber { get; set; } + public string? Email { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/EditContact_DTO.cs b/Api.SeaHavenIndustries/DTOs/EditContact_DTO.cs new file mode 100644 index 0000000..2062291 --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/EditContact_DTO.cs @@ -0,0 +1,10 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class EditContact_DTO + { + public int Id { get; set; } + public string? Name { get; set; } + public string? PhoneNumber { get; set; } + public string? Email { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/EditLocation_DTO.cs b/Api.SeaHavenIndustries/DTOs/EditLocation_DTO.cs new file mode 100644 index 0000000..cd7d64e --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/EditLocation_DTO.cs @@ -0,0 +1,9 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class EditLocation_DTO + { + public int Id { get; set; } + public string? Title { get; set; } + public string? Name { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/EditQuote_DTO.cs b/Api.SeaHavenIndustries/DTOs/EditQuote_DTO.cs new file mode 100644 index 0000000..9ca28f0 --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/EditQuote_DTO.cs @@ -0,0 +1,20 @@ +using Data.SeaHavenIndustries; + +namespace Api.SeaHavenIndustries.DTOs +{ + public class EditQuote_DTO + { + public int id { get; set; } + public string? QuotId { get; set; } + public string? Date { get; set; } + public string? TT { get; set; } + public string? PO { get; set; } + public int? ContactId { get; set; } + public int? WorkorderId { get; set; } + public string? ProjectName { get; set; } + public string? SiteName { get; set; } + public string? SiteId { get; set; } + public string? BillingAddress { get; set; } + public ICollection? LineItems { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/ForgetPassword_Dto.cs b/Api.SeaHavenIndustries/DTOs/ForgetPassword_Dto.cs new file mode 100644 index 0000000..3ad9bae --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/ForgetPassword_Dto.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Api.SeaHavenIndustries.DTOs +{ + public class ForgetPassword_Dto + { + public string Email { get; set; } + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + public string? Password { get; set; } + public string? Code { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/LineItem_DTO.cs b/Api.SeaHavenIndustries/DTOs/LineItem_DTO.cs new file mode 100644 index 0000000..627da6b --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/LineItem_DTO.cs @@ -0,0 +1,9 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class LineItem_DTO + { + public int? LineitemNumber { get; set; } + public decimal? Lineitem { get; set; } + public string? Descriptions { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Location_DTO.cs b/Api.SeaHavenIndustries/DTOs/Location_DTO.cs new file mode 100644 index 0000000..1df28a3 --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Location_DTO.cs @@ -0,0 +1,8 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class Location_DTO + { + public string? Title { get; set; } + public string? Name { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Pagination_DTO.cs b/Api.SeaHavenIndustries/DTOs/Pagination_DTO.cs new file mode 100644 index 0000000..51749ea --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Pagination_DTO.cs @@ -0,0 +1,11 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class Pagination_DTO + { + public dynamic? Data { get; set; } + public int? PageNumber { get; set; } + public int? PageSize { get; set; } + public int? TotalCount { get; set; } + public int? TotalPages { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Quote_DTO.cs b/Api.SeaHavenIndustries/DTOs/Quote_DTO.cs new file mode 100644 index 0000000..bd24a19 --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Quote_DTO.cs @@ -0,0 +1,19 @@ +using Data.SeaHavenIndustries; + +namespace Api.SeaHavenIndustries.DTOs +{ + public class Quote_DTO + { + public string? QuotId { get; set; } + public string? Date { get; set; } + public string? TT { get; set; } + public string? PO { get; set; } + public int? ContactId { get; set; } + public int? WorkorderId { get; set; } + public string? ProjectName { get; set; } + public string? SiteName { get; set; } + public string? SiteId { get; set; } + public string? BillingAddress { get; set; } + public ICollection? LineItems { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Reporting_DTO.cs b/Api.SeaHavenIndustries/DTOs/Reporting_DTO.cs new file mode 100644 index 0000000..e5133bf --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Reporting_DTO.cs @@ -0,0 +1,13 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class Reporting_DTO + { + public int TotalCreatedWorkOrder { get; set; } + public int TotalCompleted { get; set; } + public int TotalSev1 { get; set; } + public int TotalSev2 { get; set; } + public int TotalSev3 { get; set; } + public int TotalSev4 { get; set; } + public int TotalSev5 { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Roles_DTO.cs b/Api.SeaHavenIndustries/DTOs/Roles_DTO.cs new file mode 100644 index 0000000..3743ad2 --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Roles_DTO.cs @@ -0,0 +1,9 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class Roles_DTO + { + public string? Name { get; set; } + public string? Description { get; set; } + } + +} diff --git a/Api.SeaHavenIndustries/DTOs/User_DTO.cs b/Api.SeaHavenIndustries/DTOs/User_DTO.cs new file mode 100644 index 0000000..8d1e68c --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/User_DTO.cs @@ -0,0 +1,17 @@ +namespace Api.SeaHavenIndustries.DTOs +{ + public class User_DTO + { + public string? Name { get; set; } + public string? Email { get; set; } + public string? Contact { get; set; } + public string? Role { get; set; } + } + public class EditUser_DTO + { + public string? Id { get; set; } + public string? Name { get; set; } + public string? Email { get; set; } + public string? Role { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/DTOs/Workorder_DTO.cs b/Api.SeaHavenIndustries/DTOs/Workorder_DTO.cs new file mode 100644 index 0000000..598e65f --- /dev/null +++ b/Api.SeaHavenIndustries/DTOs/Workorder_DTO.cs @@ -0,0 +1,74 @@ +using Data.SeaHavenIndustries; + +namespace Api.SeaHavenIndustries.DTOs +{ + public class Workorder_DTO + { + public string? WorkerOrderNumber { get; set; } + public string? WorkerOrderTitle { get; set; } + public string? Description { get; set; } + public string? PO { get; set; } + public string? TT { get; set; } + //public int? ContactId { get; set; } + public string? AssignTo { get; set; } + public DateTime? DueDate { get; set; } + public string? Priority { get; set; } + public int? LocationId { get; set; } + public bool? istemplate { get; set; } + //public int? CategoryId { get; set; } + + public List? Attachments { get; set; } + public string? BeforPhotoIssue { get; set; } + public IFormFile? BeforPhotoAttachment { get; set; } + public string? AfterPhotoIssue { get; set; } + public IFormFile? AfterPhotoAttachment { get; set; } + public string? SignOffName { get; set; } + public IFormFile? SignOffAttachment { get; set; } + public string? SignOffSignature { get; set; } + public string? WorkOrderContacts { get; set; } + public string? WorkOrderCategories { get; set; } + public List GetContactIds() + { + return WorkOrderContacts?.Split(',').Select(int.Parse).ToList() ?? new List(); + } + public List GetCategoryIds() + { + return WorkOrderCategories?.Split(',').Select(int.Parse).ToList() ?? new List(); + } + } + public class EditWorkorder_DTO + { + public int? Id { get; set; } + public string? WorkerOrderNumber { get; set; } + public string? WorkerOrderTitle { get; set; } + public string? Description { get; set; } + public string? PO { get; set; } + public string? TT { get; set; } + //public int? ContactId { get; set; } + public string? AssignTo { get; set; } + public DateTime? DueDate { get; set; } + public string? Priority { get; set; } + public int? LocationId { get; set; } + //public int? CategoryId { get; set; } + + public List? Attachments { get; set; } + public string? BeforPhotoIssue { get; set; } + public IFormFile? BeforPhotoAttachment { get; set; } + public string? AfterPhotoIssue { get; set; } + public IFormFile? AfterPhotoAttachment { get; set; } + public string? SignOffName { get; set; } + public IFormFile? SignOffAttachment { get; set; } + public string? SignOffSignature { get; set; } + public string? WorkOrderContacts { get; set; } + public string? WorkOrderCategories { get; set; } + public List GetContactIds() + { + return WorkOrderContacts?.Split(',').Select(int.Parse).ToList() ?? new List(); + } + public List GetCategoryIds() + { + return WorkOrderCategories?.Split(',').Select(int.Parse).ToList() ?? new List(); + } + } + +} \ No newline at end of file diff --git a/Api.SeaHavenIndustries/Helper/SendMessage.cs b/Api.SeaHavenIndustries/Helper/SendMessage.cs new file mode 100644 index 0000000..1a8189a --- /dev/null +++ b/Api.SeaHavenIndustries/Helper/SendMessage.cs @@ -0,0 +1,105 @@ + + +using SendGrid; +using SendGrid.Helpers.Mail; + +namespace Api.SeaHavenIndustries.Helper +{ + public class SendMessage + { + private IConfiguration _configuration; + //string keysapi = ""; + + public SendMessage(IConfiguration configuration) + { + _configuration = configuration; + //keysapi = _configuration.GetValue("SendGrid:ApiKey"); + } + + public async Task SendEMail(string emailTo, string subject, string body) + { + try + { + //MailMessage mail = new MailMessage(); + //mail.From = new MailAddress("infoesquall@codevoir.com"); //IMPORTANT: This must be same as your smtp authentication address. + //mail.To.Add(emailTo); + //mail.Subject = subject; + //mail.Body = body; + //mail.IsBodyHtml = true; + //SmtpClient smtp = new SmtpClient("mail.codevoir.com"); + //NetworkCredential Credentials = new NetworkCredential("infoesquall@codevoir.com", "Abc123!@#"); + //smtp.UseDefaultCredentials = false; + //smtp.Credentials = Credentials; + //smtp.Port = 8889; //25 alternative port number is 8889 + //smtp.EnableSsl = false; + + //smtp.Send(mail); + //var apiKey = Environment.GetEnvironmentVariable("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\r\n"); + //var apiKey1 = Environment.GetEnvironmentVariable("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"); + // var apiKey2 = Environment.GetEnvironmentVariable("SENDGRID_API_KEY"); + var apiKey = _configuration.GetValue("SendGrid:ApiKey"); + + //var apiKey = "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"; + var client = new SendGridClient(apiKey); + var from = new EmailAddress("tech@seahavenind.com", "Sea haven Industries"); + //var subject = "Sending with SendGrid is Fun"; + var to = new EmailAddress(emailTo, ""); + var apiKey3 = Environment.GetEnvironmentVariable("SendGrid:ApiKey"); + + var plainTextContent = ""; + var htmlContent = body; + var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent); + var response = await client.SendEmailAsync(msg); + var dd = response.Body.ReadAsStringAsync(); + return true; + } + catch (Exception ex) + { + return false; + } + } + public async Task SendEMailAttachment(string emailTo, string subject, byte[] pdfBytes) + { + try + { + + var apiKey = _configuration.GetValue("SendGrid:ApiKey"); + + //var apiKey = "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"; + var client = new SendGridClient(apiKey); + var from = new EmailAddress("tech@seahavenind.com", "Sea haven Industries"); + //var subject = "Sending with SendGrid is Fun"; + var to = new EmailAddress(emailTo, ""); + var apiKey3 = Environment.GetEnvironmentVariable("SendGrid:ApiKey"); + + var plainTextContent = "Please find the attached PDF"; + var htmlContent = ""; + var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, null); + + // Specify the content type for the attachment + var attachment = new SendGrid.Helpers.Mail.Attachment + { + Content = Convert.ToBase64String(pdfBytes), + Filename = "Workorder.pdf", + Type = "application/pdf", // Use the correct MIME type for PDF + Disposition = "attachment", + ContentId = "Attachment" // Optional: ContentId for inline attachments + }; + + msg.Attachments = new List { attachment }; + + var response = await client.SendEmailAsync(msg); + + var dd = response.Body.ReadAsStringAsync(); + return true; + } + catch (Exception ex) + { + return false; + } + } + } + + + +} diff --git a/Api.SeaHavenIndustries/Helper/ViewModel/FileUploadVM.cs b/Api.SeaHavenIndustries/Helper/ViewModel/FileUploadVM.cs new file mode 100644 index 0000000..6d22372 --- /dev/null +++ b/Api.SeaHavenIndustries/Helper/ViewModel/FileUploadVM.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Components.Forms; + +namespace Api.SeaHavenIndustries.Helper.ViewModel +{ + public class FileUploadVM + { + public IBrowserFile? file { get; set; } + public string? Name { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/Helper/ViewModel/UserRoleViewModel.cs b/Api.SeaHavenIndustries/Helper/ViewModel/UserRoleViewModel.cs new file mode 100644 index 0000000..b8cd73b --- /dev/null +++ b/Api.SeaHavenIndustries/Helper/ViewModel/UserRoleViewModel.cs @@ -0,0 +1,12 @@ +namespace Api.SeaHavenIndustries.Helper.ViewModel +{ + public class UserRoleViewModel + { + public string? Id { get; set; } + public string? UserName { get; set; } + public string? Email { get; set; } + public string? RoleName { get; set; } + public string? Status { get; set; } + public string? Date { get; set; } + } +} diff --git a/Api.SeaHavenIndustries/Program.cs b/Api.SeaHavenIndustries/Program.cs new file mode 100644 index 0000000..a97d198 --- /dev/null +++ b/Api.SeaHavenIndustries/Program.cs @@ -0,0 +1,104 @@ +using Api.SeaHavenIndustries.Helper; +using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using System.Text; + +var builder = WebApplication.CreateBuilder(args); +ConfigurationManager configuration = builder.Configuration; + +builder.Services.AddDbContext(options => options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"))); + +builder.Services.AddIdentity(options => +{ + options.User.RequireUniqueEmail = false; +}) + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); + +builder.Services.AddControllers().AddJsonOptions(options => +{ + options.JsonSerializerOptions.MaxDepth = 264; // or any other desired value +}); +builder.Services.AddResponseCompression(opts => +{ + opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( + new[] { "application/octet-stream" }); +}); +builder.Services.AddCors(option => +option.AddDefaultPolicy(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod())); +builder.Services.AddScoped(); +builder.Services.AddAuthentication(options => +{ + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; +}) +.AddJwtBearer(options => +{ + options.SaveToken = true; + options.RequireHttpsMetadata = false; + options.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuer = true, + ValidateAudience = true, + ValidAudience = configuration["JWT:ValidAudience"], + ValidIssuer = configuration["JWT:ValidIssuer"], + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Secret"])) + }; +}); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(c => +{ + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Seahaven", Version = "v1" }); + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() + { + Name = "Authorization", + Type = SecuritySchemeType.ApiKey, + Scheme = "Bearer", + BearerFormat = "JWT", + In = ParameterLocation.Header, + Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\"", + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + new string[] {} + } + }); +}); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment() || app.Environment.IsProduction()) +{ + app.UseSwagger(); + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Sari"); + c.RoutePrefix = string.Empty; + }); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); +app.UseCors(); +app.UseAuthentication(); +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/Api.SeaHavenIndustries/Properties/launchSettings.json b/Api.SeaHavenIndustries/Properties/launchSettings.json new file mode 100644 index 0000000..edc9b29 --- /dev/null +++ b/Api.SeaHavenIndustries/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:44666", + "sslPort": 44317 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5141", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7195;http://localhost:5141", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Api.SeaHavenIndustries/appsettings.Development.json b/Api.SeaHavenIndustries/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Api.SeaHavenIndustries/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Api.SeaHavenIndustries/appsettings.json b/Api.SeaHavenIndustries/appsettings.json new file mode 100644 index 0000000..063218d --- /dev/null +++ b/Api.SeaHavenIndustries/appsettings.json @@ -0,0 +1,23 @@ +{ + "ConnectionStrings": { + //"DefaultConnection": "Server=DESKTOP-64LC14O\SQLEXPRESS;Database=SeahavenIndustries;TrustServerCertificate=True;Trusted_Connection=True;MultipleActiveResultSets=true", + + // Test database + "DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustries;User Id=db_a7141e_seahavenindustries_admin;Password=Abc123!@#;MultipleActiveResultSets=true" + + //Client Database + //"DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustry;User Id=db_a7141e_seahavenindustry_admin;Password=Abc123!@#;MultipleActiveResultSets=true", + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "JWT": { + "ValidAudience": "http://localhost:4200", + "ValidIssuer": "http://localhost:7195", + "Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr" + } +} diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/01d16b4f-1224-4987-8fd2-63a27dfd2be8_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/01d16b4f-1224-4987-8fd2-63a27dfd2be8_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/01d16b4f-1224-4987-8fd2-63a27dfd2be8_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/043acb66-545c-4a74-b3c1-1c59c07d7fa2_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/043acb66-545c-4a74-b3c1-1c59c07d7fa2_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/043acb66-545c-4a74-b3c1-1c59c07d7fa2_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/051e8cb3-6d0f-43b3-9bbc-f29ffb30b717_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/051e8cb3-6d0f-43b3-9bbc-f29ffb30b717_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/051e8cb3-6d0f-43b3-9bbc-f29ffb30b717_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/0b31e287-7130-49b6-86af-a8b0dc352794_bgimage.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/0b31e287-7130-49b6-86af-a8b0dc352794_bgimage.png new file mode 100644 index 0000000..d9161a6 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/0b31e287-7130-49b6-86af-a8b0dc352794_bgimage.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/11934ade-1fd9-4dfd-9afc-a013d2628c1a_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/11934ade-1fd9-4dfd-9afc-a013d2628c1a_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/11934ade-1fd9-4dfd-9afc-a013d2628c1a_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/11c78a9a-2840-41cf-81e7-ae78e7cf2722_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/11c78a9a-2840-41cf-81e7-ae78e7cf2722_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/11c78a9a-2840-41cf-81e7-ae78e7cf2722_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/261415f4-c93a-422c-9d48-d03c4e9016f2_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/261415f4-c93a-422c-9d48-d03c4e9016f2_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/261415f4-c93a-422c-9d48-d03c4e9016f2_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/2735f2cb-7bfa-4eac-bfb1-2495d21ed0d8_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/2735f2cb-7bfa-4eac-bfb1-2495d21ed0d8_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/2735f2cb-7bfa-4eac-bfb1-2495d21ed0d8_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/373a3c93-2c05-4307-bd69-18442600dfb8_bgimage.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/373a3c93-2c05-4307-bd69-18442600dfb8_bgimage.png new file mode 100644 index 0000000..d9161a6 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/373a3c93-2c05-4307-bd69-18442600dfb8_bgimage.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/3a11c89f-9da6-47eb-bc0c-ecdbebb9fd64_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/3a11c89f-9da6-47eb-bc0c-ecdbebb9fd64_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/3a11c89f-9da6-47eb-bc0c-ecdbebb9fd64_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4002296f-2db6-45b6-9738-f1ac31d688c8_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4002296f-2db6-45b6-9738-f1ac31d688c8_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4002296f-2db6-45b6-9738-f1ac31d688c8_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/40089f92-85dd-42f1-a3b3-43457cde71ff_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/40089f92-85dd-42f1-a3b3-43457cde71ff_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/40089f92-85dd-42f1-a3b3-43457cde71ff_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/41f80356-09f6-4ce6-bd47-8f49e13876b3_bgimage.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/41f80356-09f6-4ce6-bd47-8f49e13876b3_bgimage.png new file mode 100644 index 0000000..d9161a6 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/41f80356-09f6-4ce6-bd47-8f49e13876b3_bgimage.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/474e53b9-a1df-4b5e-b572-f504fde0b312_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/474e53b9-a1df-4b5e-b572-f504fde0b312_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/474e53b9-a1df-4b5e-b572-f504fde0b312_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4989c0f0-af54-41c3-9839-5dd8241ac161_bg-image.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4989c0f0-af54-41c3-9839-5dd8241ac161_bg-image.png new file mode 100644 index 0000000..4ec830c Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4989c0f0-af54-41c3-9839-5dd8241ac161_bg-image.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4ab1822f-9d16-44e3-a270-b6d8cf48e32d_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4ab1822f-9d16-44e3-a270-b6d8cf48e32d_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/4ab1822f-9d16-44e3-a270-b6d8cf48e32d_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/51425bb4-4088-4c30-8184-715d3cff6aee_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/51425bb4-4088-4c30-8184-715d3cff6aee_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/51425bb4-4088-4c30-8184-715d3cff6aee_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/551fd2a0-1c4f-46c3-8f1a-013130f2bc69_bgimage.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/551fd2a0-1c4f-46c3-8f1a-013130f2bc69_bgimage.png new file mode 100644 index 0000000..d9161a6 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/551fd2a0-1c4f-46c3-8f1a-013130f2bc69_bgimage.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/559eedf7-3c60-432f-870c-4ee1f2ee16c4_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/559eedf7-3c60-432f-870c-4ee1f2ee16c4_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/559eedf7-3c60-432f-870c-4ee1f2ee16c4_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/57c5fad9-77bf-4b76-9e14-7da0a0cf4164_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/57c5fad9-77bf-4b76-9e14-7da0a0cf4164_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/57c5fad9-77bf-4b76-9e14-7da0a0cf4164_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/5d12ebc9-9c8c-471e-95aa-2240d12e8404_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/5d12ebc9-9c8c-471e-95aa-2240d12e8404_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/5d12ebc9-9c8c-471e-95aa-2240d12e8404_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/5dad9597-ce30-4ef0-912c-fc881a60c7e8_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/5dad9597-ce30-4ef0-912c-fc881a60c7e8_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/5dad9597-ce30-4ef0-912c-fc881a60c7e8_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/60eeed67-5451-457a-8192-bc152183ca0e_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/60eeed67-5451-457a-8192-bc152183ca0e_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/60eeed67-5451-457a-8192-bc152183ca0e_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/61b9bc74-7f62-4afe-b54f-6a36b677fb2a_Arrows.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/61b9bc74-7f62-4afe-b54f-6a36b677fb2a_Arrows.png new file mode 100644 index 0000000..ffb9e25 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/61b9bc74-7f62-4afe-b54f-6a36b677fb2a_Arrows.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/61dd1bc3-4145-4a05-a562-565b2d466734_bg-image.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/61dd1bc3-4145-4a05-a562-565b2d466734_bg-image.png new file mode 100644 index 0000000..4ec830c Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/61dd1bc3-4145-4a05-a562-565b2d466734_bg-image.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/64d9df0e-b08e-42f5-9fb2-3a298ce8472a_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/64d9df0e-b08e-42f5-9fb2-3a298ce8472a_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/64d9df0e-b08e-42f5-9fb2-3a298ce8472a_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/66b624e8-e20e-47a7-91a0-84592b4a09e3_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/66b624e8-e20e-47a7-91a0-84592b4a09e3_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/66b624e8-e20e-47a7-91a0-84592b4a09e3_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6b506e00-6d5f-40a6-ad24-b131d362c967_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6b506e00-6d5f-40a6-ad24-b131d362c967_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6b506e00-6d5f-40a6-ad24-b131d362c967_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6b922cb8-a545-49b9-96f7-58353a6a49d0_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6b922cb8-a545-49b9-96f7-58353a6a49d0_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6b922cb8-a545-49b9-96f7-58353a6a49d0_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6d86e8a4-8fee-4e30-965e-50fb39fdbae5_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6d86e8a4-8fee-4e30-965e-50fb39fdbae5_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/6d86e8a4-8fee-4e30-965e-50fb39fdbae5_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/70d36660-c176-4c01-b4c8-ccbf53461b3f_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/70d36660-c176-4c01-b4c8-ccbf53461b3f_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/70d36660-c176-4c01-b4c8-ccbf53461b3f_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/767b0dc5-2ce8-4a9c-9a06-fd1b45c0d024_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/767b0dc5-2ce8-4a9c-9a06-fd1b45c0d024_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/767b0dc5-2ce8-4a9c-9a06-fd1b45c0d024_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/7f31c92a-764d-4ac0-88a9-5e66fe1c930e_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/7f31c92a-764d-4ac0-88a9-5e66fe1c930e_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/7f31c92a-764d-4ac0-88a9-5e66fe1c930e_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/809229a0-ba63-4974-a825-ad31da95b778_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/809229a0-ba63-4974-a825-ad31da95b778_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/809229a0-ba63-4974-a825-ad31da95b778_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/87c15433-5a72-4c38-828b-93062817ab14_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/87c15433-5a72-4c38-828b-93062817ab14_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/87c15433-5a72-4c38-828b-93062817ab14_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/8f2b8016-a666-4809-8d39-201b241023c3_bgimage.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/8f2b8016-a666-4809-8d39-201b241023c3_bgimage.png new file mode 100644 index 0000000..d9161a6 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/8f2b8016-a666-4809-8d39-201b241023c3_bgimage.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9358d166-6f8b-4857-a3e3-e407413d02f2_Arrows.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9358d166-6f8b-4857-a3e3-e407413d02f2_Arrows.png new file mode 100644 index 0000000..ffb9e25 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9358d166-6f8b-4857-a3e3-e407413d02f2_Arrows.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/982f4dfa-3ab5-4829-9938-b2804708fea1_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/982f4dfa-3ab5-4829-9938-b2804708fea1_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/982f4dfa-3ab5-4829-9938-b2804708fea1_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9f866ab8-33eb-4d54-88c8-5cf07b4ed48f_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9f866ab8-33eb-4d54-88c8-5cf07b4ed48f_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9f866ab8-33eb-4d54-88c8-5cf07b4ed48f_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9fa914bf-cf8e-4279-a735-e7c151a8a3c0_bgimage.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9fa914bf-cf8e-4279-a735-e7c151a8a3c0_bgimage.png new file mode 100644 index 0000000..d9161a6 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/9fa914bf-cf8e-4279-a735-e7c151a8a3c0_bgimage.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/a3a8c454-5b7e-4489-a257-1609f21e62fe_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/a3a8c454-5b7e-4489-a257-1609f21e62fe_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/a3a8c454-5b7e-4489-a257-1609f21e62fe_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/a6a592b5-4064-4b94-8616-99eec95855fb_Arrows.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/a6a592b5-4064-4b94-8616-99eec95855fb_Arrows.png new file mode 100644 index 0000000..ffb9e25 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/a6a592b5-4064-4b94-8616-99eec95855fb_Arrows.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ada238f7-2b9c-4177-a110-5a56bb5e48ae_bg-image.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ada238f7-2b9c-4177-a110-5a56bb5e48ae_bg-image.png new file mode 100644 index 0000000..4ec830c Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ada238f7-2b9c-4177-a110-5a56bb5e48ae_bg-image.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/b2c64a54-f590-4fd5-b0c1-12e3792bf106_BG 1.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/b2c64a54-f590-4fd5-b0c1-12e3792bf106_BG 1.png new file mode 100644 index 0000000..bea4418 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/b2c64a54-f590-4fd5-b0c1-12e3792bf106_BG 1.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/bd6bab46-90e9-46ca-972f-ae760173eaf4_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/bd6bab46-90e9-46ca-972f-ae760173eaf4_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/bd6bab46-90e9-46ca-972f-ae760173eaf4_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/bdbd2b5b-3ef2-4a11-b513-38ac1c736fe7_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/bdbd2b5b-3ef2-4a11-b513-38ac1c736fe7_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/bdbd2b5b-3ef2-4a11-b513-38ac1c736fe7_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c02f5448-8ad8-4b29-a084-7035ec9f015d_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c02f5448-8ad8-4b29-a084-7035ec9f015d_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c02f5448-8ad8-4b29-a084-7035ec9f015d_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c69840f3-ec44-4aa0-bca5-acd1f28c2ace_Arrows.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c69840f3-ec44-4aa0-bca5-acd1f28c2ace_Arrows.png new file mode 100644 index 0000000..ffb9e25 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c69840f3-ec44-4aa0-bca5-acd1f28c2ace_Arrows.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c6edacdc-7a6a-4950-bb85-12b86bcbc64f_bgimage.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c6edacdc-7a6a-4950-bb85-12b86bcbc64f_bgimage.png new file mode 100644 index 0000000..d9161a6 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c6edacdc-7a6a-4950-bb85-12b86bcbc64f_bgimage.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c89a5638-11ce-4a07-a7a0-a0deb43b66b1_apple.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c89a5638-11ce-4a07-a7a0-a0deb43b66b1_apple.png new file mode 100644 index 0000000..b8b7fb1 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c89a5638-11ce-4a07-a7a0-a0deb43b66b1_apple.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c92bffc6-e36d-4838-8742-3331e6683f03_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c92bffc6-e36d-4838-8742-3331e6683f03_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/c92bffc6-e36d-4838-8742-3331e6683f03_BG 2.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ca5dea85-3006-49c2-b0a4-0a0743842740_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ca5dea85-3006-49c2-b0a4-0a0743842740_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ca5dea85-3006-49c2-b0a4-0a0743842740_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ca68ca00-4d12-4e84-b691-35bc2d582dec_Arrows.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ca68ca00-4d12-4e84-b691-35bc2d582dec_Arrows.png new file mode 100644 index 0000000..ffb9e25 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/ca68ca00-4d12-4e84-b691-35bc2d582dec_Arrows.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/e63d809f-2cb3-42b5-8131-3be00286f4fe_BG 3.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/e63d809f-2cb3-42b5-8131-3be00286f4fe_BG 3.png new file mode 100644 index 0000000..f8fdff8 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/e63d809f-2cb3-42b5-8131-3be00286f4fe_BG 3.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/e94ba80a-64c7-4c1b-97f1-c85c0802a6ec_Arrows.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/e94ba80a-64c7-4c1b-97f1-c85c0802a6ec_Arrows.png new file mode 100644 index 0000000..ffb9e25 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/e94ba80a-64c7-4c1b-97f1-c85c0802a6ec_Arrows.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/f2608ee0-62a9-4445-bf4b-ad69bc22dbae_bestseller.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/f2608ee0-62a9-4445-bf4b-ad69bc22dbae_bestseller.png new file mode 100644 index 0000000..8815396 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/f2608ee0-62a9-4445-bf4b-ad69bc22dbae_bestseller.png differ diff --git a/Api.SeaHavenIndustries/wwwroot/Assets/Documents/f32f6d31-9608-42ff-a136-b026dbe39bd1_BG 2.png b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/f32f6d31-9608-42ff-a136-b026dbe39bd1_BG 2.png new file mode 100644 index 0000000..8af2351 Binary files /dev/null and b/Api.SeaHavenIndustries/wwwroot/Assets/Documents/f32f6d31-9608-42ff-a136-b026dbe39bd1_BG 2.png differ diff --git a/Data.SeaHavenIndustries/Auth/ApplicationDbContext.cs b/Data.SeaHavenIndustries/Auth/ApplicationDbContext.cs new file mode 100644 index 0000000..e1938ad --- /dev/null +++ b/Data.SeaHavenIndustries/Auth/ApplicationDbContext.cs @@ -0,0 +1,71 @@ + +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Linq; + +namespace Data.SeaHavenIndustries +{ + public class ApplicationDbContext : IdentityDbContext + { + public ApplicationDbContext(DbContextOptions options) : base(options) + { + } + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + foreach (var foreignKey in builder.Model.GetEntityTypes().SelectMany + (e => e.GetForeignKeys())) + { + foreignKey.DeleteBehavior = DeleteBehavior.Restrict; + } + } + public DbSet Categories { get; set; } + public DbSet Locations { get; set; } + public DbSet Contacts { get; set; } + public DbSet workOrders { get; set; } + public DbSet