CHANGE PROJECT NAME TO "NetinaCMS"

master
Amir Hossein Khademi 2024-03-24 12:35:42 +03:30
parent 7374d47769
commit e18da688d2
201 changed files with 45522 additions and 308 deletions

View File

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>

View File

@ -1,42 +0,0 @@
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();
app.Run();
internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

View File

@ -1,56 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="AspNetCoreRateLimit.Redis" Version="2.0.0" />
<PackageReference Include="Autofac.Extras.Quartz" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.2" />
<PackageReference Include="Quartz" Version="3.8.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HamyanEdalat.Repository\HamyanEdalat.Repository.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="HamyanEdalat.Common.Extensions" />
<Using Include="HamyanEdalat.Common.Models" />
<Using Include="HamyanEdalat.Common.Models.Api" />
<Using Include="HamyanEdalat.Common.Models.Exception" />
<Using Include="HamyanEdalat.Core.Abstracts" />
<Using Include="HamyanEdalat.Core.BaseServices.Abstracts" />
<Using Include="HamyanEdalat.Core.CoreServices.Abstracts" />
<Using Include="HamyanEdalat.Core.EntityServices.Abstracts" />
<Using Include="HamyanEdalat.Domain.Dtos.RequestDtos" />
<Using Include="HamyanEdalat.Domain.Dtos.ResponseDtos" />
<Using Include="HamyanEdalat.Domain.Dtos.SmallDto" />
<Using Include="HamyanEdalat.Domain.Entities.Users" />
<Using Include="HamyanEdalat.Domain.Enums" />
<Using Include="HamyanEdalat.Domain.Mappers" />
<Using Include="HamyanEdalat.Domain.Models.Claims" />
<Using Include="HamyanEdalat.Domain.Models.Settings" />
<Using Include="HamyanEdalat.Repository.Abstracts" />
<Using Include="HamyanEdalat.Repository.Repositories.Base.Contracts" />
<Using Include="Mapster" />
<Using Include="MediatR" />
<Using Include="Microsoft.AspNetCore.Identity" />
<Using Include="Microsoft.AspNetCore.Mvc" />
<Using Include="Microsoft.EntityFrameworkCore" />
<Using Include="Microsoft.Extensions.Options" />
<Using Include="Microsoft.IdentityModel.Tokens" />
<Using Include="Newtonsoft.Json" />
<Using Include="System.IdentityModel.Tokens.Jwt" />
<Using Include="System.Security.Claims" />
</ItemGroup>
</Project>

View File

@ -1,6 +0,0 @@
using HamyanEdalat.Domain.Dtos.ResponseDtos;
namespace HamyanEdalat.Domain.CommandQueries.Queries;
public record GetBlogsQuery(int Page = 0) : IRequest<GetBlogsResponseDto>;
public record GetBlogQuery(Guid Id) : IRequest<BlogLDto>;

View File

@ -1,7 +0,0 @@
namespace HamyanEdalat.Repository
{
public class RepositoryConfig
{
}
}

View File

@ -0,0 +1,68 @@
{
"ConnectionStrings": {
"PostgresServer": "User ID=postgres;Password=root;Host=localhost;Port=5432;Database=HamyanEdalatDB;",
"Postgres": "Host=pg-0;Username=vesmmehAgent;Password=g05CTjK358Vx3Eoc9satsWyVwo+15UmsA2dnCrZRUYh1pLTe;Database=NetinaShopDB;Application Name=NetinaShopApi",
"MartenDB": "Host=pg-0;Username=vesmmehAgent;Password=g05CTjK358Vx3Eoc9satsWyVwo+15UmsA2dnCrZRUYh1pLTe;Database=NetinaShopMartenDB;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "None",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug",
"Microsoft.AspNetCore.Http.Connections": "Debug"
}
},
"SiteSettings": {
"BaseUrl": "https://api.hamyanedalat.com",
"AdminPanelBaseUrl": "https://admin.hamyanedalat.com",
"KaveNegarApiKey": "3735494B4143727A794346457461576A2B4B6668414973424E333561505A694B",
"RootUser": {
"Username": "09214802813",
"Email": "avvampier@gmail.com",
"Password": "KqBGMExTe42yHUiz",
"Phone": "09214802813",
"RoleName": "RootAdmin",
"FirstName": "همه کاره",
"LastName": "سیستم"
},
"ManagerUser": {
"Username": "hamyanedalat",
"Email": "info@hivakil.io",
"Password": "GPDBxpk28yKo0L3v",
"Phone": "09211111111",
"RoleName": "Manager",
"FirstName": "ادمین",
"LastName": "سایت"
},
"JwtSettings": {
"SecretKey": "YA_KHOD_KHODA_fmGg7e7T5uXQMhbm99e2MF2VudmBn0KCdo+HAblHkhC9P0ldpii1Tj+0nOVep9zh_YA_EMAM_HOSSEIN_tfbiY7CdhODnAc01GG138g==_YA_JADE_SEYED_MAJID_tfbiY7CdhODnAc01GG138g==_YA_ALI_MADADI",
"Issuer": "HamyanEdalat",
"Audience": "HamyanEdalat",
"ExpireAddDay": "15"
}
},
"IpRateLimiting": {
"EnableEndpointRateLimiting": false,
"StackBlockedRequests": false,
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ],
"EndpointWhitelist": [ "get:/api/license", "*:/api/status" ],
"ClientWhitelist": [ "dev-id-1", "dev-id-2" ],
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1m",
"Limit": 60
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 250
}
]
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,72 @@
{
"ConnectionStrings": {
"PostgresServer": "User ID=postgres;Password=root;Host=localhost;Port=5432;Database=HamyanEdalatDB;",
"Postgres": "Host=pg-0,pg-1;Username=igarsonAgent;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=HamyanEdalatDB;Load Balance Hosts=true;Target Session Attributes=primary;Application Name=iGLS",
"MartenDB": "Host=pg-0,pg-1;Username=igarsonAgent;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=HamyanEdalatMartenDB;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "None",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug",
"Microsoft.AspNetCore.Http.Connections": "Debug"
}
},
"SiteSettings": {
"BaseUrl": "http://localhost:32768",
"AdminPanelBaseUrl": "https://admin.hamyanedalat.com",
"KaveNegarApiKey": "3735494B4143727A794346457461576A2B4B6668414973424E333561505A694B",
"StorageSetting": {
"AccessKey": "",
"SecretKey": ""
},
"RootUser": {
"Username": "09214802813",
"Email": "avvampier@gmail.com",
"Password": "KqBGMExTe42yHUiz",
"Phone": "09214802813",
"RoleName": "RootAdmin",
"FirstName": "همه کاره",
"LastName": "سیستم"
},
"ManagerUser": {
"Username": "hamyanedalat",
"Email": "info@hivakil.io",
"Password": "GPDBxpk28yKo0L3v",
"Phone": "09211111111",
"RoleName": "Manager",
"FirstName": "ادمین",
"LastName": "سایت"
},
"JwtSettings": {
"SecretKey": "YA_KHOD_KHODA_fmGg7e7T5uXQMhbm99e2MF2VudmBn0KCdo+HAblHkhC9P0ldpii1Tj+0nOVep9zh_YA_EMAM_HOSSEIN_tfbiY7CdhODnAc01GG138g==_YA_JADE_SEYED_MAJID_tfbiY7CdhODnAc01GG138g==_YA_ALI_MADADI",
"Issuer": "HamyanEdalat",
"Audience": "HamyanEdalat",
"ExpireAddDay": "15"
}
},
"IpRateLimiting": {
"EnableEndpointRateLimiting": false,
"StackBlockedRequests": false,
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ],
"EndpointWhitelist": [ "get:/api/license", "*:/api/status" ],
"ClientWhitelist": [ "dev-id-1", "dev-id-2" ],
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1m",
"Limit": 60
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 250
}
]
},
"AllowedHosts": "*"
}

View File

@ -4,5 +4,6 @@
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,64 @@
namespace NetinaCMS.Api.Controllers;
public class AuthController : ICarterModule
{
public virtual void AddRoutes(IEndpointRouteBuilder app)
{
var group = app.NewVersionedApi("Auth")
.MapGroup($"api/auth");
group.MapPost("login/password", LoginWithPassword)
.WithDisplayName("LoginWithPassword")
.HasApiVersion(1.0);
group.MapPost("login/swagger", LoginSwagger)
.WithDisplayName("LoginSwagger")
.HasApiVersion(1.0);
group.MapPost("login/code", LoginWithVerifyCode)
.WithDisplayName("LoginWithVerifyCode")
.HasApiVersion(1.0);
group.MapGet("verifycode", GetVerifyCodeCode)
.WithDisplayName("GetVerifyCodeCode")
.HasApiVersion(1.0);
group.MapPut("forget/password", ForgetPassword)
.WithDisplayName("ForgetPassword")
.HasApiVersion(1.0);
group.MapPost("signup", SignUpComplex)
.WithDisplayName("SignUp")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser())
.HasApiVersion(1.0);
}
public async Task<IResult> SignUpComplex([FromBody] SignUpRequestDto request, IAccountService accountService, CancellationToken cancellationToken) =>
TypedResults.Ok(await accountService.CompleteSignUpAsync(request, cancellationToken));
public async Task<IResult> LoginWithPassword([FromBody] LoginRequestDto loginRequestDto, IAccountService accountService, CancellationToken cancellationToken) =>
TypedResults.Ok(await accountService.LoginWithPasswordAsync(loginRequestDto.UserName, loginRequestDto.Password, cancellationToken));
public async Task<IResult> LoginWithVerifyCode([FromBody] LoginRequestDto loginRequestDto, IAccountService accountService, CancellationToken cancellationToken) =>
TypedResults.Ok(await accountService.LoginWithVerifyCodeAsync(loginRequestDto.UserName, loginRequestDto.VerifyCode, cancellationToken));
public async Task<IResult> GetVerifyCodeCode([FromQuery] string phoneNumber, IAccountService accountService) =>
TypedResults.Ok(await accountService.GetVerifyCodeAsync(phoneNumber));
public async Task<IResult> ForgetPassword([FromQuery] string phoneNumber, IAccountService accountService) =>
TypedResults.Ok(await accountService.ForgetPasswordAsync(phoneNumber));
public async Task<IResult> LoginSwagger(HttpContext ctx, IAccountService accountService, CancellationToken cancellationToken)
{
var username = ctx.Request.Form["username"];
var password = ctx.Request.Form["password"];
return TypedResults.Json(await accountService.LoginWithPasswordAsync(username, password, cancellationToken));
}
}

View File

@ -0,0 +1,14 @@
using NetinaCMS.Api.Views.Home;
namespace NetinaCMS.Api.Controllers;
[Route("")]
[AllowAnonymous]
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
return View("Index", new IndexModel());
}
}

View File

