Add project files.

release/production
Amir Hossein Khademi 2023-09-08 12:25:21 +03:30
parent 59850dc4a9
commit c3d4e011ff
100 changed files with 3839 additions and 0 deletions

25
.dockerignore 100644
View File

@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc;
namespace Berizco.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
public WeatherForecastController()
{
}
public IEnumerable<WeatherForecast> Get()
{
}
}
}

View File

@ -0,0 +1,21 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["Berizco.Api/Berizco.Api.csproj", "Berizco.Api/"]
RUN dotnet restore "Berizco.Api/Berizco.Api.csproj"
COPY . .
WORKDIR "/src/Berizco.Api"
RUN dotnet build "Berizco.Api.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Berizco.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Berizco.Api.dll"]

View File

@ -0,0 +1,23 @@
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// 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();
}
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,40 @@
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5062"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_URLS": "http://+:80"
},
"publishAllPorts": true
}
},
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:28470",
"sslPort": 0
}
}
}

View File

@ -0,0 +1,13 @@
namespace Berizco.Api
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,7 @@
namespace Brizco.Infrastructure
{
public class InfrastructureConfig
{
}
}

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Pluralize.NET" Version="1.0.2" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.10" />
<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
<PackageReference Include="StackExchange.Redis.Extensions.Core" Version="9.1.0" />
</ItemGroup>
</Project>

View File

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

72
Berizco.sln 100644
View File

@ -0,0 +1,72 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34018.315
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Berizco.Api", "Berizco.Api\Berizco.Api.csproj", "{9D6CE82C-1BB9-42E7-96B5-6D43AFCF8365}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Brizco.Common", "Brizco.Common\Brizco.Common.csproj", "{351E45E6-873B-40F5-97A2-CC02FB168A3D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Brizco.Domain", "Brizco.Domain\Brizco.Domain.csproj", "{D76A820B-FD40-46AA-93BF-D640F69C4C7E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Brizco.Core", "Brizco.Core\Brizco.Core.csproj", "{305576D6-7440-4153-B6CA-3D65169E4438}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Brizco.Infrastructure", "Berizco.Infrastructure\Brizco.Infrastructure.csproj", "{DE7B8F3D-392B-4C0D-8B70-40CA1F4BB15A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Brizco.Repository", "Berizco.Repository\Brizco.Repository.csproj", "{E170997A-90FF-4179-991F-B5C36746C969}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Brizco.Identity", "Brizco.Identity", "{5B01AC0C-8DFA-400C-8137-984F67227682}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Brizco.Identity.Api", "Brizco.Identity.Api\Brizco.Identity.Api.csproj", "{6E54FD68-0FC8-4252-8F4B-714823C58FAB}"
EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{9FEFFA46-5403-42CD-87A4-9B2AC30BD7B6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9D6CE82C-1BB9-42E7-96B5-6D43AFCF8365}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D6CE82C-1BB9-42E7-96B5-6D43AFCF8365}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D6CE82C-1BB9-42E7-96B5-6D43AFCF8365}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D6CE82C-1BB9-42E7-96B5-6D43AFCF8365}.Release|Any CPU.Build.0 = Release|Any CPU
{351E45E6-873B-40F5-97A2-CC02FB168A3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{351E45E6-873B-40F5-97A2-CC02FB168A3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{351E45E6-873B-40F5-97A2-CC02FB168A3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{351E45E6-873B-40F5-97A2-CC02FB168A3D}.Release|Any CPU.Build.0 = Release|Any CPU
{D76A820B-FD40-46AA-93BF-D640F69C4C7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D76A820B-FD40-46AA-93BF-D640F69C4C7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D76A820B-FD40-46AA-93BF-D640F69C4C7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D76A820B-FD40-46AA-93BF-D640F69C4C7E}.Release|Any CPU.Build.0 = Release|Any CPU
{305576D6-7440-4153-B6CA-3D65169E4438}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{305576D6-7440-4153-B6CA-3D65169E4438}.Debug|Any CPU.Build.0 = Debug|Any CPU
{305576D6-7440-4153-B6CA-3D65169E4438}.Release|Any CPU.ActiveCfg = Release|Any CPU
{305576D6-7440-4153-B6CA-3D65169E4438}.Release|Any CPU.Build.0 = Release|Any CPU
{DE7B8F3D-392B-4C0D-8B70-40CA1F4BB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE7B8F3D-392B-4C0D-8B70-40CA1F4BB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE7B8F3D-392B-4C0D-8B70-40CA1F4BB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE7B8F3D-392B-4C0D-8B70-40CA1F4BB15A}.Release|Any CPU.Build.0 = Release|Any CPU
{E170997A-90FF-4179-991F-B5C36746C969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E170997A-90FF-4179-991F-B5C36746C969}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E170997A-90FF-4179-991F-B5C36746C969}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E170997A-90FF-4179-991F-B5C36746C969}.Release|Any CPU.Build.0 = Release|Any CPU
{6E54FD68-0FC8-4252-8F4B-714823C58FAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E54FD68-0FC8-4252-8F4B-714823C58FAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E54FD68-0FC8-4252-8F4B-714823C58FAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E54FD68-0FC8-4252-8F4B-714823C58FAB}.Release|Any CPU.Build.0 = Release|Any CPU
{9FEFFA46-5403-42CD-87A4-9B2AC30BD7B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9FEFFA46-5403-42CD-87A4-9B2AC30BD7B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9FEFFA46-5403-42CD-87A4-9B2AC30BD7B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9FEFFA46-5403-42CD-87A4-9B2AC30BD7B6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{6E54FD68-0FC8-4252-8F4B-714823C58FAB} = {5B01AC0C-8DFA-400C-8137-984F67227682}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E17C1DB7-407D-4734-9AE4-541062EAF3FA}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MD.PersianDateTime.Standard" Version="2.5.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.32.2" />
</ItemGroup>
<ItemGroup>
<Using Include="MD.PersianDateTime.Standard" />
<Using Include="System.ComponentModel.DataAnnotations" />
<Using Include="System.ComponentModel.DataAnnotations.Schema" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,7 @@
namespace Brizco.Common
{
public class CommonConfig
{
}
}

View File

@ -0,0 +1,30 @@
using System.Collections;
namespace Brizco.Common.Extensions
{
public static class AssertExtensions
{
public static void NotNull<T>(T obj, string name, string message = null)
where T : class
{
if (obj is null)
throw new ArgumentNullException($"{name} : {typeof(T)}", message);
}
public static void NotNull<T>(T? obj, string name, string message = null)
where T : struct
{
if (!obj.HasValue)
throw new ArgumentNullException($"{name} : {typeof(T)}", message);
}
public static void NotEmpty<T>(T obj, string name, string message = null, T defaultValue = null)
where T : class
{
if (obj == defaultValue
|| obj is string str && string.IsNullOrWhiteSpace(str)
|| obj is IEnumerable list && !list.Cast<object>().Any())
throw new ArgumentException("Argument is empty : " + message, $"{name} : {typeof(T)}");
}
}
}

View File

@ -0,0 +1,39 @@
using Brizco.Common.Models.Entity;
namespace Brizco.Common.Extensions
{
public static class ClassDisplayExtensions
{
public static string GetDisplayAttributeName<T>()
{
var attrs =
Attribute.GetCustomAttributes(typeof(T));
foreach (var attr in attrs)
{
var displayAttribute = attr as ClassDisplay;
if (displayAttribute == null)
continue;
return displayAttribute.GetName();
}
return null;
}
public static string GetDisplayAttributeDescription<T>()
{
var attrs =
Attribute.GetCustomAttributes(typeof(T));
foreach (var attr in attrs)
{
var displayAttribute = attr as ClassDisplay;
if (displayAttribute == null)
continue;
return displayAttribute.GetDescription();
}
return null;
}
}
}

View File

@ -0,0 +1,61 @@
using MD.PersianDateTime.Standard;
namespace Brizco.Common.Extensions
{
public static class DateTimeExtensions
{
public static string GetPersianDayOfWeek(this DayOfWeek dayOfWeek)
{
switch (dayOfWeek)
{
case DayOfWeek.Friday:
return "جمعه";
case DayOfWeek.Monday:
return "دوشنبه";
case DayOfWeek.Saturday:
return "شنبه";
case DayOfWeek.Sunday:
return "یکشنبه";
case DayOfWeek.Thursday:
return "پنج شنبه";
case DayOfWeek.Tuesday:
return "سه شنبه";
case DayOfWeek.Wednesday:
return "چهارشنبه";
}
return "";
}
public static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
{
// Unix timestamp is seconds past epoch
var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
dtDateTime = dtDateTime.AddMilliseconds(unixTimeStamp).ToLocalTime();
return dtDateTime;
}
public static long DateTimeToUnixTimeStamp(DateTime dateTime)
{
return ((DateTimeOffset)dateTime).ToUnixTimeMilliseconds();
}
public static int DifferenceByDay(DateTime originDateTime, DateTime destDateTime)
{
return (int)(destDateTime - originDateTime).TotalDays;
}
public static int DifferenceByHoure(DateTime originDateTime, DateTime destDateTime)
{
return (int)(destDateTime - originDateTime).TotalHours;
}
public static TimeSpan Difference(DateTime originDateTime, DateTime destDateTime)
{
var durateion = (destDateTime - originDateTime).Duration();
return durateion;
}
public static PersianDateTime ToPersianDateTime(this DateTime dateTime)
=> new PersianDateTime(dateTime);
}
}

View File

@ -0,0 +1,55 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;
namespace Brizco.Common.Extensions
{
public enum DisplayProperty
{
Description,
GroupName,
Name,
Prompt,
ShortName,
Order
}
public static class EnumExtensions
{
public static IEnumerable<T> GetEnumValues<T>(this T input) where T : struct
{
if (!typeof(T).IsEnum)
throw new NotSupportedException();
return Enum.GetValues(input.GetType()).Cast<T>();
}
public static IEnumerable<T> GetEnumFlags<T>(this T input) where T : struct
{
if (!typeof(T).IsEnum)
throw new NotSupportedException();
foreach (var value in Enum.GetValues(input.GetType()))
if ((input as Enum).HasFlag(value as Enum))
yield return (T)value;
}
public static string ToDisplay(this Enum value, DisplayProperty property = DisplayProperty.Name)
{
AssertExtensions.NotNull(value, nameof(value));
var attribute = value.GetType().GetField(value.ToString())
.GetCustomAttributes<DisplayAttribute>(false).FirstOrDefault();
if (attribute == null)
return value.ToString();
var propValue = attribute.GetType().GetProperty(property.ToString()).GetValue(attribute, null);
return propValue.ToString();
}
public static Dictionary<int, string> ToDictionary(this Enum value)
{
return Enum.GetValues(value.GetType()).Cast<Enum>().ToDictionary(p => Convert.ToInt32(p), q => ToDisplay(q));
}
}
}

View File

@ -0,0 +1,18 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Brizco.Common.Extensions
{
public static class NewtonJsonExtensions
{
public static JsonSerializerSettings CamelCaseSerialize =>
new()
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
},
Formatting = Formatting.Indented
};
}
}

