Webiant Logo Webiant Logo
  1. No results found.

    Try your search with a different keyword or use * as a wildcard.

GdprService.cs

using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Gdpr;
using Nop.Core.Events;
using Nop.Data;
using Nop.Services.Authentication.External;
using Nop.Services.Blogs;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Forums;
using Nop.Services.Messages;
using Nop.Services.News;
using Nop.Services.Orders;
using Nop.Services.Stores;

namespace Nop.Services.Gdpr;

/// 
/// Represents the GDPR service
/// 
public partial class GdprService : IGdprService
{
    #region Fields

    protected readonly IAddressService _addressService;
    protected readonly IBackInStockSubscriptionService _backInStockSubscriptionService;
    protected readonly IBlogService _blogService;
    protected readonly ICustomerService _customerService;
    protected readonly IExternalAuthenticationService _externalAuthenticationService;
    protected readonly IEventPublisher _eventPublisher;
    protected readonly IForumService _forumService;
    protected readonly IGenericAttributeService _genericAttributeService;
    protected readonly INewsLetterSubscriptionService _newsLetterSubscriptionService;
    protected readonly INewsService _newsService;
    protected readonly IProductService _productService;
    protected readonly IRepository _gdprConsentRepository;
    protected readonly IRepository _gdprLogRepository;
    protected readonly IShoppingCartService _shoppingCartService;
    protected readonly IStoreService _storeService;

    #endregion

    #region Ctor

    public GdprService(IAddressService addressService,
        IBackInStockSubscriptionService backInStockSubscriptionService,
        IBlogService blogService,
        ICustomerService customerService,
        IExternalAuthenticationService externalAuthenticationService,
        IEventPublisher eventPublisher,
        IForumService forumService,
        IGenericAttributeService genericAttributeService,
        INewsService newsService,
        INewsLetterSubscriptionService newsLetterSubscriptionService,
        IProductService productService,
        IRepository gdprConsentRepository,
        IRepository gdprLogRepository,
        IShoppingCartService shoppingCartService,
        IStoreService storeService)
    {
        _addressService = addressService;
        _backInStockSubscriptionService = backInStockSubscriptionService;
        _blogService = blogService;
        _customerService = customerService;
        _externalAuthenticationService = externalAuthenticationService;
        _eventPublisher = eventPublisher;
        _forumService = forumService;
        _genericAttributeService = genericAttributeService;
        _newsService = newsService;
        _newsLetterSubscriptionService = newsLetterSubscriptionService;
        _productService = productService;
        _gdprConsentRepository = gdprConsentRepository;
        _gdprLogRepository = gdprLogRepository;
        _shoppingCartService = shoppingCartService;
        _storeService = storeService;
    }

    #endregion

    #region Utilities

    /// 
    /// Insert a GDPR log
    /// 
    /// GDPR log
    /// A task that represents the asynchronous operation
    protected virtual async Task InsertLogAsync(GdprLog gdprLog)
    {
        await _gdprLogRepository.InsertAsync(gdprLog);
    }

    #endregion

    #region Methods

    #region GDPR consent

    /// 
    /// Get a GDPR consent
    /// 
    /// The GDPR consent identifier
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains the gDPR consent
    /// 
    public virtual async Task GetConsentByIdAsync(int gdprConsentId)
    {
        return await _gdprConsentRepository.GetByIdAsync(gdprConsentId, cache => default);
    }

    /// 
    /// Get all GDPR consents
    /// 
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains the gDPR consent
    /// 
    public virtual async Task> GetAllConsentsAsync()
    {
        var gdprConsents = await _gdprConsentRepository.GetAllAsync(query =>
        {
            return from c in query
                orderby c.DisplayOrder, c.Id
                select c;
        }, cache => default);

        return gdprConsents;
    }

    /// 
    /// Insert a GDPR consent
    /// 
    /// GDPR consent
    /// A task that represents the asynchronous operation
    public virtual async Task InsertConsentAsync(GdprConsent gdprConsent)
    {
        await _gdprConsentRepository.InsertAsync(gdprConsent);
    }