@ -0,0 +1,121 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<AssemblyVersion>0.0.0.1</AssemblyVersion>
<FileVersion>0.0.0.1</FileVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
<PackageReference Include="Asp.Versioning.Http" Version="8.0.0" />
<PackageReference Include="Ben.BlockingDetector" Version="0.0.4" />
<PackageReference Include="Carter" Version="8.0.0" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.0" />
<PackageReference Include="MediatR.Extensions.Autofac.DependencyInjection" Version="12.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Autofac" Version="8.0.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
<PackageReference Include="Elmah.Io.AspNetCore.Serilog" Version="5.0.17" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Sentry.Serilog" Version="4.0.1" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.PostgreSQL" Version="2.3.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.ElmahIo" Version="5.0.38" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="10.2.0" />
<PackageReference Include="StackExchange.Redis.Extensions.Core" Version="10.2.0" />
<PackageReference Include="StackExchange.Redis.Extensions.Newtonsoft" Version="10.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
<PackageReference Include="System.Drawing.Common" Version="8.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NetinaCMS.Infrastructure\NetinaCMS.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Asp.Versioning" />
<Using Include="AspNetCoreRateLimit" />
<Using Include="AspNetCoreRateLimit.Redis" />
<Using Include="Autofac" />
<Using Include="Autofac.Extensions.DependencyInjection" />
<Using Include="Carter" />
<Using Include="FluentValidation" />
<Using Include="NetinaCMS.Api.Views.Home" />
<Using Include="NetinaCMS.Api.WebFramework.Configurations" />
<Using Include="NetinaCMS.Api.WebFramework.MiddleWares" />
<Using Include="NetinaCMS.Api.WebFramework.Swagger" />
<Using Include="NetinaCMS.Common.Extensions" />
<Using Include="NetinaCMS.Common.Models" />
<Using Include="NetinaCMS.Common.Models.Api" />
<Using Include="NetinaCMS.Common.Models.Entity" />
<Using Include="NetinaCMS.Common.Models.Exception" />
<Using Include="NetinaCMS.Common.Models.Mapper" />
<Using Include="NetinaCMS.Core" />
<Using Include="NetinaCMS.Core.CoreServices.Abstracts" />
<Using Include="NetinaCMS.Core.Models.Api" />
<Using Include="NetinaCMS.Domain" />
<Using Include="NetinaCMS.Domain.Dtos.RequestDtos" />
<Using Include="NetinaCMS.Domain.Entities.Users" />
<Using Include="NetinaCMS.Domain.Models.Settings" />
<Using Include="NetinaCMS.Infrastructure" />
<Using Include="NetinaCMS.Infrastructure.Models" />
<Using Include="NetinaCMS.Repository" />
<Using Include="NetinaCMS.Repository.Abstracts" />
<Using Include="NetinaCMS.Repository.Behaviors" />
<Using Include="NetinaCMS.Repository.Extensions" />
<Using Include="NetinaCMS.Repository.Models" />
<Using Include="NetinaCMS.Repository.Repositories.Base.Contracts" />
<Using Include="Mapster" />
<Using Include="MediatR" />
<Using Include="MediatR.Extensions.Autofac.DependencyInjection" />
<Using Include="MediatR.Extensions.Autofac.DependencyInjection.Builder" />
<Using Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<Using Include="Microsoft.AspNetCore.Authorization" />
<Using Include="Microsoft.AspNetCore.Identity" />
<Using Include="Microsoft.AspNetCore.Mvc" />
<Using Include="Microsoft.AspNetCore.Mvc.Authorization" />
<Using Include="Microsoft.AspNetCore.ResponseCompression" />
<Using Include="Microsoft.EntityFrameworkCore" />
<Using Include="Microsoft.IdentityModel.Tokens" />
<Using Include="Newtonsoft.Json" />
<Using Include="Newtonsoft.Json.Serialization" />
<Using Include="Serilog" />
<Using Include="StackExchange.Redis.Extensions.Core.Configuration" />
<Using Include="StackExchange.Redis.Extensions.Newtonsoft" />
<Using Include="System.IdentityModel.Tokens.Jwt" />
<Using Include="System.IO.Compression" />
<Using Include="System.Linq.Expressions" />
<Using Include="System.Net" />
<Using Include="System.Text" />
<Using Include="Weasel.Core" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,116 @@
using NetinaCMS.Api.WebFramework.Configurations;
using NetinaCMS.Api.WebFramework.MiddleWares;
using NetinaCMS.Api.WebFramework.Swagger;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.UseSerilog();
LoggerConfig.ConfigureSerilog();
string env = builder.Environment.IsDevelopment() == true ? "Development" : "Production";
builder.Host.UseContentRoot(Directory.GetCurrentDirectory());
if (builder.Environment.IsDevelopment())
builder.Configuration
.AddJsonFile($"AppSettings/appsettings.json")
.AddJsonFile($"AppSettings/appsettings.{env}.json");
if (builder.Environment.IsProduction())
builder.Configuration.AddJsonFile($"AppSettings/Production/appsettings.{env}.json");
var configuration = builder.Configuration;
var siteSetting = configuration.GetSection(nameof(SiteSettings)).Get<SiteSettings>();
builder.Services.Configure<SiteSettings>(configuration.GetSection(nameof(SiteSettings)));
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddCustomCores();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddCustomSwagger(siteSetting!.BaseUrl);
builder.Services.AddCustomApiVersioning();
builder.Services.AddCustomController();
builder.Services.AddControllers();
builder.Services.AddCustomResponseCompression();
builder.Services.AddValidatorsFromAssembly(typeof(RepositoryConfig).Assembly, includeInternalTypes: true);
builder.Services.AddCustomMvc();
builder.Services.AddCustomAuthorization();
builder.Services.AddJwtCustomAuthentication(siteSetting.JwtSettings);
builder.Services.AddMvcCore().AddRazorPages().AddRazorViewEngine().AddViews();
builder.Services.AddCustomIdentity();
builder.Services.AddCustomDbContext(configuration);
builder.Services.AddMarten(configuration, builder.Environment);
builder.Services.AddCarter();
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
var assembly = typeof(CoreConfig).Assembly;
builder
.RegisterAssemblyTypes(assembly)
.AssignableTo<IScopedDependency>()
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
var assemblyB = typeof(InfrastructureConfig).Assembly;
builder.RegisterAssemblyTypes(assemblyB)
.AssignableTo<IScopedDependency>()
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
var assemblyC = typeof(RepositoryConfig).Assembly;
builder.RegisterAssemblyTypes(assemblyC)
.AssignableTo<IScopedDependency>()
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
var assemblyD = typeof(Program).Assembly;
builder.RegisterAssemblyTypes(assemblyD)
.AssignableTo<IScopedDependency>()
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterMediatR(MediatRConfigurationBuilder
.Create(typeof(RepositoryConfig).Assembly)
.WithCustomPipelineBehavior(typeof(ValidationBehavior<,>))
.WithAllOpenGenericHandlerTypesRegistered()
.Build());
builder.RegisterMediatR(MediatRConfigurationBuilder
.Create(typeof(CoreConfig).Assembly)
.WithCustomPipelineBehavior(typeof(ValidationBehavior<,>))
.WithAllOpenGenericHandlerTypesRegistered()
.Build());
builder.RegisterMediatR(MediatRConfigurationBuilder
.Create(typeof(DomainConfig).Assembly)
.WithCustomPipelineBehavior(typeof(ValidationBehavior<,>))
.WithAllOpenGenericHandlerTypesRegistered()
.Build());
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
//app.UseSwagger();
//app.UseSwaggerUI();
}
app.UseCors("CorsPolicy");
app.UseCustomSwagger(siteSetting.BaseUrl);
app.UseAuthorization();
app.UseAuthentication();
app.UseExceptionHandlerMiddleware();
app.MapCarter();
app.UseStaticFiles();
await app.InitialDb();
app.MapControllers();
app.Run();

View File

@ -23,9 +23,10 @@
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTP_PORTS": "8080"
"ASPNETCORE_URLS": "http://+:80"
},
"publishAllPorts": true
"publishAllPorts": true,
"DockerfileRunArguments": " --network=mother -p 32768:80"
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",

View File

@ -0,0 +1,50 @@
using System.Security.Claims;
using System.Security.Cryptography;
namespace NetinaCMS.Api.Services;
public class CurrentUserService : ICurrentUserService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string? UserId => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
public string? RoleName => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Role);
public string? UserName => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name);
public string? DeviceId => GetDeviceId(_httpContextAccessor.HttpContext);
public bool IsAuthorized => GetAuthorized();
public List<string>? Permissions => _httpContextAccessor.HttpContext?.User?.FindAll("Permission")?.Select(c => c.Value)?.ToList();
private string? GetDeviceId(HttpContext? context)
{
if (context?.Request?.Headers == null)
return null;
string? userAgent = context.Request.Headers["User-Agent"];
string? ipAddress = context.Connection.RemoteIpAddress?.ToString();
string? origin = context.Request.Headers["Origin"];
string input = userAgent + "_" + ipAddress;
using SHA256 sha256Hash = SHA256.Create();
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
var uniqueId = builder.ToString();
return uniqueId;
}
private bool GetAuthorized()
{
if (_httpContextAccessor.HttpContext?.User.Identity == null)
return false;
return _httpContextAccessor.HttpContext.User.Identity.IsAuthenticated;
}
}

View File