View File

@ -0,0 +1,41 @@
using System.Text.RegularExpressions;
namespace Brizco.Common.Extensions;
public static class PhoneNumberExtensions
{
public static bool CheckPhoneNumber(string phoneNumber)
{
var regex = new Regex(@"(^(989|0989|\+989|09|9)[0-9]{9}$)");
return regex.IsMatch(phoneNumber);
}
public static string GetVerifyFromPhoneNumber(string phoneNumber)
{
var dateTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute / 5, 0);
var timeStamp = ((DateTimeOffset)dateTime).ToUnixTimeMilliseconds() / 10000;
int FTD = int.Parse(string.Format("{0}{1}{2}",
GetSumDigit(int.Parse(string.Format("{0}{1}{2}", phoneNumber[5], phoneNumber[7], phoneNumber[9]))) % 10,
GetSumDigit(int.Parse(string.Format("{0}{1}{2}", phoneNumber[4], phoneNumber[6], phoneNumber[8]))) % 10,
GetSumDigit(int.Parse(string.Format("{0}{1}{2}", phoneNumber[10], phoneNumber[9], phoneNumber[8]))) % 10));
int ATD = GetSumDigit(((int)timeStamp % 1000) + FTD);
timeStamp = (int)timeStamp / 1000;
int BTD = GetSumDigit(((int)timeStamp % 1000) + ATD);
timeStamp = (int)timeStamp / 1000;
int CTD = GetSumDigit(((int)timeStamp % 1000) + ATD);
FTD = GetSumDigit(FTD);
if (ATD % 2 == 0)
return string.Format("{0}{1}{2}{3}", GetSumDigit(ATD) % 10, GetSumDigit(BTD) % 10, GetSumDigit(CTD) % 10, GetSumDigit(FTD) % 10);
else
return string.Format("{0}{1}{2}{3}", ATD % 10, BTD % 10, CTD % 10, FTD % 10);
}
private static int GetSumDigit(int number)
{
string sNumber = number.ToString();
int total = 0;
foreach (var s in sNumber)
total += int.Parse(s.ToString());
return total;
}
}

View File

@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;
namespace Brizco.Common.Extensions
{
public static class PropertyExtensions
{
public static string GetPropertyDisplayName(this MemberInfo propertyExpression)
{
var memberInfo = propertyExpression;
var attr = memberInfo.GetCustomAttributes<DisplayAttribute>().FirstOrDefault();
if (attr == null) return memberInfo.Name;
return attr.Name;
}
}
}

View File

@ -0,0 +1,12 @@
namespace Brizco.Common.Extensions
{
public static class RandomExtensions
{
public static T RandomItem<T>(List<T> originList)
{
var random = new Random(DateTime.Now.Millisecond);
var rand = random.Next(0, originList.Count - 1);
return originList[rand];
}
}
}

View File

