From a855ea6b70799476f18cdacc11f9becbd73054c1 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sun, 22 Mar 2026 14:09:53 +0330 Subject: [PATCH] Initial ... --- .gitignore | 13 + Base/XIBaseV1Controller.cs | 33 + Base/XIBaseV1EntityController.cs | 120 ++ Base/XIBaseV1ProviderController.cs | 29 + .../Account/AccountController+Admin.cs | 135 ++ .../AccountController+Authentication.cs | 388 ++++++ .../Account/AccountController+Friendship.cs | 910 +++++++++++++ Controllers/Account/AccountController+Open.cs | 93 ++ .../Account/AccountController+Profile.cs | 528 ++++++++ .../Account/AccountController+Registration.cs | 1142 +++++++++++++++++ .../Account/AccountController+Search.cs | 54 + Controllers/AccountController.cs | 42 + Controllers/StartupController.cs | 41 + Controllers/TestIdentity.cs | 176 +++ .../ConfigurationsController+Terms.cs | 244 ++++ Controllers/V1/ConfigurationsController.cs | 40 + Controllers/V1/Entities/FilesController.cs | 324 +++++ Controllers/V1/Entities/StringsController.cs | 326 +++++ Controllers/V1/Entities/TagsController.cs | 321 +++++ Controllers/V1/Services/FilesController.cs | 309 +++++ Controllers/V1/Services/StringsController.cs | 468 +++++++ Controllers/V1/Services/TagsController.cs | 207 +++ Db/.gitkeep | 0 Extensions/XStartupExtensions.cs | 74 ++ Extensions/XUserClaimsInfoDtoExtensions.cs | 55 + Program.cs | 20 + Properties/launchSettings.json | 30 + README.md | 11 + Startup.cs | 276 ++++ appsettings.Development.json | 48 + appsettings.json | 133 ++ nuget.config | 7 + xApi.csproj | 52 + 33 files changed, 6649 insertions(+) create mode 100644 .gitignore create mode 100644 Base/XIBaseV1Controller.cs create mode 100644 Base/XIBaseV1EntityController.cs create mode 100644 Base/XIBaseV1ProviderController.cs create mode 100644 Controllers/Account/AccountController+Admin.cs create mode 100644 Controllers/Account/AccountController+Authentication.cs create mode 100644 Controllers/Account/AccountController+Friendship.cs create mode 100644 Controllers/Account/AccountController+Open.cs create mode 100644 Controllers/Account/AccountController+Profile.cs create mode 100644 Controllers/Account/AccountController+Registration.cs create mode 100644 Controllers/Account/AccountController+Search.cs create mode 100644 Controllers/AccountController.cs create mode 100644 Controllers/StartupController.cs create mode 100644 Controllers/TestIdentity.cs create mode 100644 Controllers/V1/Configurations/ConfigurationsController+Terms.cs create mode 100644 Controllers/V1/ConfigurationsController.cs create mode 100644 Controllers/V1/Entities/FilesController.cs create mode 100644 Controllers/V1/Entities/StringsController.cs create mode 100644 Controllers/V1/Entities/TagsController.cs create mode 100644 Controllers/V1/Services/FilesController.cs create mode 100644 Controllers/V1/Services/StringsController.cs create mode 100644 Controllers/V1/Services/TagsController.cs create mode 100644 Db/.gitkeep create mode 100644 Extensions/XStartupExtensions.cs create mode 100644 Extensions/XUserClaimsInfoDtoExtensions.cs create mode 100644 Program.cs create mode 100644 Properties/launchSettings.json create mode 100644 README.md create mode 100644 Startup.cs create mode 100644 appsettings.Development.json create mode 100644 appsettings.json create mode 100644 nuget.config create mode 100644 xApi.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1e99217 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# +bin +obj + +# +Db/* +!Db/.gitkeep + +# +Migrations/* + +# +wwwroot/* \ No newline at end of file diff --git a/Base/XIBaseV1Controller.cs b/Base/XIBaseV1Controller.cs new file mode 100644 index 0000000..d51ce43 --- /dev/null +++ b/Base/XIBaseV1Controller.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xCommons.Attributes; +using xCommons.Configurations; +using xCommons.Providers; +using xIdentityService.Controllers; +using xIdentityService.Interfaces; + +namespace xApi.Base +{ + [ApiController] + [ApiVersion("1.0")] + [RequireXPowered(true)] + [Route("api/v{version:apiVersion}/[controller]")] + public abstract class XIBaseV1Controller : XIBaseController + { + // + #region Constructor ... + protected XIBaseV1Controller( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider + ) + { } + #endregion + } +} diff --git a/Base/XIBaseV1EntityController.cs b/Base/XIBaseV1EntityController.cs new file mode 100644 index 0000000..843ecd2 --- /dev/null +++ b/Base/XIBaseV1EntityController.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using xCommons.Attributes; +using xCommons.Configurations; +using xCommons.Extensions; +using xCommons.Providers; +using xDataService.Interfaces; +using xIdentityService.Controllers; +using xIdentityService.Interfaces; +using xModels.Base; +using xPushService.Base; +using xPushService.Constants; + +namespace xApi.Base +{ + [ApiController] + [ApiVersion("1.0")] + [RequireXPowered(true)] + [Route("api/v{version:apiVersion}/entities/[controller]")] + public abstract class XIBaseV1EntityController : XIBaseEntityController + where TEntity : XBaseEntity + { + // + #region Constructor ... + protected XIBaseV1EntityController( + ILogger> logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXBaseRepository repository + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider, + repository + ) + { } + #endregion + } + + public abstract class XIBaseV1EntityHubController : XIBaseV1EntityController + where TEntity : XBaseEntity + { + // + #region Props ... + public IHubContext> Hub { get; } + #endregion + + // + #region Constructor ... + protected XIBaseV1EntityHubController( + ILogger> logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXBaseRepository repository, + IHubContext> hub = null + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider, + repository + ) + { + Hub = hub; + } + #endregion + + // + #region Hub ... + [NonAction] + public async Task SendPush( + string action, + string payLoad + ) + { + // + var actions = new List + { + XBaseEntityHubAction.Add.GetStringValue(), + XBaseEntityHubAction.Update.GetStringValue(), + XBaseEntityHubAction.Delete.GetStringValue(), + XBaseEntityHubAction.AddMany.GetStringValue(), + XBaseEntityHubAction.DeleteMany.GetStringValue(), + XBaseEntityHubAction.UpdateMany.GetStringValue(), + XBaseEntityHubAction.AddOrUpdate.GetStringValue(), + }; + + // + // Validate ... + var isValid = + !Hub.IsNull() && + !action.IsNullOrEmpty() && + !payLoad.IsNullOrEmpty() && + actions.Contains(action); + if (!isValid) + { + return; + } + + // + // Retrieve Connection Id ... + var connectionId = GetConnectionId(); + var clients = Hub.Clients.All; + if (!connectionId.IsNullOrEmpty()) + { + clients = Hub.Clients.AllExcept(connectionId); + } + + // + await clients.SendAsync(action, payLoad, connectionId); + } + #endregion + } +} \ No newline at end of file diff --git a/Base/XIBaseV1ProviderController.cs b/Base/XIBaseV1ProviderController.cs new file mode 100644 index 0000000..726744f --- /dev/null +++ b/Base/XIBaseV1ProviderController.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Logging; +using xCommons.Configurations; +using xCommons.Providers; +using xIdentityService.Controllers; +using xIdentityService.Interfaces; + +namespace xApi.Base +{ + [Route("api/v{version:apiVersion}/services/[controller]")] + public abstract class XIBaseV1ProviderController : XIBaseProviderController + { + // + #region Constructor ... + protected XIBaseV1ProviderController( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider + ) + { } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/Account/AccountController+Admin.cs b/Controllers/Account/AccountController+Admin.cs new file mode 100644 index 0000000..013a0fc --- /dev/null +++ b/Controllers/Account/AccountController+Admin.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using xIdentityHelper; +using xCommons.Attributes; +using xCommons.Extensions; +using xIdentityModels.Dtos; + +namespace xApi.Controllers { + public partial class AccountController { + // + #region Admin Actions ... + /// + /// Ban Specific Users + /// + /// an instance of XUserNameIdRequest which represents user identifier list to Ban + /// a list of banned users identifiers + [RequireXPowered] + [HttpPost ("Ban")] + [Authorize (Policy = XPolicies.EnabledAdmin)] + public async Task>> Ban ( + [FromBody] XUserNameIdRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + await ValidationProvider + .GroupValidationBuilder () + .AddNotNull (model) + .AddNotZeroChilds (model.Ids) + .ValidateGroupAsync (); + + // + var tokens = await RetrieveTokensAsXTokenResponse (); + var result = await identityProvider + .Ban ( + tokens, + model + ); + + // + return Ok (result) + .ToDynamicObject (); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// UnBann Specific Users + /// + /// an instance of XUserNameIdRequest which represents user identifier list to Ban + /// a list of unbanned users identifiers + [RequireXPowered] + [HttpPost ("UnBan")] + [Authorize (Policy = XPolicies.EnabledAdmin)] + public async Task>> UnBan ( + [FromBody] XUserNameIdRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + await ValidationProvider + .GroupValidationBuilder () + .AddNotNull (model) + .AddNotZeroChilds (model.Ids) + .ValidateGroupAsync (); + + // + var tokens = await RetrieveTokensAsXTokenResponse (); + var result = await identityProvider + .UnBan ( + tokens, + model + ); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Check Specific User is Banned or not + /// + /// specified user's identifier + /// a boolean value which represent user banned or not + [RequireXPowered] + [HttpGet ("IsBanned/{userSelectByParam?}")] + [Authorize (Policy = XPolicies.EnabledAdmin)] + [Authorize (Policy = XPolicies.EnabledAgent)] + public async Task> IsBanned ( + [FromRoute] string userSelectByParam = null + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (userSelectByParam.IsNullOrEmpty ()) { + userSelectByParam = User.Identity.Name; + } + ValidationProvider.NotEmpty (userSelectByParam); + + // + var tokens = await RetrieveTokensAsXTokenResponse (); + var result = await identityProvider + .IsBanned ( + tokens, + userSelectByParam + ); + + // + return Ok (result); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/Account/AccountController+Authentication.cs b/Controllers/Account/AccountController+Authentication.cs new file mode 100644 index 0000000..f0749cb --- /dev/null +++ b/Controllers/Account/AccountController+Authentication.cs @@ -0,0 +1,388 @@ +using System; +using System.Threading.Tasks; +using IdentityModel.Client; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using xIdentityHelper; +using xCommons.Attributes; +using xCommons.Extensions; +using xExceptions.Constants; +using xIdentityModels.Models; +using xModels.Dtos; +using static xIdentityHelper.XApiScopeHelper; + +namespace xApi.Controllers { + public partial class AccountController { + // + #region Authentication Actions ... + /// + /// Retrieve OAuth Discovery Document + /// + /// an instance of DiscoveryDocumentResponse + [AllowAnonymous] + [RequireXPowered] + [HttpGet ("DiscoveryDocument")] + public async Task> GetDiscoveryDocument () { + // + try { + // + var result = await identityProvider + .RequestDiscoveryDocument (); + + // + // Ceck Response Result ... + if (result.IsError) { + XException.InvalidConfiguration.Throw (); + } + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + return result; + } + } + + /// + /// Request AccessToken for Specific XApiScope + /// + /// a member of XApiScope + /// an instance of XTokenResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("RequestScopeAccessToken")] + public async Task> RequestScopeAccessToken ( + [FromHeader] XApiScope scope + ) { + // + // Do Action ... + try { + // + // Validate Args ... + var scopeName = string.Empty; + try { + scopeName = scope.GetStringValue (); + } catch { } + ValidationProvider.NotEmpty (scopeName); + + // + var result = await identityProvider + .RequestScopeAccessToken (scopeName); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + return result; + } + } + + /// + /// Authenticate User + /// + /// + /// Sample request: + /// + /// { + /// "password": "", + /// "userSelectBy": "", + /// } + /// + /// + /// User Login Required Info, an instance of XLoginRequest + /// an instance of XTokenResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("Authenticate")] + public async Task> Authenticate ( + [FromBody] XLoginRequest model + ) { + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotNull (model) + .AddNotEmpty ( + model.UserSelectBy, + model.Password + ) + .ValidateGroupAsync (); + + // + var result = await identityProvider + .Authenticate (model); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + return result; + } + } + + /// + /// Authenticate User + /// + /// + /// Sample request: + /// + /// { + /// "language": "fa-IR" + /// "password": "", + /// "userSelectBy": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// User Login Required Info, an instance of XLoginRequest + /// an instance of XLoginResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("Login")] + public async Task> Login ( + [FromBody] XLoginRequest model + ) { + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotNull ( + model, + model.Device) + .AddNotEmpty ( + model.Language, + model.UserSelectBy, + model.Password + ) + .ValidateGroupAsync (); + + // + var result = await identityProvider + .Login (model); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + return result; + } + } + + /// + /// Logout User + /// + [RequireXPowered] + [HttpPost ("Logout")] + [Authorize (Policy = XPolicies.User)] + public async Task Logout () { + try { + // + var tokens = await RetrieveTokensAsXTokenResponse (); + await identityProvider + .Logout (tokens); + + // + return Ok (); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + return result; + } + } + + /// + /// Refresh Expired Tokens + /// + /// + /// in addition to AccessToken, you had to pass RefreshToken due to Headers + /// + /// an instance of XTokenResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("RefreshTokens")] + public async Task> RefreshTokens () { + // + try { + // + // Retrieve Toke Response ... + var model = await RetrieveTokensAsXTokenResponse (); + + // + // Validate Args ... + ValidationProvider + .GroupValidationBuilder () + .AddNotNull (model) + .AddNotEmpty ( + model.AccessToken, + model.RefreshToken) + .ValidateGroup (); + + // + var result = await identityProvider + .RefreshTokens (model); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + return result; + } + } + + /// + /// Validate a Revision Checksum + /// + /// + /// + [HttpPost ("Validate")] + [Authorize (Policy = XPolicies.EnabledUser)] + public async Task> Validate ( + [FromBody] XValidateRevisionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + await ValidationProvider + .GroupValidationBuilder () + .AddNotNull (model) + .AddNotEmpty (model.Revision) + .ValidateGroupAsync (); + + // + // Get Request ... + var tokens = await RetrieveTokensAsXTokenResponse (); + var result = tokens.ValidateRevisionChecksum ( + model.Revision, + identityProvider.RevisionSecretKey + ); + + // + // Return Result + return Ok (result); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + return result; + } + } + #endregion + + // + #region Password Actions ... + /// + /// Change a User's Password ... + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - Password: user's current active password. + /// - NewPassword: user's new password to change. + /// - Device: user's client device which is an instance of XDevice. + /// - ReturnUrl: client application Login URL. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "password": "" + /// "newPassword": "", + /// "returnUrl": "http://localhost/login", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// + [RequireXPowered] + [HttpPost ("ChangePassword")] + [Authorize (Policy = XPolicies.User)] + [Authorize (Policy = XPolicies.EnabledUser)] + public async Task ChangePassword ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotNull ( + model, + model.Device + ) + .AddNotEmpty ( + model.Lang, + model.Password, + model.NewPassword, + model.ReturnUrl + ) + .ValidateGroupAsync (); + + // + // Get User Select By ... + var userSelectByParam = GetUserSelectByParam ( + model, + forceNotNull : false + ); + if (userSelectByParam.IsNullOrEmpty ()) { + userSelectByParam = User.Identity.Name; + } + ValidationProvider.NotEmpty (userSelectByParam); + + // + // Get Request ... + var tokens = await RetrieveTokensAsXTokenResponse (); + await identityProvider + .ChangePassword (tokens, model); + + // + return Ok (); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/Account/AccountController+Friendship.cs b/Controllers/Account/AccountController+Friendship.cs new file mode 100644 index 0000000..be87931 --- /dev/null +++ b/Controllers/Account/AccountController+Friendship.cs @@ -0,0 +1,910 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using xIdentityHelper; +using xCommons.Attributes; +using xCommons.Extensions; +using xIdentityModels.Constants; +using xIdentityModels.Dtos; +using xIdentityModels.Navigations; +using xModels.Dtos; +using System.Linq; +using xExceptions.Constants; + +namespace xApi.Controllers +{ + public partial class AccountController + { + // + #region Friendship Actions ... + /// + /// Follow a User + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipFollowing + [RequireXPowered] + [HttpPost("Friendship/{destUser}/Follow")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> Follow( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .Follow( + tokens, + destUser + ); + + // + // Prepare Push Message ... + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Cancel Following Request + /// + /// a user identifier which represent destination user + /// a boolean value + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpPost("Friendship/{destUser}/Cancel")] + public async Task> Cancel( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .Cancel( + tokens, + destUser + ); + + // + // Prepare Push Message ... + + // + return Ok(result); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Unfollow a Follower + /// + /// a user identifier which represent destination user + /// + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpPost("Friendship/{destUser}/UnFollowFollower")] + public async Task UnFollowFollower( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + await identityProvider + .UnFollowFollower( + tokens, + destUser + ); + + // + // Prepare Push Message ... + + // + return Ok(); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Unfollow Following + /// + /// a user identifier which represent destination user + /// + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpPost("Friendship/{destUser}/UnFollowFollowing")] + public async Task UnFollowFollowing( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + await identityProvider + .UnFollowFollowing( + tokens, + destUser + ); + + // + // Prepare Push Message ... + + // + return Ok(); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Block a Follower + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipFollowing + [HttpPost("Friendship/{destUser}/Block")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> Block( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .Block( + tokens, + destUser + ); + + // + // Prepare Push Message ... + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + + // + return exResult; + } + } + + /// + /// Unblock a Blocked User + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipFollowing + [HttpPost("Friendship/{destUser}/UnBlock")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> UnBlock( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .UnBlock( + tokens, + destUser + ); + + // + // Prepare Push Message ... + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Accept a Following Request + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipFollower + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpPost("Friendship/{destUser}/AcceptRequest")] + public async Task> AcceptRequest( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .AcceptRequest( + tokens, + destUser + ); + + // + // Prepare Push Message ... + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Reject a Following Request + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipFollower + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpPost("Friendship/{destUser}/RejectRequest")] + public async Task> RejectRequest( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .RejectRequest( + tokens, + destUser + ); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + #endregion + + // + #region Friendship Getters ... + + /// + /// Get Friendship Info Model between Specific User and Current User + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipInfoDto + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpGet("Friendship/{destUser}/FriendshipInfo")] + public async Task> FriendshipInfo( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFriendshipInfo( + tokens, + destUser + ); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Check a User IsFollower of Requested User + /// + /// a user identifier which represent destination user + /// a boolean value + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpGet("Friendship/{destUser}/IsFollower")] + public async Task> IsFollower( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .IsFollower( + tokens, + destUser + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get Follower State of a User + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipState + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpGet("Friendship/{destUser}/FollowerState")] + public async Task> FollowerState( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFollowerState( + tokens, + destUser + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get Specific Follower + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipFollower + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpGet("Friendship/{destUser}/Follower")] + public async Task> Follower( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFollower( + tokens, + destUser + ); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get Followers List Of Current User + /// + /// a collection of XFriendshipFollower + [HttpGet("Friendship/Followers")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> Followers() + { + // + // Do Action ... + try + { + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFollowers(tokens); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + + // + return exResult; + } + } + + /// + /// Get All Followers List Includes Blocked, Requested and etc + /// of Current User + /// + /// a collection of XFriendshipFollower + [HttpGet("Friendship/AllFollowers")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> AllFollowers() + { + // + // Do Action ... + try + { + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetAllFollowers(tokens); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get All Followers List Includes Blocked, Requested and etc + /// of Current User based On Query Model ... + /// + /// a Query Result of XFriendDto + [HttpGet("Friendship/QueryFollowers")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> QueryFollowers( + [FromQuery] XQuery query, + [FromQuery] string destUser + ) + { + // + // Do Action ... + try + { + // + // Normalizing Dest User ... + var userInfo = await GetUserInfo(); + bool isAdmin = userInfo.Roles.Contains(XUserRoles.ADMIN); + if (destUser.IsNullOrEmpty()) + { + destUser = userInfo.UserName; + } + bool isDestUserValid = isAdmin || destUser == userInfo.UserId || destUser == userInfo.Email || destUser == userInfo.PhoneNumber || destUser == userInfo.UserName; + if (!isDestUserValid) + { + XException.NotAllowed.Throw(); + } + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .QueryFollowers( + query: query, + tokens: tokens, + destUser: destUser + ); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Check a User is in Followings of Current User + /// + /// a user identifier which represent destination user + /// a boolean value + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpGet("Friendship/{destUser}/IsFollowing")] + public async Task> IsFollowing( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .IsFollowing( + tokens, + destUser + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get Following State Relation between Specific User + /// and Current User + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipState + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpGet("Friendship/{destUser}/FollowingState")] + public async Task> FollowingState( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFollowingState( + tokens, + destUser + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get Specific Following Model + /// + /// a user identifier which represent destination user + /// an instance of XFriendshipFollowing + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpGet("Friendship/{destUser}/Following")] + public async Task> Following( + [FromRoute] string destUser + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(destUser); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFollowing( + tokens, + destUser + ); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get Followings of Current User + /// + /// a collection of XFriendshipFollowing + [HttpGet("Friendship/Followings")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> Followings() + { + // + // Do Action ... + try + { + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFollowings(tokens); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get All Following List Includes Blocked, Requested and etc + /// of Current User + /// + /// a collection of XFriendshipFollowing + [HttpGet("Friendship/AllFollowings")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> AllFollowings() + { + // + // Do Action ... + try + { + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetAllFollowings(tokens); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Return Following UserName's List of Current User + /// + /// a collection of UserNames + [HttpGet("Friendship/FollowingsList")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> FollowingsList() + { + // + // Do Action ... + try + { + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFollowingList(tokens); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Return Followers UserName's List of Current User + /// + /// a collection of UserNames + [HttpGet("Friendship/FollowersList")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> FollowersList() + { + // + // Do Action ... + try + { + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetFollowersList(tokens); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Get All Followings List Includes Blocked, Requested and etc + /// of Current User based On Query Model ... + /// + /// a Query Result of XFriendDto + [HttpGet("Friendship/QueryFollowings")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> QueryFollowings( + [FromQuery] XQuery query, + [FromQuery] string destUser + ) + { + // + // Do Action ... + try + { + // + // Normalizing Dest User ... + var userInfo = await GetUserInfo(); + bool isAdmin = userInfo.Roles.Contains(XUserRoles.ADMIN); + if (destUser.IsNullOrEmpty()) + { + destUser = userInfo.UserName; + } + bool isDestUserValid = isAdmin || destUser == userInfo.UserId || destUser == userInfo.Email || destUser == userInfo.PhoneNumber || destUser == userInfo.UserName; + if (!isDestUserValid) + { + XException.NotAllowed.Throw(); + } + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .QueryFollowings( + query: query, + tokens: tokens, + destUser: destUser + ); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/Account/AccountController+Open.cs b/Controllers/Account/AccountController+Open.cs new file mode 100644 index 0000000..cd1a9fa --- /dev/null +++ b/Controllers/Account/AccountController+Open.cs @@ -0,0 +1,93 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using xCommons.Attributes; +using xCommons.Extensions; +using xModels.Dtos; + +namespace xApi.Controllers +{ + public partial class AccountController + { + #region Open Actions ... + [AllowAnonymous] + [RequireXPowered] + [HttpGet("GetUserInfo")] + public async Task> GetUserInfo( + [FromHeader] string token, + [FromQuery] string request + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + await ValidationProvider + .GroupValidationBuilder() + .AddNotEmpty(token) + .AddNotEmpty(request) + .ValidateGroupAsync(); + + // + var result = await identityProvider.GetUserInfo( + token: token, + request: request + ); + + // + // Return Result + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + [AllowAnonymous] + [RequireXPowered] + [HttpGet("GetUserInfoByDevice")] + public async Task> GetUserInfoByDevice( + [FromQuery] string userSelectByParam, + [FromBody] XDeviceDto device + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + await ValidationProvider + .GroupValidationBuilder() + .AddNotEmpty(userSelectByParam) + .AddNotNull(device) + .ValidateGroupAsync(); + + // + var result = await identityProvider.GetUserInfo( + userSelectByParam: userSelectByParam, + device: device + ); + + // + // Return Result + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/Account/AccountController+Profile.cs b/Controllers/Account/AccountController+Profile.cs new file mode 100644 index 0000000..9436e1d --- /dev/null +++ b/Controllers/Account/AccountController+Profile.cs @@ -0,0 +1,528 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using xIdentityHelper; +using xCommons.Attributes; +using xCommons.Extensions; +using xIdentityModels.Dtos; +using xIdentityModels.Models; +using xModels.Dtos; + +namespace xApi.Controllers +{ + public partial class AccountController + { + // + #region Retrieve Actions ... + /// + /// Retrieve User Names based on UserIds + /// + /// a comma seperated list of UserIds + /// a collection of UserNames + [RequireXPowered] + [HttpGet("Profile/{ids}/GetNames")] + [Authorize(Policy = XPolicies.User)] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> GetNames( + [FromRoute] string ids + ) + { + // + // Do Action ... + try + { + // + ValidationProvider.NotEmpty(ids); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider.GetUserNames( + tokens, + ids + ); + + // + // Return Result + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// get user ids and retrieve corresponding user names + /// + /// an instance of XUserNameIdRequest which represent required UserIds collection + /// a collection of XUserNameIdResponse instance + [RequireXPowered] + [HttpPost("Profile/GetNameIds")] + [Authorize(Policy = XPolicies.User)] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> GetNameIds( + [FromBody] XUserNameIdRequest model + ) + { + // + // Do Action ... + try + { + // + ValidationProvider.NotNull(model); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider.GetUserNameIds( + tokens, + model + ); + + // + // Return Result + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Get Profile Object of Specific User + /// + /// determine's which user profile must be retrieved + /// an instance of XUserProfileDto + [RequireXPowered] + [Authorize(Policy = XPolicies.User)] + [HttpGet("Profile/{userSelectByParam?}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> GetProfile( + [FromRoute] string userSelectByParam = "" + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + if (userSelectByParam.IsNullOrEmpty()) + { + userSelectByParam = User.Identity.Name; + } + ValidationProvider.NotEmpty(userSelectByParam); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .GetUserProfile( + tokens, + userSelectByParam + ); + + // + // Return Result + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Query Users + /// for specifiy users role for query user 'role: string' and 'forceRole: boolean' in header + /// + /// how to filter results based on XQuery structure + /// an string which represent user role + /// if it's true the user must has exact role, otherwise top level users also listed + /// an instance of XQueryResult of XUserProfileDto + [RequireXPowered] + [HttpGet("Profile/Query")] + [Authorize(Policy = XPolicies.EnabledAdmin)] + [Authorize(Policy = XPolicies.EnabledAgent)] + public async Task>> QueryProfiles( + [FromQuery] XQuery query, [FromHeader] string role, [FromHeader] bool forceRole = false + ) + { + // + // Do Action ... + try + { + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = new XQueryResult(); + if (role.IsNullOrEmpty()) + { + // + result = await identityProvider.QueryUsers( + tokens, + query + ); + } + else + { + // + result = await identityProvider.QueryInRoleUsers( + tokens, + role, + query, + forceRole + ); + } + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exception = GetExceptionActionResult(ex); + return exception; + } + } + + /// + /// Query Specified User's Profile Images + /// + /// determine's which user profile must be retrieved + /// how to filter results based on XQuery structure + /// an instance of XQueryResult of XProfileImage + [RequireXPowered] + [Authorize(Policy = XPolicies.User)] + [Authorize(Policy = XPolicies.EnabledUser)] + [Authorize(Policy = XPolicies.EnabledAdmin)] + [HttpGet("Profile/Avatars/Query/{userSelectByParam?}")] + public async Task>> QueryAvatars( + [FromQuery] XQuery query, [FromRoute] string userSelectByParam = null + ) + { + // + // Do Action ... + try + { + // + if (userSelectByParam.IsNullOrEmpty()) + { + userSelectByParam = User.Identity.Name; + } + ValidationProvider.NotEmpty(userSelectByParam); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider.QueryAvatars( + tokens, + userSelectByParam, + query + ); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exception = GetExceptionActionResult(ex); + return exception; + } + } + #endregion + + // + #region Update Actions ... + /// + /// Update User Profile based on XProfileUpdateRequest (FirstName/LastName/DateOfBirth) + /// + /// user update info, an instance of XProfileUpdateRequest + /// determine's which user profile must be retrieved + /// an instance of XUserProfileDto + [RequireXPowered] + [Authorize(Policy = XPolicies.EnabledUser)] + [HttpPost("Profile/Update/{userSelectByParam?}")] + public async Task> UpdateProfile( + [FromBody] XProfileUpdateRequest model, [FromRoute] string userSelectByParam = null + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + if (userSelectByParam.IsNullOrEmpty()) + { + userSelectByParam = User.Identity.Name; + } + ValidationProvider.NotEmpty(userSelectByParam); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider.ProfileUpdateAsync( + tokens, + userSelectByParam, + model + ); + + // + // Prepare Push Message ... + + // + // Return Result + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Update a User Profile based on XProfileUpdateRequest Full + /// + /// user update info, an instance of XProfileUpdateRequest + /// determine's which user profile must be retrieved + /// an instance of XUserProfileDto + [RequireXPowered] + [HttpPost("Profile/{userSelectByParam?}")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public async Task> FullUpdateProfile( + [FromBody] XProfileUpdateRequest model, [FromRoute] string userSelectByParam = null + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + if (userSelectByParam.IsNullOrEmpty()) + { + userSelectByParam = User.Identity.Name; + } + ValidationProvider.NotEmpty(userSelectByParam); + + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider.FullProfileUpdateAsync( + tokens, + userSelectByParam, + model + ); + + // + // Prepare Push Message ... + + // + // Return Result + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + #endregion + + // + #region Avatar Actions ... + /// + /// Add a New Profile Image + /// + /// an specific File to upload, IFormFile + /// an instance of XUserProfileDto + [RequireXPowered] + [HttpPost("Profile/Avatar")] + [RequestSizeLimit(966_367_641)] + [Authorize(Policy = XPolicies.User)] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> AddAvatar( + [FromForm] IFormFile file + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotNull(file); + + // + // Get Request ... + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .AddAvatar( + tokens, + file + ); + + // + // Prepare Push Message ... + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// Add a New Collection of Profile Images + /// + /// a collection of Files to upload, IFormFileCollection + /// an instance of XUserProfileDto + [RequireXPowered] + [HttpPost("Profile/Avatars")] + [RequestSizeLimit(966_367_641)] + [Authorize(Policy = XPolicies.User)] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> AddAvatars( + [FromForm] IFormFileCollection files + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotZeroChilds(files); + + // + // Get Request ... + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider.AddAvatars( + tokens, + files + ); + + // + // Prepare Push Message ... + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exResult = GetExceptionActionResult(ex); + return exResult; + } + } + + /// + /// set Specified Profile Image as Avatar + /// + /// an integer which reperesent AvatarId to set as current Avatar + /// an instance of XUserProfileDto + [RequireXPowered] + [HttpPost("Profile/Avatars/{id:int}/Set")] + [Authorize(Policy = XPolicies.User)] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> SetAvatar( + [FromRoute] int id + ) + { + // + // Do Action ... + try + { + // + // Get Request ... + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .SetAvatar( + tokens, + id + ); + + // + // Prepare Push Message ... + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exception = GetExceptionActionResult(ex); + return exception; + } + } + + /// + /// Remove Profile Images + /// + /// a comma seperated list of avatarIds to remove + /// an instance of XUserProfileDto + [RequireXPowered] + [Authorize(Policy = XPolicies.User)] + [HttpDelete("Profile/Avatars/{ids}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> RemoveAvatars( + [FromRoute] string ids + ) + { + // + // Do Action ... + try + { + // + // Validate Args ... + ValidationProvider.NotEmpty(ids); + + // + // Get Request ... + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider + .RemoveAvatars( + tokens, + ids + ); + + // + // Prepare Push Message ... + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/Account/AccountController+Registration.cs b/Controllers/Account/AccountController+Registration.cs new file mode 100644 index 0000000..dca93d5 --- /dev/null +++ b/Controllers/Account/AccountController+Registration.cs @@ -0,0 +1,1142 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using xIdentityHelper; +using xCommons.Attributes; +using xCommons.Extensions; +using xExceptions.Constants; +using xIdentityModels.Constants; +using xIdentityModels.Extensions; +using xIdentityModels.Models; + +namespace xApi.Controllers { + public partial class AccountController { + // + #region Registration ... + /// + /// Check a UserName is Available For Registration or not + /// + /// an string value which represent desired username + /// a boolean value + [AllowAnonymous] + [RequireXPowered] + [HttpGet ("CanRegisterUserName/{userName?}")] + public async Task> CanRegisterUserName ( + [FromRoute] string userName + ) { + // + // Do Action ... + try { + // + // Validate Args ... + ValidationProvider.NotEmpty (userName); + + // + // Validate Type ... + var type = userName.GetUserSelectByType (); + if (type != XUserSelectBy.Username) { + XException.InvalidArgs.Throw (); + } + + // + var result = await identityProvider + .CanRegister (userName); + + // + // Return Result + return Ok (result); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + + // + return result; + } + } + + /// + /// Check a Mobile Number is Available For Registration or not + /// + /// an string value which represent desired mobile number + /// a boolean value + [AllowAnonymous] + [RequireXPowered] + [HttpGet ("CanRegisterMobileNumber/{mobileNumber?}")] + public async Task> CanRegisterMobileNumber ( + [FromRoute] string mobileNumber + ) { + // + // Do Action ... + try { + // + // Validate Args ... + ValidationProvider.NotEmpty (mobileNumber); + + // + // Validate Type ... + var type = mobileNumber.GetUserSelectByType (); + if (type != XUserSelectBy.MobileNumber) { + XException.InvalidArgs.Throw (); + } + + // + var result = await identityProvider + .CanRegister (mobileNumber); + + // + // Return Result + return Ok (result); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + + // + return result; + } + } + + /// + /// Check a Email Address is Available For Registration or not + /// + /// an string value which represent desired email address + /// a boolean value + [AllowAnonymous] + [RequireXPowered] + [HttpGet ("CanRegisterEmail/{email?}")] + public async Task> CanRegisterEmail ( + [FromRoute] string email + ) { + // + // Do Action ... + try { + // + // Validate Args ... + ValidationProvider.NotEmpty (email); + + // + // Validate Type ... + var type = email.GetUserSelectByType (); + if (type != XUserSelectBy.Email) { + XException.InvalidArgs.Throw (); + } + + // + var result = await identityProvider + .CanRegister (email); + + // + // Return Result + return Ok (result); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + + // + return result; + } + } + + /// + /// Invite a User to Register on Dashboard + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - Email: which email address is going to invite. + /// - Device: user's client device which is an instance of XDevice. + /// - ReturnUrl: client application Registration URL. + /// notice in this step you had to provide all this informations as FormData + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "email": "", + /// "returnUrl": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// an instance of XActionResponse + [RequireXPowered] + [HttpPost ("InviteUser")] + [Authorize (Policy = XPolicies.EnabledAdmin)] + [Authorize (Policy = XPolicies.EnabledAgent)] + public async Task> InviteUser ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + + // + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.Email, + model.ReturnUrl) + .AddEmailAddress (model.Email) + .AddNotNull (model.Device) + .ValidateGroupAsync (); + + // + // Get Request ... + var tokens = await RetrieveTokensAsXTokenResponse (); + var result = await identityProvider + .InviteUser ( + tokens, + model + ); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + return result; + } + } + + /// + /// Recieve some Basic Informations and Start Registration Proccess + /// if they Valid + /// + /// Registration Proccess Starts with Invoking this Action + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - FirstName: user's FirstName. + /// - LastName: user's LastName. + /// - DateOfBirth: user's dob date. + /// - MobileNumber: user's MobileNumber optional. + /// - Email: user's Email optional. + /// - ActionToken: user's requested action token for this action (if user invited). + /// - Device: user's client device which is an instance of XDevice. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "firstName": "", + /// "lastName": "", + /// "dateOfBirth": "", + /// "email": "", + /// "mobileNumber": "", + /// "actionToken": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// an instance of XActionResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("RequestRegistration")] + public async Task> RequestRegistration ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.FirstName, + model.LastName) + .AddNotNull ( + model.Device, + model.DateOfBirth) + .ValidateGroupAsync (); + + // + // Get Request ... + var result = await identityProvider + .RequestRegistration ( + model + ); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + + // + return exResult; + } + } + + /// + /// Add User Account Informations + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - ActionToken: user's requested action token for this action. + /// - UserName: user name. + /// - Password: assigne password. + /// - Device: user's client device which is an instance of XDevice. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "userName": "", + /// "password": "", + /// "actionToken": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// an instance of XActionResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("AddAccountInfo")] + public async Task> AddAccountInfo ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.ActionToken, + model.UserName, + model.Password) + .AddNotNull (model.Device) + .ValidateGroupAsync (); + + // + // Get Request ... + var result = await identityProvider + .AddAccountInfo ( + model + ); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Upload and Attach a Profile Image for User. this is an Optional Step + /// + /// user's requested action token + /// an instance of IFormFile for user's Avatar + /// an instance of XActionResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("AttachProfileImage")] + public async Task> AttachProfileImage ( + [FromForm] string actionToken, [FromForm] IFormFile file + ) { + // + // Do Action ... + try { + // + // Validate Args ... + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty (actionToken) + .AddNotNull (file) + .ValidateGroupAsync (); + + // + var result = await identityProvider + .AttachProfileImage ( + actionToken, + file + ); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Finish Registrationn Proccess + /// + /// + /// for this action you have to provide: + /// - a proper User Identifier such as: (UserId, UserName, Email or MobileNumber). + /// - Lang: client device currently used locale, such as: en-US. + /// - ActionToken: user's requested action token for this action. + /// - Password: assigne password. + /// - Device: user's client device which is an instance of XDevice. + /// - ReturnUrl: client application Login URL. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "userName": "", + /// "password": "", + /// "returnUrl": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("FinishRegistration")] + public async Task FinishRegistration ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.Password, + model.ReturnUrl) + .AddNotNull (model.Device) + .AddUrl (model.ReturnUrl) + .ValidateGroupAsync (); + + // + var userSelectByParam = identityProvider + .GetUserSelectByParam (model); + ValidationProvider + .NotEmpty (userSelectByParam); + + // + // Get Request ... + await identityProvider + .FinishRegistration (model); + + // + return Ok (); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + + // + return exResult; + } + } + + /// + /// Check User is Confirmed Email or not + /// + /// a boolean value + [RequireXPowered] + [HttpGet ("IsConfirmedEmail")] + [Authorize (Policy = XPolicies.User)] + public async Task> IsConfirmedEmail () { + // + // Do Action ... + try { + // + // Get Result ... + var tokens = await RetrieveTokensAsXTokenResponse (); + var result = await identityProvider + .IsConfirmedEmail ( + tokens, + User.Identity.Name + ); + + // + // Return Result + return Ok (result); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + + // + return result; + } + } + + /// + /// Check User is Confirmed Mobile or not + /// + /// a boolean value + [RequireXPowered] + [HttpGet ("IsConfirmedMobile")] + [Authorize (Policy = XPolicies.User)] + public async Task> IsConfirmedMobile () { + // + // Do Action ... + try { + // + // Get Result ... + var tokens = await RetrieveTokensAsXTokenResponse (); + var result = await identityProvider + .IsConfirmedMobile ( + tokens, + User.Identity.Name + ); + + // + // Return Result + return Ok (result); + } catch (Exception ex) { + // + var result = GetExceptionActionResult (ex); + + // + return result; + } + } + + /// + /// Request Registration Confirm + /// + /// + /// for this action you have to provide: + /// - a UserSelectedBy identifier which represet User. + /// - Lang: client device currently used locale, such as: en-US. + /// - Password: user's current active password. + /// - Device: user's client device which is an instance of XDevice. + /// - ReturnUrl: client application Confirm Registration URL. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "userId": "" + /// "password": "", + /// "returnUrl": "http://localhost/confirm", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("RequestConfirmRegistration")] + public async Task RequestConfirmRegistration ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.Password, + model.ReturnUrl) + .AddNotNull (model.Device) + .AddUrl (model.ReturnUrl) + .ValidateGroupAsync (); + + // + // Get UserSelect By Param ... + var userSelectByParam = model.GetUserSelectByParam (); + ValidationProvider.NotEmpty (userSelectByParam); + + // + await identityProvider + .RequestConfirmRegistration (model); + + // + return Ok (); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Confirm Registration + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - ActionToken: user's requested action token for this action. + /// - Device: user's client device which is an instance of XDevice. + /// - ReturnUrl: client application Login URL. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "actionToken": "" + /// "returnUrl": "http://localhost/login", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("ConfirmRegistration")] + public async Task ConfirmRegistration ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.ActionToken, + model.ReturnUrl + ) + .AddNotNull (model.Device) + .ValidateGroupAsync (); + + // + // Get Request ... + await identityProvider + .ConfirmRegistration (model); + + // + return Ok (); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Request For Mobile Number Change/Confirm + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - Password: user's current active password. + /// - MobileNumber: which phone number is going to confirm. + /// - Device: user's client device which is an instance of XDevice. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "password": "", + /// "mobileNumber": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// an instance of XActionResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("RequestConfirmMobile")] + public async Task> RequestConfirmMobile ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.Password, + model.MobileNumber) + .AddNotNull (model.Device) + .AddMobileNumber (model.MobileNumber) + .ValidateGroupAsync (); + + // + // Get UserSelect By Param ... + var userSelectByParam = GetUserSelectByParam ( + model, + excludes : new List { + XUserSelectBy.Email, + XUserSelectBy.MobileNumber + }); + + // + // Get Request ... + var result = await identityProvider + .RequestConfirmMobile (model); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Confirm Requested Mobile Number + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - ActionToken: user's requested action token for this action. + /// - Device: user's client device which is an instance of XDevice. + /// - MobileVerificationCode: a verification code which produced due Request Action. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "actionToken": "" + /// "mobileVerificationCode": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// an instance of XActionResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("ConfirmMobileNumber")] + public async Task> ConfirmMobileNumber ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.MobileVerificationCode, + model.ActionToken + ) + .AddNotNull (model.Device) + .ValidateGroupAsync (); + + // + // Get Request ... + var result = await identityProvider + .ConfirmMobileNumber (model); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Request For Email Address Change/Confirm + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - Password: user's current active password. + /// - Email: which email address is going to confirm. + /// - Device: user's client device which is an instance of XDevice. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "password": "", + /// "email": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// an instance of XActionResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("RequestConfirmEmail")] + public async Task> RequestConfirmEmail ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.Email, + model.Password) + .AddNotNull (model.Device) + .AddEmailAddress (model.Email) + .ValidateGroupAsync (); + + // + // Get UserSelect By Param ... + var userSelectByParam = GetUserSelectByParam ( + model, + excludes : new List { + XUserSelectBy.Email, + XUserSelectBy.MobileNumber + }); + + // + // Get Request ... + var result = await identityProvider + .RequestConfirmEmail (model); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Confirm Requested Email Address + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - ActionToken: user's requested action token for this action. + /// - Device: user's client device which is an instance of XDevice. + /// - EmailVerificationCode: a verification code which produced due Request Action. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "actionToken": "" + /// "emailVerificationCode": "", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// an instance of XActionResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("ConfirmEmailAddress")] + public async Task> ConfirmEmailAddress ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.EmailVerificationCode, + model.ActionToken + ) + .AddNotNull (model.Device) + .ValidateGroupAsync (); + + // + // Get Request ... + var result = await identityProvider + .ConfirmEmailAddress (model); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Request Reset Password Action + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - Device: user's client device which is an instance of XDevice. + /// - ReturnUrl: client application ResetPassword URL. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "returnUrl": "http://localhost/reset-password", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// an instance of XActionResponse + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("RequestResetPassword")] + public async Task> RequestResetPassword ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.ReturnUrl) + .AddNotNull (model.Device) + .AddUrl (model.ReturnUrl) + .ValidateGroupAsync (); + + // + // Get UserSelect By Param ... + var userSelectByParam = GetUserSelectByParam ( + model, + excludes : new List { + XUserSelectBy.Email, + XUserSelectBy.MobileNumber + }); + + // + // Get Request ... + var result = await identityProvider + .RequestResetPassword (model); + + // + return Ok (result + .ToDynamicObject ()); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + + /// + /// Reset a User's Password + /// + /// + /// for this action you have to provide: + /// - Lang: client device currently used locale, such as: en-US. + /// - ActionToken: user's requested action token for this action. + /// - NewPassword: user's new password to change. + /// - Device: user's client device which is an instance of XDevice. + /// - ReturnUrl: client application Login URL. + /// + /// Sample request: + /// + /// { + /// "lang": "fa-IR", + /// "actionToken": "", + /// "newPassword": "", + /// "returnUrl": "http://localhost/login", + /// "device": { + /// "os":"Mac", + /// "browser":"Chrome", + /// "osVersion":"mac-os-x-15", + /// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36", + /// "deviceType":3, + /// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]", + /// "token":"96f400dd9aa5c57a8cec9d6f4775bad3" + /// } + /// } + /// + /// + /// an instance of XActionRequest class which provider requirement for action + /// + [AllowAnonymous] + [RequireXPowered] + [HttpPost ("ResetPassword")] + public async Task ResetPassword ( + [FromBody] XActionRequest model + ) { + // + // Do Action ... + try { + // + // Validate Args ... + if (!ModelState.IsValid) { + XException.InvalidArgs.Throw (); + } + await ValidationProvider + .GroupValidationBuilder () + .AddNotEmpty ( + model.Lang, + model.ActionToken, + model.NewPassword, + model.ReturnUrl) + .AddNotNull (model.Device) + .ValidateGroupAsync (); + + // + // Get Request ... + await identityProvider + .ResetPassword (model); + + // + return Ok (); + } catch (Exception ex) { + // + var exResult = GetExceptionActionResult (ex); + return exResult; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/Account/AccountController+Search.cs b/Controllers/Account/AccountController+Search.cs new file mode 100644 index 0000000..fdf3c68 --- /dev/null +++ b/Controllers/Account/AccountController+Search.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using xCommons.Attributes; +using xCommons.Extensions; +using xIdentityHelper; +using xIdentityModels.Dtos; +using xModels.Dtos; + +namespace xApi.Controllers +{ + public partial class AccountController + { + // + #region Actions ... + /// + /// Query Open To Search Users Profiles ... + /// Query all Users Which their Profiles is Open To Search ... + /// + /// how to filter results based on XQuery structure + /// an instance of XQueryResult of XUserProfileDto + [RequireXPowered] + [HttpGet("OpenToSearch/Query")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> QueryOpenToSearchProfiles( + [FromQuery] XQuery query + ) + { + // + // Do Action ... + try + { + // + var tokens = await RetrieveTokensAsXTokenResponse(); + var result = await identityProvider.QueryOpenToSearchUsers( + tokens, + query + ); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var exception = GetExceptionActionResult(ex); + return exception; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/AccountController.cs b/Controllers/AccountController.cs new file mode 100644 index 0000000..2378ac5 --- /dev/null +++ b/Controllers/AccountController.cs @@ -0,0 +1,42 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Logging; +using xCommons.Attributes; +using xCommons.Configurations; +using xCommons.Providers; +using xIdentityService.Controllers; +using xIdentityService.Interfaces; + +namespace xApi.Controllers +{ + /// + /// Handle all Account Related Actions ... + /// + [AllowAnonymous] + [RequireXPowered(true)] + public partial class AccountController : XIBaseController + { + // + #region Props ... + private readonly IXIdentityProvider identityProvider; + #endregion + + // + #region Constructor ... + public AccountController( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider + ) + { + // + this.identityProvider = identityProvider; + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/StartupController.cs b/Controllers/StartupController.cs new file mode 100644 index 0000000..fbaef93 --- /dev/null +++ b/Controllers/StartupController.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xCommons.Configurations; +using xCommons.Controllers; +using xCommons.Providers; + +namespace xApi.Controllers { + /// + /// Runing when application start ... + /// + [Route ("")] + [AllowAnonymous] + public class StartupController : XBaseController { + + public StartupController ( + ILogger logger, + XAppConfiguration appConfiguration, + XValidationProvider validationProvider + ) : base ( + logger, + appConfiguration, + validationProvider + ) { } + + /// + /// Show Configured Welcome Message + /// + /// + [HttpGet ("")] + [AllowAnonymous] + public virtual ActionResult Index () { + // + var controllerName = GetControllerName (); + var message = $"{AppConfiguration.WelcomeMessage}"; + + // + return Ok (message); + } + } +} \ No newline at end of file diff --git a/Controllers/TestIdentity.cs b/Controllers/TestIdentity.cs new file mode 100644 index 0000000..09d3acc --- /dev/null +++ b/Controllers/TestIdentity.cs @@ -0,0 +1,176 @@ +using System.Linq; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xCommons.Attributes; +using xCommons.Configurations; +using xCommons.Providers; +using xIdentityHelper; +using xIdentityService.Controllers; +using xIdentityService.Interfaces; + +namespace xApi.Controllers { + /// + /// Test all Authentication Policies ... + /// + [RequireXPowered (false)] + public class TestIdentity : XIBaseController { + public TestIdentity ( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider + ) : base ( + logger, + appConfiguration, + identityProvider, + validationProvider + ) { } + + // + #region Test Actions ... + /// + /// API Read Scope + /// + /// string message + [HttpGet ("PassReadAccess")] + [Authorize (Policy = XPolicies.ReadAccess)] + public ActionResult PassReadAccess () { + return Ok ("Read Access Passed ..."); + } + + /// + /// API Write Scope + /// + /// string message + [HttpGet ("PassWriteAccess")] + [Authorize (Policy = XPolicies.WriteAccess)] + public ActionResult PassWriteAccess () { + return Ok ("Write Access Passed ..."); + } + + /// + /// API Admin Scope + /// + /// string message + [HttpGet ("PassAdminAccess")] + [Authorize (Policy = XPolicies.AdminAccess)] + public ActionResult PassAdminAccess () { + return Ok ("Admin Access Passed ..."); + } + + /// + /// API Manage Scop + /// + /// string message + [HttpGet ("PassManageAccess")] + [Authorize (Policy = XPolicies.ManageAccess)] + public ActionResult PassManageAccess () { + return Ok ("Manage Access Passed ..."); + } + + /// + /// a simple Action which returns a List of Authenticated User Claims + /// + /// string message which represent current user's claims + [HttpGet ("HiClaims")] + [Authorize (Policy = XPolicies.User)] + public ActionResult HiClaims () { + // + var result = new { + name = User.Identity.Name, + claims = User.Claims.Select (c => new { + c.Type, c.Value + }) + }; + + // + return Ok (result); + } + + /// + /// a simple Hello User for Checking Authentication and Policy + /// + /// string message which contains authenticated user name + [HttpGet ("HiUser")] + [Authorize (Policy = XPolicies.User)] + public ActionResult HiUser () { + // + var result = $"Hi User: {User.Identity.Name} ..."; + + // + return Ok (result); + } + + /// + /// a simple Hello User for Checking Authentication and Policy + /// + /// string message which contains authenticated user name + [HttpGet ("HiEnabledUser")] + [Authorize (Policy = XPolicies.EnabledUser)] + public ActionResult HiEnabledUser () { + // + var result = $"Hi User: {User.Identity.Name} is Enabled ..."; + + // + return Ok (result); + } + + /// + /// a simple Hello User for Checking Authentication and Policy + /// + /// string message which contains authenticated user name + [HttpGet ("HiAgent")] + [Authorize (Policy = XPolicies.Agent)] + public ActionResult HiAgent () { + // + var result = $"Hi Admin: {User.Identity.Name} ..."; + + // + return Ok (result); + } + + /// + /// a simple Hello User for Checking Authentication and Policy + /// + /// string message which contains authenticated user name + [HttpGet ("HiEnabledAgent")] + [Authorize (Policy = XPolicies.EnabledAgent)] + public ActionResult HiEnabledAgent () { + // + var result = $"Hi Admin: {User.Identity.Name} is Enabled ..."; + + // + return Ok (result); + } + + /// + /// a simple Hello User for Checking Authentication and Policy + /// + /// string message which contains authenticated user name + [HttpGet ("HiAdmin")] + [Authorize (Policy = XPolicies.Admin)] + public ActionResult HiAdmin () { + // + var result = $"Hi Admin: {User.Identity.Name} ..."; + + // + return Ok (result); + } + + /// + /// a simple Hello User for Checking Authentication and Policy + /// + /// string message which contains authenticated user name + [HttpGet ("HiEnabledAdmin")] + [Authorize (Policy = XPolicies.EnabledAdmin)] + public ActionResult HiEnabledAdmin () { + // + var result = $"Hi Admin: {User.Identity.Name} is Enabled ..."; + + // + return Ok (result); + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/V1/Configurations/ConfigurationsController+Terms.cs b/Controllers/V1/Configurations/ConfigurationsController+Terms.cs new file mode 100644 index 0000000..5a06e1b --- /dev/null +++ b/Controllers/V1/Configurations/ConfigurationsController+Terms.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using xCommons.Extensions; +using xIdentityHelper; +using xServices.TermsConditions.Interfaces; + +namespace xApi.Controllers.V1 +{ + /// + /// Implementing Terms and Conditions Action Provider ... + /// + public partial class ConfigurationsController : IXTermsConditionsControllerActions + { + // + #region Actions ... + /// + /// Retrieved all Exists Languages Terms and Conditions ... + /// + /// + [HttpGet("Terms/Languages")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task>> TermsLanguages() + { + // + // Do ... + try + { + // + // Retrieve User Info ... + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await TermsProvider.TermsLanguages(); + + // + return Ok(result + .ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Check Has Terms and Conditions based on Specified Language ... + /// + /// if null, used Default Language ... + /// + [HttpGet("Terms/{language}/Has")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> HasTerms( + [FromRoute] string language = null + ) + { + // + // Do ... + try + { + // + // Retrieve User Info ... + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await TermsProvider.HasTerms( + language: language + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Retrieve Terms and Conditions for Specified Language ... + /// + /// if null, used Default Language ... + /// + [AllowAnonymous] + [HttpGet("Terms/{language}")] + public async Task> GetTerms( + [FromRoute] string language = null + ) + { + // + // Do ... + try + { + // + // Retrieve User Info ... + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await TermsProvider.GetTerms( + language: language + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Add Terms and Conditions for Specified Language ... + /// + /// + /// + /// + [HttpPost("Terms/{language}")] + [Authorize(Policy = XPolicies.EnabledAdmin)] + public async Task> AddTerms( + [FromRoute] string language, + [FromQuery] string terms + ) + { + // + // Do ... + try + { + // + // Retrieve User Info ... + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await TermsProvider.AddTerms( + terms: terms, + language: language, + userInfo: userInfo, + connectionId: connectionId + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Remove Terms and Conditions of Specified Language ... + /// + /// + /// + [HttpDelete("Terms/{language}")] + [Authorize(Policy = XPolicies.EnabledAdmin)] + public async Task> RemoveTerms( + [FromRoute] string language + ) + { + // + // Do ... + try + { + // + // Retrieve User Info ... + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await TermsProvider.RemoveTerms( + language: language, + userInfo: userInfo, + connectionId: connectionId + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Update Terms and Conditions of Specified Language ... + /// + /// + /// + /// + [HttpPut("Terms/{language}")] + [Authorize(Policy = XPolicies.EnabledAdmin)] + public async Task> UpdateTerms( + [FromRoute] string language, + [FromQuery] string terms + ) + { + // + // Do ... + try + { + // + // Retrieve User Info ... + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await TermsProvider.UpdateTerms( + terms: terms, + language: language, + userInfo: userInfo, + connectionId: connectionId + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/V1/ConfigurationsController.cs b/Controllers/V1/ConfigurationsController.cs new file mode 100644 index 0000000..7e53100 --- /dev/null +++ b/Controllers/V1/ConfigurationsController.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Logging; +using xApi.Base; +using xCommons.Configurations; +using xCommons.Providers; +using xIdentityService.Interfaces; +using xServices.TermsConditions.Interfaces; + +namespace xApi.Controllers.V1 +{ + /// + /// Provides all Configuration related Actions such as String resources and Terms and Configurations ... + /// + public partial class ConfigurationsController : XIBaseV1Controller + { + // + #region Properties ... + public IXTermsComditionsProvider TermsProvider { get; } + #endregion + + // + #region Constructor ... + public ConfigurationsController( + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXTermsComditionsProvider termsProvider, + ILogger logger + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider + ) + { + // + TermsProvider = termsProvider; + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/V1/Entities/FilesController.cs b/Controllers/V1/Entities/FilesController.cs new file mode 100644 index 0000000..e5b52b9 --- /dev/null +++ b/Controllers/V1/Entities/FilesController.cs @@ -0,0 +1,324 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using xApi.Base; +using xCommons.Configurations; +using xCommons.Extensions; +using xCommons.Providers; +using xDataService.Interfaces; +using xFileService.Interfaces.Entities; +using xFileService.Models.Entities; +using xIdentityHelper; +using xIdentityService.Interfaces; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; +using xPushService.Constants; + +namespace xApi.Controllers.V1.Entities +{ + public class FilesController : XIBaseV1EntityHubController + { + // + #region Constructor ... + public FilesController( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXFileRepository repository, + IHubContext> hub = null + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider, + repository, + hub + ) + { } + #endregion + + // + #region Interface Implementations ... + // + #region Retrieve ... + [HttpGet("{id}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> Get( + [FromRoute] Guid id, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .Get( + id: id, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> GetAll( + [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .GetAll( + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("FindOne/{query}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> FindOne( + [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .FindOne( + query: query, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("FindMany/{query}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> FindMany( + [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .FindMany( + query: query, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("Query")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> Query( + [FromQuery] XQuery query, [FromQuery] bool ignoreSoftDeleteds = true + ) + { + return await base + .Query( + query: query, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + + // + #region Add ... + [HttpPost] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Add( + [FromBody] XFile item + ) + { + // + var entity = await base + .Add(item); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Add.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("AddOrUpdate")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> AddOrUpdate( + [FromBody] XFile item + ) + { + // + var entity = await base + .AddOrUpdate(item); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.AddOrUpdate.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("AddMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task AddMany( + [FromBody] XBaseRangeRequest request + ) + { + // + var result = await base + .AddMany(request); + + // + if (!(result as OkObjectResult).IsNull()) + { + // + await SendPush( + action: XBaseEntityHubAction.AddMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + [HttpPut("{id}")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Update( + [FromRoute] Guid id, [FromBody] XFile item + ) + { + // + var entity = await base + .Update( + id, + item + ); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Update.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("UpdateMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> UpdateMany( + [FromBody] XBaseRangeRequest request + ) + { + // + var result = await base + .UpdateMany(request); + + // + var resultObject = (result.Result as OkObjectResult).Value; + if (!resultObject.IsNull() && (bool)resultObject) + { + // + await SendPush( + action: XBaseEntityHubAction.UpdateMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + + // + #region Exists ... + [HttpGet("{id}/IsExists")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> IsExists( + [FromRoute] Guid id, [FromQuery] bool ignoreSoftDeleteds = true + ) + { + return await base + .IsExists( + id: id, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + + // + #region Remove ... + [HttpDelete("{id}")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Remove( + [FromRoute] Guid id, bool softDelete = true + ) + { + // + var entity = await base + .Remove( + id: id, + softDelete: softDelete + ); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Delete.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("RemoveMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task RemoveMany( + [FromBody] XBaseRangeRequest request, bool softDelete = true + ) + { + // + var result = await base + .RemoveMany( + request: request, + softDelete: softDelete + ); + + // + if (!(result as OkObjectResult).IsNull()) + { + // + await SendPush( + action: XBaseEntityHubAction.DeleteMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + #endregion + } +} \ No newline at end of file diff --git a/Controllers/V1/Entities/StringsController.cs b/Controllers/V1/Entities/StringsController.cs new file mode 100644 index 0000000..a1306e9 --- /dev/null +++ b/Controllers/V1/Entities/StringsController.cs @@ -0,0 +1,326 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using xApi.Base; +using xCommons.Configurations; +using xCommons.Extensions; +using xCommons.Providers; +using xIdentityHelper; +using xIdentityService.Interfaces; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; +using xPushService.Constants; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xApi.Controllers.V1.Entities +{ + /// + /// Simple XString Entity Controller ... + /// + public class StringsController : XIBaseV1EntityHubController + { + // + #region Constructor ... + public StringsController( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXStringRepository repository, + IHubContext> hub = null + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider, + repository, + hub + ) + { } + #endregion + + // + #region Interface Implementations ... + // + #region Retrieve ... + [HttpGet("{id}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> Get( + [FromRoute] int id, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .Get( + id: id, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> GetAll( + [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .GetAll( + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("FindOne/{query}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> FindOne( + [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .FindOne( + query: query, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("FindMany/{query}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> FindMany( + [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .FindMany( + query: query, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("Query")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> Query( + [FromQuery] XQuery query, [FromQuery] bool ignoreSoftDeleteds = true + ) + { + return await base + .Query( + query: query, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + + // + #region Add ... + [HttpPost] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Add( + [FromBody] XString item + ) + { + // + var entity = await base + .Add(item); + + // + // Handle Sending Push Notification ... + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Add.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("AddOrUpdate")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> AddOrUpdate( + [FromBody] XString item + ) + { + // + var entity = await base + .AddOrUpdate(item); + + // + // Handle Sending Push Notification ... + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.AddOrUpdate.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("AddMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task AddMany( + [FromBody] XBaseRangeRequest request + ) + { + // + var result = await base + .AddMany(request); + + // + if (!(result as OkObjectResult).IsNull()) + { + // + await SendPush( + action: XBaseEntityHubAction.AddMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + [HttpPut("{id}")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Update( + [FromRoute] int id, [FromBody] XString item + ) + { + // + var entity = await base + .Update( + id, + item + ); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Update.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("UpdateMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> UpdateMany( + [FromBody] XBaseRangeRequest request + ) + { + // + var result = await base + .UpdateMany(request); + + // + var resultObject = (result.Result as OkObjectResult).Value; + if (!resultObject.IsNull() && (bool)resultObject) + { + // + await SendPush( + action: XBaseEntityHubAction.UpdateMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + + // + #region Exists ... + [HttpGet("{id}/IsExists")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> IsExists( + [FromRoute] int id, [FromQuery] bool ignoreSoftDeleteds = true + ) + { + return await base + .IsExists( + id: id, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + + // + #region Remove ... + [HttpDelete("{id}")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Remove( + [FromRoute] int id, bool softDelete = true + ) + { + // + var entity = await base + .Remove( + id: id, + softDelete: softDelete + ); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Delete.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("RemoveMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task RemoveMany( + [FromBody] XBaseRangeRequest request, bool softDelete = true + ) + { + // + var result = await base + .RemoveMany( + request: request, + softDelete: softDelete + ); + + // + if (!(result as OkObjectResult).IsNull()) + { + // + await SendPush( + action: XBaseEntityHubAction.DeleteMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + #endregion + } +} \ No newline at end of file diff --git a/Controllers/V1/Entities/TagsController.cs b/Controllers/V1/Entities/TagsController.cs new file mode 100644 index 0000000..ef369f0 --- /dev/null +++ b/Controllers/V1/Entities/TagsController.cs @@ -0,0 +1,321 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using xApi.Base; +using xCommons.Configurations; +using xCommons.Extensions; +using xCommons.Providers; +using xIdentityHelper; +using xIdentityService.Interfaces; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; +using xPushService.Constants; +using xTagService.Interfaces.Entities; +using xTagService.Models.Entities; + +namespace xApi.Controllers.V1.Entities +{ + public class TagsController : XIBaseV1EntityHubController + { + // + #region Constructor ... + public TagsController( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXTagRepository repository, + IHubContext> hub = null + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider, + repository, + hub + ) + { } + #endregion + + // + #region Interface Implementations ... + // + #region Retrieve ... + [HttpGet("{id}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> Get( + [FromRoute] int id, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .Get( + id: id, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> GetAll( + [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .GetAll( + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("FindOne/{query}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> FindOne( + [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .FindOne( + query: query, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("FindMany/{query}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> FindMany( + [FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false + ) + { + return await base + .FindMany( + query: query, + containsDetail: containsDetail, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + [HttpGet("Query")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> Query( + [FromQuery] XQuery query, [FromQuery] bool ignoreSoftDeleteds = true + ) + { + return await base + .Query( + query: query, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + + // + #region Add ... + [HttpPost] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Add( + [FromBody] XTag item + ) + { + // + var entity = await base + .Add(item); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Add.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("AddOrUpdate")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> AddOrUpdate( + [FromBody] XTag item + ) + { + // + var entity = await base + .AddOrUpdate(item); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.AddOrUpdate.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("AddMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task AddMany( + [FromBody] XBaseRangeRequest request + ) + { + // + var result = await base + .AddMany(request); + + // + if (!(result as OkObjectResult).IsNull()) + { + // + await SendPush( + action: XBaseEntityHubAction.AddMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + [HttpPut("{id}")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Update( + [FromRoute] int id, [FromBody] XTag item + ) + { + // + var entity = await base + .Update( + id, + item + ); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Update.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("UpdateMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> UpdateMany( + [FromBody] XBaseRangeRequest request + ) + { + // + var result = await base + .UpdateMany(request); + + // + var resultObject = (result.Result as OkObjectResult).Value; + if (!resultObject.IsNull() && (bool)resultObject) + { + // + await SendPush( + action: XBaseEntityHubAction.UpdateMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + + // + #region Exists ... + [HttpGet("{id}/IsExists")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> IsExists( + [FromRoute] int id, [FromQuery] bool ignoreSoftDeleteds = true + ) + { + return await base + .IsExists( + id: id, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + + // + #region Remove ... + [HttpDelete("{id}")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Remove( + [FromRoute] int id, bool softDelete = true + ) + { + // + var entity = await base + .Remove( + id: id, + softDelete: softDelete + ); + + // + if (!entity.IsNullOrDefault()) + { + // + await SendPush( + action: XBaseEntityHubAction.Delete.GetStringValue(), + payLoad: entity.ToJSON() + ); + } + + // + return entity; + } + + [HttpPost("RemoveMany")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task RemoveMany( + [FromBody] XBaseRangeRequest request, bool softDelete = true + ) + { + // + var result = await base + .RemoveMany( + request: request, + softDelete: softDelete + ); + + // + if (!(result as OkObjectResult).IsNull()) + { + // + await SendPush( + action: XBaseEntityHubAction.DeleteMany.GetStringValue(), + payLoad: request.Items.ToJSON() + ); + } + + // + return result; + } + #endregion + #endregion + } +} \ No newline at end of file diff --git a/Controllers/V1/Services/FilesController.cs b/Controllers/V1/Services/FilesController.cs new file mode 100644 index 0000000..a0785a2 --- /dev/null +++ b/Controllers/V1/Services/FilesController.cs @@ -0,0 +1,309 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xCommons.Attributes; +using xCommons.Configurations; +using xCommons.Providers; +using xFileService.Controllers; +using xFileService.Interfaces; +using xIdentityHelper; +using xIdentityService.Interfaces; +using xModels.Dtos; +using XFileDto = xFileService.Models.Dtos.XFileDto; + +namespace xApi.Controllers.V1.Services +{ + [ApiController] + [ApiVersion("1.0")] + [RequireXPowered(true)] + [Route("api/v{version:apiVersion}/services/[controller]")] + public class FilesController : XFileServiceControllerBase, IXFileServiceControllerActions + { + // + #region Constructor ... + public FilesController( + ILogger logger, + IXFileProvider fileProvider, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider + ) : base( + logger, + fileProvider, + appConfiguration, + identityProvider, + validationProvider + ) + { } + #endregion + + // + #region Tools ... + /// + /// Stream Specified File ... + /// + /// + /// + [HttpGet("{id}/Stream/ById")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task Stream( + [FromRoute] Guid id + ) + { + return await base.Stream(id); + } + + /// + /// Stream Specified File ... + /// + /// + /// + [HttpGet("{name}/Stream/ByName")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task Stream( + [FromRoute] string name + ) + { + return await base.Stream(name); + } + + /// + /// Download Specified File ... + /// + /// + /// + [HttpGet("{id}/Download/ById")] + public override async Task Download( + [FromRoute] Guid id + ) + { + return await base.Download(id); + } + + /// + /// Download Specified File ... + /// + /// + /// + [HttpGet("{name}/Download/ByName")] + public override async Task Download( + [FromRoute] string name + ) + { + return await base.Download(name); + } + + /// + /// Upload Files ... + /// + /// + /// + [HttpPost("")] + [RequestSizeLimit(966_367_641)] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> Upload( + [FromForm] IFormFileCollection files + ) + { + return await base.Upload(files); + } + + /// + /// Remove Specified Files ... + /// + /// + /// + /// [HttpDelete("Remove")] + [HttpDelete("")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task>> Remove( + [FromQuery] string ids + ) + { + return await base.Remove(ids); + } + #endregion + + // + #region Model ... + /// + /// Get Specified File Model ... + /// + /// + /// + [HttpGet("{id}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> Get( + [FromRoute] Guid id + ) + { + return await base.Get(id); + } + + /// + /// Get All Exists File Models ... + /// + /// + [HttpGet("All")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task>> GetAll() + { + return await base.GetAll(); + } + + /// + /// retrieve Entities based on XQuery Pagination structure ... + /// + /// + /// + [HttpGet("Query")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> Query( + [FromQuery] XQuery query + ) + { + return await base.Query(query); + } + + /// + /// retrieve Owned Entities based on XQuery Pagination structure ... + /// + /// + /// + [HttpGet("Query/Owned")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> QueryOwned( + [FromQuery] XQuery query + ) + { + return await base.QueryOwned(query); + } + + /// + /// count all exists Entities ... + /// + /// + [HttpGet("Count")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> Count() + { + return await base.Count(); + } + + /// + /// Check an Entity exists or not ... + /// + /// + /// + [HttpGet("{id}/IsExists")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> IsExists( + [FromRoute] Guid id + ) + { + return await base.IsExists(id); + } + #endregion + + // + #region Tags ... + /// + /// Attach Tag to Specified Model ... + /// + /// + /// + /// + [HttpPost("{id}/Tags/Attach")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task AttachTag( + [FromRoute] Guid id, + [FromQuery] string tag + ) + { + // + return await base.AttachTag( + id: id, + tag: tag + ); + } + + /// + /// Detach Tag From Specified Model ... + /// + /// + /// + /// + [HttpDelete("{id}/Tags/Detach")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task DetachTag( + [FromRoute] Guid id, + [FromQuery] string tag + ) + { + // + return await base.DetachTag( + id: id, + tag: tag + ); + } + + /// + /// Attach Tags to Specified Model ... + /// + /// + /// + /// + [HttpPost("{id}/Tags/AttachMany")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task AttachTags( + [FromRoute] Guid id, + [FromQuery] string tags + ) + { + // + return await base.AttachTags( + id: id, + tags: tags + ); + } + + /// + /// Detach Tags From Specified Model ... + /// + /// + /// + /// + [HttpDelete("{id}/Tags/DetachMany")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task DetachTags( + [FromRoute] Guid id, + [FromQuery] string tags + ) + { + // + return await base.DetachTags( + id: id, + tags: tags + ); + } + + /// + /// Retrieve Tags of Specified File ... + /// + /// + /// + [HttpGet("{id}/Tags")] + public override async Task>> GetTags( + [FromRoute] Guid id + ) + { + // + return await base.GetTags(id); + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/V1/Services/StringsController.cs b/Controllers/V1/Services/StringsController.cs new file mode 100644 index 0000000..c6cc2d0 --- /dev/null +++ b/Controllers/V1/Services/StringsController.cs @@ -0,0 +1,468 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xCommons.Attributes; +using xCommons.Configurations; +using xCommons.Providers; +using xIdentityHelper; +using xIdentityService.Interfaces; +using xModels.Dtos; +using xStringService.Controllers; +using xStringService.Interfaces; +using xStringService.Models.Dtos; + +namespace xApi.Controllers.V1.Services +{ + [ApiController] + [ApiVersion("1.0")] + [RequireXPowered(true)] + [Route("api/v{version:apiVersion}/services/[controller]")] + public class StringsController : XStringServiceControllerBase, IXStringServiceControllerActions + { + // + #region Constructor ... + public StringsController( + ILogger logger, + IXStringProvider stringProvider, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider + ) : base( + logger, + stringProvider, + appConfiguration, + identityProvider, + validationProvider + ) + { } + #endregion + + // + #region Implementing Actions ... + // + #region Retrievers ... + /// + /// Retrieve all Exists Languages ... + /// + /// + [AllowAnonymous] + [HttpGet("Languages")] + public override async Task>> GetLanguages() + { + return await base.GetLanguages(); + } + + /// + /// Check Specified Resource Exists or not ... + /// + /// + /// + /// + [AllowAnonymous] + [HttpGet("IsResourceExists")] + public override async Task> IsResourceExists( + [FromQuery] string resource, + [FromQuery] string language = null + ) + { + // + return await base + .IsResourceExists( + resource: resource, + language: language + ); + } + + /// + /// Retrieve Specified Resource ... + /// + /// + /// + /// + [HttpGet("")] + [AllowAnonymous] + public override async Task> Get( + [FromQuery] string resource, + [FromQuery] string language = null + ) + { + // + return await base + .Get( + resource: resource, + language: language + ); + } + + /// + /// Retrieve Specified Translation of Specified Resource ... + /// + /// + /// + /// + [AllowAnonymous] + [HttpGet("ResourceValue")] + public override async Task> GetResourceValue( + [FromQuery] string resource, + [FromQuery] string language = null + ) + { + // + return await base + .GetResourceValue( + resource: resource, + language: language + ); + } + + /// + /// Retrieve an Specified Resource Items ... + /// + /// + /// + [AllowAnonymous] + [HttpGet("Resources")] + public override async Task>> GetResources( + [FromQuery] string resource + ) + { + return await base.GetResources(resource); + } + + /// + /// Retrieve Specified Resource Items as XResourceDto Presentation ... + /// + /// + /// + [AllowAnonymous] + [HttpGet("AsResource")] + public override async Task> GetResource( + [FromQuery] string resource + ) + { + return await base.GetResource(resource); + } + #endregion + + // + #region Query ... + /// + /// Query Resource IDs ... + /// + /// + /// + [AllowAnonymous] + [HttpGet("QueryResourceIds")] + public override ActionResult> QueryResourceIds( + [FromQuery] XQuery query + ) + { + return base.QueryResourceIds(query); + } + + /// + /// Query Specified Language Resources ... + /// + /// + /// + /// + [HttpGet("QueryLanguageResources")] + public override async Task>> QueryLanguageResources( + [FromQuery] XQuery query, + [FromQuery] string language = null // + ) + { + // + return await base + .QueryLanguageResources( + query: query, + language: language + ); + } + + /// + /// Query Locale Resources ... + /// + /// + /// + /// + [HttpGet("QueryLocaleResources")] + public override async Task>> QueryLocaleResources( + [FromQuery] XQuery query, + [FromQuery] string language = null // + ) + { + // + return await base + .QueryLocaleResources( + query: query, + language: language + ); + } + #endregion + + // + #region Add/Update Actions ... + /// + /// Add Specified Resource ... + /// + /// + /// + /// + /// + [HttpPost("Add")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Add( + [FromQuery] string resource, + [FromQuery] string value, + [FromQuery] string language = null + ) + { + // + return await base + .Add( + value: value, + resource: resource, + language: language + ); + } + + /// + /// Update Resource ... + /// + /// + /// + /// + /// + [HttpPut("Update")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Update( + [FromQuery] string resource, + [FromQuery] string value, + [FromQuery] string language = null + ) + { + // + return await base + .Update( + value: value, + resource: resource, + language: language + ); + } + + /// + /// Add Or Update Resource ... + /// + /// + /// + /// + /// + [HttpPost("AddOrUpdate")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> AddOrUpdate( + [FromQuery] string resource, + [FromQuery] string value, + [FromQuery] string language = null + ) + { + // + return await base + .AddOrUpdate( + value: value, + resource: resource, + language: language + ); + } + + /// + /// Add Specified Resource ... + /// + /// + /// + [HttpPost("AddModel")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> AddEntity( + [FromBody] XStringDto item + ) + { + return await base.AddEntity(item); + } + + /// + /// Update Specified Entity ... + /// + /// + /// + [HttpPut("UpdateModel")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> UpdateEntity( + [FromBody] XStringDto item + ) + { + return await base.UpdateEntity(item); + } + + /// + /// Add Or Update Specified Entitiy ... + /// + /// + /// + [HttpPost("AddOrUpdateModel")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> AddOrUpdateEntity( + [FromBody] XStringDto item + ) + { + return await base.AddOrUpdateEntity(item); + } + + /// + /// Add Specified Locale Resource ... + /// + /// + /// + /// + [HttpPost("AddLocale")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> AddByLocaleResource( + [FromBody] XLocaleResourceDto item, + [FromQuery] string resource + ) + { + // + return await base + .AddByLocaleResource( + item: item, + resource: resource + ); + } + + /// + /// Update Specified Locale Resource ... + /// + /// + /// + /// + [HttpPut("UpdateLocale")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> UpdateByLocaleResource( + [FromBody] XLocaleResourceDto item, + [FromQuery] string resource + ) + { + // + return await base + .UpdateByLocaleResource( + item: item, + resource: resource + ); + } + + /// + /// Add Or Update Resource By Locale ... + /// + /// + /// + /// + [HttpPost("AddOrUpdateLocale")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> AddOrUpdateByLocaleResource( + [FromBody] XLocaleResourceDto item, + [FromQuery] string resource + ) + { + // + return await base + .AddOrUpdateByLocaleResource( + item: item, + resource: resource + ); + } + + /// + /// Add Or Update all XResourceDto(s) Locales ... + /// + /// + /// + [HttpPost("AddResource")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task>> AddByResource( + [FromBody] XResourceDto item + ) + { + return await base.AddByResource(item); + } + #endregion + + // + #region Remove Actions ... + /// + /// Remove all Specified Language's Resources ... + /// + /// + /// + [HttpDelete("RemoveLanguage")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task RemoveLanguageResources( + [FromQuery] string language + ) + { + return await base.RemoveLanguageResources(language); + } + + /// + /// Remove all Specified Resource Ids instances ... + /// + /// + /// + [HttpDelete("RemoveLocales")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task>> RemoveResource( + [FromQuery] string resource + ) + { + return await base.RemoveResource(resource); + } + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + [HttpDelete("Remove")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Remove( + [FromQuery] string resource, + [FromQuery] string language = null + ) + { + // + return await base + .Remove( + resource: resource, + language: language + ); + } + + /// + /// Remove all Resource of Specified XResourceDto ... + /// + /// + /// + [HttpPost("RemoveResource")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task RemoveByResource( + [FromBody] XResourceDto item + ) + { + // + return await base.RemoveByResource(item); + } + #endregion + #endregion + } +} \ No newline at end of file diff --git a/Controllers/V1/Services/TagsController.cs b/Controllers/V1/Services/TagsController.cs new file mode 100644 index 0000000..6c0f7dd --- /dev/null +++ b/Controllers/V1/Services/TagsController.cs @@ -0,0 +1,207 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xCommons.Attributes; +using xCommons.Configurations; +using xCommons.Providers; +using xIdentityHelper; +using xIdentityService.Interfaces; +using xModels.Dtos; +using xTagService.Controllers; +using xTagService.Interfaces; +using xTagService.Models.Dtos; + +namespace xApi.Controllers.V1.Services +{ + [ApiController] + [ApiVersion("1.0")] + [RequireXPowered(true)] + [Route("api/v{version:apiVersion}/services/[controller]")] + public class TagsController : XTagServiceControllerBase + { + // + #region Constructor ... + public TagsController( + ILogger logger, + IXTagProvider tagProvider, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider + ) : base( + logger, + tagProvider, + appConfiguration, + identityProvider, + validationProvider + ) + { } + #endregion + + // + #region Actions ... + /// + /// Add Tag by Providing Dto ... + /// + /// + /// + [HttpPost("")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> Add( + [FromBody] XTagDto model + ) + { + return await base.Add(model); + } + + /// + /// Update Specified Tag ... + /// + /// + /// + /// + [HttpPut("{id}")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> Update( + [FromRoute] int id, + [FromBody] XTagDto model + ) + { + return await base.Update(id, model); + } + + /// + /// Remove Specified Tag by ID ... + /// + /// + /// + [HttpDelete("{id}")] + [Authorize(Policy = XPolicies.EnabledAdminOrAgent)] + public override async Task> Remove( + [FromRoute] int id + ) + { + return await base.Remove(id); + } + + /// + /// Retrieve Specified Tag Dto by ID ... + /// + /// + /// + [HttpGet("{id}")] + public override async Task> Get( + [FromRoute] int id + ) + { + return await base.Get(id); + } + + /// + /// Retrieve Specified Tag Dto by it's Label ... + /// + /// + /// + [HttpGet("GetTag")] + public override async Task> GetTag( + [FromQuery] string tag + ) + { + return await base.GetTag(tag); + } + + /// + /// Retrieve All Exists Tags ... + /// + /// + [HttpGet("All")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> GetAll() + { + return await base.GetAll(); + } + + /// + /// Search For Specified Tag by Providing a query on Label ... + /// + /// + /// + [HttpGet("FindOne")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> FindOne( + [FromQuery] string query + ) + { + return await base.FindOne(query); + } + + /// + /// Search For Specified Tags By Providing Query on Labels ... + /// + /// + /// + [HttpGet("FindMany")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> FindMany( + [FromQuery] string query + ) + { + return await base.FindMany(query); + } + + /// + /// Retrieve Tags based on Query Model ... + /// + /// + /// + [HttpGet("Query")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task>> Query( + [FromQuery] XQuery query + ) + { + return await base.Query(query); + } + + /// + /// Count Exists Tags ... + /// + /// + [HttpGet("Count")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> Count() + { + return await base.Count(); + } + + /// + /// Check Tag Exists by ID ... + /// + /// + /// + [HttpGet("{id}/IsExists")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> IsExists( + [FromRoute] int id + ) + { + return await base.IsExists(id); + } + + /// + /// Check Tag Exists by Providing Label ... + /// + /// + /// + [HttpGet("IsTagExists")] + [Authorize(Policy = XPolicies.EnabledUser)] + public override async Task> IsTagExists( + [FromQuery] string tag + ) + { + return await base.IsTagExists(tag); + } + #endregion + } +} \ No newline at end of file diff --git a/Db/.gitkeep b/Db/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Extensions/XStartupExtensions.cs b/Extensions/XStartupExtensions.cs new file mode 100644 index 0000000..6e40812 --- /dev/null +++ b/Extensions/XStartupExtensions.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.Extensions.DependencyInjection; +using xIdentityHelper; +using xCommons.Authorization; +using xCommons.Extensions; + +namespace xApi.Extensions { + public static class XStartupExtensions { + /// + /// Register Authorization Policies + /// + /// + /// + public static void AddXAuthorization ( + this IServiceCollection services, + IDictionary policies = null + ) { + // + services.AddAuthorization (options => { + // + if (!policies.IsNull ()) { + // + // Fill Policies ... + using (var policiesEnumerator = policies.GetEnumerator ()) { + while (policiesEnumerator.MoveNext ()) { + var policyDescriptor = policiesEnumerator.Current; + options.AddPolicy (policyDescriptor.Key, policyDescriptor.Value); + } + } + } + + // + var xPolicies = XAuthorizationHelper.GetXAuthorizationPolicies (); + if (!xPolicies.IsNull ()) { + // + // Fill Policies ... + using (var policiesEnumerator = xPolicies.GetEnumerator ()) { + while (policiesEnumerator.MoveNext ()) { + var policyDescriptor = policiesEnumerator.Current; + options.AddPolicy (policyDescriptor.Key, policyDescriptor.Value); + } + } + } + }); + + // + services.AddSingleton (); + } + + /// + /// Use Forward Headers Options for resolving behind a proxy issues ... + /// + /// + /// + public static void UseXForwardOptions (this IApplicationBuilder source) { + // + var forwardOptions = new ForwardedHeadersOptions { + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto, + RequireHeaderSymmetry = false + }; + + // + forwardOptions.KnownNetworks.Clear (); + forwardOptions.KnownProxies.Clear (); + + // + // ref: https://github.com/aspnet/Docs/issues/2384 + source.UseForwardedHeaders (forwardOptions); + } + } +} \ No newline at end of file diff --git a/Extensions/XUserClaimsInfoDtoExtensions.cs b/Extensions/XUserClaimsInfoDtoExtensions.cs new file mode 100644 index 0000000..e4d75d2 --- /dev/null +++ b/Extensions/XUserClaimsInfoDtoExtensions.cs @@ -0,0 +1,55 @@ +using xCommons.Extensions; +using xIdentityModels.Constants; +using xIdentityModels.Models; + +namespace xApi.Extensions { + public static class XUserClaimsInfoDtoExtensions { + public static string GetUserSelectByParam ( + this XUserClaimsInfoDto source, + XUserSelectBy userSelectBy = XUserSelectBy.Username + ) { + // + var result = ""; + + // + switch (userSelectBy) { + // + case XUserSelectBy.ID: + result = source.UserId; + break; + + // + case XUserSelectBy.Username: + result = source.UserName; + break; + + // + case XUserSelectBy.Email: + result = source.Email; + break; + + // + case XUserSelectBy.MobileNumber: + result = source.PhoneNumber; + break; + } + + // + if (result.IsNullOrEmpty ()) { + // + if (!source.UserId.IsNullOrEmpty ()) { + result = source.UserId; + } else if (!source.UserName.IsNullOrEmpty ()) { + result = source.UserName; + } else if (!source.Email.IsNullOrEmpty ()) { + result = source.Email; + } else if (!source.PhoneNumber.IsNullOrEmpty ()) { + result = source.PhoneNumber; + } + } + + // + return result; + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..63cc5ec --- /dev/null +++ b/Program.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace xApi +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} \ No newline at end of file diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json new file mode 100644 index 0000000..8749504 --- /dev/null +++ b/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:34556", + "sslPort": 44393 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "startup", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "xApiWithData": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "startup", + "applicationUrl": "https://localhost:5001;http://localhost:5000;https://0.0.0.0:5001;", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..d40a0ce --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# xSaherElmAI.xApi + +a WebAPI Project which contains all Business Logic of xSaherElm AI Project. + +## Maintainer + +Hadi Khazaee asl + +[https://www.saherelm.ir](https://www.saherelm.ir) + +[hadi_khazaee_asl@yahoo.com](mailto:hadi_khazaee_asl@yahoo.com) diff --git a/Startup.cs b/Startup.cs new file mode 100644 index 0000000..2cb2fee --- /dev/null +++ b/Startup.cs @@ -0,0 +1,276 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Reflection; +using IdentityModel.AspNetCore.OAuth2Introspection; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using xApi.Extensions; +using xCommons.Configurations; +using xCommons.Extensions; +using xDataHelper; +using xDataHelper.DbSeeder; +using xDataHelper.Helpers; +using xDataService.Configuration; +using xDataService.Constants; +using xDataService.DI; +using xDataService.Interfaces; +using xFileService.Hubs; +using xHttpService.DI; +using xIdentityService.DI; +using xPushHelper.DI; +using xPushService.DI; +using xPushService.Helpers; +using xServices.DI; +using xServices.TermsConditions.Push; +using xStringService.Hubs; +using xTagService.Hubs; + +namespace xApi +{ + public class Startup + { + public IConfiguration Configuration { get; } + + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public void ConfigureServices(IServiceCollection services) + { + // + // Register Validation Provider and all XCommons Module Services ... + services.AddXCommons(); + + // + // Register App Configuration ... + services.AddXAppConfiguration(Configuration); + var appConfiguration = services.GetRegisteredService(); + + // + // Register Allowed Origins ... + services.AddXCors(appConfiguration.AllowedOrigins); + + // + // Register Swagger ... + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + services.AddXSwagger(Configuration, xmlFilePath: xmlPath); + + // + // Register HttpService ... + services.AddXHttpService(Configuration); + + // + // Register Api Versioning ... + services.AddApiVersioning(opt => + { + // + // Set Default Api Version ... + opt.DefaultApiVersion = new ApiVersion(1, 0); + + // + // Set Routing to Default API Version, if Version unspecified ... + opt.AssumeDefaultVersionWhenUnspecified = true; + + // + // Report All Available Api Versions on Response ... + opt.ReportApiVersions = true; + }); + + // + var lifeTime = ServiceLifetime.Scoped; + + // + // OAuthIntrospectin Http Client Handler ... + // this is for handling SSLErrors ... + services.AddHttpClient(OAuth2IntrospectionDefaults.BackChannelHttpClientName) + .ConfigurePrimaryHttpMessageHandler(() => + { + return new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true + }; + }); + + // + // Register Authorizations ... + services.AddXAuthorization(); + + // + services.AddControllers() + .AddNewtonsoftJson(x => + { + x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + x.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + }); + + // + // Register XPushService ... + services.AddXPushService(Configuration); + services.AddXPushHubProvider(lifeTime); + + // + // Register XIdentityService ... + services.AddXIdentityService(Configuration, lifeTime); + + // + // Register DataService here ... + #region Register xDataService ... + // + // Register IXDataServiceHelper ... + services.AddSingleton(); + + // + // Prepare Db Options Builder based on Provider ... + var providerType = Configuration.GetXDbProviderType(); + switch (providerType) + { + // + case XDbProviders.MySQL: + case XDbProviders.SQLite: + case XDbProviders.SQLServer: + Action optionsBuilder = optionsBuilder = b => + { + b.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); + }; + + // + // Register xDataService on DI ... + services.AddXDataService( + Configuration, + lifeTime, + XDbProviderConfigurations.DEFAULT_CONNECTION_NAME, + optionsBuilder + ); + break; + + // + case XDbProviders.MongoDB: + // + // Register xDataService on DI ... + services.AddXDataService( + Configuration, + lifeTime, + XDbProviderConfigurations.DEFAULT_CONNECTION_NAME + ); + break; + } + #endregion + + // + // Register GraphQL here ... + #region Register xGraphQL ... + // + services.Configure(options => + { + options.AllowSynchronousIO = true; + }); + + // + services.Configure(options => + { + options.AllowSynchronousIO = true; + }); + + // + // Register XGraphQL Helper ... + services.AddSingleton(); + + // + services.AddXGraphQL(options => + { + // + options.EnableMetrics = true; + options.UnhandledExceptionDelegate = context => + { + Console.WriteLine("XGraphQL Error: " + context.OriginalException.Message); + }; + }); + #endregion + + // + // Register Services Module Providers here ... + #region Register xServices ... + services.AddXServices( + lifeTime: lifeTime, + configuration: Configuration + ); + #endregion + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + // + var withPlayground = false; + if (env.IsDevelopment()) + { + // + withPlayground = true; + app.UseDeveloperExceptionPage(); + } + + // + // Use Swagger Middleware ... + app.UseXSwagger(); + + // + app.UseHttpsRedirection(); + + // + // Using Cors ... + app.UseXCors(); + + // + app.UseRouting(); + + // + // Use xIdentityService ... + app.UseXIdentityService(); + + // + app.UseAuthorization(); + + // + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + + // + #region XPushService ... + // + var helper = new XPushServiceHelper(); + + // + helper.AddHub("termsHub"); + helper.AddHub("tagEntityHub"); + helper.AddHub("fileEntityHub"); + helper.AddHub("stringEntityHub"); + + // + app.UseXPushService(helper); + #endregion + + // + // Use xDataService Middleware ... + app.UseXDataService(); + + // + // Using Services ... + app.UseXServices(); + + // + // Use xGraphQL Middleware ... + app.UseXGraphQL(withPlayground: withPlayground); + } + } +} \ No newline at end of file diff --git a/appsettings.Development.json b/appsettings.Development.json new file mode 100644 index 0000000..0c039de --- /dev/null +++ b/appsettings.Development.json @@ -0,0 +1,48 @@ +{ + "AllowedOrigins": [ + "http://localhost:4200", + "https://localhost:4200", + "http://saherelm.ir", + "https://saherelm.ir", + "http://saherelmhub.ir", + "https://saherelmhub.ir", + "https://192.168.1.15:4200", + "https://192.168.1.110:4200" + ], + "IdentityServiceConfiguration": { + "Authority": "https://localhost:4001", + "ApiName": "xSaherElmAPI", + "ApiSecret": "s@H@1694056", + "ClientId": "xSaherElmAPIClient", + "ClientSecret": "s@H@1694056", + "XPoweredValue": "SaherElmITCenter", + "XRevisionSecretKey": "SaherElmITCenter@1694056", + "DefaultClientTimeout": -1 + }, + "StorageConfiguration": { + "Authority": "https://localhost:5001", + "IdentityAuthority": "https://localhost:5001", + "Storage": "Storage", + "Temp": "Temp", + "Thumb": "Thumb", + "Uploads": "Uploads", + "Widgets": "Widgets", + "Image": "Image", + "Audio": "Audio", + "Video": "Video", + "Document": "Document", + "FilePrefix": "xSaherElm_", + "ThumbPrefix": "Thumb_", + "ThumbSize": 512, + "ThumbQuality": 72, + "MaxFileSize": 41943040 + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/appsettings.json b/appsettings.json new file mode 100644 index 0000000..d87e335 --- /dev/null +++ b/appsettings.json @@ -0,0 +1,133 @@ +{ + "Version": "0.1", + "Name": "xApi", + "DefaultLanguage": "fa-IR", + "XPoweredValue": "SaherElmITCenter", + "WelcomeMessage": "Welcome to xSaherElm Project's API", + "AllowedOrigins": [ + "http://saherelm.ir", + "https://saherelm.ir" + ], + "SwaggerConfiguration": { + "Version": "v1.0", + "Title": "xSaherElm API", + "Description": "Complete API Documentation", + "Contact": { + "Name": "Hadi Khazaee Asl", + "Email": "hadi_khazaee_asl@yahoo.com", + "Url": "https://www.saherelm.ir" + } + }, + "XDbProvider": "SQLITE", + "ConnectionStrings": { + "DataConnection": "Filename=./Db/XApi.db" + }, + "MessageConfiguration": { + "MailConfigurations": { + "gmail": { + "Title": "SaherElm Dashboard", + "Host": "smtp.gmail.com", + "Port": 587, + "EnableSsl": true, + "Username": "saherelm@gmail.com", + "Password": "vzuz gtrk tndb ctbc" + } + }, + "SmsConfigurations": { + "yoursms": { + "ServiceUrl": "http://sms.yourprovider.ir", + "Username": "user", + "Password": "psw", + "LineNumber": "linenumber", + "UserApiKey": "", + "SecretKey": "" + } + } + }, + "MessageResourceTitles": { + "Terms": "terms", + "Invite": "user_invite_msg", + "RegistrationApprove": "registration_approve_msg", + "Registered": "registered_msg", + "VerificationCode": "verification_code_msg", + "ChangePassword": "change_password_msg", + "PasswordChanged": "password_changed_msg", + "NewDeviceLoggedIn": "new_device_logged_in_msg" + }, + "DataServiceConfiguration": { + "EnableTracking": true, + "EnableSoftDelete": false, + "EnableDetailedErrors": false, + "EnableSensitiveDataLogging": true, + "PagingConfiguration": { + "DefaultPageSize": 20, + "MaxAvailablePageSize": 400, + "MinAvailablePageSize": 5 + }, + "GraphQLBasePath": "/graphs" + }, + "DbSeeder": { + "UpdateExists": false, + "Strings": [], + "Terms": [ + { + "Language": "fa-IR", + "ResourceTitle": "terms", + "TranslatedValue": "توافقنامه استفاده از خدمات و شرایط و ضوابط عضویت" + }, + { + "Language": "en-US", + "ResourceTitle": "terms", + "TranslatedValue": "Terms and Conditions of Using Yuze Services" + } + ] + }, + "HttpServiceConfiguration": { + "DisableSSLCheck": true, + "DefaultClientTimeout": -1 + }, + "IdentityServiceConfiguration": { + "Authority": "https://172.18.0.151", + "ApiName": "xSaherElmAPI", + "ApiSecret": "s@H@1694056", + "ClientId": "xSaherElmAPIClient", + "ClientSecret": "s@H@1694056", + "XPoweredValue": "SaherElmITCenter", + "XRevisionSecretKey": "SaherElmITCenter@1694056", + "DefaultClientTimeout": -1 + }, + "PushServiceConfiguration": { + "BaseRoute": "hubs", + "AddSupportMessageProtocol": true + }, + "StorageConfiguration": { + "Authority": "https://api.saherelm.ir", + "IdentityAuthority": "https://ids.saherelm.ir", + "Storage": "Storage", + "Temp": "Temp", + "Thumb": "Thumb", + "Uploads": "Uploads", + "Widgets": "Widgets", + "Image": "Image", + "Audio": "Audio", + "Video": "Video", + "Document": "Document", + "FilePrefix": "xSaherElm_", + "ThumbPrefix": "Thumb_", + "ThumbSize": 512, + "ThumbQuality": 72, + "MaxFileSize": 41943040 + }, + "ServicesConfiguration": { + "SummaryEndsWdith": " ...", + "ContentSummaryMaxLength": 255 + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/nuget.config b/nuget.config new file mode 100644 index 0000000..632defe --- /dev/null +++ b/nuget.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/xApi.csproj b/xApi.csproj new file mode 100644 index 0000000..72b5139 --- /dev/null +++ b/xApi.csproj @@ -0,0 +1,52 @@ + + + + netcoreapp3.1 + xSaherElmAI.xApi + 1.0.0 + Hadi Khazaee Asl + SaherElm IT Center + + a WebAPI Project which contains all Business Logic of xSaherElm AI Project. + + + + false + false + + + + + + + + + + + + + + + + + + + + true + true + $(NoWarn);1591 + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + +