diff --git a/Constants/xWebinarServiceConstants.cs b/Constants/xWebinarServiceConstants.cs
index 6135890..2b727fc 100644
--- a/Constants/xWebinarServiceConstants.cs
+++ b/Constants/xWebinarServiceConstants.cs
@@ -1,3 +1,16 @@
+using xExceptions.Attributes;
+
namespace xWebinarService.Constants {
public class xWebinarServiceConstants { }
+
+ ///
+ /// Webinar Type ...
+ ///
+ public enum XWebinarType
+ {
+ [StringValue("Public")]
+ Public = 0,
+ [StringValue("Private")]
+ Private = 1
+ }
}
\ No newline at end of file
diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs
index f0aba89..160ac05 100644
--- a/DI/XDIHelperExtension.cs
+++ b/DI/XDIHelperExtension.cs
@@ -1,3 +1,117 @@
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using xCommons.Extensions;
+using xExceptions.Constants;
+using xWebinarService.Interfaces;
+using xWebinarService.Interfaces.Entities;
+using xWebinarService.Providers;
+
namespace xWebinarService.DI {
- public static class XDIHelperExtension { }
+ public static class XDIHelperExtension
+ {
+ ///
+ /// Register Module Provided Service on DI
+ ///
+ ///
+ ///
+ public static void AddXWebinarService(
+ this IServiceCollection services,
+ ServiceLifetime lifeTime
+ )
+ {
+ //
+ AddWebinarService(
+ services,
+ lifeTime
+ );
+ }
+
+ //
+ #region Private ...
+ ///
+ /// a LogTag for XWebinarService ...
+ ///
+ private static string XLogTag = "XWebinarService";
+
+ ///
+ /// print a log in Console ...
+ ///
+ ///
+ private static void Log(string message)
+ {
+ Console.WriteLine($"{XLogTag} => {message}");
+ }
+
+ ///
+ /// Register Push Service ...
+ ///
+ ///
+ ///
+ private static void AddWebinarService(
+ IServiceCollection services,
+ ServiceLifetime lifeTime
+ )
+ {
+ //
+ var exception = XException.InvalidArgs.ToException(); ;
+
+ //
+ // Services ...
+ var isServicesExists = !services.IsNull();
+ if (!isServicesExists)
+ {
+ //
+ Log("AddWebinarService failed, services not provided ...");
+ throw exception;
+ }
+
+ //
+ // Lifetime ...
+ var isLifetimeExists = !lifeTime.IsNull();
+ if (!isLifetimeExists)
+ {
+ //
+ Log("AddWebinarService failed, lifetime not provided ...");
+ throw exception;
+ }
+
+ //
+ // Check String Repository Exists ...
+ var isWebinarRepositoryExists = !services
+ .GetRegisteredService()
+ .IsNull() &&
+ !services.GetRegisteredService()
+ .IsNull();
+ if (!isWebinarRepositoryExists)
+ {
+ //
+ Log("AddWebinarService failed, IXWebinarRepository or IXWebinarSubscriberRepository not provided ...");
+ throw exception;
+ }
+
+ //
+ // Check WEBRTC Hub Exists ...
+ var isWebRTCHubExists = !services.GetRegisteredService().IsNull();
+ if (!isWebRTCHubExists)
+ {
+ //
+ Log("AddWebinarService failed, XWebinarHub not provided ...");
+ throw exception;
+ }
+
+ //
+ // Register Resource Providers ...
+ services.Add(new ServiceDescriptor(typeof(IXWebinarTitleResourceProvider), typeof(XWebinarTitleResourceProvider), lifeTime));
+ services.Add(new ServiceDescriptor(typeof(IXWebinarDescriptionResourceProvider), typeof(XWebinarDescriptionResourceProvider), lifeTime));
+
+ //
+ // Register Main Provider ...
+ services.Add(new ServiceDescriptor(typeof(IXWebinarProvider), typeof(XWebinarProvider), lifeTime));
+
+ //
+ Log("AddWebinarService Succeed ...");
+ }
+ #endregion
+
+ }
}
\ No newline at end of file
diff --git a/Interfaces/IXWebinarDescriptionResourceProvider.cs b/Interfaces/IXWebinarDescriptionResourceProvider.cs
new file mode 100644
index 0000000..68169c5
--- /dev/null
+++ b/Interfaces/IXWebinarDescriptionResourceProvider.cs
@@ -0,0 +1,7 @@
+using xStringService.Interfaces;
+
+namespace xWebinarService.Interfaces
+{
+ public interface IXWebinarDescriptionResourceProvider : IXBaseStringResourceProvider
+ { }
+}
\ No newline at end of file
diff --git a/Interfaces/IXWebinarHub.cs b/Interfaces/IXWebinarHub.cs
new file mode 100644
index 0000000..f62a379
--- /dev/null
+++ b/Interfaces/IXWebinarHub.cs
@@ -0,0 +1,19 @@
+using xPushService.Base;
+using xPushService.Interfaces;
+
+namespace xWebinarService.Interfaces
+{
+ public abstract class XWebinarHub : XBaseWebRTCHub
+ {
+ protected XWebinarHub(
+ IXPushGroupStore groupStore,
+ IXPushConnectionStore connectionStore,
+ IXWebRTCConnectionStore webRTCConnectionStore
+ ) : base(
+ groupStore,
+ connectionStore,
+ webRTCConnectionStore
+ )
+ { }
+ }
+}
\ No newline at end of file
diff --git a/Interfaces/IXWebinarProvider.cs b/Interfaces/IXWebinarProvider.cs
new file mode 100644
index 0000000..819dd5c
--- /dev/null
+++ b/Interfaces/IXWebinarProvider.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using xDataService.Configuration;
+using xIdentityService.Interfaces;
+using xModels.Dtos;
+using xWebinarService.Interfaces.Entities;
+using xWebinarService.Models.Dtos;
+using xWebinarService.Models.Entities;
+
+namespace xWebinarService.Interfaces
+{
+ public interface IXWebinarProvider
+ {
+ //
+ #region Props ...
+ IXIdentityProvider IdentityProvider { get; }
+ IXWebinarRepository WebinarRepository { get; }
+ XDataServiceConfiguration DataSercviceConfiguration { get; }
+ IXWebinarTitleResourceProvider TitleResourceProvider { get; }
+ IXWebinarSubscriberRepository WebinarSubscriberRepository { get; }
+ IXWebinarDescriptionResourceProvider DescriptionResourceProvider { get; }
+ #endregion
+
+ //
+ #region Tools ...
+ ///
+ /// Converts Specified XWebinar Entity to it's Corresponding Dto Presentation
+ /// and also Fill Owner and Title/Description Resources ...
+ ///
+ ///
+ ///
+ Task ToXWebinarDto(XWebinar model);
+
+ ///
+ /// Converts Specified WebinarSubscriber Entity to it's Dto Presentation ...
+ ///
+ ///
+ ///
+ Task ToXWebinarSubscriberDto(XWebinarSubscriber model);
+ #endregion
+
+ //
+ #region Actions ...
+ ///
+ /// Create Webinar ...
+ ///
+ ///
+ ///
+ Task CreateWebinar(XWebinarDto item);
+
+ ///
+ /// Update a Webinar ...
+ ///
+ ///
+ ///
+ Task UpdateWebinar(XWebinarDto item);
+
+ ///
+ /// Retrieve Specified Webinar ...
+ ///
+ ///
+ ///
+ Task GetWebinar(Guid id);
+
+ ///
+ /// Retrieve all Exists Webinars ...
+ ///
+ ///
+ Task> GetWebinars();
+
+ ///
+ /// Query Webinars ...
+ ///
+ ///
+ ///
+ Task> QueryWebinars(XQuery query);
+
+ ///
+ /// Remove Specified Webinar ...
+ ///
+ ///
+ ///
+ ///
+ Task RemoveWebinar(
+ Guid webinarId,
+ string requesterUserSelectByParam = null
+ );
+ #endregion
+
+ //
+ #region WebinarSubscriber ...
+ ///
+ /// Subscribe a User to Webinar ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task Subscribe(
+ Guid webinarId,
+ string subscriberId,
+ string requesterUserSelectByParam = null
+ );
+
+ ///
+ /// Check Specified User Subscribed on a Webinar or not ...
+ ///
+ ///
+ ///
+ ///
+ Task IsSubscribed(
+ Guid webinarId,
+ string subscriberId
+ );
+
+ ///
+ /// Unsubscribe Specified User from a Specified Webinar ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task Unsubscribe(
+ Guid webinarId,
+ string subscriberId,
+ string requesterUserSelectByParam = null
+ );
+
+ ///
+ /// Retrieve Specified Subscriber ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task GetSubscriber(
+ Guid webinarId,
+ string subscriberId,
+ string requesterUserSelectByParam = null
+ );
+
+ ///
+ /// Get all Specified Webinars Subscribers ...
+ ///
+ ///
+ ///
+ ///
+ Task> GetSubscribers(
+ Guid webinarId,
+ string requesterUserSelectByParam = null
+ );
+
+ ///
+ /// Query Specified Webinar's Subscribers ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QuerySubscribers(
+ Guid webinarId,
+ XQuery query,
+ string requesterUserSelectByParam = null
+ );
+ #endregion
+
+ }
+}
\ No newline at end of file
diff --git a/Interfaces/IXWebinarTitleResourceProvider.cs b/Interfaces/IXWebinarTitleResourceProvider.cs
new file mode 100644
index 0000000..a112d22
--- /dev/null
+++ b/Interfaces/IXWebinarTitleResourceProvider.cs
@@ -0,0 +1,7 @@
+using xStringService.Interfaces;
+
+namespace xWebinarService.Interfaces
+{
+ public interface IXWebinarTitleResourceProvider : IXBaseStringResourceProvider
+ { }
+}
\ No newline at end of file
diff --git a/Models/Dtos/XWebinarDto.cs b/Models/Dtos/XWebinarDto.cs
index a93fda7..cf4e578 100644
--- a/Models/Dtos/XWebinarDto.cs
+++ b/Models/Dtos/XWebinarDto.cs
@@ -1,20 +1,20 @@
using System;
using xModels.Base;
using xModels.Dtos;
+using xWebinarService.Constants;
namespace xWebinarService.Models.Dtos
{
public class XWebinarDto : XBaseDto
{
public Guid Id { get; set; }
-
public XResourceDto Title { get; set; }
public XResourceDto Description { get; set; }
-
public string OwnerId { get; set; }
public XPersonDto Owner { get; set; }
-
+ public XWebinarType Type { get; set; }
public DateTime CreatedOn { get; set; }
+ public bool Enabled { get; set; }
}
public class XWebinarSubscriberDto : XBaseDto
diff --git a/Models/Entities/XWebinar.cs b/Models/Entities/XWebinar.cs
index cedfa60..b98fc9e 100644
--- a/Models/Entities/XWebinar.cs
+++ b/Models/Entities/XWebinar.cs
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations;
using xModels.Base;
+using xWebinarService.Constants;
namespace xWebinarService.Models.Entities
{
@@ -32,12 +33,23 @@ namespace xWebinarService.Models.Entities
[Required]
public string OwnerId { get; set; }
+ ///
+ /// Webinar Type ...
+ ///
+ public XWebinarType Type { get; set; }
+
///
/// Creation Time ...
///
///
[Required]
public DateTime CreatedOn { get; set; }
+
+ ///
+ /// Specified Webinar Enabled or not ...
+ ///
+ ///
+ public bool Enabled { get; set; }
}
///
diff --git a/Providers/XWebinarDescriptionResourceProvider.cs b/Providers/XWebinarDescriptionResourceProvider.cs
new file mode 100644
index 0000000..aad3fec
--- /dev/null
+++ b/Providers/XWebinarDescriptionResourceProvider.cs
@@ -0,0 +1,23 @@
+using xCommons.Configurations;
+using xStringService.Base;
+using xStringService.Interfaces;
+using xWebinarService.Interfaces;
+
+namespace xWebinarService.Providers
+{
+ ///
+ /// a Servide to Provides Requirements for XWebinar Description Resources ...
+ ///
+ public class XWebinarDescriptionResourceProvider : XBaseStringResourceProvider, IXWebinarDescriptionResourceProvider
+ {
+ public XWebinarDescriptionResourceProvider(
+ IXStringProvider provider,
+ XAppConfiguration appConfiguration
+ ) : base(
+ "XWEBD",
+ provider,
+ appConfiguration
+ )
+ { }
+ }
+}
\ No newline at end of file
diff --git a/Providers/XWebinarProvider.cs b/Providers/XWebinarProvider.cs
index 4d702ee..90915a0 100644
--- a/Providers/XWebinarProvider.cs
+++ b/Providers/XWebinarProvider.cs
@@ -1,5 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
+using xCommons.Extensions;
+using xDataService.Configuration;
+using xDataService.Extensions;
+using xExceptions.Constants;
+using xIdentityModels.Dtos;
+using xIdentityService.Extensions;
using xIdentityService.Interfaces;
+using xModels.Dtos;
+using xWebinarService.Constants;
+using xWebinarService.Interfaces;
using xWebinarService.Interfaces.Entities;
using xWebinarService.Models.Dtos;
using xWebinarService.Models.Entities;
@@ -9,47 +21,1008 @@ namespace xWebinarService.Providers
///
/// Implement all Webinar Related Things here ...
///
- public class XWebinarProvider
+ public class XWebinarProvider : IXWebinarProvider
{
//
#region Props ...
- public IXIdentityProvider IdentityProvider;
- public IXWebinarRepository WebinarRepository;
- public IXWebinarSubscriberRepository WebinarSubscriberRepository;
- #endregion;
+ public IXIdentityProvider IdentityProvider { get; }
+ public IXWebinarRepository WebinarRepository { get; }
+ public XDataServiceConfiguration DataSercviceConfiguration { get; }
+ public IXWebinarTitleResourceProvider TitleResourceProvider { get; }
+ public IXWebinarSubscriberRepository WebinarSubscriberRepository { get; }
+ public IXWebinarDescriptionResourceProvider DescriptionResourceProvider { get; }
+ #endregion
//
#region Constructor ...
public XWebinarProvider(
IXIdentityProvider identityProvider,
IXWebinarRepository webinarRepository,
- IXWebinarSubscriberRepository webinarSubscriberRepository
+ XDataServiceConfiguration dataSercviceConfiguration,
+ IXWebinarTitleResourceProvider titleResourceProvider,
+ IXWebinarSubscriberRepository webinarSubscriberRepository,
+ IXWebinarDescriptionResourceProvider descriptionResourceProvider
)
{
//
- this.IdentityProvider = identityProvider;
- this.WebinarRepository = webinarRepository;
- this.WebinarSubscriberRepository = webinarSubscriberRepository;
+ IdentityProvider = identityProvider;
+ WebinarRepository = webinarRepository;
+ DataSercviceConfiguration = dataSercviceConfiguration;
+ TitleResourceProvider = titleResourceProvider;
+ WebinarSubscriberRepository = webinarSubscriberRepository;
+ DescriptionResourceProvider = descriptionResourceProvider;
}
#endregion
//
#region Tools ...
+ ///
+ /// Converts Specified XWebinar Entity to it's Corresponding Dto Presentation
+ /// and also Fill Owner and Title/Description Resources ...
+ ///
+ ///
+ ///
public async Task ToXWebinarDto(XWebinar model)
{
//
- XWebinarDto result = null;
+ // Validate ...
+ bool isValid =
+ !model.IsNullOrDefault() &&
+ !model.Title.IsNullOrEmpty() &&
+ !model.OwnerId.IsNullOrEmpty() &&
+ !model.Description.IsNullOrEmpty();
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
//
- result.Id = model.Id;
- result.OwnerId = model.OwnerId;
- result.CreatedOn = model.CreatedOn;
+ var result = new XWebinarDto
+ {
+ //
+ // Set Common Properties ...
+ Id = model.Id,
+ Type = model.Type,
+ OwnerId = model.OwnerId,
+ CreatedOn = model.CreatedOn,
+
+ //
+ // Fill Resources ...
+ Title = await TitleResourceProvider.GetResource(model.Id.ToString()),
+ Description = await DescriptionResourceProvider.GetResource(model.Id.ToString())
+ };
//
- // Fill Resources ...
+ // Prepare Inner API Providers Device Dto ...
+ var device = await IdentityProvider.GetDevice();
+ var userInfo = await IdentityProvider.GetUserInfo(
+ device: device,
+ userSelectByParam: model.OwnerId
+ );
+ isValid = !userInfo.IsNullOrDefault();
+ if (!isValid)
+ {
+ XException.NotFound.Throw();
+ }
//
- // Fill Owner ...
+ result.Owner = userInfo.ToXPersonDto();
+
+ //
+ return result;
+ }
+
+ ///
+ /// Converts Specified WebinarSubscriber Entity to it's Dto Presentation ...
+ ///
+ ///
+ ///
+ public async Task ToXWebinarSubscriberDto(XWebinarSubscriber model)
+ {
+ //
+ bool isValid =
+ !model.IsNull() &&
+ !model.SubscriberId.IsNullOrEmpty();
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Retrieve User Info ...
+ var device = await IdentityProvider.GetDevice();
+ var userInfo = await IdentityProvider.GetUserInfo(
+ device: device,
+ userSelectByParam: model.SubscriberId
+ );
+ isValid = !userInfo.IsNullOrDefault();
+ if (!isValid)
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ var result = new XWebinarSubscriberDto
+ {
+ Id = model.Id,
+ SubscriberId = model.SubscriberId,
+ SubscribedOn = model.SubscribedOn,
+ Subscriber = userInfo.ToXPersonDto(),
+ };
+
+ //
+ return result;
+ }
+ #endregion
+
+ //
+ #region Actions ...
+ ///
+ /// Create Webinar ...
+ ///
+ ///
+ ///
+ public async Task CreateWebinar(XWebinarDto item)
+ {
+ //
+ // Validate ...
+ bool isValid =
+ !item.IsNull() &&
+ !item.Title.IsNull() &&
+ !item.Description.IsNull() &&
+ !item.OwnerId.IsNullOrEmpty();
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Check Title and Descriptions Has Value ...
+ isValid =
+ item.Title.Locales.HasChild() &&
+ item.Description.Locales.HasChild() &&
+ item.Title.Locales.All(l => !l.Value.IsNullOrEmpty()) &&
+ item.Description.Locales.All(l => !l.Value.IsNullOrEmpty());
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Prepare Temp Webinar Entity ...
+ string tmpValue = Guid.NewGuid().ToString();
+ var entity = new XWebinar
+ {
+ Type = item.Type,
+ OwnerId = item.OwnerId,
+ Title = "T_" + tmpValue,
+ CreatedOn = DateTime.UtcNow,
+ Description = "D_" + tmpValue,
+ };
+ entity = await WebinarRepository.AddAsync(entity);
+ isValid =
+ !entity.IsNullOrDefault() &&
+ !entity.Id.IsDefaultGuid();
+ if (!isValid)
+ {
+ XException.ActionFailed.Throw();
+ }
+
+ //
+ // Use Entity ID as Resources Suffix ...
+ Guid suffixGuid = entity.Id;
+ string suffix = suffixGuid.ToString();
+ var titleResource = await TitleResourceProvider.AddResource(
+ suffix: suffix,
+ item: item.Title
+ );
+ var descriptionResource = await DescriptionResourceProvider.AddResource(
+ suffix: suffix,
+ item: item.Description
+ );
+ isValid =
+ //
+ // Title Resource Validation ...
+ !titleResource.IsNullOrDefault() &&
+ titleResource.Locales.HasChild() &&
+ !titleResource.Resource.IsNullOrEmpty() &&
+ //
+ // Description Resource Validation ...
+ !descriptionResource.IsNullOrDefault() &&
+ descriptionResource.Locales.HasChild() &&
+ !descriptionResource.Resource.IsNullOrEmpty()
+ ;
+ if (!isValid)
+ {
+ //
+ // Rollback ...
+ try
+ {
+ //
+ entity.Id = suffixGuid;
+ await TitleResourceProvider.Remove(suffix);
+ await WebinarRepository.RemoveAsync(entity);
+ await DescriptionResourceProvider.Remove(suffix);
+ }
+ catch { }
+
+ //
+ XException.ActionFailed.Throw();
+ }
+
+ //
+ // Update Title/Description Resources ...
+ entity.Title = titleResource.Resource;
+ entity.Description = descriptionResource.Resource;
+ entity = await WebinarRepository.UpdateAsync(entity.Id, entity);
+ isValid = !entity.IsNullOrDefault();
+ if (!isValid)
+ {
+ //
+ // Rollback ...
+ try
+ {
+ //
+ entity.Id = suffixGuid;
+ await TitleResourceProvider.Remove(suffix);
+ await WebinarRepository.RemoveAsync(entity);
+ await DescriptionResourceProvider.Remove(suffix);
+ }
+ catch { }
+
+ //
+ XException.ActionFailed.Throw();
+ }
+
+ //
+ // Convert Entity to Dto ...
+ var result = await ToXWebinarDto(entity);
+ return result;
+ }
+
+ ///
+ /// Update a Webinar ...
+ ///
+ ///
+ ///
+ public async Task UpdateWebinar(XWebinarDto item)
+ {
+ //
+ // Validate ...
+ bool isValid =
+ !item.Id.IsNull() &&
+
+ !item.IsNullOrDefault() &&
+ !item.Id.IsDefaultGuid() &&
+ !item.OwnerId.IsNullOrEmpty() &&
+ !item.Title.IsNullOrDefault() &&
+ !item.Description.IsNullOrDefault() &&
+ //
+ // Title Validation ...
+ item.Title.Locales.HasChild() &&
+ !item.Title.Resource.IsNullOrEmpty() &&
+ item.Title.Locales.All(l => !l.IsNullOrDefault() && !l.Value.IsNullOrEmpty() && !l.Language.IsNullOrEmpty()) &&
+ //
+ // Description Validation ...
+ item.Description.Locales.HasChild() &&
+ !item.Description.Resource.IsNullOrEmpty() &&
+ item.Description.Locales.All(l => !l.IsNullOrDefault() && !l.Value.IsNullOrEmpty() && !l.Language.IsNullOrEmpty())
+ ;
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Check Item Exists ...
+ isValid = await WebinarRepository.IsExistsAsync(item.Id);
+ if (!isValid)
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ // Retrieve Entity ...
+ var entity = await WebinarRepository.GetAsync(item.Id);
+
+ //
+ // Check if Type Change Update it ...
+ if (entity.Type != item.Type)
+ {
+ //
+ entity.Type = item.Type;
+ entity = await WebinarRepository.UpdateAsync(entity.Id, entity);
+ }
+
+ //
+ // Retrieve Entity Dto ...
+ var entityDto = await ToXWebinarDto(entity);
+
+ //
+ // Exclude Must Remove items ...
+ var mustRemoveTitleLocals = entityDto.Title.Locales.Where(e =>
+ !item.Title.Locales.Any(l =>
+ l.Language.ToNormalString() == e.Language.ToNormalString())
+ );
+ var mustRemoveDescriptionLocals = entityDto.Description.Locales.Where(e =>
+ !item.Description.Locales.Any(l =>
+ l.Language.ToNormalString() == e.Language.ToNormalString())
+ );
+
+ //
+ // Remove Specified Locales ...
+
+ //
+ // Titles ...
+ foreach (var locale in mustRemoveTitleLocals)
+ {
+ //
+ try
+ {
+ //
+ await TitleResourceProvider.Remove(
+ resource: entity.Title,
+ language: locale.Language
+ );
+ }
+ catch { }
+ }
+
+ //
+ // Descriptions ...
+ foreach (var locale in mustRemoveDescriptionLocals)
+ {
+ //
+ try
+ {
+ //
+ await DescriptionResourceProvider.Remove(
+ resource: entity.Description,
+ language: locale.Language
+ );
+ }
+ catch { }
+ }
+
+ //
+ // Add Or Update Locales ...
+
+ //
+ // Title ...
+ var titleAddedLocales = await TitleResourceProvider.AddOrUpdate(
+ resource: entity.Title,
+ locales: entityDto.Title.Locales
+ );
+
+ //
+ // Description ...
+ var descriptionAddedLocales = await DescriptionResourceProvider.AddOrUpdate(
+ resource: entity.Description,
+ locales: entityDto.Description.Locales
+ );
+
+ //
+ var result = await ToXWebinarDto(entity);
+
+ //
+ return result;
+ }
+
+ ///
+ /// Retrieve Specified Webinar ...
+ ///
+ ///
+ ///
+ public async Task GetWebinar(Guid id)
+ {
+ //
+ var entity = await WebinarRepository.GetAsync(id);
+ if (entity.IsNullOrDefault())
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ var result = await ToXWebinarDto(entity);
+ return result;
+ }
+
+ ///
+ /// Retrieve all Exists Webinars ...
+ ///
+ ///
+ public async Task> GetWebinars()
+ {
+ //
+ var list = await WebinarRepository.GetAllAsync();
+ var result = await list.SelectAsync(async l => await ToXWebinarDto(l));
+
+ //
+ return result;
+ }
+
+ ///
+ /// Query Webinars ...
+ ///
+ ///
+ ///
+ public async Task> QueryWebinars(XQuery query)
+ {
+ //
+ // Validate ...
+ if (query.IsNull())
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Normalize ...
+ query = query.NormalizeQuery(DataSercviceConfiguration);
+
+ //
+ // Since in Resourceable Entities we have to Search on Locales
+ // we Must Implement Senario Custom ...
+ var totalEntities = await WebinarRepository.GetAllAsync();
+ var items = await totalEntities.SelectAsync(async e => await ToXWebinarDto(e));
+ var totalItemsCount = items.Count();
+
+ //
+ // Apply Filter ...
+ if (!query.Filter.IsNullOrEmpty())
+ {
+ //
+ items = items
+ .ApplyFilter(query.Filter);
+ }
+ int filteredItemsCount = items.Count();
+
+ //
+ // Count Pages ...
+ var totalPagesCount = query.CountPages(totalItemsCount);
+ var filteredPagesCount = query.CountPages(filteredItemsCount);
+
+ //
+ // Apply Paging and Sorting ...
+ if (totalItemsCount > 0 &&
+ filteredItemsCount > 0)
+ {
+ //
+ // Apply Sorting ...
+ items = items.ApplySorting(
+ query.SortBy,
+ query.IsAscending
+ );
+
+ //
+ // Apply Paging ...
+ items = items.ApplyPaging(
+ query.Page,
+ query.PageSize
+ );
+ }
+
+ //
+ // Prepare Result ...
+ var result = new XQueryResult
+ {
+ Page = query.Page,
+ PageSize = query.PageSize,
+ TotalPages = totalPagesCount,
+ TotalItems = totalItemsCount,
+ TotalFilteredPages = filteredPagesCount,
+ TotalFilteredItems = filteredItemsCount
+ };
+
+ //
+ return result;
+ }
+
+ ///
+ /// Remove Specified Webinar ...
+ ///
+ ///
+ ///
+ ///
+ public async Task RemoveWebinar(
+ Guid webinarId,
+ string requesterUserSelectByParam = null
+ )
+ {
+ //
+ bool result = false;
+
+ //
+ // Validate ...
+ result =
+ !webinarId.IsNull() &&
+ !webinarId.IsDefaultGuid();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Get Entity ...
+ var entity = await WebinarRepository.GetAsync(webinarId);
+ result = !entity.IsNullOrDefault();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Check Permissions ...
+ result = entity.OwnerId == requesterUserSelectByParam;
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Handle Remove ...
+ var subscribers = await GetSubscribers(
+ webinarId: webinarId,
+ requesterUserSelectByParam: requesterUserSelectByParam
+ );
+ try
+ {
+ //
+ await subscribers.SelectAsync(async s => await Unsubscribe(
+ webinarId: webinarId,
+ subscriberId: s.SubscriberId,
+ requesterUserSelectByParam: requesterUserSelectByParam
+ ));
+
+ //
+ string resourceID = webinarId.ToString();
+ await TitleResourceProvider.Remove(resourceID);
+ await DescriptionResourceProvider.Remove(resourceID);
+
+ //
+ await WebinarRepository.RemoveAsync(webinarId);
+ }
+ catch { }
+
+ //
+ // Check Entity Removed ...
+ result = !await WebinarRepository.IsExistsAsync(webinarId);
+
+ //
+ return result;
+ }
+ #endregion
+
+ //
+ #region WebinarSubscriber ...
+ ///
+ /// Subscribe a User to Webinar ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task Subscribe(
+ Guid webinarId,
+ string subscriberId,
+ string requesterUserSelectByParam = null
+ )
+ {
+ //
+ var result = false;
+
+ //
+ // Validate ...
+ result =
+ !webinarId.IsNull() &&
+ !webinarId.IsDefaultGuid() &&
+ !subscriberId.IsNullOrEmpty();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Check Webinar Exists ...
+ result = await WebinarRepository.IsExistsAsync(webinarId);
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Retrieve Webinar Entity ...
+ var webinar = await WebinarRepository.GetAsync(webinarId);
+
+ //
+ // Check Webinar Enabled ...
+ result =
+ webinar.Enabled ||
+ requesterUserSelectByParam == webinar.OwnerId;
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Check Webinar Type ...
+ result =
+ webinar.Type == XWebinarType.Public ||
+ requesterUserSelectByParam == webinar.OwnerId;
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Check User Exists ...
+ var device = await IdentityProvider.GetDevice();
+ XOpenActionUserInfoDto userInfo = null;
+ try
+ {
+ //
+ userInfo = await IdentityProvider.GetUserInfo(
+ device: device,
+ userSelectByParam: subscriberId
+ );
+ }
+ catch { }
+ result = !userInfo.IsNullOrDefault();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Create Subscription Model ...
+ var entity = new XWebinarSubscriber
+ {
+ WebinarId = webinarId,
+ SubscriberId = subscriberId,
+ SubscribedOn = DateTime.UtcNow,
+ };
+ entity = await WebinarSubscriberRepository.AddAsync(entity);
+ result = !entity.IsNullOrDefault();
+
+ //
+ return result;
+ }
+
+ ///
+ /// Check Specified User Subscribed on a Webinar or not ...
+ ///
+ ///
+ ///
+ ///
+ public async Task IsSubscribed(
+ Guid webinarId,
+ string subscriberId
+ )
+ {
+ //
+ bool result = false;
+
+ //
+ // Validate ...
+ result =
+ !webinarId.IsNull() &&
+ !webinarId.IsDefaultGuid() &&
+ !subscriberId.IsNullOrEmpty();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Check Webinar Exists ...
+ result = await WebinarRepository.IsExistsAsync(webinarId);
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Check User Exists ...
+ var device = await IdentityProvider.GetDevice();
+ XOpenActionUserInfoDto userInfo = null;
+ try
+ {
+ //
+ userInfo = await IdentityProvider.GetUserInfo(
+ device: device,
+ userSelectByParam: subscriberId
+ );
+ }
+ catch { }
+ result = !userInfo.IsNullOrDefault();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ result = !(await WebinarSubscriberRepository.FindOneAsync(ws =>
+ ws.WebinarId == webinarId &&
+ ws.SubscriberId == subscriberId
+ )).IsNull();
+
+ //
+ return result;
+ }
+
+ ///
+ /// Unsubscribe Specified User from a Specified Webinar ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task Unsubscribe(
+ Guid webinarId,
+ string subscriberId,
+ string requesterUserSelectByParam = null
+ )
+ {
+ //
+ var result = false;
+
+ //
+ // Validate ...
+ result =
+ !webinarId.IsNull() &&
+ !webinarId.IsDefaultGuid() &&
+ !subscriberId.IsNullOrEmpty();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Check Subscription ..
+ result = await IsSubscribed(
+ webinarId: webinarId,
+ subscriberId: subscriberId
+ );
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Retrieve Webinar ...
+ var webinar = await WebinarRepository.GetAsync(webinarId);
+
+ //
+ // Check Permission ...
+ result =
+ requesterUserSelectByParam == subscriberId ||
+ requesterUserSelectByParam == webinar.OwnerId;
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ // Retrieve Subscription Entity ...
+ var entity = await WebinarSubscriberRepository.FindOneAsync(ws =>
+ ws.WebinarId == webinarId &&
+ ws.SubscriberId == subscriberId
+ );
+ entity = await WebinarSubscriberRepository.RemoveAsync(entity);
+ result = !entity.IsNullOrDefault();
+
+ //
+ return result;
+ }
+
+ ///
+ /// Retrieve Specified Subscriber ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task GetSubscriber(
+ Guid webinarId,
+ string subscriberId,
+ string requesterUserSelectByParam = null
+ )
+ {
+ //
+ // Validate ...
+ bool isValid =
+ !webinarId.IsNull() &&
+ !webinarId.IsDefaultGuid() &&
+ !subscriberId.IsNullOrEmpty();
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Retrieve Webinar and Validate it ...
+ var webinar = await WebinarRepository.GetAsync(webinarId);
+ isValid = !webinar.IsNullOrDefault();
+ if (!isValid)
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ // Retrieve Entity and Validate it ...
+ var entity = await WebinarSubscriberRepository.FindOneAsync(e =>
+ e.WebinarId == webinarId &&
+ e.SubscriberId == subscriberId
+ );
+ isValid = !entity.IsNullOrDefault();
+ if (!isValid)
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ // Check Permissions ...
+ isValid =
+ subscriberId == requesterUserSelectByParam ||
+ webinar.OwnerId == requesterUserSelectByParam;
+ if (!isValid)
+ {
+ XException.NotAllowed.Throw();
+ }
+
+ //
+ // Converts to Subscriber Dto ...
+ var result = await ToXWebinarSubscriberDto(entity);
+ return result;
+ }
+
+ ///
+ /// Get all Specified Webinars Subscribers ...
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetSubscribers(
+ Guid webinarId,
+ string requesterUserSelectByParam = null
+ )
+ {
+ //
+ // Validate ...
+ bool isValid =
+ !webinarId.IsNull() &&
+ !webinarId.IsDefaultGuid();
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Retrieve and Validate Webinar Entity ...
+ var webinar = await WebinarRepository.GetAsync(webinarId);
+ isValid = !webinar.IsNullOrDefault();
+ if (!isValid)
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ // Check Permissions ...
+ isValid =
+ webinar.OwnerId == requesterUserSelectByParam;
+ if (!isValid)
+ {
+ XException.NotAllowed.Throw();
+ }
+
+ //
+ var subscribers = await WebinarSubscriberRepository.FindManyAsync(e =>
+ e.WebinarId == webinarId
+ );
+
+ //
+ // Prepare Result ...
+ var result = await subscribers
+ .SelectAsync(async s => await ToXWebinarSubscriberDto(s));
+
+ //
+ return result;
+ }
+
+ ///
+ /// Query Specified Webinar's Subscribers ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> QuerySubscribers(
+ Guid webinarId,
+ XQuery query,
+ string requesterUserSelectByParam = null
+ )
+ {
+ //
+ // Validate ...
+ bool isValid =
+ !query.IsNull() &&
+ !webinarId.IsNull() &&
+ !webinarId.IsDefaultGuid();
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Normalize ...
+ query = query.NormalizeQuery(DataSercviceConfiguration);
+
+ //
+ // Check Webinar Exists ...
+ isValid = await WebinarRepository.IsExistsAsync(webinarId);
+ if (!isValid)
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ // Retrieve all Items ...
+ var items = await GetSubscribers(
+ webinarId: webinarId,
+ requesterUserSelectByParam: requesterUserSelectByParam
+ );
+ var totalItemsCount = items.Count();
+
+ //
+ // Try Filter Items ...
+ if (!query.Filter.IsNullOrEmpty())
+ {
+ //
+ var filteredItems = new List();
+
+ //
+ // Implement Filtering Senario ...
+
+ //
+ items = filteredItems.AsEnumerable();
+ }
+ var filteredItemsCount = items.Count();
+
+ //
+ // Counting Pages ...
+ var totalPagesCount = query.CountPages(totalItemsCount);
+ var filteredPagesCount = query.CountPages(filteredItemsCount);
+
+ //
+ // Apply Sorting and Paging ...
+ if (totalItemsCount > 0 &&
+ filteredItemsCount > 0)
+ {
+ //
+ // Apply Sorting ...
+ items = items.ApplySorting(
+ query.SortBy,
+ query.IsAscending
+ );
+
+ //
+ // Apply Paging ...
+ items = items.ApplyPaging(
+ query.Page,
+ query.PageSize
+ );
+ }
+
+ //
+ // Prepare Result ...
+ var result = new XQueryResult
+ {
+ Page = query.Page,
+ PageSize = query.PageSize,
+ TotalPages = totalPagesCount,
+ TotalItems = totalItemsCount,
+ TotalFilteredPages = filteredPagesCount,
+ TotalFilteredItems = filteredItemsCount
+ };
//
return result;
diff --git a/Providers/XWebinarTitleResourceProvider.cs b/Providers/XWebinarTitleResourceProvider.cs
new file mode 100644
index 0000000..a233a94
--- /dev/null
+++ b/Providers/XWebinarTitleResourceProvider.cs
@@ -0,0 +1,23 @@
+using xCommons.Configurations;
+using xStringService.Base;
+using xStringService.Interfaces;
+using xWebinarService.Interfaces;
+
+namespace xWebinarService.Providers
+{
+ ///
+ /// a Servide to Provides Requirements for XWebinar Title Resources ...
+ ///
+ public class XWebinarTitleResourceProvider : XBaseStringResourceProvider, IXWebinarTitleResourceProvider
+ {
+ public XWebinarTitleResourceProvider(
+ IXStringProvider provider,
+ XAppConfiguration appConfiguration
+ ) : base(
+ "XWEWBT",
+ provider,
+ appConfiguration
+ )
+ { }
+ }
+}
\ No newline at end of file
diff --git a/xWebinarService.csproj b/xWebinarService.csproj
index 57cd5be..454982c 100644
--- a/xWebinarService.csproj
+++ b/xWebinarService.csproj
@@ -24,6 +24,7 @@
+