@ -0,0 +1,165 @@
namespace Brizco.Common.Extensions
{
public static class StringExtensions
{
public static string ToPriceWhitPriceType(this long price, string priceType)
{
return price.ToString("N0") + " " + priceType;
}
public static string ToPriceWhitPriceType(this decimal price, string priceType)
{
return price.ToString("N0") + " " + priceType;
}
public static string ToPriceWhitPriceType(this double price, string priceType)
{
return price.ToString("N0") + " " + priceType;
}
public static bool HasValue(this string value, bool ignoreWhiteSpace = true)
{
return ignoreWhiteSpace ? !string.IsNullOrWhiteSpace(value) : !string.IsNullOrEmpty(value);
}
public static int ToInt(this string value)
{
return Convert.ToInt32(value);
}
public static decimal ToDecimal(this string value)
{
return Convert.ToDecimal(value);
}
public static string ToNumeric(this int value)
{
return value.ToString("N0"); //"123,456"
}
public static string ToNumeric(this decimal value)
{
return value.ToString("N0");
}
public static string ToCurrency(this int value)
{
//fa-IR => current culture currency symbol => ریال
//123456 => "123,123ریال"
return value.ToString("C0");
}
public static string ToCurrency(this decimal value)
{
return value.ToString("C0");
}
public static string En2Fa(this string str)
{
return str.Replace("0", "۰")
.Replace("1", "۱")
.Replace("2", "۲")
.Replace("3", "۳")
.Replace("4", "۴")
.Replace("5", "۵")
.Replace("6", "۶")
.Replace("7", "۷")
.Replace("8", "۸")
.Replace("9", "۹");
}
public static string Fa2En(this string str)
{
return str.Replace("۰", "0")
.Replace("۱", "1")
.Replace("۲", "2")
.Replace("۳", "3")
.Replace("۴", "4")
.Replace("۵", "5")
.Replace("۶", "6")
.Replace("۷", "7")
.Replace("۸", "8")
.Replace("۹", "9")
//iphone numeric
.Replace("٠", "0")
.Replace("١", "1")
.Replace("٢", "2")
.Replace("٣", "3")
.Replace("٤", "4")
.Replace("٥", "5")
.Replace("٦", "6")
.Replace("٧", "7")
.Replace("٨", "8")
.Replace("٩", "9");
}
public static string FixPersianChars(this string str)
{
return str.Replace("ﮎ", "ک")
.Replace("ﮏ", "ک")
.Replace("ﮐ", "ک")
.Replace("ﮑ", "ک")
.Replace("ك", "ک")
.Replace("ي", "ی")
.Replace(" ", " ")
.Replace("", " ")
.Replace("ھ", "ه"); //.Replace("ئ", "ی");
}
public static string CleanString(this string str)
{
return str.Trim().FixPersianChars().Fa2En().NullIfEmpty();
}
public static string NullIfEmpty(this string str)
{
return str?.Length == 0 ? null : str;
}
public static string GetId(int length = 8)
{
return Guid.NewGuid().ToString("N").Substring(0, length);
}
public static string ConvertTo3Digit(this string str)
{
str = string.Concat(str.Split(','));
var array = str.ToCharArray();
Array.Reverse(array);
str = new string(array);
var newStr = "";
for (var i = 0; i < str.Length; i++)
{
newStr += str[i];
if ((i + 1) % 3 == 0)
newStr += ",";
}
var newarray = newStr.ToCharArray();
Array.Reverse(newarray);
newStr = new string(newarray);
if (newStr.Length > 0 && newStr[0] == ',')
newStr = newStr.Substring(1);
return newStr;
}
public static string ConvertToOrginal(this string str)
{
return string.Concat(str.Split(','));
}
public static string CheckPhoneNumber(string phoneNumber)
{
if (phoneNumber.Substring(0, 3).Contains("+98"))
phoneNumber = phoneNumber.Replace("+98", "0");
else if (phoneNumber.Substring(0, 2).Contains("98"))
phoneNumber = string.Concat("0", phoneNumber.Substring(2));
else if (phoneNumber[0] != '0')
phoneNumber = string.Concat("0", phoneNumber);
return phoneNumber;
}
}
}

View File

@ -0,0 +1,21 @@
namespace Brizco.Common.Extensions
{
public static class ValidationExtensions
{
public static bool CheckDateIs(this DateTime dateTime, DateTime From, DateTime To)
{
if (dateTime.Date > To.Date && dateTime.Date < From.Date)
return true;
return false;
}
public static bool CheckDateFromToNow(this DateTime dateTime, int fromDays = 5)
{
var From = DateTime.Now.AddDays(-fromDays);
var To = DateTime.Now;
if (dateTime.Date > To.Date && dateTime.Date < From.Date)
return true;
return false;
}
}
}

View File

@ -0,0 +1,51 @@
using System.IdentityModel.Tokens.Jwt;
namespace Brizco.Common.Models.Api
{
public class AccessToken
{
public AccessToken()
{
}
public AccessToken(JwtSecurityToken securityToken)
{
access_token = new JwtSecurityTokenHandler().WriteToken(securityToken);
token_type = "Bearer";
expire_in_datetime = securityToken.ValidTo;
expires_in = (int)(securityToken.ValidTo - DateTime.UtcNow).TotalSeconds;
}
public string access_token { get; set; } = string.Empty;
public string refresh_token { get; set; } = string.Empty;
public string token_type { get; set; } = string.Empty;
public int expires_in { get; set; }
public string token_id { get; set; } = string.Empty;
public DateTime expire_in_datetime { get; set; }
public string BearerToken => $"Bearer {access_token}";
}
public class AccessToken<TUser>
{
public AccessToken()
{
}
public AccessToken(JwtSecurityToken securityToken)
{
access_token = new JwtSecurityTokenHandler().WriteToken(securityToken);
token_type = "Bearer";
expires_in = (int)(securityToken.ValidTo - DateTime.UtcNow).TotalSeconds;
}
public string access_token { get; set; } = string.Empty;
public string ig_access_token { get; set; } = string.Empty;
public string refresh_token { get; set; } = string.Empty;
public string token_type { get; set; } = string.Empty;
public int expires_in { get; set; }
public TUser User { get; set; }
public string BearerToken => $"Bearer {access_token}";
public List<string> Permissions { get; set; }
}
}

View File

@ -0,0 +1,42 @@
using System.ComponentModel.DataAnnotations;
using System.Net;
namespace Brizco.Common.Models.Api
{
public enum ApiResultStatusCode
{
[Display(Name = "عملیات با موفقیت انجام شد")]
Success = HttpStatusCode.OK,
[Display(Name = "خطایی در سرور رخ داده است")]
ServerError = HttpStatusCode.InternalServerError,
[Display(Name = "پارامتر های ارسالی معتبر نیستند")]
BadRequest = HttpStatusCode.BadRequest,
[Display(Name = "یافت نشد")]
NotFound = HttpStatusCode.NotFound,
[Display(Name = "لیست خالی است")]
ListEmpty = 4,
[Display(Name = "خطایی در پردازش رخ داد")]
LogicError = 5,
[Display(Name = "موجودی کیف پول کافی نمی باشد")]
WalletBalanceNoEnough = 6,
[Display(Name = "خطای احراز هویت")]
UnAuthorized = HttpStatusCode.Unauthorized,
[Display(Name = "سرور خاموش شده است لطفا منتظر بمانید")]
ServerDown = HttpStatusCode.ServiceUnavailable,
[Display(Name = "در ارسال پیامک مورد نظر مشکلی رخ داده است")]
SendSmsError = 7,
[Display(Name = "در ارسال درخواست به سرورهای دیگر مشکلی رخ داده است")]
RefitError = 8
}
}

View File

@ -0,0 +1,7 @@
namespace Brizco.Common.Models.Api
{
public class AppSettings
{
public bool Seeded { get; set; }
}
}

View File