@ -0,0 +1,274 @@
@model NetinaCMS.Api.Views.Home.IndexModel
@{
}
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>HiVakil API</title>
<meta content="" name="description">
<meta content="" name="keywords">
<!-- Favicons -->
<link href="assets/img/favicon.png" rel="icon">
<link href="assets/img/apple-touch-icon.png" rel="apple-touch-icon">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Jost:300,300i,400,400i,500,500i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
<link rel="preconnect" href="//fdn.fontcdn.ir">
<link rel="preconnect" href="//v1.fontapi.ir">
<link href="https://v1.fontapi.ir/css/Shabnam" rel="stylesheet">
<!-- Vendor CSS Files -->
<link href="assets/vendor/boxicons/css/boxicons.min.css" rel="stylesheet">
<link href="assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Template Main CSS File -->
<link href="assets/css/style.css" rel="stylesheet">
</head>
<body>
<!-- ======= Header ======= -->
<header id="header" class="fixed-top ">
<div class="container d-flex align-items-center">
<h1 class="logo me-auto"><a href="index.html">HiVakil API</a></h1>
<!-- Uncomment below if you prefer to use an image logo -->
<!-- <a href="index.html" class="logo me-auto"><img src="assets/img/logo.png" alt="" class="img-fluid"></a>-->
<nav id="navbar" class="navbar">
<ul>
<li><a class="nav-link scrollto active" href="#hero">Home</a></li>
<li><a class="nav-link scrollto" href="#why-us">Features</a></li>
<li><a class="nav-link scrollto" href="#skills">Framworks</a></li>
<li><a class="getstarted scrollto" target="_blank" href="/swagger/index.html">Go To Swagger</a></li>
</ul>
<i class="bi bi-list mobile-nav-toggle"></i>
</nav><!-- .navbar -->
</div>
</header><!-- End Header -->
<!-- ======= Hero Section ======= -->
<section id="hero" dir="ltr" class="d-flex min-vh-100 flex-column justify-content-center">
<div class="container">
<div class="row">
<div class="col-lg-6 d-flex flex-column justify-content-center pt-4 pt-lg-0 order-2 order-lg-1" data-aos="fade-up" data-aos-delay="200">
<h1>New API for use </h1>
<h2 style="font-family: SF Pro Display, sans-serif; text-align: justify ;">
This API is organized around REST. Our API has predictable resource-oriented URLs, accepts form-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.
</h2>
<h2 style="font-family: SF Pro Display, sans-serif; text-align: justify ;">
Version : @Model?.Version
</h2>
<div class="d-flex justify-content-center justify-content-lg-start">
<a href="/swagger/index.html" target="_blank" class="btn-get-started scrollto"><i class="bi bi-chevron-right" style="font-family: SF Pro Display, sans-serif; margin-right:10px ;"></i><span>Go to Swagger</span></a>
</div>
</div>
<div class="col-lg-6 order-1 order-lg-2 hero-img" data-aos="zoom-in" data-aos-delay="200">
<img src="assets/img/hero-img.png" class="img-fluid animated" alt="">
</div>
</div>
</div>
</section><!-- End Hero -->
<main id="main">
<!-- ======= Why Us Section ======= -->
<section id="why-us" class="why-us section-bg d-flex min-vh-100 flex-column justify-content-center">
<div class="container-fluid" data-aos="fade-up">
<div class="row">
<div class="col-lg-7 d-flex flex-column justify-content-center align-items-stretch order-2 order-lg-1">
<div class="content">
<h3>Features of using this API</h3>
<p>
We have brought you lots of different features in this API for you
</p>
</div>
<div class="accordion-list">
<ul>
<li>
<a data-bs-toggle="collapse" class="collapse" data-bs-target="#accordion-list-1"><span>01</span> Use JSON <i class="bx bx-chevron-down icon-show"></i><i class="bx bx-chevron-up icon-close"></i></a>
<div id="accordion-list-1" class="collapse show" data-bs-parent=".accordion-list">
<p>
All responses and data convert to JSON , and you get json compresed response in all request
</p>
</div>
</li>
<li>
<a data-bs-toggle="collapse" data-bs-target="#accordion-list-2" class="collapsed"><span>02</span> User Authentication <i class="bx bx-chevron-down icon-show"></i><i class="bx bx-chevron-up icon-close"></i></a>
<div id="accordion-list-2" class="collapse" data-bs-parent=".accordion-list">
<p>
The authentication of API is based on USERNAME & PASSWORD , in this case you user your test user for testing API and methods
</p>
</div>
</li>
<li>
<a data-bs-toggle="collapse" data-bs-target="#accordion-list-3" class="collapsed"><span>03</span> Api Versionening <i class="bx bx-chevron-down icon-show"></i><i class="bx bx-chevron-up icon-close"></i></a>
<div id="accordion-list-3" class="collapse" data-bs-parent=".accordion-list">
<p>
We create several version of APIs and update it , so you can use all version of APIs , old one and new one . you have to be care about use versions
</p>
</div>
</li>
</ul>
</div>
</div>
<div class="col-lg-5 align-items-stretch order-1 order-lg-2 img" style='background-image: url("assets/img/features.svg");' data-aos="zoom-in" data-aos-delay="150">&nbsp;</div>
</div>
</div>
</section><!-- End Why Us Section -->
<!-- ======= Cta Section ======= -->
<section id="cta" class="cta ">
<div class="container" data-aos="zoom-in">
<div class="row">
<div class="col-lg-9 text-center text-lg-start">
<h3>SWAGGER</h3>
<p>Swagger is one of the best API document generator , You can use swagger to read API document and test API , for using swagger you need to login and use you username and password</p>
</div>
<div class="col-lg-3 cta-btn-container text-center">
<a class="cta-btn align-middle" target="_blank" href="/swagger/index.html">Go to swagger</a>
</div>
</div>
</div>
</section><!-- End Cta Section -->
<!-- ======= Skills Section ======= -->
<section id="skills" class="skills d-flex min-vh-100 flex-column justify-content-center">
<div class="container" data-aos="fade-up">
<div class="row">
<div class="col-lg-6 d-flex align-items-center" data-aos="fade-right" data-aos-delay="100">
<img src="assets/img/skills.png" class="img-fluid" alt="">
</div>
<div class="col-lg-6 pt-4 pt-lg-0 content" data-aos="fade-left" data-aos-delay="100">
<h3>Framworks that we used in this project</h3>
<p class="fst-italic">
We use several frameworks to develope our projects , is this project we use hight teck and most popular frameworks and programming languages
</p>
<div class="skills-content">
<div class="progress">
<span class="skill">.NET <i class="val">100%</i></span>
<div class="progress-bar-wrap">
<div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="progress">
<span class="skill">MicroServices <i class="val">100%</i></span>
<div class="progress-bar-wrap">
<div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="progress">
<span class="skill">Netina-Architecture <i class="val">100%</i></span>
<div class="progress-bar-wrap">
<div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="progress">
<span class="skill">DDD <i class="val">90%</i></span>
<div class="progress-bar-wrap">
<div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="progress">
<span class="skill">MediatR <i class="val">90%</i></span>
<div class="progress-bar-wrap">
<div class="progress-bar" role="progressbar" aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="progress">
<span class="skill">Redis <i class="val">90%</i></span>
<div class="progress-bar-wrap">
<div class="progress-bar" role="progressbar" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</section><!-- End Skills Section -->
</main><!-- End #main -->
<!-- ======= Footer ======= -->
<footer id="footer">
<div class="footer-top">
<div class="container">
<div class="row">
<div class="col-lg-9 content align-items-center justify-content-center">
<h1 class="display-1">HiVakil API</h1>
</div>
<div class="col-lg-3 col-md-6 footer-links">
<h4>Our Social Networks</h4>
<p>Cras fermentum odio eu feugiat lide par naso tierra videa magna derita valies</p>
<div class="social-links mt-3">
<a href="#" class="twitter"><i class="bx bxl-twitter"></i></a>
<a href="#" class="facebook"><i class="bx bxl-facebook"></i></a>
<a href="#" class="instagram"><i class="bx bxl-instagram"></i></a>
<a href="#" class="google-plus"><i class="bx bxl-skype"></i></a>
<a href="#" class="linkedin"><i class="bx bxl-linkedin"></i></a>
</div>
</div>
</div>
</div>
</div>
<div class="container footer-bottom clearfix">
<div class="copyright">
&copy; Copyright <strong><span>HiVakil</span></strong>. All Rights Reserved
</div>
<div class="credits">
<!-- All the links in the footer should remain intact. -->
<!-- You can delete the links only if you purchased the pro version. -->
<!-- Licensing information: https://bootstrapmade.com/license/ -->
<!-- Purchase the pro version with working PHP/AJAX contact form: https://bootstrapmade.com/arsha-free-bootstrap-html-template-corporate/ -->
Designed by <a href="https://mr-mohande3.ir/" style="color:white;">Amir Hossein Khademi (MR.MOHANDE3)</a>
</div>
</div>
</footer><!-- End Footer -->
<div id="preloader"></div>
<a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i class="bi bi-arrow-up-short"></i></a>
<!-- Vendor JS Files -->
<script src="assets/vendor/aos/aos.js"></script>
<script src="assets/vendor/glightbox/js/glightbox.min.js"></script>
<script src="assets/vendor/waypoints/noframework.waypoints.js"></script>
<script src="assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Template Main JS File -->
<script src="assets/js/main.js"></script>
</body>
</html>

View File

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace NetinaCMS.Api.Views.Home
{
public class IndexModel : PageModel
{
public string Version = typeof(Program).Assembly.GetName().Version.ToString();
public void OnGet()
{
}
}
}

View File

@ -0,0 +1,76 @@
using Microsoft.AspNetCore.Mvc.Filters;
namespace NetinaCMS.Api.WebFramework.Bases;
public class ApiResultFactory
{
}
public class ApiResultFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
if (context.Result is OkObjectResult okObjectResult)
{
var apiResult = new ApiResult<object>(true, ApiResultStatusCode.Success, okObjectResult.Value);
context.Result = new JsonResult(apiResult) { StatusCode = okObjectResult.StatusCode };
}
else if (context.Result is OkResult okResult)
{
var apiResult = new ApiResult(true, ApiResultStatusCode.Success);
context.Result = new JsonResult(apiResult) { StatusCode = okResult.StatusCode };
}
else if (context.Result is BadRequestResult badRequestResult)
{
var apiResult = new ApiResult(false, ApiResultStatusCode.BadRequest);
context.Result = new JsonResult(apiResult) { StatusCode = badRequestResult.StatusCode };
}
else if (context.Result is BadRequestObjectResult badRequestObjectResult)
{
var message = badRequestObjectResult.Value.ToString();
if (badRequestObjectResult.Value is SerializableError errors)
{
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
message = string.Join(" | ", errorMessages);
}
if (badRequestObjectResult.Value is ValidationProblemDetails problemDetails)
{
var errorMessages = problemDetails.Errors.Values.SelectMany(v => v);
message = string.Join(" | ", errorMessages);
}
var apiResult = new ApiResult(false, ApiResultStatusCode.BadRequest, message);
context.Result = new JsonResult(apiResult) { StatusCode = badRequestObjectResult.StatusCode };
}
else if (context.Result is ContentResult contentResult)
{
var apiResult = new ApiResult(true, ApiResultStatusCode.Success, contentResult.Content);
context.Result = new JsonResult(apiResult) { StatusCode = contentResult.StatusCode };
}
else if (context.Result is NotFoundResult notFoundResult)
{
var apiResult = new ApiResult(false, ApiResultStatusCode.NotFound);
context.Result = new JsonResult(apiResult) { StatusCode = notFoundResult.StatusCode };
}
else if (context.Result is NotFoundObjectResult notFoundObjectResult)
{
var apiResult = new ApiResult<object>(false, ApiResultStatusCode.NotFound, notFoundObjectResult.Value);
context.Result = new JsonResult(apiResult) { StatusCode = notFoundObjectResult.StatusCode };
}
else if (context.Result is ObjectResult objectResult && objectResult.StatusCode == null
&& !(objectResult.Value is ApiResult))
{
var apiResult = new ApiResult<object>(true, ApiResultStatusCode.Success, objectResult.Value);
context.Result = new JsonResult(apiResult) { StatusCode = objectResult.StatusCode };
}
else if (context.Result is ObjectResult objectResultBad && objectResultBad.Value is ApiResult)
{
var apiResult = objectResultBad.Value as ApiResult;
context.Result = new JsonResult(apiResult) { StatusCode = objectResultBad.StatusCode };
}
base.OnResultExecuting(context);
}
}

View File

@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc.Filters;
namespace NetinaCMS.Api.WebFramework.Bases;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class ClaimRequirement : AuthorizeAttribute, IAuthorizationFilter
{
private readonly string _claimsType;
private readonly string _claimsValue;
public ClaimRequirement(string type,string value)
{
type = value;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
var permissions = user.Claims?.Where(c => c.Type == _claimsType)?.ToList();
if (permissions == null)
{
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
}
else
{
bool isAccepted = false;
if (permissions.FirstOrDefault(p => p.Value == _claimsValue) != null)
isAccepted = true;
if (!isAccepted)
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
}
}
}

View File