    /// 
    /// Update the GDPR consent
    /// 
    /// GDPR consent
    /// A task that represents the asynchronous operation
    public virtual async Task UpdateConsentAsync(GdprConsent gdprConsent)
    {
        await _gdprConsentRepository.UpdateAsync(gdprConsent);
    }

    /// 
    /// Delete a GDPR consent
    /// 
    /// GDPR consent
    /// A task that represents the asynchronous operation
    public virtual async Task DeleteConsentAsync(GdprConsent gdprConsent)
    {
        await _gdprConsentRepository.DeleteAsync(gdprConsent);
    }

    /// 
    /// Gets the latest selected value (a consent is accepted or not by a customer)
    /// 
    /// Consent identifier
    /// Customer identifier
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains the result; null if previous a customer hasn't been asked
    /// 
    public virtual async Task IsConsentAcceptedAsync(int consentId, int customerId)
    {
        //get latest record
        var log = (await GetAllLogAsync(customerId: customerId, consentId: consentId, pageIndex: 0, pageSize: 1)).FirstOrDefault();
        if (log == null)
            return null;

        return log.RequestType switch
        {
            GdprRequestType.ConsentAgree => true,
            GdprRequestType.ConsentDisagree => false,
            _ => null,
        };
    }

    #endregion

    #region GDPR log

    /// 
    /// Get all GDPR log records
    /// 
    /// Customer identifier
    /// Consent identifier
    /// Customer info (Exact match)
    /// GDPR request type
    /// Page index
    /// Page size
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains the gDPR log records
    /// 
    public virtual async Task> GetAllLogAsync(int customerId = 0, int consentId = 0,
        string customerInfo = "", GdprRequestType? requestType = null,
        int pageIndex = 0, int pageSize = int.MaxValue)
    {
        return await _gdprLogRepository.GetAllPagedAsync(query =>
        {
            if (customerId > 0)
                query = query.Where(log => log.CustomerId == customerId);

            if (consentId > 0)
                query = query.Where(log => log.ConsentId == consentId);

            if (!string.IsNullOrEmpty(customerInfo))
                query = query.Where(log => log.CustomerInfo == customerInfo);

            if (requestType != null)
            {
                var requestTypeId = (int)requestType;
                query = query.Where(log => log.RequestTypeId == requestTypeId);
            }

            query = query.OrderByDescending(log => log.CreatedOnUtc).ThenByDescending(log => log.Id);

            return query;
        }, pageIndex, pageSize);
    }

    /// 
    /// Insert a GDPR log
    /// 
    /// Customer
    /// Consent identifier
    /// Request type
    /// Request details
    /// A task that represents the asynchronous operation
    public virtual async Task InsertLogAsync(Customer customer, int consentId, GdprRequestType requestType, string requestDetails)
    {
        ArgumentNullException.ThrowIfNull(customer);

        var gdprLog = new GdprLog
        {
            CustomerId = customer.Id,
            ConsentId = consentId,
            CustomerInfo = customer.Email,
            RequestType = requestType,
            RequestDetails = requestDetails,
            CreatedOnUtc = DateTime.UtcNow
        };

        await InsertLogAsync(gdprLog);
    }

    #endregion

    #region Customer

    /// 
    /// Permanent delete of customer
    /// 
    /// Customer
    /// A task that represents the asynchronous operation
    public virtual async Task PermanentDeleteCustomerAsync(Customer customer)
    {
        ArgumentNullException.ThrowIfNull(customer);

        //blog comments
        var blogComments = await _blogService.GetAllCommentsAsync(customerId: customer.Id);
        await _blogService.DeleteBlogCommentsAsync(blogComments);

        //news comments
        var newsComments = await _newsService.GetAllCommentsAsync(customerId: customer.Id);
        await _newsService.DeleteNewsCommentsAsync(newsComments);

        //back in stock subscriptions
        var backInStockSubscriptions = await _backInStockSubscriptionService.GetAllSubscriptionsByCustomerIdAsync(customer.Id);
        foreach (var backInStockSubscription in backInStockSubscriptions)
            await _backInStockSubscriptionService.DeleteSubscriptionAsync(backInStockSubscription);

        //product review
        var productReviews = await _productService.GetAllProductReviewsAsync(customer.Id);
        var reviewedProducts = await _productService.GetProductsByIdsAsync(productReviews.Select(p => p.ProductId).Distinct().ToArray());
        await _productService.DeleteProductReviewsAsync(productReviews);
        //update product totals
        foreach (var product in reviewedProducts)
            await _productService.UpdateProductReviewTotalsAsync(product);

        //external authentication record
        foreach (var ear in await _externalAuthenticationService.GetCustomerExternalAuthenticationRecordsAsync(customer))
            await _externalAuthenticationService.DeleteExternalAuthenticationRecordAsync(ear);

        //forum subscriptions
        var forumSubscriptions = await _forumService.GetAllSubscriptionsAsync(customer.Id);
        foreach (var forumSubscription in forumSubscriptions)
            await _forumService.DeleteSubscriptionAsync(forumSubscription);

        //shopping cart items
        foreach (var sci in await _shoppingCartService.GetShoppingCartAsync(customer))
            await _shoppingCartService.DeleteShoppingCartItemAsync(sci);

        //private messages (sent)
        foreach (var pm in await _forumService.GetAllPrivateMessagesAsync(0, customer.Id, 0, null, null, null, null))
            await _forumService.DeletePrivateMessageAsync(pm);

        //private messages (received)
        foreach (var pm in await _forumService.GetAllPrivateMessagesAsync(0, 0, customer.Id, null, null, null, null))
            await _forumService.DeletePrivateMessageAsync(pm);

        //newsletter
        var allStores = await _storeService.GetAllStoresAsync();
        foreach (var store in allStores)
        {
            var newsletter = await _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmailAndStoreIdAsync(customer.Email, store.Id);
            if (newsletter != null)
                await _newsLetterSubscriptionService.DeleteNewsLetterSubscriptionAsync(newsletter);
        }

        //addresses
        foreach (var address in await _customerService.GetAddressesByCustomerIdAsync(customer.Id))
        {
            await _customerService.RemoveCustomerAddressAsync(customer, address);
            await _customerService.UpdateCustomerAsync(customer);
            //now delete the address record
            await _addressService.DeleteAddressAsync(address);
        }

        //generic attributes
        var keyGroup = customer.GetType().Name;
        var genericAttributes = await _genericAttributeService.GetAttributesForEntityAsync(customer.Id, keyGroup);
        await _genericAttributeService.DeleteAttributesAsync(genericAttributes);

        //ignore ActivityLog
        //ignore ForumPost, ForumTopic, ignore ForumPostVote
        //ignore Log
        //ignore PollVotingRecord
        //ignore ProductReviewHelpfulness
        //ignore RecurringPayment 
        //ignore ReturnRequest
        //ignore RewardPointsHistory
        //and we do not delete orders

        //remove from Registered role, add to Guest one
        if (await _customerService.IsRegisteredAsync(customer))
        {
            var registeredRole = await _customerService.GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.RegisteredRoleName);
            await _customerService.RemoveCustomerRoleMappingAsync(customer, registeredRole);
        }

        if (!await _customerService.IsGuestAsync(customer))
        {
            var guestRole = await _customerService.GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.GuestsRoleName);
            await _customerService.AddCustomerRoleMappingAsync(new CustomerCustomerRoleMapping { CustomerId = customer.Id, CustomerRoleId = guestRole.Id });
        }

        var email = customer.Email;

        //clear other information
        customer.Email = string.Empty;
        customer.EmailToRevalidate = string.Empty;
        customer.Username = string.Empty;
        customer.Active = false;
        customer.Deleted = true;

        await _customerService.UpdateCustomerAsync(customer);

        //raise event
        await _eventPublisher.PublishAsync(new CustomerPermanentlyDeleted(customer.Id, email));
    }

    #endregion

    #endregion
}