@ -0,0 +1,15 @@
namespace Brizco.Common.Models.Api
{
public enum FileUploadType
{
Handout,
Video,
Image
}
public class FileUploadRequest
{
public string StringBaseFile { get; set; }
public string FileName { get; set; }
public FileUploadType FileUploadType { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace Brizco.Common.Models.Api
{
public class HealthCheck
{
public bool Health { get; set; }
public string Version { get; set; }
public string TotalMemory { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace Brizco.Common.Models.Api
{
public class ResponseFile
{
public string Url { get; set; }
public string Location { get; set; }
public string Name { get; set; }
}
}

View File

@ -0,0 +1,18 @@
namespace Brizco.Common.Models.Api
{
public class TokenRequest
{
public string grant_type { get; set; }
public string username { get; set; }
public string password { get; set; }
public string refresh_token { get; set; }
public string scope { get; set; }
public string client_id { get; set; }
public string client_secret { get; set; }
public string login_hash { get; set; }
public string device_id { get; set; }
public string license_id { get; set; }
}
}

View File

@ -0,0 +1,11 @@
namespace Brizco.Common.Models.Claims;
public static class ApplicationClaims
{
//public static ClaimDto ManageProducts { get; } = new ClaimDto
//{
// Type = CustomClaimType.Permission,
// Value = ApplicationPermission.ManageProducts,
// Title = "دسترسی کامل به محصولات",
// Detail = "دسترسی به افزودن و مدیریت محصولات فروشگاه شما"
//};
}

View File

@ -0,0 +1,5 @@
namespace Brizco.Common.Models.Claims;
public static class ApplicationPermission
{
//public const string ManageProducts = nameof(ManageProducts);
}

View File

@ -0,0 +1,20 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Security.Claims;
namespace Brizco.Common.Models.Claims;
public class ClaimDto : INotifyPropertyChanged
{
public string Value { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string Detail { get; set; } = string.Empty;
public bool IsSelected { get; set; } = false;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Claim GetClaim => new Claim(Type, Value);
}

View File

@ -0,0 +1,7 @@
namespace Brizco.Common.Models.Claims
{
public static class CustomClaimType
{
public static string Permission { get; } = "Permission";
}
}

View File

@ -0,0 +1,29 @@
namespace Brizco.Common.Models.Entity;
public abstract class ApiEntity : IApiEntity
{
[Key]
public Guid Id { get; set; }
[Display(Name = "تاریخ حذف")]
public DateTime RemovedAt { get; set; }
[Display(Name = "تاریخ ساخت")]
public DateTime CreatedAt { get; set; }
[Display(Name = "ساخته شده توسط")]
public string CreatedBy { get; set; } = string.Empty;
[Display(Name = "حذف شده")]
public bool IsRemoved { get; set; }
[Display(Name = "حذف شده توسط")]
public string RemovedBy { get; set; } = string.Empty;
[Display(Name = "اخرین تغییر در")]
public DateTime ModifiedAt { get; set; }
[Display(Name = "اخرین تغییر توسط")]
public string ModifiedBy { get; set; } = string.Empty;
[NotMapped]
public PersianDateTime CreationPersianDate => new PersianDateTime(CreatedAt);
}

View File

@ -0,0 +1,25 @@
namespace Brizco.Common.Models.Entity
{
[AttributeUsage(AttributeTargets.Class)]
public class ClassDisplay : Attribute
{
private readonly string _description;
private readonly string _name;
public ClassDisplay(string name, string description)
{
_name = name;
_description = description;
}
public string GetName()
{
return _name;
}
public string GetDescription()
{
return _description;
}
}
}

View File

@ -0,0 +1,13 @@
namespace Brizco.Common.Models.Entity
{
public interface IApiEntity
{
string CreatedBy { get; set; }
string ModifiedBy { get; set; }
string RemovedBy { get; set; }
bool IsRemoved { get; set; }
DateTime CreatedAt { get; set; }
DateTime RemovedAt { get; set; }
DateTime ModifiedAt { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using System.Runtime.Serialization;
using Brizco.Common.Models.Api;
namespace Brizco.Common.Models.Exception
{
[Serializable()]
public class AppException : System.Exception
{
protected AppException(SerializationInfo info, StreamingContext context) : base(info, context) { }
public ApiResultStatusCode StatusCode { get; set; }
public AppException()
{
StatusCode = ApiResultStatusCode.ServerError;
}
public AppException(string message) : base(message)
{
StatusCode = ApiResultStatusCode.ServerError;
}
public AppException(string message, ApiResultStatusCode statusCode) : base(message)
{
StatusCode = statusCode;
}
}
}

View File

@ -0,0 +1,91 @@
using System.Net;
using System.Runtime.Serialization;
using Brizco.Common.Models.Api;
namespace Brizco.Common.Models.Exception
{
[Serializable()]
public class BaseApiException : System.Exception
{
protected BaseApiException(SerializationInfo info, StreamingContext context) : base(info, context) { }
public BaseApiException()
: this(ApiResultStatusCode.ServerError)
{
}
public BaseApiException(ApiResultStatusCode statusCode)
: this(statusCode, null)
{
}
public BaseApiException(string message)
: this(ApiResultStatusCode.ServerError, message)
{
}
public BaseApiException(ApiResultStatusCode statusCode, string message)
: this(statusCode, message, HttpStatusCode.InternalServerError)
{
}
public BaseApiException(string message, object additionalData) : this(ApiResultStatusCode.ServerError, message, additionalData)
{
}
public BaseApiException(ApiResultStatusCode statusCode, object additionalData) : this(statusCode, null, additionalData)
{
}
public BaseApiException(ApiResultStatusCode statusCode, string message, object additionalData)
: this(statusCode, message, HttpStatusCode.InternalServerError, additionalData)
{
}
public BaseApiException(ApiResultStatusCode statusCode, string message, HttpStatusCode httpStatusCode)
: this(statusCode, message, httpStatusCode, null)
{
}
public BaseApiException(ApiResultStatusCode statusCode, string message, HttpStatusCode httpStatusCode, object additionalData)
: this(statusCode, message, httpStatusCode, null, additionalData)
{
}
public BaseApiException(string message, System.Exception exception)
: this(ApiResultStatusCode.ServerError, message, exception)
{
}
public BaseApiException(string message, System.Exception exception, object additionalData)
: this(ApiResultStatusCode.ServerError, message, exception, additionalData)
{
}
public BaseApiException(ApiResultStatusCode statusCode, string message, System.Exception exception)
: this(statusCode, message, HttpStatusCode.InternalServerError, exception)
{
}
public BaseApiException(ApiResultStatusCode statusCode, string message, System.Exception exception, object additionalData)
: this(statusCode, message, HttpStatusCode.InternalServerError, exception, additionalData)
{
}
public BaseApiException(ApiResultStatusCode statusCode, string message, HttpStatusCode httpStatusCode, System.Exception exception)
: this(statusCode, message, httpStatusCode, exception, null)
{
}
public BaseApiException(ApiResultStatusCode statusCode, string message, HttpStatusCode httpStatusCode, System.Exception exception, object additionalData)
: base(message, exception)
{
ApiStatusCode = statusCode;
HttpStatusCode = httpStatusCode;
AdditionalData = additionalData;
}
public HttpStatusCode HttpStatusCode { get; set; }
public ApiResultStatusCode ApiStatusCode { get; set; }
public object AdditionalData { get; set; }
}
}

View File

@ -0,0 +1,6 @@
namespace Brizco.Common.Models
{
public interface IScopedDependency
{
}
}

View File

@ -0,0 +1,97 @@
using System.ComponentModel;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using Brizco.Common.Models.Exception;
namespace Brizco.Common.Models.Mapper
{
/// <summary>
/// Base Dto Class initial map config between entity and dto
/// </summary>
/// <typeparam name="TDto">Type of Dto Class</typeparam>
/// <typeparam name="TEntity">Type of Entity Class</typeparam>
public abstract class BaseDto<TDto, TEntity> : INotifyPropertyChanged, IBaseDto<TDto,TEntity> where TEntity : class where TDto : class
{
public int Id { get; set; }
public static Expression<Func<TEntity, TDto>> ProjectToDto
{
get => GetProjectToDto();
}
private static Expression<Func<TEntity, TDto>> GetProjectToDto()
{
var assembly = typeof(TEntity).Assembly;
var mapperName = $"{typeof(TEntity).Name}Mapper";
var mapperType = assembly.GetTypes()?.FirstOrDefault(t => t.Name.Contains(mapperName));
if (mapperType == null)
throw new AppException($"{typeof(TEntity).Name}Mapper Not Found!");
if (typeof(TDto).Name.Contains("SDto"))
{
var projectProperty = mapperType.GetProperty("ProjectToSDto");
if (projectProperty == null)
throw new AppException($"{typeof(TEntity).Name}Mapper Dont Have ProjectTo");
return projectProperty.GetValue(null, null) as Expression<Func<TEntity, TDto>>;
}
else if (typeof(TDto).Name.Contains("LDto"))
{
var projectProperty = mapperType.GetProperty("ProjectToLDto");
if (projectProperty == null)
throw new AppException($"{typeof(TEntity).Name}Mapper Dont Have ProjectTo");
return projectProperty.GetValue(null, null) as Expression<Func<TEntity, TDto>>;
}
else
throw new AppException($"{typeof(TDto).Name} Projection Not Implemented");
}
public virtual bool Compare(object obj)
{
if(obj is BaseDto<TDto,TEntity> objDto)
return objDto.Id == this.Id;
return Equals(obj);
}
public TDto Clone()
{
return (TDto)MemberwiseClone();
}
public TEntity ToEntity()
{
var assembly = typeof(TEntity).Assembly;
var mapperName = $"{typeof(TEntity).Name}Mapper";
var mapperType = assembly.GetTypes()?.FirstOrDefault(t => t.Name.Contains(mapperName));
var toEntityMethodInfo = mapperType.GetMethod($"AdaptTo{typeof(TEntity).Name}");
var parms = new[] { this };
var entity = toEntityMethodInfo.Invoke(null, parms);
if (entity is TEntity o)
return o;
return null;
}
public static TDto FromEntity(TEntity model)
{
var assembly = typeof(TEntity).Assembly;
var mapperName = $"{typeof(TEntity).Name}Mapper";
var mapperType = assembly.GetTypes()?.FirstOrDefault(t => t.Name.Contains(mapperName));
var toDtoMethodInfo = mapperType.GetMethod("AdaptToDto");
var parms = new[] { model };
var dto = toDtoMethodInfo.Invoke(null, parms);
if (dto is TDto o)
return o;
return null;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
}

View File

@ -0,0 +1,11 @@
using System.Linq.Expressions;
namespace Brizco.Common.Models.Mapper
{
public interface IBaseDto<TDto,TEntity>
{
int Id { get; set; }
bool Compare(object obj);
static Expression<Func<TEntity, TDto>> ProjectToDto;
}
}

View File

@ -0,0 +1,38 @@
namespace Brizco.Common.Models.Report
{
public class ChartUnit
{
public List<long> Values { get; set; } = new();
public List<string> ValuesStr
{
get { return Values.Select(v => v.ToString()).ToList(); }
}
public List<string> Labels { get; set; } = new();
}
public class ChartUnitIQuery
{
public IQueryable<long> Values { get; set; }
public List<string> ValuesStr
{
get { return Values.Select(v => v.ToString()).ToList(); }
}
public IQueryable<string> Labels { get; set; }
}
public class ChartUnit<TValue>
{
public List<TValue> Values { get; set; } = new();
public List<string> ValuesStr
{
get { return Values.Select(v => v.ToString()).ToList(); }
}
public List<string> Labels { get; set; } = new();
}
}

View File

@ -0,0 +1,24 @@
namespace Brizco.Common.Models.Report
{
public enum ReportType
{
ByDate,
ByValue,
BySelected
}
public class ReportRequestProp
{
public string PropertyName { get; set; }
public string PropertyValue { get; set; }
}
public class ReportRequest
{
public string TableType { get; set; }
public ReportType ReportType { get; set; }
public DateTime FromDateTime { get; set; }
public DateTime ToDateTime { get; set; }
public List<ReportRequestProp> ReportRequestProps { get; set; } = new();
}
}

View File

@ -0,0 +1,34 @@
namespace Brizco.Common.Models.Report
{
public class ReportResult
{
private List<ReportRow> _rows;
public List<ReportRow> Rows
{
get
{
if (_rows == null)
_rows = new List<ReportRow>();
return _rows;
}
set => _rows = value;
}
}
public class ReportRow
{
private List<string> _cells;
public List<string> Cells
{
get
{
if (_cells == null)
_cells = new List<string>();
return _cells;
}
set => _cells = value;
}
}
}

View File

@ -0,0 +1,89 @@
using System.Collections;
using System.Reflection;
namespace Brizco.Common.Models.Report
{
public interface IReportableItem
{
string Name { get; set; }
string PropertyName { get; set; }
object DefaultValue { get; set; }
object SelectedValue { get; set; }
string ItemType { get; }
object Element { get; set; }
}
public class BoolReportable : IReportableItem
{
public BoolReportable()
{
ItemType = GetType().Name;
}
public string Name { get; set; }
public string PropertyName { get; set; }
public object DefaultValue { get; set; }
public object SelectedValue { get; set; }
public string ItemType { get; }
public object Element { get; set; }
}
public class ListReportable : IReportableItem
{
public ListReportable()
{
ItemType = GetType().Name;
}
public IList List { get; set; }
public IList ConvertedList { get; set; }
public string DisplayMemberPath { get; set; }
public string SelectedMemberPath { get; set; }
public string ListItemType { get; set; }
public string Name { get; set; }
public string PropertyName { get; set; }
public object DefaultValue { get; set; }
public object SelectedValue { get; set; }
public string ItemType { get; }
public object Element { get; set; }
}
public class EnumReportable : IReportableItem
{
public EnumReportable()
{
ItemType = GetType().Name;
}
public string EnumTypeName { get; set; }
public string Name { get; set; }
public string PropertyName { get; set; }
public object DefaultValue { get; set; }
public object SelectedValue { get; set; }
public string ItemType { get; }
public object Element { get; set; }
public Type EnumType(Assembly domainAssembly)
{
var types = domainAssembly.GetTypes();
var type = types.FirstOrDefault(t => t.Name == EnumTypeName);
return type;
}
}
public class NumericReportable : IReportableItem
{
public NumericReportable()
{
ItemType = GetType().Name;
}
public string Name { get; set; }
public string PropertyName { get; set; }
public object DefaultValue { get; set; }
public object SelectedValue { get; set; }
public string ItemType { get; }
public object Element { get; set; }
}
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,7 @@
namespace Brizco.Core
{
public class CoreConfig
{
}
}

View File

@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mapster" Version="7.3.0" />
<PackageReference Include="Mapster.Core" Version="1.2.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="7.0.10" />
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Brizco.Common\Brizco.Common.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Brizco.Common.Models.Entity" />
<Using Include="Brizco.Domain.Enums" />
<Using Include="Microsoft.AspNetCore.Identity" />
<Using Include="System.ComponentModel" />
<Using Include="System.ComponentModel.DataAnnotations" />
<Using Include="System.Runtime.CompilerServices" />
<Using Include="System.Security.Claims" />
</ItemGroup>
<ItemGroup>
<Folder Include="Enums\" />
<Folder Include="Models\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,7 @@
namespace Brizco.Domain
{
public class DomainConfig
{
}
}

View File

@ -0,0 +1,6 @@
namespace Brizco.Domain.Entities;
public class ApplicationRole : IdentityRole<Guid>
{
}

View File

@ -0,0 +1,6 @@
namespace Brizco.Domain.Entities;
public class ApplicationUser : IdentityUser<Guid>
{
}

View File

@ -0,0 +1,8 @@
namespace Brizco.Domain.Entities;
public class Complex : ApiEntity
{
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public string SupportPhone { get; set; } = string.Empty;
}

View File

@ -0,0 +1,11 @@
namespace Brizco.Domain.Entities;
public class ComplexUser : ApiEntity
{
public Guid UserId { get; set; }
public Guid ComplexId { get; set; }
public Guid RoleId { get; set; }
public ApplicationUser? User { get; set; }
public Complex? Complex { get; set; }
}

View File

@ -0,0 +1,10 @@
namespace Brizco.Domain.Entities;
public class Shift : ApiEntity
{
public string Name { get; set; } = string.Empty;
public DayOfWeek DayOfWeek { get; set; }
public string Detail { get; set; } = string.Empty;
public TimeSpan StartAt { get; set; }
public TimeSpan EndAt { get; set; }
}

View File

@ -0,0 +1,5 @@
namespace Brizco.Domain.Entities;
public class SubTask : Task
{
}

View File

@ -0,0 +1,23 @@
using TaskStatus = Brizco.Domain.Enums.TaskStatus;
namespace Brizco.Domain.Entities;
public class Task : ApiEntity
{
public TaskType Type { get; set; }
public string Title { get; set; } = string.Empty;
public string Detail { get; set; } = string.Empty;
public bool IsRelatedToShift { get; set; }
public bool IsRelatedToRole { get; set; }
public bool IsRelatedToPerson { get; set; }
public TaskStatus Status { get; set; }
public bool IsDisposable { get; set; }
public DateTime SetFor { get; set; }
public bool HasDisposed { get; set; }
public int Amount { get; set; }
public PurchaseAmountType AmountType { get; set; }
public virtual ICollection<TaskUser>? TaskUsers { get; set; }
public virtual ICollection<TaskShift>? TaskShifts { get; set; }
public virtual ICollection<TaskRole>? TaskRoles { get; set; }
}

View File

@ -0,0 +1,10 @@
namespace Brizco.Domain.Entities;
public class TaskRole : ApiEntity
{
public Guid RoleId { get; set; }
public virtual ApplicationRole? Role { get; set; }
public Guid TaskId { get; set; }
public virtual Task? Task { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Brizco.Domain.Entities;
public class TaskShift : ApiEntity
{
public Guid TaskId { get; set; }
public virtual Task? Task { get; set; }
public Guid ShiftId { get; set; }
public virtual Shift? Shift { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Brizco.Domain.Entities;
public class TaskUser : ApiEntity
{
public Guid UserId { get; set; }
public virtual ApplicationUser? User { get; set; }
public Guid TaskId { get; set; }
public virtual Task? Task { get; set; }
}

View File

@ -0,0 +1,11 @@
namespace Brizco.Domain.Enums;
public enum PurchaseAmountType
{
[Display(Name = "کلیوگرم")]
Kilogram,
[Display(Name = "عدد")]
Numerical,
[Display(Name = "بسته")]
Pack
}

View File

@ -0,0 +1,13 @@
namespace Brizco.Domain.Enums;
public enum TaskStatus
{
[Display(Name = "ساخته شده")]
Created,
[Display(Name = "در حال انجام")]
InProgress,
[Display(Name = "انجام شده")]
Done,
[Display(Name = "انجام نشده")]
UnDone
}

View File

@ -0,0 +1,7 @@
namespace Brizco.Domain.Enums;
public enum TaskType
{
SubTask,
Purchase
}

View File

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>

View File

@ -0,0 +1,78 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Pluralize.NET" Version="1.0.2" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.7.1" />
<PackageReference Include="MediatR.Extensions.Autofac.DependencyInjection" Version="11.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.8" />
<PackageReference Include="Autofac" Version="7.1.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Serilog" Version="3.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.ElmahIo" Version="5.0.37" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.PostgreSQL" Version="2.3.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.10" />
<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
<PackageReference Include="StackExchange.Redis.Extensions.Core" Version="9.1.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="7.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Brizco.Common\Brizco.Common.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Autofac" />
<Using Include="Autofac.Extensions.DependencyInjection" />
<Using Include="Brizco.Common.Extensions" />
<Using Include="Brizco.Common.Models" />
<Using Include="Brizco.Common.Models.Api" />
<Using Include="Brizco.Identity.Api" />
<Using Include="Brizco.Identity.Api.Domain" />
<Using Include="Brizco.Identity.Api.Domain.Entities" />
<Using Include="Brizco.Identity.Api.Models" />
<Using Include="Brizco.Identity.Api.Services.Contracts" />
<Using Include="Brizco.Identity.Api.WebFramework.Configurations" />
<Using Include="Brizco.Identity.Api.WebFramework.MiddleWares" />
<Using Include="Microsoft.AspNetCore.Identity" />
<Using Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
<Using Include="Microsoft.AspNetCore.Mvc" />
<Using Include="Microsoft.AspNetCore.Mvc.Authorization" />
<Using Include="Microsoft.EntityFrameworkCore" />
<Using Include="Newtonsoft.Json" />
<Using Include="Serilog" />
<Using Include="StackExchange.Redis.Extensions.Core.Configuration" />
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
<Folder Include="Services\Contracts\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,24 @@
using Brizco.Identity.Api.WebFramework.Bases;
using Microsoft.AspNetCore.Authorization;
namespace Brizco.Identity.Api.Controllers.V1;
[ApiController]
[ApiResultFilter]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1")]
[AllowAnonymous]
public class AccountController : ControllerBase
{
private readonly IUserService _userService;
public AccountController(IUserService userService)
{
_userService = userService;
}
[HttpGet]
public async Task<IActionResult> GetUsersAsync(CancellationToken cancellationToken)
{
return Ok(await _userService.GetUsersAsync(cancellationToken));
}
}

View File

@ -0,0 +1,21 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["Brizco.Identity.Api/Brizco.Identity.Api.csproj", "Brizco.Identity.Api/"]
RUN dotnet restore "Brizco.Identity.Api/Brizco.Identity.Api.csproj"
COPY . .
WORKDIR "/src/Brizco.Identity.Api"
RUN dotnet build "Brizco.Identity.Api.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Brizco.Identity.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Brizco.Identity.Api.dll"]

View File

@ -0,0 +1,7 @@
namespace Brizco.Identity.Api.Domain;
public class ApplicationContext : IdentityDbContext<ApplicationUser,ApplicationRole,Guid>
{
public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
{
}
}

View File

@ -0,0 +1,6 @@
namespace Brizco.Identity.Api.Domain.Entities;
public class ApplicationRole : IdentityRole<Guid>
{
public Guid ComplexId { get; set; }
}

View File

@ -0,0 +1,7 @@
namespace Brizco.Identity.Api.Domain.Entities;
public class ApplicationUser : IdentityUser<Guid>
{
}

View File

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>

View File

@ -0,0 +1,279 @@
// <auto-generated />
using System;
using Brizco.Identity.Api.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Brizco.Identity.Api.Migrations
{
[DbContext(typeof(ApplicationContext))]
[Migration("20230830071509_init")]
partial class init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Brizco.Identity.Api.Domain.Entities.ApplicationRole", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("ComplexId")
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Brizco.Identity.Api.Domain.Entities.ApplicationUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<Guid>("RoleId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<Guid>("RoleId")
.HasColumnType("uuid");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,224 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Brizco.Identity.Api.Migrations
{
/// <inheritdoc />
public partial class init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ComplexId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
PhoneNumber = table.Column<string>(type: "text", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RoleId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
RoleId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
LoginProvider = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

View File

@ -0,0 +1,276 @@
// <auto-generated />
using System;
using Brizco.Identity.Api.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Brizco.Identity.Api.Migrations
{
[DbContext(typeof(ApplicationContext))]
partial class ApplicationContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Brizco.Identity.Api.Domain.Entities.ApplicationRole", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("ComplexId")
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Brizco.Identity.Api.Domain.Entities.ApplicationUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<Guid>("RoleId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<Guid>("RoleId")
.HasColumnType("uuid");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.HasOne("Brizco.Identity.Api.Domain.Entities.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,8 @@
namespace Brizco.Identity.Api.Models;
public class JwtSettings
{
public string SecretKey { get; set; } = string.Empty;
public string Audience { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
}

View File

@ -0,0 +1,6 @@
namespace Brizco.Identity.Api.Models;
public class SiteSettings
{
public string BaseUrl { get; set; } = string.Empty;
}

View File

@ -0,0 +1,52 @@
using Brizco.Identity.Api.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.UseSerilog();
LoggerConfig.ConfigureSerilog();
var configuration = builder.Configuration;
var siteSetting = configuration.GetSection(nameof(SiteSettings)).Get<SiteSettings>();
builder.Services.Configure<SiteSettings>(configuration.GetSection(nameof(SiteSettings)));
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddCustomDbContext(configuration);
builder.Services.AddCustomController();
builder.Services.AddCustomSwagger(siteSetting.BaseUrl);
builder.Services.AddCustomCores();
builder.Services.AddCustomIdentity();
builder.Services.AddCustomApiVersioning();
builder.Services.AddDataProtection();
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
var assemblyD = typeof(Program).Assembly;
builder.RegisterAssemblyTypes(assemblyD)
.AssignableTo<IScopedDependency>()
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseCustomSwagger(siteSetting.BaseUrl, builder.Environment);
}
app.UseAuthorization();
app.UseAuthentication();
app.UseExceptionHandlerMiddleware();
app.MapControllers();
app.UseCors("CorsPolicy");
DbInitializerService.InitilizeDB(app);
app.Run();

View File

@ -0,0 +1,41 @@
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5245"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_URLS": "http://+:80"
},
"publishAllPorts": true,
"DockerfileRunArguments": "--network=mother -p 5245:80"
}
},
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:25754",
"sslPort": 0
}
}
}

View File

@ -0,0 +1,6 @@
namespace Brizco.Identity.Api.Services.Contracts;
public interface IDbInitializerService : IScopedDependency
{
void Initialize();
}

View File

@ -0,0 +1,6 @@
namespace Brizco.Identity.Api.Services.Contracts;
public interface IUserService : IScopedDependency
{
Task<List<ApplicationUser>> GetUsersAsync(CancellationToken cancellationToken);
}

View File

@ -0,0 +1,38 @@
namespace Brizco.Identity.Api.Services;
public class DbInitializerService : IDbInitializerService
{
private readonly ApplicationContext _context;
private readonly ILogger<DbInitializerService> _logger;
public DbInitializerService( ApplicationContext context, ILogger<DbInitializerService> logger)
{
_context = context;
_logger = logger;
}
public void Initialize()
{
try
{
_context.Database.Migrate();
_logger.LogInformation("Migration SUCCESS !!!!");
}
catch (Exception e)
{
_logger.LogError(e, e.Message);
}
}
public static void InitilizeDB(IApplicationBuilder app)
{
var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var identityDbInitialize = scope.ServiceProvider.GetService<IDbInitializerService>();
if (identityDbInitialize != null)
{
identityDbInitialize.Initialize();
}
}
}
}

View File

@ -0,0 +1,28 @@
using Brizco.Common.Models.Exception;
namespace Brizco.Identity.Api.Services;
public class UserService : IUserService
{
private readonly UserManager<ApplicationUser> _userManager;
public UserService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task<List<ApplicationUser>> GetUsersAsync(CancellationToken cancellationToken)
{
var res = await _userManager.CreateAsync(new ApplicationUser
{
Email = StringExtensions.GetId(8),
UserName = StringExtensions.GetId(9),
});
if (!res.Succeeded)
{
throw new AppException(res.Errors.ToString());
}
return await _userManager.Users.ToListAsync(cancellationToken);
}
}

View File

@ -0,0 +1,118 @@
namespace Brizco.Identity.Api.WebFramework.Bases
{
public class ApiResult
{
public bool IsSuccess { get; set; }
public ApiResultStatusCode StatusCode { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Message { get; set; }
public ApiResult(bool isSuccess, ApiResultStatusCode statusCode, string message = null)
{
IsSuccess = isSuccess;
StatusCode = statusCode;
Message = message ?? statusCode.ToDisplay();
}
#region Implicit Operators
public static implicit operator ApiResult(OkResult result)
{
return new ApiResult(true, ApiResultStatusCode.Success);
}
public static implicit operator ApiResult(BadRequestResult result)
{
return new ApiResult(false, ApiResultStatusCode.BadRequest);
}
public static implicit operator ApiResult(BadRequestObjectResult result)
{
var message = result.Value.ToString();
if (result.Value is SerializableError errors)
{
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
message = string.Join(" | ", errorMessages);
}
return new ApiResult(false, ApiResultStatusCode.BadRequest, message);
}
public static implicit operator ApiResult(ContentResult result)
{
return new ApiResult(true, ApiResultStatusCode.Success, result.Content);
}
public static implicit operator ApiResult(NotFoundResult result)
{
return new ApiResult(false, ApiResultStatusCode.NotFound);
}
public static implicit operator ApiResult(ForbidResult result)
{
return new ApiResult(false, ApiResultStatusCode.NotFound);
}
public static implicit operator ApiResult(StatusCodeResult result)
{
return new ApiResult(false, ApiResultStatusCode.NotFound);
}
#endregion
}
public class ApiResult<TData> : ApiResult
where TData : class
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public TData Data { get; set; }
public ApiResult(bool isSuccess, ApiResultStatusCode statusCode, TData data, string message = null)
: base(isSuccess, statusCode, message)
{
Data = data;
}
#region Implicit Operators
public static implicit operator ApiResult<TData>(TData data)
{
return new ApiResult<TData>(true, ApiResultStatusCode.Success, data);
}
public static implicit operator ApiResult<TData>(OkResult result)
{
return new ApiResult<TData>(true, ApiResultStatusCode.Success, null);
}
public static implicit operator ApiResult<TData>(OkObjectResult result)
{
return new ApiResult<TData>(true, ApiResultStatusCode.Success, (TData)result.Value);
}
public static implicit operator ApiResult<TData>(BadRequestResult result)
{
return new ApiResult<TData>(false, ApiResultStatusCode.BadRequest, null);
}
public static implicit operator ApiResult<TData>(BadRequestObjectResult result)
{
var message = result.Value.ToString();
if (result.Value is SerializableError errors)
{
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
message = string.Join(" | ", errorMessages);
}
return new ApiResult<TData>(false, ApiResultStatusCode.BadRequest, null, message);
}
public static implicit operator ApiResult<TData>(ContentResult result)
{
return new ApiResult<TData>(true, ApiResultStatusCode.Success, null, result.Content);
}
public static implicit operator ApiResult<TData>(NotFoundResult result)
{
return new ApiResult<TData>(false, ApiResultStatusCode.NotFound, null);
}
public static implicit operator ApiResult<TData>(NotFoundObjectResult result)
{
return new ApiResult<TData>(false, ApiResultStatusCode.NotFound, (TData)result.Value);
}
#endregion
}
}

View File

@ -0,0 +1,72 @@
using Microsoft.AspNetCore.Mvc.Filters;
namespace Brizco.Identity.Api.WebFramework.Bases
{
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,26 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
namespace Brizco.Identity.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"];
if (!string.IsNullOrEmpty(accessToken))
{
context.Token = accessToken;
}
}
};
}
}
}

View File

@ -0,0 +1,24 @@
using Serilog;
using Serilog.Events;
using Serilog.Sinks.ElmahIo;
using Serilog.Sinks.SystemConsole.Themes;
namespace Brizco.Identity.Api.WebFramework.Configurations
{
public static class LoggerConfig
{
public static void ConfigureSerilog()
{
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.ElmahIo(new ElmahIoSinkOptions("279e90cbf4da4814a971a33df23ebd1e", new Guid("7fb24511-87b1-414e-933a-006f67e97ffc"))
{
MinimumLogEventLevel = LogEventLevel.Warning,
})
.WriteTo.Console(theme: AnsiConsoleTheme.Literate)
.CreateLogger();
}
}
}

View File

@ -0,0 +1,27 @@
namespace Brizco.Identity.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,145 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace Brizco.Identity.Api.WebFramework.Configurations
{
public static class ServiceExtensions
{
public static void AddCustomDbContext(this IServiceCollection serviceCollection, IConfigurationRoot Configuration)
{
serviceCollection.AddDbContext<ApplicationContext>(options =>
{
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
options.UseNpgsql(Configuration.GetConnectionString("Postgres"), b => b.MigrationsAssembly("Brizco.Identity.Api"));
options.EnableServiceProviderCaching(false);
}, ServiceLifetime.Scoped);
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", 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 AddCustomApiVersioning(this IServiceCollection serviceCollection)
{
serviceCollection.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ReportApiVersions = true;
});
}
public static void AddCustomController(this IServiceCollection serviceCollection)
{
serviceCollection.AddControllers(options => { options.Filters.Add(new AuthorizeFilter()); })
.AddControllersAsServices()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}
);
}
public static void AddJwtCustomAuthentication(this IServiceCollection serviceCollection, JwtSettings jwtSettings)
{
serviceCollection.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(IdentityConstants.ApplicationScheme, options =>
{
})
.AddCookie(IdentityConstants.TwoFactorUserIdScheme, options =>
{
})
.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.IncludeErrorDetails = true;
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
if (!string.IsNullOrEmpty(accessToken))
context.Token = accessToken.ToString();
var videoStorageOrigin = context.Request.Headers["X-Original-URI"].ToString();
var videoToken = videoStorageOrigin.Split("?access_token=").Last();
if (!string.IsNullOrEmpty(videoToken))
context.Token = videoToken;
return Task.CompletedTask;
},
OnForbidden = context =>
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
},
OnChallenge = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
}
};
});
}
public static void AddCustomIdentity(this IServiceCollection serviceCollection)
{
serviceCollection.AddIdentityCore<ApplicationUser>(options =>
{
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.User.RequireUniqueEmail = false;
})
.AddRoles<ApplicationRole>()
.AddSignInManager<SignInManager<ApplicationUser>>()
.AddEntityFrameworkStores<ApplicationContext>()
.AddDefaultTokenProviders()
.AddErrorDescriber<PersianIdentityErrorDescriber>();
}
}
}

View File

@ -0,0 +1,339 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Pluralize.NET;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
namespace Brizco.Identity.Api.WebFramework.Configurations;
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 = "MCAS-Online Api Dacument",
Description = "MCAS-Online 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/v1/Auth/LoginSwagger";
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n
Enter 'Bearer' [space] and then your token in the text input below.
\r\n\r\nExample: 'Bearer 12345abcdef'",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
});
// options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme
// {
// In = ParameterLocation.Header,
// Description = "Please enter token",
// Name = "Authorization",
// Type = SecuritySchemeType.Http,
// BearerFormat = "JWT",
// Scheme = "bearer"
// });
// options.AddSecurityRequirement(new OpenApiSecurityRequirement
//{
// {
// new OpenApiSecurityScheme
// {
// Reference = new OpenApiReference
// {
// Type=ReferenceType.SecurityScheme,
// Id="Bearer"
// }
// },
// new string[]{}
// }
//});
//options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
//{
// Type = SecuritySchemeType.OAuth2,
// Scheme = "Bearer",
// Name = "Authorization",
// In = ParameterLocation.Header,
// 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, IWebHostEnvironment env)
{
app.UseSwagger(options =>
{
options.SerializeAsV2 = true;
});
app.UseSwaggerUI(options =>
{
//var sidebar = Path.Combine(env.ContentRootPath, "wwwroot/assets/swagger-ui/customSidebar.html");
//options.HeadContent = File.ReadAllText(sidebar);
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.OAuthClientId("clientname");
options.OAuthRealm("your-realm");
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) return;
var pluralizer = new Pluralizer();
var actionName = controllerActionDescriptor.ActionName;
var singularizeName = pluralizer.Singularize(controllerActionDescriptor.ControllerName);
var pluralizeName = pluralizer.Pluralize(singularizeName);
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
}
}

View File

@ -0,0 +1,182 @@
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using Brizco.Common.Models.Exception;
using Brizco.Identity.Api.WebFramework.Bases;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Serialization;
namespace Brizco.Identity.Api.WebFramework.MiddleWares
{
public static class ExceptionHandlerMiddlewareExtensions
{
public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder applicationBuilder)
{
return applicationBuilder.UseMiddleware<ExceptionHandlerMiddleware>();
}
}
public class ExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly IWebHostEnvironment _env;
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
public ExceptionHandlerMiddleware(
RequestDelegate next,
IWebHostEnvironment env,
ILogger<ExceptionHandlerMiddleware> logger)
{
_next = next;
_env = env;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
string message = null;
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
ApiResultStatusCode 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));
DefaultContractResolver contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
message = JsonConvert.SerializeObject(dic, new JsonSerializerSettings
{
ContractResolver = contractResolver,
Formatting = Formatting.Indented
});
}
else
{
message = exception.Message;
}
await WriteToResponseAsync();
}
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 (Exception exception)
{
_logger.LogError(exception, exception.Message);
if (_env.IsDevelopment())
{
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);
DefaultContractResolver contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
string 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,17 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"DockerCompose": "Host=pg_0;Username=berzco;Password=berzco;Database=BrizcoIdentityDB;",
"Postgres": "Host=pg-0,pg-1;Username=postgres;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=BrizcoIdentityDB;Load Balance Hosts=true;Target Session Attributes=primary"
},
"SiteSettings": {
"BaseUrl": "http://localhost:5245"
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

28
NuGet.config 100644
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key='maxHttpRequestsPerSource' value='10' />
</config>
<packageSources>
<clear />
<add key="VnfRepos" value="https://packages.vnfco.ir/repository/nuget-group/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
<packageSourceCredentials>
<VnfRepos>
<add key="Username" value="runner" />
<add key="ClearTextPassword" value="22102210aA" />
</VnfRepos>
</packageSourceCredentials>
</configuration>
<!-- <configuration>
<config>
<add key='maxHttpRequestsPerSource' value='10' />
</config>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration> -->

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
<PropertyGroup Label="Globals">
<ProjectVersion>2.1</ProjectVersion>
<DockerTargetOS>Linux</DockerTargetOS>
<ProjectGuid>9feffa46-5403-42cd-87a4-9b2ac30bd7b6</ProjectGuid>
<DockerLaunchAction>LaunchBrowser</DockerLaunchAction>
<DockerServiceUrl>{Scheme}://localhost:{ServicePort}/swagger</DockerServiceUrl>
<DockerServiceName>berizco.api</DockerServiceName>
</PropertyGroup>
<ItemGroup>
<None Include="docker-compose.override.yml">
<DependentUpon>docker-compose.yml</DependentUpon>
</None>
<None Include="docker-compose.yml" />
<None Include=".dockerignore" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,15 @@
version: '3.4'
services:
brizco.identity.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "80"
berizco.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "80"

42
docker-compose.yml 100644
View File

@ -0,0 +1,42 @@
version: '3.4'
networks:
brizco:
driver: bridge
services:
brizco.identity.api:
image: ${DOCKER_REGISTRY-}brizcoidentityapi
depends_on:
- "postgres_image"
build:
context: .
dockerfile: Brizco.Identity.Api/Dockerfile
ports:
- "5245:80"
networks:
- brizco
berizco.api:
image: ${DOCKER_REGISTRY-}berizcoapi
build:
context: .
dockerfile: Berizco.Api/Dockerfile
postgres_image:
image: postgres:latest
ports:
- "5432"
restart: always
volumes:
- db:/var/lib/postgresql/data
environment:
POSTGRES_USER: "berzco"
POSTGRES_PASSWORD: "berzco"
POSTGRES_DB: "berzcoDB"
networks:
- brizco
volumes:
db:
driver: local

View File

@ -0,0 +1,12 @@
{
"profiles": {
"Docker Compose": {
"commandName": "DockerCompose",
"commandVersion": "1.0",
"serviceActions": {
"berizco.api": "StartDebugging",
"brizco.identity.api": "StartDebugging"
}
}
}
}