@ -0,0 +1,218 @@
namespace NetinaCMS.Api.WebFramework.Bases;
public class CrudEndpoint<TEntity,TGetAllQuery,TGetOneQuery,TCreateCommand,TUpdateCommand,TDeleteCommand> where TEntity : ApiEntity, new()
{
private readonly string _endpointName;
public CrudEndpoint(string endpointName)
{
_endpointName = endpointName;
}
public virtual void AddRoutes(IEndpointRouteBuilder app)
{
var group = app.NewVersionedApi(_endpointName).MapGroup($"api/{_endpointName}");
group.MapGet("", GetAllAsync)
.WithDisplayName("GetAll")
.HasApiVersion(1.0);
group.MapGet("{id}", GetAsync)
.WithName("GetOne")
.HasApiVersion(1.0);
group.MapPost("", Post)
.HasApiVersion(1.0);
group.MapPut("", Put)
.HasApiVersion(1.0);
group.MapDelete("", Delete)
.HasApiVersion(1.0);
}
// GET:Get All Entity
public virtual async Task<IResult> GetAllAsync(ISender sender , CancellationToken cancellationToken)
{
var res = sender.Send(Activator.CreateInstance<TGetAllQuery>(),cancellationToken);
return TypedResults.Ok(res);
}
// GET:Get An Entity By Id
public async Task<IResult> GetAsync(Guid id, ISender sender, CancellationToken cancellationToken)
=> TypedResults.Ok(sender.Send(Activator.CreateInstance<TGetOneQuery>()));
// POST:Create Entity
public virtual async Task<IResult> Post([FromBody] TCreateCommand ent , ISender mediator , CancellationToken cancellationToken)
{
return TypedResults.Ok(await mediator.Send(ent, cancellationToken));
}
// PUT:Update Entity
public virtual async Task<IResult> Put([FromBody] TEntity ent , IRepositoryWrapper _repositoryWrapper, CancellationToken cancellationToken)
{
_repositoryWrapper.SetRepository<TEntity>().Update(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return TypedResults.Ok();
}
// DELETE:Delete Entity
public virtual async Task<IResult> Delete(Guid id,IRepositoryWrapper _repositoryWrapper, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<TEntity>().GetByIdAsync(cancellationToken, id);
_repositoryWrapper.SetRepository<TEntity>().Delete(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return TypedResults.Ok();
}
}
[ApiController]
//[AllowAnonymous]
[ApiResultFilter]
[Route("api/v{version:apiVersion}/[controller]")] // api/v1/[controller]
public class BaseController : ControllerBase
{
//public UserRepository UserRepository { get; set; } => property injection
public bool UserIsAutheticated => HttpContext.User.Identity.IsAuthenticated;
}
[Authorize(AuthenticationSchemes = "Bearer")]
public class CrudController<TDto, TEntity> : BaseController
where TDto : BaseDto<TDto, TEntity>, new()
where TEntity : ApiEntity, new()
{
protected readonly IRepositoryWrapper _repositoryWrapper;
public CrudController(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
// GET:Get All Entity
[HttpGet]
public virtual async Task<IActionResult> GetAllAsync(CancellationToken cancellationToken)
{
var projectTo = typeof(TDto).BaseType?.GetProperty("ProjectToDto")?.GetValue(null, null);
if (projectTo != null)
{
var exprss = projectTo as Expression<Func<TEntity, TDto>>;
var entites = await _repositoryWrapper
.SetRepository<TEntity>()
.TableNoTracking
.Select(exprss)
.ToListAsync(cancellationToken);
return Ok(entites);
}
throw new BaseApiException("ProjectTo Not Found");
}
// GET:Get An Entity By Id
[HttpGet("{id}")]
public virtual async Task<IActionResult> GetAsync(string id, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<TEntity>().GetByIdAsync(cancellationToken, id);
var dto = ent.Adapt<TDto>();
return Ok(dto);
}
// POST:Add New Entity
[HttpPost]
public virtual async Task<IActionResult> PostOrginal([FromBody] TEntity ent, CancellationToken cancellationToken)
{
_repositoryWrapper.SetRepository<TEntity>().Add(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return Ok(ent);
}
// POST:Add New Entity By Dto
[HttpPost("Dto")]
public async Task<IActionResult> PostDto([FromBody] TDto dto, CancellationToken cancellationToken)
{
_repositoryWrapper
.SetRepository<TEntity>()
.Add(dto.ToEntity());
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return Ok();
}
// PUT:Update Entity
[HttpPut]
public virtual async Task<IActionResult> Put([FromBody] TEntity ent, CancellationToken cancellationToken)
{
_repositoryWrapper
.SetRepository<TEntity>()
.Update(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return Ok();
}
// DELETE:Delete Entity
[HttpDelete]
[Route("{id:int}")]
public virtual async Task<IActionResult> Delete(int id, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper
.SetRepository<TEntity>()
.GetByIdAsync(cancellationToken, id);
_repositoryWrapper.SetRepository<TEntity>().Delete(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return Ok();
}
}
[Authorize(AuthenticationSchemes = "Bearer")]
public class CrudController<TEntity> : BaseController
where TEntity : ApiEntity, new()
{
protected readonly IRepositoryWrapper _repositoryWrapper;
public CrudController(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
// GET:Get All Entity
[HttpGet]
public virtual async Task<IActionResult> GetAllAsync()
{
return Ok(await _repositoryWrapper.SetRepository<TEntity>().TableNoTracking.ToListAsync());
}
// GET:Get An Entity By Id
[HttpGet("{id}")]
public async Task<IActionResult> GetAsync(int id, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<TEntity>().GetByIdAsync(cancellationToken, id);
return Ok(ent);
}
// POST:Add New Entity
[HttpPost]
public virtual async Task<IActionResult> Post([FromBody] TEntity ent, CancellationToken cancellationToken)
{
_repositoryWrapper.SetRepository<TEntity>().Add(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return Ok(ent);
}
// PUT:Update Entity
[HttpPut]
public virtual async Task<IActionResult> Put([FromBody] TEntity ent, CancellationToken cancellationToken)
{
_repositoryWrapper.SetRepository<TEntity>().Update(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return Ok();
}
// DELETE:Delete Entity
[HttpDelete("{id}")]
public virtual async Task<IActionResult> Delete(int id, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<TEntity>().GetByIdAsync(cancellationToken, id);
_repositoryWrapper.SetRepository<TEntity>().Delete(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return Ok();
}
}

View File

@ -0,0 +1,23 @@
using Microsoft.Extensions.Options;
namespace NetinaCMS.Api.WebFramework.Configurations;
public class ConfigureJwtBearerOptions : IPostConfigureOptions<JwtBearerOptions>
{
public void PostConfigure(string name, JwtBearerOptions options)
{
var originalOnMessageReceived = options.Events.OnMessageReceived;
options.Events.OnMessageReceived = async context =>
{
await originalOnMessageReceived(context);
if (string.IsNullOrEmpty(context.Token))
{
var accessToken = context.Request.Query["access_token"];
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken)) context.Token = accessToken;
}
};
}
}

View File

@ -0,0 +1,22 @@
using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes;
namespace NetinaCMS.Api.WebFramework.Configurations;
public static class LoggerConfig
{
public static void ConfigureSerilog()
{
var logName = $"{DirectoryAddress.Logs}/Log_Server_.log";
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Console(theme: AnsiConsoleTheme.Literate)
.WriteTo.Sentry(o =>
{
o.MinimumEventLevel = LogEventLevel.Error;
o.Dsn = "https://592b7fbb29464442a8e996247abe857f@watcher.igarson.app/7";
})
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", Serilog.Events.LogEventLevel.Error)
.CreateLogger();
}
}

View File

@ -0,0 +1,134 @@
namespace NetinaCMS.Api.WebFramework.Configurations;
public class PersianIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError DefaultError()
{
return new IdentityError { Code = nameof(DefaultError), Description = "ارور ناشناخته ای رخ داده است" };
}
public override IdentityError ConcurrencyFailure()
{
return new IdentityError
{ Code = nameof(ConcurrencyFailure), Description = "در درخواست شما تداخلی ایجاد شده است" };
}
public override IdentityError PasswordMismatch()
{
return new IdentityError { Code = nameof(PasswordMismatch), Description = "رمز عبور اشتباه است" };
}
public override IdentityError InvalidToken()
{
return new IdentityError { Code = nameof(InvalidToken), Description = "توکن ارسالی اشتباه است" };
}
public override IdentityError LoginAlreadyAssociated()
{
return new IdentityError
{ Code = nameof(LoginAlreadyAssociated), Description = "یوزری با این مشخصات در حال حاضر لاگین کرده است" };
}
public override IdentityError InvalidUserName(string userName)
{
return new IdentityError
{
Code = nameof(InvalidUserName),
Description = $"یوزر نیم '{userName}' صحیح نمی باشد فقط می توانید از حروف و اعداد استفاده کنید"
};
}
public override IdentityError InvalidEmail(string email)
{
return new IdentityError { Code = nameof(InvalidEmail), Description = $"ایمیل '{email}' صحیح نمی باشد" };
}
public override IdentityError DuplicateUserName(string userName)
{
return new IdentityError
{
Code = nameof(DuplicateUserName),
Description = $"یوزرنیم '{userName}' قبلا توسط اکانت دیگری استفاده شده است"
};
}
public override IdentityError DuplicateEmail(string email)
{
return new IdentityError
{ Code = nameof(DuplicateEmail), Description = $"ایمیل '{email}' قبل استفاده شده است" };
}
public override IdentityError InvalidRoleName(string role)
{
return new IdentityError { Code = nameof(InvalidRoleName), Description = $"نقش '{role}' موجود نمی باشد" };
}
public override IdentityError DuplicateRoleName(string role)
{
return new IdentityError
{ Code = nameof(DuplicateRoleName), Description = $"نقش '{role}' قبلا برای این کاربر استفاده شده است" };
}
public override IdentityError UserAlreadyHasPassword()
{
return new IdentityError
{ Code = nameof(UserAlreadyHasPassword), Description = "کاربر قبلا رمز عبوری را استفاده کرده است" };
}
public override IdentityError UserLockoutNotEnabled()
{
return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "کاربر مورد نظر قفل شده است" };
}
public override IdentityError UserAlreadyInRole(string role)
{
return new IdentityError
{ Code = nameof(UserAlreadyInRole), Description = "نشق مورد نظر برای این کاربر استفاده شده است" };
}
public override IdentityError UserNotInRole(string role)
{
return new IdentityError { Code = nameof(UserNotInRole), Description = $"کاربر مورد نظر در نقش '{role}' نیست" };
}
public override IdentityError PasswordTooShort(int length)
{
return new IdentityError
{ Code = nameof(PasswordTooShort), Description = $"پسورد حداقل باید {length} کاراکتر باشد" };
}
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return new IdentityError
{
Code = nameof(PasswordRequiresNonAlphanumeric),
Description = "رمز عبور باید حداقل یک کاراکتر غیر عددی داشته باشد"
};
}
public override IdentityError PasswordRequiresDigit()
{
return new IdentityError
{
Code = nameof(PasswordRequiresDigit), Description = "پسور مورد نظر باید حداقل یک عدد داشته باشد ('0'-'9')"
};
}
public override IdentityError PasswordRequiresLower()
{
return new IdentityError
{
Code = nameof(PasswordRequiresLower),
Description = "پسورد مورد نظر باید حداقل یکی از حروف ('a'-'z') به صورت کوچک داشته باشد"
};
}
public override IdentityError PasswordRequiresUpper()
{
return new IdentityError
{
Code = nameof(PasswordRequiresUpper),
Description = "پسورد مورد نظر باید حداقل یکی از حروف ('A'-'Z') به صورت بزرگ داشته باشد"
};
}
}

View File

@ -0,0 +1,199 @@
using Marten;
namespace NetinaCMS.Api.WebFramework.Configurations;
public static class ServiceExtensions
{
public static void AddIpRateLimit(this IServiceCollection services, IConfigurationRoot configuration)
{
//load general configuration from appsettings.json
services.Configure<IpRateLimitOptions>(configuration.GetSection("IpRateLimiting"));
//load ip rules from appsettings.json
services.Configure<IpRateLimitPolicies>(configuration.GetSection("IpRateLimitPolicies"));
// inject counter and rules stores
//services.AddInMemoryRateLimiting();
services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, DistributedCacheRateLimitCounterStore>();
services.AddDistributedRateLimiting<AsyncKeyLockProcessingStrategy>();
services.AddDistributedRateLimiting<RedisProcessingStrategy>();
services.AddRedisRateLimiting();
// configuration (resolvers, counter key builders)
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
}
public static void AddCustomStackExchangeRedis(this IServiceCollection serviceCollection, SiteSettings siteSettings)
{
serviceCollection.AddStackExchangeRedisExtensions<NewtonsoftSerializer>(options =>
{
return new List<RedisConfiguration>
{
new()
{
Hosts = new[]
{
new RedisHost
{
Port = siteSettings.MasterRedisConfiguration.Port,
Host = siteSettings.MasterRedisConfiguration.Host
}
},
Password = siteSettings.MasterRedisConfiguration.Password,
Ssl = false
}
};
});
}
public static void AddCustomDbContext(this IServiceCollection serviceCollection, IConfigurationRoot Configuration)
{
serviceCollection.AddDbContextFactory<ApplicationContext>(options =>
{
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
options.UseNpgsql(Configuration.GetConnectionString("Postgres"), b => b.MigrationsAssembly("HamyanEdalat.Repository"))
.UseProjectAssembly(typeof(ApplicationUser).Assembly);
//options.EnableServiceProviderCaching(true);
}).BuildServiceProvider();
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
}
public static void AddMarten(this IServiceCollection serviceCollection, IConfigurationRoot configuration , IWebHostEnvironment environment)
{
serviceCollection.AddMarten(options =>
{
// Establish the connection string to your Marten database
options.Connection(configuration.GetConnectionString("MartenDB")!);
// If we're running in development mode, let Marten just take care
// of all necessary schema building and patching behind the scenes
if (environment.IsDevelopment())
{
options.AutoCreateSchemaObjects = AutoCreate.All;
}
});
}
public static void AddCustomResponseCompression(this IServiceCollection serviceCollection)
{
serviceCollection.Configure<GzipCompressionProviderOptions>(options =>
options.Level = CompressionLevel.Fastest);
serviceCollection.AddResponseCompression(options =>
{
options.Providers.Add<GzipCompressionProvider>();
options.EnableForHttps = true;
});
}
public static void AddCustomCores(this IServiceCollection serviceCollection)
{
serviceCollection.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod()
.SetPreflightMaxAge(TimeSpan.FromHours(24))
.WithExposedHeaders("Access-control-allow-origins")
.AllowAnyHeader()
.SetIsOriginAllowed(_ => true)
.AllowCredentials();
}));
}
public static void AddCustomController(this IServiceCollection serviceCollection)
{
serviceCollection.AddControllers(options => { options.Filters.Add(new AuthorizeFilter()); })
.AddControllersAsServices()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
//options.SerializerSettings.ContractResolver = new DefaultContractResolver();
}
);
}
public static void AddCustomMvc(this IServiceCollection serviceCollection)
{
serviceCollection
.AddMvc()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
}
public static void AddCustomAuthorization(this IServiceCollection serviceCollection)
{
serviceCollection.AddAuthorization();
}
public static void AddJwtCustomAuthentication(this IServiceCollection serviceCollection, JwtSettings jwtSettings)
{
serviceCollection.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
var secretKey = Encoding.UTF8.GetBytes(jwtSettings.SecretKey);
var validateParammetrs = new TokenValidationParameters
{
ClockSkew = TimeSpan.Zero,
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(secretKey),
RequireExpirationTime = true,
ValidateLifetime = true,
ValidateAudience = true,
ValidAudience = jwtSettings.Audience,
ValidateIssuer = true,
ValidIssuer = jwtSettings.Issuer
};
options.RequireHttpsMetadata = true;
options.SaveToken = true;
options.TokenValidationParameters = validateParammetrs;
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken))
// Read the token out of the query string
context.Token = accessToken.ToString();
return Task.CompletedTask;
}
};
});
}
public static void AddCustomIdentity(this IServiceCollection serviceCollection)
{
serviceCollection.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.User.RequireUniqueEmail = false;
}).AddEntityFrameworkStores<ApplicationContext>()
.AddDefaultTokenProviders()
.AddErrorDescriber<PersianIdentityErrorDescriber>();
}
public static void AddCustomApiVersioning(this IServiceCollection serviceCollection)
{
serviceCollection.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ApiVersionReader = new HeaderApiVersionReader("api-version");
options.ReportApiVersions = true;
});
}
}

