using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text.Json; using System.Threading.Tasks; using Npgsql; using NpgsqlTypes; using SkyArtShop.Models; namespace SkyArtShop.Services; public class PostgreSQLService { private readonly string _connectionString; public PostgreSQLService(string connectionString) { _connectionString = connectionString; } private async Task GetConnectionAsync() { NpgsqlConnection conn = new NpgsqlConnection(_connectionString); await conn.OpenAsync(); return conn; } public async Task> GetAllAsync(string tableName) where T : class, new() { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "SELECT * FROM " + tableName.ToLower(); using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); using NpgsqlDataReader reader = await cmd.ExecuteReaderAsync(); List results = new List(); while (await reader.ReadAsync()) { results.Add(MapToObject(reader)); } return results; } public async Task GetByIdAsync(string tableName, string id) where T : class, new() { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "SELECT * FROM " + tableName.ToLower() + " WHERE id = @id"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("id", id); using NpgsqlDataReader reader = await cmd.ExecuteReaderAsync(); if (await reader.ReadAsync()) { return MapToObject(reader); } return null; } public async Task GetUserByEmailAsync(string email) { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "SELECT * FROM adminusers WHERE LOWER(email) = LOWER(@email) AND isactive = true"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("email", email); using NpgsqlDataReader reader = await cmd.ExecuteReaderAsync(); if (await reader.ReadAsync()) { return MapToAdminUser(reader); } return null; } public async Task UpdateUserLastLoginAsync(string userId, DateTime lastLogin) { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "UPDATE adminusers SET lastlogin = @lastlogin WHERE id = @id"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("id", userId); cmd.Parameters.AddWithValue("lastlogin", lastLogin); await cmd.ExecuteNonQueryAsync(); } public async Task CreateAdminUserAsync(AdminUser user) { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "INSERT INTO adminusers (id, email, passwordhash, name, role, permissions, isactive, createdby, createdat)\n VALUES (@id, @email, @passwordhash, @name, @role, @permissions::jsonb, @isactive, @createdby, @createdat)"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("id", Guid.NewGuid().ToString()); cmd.Parameters.AddWithValue("email", user.Email); cmd.Parameters.AddWithValue("passwordhash", user.PasswordHash); cmd.Parameters.AddWithValue("name", user.Name); cmd.Parameters.AddWithValue("role", user.Role); cmd.Parameters.AddWithValue("permissions", JsonSerializer.Serialize(user.Permissions)); cmd.Parameters.AddWithValue("isactive", user.IsActive); cmd.Parameters.AddWithValue("createdby", user.CreatedBy); cmd.Parameters.AddWithValue("createdat", user.CreatedAt); await cmd.ExecuteNonQueryAsync(); } public async Task> GetProductsAsync() { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "SELECT * FROM products WHERE isactive = true ORDER BY createdat DESC"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); using NpgsqlDataReader reader = await cmd.ExecuteReaderAsync(); List results = new List(); while (await reader.ReadAsync()) { results.Add(MapToProduct(reader)); } return results; } public async Task GetProductBySlugAsync(string slug) { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "SELECT * FROM products WHERE slug = @slug AND isactive = true"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("slug", slug); using NpgsqlDataReader reader = await cmd.ExecuteReaderAsync(); if (await reader.ReadAsync()) { return MapToProduct(reader); } return null; } public async Task GetPageBySlugAsync(string slug) { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "SELECT * FROM pages WHERE pageslug = @slug AND isactive = true"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("slug", slug); using NpgsqlDataReader reader = await cmd.ExecuteReaderAsync(); if (await reader.ReadAsync()) { return MapToPage(reader); } return null; } public async Task GetSiteSettingsAsync() { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "SELECT * FROM sitesettings LIMIT 1"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); using NpgsqlDataReader reader = await cmd.ExecuteReaderAsync(); if (await reader.ReadAsync()) { return MapToSiteSettings(reader); } return null; } public async Task> GetMenuItemsAsync() { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "SELECT * FROM menuitems WHERE isactive = true ORDER BY displayorder"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); using NpgsqlDataReader reader = await cmd.ExecuteReaderAsync(); List results = new List(); while (await reader.ReadAsync()) { results.Add(MapToMenuItem(reader)); } return results; } public async Task InsertAsync(string tableName, T entity) where T : class { using NpgsqlConnection conn = await GetConnectionAsync(); Type typeFromHandle = typeof(T); List list = (from p in typeFromHandle.GetProperties() where p.CanRead && p.Name != "Id" select p).ToList(); PropertyInfo property = typeFromHandle.GetProperty("Id"); if (property != null && string.IsNullOrEmpty(property.GetValue(entity)?.ToString())) { property.SetValue(entity, Guid.NewGuid().ToString()); } string value = string.Join(", ", list.Select((PropertyInfo p) => p.Name.ToLower()).Prepend("id")); string value2 = string.Join(", ", list.Select((PropertyInfo p) => "@" + p.Name.ToLower()).Prepend("@id")); string cmdText = $"INSERT INTO {tableName.ToLower()} ({value}) VALUES ({value2})"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("id", property?.GetValue(entity)?.ToString() ?? Guid.NewGuid().ToString()); foreach (PropertyInfo item in list) { object value3 = item.GetValue(entity); string parameterName = item.Name.ToLower(); if (value3 == null) { cmd.Parameters.AddWithValue(parameterName, DBNull.Value); } else if (item.PropertyType == typeof(List) || item.PropertyType == typeof(List) || item.PropertyType == typeof(List) || item.PropertyType == typeof(Dictionary)) { cmd.Parameters.AddWithValue(parameterName, NpgsqlDbType.Jsonb, JsonSerializer.Serialize(value3)); } else if (item.PropertyType == typeof(DateTime) || item.PropertyType == typeof(DateTime?)) { cmd.Parameters.AddWithValue(parameterName, value3); } else if (item.PropertyType == typeof(bool) || item.PropertyType == typeof(bool?)) { cmd.Parameters.AddWithValue(parameterName, value3); } else { cmd.Parameters.AddWithValue(parameterName, value3); } } await cmd.ExecuteNonQueryAsync(); } public async Task UpdateAsync(string tableName, string id, T entity) where T : class { using NpgsqlConnection conn = await GetConnectionAsync(); Type typeFromHandle = typeof(T); List list = (from p in typeFromHandle.GetProperties() where p.CanRead && p.Name != "Id" select p).ToList(); string value = string.Join(", ", list.Select((PropertyInfo p) => p.Name.ToLower() + " = @" + p.Name.ToLower())); string cmdText = $"UPDATE {tableName.ToLower()} SET {value} WHERE id = @id"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("id", id); foreach (PropertyInfo item in list) { object value2 = item.GetValue(entity); string parameterName = item.Name.ToLower(); if (value2 == null) { cmd.Parameters.AddWithValue(parameterName, DBNull.Value); } else if (item.PropertyType == typeof(List) || item.PropertyType == typeof(List) || item.PropertyType == typeof(List) || item.PropertyType == typeof(Dictionary)) { cmd.Parameters.AddWithValue(parameterName, NpgsqlDbType.Jsonb, JsonSerializer.Serialize(value2)); } else if (item.PropertyType == typeof(DateTime) || item.PropertyType == typeof(DateTime?)) { cmd.Parameters.AddWithValue(parameterName, value2); } else if (item.PropertyType == typeof(bool) || item.PropertyType == typeof(bool?)) { cmd.Parameters.AddWithValue(parameterName, value2); } else { cmd.Parameters.AddWithValue(parameterName, value2); } } await cmd.ExecuteNonQueryAsync(); } public async Task DeleteAsync(string tableName, string id) where T : class { using NpgsqlConnection conn = await GetConnectionAsync(); string cmdText = "DELETE FROM " + tableName.ToLower() + " WHERE id = @id"; using NpgsqlCommand cmd = new NpgsqlCommand(cmdText, conn); cmd.Parameters.AddWithValue("id", id); await cmd.ExecuteNonQueryAsync(); } private T MapToObject(NpgsqlDataReader reader) where T : class, new() { Type typeFromHandle = typeof(T); if (typeFromHandle == typeof(AdminUser)) { return (MapToAdminUser(reader) as T) ?? new T(); } if (typeFromHandle == typeof(Product)) { return (MapToProduct(reader) as T) ?? new T(); } if (typeFromHandle == typeof(Page)) { return (MapToPage(reader) as T) ?? new T(); } if (typeFromHandle == typeof(MenuItem)) { return (MapToMenuItem(reader) as T) ?? new T(); } if (typeFromHandle == typeof(SiteSettings)) { return (MapToSiteSettings(reader) as T) ?? new T(); } if (typeFromHandle == typeof(PortfolioCategory)) { return (MapToPortfolioCategory(reader) as T) ?? new T(); } if (typeFromHandle == typeof(PortfolioProject)) { return (MapToPortfolioProject(reader) as T) ?? new T(); } if (typeFromHandle == typeof(BlogPost)) { return (MapToBlogPost(reader) as T) ?? new T(); } if (typeFromHandle == typeof(HomepageSection)) { return (MapToHomepageSection(reader) as T) ?? new T(); } return new T(); } private AdminUser MapToAdminUser(NpgsqlDataReader reader) { AdminUser adminUser = new AdminUser(); adminUser.Id = reader["id"].ToString(); adminUser.Email = reader["email"].ToString() ?? ""; adminUser.PasswordHash = reader["passwordhash"].ToString() ?? ""; adminUser.Name = reader["name"].ToString() ?? ""; adminUser.Role = reader["role"].ToString() ?? "Admin"; adminUser.Permissions = JsonSerializer.Deserialize>(reader["permissions"].ToString() ?? "[]") ?? new List(); adminUser.IsActive = (reader["isactive"] as bool?) ?? true; adminUser.CreatedBy = reader["createdby"]?.ToString() ?? ""; adminUser.CreatedAt = (reader["createdat"] as DateTime?) ?? DateTime.UtcNow; adminUser.LastLogin = (reader.IsDBNull(reader.GetOrdinal("lastlogin")) ? ((DateTime?)null) : new DateTime?(reader.GetDateTime(reader.GetOrdinal("lastlogin")))); adminUser.Phone = reader["phone"]?.ToString() ?? ""; adminUser.Notes = reader["notes"]?.ToString() ?? ""; return adminUser; } private Product MapToProduct(NpgsqlDataReader reader) { Product product = new Product(); product.Id = reader["id"].ToString(); product.Name = reader["name"].ToString() ?? ""; product.Slug = reader["slug"].ToString() ?? ""; product.SKU = reader["sku"]?.ToString() ?? ""; product.ShortDescription = reader["shortdescription"]?.ToString() ?? ""; product.Description = reader["description"]?.ToString() ?? ""; product.Price = (reader["price"] as decimal?).GetValueOrDefault(); product.Category = reader["category"]?.ToString() ?? ""; product.Color = reader["color"]?.ToString() ?? ""; product.Colors = JsonSerializer.Deserialize>(reader["colors"].ToString() ?? "[]") ?? new List(); product.ImageUrl = reader["imageurl"]?.ToString() ?? ""; product.Images = JsonSerializer.Deserialize>(reader["images"].ToString() ?? "[]") ?? new List(); product.IsFeatured = reader["isfeatured"] as bool? == true; product.IsTopSeller = reader["istopseller"] as bool? == true; product.StockQuantity = (reader["stockquantity"] as int?).GetValueOrDefault(); product.IsActive = (reader["isactive"] as bool?) ?? true; product.UnitsSold = (reader["unitssold"] as int?).GetValueOrDefault(); product.TotalRevenue = (reader["totalrevenue"] as decimal?).GetValueOrDefault(); product.AverageRating = (reader["averagerating"] as double?).GetValueOrDefault(); product.TotalReviews = (reader["totalreviews"] as int?).GetValueOrDefault(); product.CostPrice = (reader["costprice"] as decimal?).GetValueOrDefault(); product.Tags = JsonSerializer.Deserialize>(reader["tags"].ToString() ?? "[]") ?? new List(); product.MetaDescription = reader["metadescription"]?.ToString() ?? ""; product.CreatedAt = (reader["createdat"] as DateTime?) ?? DateTime.UtcNow; product.UpdatedAt = (reader["updatedat"] as DateTime?) ?? DateTime.UtcNow; return product; } private Page MapToPage(NpgsqlDataReader reader) { Page page = new Page(); page.Id = reader["id"].ToString(); page.PageName = reader["pagename"].ToString() ?? ""; page.PageSlug = reader["pageslug"].ToString() ?? ""; page.Title = reader["title"]?.ToString() ?? ""; page.Subtitle = reader["subtitle"]?.ToString() ?? ""; page.HeroImage = reader["heroimage"]?.ToString() ?? ""; page.Content = reader["content"]?.ToString() ?? ""; page.MetaDescription = reader["metadescription"]?.ToString() ?? ""; page.ImageGallery = JsonSerializer.Deserialize>(reader["imagegallery"].ToString() ?? "[]") ?? new List(); page.IsActive = (reader["isactive"] as bool?) ?? true; page.CreatedAt = (reader["createdat"] as DateTime?) ?? DateTime.UtcNow; page.UpdatedAt = (reader["updatedat"] as DateTime?) ?? DateTime.UtcNow; return page; } private MenuItem MapToMenuItem(NpgsqlDataReader reader) { MenuItem menuItem = new MenuItem(); menuItem.Id = reader["id"].ToString(); menuItem.Label = reader["label"].ToString() ?? ""; menuItem.Url = reader["url"].ToString() ?? ""; menuItem.DisplayOrder = (reader["displayorder"] as int?).GetValueOrDefault(); menuItem.IsActive = (reader["isactive"] as bool?) ?? true; menuItem.ShowInNavbar = (reader["showinnavbar"] as bool?) ?? true; menuItem.ShowInDropdown = (reader["showindropdown"] as bool?) ?? true; menuItem.OpenInNewTab = reader["openinnewtab"] as bool? == true; menuItem.CreatedAt = (reader["createdat"] as DateTime?) ?? DateTime.UtcNow; return menuItem; } private SiteSettings MapToSiteSettings(NpgsqlDataReader reader) { SiteSettings siteSettings = new SiteSettings(); siteSettings.Id = reader["id"].ToString(); siteSettings.SiteName = reader["sitename"]?.ToString() ?? "Sky Art Shop"; siteSettings.SiteTagline = reader["sitetagline"]?.ToString() ?? ""; siteSettings.ContactEmail = reader["contactemail"]?.ToString() ?? ""; siteSettings.ContactPhone = reader["contactphone"]?.ToString() ?? ""; siteSettings.InstagramUrl = reader["instagramurl"]?.ToString() ?? "#"; siteSettings.FooterText = reader["footertext"]?.ToString() ?? ""; siteSettings.UpdatedAt = (reader["updatedat"] as DateTime?) ?? DateTime.UtcNow; return siteSettings; } private PortfolioCategory MapToPortfolioCategory(NpgsqlDataReader reader) { PortfolioCategory portfolioCategory = new PortfolioCategory(); portfolioCategory.Id = reader["id"].ToString(); portfolioCategory.Name = reader["name"].ToString() ?? ""; portfolioCategory.Slug = reader["slug"].ToString() ?? ""; portfolioCategory.Description = reader["description"]?.ToString() ?? ""; portfolioCategory.ThumbnailImage = reader["thumbnailimage"]?.ToString() ?? ""; portfolioCategory.FeaturedImage = reader["featuredimage"]?.ToString() ?? ""; portfolioCategory.DisplayOrder = (reader["displayorder"] as int?).GetValueOrDefault(); portfolioCategory.IsActive = (reader["isactive"] as bool?) ?? true; portfolioCategory.CreatedAt = (reader["createdat"] as DateTime?) ?? DateTime.UtcNow; portfolioCategory.UpdatedAt = (reader["updatedat"] as DateTime?) ?? DateTime.UtcNow; return portfolioCategory; } private BlogPost MapToBlogPost(NpgsqlDataReader reader) { BlogPost blogPost = new BlogPost(); blogPost.Id = reader["id"].ToString(); blogPost.Title = reader["title"].ToString() ?? ""; blogPost.Slug = reader["slug"].ToString() ?? ""; blogPost.Content = reader["content"]?.ToString() ?? ""; blogPost.Excerpt = reader["excerpt"]?.ToString() ?? ""; blogPost.FeaturedImage = reader["featuredimage"]?.ToString() ?? ""; blogPost.Author = reader["author"]?.ToString() ?? ""; blogPost.Tags = JsonSerializer.Deserialize>(reader["tags"].ToString() ?? "[]") ?? new List(); blogPost.IsPublished = (reader["ispublished"] as bool?) ?? true; blogPost.PublishedDate = (reader["publisheddate"] as DateTime?) ?? DateTime.UtcNow; blogPost.CreatedAt = (reader["createdat"] as DateTime?) ?? DateTime.UtcNow; blogPost.UpdatedAt = (reader["updatedat"] as DateTime?) ?? DateTime.UtcNow; return blogPost; } private HomepageSection MapToHomepageSection(NpgsqlDataReader reader) { HomepageSection homepageSection = new HomepageSection(); homepageSection.Id = reader["id"].ToString(); homepageSection.Title = reader["title"]?.ToString() ?? ""; homepageSection.Subtitle = reader["subtitle"]?.ToString() ?? ""; homepageSection.Content = reader["content"]?.ToString() ?? ""; homepageSection.SectionType = reader["sectiontype"]?.ToString() ?? ""; homepageSection.ImageUrl = reader["imageurl"]?.ToString() ?? ""; homepageSection.ButtonText = reader["buttontext"]?.ToString() ?? ""; homepageSection.ButtonUrl = reader["buttonurl"]?.ToString() ?? ""; homepageSection.IsActive = (reader["isactive"] as bool?) ?? true; homepageSection.DisplayOrder = (reader["displayorder"] as int?).GetValueOrDefault(); homepageSection.AdditionalData = JsonSerializer.Deserialize>(reader["additionaldata"]?.ToString() ?? "{}") ?? new Dictionary(); homepageSection.CreatedAt = (reader["createdat"] as DateTime?) ?? DateTime.UtcNow; homepageSection.UpdatedAt = (reader["updatedat"] as DateTime?) ?? DateTime.UtcNow; return homepageSection; } private PortfolioProject MapToPortfolioProject(NpgsqlDataReader reader) { PortfolioProject portfolioProject = new PortfolioProject(); portfolioProject.Id = reader["id"].ToString(); portfolioProject.CategoryId = reader["categoryid"]?.ToString() ?? ""; portfolioProject.Title = reader["title"]?.ToString() ?? ""; portfolioProject.Description = reader["description"]?.ToString() ?? ""; portfolioProject.FeaturedImage = reader["featuredimage"]?.ToString() ?? ""; portfolioProject.Images = JsonSerializer.Deserialize>(reader["images"].ToString() ?? "[]") ?? new List(); portfolioProject.DisplayOrder = (reader["displayorder"] as int?).GetValueOrDefault(); portfolioProject.IsActive = (reader["isactive"] as bool?) ?? true; portfolioProject.CreatedAt = (reader["createdat"] as DateTime?) ?? DateTime.UtcNow; portfolioProject.UpdatedAt = (reader["updatedat"] as DateTime?) ?? DateTime.UtcNow; return portfolioProject; } }