View File

@ -0,0 +1,223 @@
using Refit;
namespace NetinaCMS.Api.WebFramework.MiddleWares;
public static class ExceptionHandlerMiddlewareExtensions
{
public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder applicationBuilder)
{
return applicationBuilder.UseMiddleware<ExceptionHandlerMiddleware>();
}
}
public class ExceptionHandlerMiddleware
{
private readonly IWebHostEnvironment _env;
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
private readonly RequestDelegate _next;
public ExceptionHandlerMiddleware(
RequestDelegate next,
IWebHostEnvironment env,
ILogger<ExceptionHandlerMiddleware> logger)
{
_next = next;
_env = env;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
string message = null;
var httpStatusCode = HttpStatusCode.InternalServerError;
var apiStatusCode = ApiResultStatusCode.ServerError;
try
{
await _next(context);
}
catch (BaseApiException exception)
{
_logger.LogError(exception, exception.Message);
httpStatusCode = exception.HttpStatusCode;
apiStatusCode = exception.ApiStatusCode;
if (_env.IsDevelopment())
{
var dic = new Dictionary<string, string>
{
["Exception"] = exception.Message,
["StackTrace"] = exception.StackTrace
};
if (exception.InnerException != null)
{
dic.Add("InnerException.Exception", exception.InnerException.Message);
dic.Add("InnerException.StackTrace", exception.InnerException.StackTrace);
}
if (exception.AdditionalData != null)
dic.Add("AdditionalData", JsonConvert.SerializeObject(exception.AdditionalData));
var contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
message = JsonConvert.SerializeObject(dic, new JsonSerializerSettings
{
ContractResolver = contractResolver,
Formatting = Formatting.Indented
});
}
else
{
message = exception.Message;
}
if (exception.AdditionalData == null)
await WriteToResponseAsync();
else
await WriteToResponseWithObjectAsync(exception.AdditionalData);
}
catch (SecurityTokenExpiredException exception)
{
_logger.LogError(exception, exception.Message);
SetUnAuthorizeResponse(exception);
await WriteToResponseAsync();
}
catch (UnauthorizedAccessException exception)
{
_logger.LogError(exception, exception.Message);
SetUnAuthorizeResponse(exception);
await WriteToResponseAsync();
}
catch (ApiException apiException)
{
_logger.LogError(apiException, apiException.Message);
httpStatusCode = HttpStatusCode.InternalServerError;
apiStatusCode = ApiResultStatusCode.RefitError;
message = apiException.Message;
await WriteToResponseAsync();
}
catch (Exception exception)
{
_logger.LogError(exception, exception.Message);
if (_env.IsDevelopment())
{
if (exception?.InnerException?.Message != null)
{
var dic = new Dictionary<string, string>
{
["Exception"] = exception.Message,
["InnerException"] = exception?.InnerException?.Message,
["StackTrace"] = exception?.StackTrace
};
message = JsonConvert.SerializeObject(dic);
}
}
message = exception.Message;
await WriteToResponseAsync();
}
async Task WriteToResponseAsync()
{
if (context.Response.HasStarted)
throw new InvalidOperationException("The response has already started, the http status code middleware will not be executed.");
var result = new ApiResult(false, apiStatusCode, message);
var contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings
{
ContractResolver = contractResolver,
Formatting = Formatting.Indented
});
context.Response.StatusCode = (int)httpStatusCode;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(json);
}
async Task WriteToResponseWithObjectAsync(object additionalData)
{
if (context.Response.HasStarted)
throw new InvalidOperationException(
"The response has already started, the http status code middleware will not be executed.");
var result = new ApiResult<object>(false, apiStatusCode, additionalData, message);
var contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings
{
ContractResolver = contractResolver,
Formatting = Formatting.Indented
});
context.Response.StatusCode = (int)httpStatusCode;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(json);
}
void SetUnAuthorizeResponse(Exception exception)
{
httpStatusCode = HttpStatusCode.Unauthorized;
apiStatusCode = ApiResultStatusCode.UnAuthorized;
if (_env.IsDevelopment())
{
var dic = new Dictionary<string, string>
{
["Exception"] = exception.Message,
["StackTrace"] = exception.StackTrace
};
if (exception is SecurityTokenExpiredException tokenException)
dic.Add("Expires", tokenException.Expires.ToString());
message = JsonConvert.SerializeObject(dic);
}
}
JwtSecurityToken ReadJwtToken(bool fromHeader = true)
{
try
{
if (fromHeader)
{
var stream = context.Request.Headers.Values.First(v => v.FirstOrDefault().Contains("Bearer"))
.FirstOrDefault();
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream.Split(" ").Last());
return jsonToken as JwtSecurityToken;
}
else
{
string stream = context.Request.Query["access_token"];
;
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream.Split(" ").Last());
return jsonToken as JwtSecurityToken;
}
}
catch (Exception e)
{
throw new BaseApiException(ApiResultStatusCode.UnAuthorized, e.Message + " Jwt is wrong",
HttpStatusCode.Unauthorized);
}
}
}
}

View File

@ -0,0 +1,37 @@
using System.Diagnostics;
namespace NetinaCMS.Api.WebFramework.MiddleWares;
public static class PerformanceMiddlewareExtensions
{
public static IApplicationBuilder UsePerformanceMiddlewar(this IApplicationBuilder applicationBuilder)
{
return applicationBuilder.UseMiddleware<PerformanceMiddleware>();
}
}
public class PerformanceMiddleware
{
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
private readonly RequestDelegate _next;
private readonly Stopwatch _timer;
public PerformanceMiddleware(
RequestDelegate next,
ILogger<ExceptionHandlerMiddleware> logger)
{
_next = next;
_logger = logger;
_timer = new Stopwatch();
}
public async System.Threading.Tasks.Task Invoke(HttpContext context)
{
_timer.Start();
await _next(context);
_timer.Stop();
var elapsedMilliseconds = _timer.ElapsedMilliseconds;
_logger.LogWarning($"REQUEST TIMER : {elapsedMilliseconds}");
}
}

View File

@ -0,0 +1,283 @@
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Pluralize.NET;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
namespace NetinaCMS.Api.WebFramework.Swagger;
public static class SwaggerConfiguration
{
public static void AddCustomSwagger(this IServiceCollection services,string baseUrl)
{
services.AddSwaggerGen(options =>
{
//var xmlDuc = Path.Combine(AppContext.BaseDirectory, "swaggerApi.xml");
//options.IncludeXmlComments(xmlDuc,true);
options.SwaggerDoc("v1",
new OpenApiInfo
{
Version = "v1",
Title = "iGarson Api Dacument",
Description = "iGarson api for clients that wana use",
License = new OpenApiLicense { Name = "Vira Safir Fanavar " },
Contact = new OpenApiContact
{
Name = "Amir Hossein Khademi",
Email = "avvampier@gmail.com",
Url = new Uri("http://amir-khademi.ir/")
}
});
options.EnableAnnotations();
options.DescribeAllParametersInCamelCase();
options.IgnoreObsoleteActions();
//#region Versioning
//// Remove version parameter from all Operations
//options.OperationFilter<RemoveVersionParameters>();
////set version "api/v{version}/[controller]" from current swagger doc verion
//options.DocumentFilter<SetVersionInPaths>();
////Seperate and categorize end-points by doc version
//options.DocInclusionPredicate((version, desc) =>
//{
// if (!desc.TryGetMethodInfo(out var methodInfo)) return false;
// var versions = methodInfo.DeclaringType
// .GetCustomAttributes(true)
// .OfType<ApiVersionAttribute>()
// .SelectMany(attr => attr.Versions)
// .ToList();
// return versions.Any(v => $"v{v.ToString()}" == version);
//});
//#endregion
#region Security
var url = $"{baseUrl}/api/auth/login/swagger";
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Scheme = "Bearer",
Name = "Bearer",
Flows = new OpenApiOAuthFlows
{
Password = new OpenApiOAuthFlow
{
TokenUrl = new Uri(url)
}
}
});
options.OperationFilter<UnauthorizedResponsesOperationFilter>(true, "Bearer");
#endregion
#region Customize
options.OperationFilter<ApplySummariesOperationFilter>();
#endregion
});
}
public static void UseCustomSwagger(this IApplicationBuilder app,string baseUrl)
{
app.UseSwagger(options =>
{
options.SerializeAsV2 = true;
});
app.UseSwaggerUI(options =>
{
options.InjectStylesheet("/assets/swagger-ui/x3/theme-flattop.css");
options.DocExpansion(DocExpansion.None);
// Display
options.DefaultModelExpandDepth(2);
options.DefaultModelRendering(ModelRendering.Model);
options.DefaultModelsExpandDepth(-1);
options.DisplayOperationId();
options.DisplayRequestDuration();
options.EnableDeepLinking();
options.EnableFilter();
options.ShowExtensions();
options.OAuthUseBasicAuthenticationWithAccessCodeGrant();
options.SwaggerEndpoint($"{baseUrl}/swagger/v1/swagger.json", "V1 Docs");
});
}
}
public class RemoveVersionParameters : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
// Remove version parameter from all Operations
var versionParameter = operation.Parameters.SingleOrDefault(p => p.Name == "version");
if (versionParameter != null)
operation.Parameters.Remove(versionParameter);
}
}
public class SetVersionInPaths : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
if (swaggerDoc == null)
throw new ArgumentNullException(nameof(swaggerDoc));
var replacements = new OpenApiPaths();
foreach (var (key, value) in swaggerDoc.Paths)
replacements.Add(key.Replace("v{version}", swaggerDoc.Info.Version, StringComparison.InvariantCulture),
value);
swaggerDoc.Paths = replacements;
}
}
public class UnauthorizedResponsesOperationFilter : IOperationFilter
{
private readonly bool includeUnauthorizedAndForbiddenResponses;
private readonly string schemeName;
public UnauthorizedResponsesOperationFilter(bool includeUnauthorizedAndForbiddenResponses,
string schemeName = "Bearer")
{
this.includeUnauthorizedAndForbiddenResponses = includeUnauthorizedAndForbiddenResponses;
this.schemeName = schemeName;
}
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var filters = context.ApiDescription.ActionDescriptor.FilterDescriptors;
var hasAnynomousEndPoint = context.ApiDescription.ActionDescriptor.EndpointMetadata.Any(e =>
e.GetType() == typeof(AllowAnonymousAttribute));
//var hasAnonymous = filters.Any(p => p.Filter is AllowAnonymousFilter);
if (hasAnynomousEndPoint)
return;
/*var hasAuthorize = filters.Any(p => p.Filter is AuthorizeFilter);
if (!hasAuthorize)
return;*/
if (includeUnauthorizedAndForbiddenResponses)
{
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
}
operation.Security.Add(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
}
}
public class ApplySummariesOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var controllerActionDescriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor == null)
{
operation.Summary = context.ApiDescription.ActionDescriptor.DisplayName;
return;
}
var pluralizer = new Pluralizer();
var actionName = controllerActionDescriptor.ActionName;
var singularizeName = pluralizer.Singularize(controllerActionDescriptor.ControllerName);
var pluralizeName = pluralizer.Pluralize(controllerActionDescriptor.DisplayName);
var parameterCount = operation.Parameters.Where(p => p.Name != "version" && p.Name != "api-version").Count();
if (IsGetAllAction())
{
if (!operation.Summary.HasValue())
operation.Summary = $"Returns all {pluralizeName}";
}
else if (IsActionName("Post", "Create"))
{
if (!operation.Summary.HasValue())
operation.Summary = $"Creates a {singularizeName}";
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
operation.Parameters[0].Description = $"A {singularizeName} representation";
}
else if (IsActionName("Read", "Get"))
{
if (!operation.Summary.HasValue())
operation.Summary = $"Retrieves a {singularizeName} by unique id";
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
operation.Parameters[0].Description = $"a unique id for the {singularizeName}";
}
else if (IsActionName("Put", "Edit", "Update"))
{
if (!operation.Summary.HasValue())
operation.Summary = $"Updates a {singularizeName} by unique id";
//if (!operation.Parameters[0].OrderDescription.HasValue())
// operation.Parameters[0].OrderDescription = $"A unique id for the {singularizeName}";
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
operation.Parameters[0].Description = $"A {singularizeName} representation";
}
else if (IsActionName("Delete", "Remove"))
{
if (!operation.Summary.HasValue())
operation.Summary = $"Deletes a {singularizeName} by unique id";
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
operation.Parameters[0].Description = $"A unique id for the {singularizeName}";
}
else
{
if (!operation.Summary.HasValue())
operation.Summary = $"{actionName} {pluralizeName}";
}
#region Local Functions
bool IsGetAllAction()
{
foreach (var name in new[] { "Get", "Read", "Select" })
if (actionName.Equals(name, StringComparison.OrdinalIgnoreCase) && parameterCount == 0 ||
actionName.Equals($"{name}All", StringComparison.OrdinalIgnoreCase) ||
actionName.Equals($"{name}{pluralizeName}", StringComparison.OrdinalIgnoreCase) ||
actionName.Equals($"{name}All{singularizeName}", StringComparison.OrdinalIgnoreCase) ||
actionName.Equals($"{name}All{pluralizeName}", StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
bool IsActionName(params string[] names)
{
foreach (var name in names)
if (actionName.Contains(name, StringComparison.OrdinalIgnoreCase) ||
actionName.Contains($"{name}ById", StringComparison.OrdinalIgnoreCase) ||
actionName.Contains($"{name}{singularizeName}", StringComparison.OrdinalIgnoreCase) ||
actionName.Contains($"{name}{singularizeName}ById", StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -0,0 +1,257 @@
/**
* Template Name: Arsha - v4.9.1
* Template URL: https://bootstrapmade.com/arsha-free-bootstrap-html-template-corporate/
* Author: BootstrapMade.com
* License: https://bootstrapmade.com/license/
*/
(function() {
"use strict";
/**
* Easy selector helper function
*/
const select = (el, all = false) => {
el = el.trim()
if (all) {
return [...document.querySelectorAll(el)]
} else {
return document.querySelector(el)
}
}
/**
* Easy event listener function
*/
const on = (type, el, listener, all = false) => {
let selectEl = select(el, all)
if (selectEl) {
if (all) {
selectEl.forEach(e => e.addEventListener(type, listener))
} else {
selectEl.addEventListener(type, listener)
}
}
}
/**
* Easy on scroll event listener
*/
const onscroll = (el, listener) => {
el.addEventListener('scroll', listener)
}
/**
* Navbar links active state on scroll
*/
let navbarlinks = select('#navbar .scrollto', true)
const navbarlinksActive = () => {
let position = window.scrollY + 200
navbarlinks.forEach(navbarlink => {
if (!navbarlink.hash) return
let section = select(navbarlink.hash)
if (!section) return
if (position >= section.offsetTop && position <= (section.offsetTop + section.offsetHeight)) {
navbarlink.classList.add('active')
} else {
navbarlink.classList.remove('active')
}
})
}
window.addEventListener('load', navbarlinksActive)
onscroll(document, navbarlinksActive)
/**
* Scrolls to an element with header offset
*/
const scrollto = (el) => {
let header = select('#header')
let offset = header.offsetHeight
let elementPos = select(el).offsetTop
window.scrollTo({
top: elementPos - offset,
behavior: 'smooth'
})
}
/**
* Toggle .header-scrolled class to #header when page is scrolled
*/
let selectHeader = select('#header')
if (selectHeader) {
const headerScrolled = () => {
if (window.scrollY > 100) {
selectHeader.classList.add('header-scrolled')
} else {
selectHeader.classList.remove('header-scrolled')
}
}
window.addEventListener('load', headerScrolled)
onscroll(document, headerScrolled)
}
/**
* Back to top button
*/
let backtotop = select('.back-to-top')
if (backtotop) {
const toggleBacktotop = () => {
if (window.scrollY > 100) {
backtotop.classList.add('active')
} else {
backtotop.classList.remove('active')
}
}
window.addEventListener('load', toggleBacktotop)
onscroll(document, toggleBacktotop)
}
/**
* Mobile nav toggle
*/
on('click', '.mobile-nav-toggle', function(e) {
select('#navbar').classList.toggle('navbar-mobile')
this.classList.toggle('bi-list')
this.classList.toggle('bi-x')
})
/**
* Mobile nav dropdowns activate
*/
on('click', '.navbar .dropdown > a', function(e) {
if (select('#navbar').classList.contains('navbar-mobile')) {
e.preventDefault()
this.nextElementSibling.classList.toggle('dropdown-active')
}
}, true)
/**
* Scrool with ofset on links with a class name .scrollto
*/
on('click', '.scrollto', function(e) {
if (select(this.hash)) {
e.preventDefault()
let navbar = select('#navbar')
if (navbar.classList.contains('navbar-mobile')) {
navbar.classList.remove('navbar-mobile')
let navbarToggle = select('.mobile-nav-toggle')
navbarToggle.classList.toggle('bi-list')
navbarToggle.classList.toggle('bi-x')
}
scrollto(this.hash)
}
}, true)
/**
* Scroll with ofset on page load with hash links in the url
*/
window.addEventListener('load', () => {
if (window.location.hash) {
if (select(window.location.hash)) {
scrollto(window.location.hash)
}
}
});
/**
* Preloader
*/
let preloader = select('#preloader');
if (preloader) {
window.addEventListener('load', () => {
preloader.remove()
});
}
/**
* Initiate glightbox
*/
const glightbox = GLightbox({
selector: '.glightbox'
});
/**
* Skills animation
*/
let skilsContent = select('.skills-content');
if (skilsContent) {
new Waypoint({
element: skilsContent,
offset: '80%',
handler: function(direction) {
let progress = select('.progress .progress-bar', true);
progress.forEach((el) => {
el.style.width = el.getAttribute('aria-valuenow') + '%'
});
}
})
}
/**
* Porfolio isotope and filter
*/
window.addEventListener('load', () => {
let portfolioContainer = select('.portfolio-container');
if (portfolioContainer) {
let portfolioIsotope = new Isotope(portfolioContainer, {
itemSelector: '.portfolio-item'
});
let portfolioFilters = select('#portfolio-flters li', true);
on('click', '#portfolio-flters li', function(e) {
e.preventDefault();
portfolioFilters.forEach(function(el) {
el.classList.remove('filter-active');
});
this.classList.add('filter-active');
portfolioIsotope.arrange({
filter: this.getAttribute('data-filter')
});
portfolioIsotope.on('arrangeComplete', function() {
AOS.refresh()
});
}, true);
}
});
/**
* Initiate portfolio lightbox
*/
const portfolioLightbox = GLightbox({
selector: '.portfolio-lightbox'
});
/**
* Portfolio details slider
*/
new Swiper('.portfolio-details-slider', {
speed: 400,
loop: true,
autoplay: {
delay: 5000,
disableOnInteraction: false
},
pagination: {
el: '.swiper-pagination',
type: 'bullets',
clickable: true
}
});
/**
* Animation on scroll
*/
window.addEventListener('load', () => {
AOS.init({
duration: 1000,
easing: "ease-in-out",
once: true,
mirror: false
});
});
})()

View File

@ -0,0 +1 @@
The .scss (Sass) files are only avilable in the pro version. You can buy it from: https://bootstrapmade.com/arsha-free-bootstrap-html-template-corporate/

View File

@ -0,0 +1,7 @@
<!DOCTYPE html>
<div class="sidebar">
<a class="active" href="#home">Home</a>
<a href="#news">News</a>
<a href="#contact">Contact</a>
<a href="#about">About</a>
</div>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,758 @@
/*!
Waypoints - 4.0.1
Copyright © 2011-2016 Caleb Troughton
Licensed under the MIT license.
https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
*/
(function() {
'use strict'
var keyCounter = 0
var allWaypoints = {}
/* http://imakewebthings.com/waypoints/api/waypoint */
function Waypoint(options) {
if (!options) {
throw new Error('No options passed to Waypoint constructor')
}
if (!options.element) {
throw new Error('No element option passed to Waypoint constructor')
}
if (!options.handler) {
throw new Error('No handler option passed to Waypoint constructor')
}
this.key = 'waypoint-' + keyCounter
this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
this.element = this.options.element
this.adapter = new Waypoint.Adapter(this.element)
this.callback = options.handler
this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
this.enabled = this.options.enabled
this.triggerPoint = null
this.group = Waypoint.Group.findOrCreate({
name: this.options.group,
axis: this.axis
})
this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
if (Waypoint.offsetAliases[this.options.offset]) {
this.options.offset = Waypoint.offsetAliases[this.options.offset]
}
this.group.add(this)
this.context.add(this)
allWaypoints[this.key] = this
keyCounter += 1
}
/* Private */
Waypoint.prototype.queueTrigger = function(direction) {
this.group.queueTrigger(this, direction)
}
/* Private */
Waypoint.prototype.trigger = function(args) {
if (!this.enabled) {
return
}
if (this.callback) {
this.callback.apply(this, args)
}
}
/* Public */
/* http://imakewebthings.com/waypoints/api/destroy */
Waypoint.prototype.destroy = function() {
this.context.remove(this)
this.group.remove(this)
delete allWaypoints[this.key]
}
/* Public */
/* http://imakewebthings.com/waypoints/api/disable */
Waypoint.prototype.disable = function() {
this.enabled = false
return this
}
/* Public */
/* http://imakewebthings.com/waypoints/api/enable */
Waypoint.prototype.enable = function() {
this.context.refresh()
this.enabled = true
return this
}
/* Public */
/* http://imakewebthings.com/waypoints/api/next */
Waypoint.prototype.next = function() {
return this.group.next(this)
}
/* Public */
/* http://imakewebthings.com/waypoints/api/previous */
Waypoint.prototype.previous = function() {
return this.group.previous(this)
}
/* Private */
Waypoint.invokeAll = function(method) {
var allWaypointsArray = []
for (var waypointKey in allWaypoints) {
allWaypointsArray.push(allWaypoints[waypointKey])
}
for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
allWaypointsArray[i][method]()
}
}
/* Public */
/* http://imakewebthings.com/waypoints/api/destroy-all */
Waypoint.destroyAll = function() {
Waypoint.invokeAll('destroy')
}
/* Public */
/* http://imakewebthings.com/waypoints/api/disable-all */
Waypoint.disableAll = function() {
Waypoint.invokeAll('disable')
}
/* Public */
/* http://imakewebthings.com/waypoints/api/enable-all */
Waypoint.enableAll = function() {
Waypoint.Context.refreshAll()
for (var waypointKey in allWaypoints) {
allWaypoints[waypointKey].enabled = true
}
return this
}
/* Public */
/* http://imakewebthings.com/waypoints/api/refresh-all */
Waypoint.refreshAll = function() {
Waypoint.Context.refreshAll()
}
/* Public */
/* http://imakewebthings.com/waypoints/api/viewport-height */
Waypoint.viewportHeight = function() {
return window.innerHeight || document.documentElement.clientHeight
}
/* Public */
/* http://imakewebthings.com/waypoints/api/viewport-width */
Waypoint.viewportWidth = function() {
return document.documentElement.clientWidth
}
Waypoint.adapters = []
Waypoint.defaults = {
context: window,
continuous: true,
enabled: true,
group: 'default',
horizontal: false,
offset: 0
}
Waypoint.offsetAliases = {
'bottom-in-view': function() {
return this.context.innerHeight() - this.adapter.outerHeight()
},
'right-in-view': function() {
return this.context.innerWidth() - this.adapter.outerWidth()
}
}
window.Waypoint = Waypoint
}())
;(function() {
'use strict'
function requestAnimationFrameShim(callback) {
window.setTimeout(callback, 1000 / 60)
}
var keyCounter = 0
var contexts = {}
var Waypoint = window.Waypoint
var oldWindowLoad = window.onload
/* http://imakewebthings.com/waypoints/api/context */
function Context(element) {
this.element = element
this.Adapter = Waypoint.Adapter
this.adapter = new this.Adapter(element)
this.key = 'waypoint-context-' + keyCounter
this.didScroll = false
this.didResize = false
this.oldScroll = {
x: this.adapter.scrollLeft(),
y: this.adapter.scrollTop()
}
this.waypoints = {
vertical: {},
horizontal: {}
}
element.waypointContextKey = this.key
contexts[element.waypointContextKey] = this
keyCounter += 1
if (!Waypoint.windowContext) {
Waypoint.windowContext = true
Waypoint.windowContext = new Context(window)
}
this.createThrottledScrollHandler()
this.createThrottledResizeHandler()
}
/* Private */
Context.prototype.add = function(waypoint) {
var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
this.waypoints[axis][waypoint.key] = waypoint
this.refresh()
}
/* Private */
Context.prototype.checkEmpty = function() {
var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
var isWindow = this.element == this.element.window
if (horizontalEmpty && verticalEmpty && !isWindow) {
this.adapter.off('.waypoints')
delete contexts[this.key]
}
}
/* Private */
Context.prototype.createThrottledResizeHandler = function() {
var self = this
function resizeHandler() {
self.handleResize()
self.didResize = false
}
this.adapter.on('resize.waypoints', function() {
if (!self.didResize) {
self.didResize = true
Waypoint.requestAnimationFrame(resizeHandler)
}
})
}
/* Private */
Context.prototype.createThrottledScrollHandler = function() {
var self = this
function scrollHandler() {
self.handleScroll()
self.didScroll = false
}
this.adapter.on('scroll.waypoints', function() {
if (!self.didScroll || Waypoint.isTouch) {
self.didScroll = true
Waypoint.requestAnimationFrame(scrollHandler)
}
})
}
/* Private */
Context.prototype.handleResize = function() {
Waypoint.Context.refreshAll()
}
/* Private */
Context.prototype.handleScroll = function() {
var triggeredGroups = {}
var axes = {
horizontal: {
newScroll: this.adapter.scrollLeft(),
oldScroll: this.oldScroll.x,
forward: 'right',
backward: 'left'
},
vertical: {
newScroll: this.adapter.scrollTop(),
oldScroll: this.oldScroll.y,
forward: 'down',
backward: 'up'
}
}
for (var axisKey in axes) {
var axis = axes[axisKey]
var isForward = axis.newScroll > axis.oldScroll
var direction = isForward ? axis.forward : axis.backward
for (var waypointKey in this.waypoints[axisKey]) {
var waypoint = this.waypoints[axisKey][waypointKey]
if (waypoint.triggerPoint === null) {
continue
}
var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
if (crossedForward || crossedBackward) {
waypoint.queueTrigger(direction)
triggeredGroups[waypoint.group.id] = waypoint.group
}
}
}
for (var groupKey in triggeredGroups) {
triggeredGroups[groupKey].flushTriggers()
}
this.oldScroll = {
x: axes.horizontal.newScroll,
y: axes.vertical.newScroll
}
}
/* Private */
Context.prototype.innerHeight = function() {
/*eslint-disable eqeqeq */
if (this.element == this.element.window) {
return Waypoint.viewportHeight()
}
/*eslint-enable eqeqeq */
return this.adapter.innerHeight()
}
/* Private */
Context.prototype.remove = function(waypoint) {
delete this.waypoints[waypoint.axis][waypoint.key]
this.checkEmpty()
}
/* Private */
Context.prototype.innerWidth = function() {
/*eslint-disable eqeqeq */
if (this.element == this.element.window) {
return Waypoint.viewportWidth()
}
/*eslint-enable eqeqeq */
return this.adapter.innerWidth()
}
/* Public */
/* http://imakewebthings.com/waypoints/api/context-destroy */
Context.prototype.destroy = function() {
var allWaypoints = []
for (var axis in this.waypoints) {
for (var waypointKey in this.waypoints[axis]) {
allWaypoints.push(this.waypoints[axis][waypointKey])
}
}
for (var i = 0, end = allWaypoints.length; i < end; i++) {
allWaypoints[i].destroy()
}
}
/* Public */
/* http://imakewebthings.com/waypoints/api/context-refresh */
Context.prototype.refresh = function() {
/*eslint-disable eqeqeq */
var isWindow = this.element == this.element.window
/*eslint-enable eqeqeq */
var contextOffset = isWindow ? undefined : this.adapter.offset()
var triggeredGroups = {}
var axes
this.handleScroll()
axes = {
horizontal: {
contextOffset: isWindow ? 0 : contextOffset.left,
contextScroll: isWindow ? 0 : this.oldScroll.x,
contextDimension: this.innerWidth(),
oldScroll: this.oldScroll.x,
forward: 'right',
backward: 'left',
offsetProp: 'left'
},
vertical: {
contextOffset: isWindow ? 0 : contextOffset.top,
contextScroll: isWindow ? 0 : this.oldScroll.y,
contextDimension: this.innerHeight(),
oldScroll: this.oldScroll.y,
forward: 'down',
backward: 'up',
offsetProp: 'top'
}
}
for (var axisKey in axes) {
var axis = axes[axisKey]
for (var waypointKey in this.waypoints[axisKey]) {
var waypoint = this.waypoints[axisKey][waypointKey]
var adjustment = waypoint.options.offset
var oldTriggerPoint = waypoint.triggerPoint
var elementOffset = 0
var freshWaypoint = oldTriggerPoint == null
var contextModifier, wasBeforeScroll, nowAfterScroll
var triggeredBackward, triggeredForward
if (waypoint.element !== waypoint.element.window) {
elementOffset = waypoint.adapter.offset()[axis.offsetProp]
}
if (typeof adjustment === 'function') {
adjustment = adjustment.apply(waypoint)
}
else if (typeof adjustment === 'string') {
adjustment = parseFloat(adjustment)
if (waypoint.options.offset.indexOf('%') > - 1) {
adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
}
}
contextModifier = axis.contextScroll - axis.contextOffset
waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
wasBeforeScroll = oldTriggerPoint < axis.oldScroll
nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
triggeredBackward = wasBeforeScroll && nowAfterScroll
triggeredForward = !wasBeforeScroll && !nowAfterScroll
if (!freshWaypoint && triggeredBackward) {
waypoint.queueTrigger(axis.backward)
triggeredGroups[waypoint.group.id] = waypoint.group
}
else if (!freshWaypoint && triggeredForward) {
waypoint.queueTrigger(axis.forward)
triggeredGroups[waypoint.group.id] = waypoint.group
}
else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
waypoint.queueTrigger(axis.forward)
triggeredGroups[waypoint.group.id] = waypoint.group
}
}
}
Waypoint.requestAnimationFrame(function() {
for (var groupKey in triggeredGroups) {
triggeredGroups[groupKey].flushTriggers()
}
})
return this
}
/* Private */
Context.findOrCreateByElement = function(element) {
return Context.findByElement(element) || new Context(element)
}
/* Private */
Context.refreshAll = function() {
for (var contextId in contexts) {
contexts[contextId].refresh()
}
}
/* Public */
/* http://imakewebthings.com/waypoints/api/context-find-by-element */
Context.findByElement = function(element) {
return contexts[element.waypointContextKey]
}
window.onload = function() {
if (oldWindowLoad) {
oldWindowLoad()
}
Context.refreshAll()
}
Waypoint.requestAnimationFrame = function(callback) {
var requestFn = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
requestAnimationFrameShim
requestFn.call(window, callback)
}
Waypoint.Context = Context
}())
;(function() {
'use strict'
function byTriggerPoint(a, b) {
return a.triggerPoint - b.triggerPoint
}
function byReverseTriggerPoint(a, b) {
return b.triggerPoint - a.triggerPoint
}
var groups = {
vertical: {},
horizontal: {}
}
var Waypoint = window.Waypoint
/* http://imakewebthings.com/waypoints/api/group */
function Group(options) {
this.name = options.name
this.axis = options.axis
this.id = this.name + '-' + this.axis
this.waypoints = []
this.clearTriggerQueues()
groups[this.axis][this.name] = this
}
/* Private */
Group.prototype.add = function(waypoint) {
this.waypoints.push(waypoint)
}
/* Private */
Group.prototype.clearTriggerQueues = function() {
this.triggerQueues = {
up: [],
down: [],
left: [],
right: []
}
}
/* Private */
Group.prototype.flushTriggers = function() {
for (var direction in this.triggerQueues) {
var waypoints = this.triggerQueues[direction]
var reverse = direction === 'up' || direction === 'left'
waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
for (var i = 0, end = waypoints.length; i < end; i += 1) {
var waypoint = waypoints[i]
if (waypoint.options.continuous || i === waypoints.length - 1) {
waypoint.trigger([direction])
}
}
}
this.clearTriggerQueues()
}
/* Private */
Group.prototype.next = function(waypoint) {
this.waypoints.sort(byTriggerPoint)
var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
var isLast = index === this.waypoints.length - 1
return isLast ? null : this.waypoints[index + 1]
}
/* Private */
Group.prototype.previous = function(waypoint) {
this.waypoints.sort(byTriggerPoint)
var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
return index ? this.waypoints[index - 1] : null
}
/* Private */
Group.prototype.queueTrigger = function(waypoint, direction) {
this.triggerQueues[direction].push(waypoint)
}
/* Private */
Group.prototype.remove = function(waypoint) {
var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
if (index > -1) {
this.waypoints.splice(index, 1)
}
}
/* Public */
/* http://imakewebthings.com/waypoints/api/first */
Group.prototype.first = function() {
return this.waypoints[0]
}
/* Public */
/* http://imakewebthings.com/waypoints/api/last */
Group.prototype.last = function() {
return this.waypoints[this.waypoints.length - 1]
}
/* Private */
Group.findOrCreate = function(options) {
return groups[options.axis][options.name] || new Group(options)
}
Waypoint.Group = Group
}())
;(function() {
'use strict'
var Waypoint = window.Waypoint
function isWindow(element) {
return element === element.window
}
function getWindow(element) {
if (isWindow(element)) {
return element
}
return element.defaultView
}
function NoFrameworkAdapter(element) {
this.element = element
this.handlers = {}
}
NoFrameworkAdapter.prototype.innerHeight = function() {
var isWin = isWindow(this.element)
return isWin ? this.element.innerHeight : this.element.clientHeight
}
NoFrameworkAdapter.prototype.innerWidth = function() {
var isWin = isWindow(this.element)
return isWin ? this.element.innerWidth : this.element.clientWidth
}
NoFrameworkAdapter.prototype.off = function(event, handler) {
function removeListeners(element, listeners, handler) {
for (var i = 0, end = listeners.length - 1; i < end; i++) {
var listener = listeners[i]
if (!handler || handler === listener) {
element.removeEventListener(listener)
}
}
}
var eventParts = event.split('.')
var eventType = eventParts[0]
var namespace = eventParts[1]
var element = this.element
if (namespace && this.handlers[namespace] && eventType) {
removeListeners(element, this.handlers[namespace][eventType], handler)
this.handlers[namespace][eventType] = []
}
else if (eventType) {
for (var ns in this.handlers) {
removeListeners(element, this.handlers[ns][eventType] || [], handler)
this.handlers[ns][eventType] = []
}
}
else if (namespace && this.handlers[namespace]) {
for (var type in this.handlers[namespace]) {
removeListeners(element, this.handlers[namespace][type], handler)
}
this.handlers[namespace] = {}
}
}
/* Adapted from jQuery 1.x offset() */
NoFrameworkAdapter.prototype.offset = function() {
if (!this.element.ownerDocument) {
return null
}
var documentElement = this.element.ownerDocument.documentElement
var win = getWindow(this.element.ownerDocument)
var rect = {
top: 0,
left: 0
}
if (this.element.getBoundingClientRect) {
rect = this.element.getBoundingClientRect()
}
return {
top: rect.top + win.pageYOffset - documentElement.clientTop,
left: rect.left + win.pageXOffset - documentElement.clientLeft
}
}
NoFrameworkAdapter.prototype.on = function(event, handler) {
var eventParts = event.split('.')
var eventType = eventParts[0]
var namespace = eventParts[1] || '__default'
var nsHandlers = this.handlers[namespace] = this.handlers[namespace] || {}
var nsTypeList = nsHandlers[eventType] = nsHandlers[eventType] || []
nsTypeList.push(handler)
this.element.addEventListener(eventType, handler)
}
NoFrameworkAdapter.prototype.outerHeight = function(includeMargin) {
var height = this.innerHeight()
var computedStyle
if (includeMargin && !isWindow(this.element)) {
computedStyle = window.getComputedStyle(this.element)
height += parseInt(computedStyle.marginTop, 10)
height += parseInt(computedStyle.marginBottom, 10)
}
return height
}
NoFrameworkAdapter.prototype.outerWidth = function(includeMargin) {
var width = this.innerWidth()
var computedStyle
if (includeMargin && !isWindow(this.element)) {
computedStyle = window.getComputedStyle(this.element)
width += parseInt(computedStyle.marginLeft, 10)
width += parseInt(computedStyle.marginRight, 10)
}
return width
}
NoFrameworkAdapter.prototype.scrollLeft = function() {
var win = getWindow(this.element)
return win ? win.pageXOffset : this.element.scrollLeft
}
NoFrameworkAdapter.prototype.scrollTop = function() {
var win = getWindow(this.element)
return win ? win.pageYOffset : this.element.scrollTop
}
NoFrameworkAdapter.extend = function() {
var args = Array.prototype.slice.call(arguments)
function merge(target, obj) {
if (typeof target === 'object' && typeof obj === 'object') {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
target[key] = obj[key]
}
}
}
return target
}
for (var i = 1, end = args.length; i < end; i++) {
merge(args[0], args[i])
}
return args[0]
}
NoFrameworkAdapter.inArray = function(element, array, i) {
return array == null ? -1 : array.indexOf(element, i)
}
NoFrameworkAdapter.isEmptyObject = function(obj) {
/* eslint no-unused-vars: 0 */
for (var name in obj) {
return false
}
return true
}
Waypoint.adapters.push({
name: 'noframework',
Adapter: NoFrameworkAdapter
})
Waypoint.Adapter = NoFrameworkAdapter
}())
;

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common
namespace NetinaCMS.Common
{
public class CommonConfig
{

View File

@ -1,6 +1,6 @@
using System.Collections;
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public static class AssertExtensions
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Extensions;
namespace NetinaCMS.Common.Extensions;
public static class BoolExtensions
{

View File

@ -1,6 +1,6 @@
using HamyanEdalat.Common.Models.Entity;
using NetinaCMS.Common.Models.Entity;
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public static class ClassDisplayExtensions
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public static class DateTimeExtensions
{

View File

@ -1,6 +1,6 @@
using System.Reflection;
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public enum DisplayProperty
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public static class NewtonJsonExtensions
{

View File

@ -1,6 +1,6 @@
using System.Text.RegularExpressions;
namespace HamyanEdalat.Common.Extensions;
namespace NetinaCMS.Common.Extensions;
public static class PhoneNumberExtensions
{
public static bool CheckPhoneNumber(string phoneNumber)

View File

@ -1,6 +1,6 @@
using System.Reflection;
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public static class PropertyExtensions
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public static class RandomExtensions
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public static class StringExtensions
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Extensions
namespace NetinaCMS.Common.Extensions
{
public static class ValidationExtensions
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Api
namespace NetinaCMS.Common.Models.Api
{
public class AccessToken
{

View File

@ -1,6 +1,6 @@
using System.Net;
namespace HamyanEdalat.Common.Models.Api
namespace NetinaCMS.Common.Models.Api
{
public enum ApiResultStatusCode
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Api
namespace NetinaCMS.Common.Models.Api
{
public class AppSettings
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Api
namespace NetinaCMS.Common.Models.Api
{
public enum FileUploadType
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Api;
namespace NetinaCMS.Common.Models.Api;
public class FileUploadResponse
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Api
namespace NetinaCMS.Common.Models.Api
{
public class HealthCheck
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Api
namespace NetinaCMS.Common.Models.Api
{
public class ResponseFile
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Api
namespace NetinaCMS.Common.Models.Api
{
public class TokenRequest
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Entity;
namespace NetinaCMS.Common.Models.Entity;
public abstract class ApiEntity : IApiEntity , IEquatable<ApiEntity>
{
[Key]

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Entity
namespace NetinaCMS.Common.Models.Entity
{
public interface IApiEntity
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Entity
namespace NetinaCMS.Common.Models.Entity
{
[AttributeUsage(AttributeTargets.Class)]
public class PageClassDisplay : Attribute

View File

@ -1,7 +1,7 @@
using System.Runtime.Serialization;
using HamyanEdalat.Common.Models.Api;
using NetinaCMS.Common.Models.Api;
namespace HamyanEdalat.Common.Models.Exception
namespace NetinaCMS.Common.Models.Exception
{
[Serializable()]
public class AppException : System.Exception

View File

@ -1,8 +1,8 @@
using System.Net;
using System.Runtime.Serialization;
using HamyanEdalat.Common.Models.Api;
using NetinaCMS.Common.Models.Api;
namespace HamyanEdalat.Common.Models.Exception
namespace NetinaCMS.Common.Models.Exception
{
[Serializable()]
public class BaseApiException : System.Exception

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models.Exception;
namespace NetinaCMS.Common.Models.Exception;
public class ValidationException : System.Exception
{

View File

@ -1,4 +1,4 @@
namespace HamyanEdalat.Common.Models
namespace NetinaCMS.Common.Models
{
public interface IScopedDependency
{

View File

@ -1,9 +1,9 @@
using System.ComponentModel;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using HamyanEdalat.Common.Models.Exception;
using NetinaCMS.Common.Models.Exception;
namespace HamyanEdalat.Common.Models.Mapper
namespace NetinaCMS.Common.Models.Mapper
{
/// <summary>
/// Base Dto Class initial map config between entity and dto

View File

@ -1,6 +1,6 @@
using System.Linq.Expressions;
namespace HamyanEdalat.Common.Models.Mapper
namespace NetinaCMS.Common.Models.Mapper
{
public interface IBaseDto<TDto,TEntity>
{

Some files were not shown because too many files have changed in this diff Show More