Compare commits
34
Commits
40515d0e3a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a9316ed6f | ||
|
|
f3b1d901a8 | ||
|
|
df7e8827be | ||
|
|
2e477ca023 | ||
|
|
5292b99af6 | ||
|
|
3d83e95613 | ||
|
|
75b49be476 | ||
|
|
ba4976fce4 | ||
|
|
4eafa2fa8d | ||
|
|
70083f1230 | ||
|
|
9070bebb54 | ||
|
|
5d2e989ee9 | ||
|
|
ce2b3ba8c9 | ||
|
|
c9228950d5 | ||
|
|
2e7f9e7a27 | ||
|
|
d656229ab3 | ||
|
|
fa3b289a77 | ||
|
|
09ac6c6bb1 | ||
|
|
8228ff27b8 | ||
|
|
c0bc89083d | ||
|
|
fb751ecbc3 | ||
|
|
d4543b5169 | ||
|
|
adf62c8dcc | ||
|
|
936094a4bf | ||
|
|
4c19ec3e6a | ||
|
|
8eccd04332 | ||
|
|
a449028e90 | ||
|
|
2e81082615 | ||
|
|
7744dc3680 | ||
|
|
1681f48bbf | ||
|
|
d57751eefa | ||
|
|
817eee7d3e | ||
|
|
9173d551f4 | ||
|
|
3ba26bee33 |
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
|
||||
{
|
||||
"name": "C#: FamilyTreeAPI",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/FamilyTreeAPI/bin/Debug/net10.0/FamilyTreeAPI.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"stopAtEntry": false,
|
||||
"console": "internalConsole",
|
||||
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_URLS": "http://localhost:5019"
|
||||
},
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)",
|
||||
"uriFormat": "%s/swagger/index.html"
|
||||
},
|
||||
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
},
|
||||
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Launch (web) - Release",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "publish",
|
||||
"program": "${workspaceFolder}/FamilyTreeAPI/bin/Release/net10.0/linux-x64/FamilyTreeAPI.dll",
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "listening on:\\s+(https?://\\S+)",
|
||||
"uriFormat": "%s/swagger/index.html"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Production",
|
||||
"ASPNETCORE_URLS": "https://localhost:5019"
|
||||
},
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/FamilyTreeAPI/FamilyTreeAPI.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/FamilyTreeAPI/FamilyTreeAPI.csproj",
|
||||
"-c",
|
||||
"Release"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34202.233
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
|
||||
@@ -3,6 +3,7 @@ using FamilyTreeAPI.Repository;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers;
|
||||
|
||||
using DocumentFormat.OpenXml.Drawing.Charts;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
@@ -110,14 +111,44 @@ public class FileUploadController : ControllerBase
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> DownloadPersonPhotoById(DeleteCriteria<int> criteria)
|
||||
{
|
||||
|
||||
var result = await _personPhoto.DownloadPersonPhotoById(criteria.Id);
|
||||
if (result.StatusCode > 0)
|
||||
return File(result.Data.Content, result.Data.ContentType, result.Data.FileName);
|
||||
else
|
||||
return NotFound("not found image");
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> DownloadPersonPhoto(DownloadFileCriteria criteria)
|
||||
{
|
||||
|
||||
var result = await _personPhoto.DownloadPersonPhoto(criteria.Id, criteria.FileName);
|
||||
|
||||
var result = await _personPhoto.DownloadPersonPhotoPerson(criteria.Id,criteria.PhotoType ,criteria.FileName);
|
||||
if (result.StatusCode > 0)
|
||||
return File(result.Data.Content, result.Data.ContentType, result.Data.FileName);
|
||||
else
|
||||
return NotFound("not found image");
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> DownloadPersonPhoto64(DownloadFileCriteria criteria)
|
||||
{
|
||||
|
||||
var result = await _personPhoto.DownloadPersonPhotoPerson(criteria.Id,criteria.PhotoType ,criteria.FileName);
|
||||
if (result.StatusCode > 0)
|
||||
{
|
||||
byte[] file64 = result.Data.Content;
|
||||
string rval = Convert.ToBase64String(file64);
|
||||
ResultModel<string> retval = new() {
|
||||
Data = rval,
|
||||
StatusCode = 1,
|
||||
Message = ""
|
||||
};
|
||||
return Ok(retval);
|
||||
}
|
||||
else
|
||||
return NotFound("not found image");
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<ActionResult> DeletePersonPhoto(DeleteFileCriteria criteria)
|
||||
@@ -127,8 +158,18 @@ public class FileUploadController : ControllerBase
|
||||
if ( criteria.Id > 0)
|
||||
{
|
||||
|
||||
ret = await _personPhoto.DeletePersonPhoto(criteria.Id);
|
||||
ret = await _personPhoto.DeletePersonPhoto(criteria.Id, criteria.PhotoType);
|
||||
}
|
||||
return Ok(ret);
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<ActionResult> DeletePersonPhotoById(DeleteCriteria<int> criteria)
|
||||
{
|
||||
|
||||
ResultModel<int> ret = new();
|
||||
|
||||
ret = await _personPhoto.DeletePersonPhotoById(criteria.Id);
|
||||
|
||||
return Ok(ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace FamilyTreeAPI.Controllers
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> UploadImage(IFormFile file)
|
||||
{
|
||||
|
||||
@@ -37,8 +37,25 @@ public class UsersController : ControllerBase
|
||||
public async Task<IActionResult> LoginApiAD([FromBody] AuthenticateRequest model)
|
||||
{
|
||||
string remoteIpAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
var response = await _userService.LoginApiAD(model, remoteIpAddress);
|
||||
return Ok(response);
|
||||
var rval = await _userService.LoginApiAD(model, remoteIpAddress);
|
||||
if (rval.Data != null && rval.Data.Token != null)
|
||||
{
|
||||
// Configure cookie options
|
||||
|
||||
var cookieOptions = new CookieOptions
|
||||
{
|
||||
HttpOnly = true, // Blocks client-side JavaScript reading/theft
|
||||
Secure = false, // Requires HTTPS connections
|
||||
SameSite = SameSiteMode.Unspecified, // Prevents CSRF attacks
|
||||
Expires = DateTimeOffset.UtcNow.AddDays(1), // Match your token lifespan
|
||||
Path = "/" // Accessible across entire domain structure
|
||||
};
|
||||
|
||||
// Write cookie into response headers
|
||||
Response.Cookies.Append("token", rval.Data.Token, cookieOptions);
|
||||
}
|
||||
return Ok(rval);
|
||||
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
@@ -51,6 +68,14 @@ public class UsersController : ControllerBase
|
||||
string token = Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
string remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();
|
||||
var response = await _userService.Logout(token, currentUser, remoteIpAddress);
|
||||
Response.Cookies.Delete("token", new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
Secure = false,
|
||||
SameSite = SameSiteMode.Unspecified,
|
||||
Path = "/"
|
||||
});
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
||||
#FROM mcr.microsoft.com/dotnet/aspnet:9::.0 AS base
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["FamilyTreeAPI/FamilyTreeAPI.csproj", "FamilyTreeAPI/"]
|
||||
RUN dotnet restore "./FamilyTreeAPI/FamilyTreeAPI.csproj"
|
||||
@@ -31,7 +31,7 @@ FROM build AS publish
|
||||
RUN dotnet publish "./FamilyTreeAPI.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||
WORKDIR /app
|
||||
ENV ASPNETCORE_HTTP_PORTS=8080
|
||||
EXPOSE 8080
|
||||
|
||||
@@ -4,9 +4,9 @@ public class AppSettings
|
||||
{
|
||||
public string Secret { get; set; }
|
||||
public string SQLConnectionString { get; set; }
|
||||
public string LoginWebAPI { get; set; }
|
||||
public string ImageFolder { get; set; }
|
||||
|
||||
public string ClientURL { get; set; }
|
||||
public string ImportFolder { get; set; }
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,16 +15,19 @@ public class DownloadFileCriteria
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PhotoType {get; set;}
|
||||
}
|
||||
public class UploadCriteria
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public int PersonId { get; set; }
|
||||
|
||||
public int PhotoType {get; set;}
|
||||
public IFormFile File { get; set; }
|
||||
}
|
||||
public class DeleteFileCriteria
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Filename { get; set; }
|
||||
public int PhotoType {get; set;}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
|
||||
//photo Type string number
|
||||
public enum enumPhotoType
|
||||
{
|
||||
Profile = 1,
|
||||
Other = 2
|
||||
}
|
||||
public class PersonPhotoDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
@@ -1,38 +1,41 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
<AllowMissingPrunePackageData>true</AllowMissingPrunePackageData>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Models_old\**" />
|
||||
<Content Remove="Models_old\**" />
|
||||
<EmbeddedResource Remove="Models_old\**" />
|
||||
<None Remove="Models_old\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HotChocolate.AspNetCore" Version="15.1.6" />
|
||||
<PackageReference Include="HotChocolate.Data.EntityFramework" Version="15.1.6" />
|
||||
<PackageReference Include="HotChocolate.Pagination.EntityFramework" Version="14.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
||||
<PackageReference Include="HotChocolate.AspNetCore" Version="16.6.1" />
|
||||
<PackageReference Include="HotChocolate.Data.EntityFramework" Version="16.6.1" />
|
||||
<PackageReference Include="HotChocolate.Pagination.EntityFramework" Version="14.3.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.11">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.11">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.3" />
|
||||
<PackageReference Include="SpreadsheetLight" Version="3.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="10.0.11" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="appsettings.Development.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Helpers
|
||||
{
|
||||
public static string GetFileExtension(string fileName)
|
||||
{
|
||||
string result = System.IO.Path.GetExtension(fileName);
|
||||
|
||||
return result;
|
||||
}
|
||||
public static string GetFileContent(string extension)
|
||||
{
|
||||
string contentType = "";
|
||||
|
||||
@@ -71,6 +71,10 @@ $ sudo nano /etc/nginx/sites-avaible/default
|
||||
After adding the content, save it. Then let’s enable and start the service:
|
||||
sudo systemctl enable kestrel-app.service
|
||||
sudo systemctl start kestrel-app.service
|
||||
put familytreeapp.conf
|
||||
|
||||
put in /etc/nginx/sites-availalble/familytreeapp.conf
|
||||
$) sudo ln -s /etc/nginx/sites-available/familytreeapp.conf /etc/nginx/sites-enabled/
|
||||
|
||||
postgresql.conf:
|
||||
|
||||
@@ -105,3 +109,6 @@ $ sudo nano /etc/nginx/sites-avaible/default
|
||||
docker run -p 5432:5432 -e POSTGRES_PASSWORD=123456789 \
|
||||
-d postgres:9.3.6 \
|
||||
-c config_file=/path/to/postgresql.conf
|
||||
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ namespace FamilyTreeAPI.Interface;
|
||||
public interface IPersonPhoto
|
||||
{
|
||||
Task<ResultModel<int>> SaveAsync(UploadCriteria criteria);
|
||||
Task<ResultModel<FileContent>> DownloadPersonPhoto(int id, string? filename);
|
||||
|
||||
Task<ResultModel<int>> DeletePersonPhoto(int id);
|
||||
Task<ResultModel<FileContent>> DownloadPersonPhotoPerson(int personId, int photoType, string filename);
|
||||
Task<ResultModel<FileContent>> DownloadPersonPhotoById(int id);
|
||||
Task<ResultModel<int>> DeletePersonPhoto(int id, int photoType);
|
||||
Task<ResultModel<int>> DeletePersonPhotoById(int id);
|
||||
Task<ResultModel<List<PersonPhotoDto>>> LoadPersonPhoto(int personId);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text;
|
||||
using DocumentFormat.OpenXml.Office2010.Drawing.Charts;
|
||||
using FamilyTreeAPI.Authorization;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.GraphQL.Query;
|
||||
@@ -14,6 +13,15 @@ using FamilyTreeAPI.Repository;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Logging.AddConsole();
|
||||
builder.Logging.AddDebug();
|
||||
// Explicitly register the base paths for Linux container execution
|
||||
builder.Configuration
|
||||
.SetBasePath(AppContext.BaseDirectory) // <-- Pulls from wherever the binary sits
|
||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true)
|
||||
.AddEnvironmentVariables();
|
||||
// Add services to the container.
|
||||
#region Services
|
||||
var services = builder.Services;
|
||||
@@ -22,11 +30,26 @@ services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
services.AddEndpointsApiExplorer();
|
||||
services.AddSwaggerGen();
|
||||
string skey = "Super Secret SIGN AND VERIFY JWT TOKENS";
|
||||
|
||||
|
||||
var appSettingsSection = builder.Configuration.GetSection("AppSettings");
|
||||
services.Configure<AppSettings>(appSettingsSection);
|
||||
var appSettings = appSettingsSection.Get<AppSettings>();
|
||||
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
|
||||
if (appSettingsSection.Exists())
|
||||
{
|
||||
services.Configure<AppSettings>(appSettingsSection);
|
||||
var appSettings = appSettingsSection.Get<AppSettings>();
|
||||
if ( appSettings != null)
|
||||
skey = appSettings.Secret;
|
||||
else
|
||||
{
|
||||
string tkey = builder.Configuration.GetValue<string>("AppSettings:Secret") ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty(tkey))
|
||||
skey = tkey;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var key = Encoding.ASCII.GetBytes(skey);
|
||||
|
||||
services.AddAuthentication(x =>
|
||||
{
|
||||
@@ -103,10 +126,7 @@ using (var scope = app.Services.CreateScope())
|
||||
var db = context.Database;
|
||||
if (db != null)
|
||||
{
|
||||
|
||||
db.Migrate();
|
||||
db.EnsureCreated();
|
||||
var staff = context.GetService<Seed>();
|
||||
var staff = scope.ServiceProvider.GetService<Seed>();
|
||||
int id = staff.InsertOneUser();
|
||||
if (id < 0)
|
||||
{
|
||||
@@ -114,23 +134,34 @@ using (var scope = app.Services.CreateScope())
|
||||
if (databaseCreator != null)
|
||||
{
|
||||
//if (!databaseCreator.Exists())
|
||||
try
|
||||
{
|
||||
// Check if database exists
|
||||
if (!databaseCreator.Exists())
|
||||
{
|
||||
databaseCreator.Create();
|
||||
}
|
||||
|
||||
if (!databaseCreator.HasTables())
|
||||
{
|
||||
databaseCreator.CreateTables();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//continue
|
||||
}
|
||||
}
|
||||
id = staff.InsertOneUser();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
app.UseMiddleware<JwtMiddleware>();
|
||||
// Configure the HTTP request pipeline.
|
||||
//if (app.Environment.IsDevelopment())//
|
||||
@@ -156,6 +187,17 @@ app.Run();
|
||||
#endregion
|
||||
|
||||
/*
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="appsettings.Development.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
https://www.youtube.com/watch?v=WQFx2m5Ub9M
|
||||
|
||||
|
||||
@@ -171,14 +213,43 @@ PM> Scaffold-DbContext "Host=postgresdb;Port=5432;database=FamilyTreeDB;user id=
|
||||
https://www.youtube.com/watch?v=HnXA8RI7Tvc
|
||||
|
||||
query {
|
||||
family {
|
||||
persons {
|
||||
nodes{
|
||||
id
|
||||
firstname
|
||||
lastname
|
||||
firstName
|
||||
sex
|
||||
email
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dotnet --list-sdks
|
||||
|
||||
In the VS Code Explorer, click and open your <ProjectName>.csproj file.
|
||||
Locate the <TargetFramework> tag inside the <PropertyGroup> block.
|
||||
Change the value to your desired version (e.g., change net11.0 or net9.0 to net10.0
|
||||
|
||||
now run to see out of date
|
||||
|
||||
dotnet list package --outdated
|
||||
|
||||
dotnet tool uninstall --global dotnet-outdated
|
||||
dotnet tool install --global dotnet-outdated-tool
|
||||
|
||||
//update the outdate
|
||||
dotnet outdated -u
|
||||
|
||||
update the package
|
||||
dotnet add package <Package_Name>
|
||||
|
||||
Open the .vscode folder in your workspace and select launch.json.
|
||||
Look for lines containing your old framework directory string (e.g., /bin/Debug/net8.0/).
|
||||
Update those paths to reflect your new version (e.g., /bin/Debug/net9.0/).
|
||||
|
||||
clear and rebuild
|
||||
|
||||
dotnet clean
|
||||
dotnet restore
|
||||
dotnet build
|
||||
*/
|
||||
@@ -8,35 +8,17 @@
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "http://localhost:5016",
|
||||
"applicationUrl1": "http://192.168.8.188:5015"
|
||||
"applicationUrl": "http://localhost:5016"
|
||||
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Container (Dockerfile)": {
|
||||
"commandName": "Docker",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_HTTP_PORTS": "8080"
|
||||
},
|
||||
"publishAllPorts": true,
|
||||
"useSSL": false
|
||||
}
|
||||
"applicationUrl": "http://localhost:5000"
|
||||
},
|
||||
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:4559",
|
||||
"sslPort": 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ namespace FamilyTreeAPI.Repository
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
Lookup model = null!;
|
||||
FamilyTreeAPI.Models.Lookup model = null!;
|
||||
bool ok = !checkDescription(desc, lookup.Type, lookup.Id);
|
||||
if (ok)
|
||||
{
|
||||
@@ -52,7 +52,7 @@ namespace FamilyTreeAPI.Repository
|
||||
}
|
||||
else
|
||||
{
|
||||
Lookup? model1 = await _context.Lookups.FindAsync(lookup.Id);
|
||||
FamilyTreeAPI.Models.Lookup? model1 = await _context.Lookups.FindAsync(lookup.Id);
|
||||
if (model1 != null)
|
||||
{
|
||||
model1.Description = desc;
|
||||
|
||||
@@ -3,6 +3,7 @@ using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Helper;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Models;
|
||||
using HotChocolate.CostAnalysis.Types;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FamilyTreeAPI.Repository
|
||||
@@ -31,12 +32,12 @@ namespace FamilyTreeAPI.Repository
|
||||
dto.PhotoType = model.PhotoType;
|
||||
return dto;
|
||||
}
|
||||
private PersonPhoto FillModel(PersonPhoto model, int personId, string filename)
|
||||
private PersonPhoto FillModel(PersonPhoto model, int personId, int photoType, string filename)
|
||||
{
|
||||
|
||||
model.PersonId = personId;
|
||||
model.Photo = filename;
|
||||
model.PhotoType = System.IO.Path.GetExtension(filename);
|
||||
model.PhotoType = photoType.ToString(); //System.IO.Path.GetExtension(filename);
|
||||
|
||||
return model;
|
||||
}
|
||||
@@ -44,8 +45,10 @@ namespace FamilyTreeAPI.Repository
|
||||
{
|
||||
int result = default(int);
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
|
||||
string error = "";//Other
|
||||
string photoType = "2"; //
|
||||
if (criteria.PhotoType > 0)
|
||||
photoType = criteria.PhotoType.ToString();
|
||||
HttpContext? httpContext = _httpContext.HttpContext;
|
||||
string loginName = "";
|
||||
if (httpContext != null)
|
||||
@@ -63,7 +66,7 @@ namespace FamilyTreeAPI.Repository
|
||||
|
||||
model = new();
|
||||
|
||||
model = FillModel(model,criteria.PersonId, formfile.FileName);
|
||||
model = FillModel(model,criteria.PersonId, criteria.PhotoType,formfile.FileName);
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
@@ -72,6 +75,7 @@ namespace FamilyTreeAPI.Repository
|
||||
}
|
||||
_context.PersonPhotos.Add(model);
|
||||
await _context.SaveChangesAsync();
|
||||
result = model.Id;
|
||||
|
||||
statuscode = 1;
|
||||
|
||||
@@ -89,15 +93,50 @@ namespace FamilyTreeAPI.Repository
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<FileContent>> DownloadPersonPhoto(int id, string? filename)
|
||||
public async Task<ResultModel<FileContent>> DownloadPersonPhotoById(int Id)
|
||||
{
|
||||
|
||||
int statusCode = -1;
|
||||
string error = "";
|
||||
string extension = "";
|
||||
PersonPhoto? model = null;
|
||||
FileContent fileContent = new();
|
||||
if (id < 1)
|
||||
try {
|
||||
|
||||
model = await _context.PersonPhotos.FindAsync(Id);
|
||||
|
||||
|
||||
if (model != null)
|
||||
{
|
||||
extension = Helpers.GetFileExtension(model.Photo);
|
||||
fileContent.ContentType = Helpers.GetFileContent(extension);
|
||||
fileContent.Content = (byte[])model.ImagePhoto;
|
||||
fileContent.FileName = model.Photo;
|
||||
statusCode = 1;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = e.ToString();
|
||||
statusCode = -1;
|
||||
}
|
||||
return new ResultModel<FileContent>()
|
||||
{
|
||||
Data = fileContent,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<FileContent>> DownloadPersonPhotoPerson(int personId, int photoType, string filename)
|
||||
{
|
||||
|
||||
int statusCode = -1;
|
||||
string error = "";
|
||||
string extension = "";
|
||||
PersonPhoto? model = null;
|
||||
FileContent fileContent = new();
|
||||
if (personId < 1)
|
||||
{
|
||||
var rlist = await _context.PersonPhotos.Where(x => x.Photo == filename).ToListAsync();
|
||||
if (rlist != null)
|
||||
@@ -108,19 +147,26 @@ namespace FamilyTreeAPI.Repository
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
model = await _context.PersonPhotos.FindAsync(id);
|
||||
var rlist = await _context.PersonPhotos.Where (x => x.PersonId == personId && photoType.ToString() == x.PhotoType).ToListAsync();
|
||||
for ( int i = 0; i < rlist.Count; i++)
|
||||
{
|
||||
model = rlist[i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (model != null)
|
||||
{
|
||||
fileContent.ContentType = Helpers.GetFileContent(model.PhotoType);
|
||||
extension = Helpers.GetFileExtension(model.Photo);
|
||||
fileContent.ContentType = Helpers.GetFileContent(extension);
|
||||
fileContent.Content = (byte[])model.ImagePhoto;
|
||||
fileContent.FileName = model.Photo;
|
||||
statusCode = 1;
|
||||
}
|
||||
|
||||
return new ResultModel<FileContent>()
|
||||
{
|
||||
Data = fileContent,
|
||||
@@ -129,21 +175,70 @@ namespace FamilyTreeAPI.Repository
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<int>> DeletePersonPhoto(int id)
|
||||
public async Task<ResultModel<int>> DeletePersonPhoto(int personId, int photoType)
|
||||
{
|
||||
int result = default(int);
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
PersonPhoto? model;
|
||||
try
|
||||
{
|
||||
PersonPhoto? model = await _context.PersonPhotos.FindAsync(id);
|
||||
if (model != null)
|
||||
if (photoType < 1)
|
||||
{
|
||||
List<PersonPhoto> list = await _context.PersonPhotos.Where ( x => x.PersonId == personId).ToListAsync();
|
||||
for (int i = 0; i< list.Count; i++)
|
||||
{
|
||||
model = list[i];
|
||||
_context.PersonPhotos.Remove(model);
|
||||
await _context.SaveChangesAsync();
|
||||
statuscode = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List<PersonPhoto> list = await _context.PersonPhotos.Where ( x => x.PersonId == personId && x.PhotoType == photoType.ToString()).ToListAsync();
|
||||
for (int i = 0; i< list.Count; i++)
|
||||
{
|
||||
model = list[i];
|
||||
_context.PersonPhotos.Remove(model);
|
||||
await _context.SaveChangesAsync();
|
||||
statuscode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
}
|
||||
//var dto = await Task.Run(() => result);
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<int>> DeletePersonPhotoById(int id)
|
||||
{
|
||||
int result = default(int);
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
PersonPhoto? model = await _context.PersonPhotos.FindAsync(id);
|
||||
if (model != null)
|
||||
{
|
||||
|
||||
_context.PersonPhotos.Remove(model);
|
||||
await _context.SaveChangesAsync();
|
||||
statuscode = 1;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
|
||||
@@ -283,7 +283,7 @@ public partial class PersonRepository : IPerson
|
||||
node.Key = item.Id.ToString();
|
||||
node.Type = type;
|
||||
if (item.Image != null)
|
||||
node.Data.Image = await LoadPersonImage(item.Image);
|
||||
node.Data.Image = await LoadPersonImage(item.Id, (int) enumPhotoType.Profile, item.Image);
|
||||
|
||||
node.Icon = "T";
|
||||
node.StyleClass = getStyleClass(node.Icon);
|
||||
@@ -319,8 +319,8 @@ public partial class PersonRepository : IPerson
|
||||
TreeNode<TreeData> child;
|
||||
PersonDto dto;
|
||||
Person pe;
|
||||
int fatherId, motherId;
|
||||
fatherId = motherId = 0;
|
||||
int fatherId, motherId, personId;
|
||||
personId = fatherId = motherId = 0;
|
||||
string data = person.Sex;
|
||||
TreeNode<TreeData> citem;
|
||||
string pName = "";
|
||||
@@ -371,6 +371,7 @@ public partial class PersonRepository : IPerson
|
||||
pName = pe.FirstName;
|
||||
image = pe.Image;
|
||||
key = motherId.ToString();
|
||||
personId = motherId;
|
||||
data = pe.Sex;
|
||||
}
|
||||
}
|
||||
@@ -382,6 +383,7 @@ public partial class PersonRepository : IPerson
|
||||
pName = pe.FirstName;
|
||||
image = pe.Image;
|
||||
key = fatherId.ToString();
|
||||
personId = fatherId;
|
||||
data = pe.Sex;
|
||||
}
|
||||
}
|
||||
@@ -390,7 +392,7 @@ public partial class PersonRepository : IPerson
|
||||
citem.Data = new();
|
||||
citem.Label = pName;
|
||||
if (image != null)
|
||||
citem.Data.Image = await LoadPersonImage(image);
|
||||
citem.Data.Image = await LoadPersonImage(personId, (int) enumPhotoType.Profile, image);
|
||||
|
||||
citem.Icon = "P";
|
||||
|
||||
@@ -411,7 +413,7 @@ public partial class PersonRepository : IPerson
|
||||
child.Type = type;
|
||||
image = dto.Image;
|
||||
if (image != null)
|
||||
child.Data.Image = await LoadPersonImage(image);
|
||||
child.Data.Image = await LoadPersonImage(dto.Id,(int) enumPhotoType.Profile, image);
|
||||
child.Icon = "C";
|
||||
child.StyleClass = getStyleClass(child.Icon);
|
||||
child.Label = dto.FirstName;
|
||||
@@ -480,12 +482,12 @@ public partial class PersonRepository : IPerson
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="familyId"></param>
|
||||
/// <param name="base64"></param>
|
||||
private string SaveFile(string fileName, int familyId, string base64)
|
||||
private async Task<string> SaveFile(string fileName, int personId, string base64)
|
||||
{
|
||||
string path = "";
|
||||
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
// string error = "";
|
||||
string sdate = GetCurrentDateTime();
|
||||
string filename, extention;
|
||||
filename = extention = "";
|
||||
@@ -494,14 +496,33 @@ public partial class PersonRepository : IPerson
|
||||
string rbase = base64.Substring(first, last - first);
|
||||
|
||||
byte[] newBytes = Convert.FromBase64String(rbase);
|
||||
extention = System.IO.Path.GetExtension(fileName);
|
||||
filename = personId + "_" + sdate + extention;
|
||||
|
||||
// Wrap the byte array in a MemoryStream
|
||||
var stream = new MemoryStream(newBytes);
|
||||
|
||||
// Create the IFormFile instance
|
||||
IFormFile file = new FormFile(stream, 0, newBytes.Length, "Profile", filename)
|
||||
{
|
||||
Headers = new HeaderDictionary(),
|
||||
ContentType = "application/octet-stream" // Change to your specific MIME type if known (e.g., "image/jpeg", "application/pdf")
|
||||
};
|
||||
//save to database.
|
||||
UploadCriteria criteria = new();
|
||||
criteria.FileName = filename;
|
||||
criteria.PersonId = personId;
|
||||
criteria.PhotoType = (int) enumPhotoType.Profile;
|
||||
criteria.File = file;
|
||||
var rval = await _personPhoto.SaveAsync(criteria);
|
||||
|
||||
/*
|
||||
path = _config["AppSettings:ImageFolder"];
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
extention = System.IO.Path.GetExtension(fileName);
|
||||
filename = familyId + "_" + sdate + extention;
|
||||
string fullpath = System.IO.Path.Combine(path, filename);
|
||||
/*
|
||||
using (var fileStream = new FileStream(fullpath, FileMode.Create))
|
||||
@@ -520,10 +541,12 @@ public partial class PersonRepository : IPerson
|
||||
|
||||
}
|
||||
*/
|
||||
/*
|
||||
using (FileStream fileStream = new FileStream(fullpath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
fileStream.Write(newBytes, 0, newBytes.Length);
|
||||
}
|
||||
*/
|
||||
|
||||
return filename;
|
||||
}
|
||||
@@ -571,7 +594,7 @@ public partial class PersonRepository : IPerson
|
||||
if (!string.IsNullOrEmpty(container.FileName))
|
||||
{
|
||||
|
||||
string image = SaveFile(container.FileName, result, container.FormData);
|
||||
string image = await SaveFile(container.FileName, result, container.FormData);
|
||||
// update the image in table to new
|
||||
model.Image = image;
|
||||
await _context.SaveChangesAsync();
|
||||
@@ -587,7 +610,7 @@ public partial class PersonRepository : IPerson
|
||||
result = item.Id;
|
||||
if (!string.IsNullOrEmpty(container.FileName))
|
||||
{
|
||||
string image = SaveFile(container.FileName, result, container.FormData);
|
||||
string image = await SaveFile(container.FileName, result, container.FormData);
|
||||
// update the image in table to new
|
||||
model1.Image = image;
|
||||
}
|
||||
@@ -714,17 +737,37 @@ public partial class PersonRepository : IPerson
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<string> LoadPersonImage(string filename)
|
||||
private async Task<string> LoadPersonImage_old(string filename)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
DownloadFileCriteria criteria = new() { FileName = filename };
|
||||
var resultModel = await _importPersonRepository.DownloadFile(criteria);
|
||||
if (!string.IsNullOrEmpty((resultModel.Data)))
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(resultModel.Data))
|
||||
result = "data:image/png;base64," + resultModel.Data;
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<string> LoadPersonImage(int personId, int photoType, string filename)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
// DownloadFileCriteria criteria = new() { FileName = filename };
|
||||
|
||||
var resultModel = await _personPhoto.DownloadPersonPhotoPerson(personId, photoType , filename);
|
||||
if (resultModel.StatusCode > 0)
|
||||
{
|
||||
|
||||
string base64String = Convert.ToBase64String(resultModel.Data.Content);
|
||||
|
||||
if (!string.IsNullOrEmpty(base64String))
|
||||
result = "data:image/png;base64," + base64String;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ResultModel<int> DeleteUploadFile(DeleteFileCriteria criteria)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
@@ -66,7 +66,6 @@ public class Seed
|
||||
var conn = _context.Database.GetDbConnection();
|
||||
try
|
||||
{
|
||||
|
||||
conn.Open();
|
||||
var command = conn.CreateCommand();
|
||||
command.CommandText = sptext;
|
||||
|
||||
@@ -146,7 +146,7 @@ public class UserServiceRepository : IUserService
|
||||
AuthenticateResponse retval = null;
|
||||
string error = "user name is not in DB or user Name profile is not generic";
|
||||
int statuscode = 0;
|
||||
string webAPIUrl = _appSettings.LoginWebAPI;
|
||||
string webAPIUrl = "_appSettings.LoginWebAPI";
|
||||
//KCO, D204KCO
|
||||
//now check the adminuser table
|
||||
//ward clerk
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
|
||||
"AppSettings": {
|
||||
"Secret": "Nepean Blue Mountain Super Secret SIGN AND VERIFY JWT TOKENS, BEARER TOKEN USE WHEN CALLING THIS API.",
|
||||
"SQLConnectionString": "host=localhost;port=5432;database=FamilyTreeDB;username=postgres;password=Positive~1;",
|
||||
"SQLConnectionString_o": "host=192.168.1.123;port=5432;database=FamilyTreeDB;username=postgres;password=Positive~1;",
|
||||
"Secret": "Super Secret SIGN AND VERIFY JWT TOKENS, BEARER TOKEN USE WHEN CALLING THIS API.",
|
||||
"iSQLConnectionString_i": "host=localhost;port=5432;database=familytreedb;username=postgres;password=Positive~1;",
|
||||
"SQLConnectionString": "host=127.0.0.1;port=5432;database=familytreedb;username=postgres;password=Positive~1;",
|
||||
|
||||
"ImageFolder": "c:\\temp\\Family",
|
||||
"ImportFolder": "c:\\temp"
|
||||
"ImageFolder": "/temp/Family",
|
||||
"ImportFolder": "/temp"
|
||||
|
||||
},
|
||||
"Logging": {
|
||||
@@ -17,11 +17,12 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel_not_use": {
|
||||
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://*:5015"
|
||||
}
|
||||
"Url": "http://localhost:5016"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
[Unit]
|
||||
Description=ASP.NET Core Web App running on Ubuntu
|
||||
Description=ASP.NET Core Web App running on arch linux
|
||||
[Service]
|
||||
WorkingDirectory=/var/www/familytree/api
|
||||
ExecStart=/usr/bin/dotnet /var/www/fadmilytree/api/FamilyTreeAPI.dll
|
||||
ExecStart=/usr/bin/dotnet /var/www/familytree/api/FamilyTreeAPI.dll
|
||||
Restart=always
|
||||
# Restart service after 10 seconds if the dotnet service crashes:
|
||||
RestartSec=10
|
||||
# Restart service after 20 seconds if the dotnet service crashes:
|
||||
RestartSec=20
|
||||
KillSignal=SIGINT
|
||||
SyslogIdentifier=dotnet-web-familytree-api
|
||||
# This user should exist on the server and have ownership of the deployment directory
|
||||
User=www-data
|
||||
#User=www-data this is other ubuntu
|
||||
#arch linux has user http
|
||||
User=http
|
||||
Environment=ASPNETCORE_ENVIRONMENT=Production
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
#make sure in nginx.conf has include module.d/*.conf inside http block one.
|
||||
server {
|
||||
listen 80; #make nginx out side listen 82;
|
||||
location /familytreeapi/ {
|
||||
#proxy_pass http://127.0.0.1:5015;
|
||||
proxy_pass http://192.168.1.219:5015/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection keep-alive;
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 /familytreeui/; #if same one redirect to /familytreeui/
|
||||
}
|
||||
|
||||
location /familytreeui {
|
||||
return 301 /familytreeui/; #if same one redirect to /familytreeui/
|
||||
}
|
||||
|
||||
location /familytreeui/ {
|
||||
#root /var/www/familytree/; #path is real must exist like /var/www/familytree/familytreeui and /var/www/familytree/api folder.
|
||||
alias /var/www/familytree/ui/; #location does not to match. but angular index baseurl must same as location.
|
||||
#index index.html;
|
||||
try_files $uri $uri/ /familytreeui/index.html /index.html;
|
||||
}
|
||||
|
||||
|
||||
# Optional: Cache static assets for better performance
|
||||
#location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
|
||||
# expires 30d;
|
||||
# add_header Cache-Control "public";
|
||||
#}
|
||||
|
||||
# error_page 404 /index.html;
|
||||
|
||||
# put in /etc/nginx/sites-availalble/familytreeapp.conf
|
||||
# link to enable
|
||||
# $) sudo ln -s /etc/nginx/sites-availalble/familytreeapp.conf /etc/nginx/sites-enabled/
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
|
||||
user http;
|
||||
worker_processes auto;
|
||||
worker_cpu_affinity auto;
|
||||
|
||||
#error_log logs/error.log;
|
||||
#error_log logs/error.log notice;
|
||||
#error_log logs/error.log info;
|
||||
|
||||
#pid logs/nginx.pid;
|
||||
|
||||
|
||||
# Load all installed modules
|
||||
#include modules.d/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
charset utf-8;
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
types_hash_max_size 4096;
|
||||
client_max_body_size 16M;
|
||||
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
# '$status $body_bytes_sent "$http_referer" '
|
||||
# '"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
#access_log logs/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
#keepalive_timeout 0;
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
include modules.d/*.conf;
|
||||
|
||||
server {
|
||||
listen 81;
|
||||
server_name localhost;
|
||||
|
||||
#access_log logs/host.access.log main;
|
||||
|
||||
#kham comment out first
|
||||
#location / {
|
||||
# root /usr/share/nginx/html;
|
||||
# index index.html index.htm;
|
||||
# }
|
||||
|
||||
#error_page 404 /404.html;
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
#
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
|
||||
#
|
||||
#location ~ \.php$ {
|
||||
# proxy_pass http://127.0.0.1;
|
||||
#}
|
||||
|
||||
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
|
||||
#
|
||||
#location ~ \.php$ {
|
||||
# root html;
|
||||
# fastcgi_pass 127.0.0.1:9000;
|
||||
# fastcgi_index index.php;
|
||||
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
|
||||
# include fastcgi_params;
|
||||
#}
|
||||
|
||||
# deny access to .htaccess files, if Apache's document root
|
||||
# concurs with nginx's one
|
||||
#
|
||||
#location ~ /\.ht {
|
||||
# deny all;
|
||||
#}
|
||||
}
|
||||
|
||||
|
||||
# another virtual host using mix of IP-, name-, and port-based configuration
|
||||
#
|
||||
#server {
|
||||
# listen 8000;
|
||||
# listen somename:8080;
|
||||
# server_name somename alias another.alias;
|
||||
|
||||
# location / {
|
||||
# root html;
|
||||
# index index.html index.htm;
|
||||
# }
|
||||
#}
|
||||
|
||||
|
||||
# HTTPS server
|
||||
#
|
||||
#server {
|
||||
# listen 443 ssl;
|
||||
# server_name localhost;
|
||||
|
||||
# ssl_certificate cert.pem;
|
||||
# ssl_certificate_key cert.key;
|
||||
|
||||
# ssl_session_cache shared:SSL:1m;
|
||||
# ssl_session_timeout 5m;
|
||||
|
||||
# ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
# ssl_prefer_server_ciphers on;
|
||||
|
||||
# location / {
|
||||
# root html;
|
||||
# index index.html index.htm;
|
||||
# }
|
||||
#}
|
||||
|
||||
}
|
||||
Generated
+3161
-4311
File diff suppressed because it is too large
Load Diff
+18
-18
@@ -23,35 +23,35 @@
|
||||
"private": true,
|
||||
"packageManager": "npm@11.6.4",
|
||||
"dependencies": {
|
||||
"@angular/common": "^21.0.0",
|
||||
"@angular/compiler": "^21.0.0",
|
||||
"@angular/core": "^21.0.0",
|
||||
"@angular/forms": "^21.0.0",
|
||||
"@angular/platform-browser": "^21.0.0",
|
||||
"@angular/router": "^21.0.0",
|
||||
"@ngrx/effects": "^21.0.1",
|
||||
"@ngrx/store": "^21.0.1",
|
||||
"@ngrx/store-devtools": "^21.0.1",
|
||||
"@primeuix/themes": "^2.0.2",
|
||||
"@angular/common": "^22.0.0",
|
||||
"@angular/compiler": "^22.0.0",
|
||||
"@angular/core": "^22.0.0",
|
||||
"@angular/forms": "^22.0.0",
|
||||
"@angular/platform-browser": "^22.0.0",
|
||||
"@angular/router": "^22.0.0",
|
||||
"@ngrx/effects": "^22.0.0",
|
||||
"@ngrx/store": "^22.0.0",
|
||||
"@ngrx/store-devtools": "^22.0.0",
|
||||
"@openng/optimus-ui": "^2.0.2",
|
||||
"@tailwindcss/postcss": "^4.1.17",
|
||||
"file-saver": "^2.0.5",
|
||||
"moment": "^2.30.1",
|
||||
"postcss": "^8.5.6",
|
||||
"primeicons": "^7.0.0",
|
||||
"primeng": "^21.0.1",
|
||||
"rxjs": "~7.8.0",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"tailwindcss-primeui": "^0.6.1",
|
||||
"tslib": "^2.3.0",
|
||||
"xlsx": "^0.18.5"
|
||||
"xlsx": "^0.18.5",
|
||||
"@openng/icons": "^1.0.0",
|
||||
"@openng/optimus-ui-themes": "^2.0.2",
|
||||
"@openng/optimus-ui-tailwindcss": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "^21.0.2",
|
||||
"@angular/cli": "^21.0.2",
|
||||
"@angular/compiler-cli": "^21.0.0",
|
||||
"@angular/build": "^22.0.0",
|
||||
"@angular/cli": "^22.0.0",
|
||||
"@angular/compiler-cli": "^22.0.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"jsdom": "^27.1.0",
|
||||
"typescript": "~5.9.2",
|
||||
"typescript": "~6.0.0",
|
||||
"vitest": "^4.0.8"
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,7 @@
|
||||
"baseUrl1": "http://192.168.8.188:5015",
|
||||
"baseUrl": "http://localhost:5016",
|
||||
"baseUrl_docker": "http://localhost:8080",
|
||||
"attachment": "http://localhost/document/family"
|
||||
"attachment": "http://localhost/document/family",
|
||||
"username": "kham.vilaythong@gmail.com",
|
||||
"prefill_ps": "passwor"
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -1,9 +1,9 @@
|
||||
import { ApplicationConfig, provideBrowserGlobalErrorListeners ,
|
||||
provideAppInitializer} from '@angular/core';
|
||||
import { provideRouter, withComponentInputBinding } from '@angular/router';
|
||||
import { providePrimeNG } from 'primeng/config';
|
||||
import { provideOptimus } from '@openng/optimus-ui/config';
|
||||
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
||||
import { ConfirmationService, MessageService } from '@openng/optimus-ui/api';
|
||||
import { routes } from './app.routes';
|
||||
import MyPreset from './mythem';
|
||||
import { JwtInterceptor, ErrorInterceptor, initializeApp } from './shares';
|
||||
@@ -29,13 +29,13 @@ export const appConfig: ApplicationConfig = {
|
||||
provideAppInitializer(initializeApp()),
|
||||
provideHttpClient(withInterceptors([JwtInterceptor, ErrorInterceptor])),
|
||||
provideRouter(routes, withComponentInputBinding()),
|
||||
providePrimeNG({
|
||||
provideOptimus({
|
||||
theme: {
|
||||
preset: MyPreset,
|
||||
options: {
|
||||
cssLayer: {
|
||||
name: 'primeng',
|
||||
order: 'theme, base, primeng'
|
||||
name: 'optimus',
|
||||
order: 'theme, base, optimus'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,9 @@ export const appConfig: ApplicationConfig = {
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
$) ng build --base-href "/familytreeui/" -c production
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { ToolbarComponent } from './toolbar/toolbar.component';
|
||||
import { ToastModule } from 'primeng/toast';
|
||||
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
||||
import { ToastModule } from '@openng/optimus-ui/toast';
|
||||
import { ConfirmDialogModule } from '@openng/optimus-ui/confirmdialog';
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet,ToastModule,ToolbarComponent,ConfirmDialogModule],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="flex items-end justify-end mt-4">
|
||||
@if (files)
|
||||
{
|
||||
<button pButton pRipple type="button" icon="pi pi-upload" label="Add Photo" class="p-button-sm mr-2"
|
||||
<button pButton pRipple type="button" icon="pi pi-upload" label="OK" class="p-button-sm mr-2"
|
||||
(click)="upload($event)"></button>
|
||||
}
|
||||
<button pButton pRipple type="button" icon="pi pi-times" label="Cancel" class="p-button-sm"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { ChangeDetectorRef, Component, inject, Inject, OnDestroy, OnInit, signal } from '@angular/core';
|
||||
import { DynamicDialogModule, DynamicDialogRef ,DynamicDialogConfig} from 'primeng/dynamicdialog';
|
||||
import { DynamicDialogModule, DynamicDialogRef ,DynamicDialogConfig} from '@openng/optimus-ui/dynamicdialog';
|
||||
|
||||
import { LookupEdit } from '../models';
|
||||
import { UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
||||
import { ConfirmationService, MessageService } from '@openng/optimus-ui/api';
|
||||
import { LookupService } from '../shares';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CheckboxModule } from 'primeng/checkbox';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { CheckboxModule } from '@openng/optimus-ui/checkbox';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
@Component({
|
||||
selector: 'add-photo',
|
||||
imports: [CommonModule, ReactiveFormsModule,
|
||||
@@ -67,9 +67,9 @@ export class AddPhoto implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
else {
|
||||
//new cleaner
|
||||
//new photo
|
||||
const ward:LookupEdit = {
|
||||
id: -1, description: '', codeId: maxcodeId, type: this.selType, active: true,
|
||||
id, description: '', codeId: maxcodeId, type: this.selType, active: true,
|
||||
|
||||
};
|
||||
this.assignValue(ward);
|
||||
@@ -157,7 +157,14 @@ export class AddPhoto implements OnInit, OnDestroy {
|
||||
}
|
||||
upload(e: Event): void {
|
||||
e.preventDefault();
|
||||
if (this.files.length > 0)
|
||||
{
|
||||
this.ref.close(this.files);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.messageService.add({severity: 'error', summary: 'No File to upload file', detail: 'select file first then upload file'});
|
||||
}
|
||||
}
|
||||
|
||||
cancel(e: Event): void {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<th>Id</th>
|
||||
<th pSortableColumn="description">Description<p-sortIcon field="description"></p-sortIcon>
|
||||
</th>
|
||||
|
||||
<th>Photo Type</th>
|
||||
<th>Action</th>
|
||||
|
||||
</tr>
|
||||
@@ -25,6 +25,7 @@
|
||||
<tr>
|
||||
<td>{{item.id}}</td>
|
||||
<td >{{item.photo}}</td>
|
||||
<td>{{item.photoType}}</td>
|
||||
<td>
|
||||
|
||||
<button pButton type="button" icon="pi pi-times"
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal, output } from '@angular/core';
|
||||
import { catchError, EMPTY, finalize, Subscription } from 'rxjs';
|
||||
import { CommonUtilities, HttpUtility, LookupService } from '../shares';
|
||||
import { DialogService ,DynamicDialogConfig,DynamicDialogModule, DynamicDialogRef} from 'primeng/dynamicdialog';
|
||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
||||
import { DialogService ,DynamicDialogConfig,DynamicDialogModule, DynamicDialogRef} from '@openng/optimus-ui/dynamicdialog';
|
||||
import { ConfirmationService, MessageService } from '@openng/optimus-ui/api';
|
||||
import { AddPhoto } from './add.photo';
|
||||
import { PersonPhotoDto } from '../models';
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { TooltipModule } from 'primeng/tooltip';
|
||||
import { TableModule } from '@openng/optimus-ui/table';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { TooltipModule } from '@openng/optimus-ui/tooltip';
|
||||
import { AuthenticationService } from '../user-services';
|
||||
import { HttpResponse } from '@angular/common/http';
|
||||
import { PersonService } from '../person';
|
||||
@@ -69,11 +69,11 @@ export class PhotoList implements OnInit, OnDestroy {
|
||||
downloadAttachment(id: number): void {
|
||||
//GetReportFile
|
||||
|
||||
let typeofCall = "personId_" + id.toString();
|
||||
let typeofCall = "personPhotoId_" + id.toString();
|
||||
|
||||
let criteria:any ={id, fileName:''};
|
||||
let criteria: any = { id };
|
||||
this.downloadFile.set(false);
|
||||
this.http.getFileResponse("api/FileUpload/downloadPersonPhoto", criteria).pipe(
|
||||
this.http.getFileResponse("api/FileUpload/DownloadPersonPhotoById", criteria).pipe(
|
||||
catchError(err => {
|
||||
console.error(err.message);
|
||||
return EMPTY;
|
||||
@@ -128,7 +128,7 @@ doRemove(id: number): void {
|
||||
}
|
||||
else
|
||||
{
|
||||
const deletepersonPhoto$ = this.personService.deletePersonPhotoFile(id);
|
||||
const deletepersonPhoto$ = this.personService.deletePersonPhotoFileById(id);
|
||||
this.subscription.add(deletepersonPhoto$.subscribe(
|
||||
{
|
||||
next: x => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { FileUploadEvent, FileUploadModule } from 'primeng/fileupload';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { FileUpload } from 'primeng/fileupload';
|
||||
import { ToastModule } from 'primeng/toast';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { FileUploadEvent, FileUploadModule } from '@openng/optimus-ui/fileupload';
|
||||
import { MessageService } from '@openng/optimus-ui/api';
|
||||
import { FileUpload } from '@openng/optimus-ui/fileupload';
|
||||
import { ToastModule } from '@openng/optimus-ui/toast';
|
||||
import { AppSettingService } from '../shares';
|
||||
/*
|
||||
interface UploadEvent {
|
||||
|
||||
@@ -5,15 +5,15 @@ import { first } from 'rxjs/operators';
|
||||
|
||||
import { AuthenticationService } from '../user-services';
|
||||
|
||||
import { ConfirmationService } from 'primeng/api';
|
||||
import { ConfirmationService } from '@openng/optimus-ui/api';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CardModule } from 'primeng/card';
|
||||
import { CardModule } from '@openng/optimus-ui/card';
|
||||
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
|
||||
import { Utils } from '../shares';
|
||||
import { AppSettingService, Utils } from '../shares';
|
||||
@Component({
|
||||
templateUrl: './login.html',
|
||||
styleUrl: './login.css',
|
||||
@@ -29,6 +29,7 @@ export class Login implements OnInit, OnDestroy {
|
||||
router = inject(Router);
|
||||
authenticationService = inject(AuthenticationService);
|
||||
formBuilder = inject(FormBuilder);
|
||||
private appSetting =inject(AppSettingService);
|
||||
loading = false;
|
||||
homeUrl = "/person";
|
||||
submitted = false;
|
||||
@@ -40,10 +41,11 @@ export class Login implements OnInit, OnDestroy {
|
||||
private subscription: Subscription = new Subscription();
|
||||
|
||||
constructor() {
|
||||
|
||||
const default_us = this.appSetting.appSetting.username;
|
||||
const pass = this.appSetting.appSetting.prefill_ps;
|
||||
this.loginForm = this.formBuilder.group({
|
||||
username: ['kham.vilaythong@gmail.com', Validators.required],
|
||||
password: ['password', Validators.required],
|
||||
username: [default_us, Validators.required],
|
||||
password: [pass, Validators.required],
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ export enum mState {
|
||||
Modified = 1,
|
||||
New =2,
|
||||
};
|
||||
|
||||
export enum enumPhoto {
|
||||
Profile = 1,
|
||||
Other = 2
|
||||
}
|
||||
export enum userRole {
|
||||
Normal = 1,
|
||||
Admin = 2,
|
||||
|
||||
+28
-37
@@ -1,51 +1,41 @@
|
||||
|
||||
|
||||
//mypreset.ts
|
||||
import { definePreset } from '@primeuix/themes';
|
||||
import Aura from '@primeuix/themes/aura';
|
||||
import { primitive } from '@primeuix/themes/aura/base';
|
||||
import { definePreset } from '@openng/optimus-ui-themes';
|
||||
import Aura from '@openng/optimus-ui-themes/aura';
|
||||
|
||||
const MyPreset = definePreset(Aura, {
|
||||
semantic: {
|
||||
colorScheme: {
|
||||
primitive: {
|
||||
cyan: {
|
||||
50: '{cyan.50}',
|
||||
100: '{cyan.100}',
|
||||
200: '{cyan.200}',
|
||||
300: '{cyan.300}',
|
||||
400: '{cyan.400}',
|
||||
500: '{cyan.500}',
|
||||
}
|
||||
|
||||
},
|
||||
primary: {
|
||||
50: '{zinc.50}',
|
||||
100: '{zinc.100}',
|
||||
200: '{zinc.200}',
|
||||
300: '{zinc.300}',
|
||||
400: '{zinc.400}',
|
||||
500: '{zinc.500}',
|
||||
600: '{zinc.600}',
|
||||
700: '{zinc.700}',
|
||||
800: '{zinc.800}',
|
||||
900: '{zinc.900}',
|
||||
950: '{zinc.950}'
|
||||
50: '{blue.50}',
|
||||
100: '{blue.100}',
|
||||
200: '{blue.200}',
|
||||
300: '{blue.300}',
|
||||
400: '{blue.400}',
|
||||
500: '{blue.500}',
|
||||
600: '{blue.600}',
|
||||
700: '{blue.700}',
|
||||
800: '{blue.800}',
|
||||
900: '{blue.900}',
|
||||
950: '{blue.950}'
|
||||
},
|
||||
colorScheme: {
|
||||
|
||||
|
||||
light: {
|
||||
surface: {
|
||||
0: '#ffffff',
|
||||
50: '{zinc.50}',
|
||||
100: '{zinc.100}',
|
||||
200: '{zinc.200}',
|
||||
300: '{zinc.300}',
|
||||
400: '{zinc.400}',
|
||||
500: '{zinc.500}',
|
||||
600: '{zinc.600}',
|
||||
700: '{zinc.700}',
|
||||
800: '{zinc.800}',
|
||||
900: '{zinc.900}',
|
||||
950: '{zinc.950}'
|
||||
50: '{blue.50}',
|
||||
100: '{blue.100}',
|
||||
200: '{blue.200}',
|
||||
300: '{blue.300}',
|
||||
400: '{blue.400}',
|
||||
500: '{blue.500}',
|
||||
600: '{blue.600}',
|
||||
700: '{blue.700}',
|
||||
800: '{blue.800}',
|
||||
900: '{blue.900}',
|
||||
950: '{blue.950}'
|
||||
}
|
||||
},
|
||||
dark: {
|
||||
@@ -65,6 +55,7 @@ const MyPreset = definePreset(Aura, {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal} from '@angular/core';
|
||||
|
||||
import { StaffView ,StaffSearch, Person, RelationShip } from '../models';
|
||||
import { OrganizationChartModule } from 'primeng/organizationchart';
|
||||
import { OrganizationChartModule } from '@openng/optimus-ui/organizationchart';
|
||||
|
||||
import { take } from 'rxjs/operators';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { PersonService } from './person.service';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { TableModule } from '@openng/optimus-ui/table';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { TreeNode } from 'primeng/api';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { DialogService, DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { TreeNode } from '@openng/optimus-ui/api';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
import { DialogService, DynamicDialogConfig, DynamicDialogRef } from '@openng/optimus-ui/dynamicdialog';
|
||||
import { PersonEdit } from './person.edit';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { TreeModule, TreeNodeDoubleClickEvent, TreeNodeSelectEvent } from 'primeng/tree';
|
||||
import { MessageService } from '@openng/optimus-ui/api';
|
||||
import { TreeModule, TreeNodeDoubleClickEvent, TreeNodeSelectEvent } from '@openng/optimus-ui/tree';
|
||||
import { Utils } from '../shares';
|
||||
import { PopoverModule } from 'primeng/popover';
|
||||
import { PopoverModule } from '@openng/optimus-ui/popover';
|
||||
|
||||
@Component({
|
||||
selector: 'family-orga',
|
||||
@@ -64,7 +64,7 @@ export class FamilyOrga implements OnInit, OnDestroy{
|
||||
{
|
||||
expanded: true,
|
||||
type: 'person',
|
||||
styleClass: 'bg-indigo-500 text-white',
|
||||
styleClass: 'bg-blue-500 text-white',
|
||||
data: {
|
||||
image: 'https://primefaces.org/cdn/primeng/images/demo/avatar/amyelsner.png',
|
||||
name: 'Amy Elsner',
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal} from '@angular/core';
|
||||
|
||||
import { StaffView ,StaffSearch, Person } from '../models';
|
||||
import { OrganizationChartModule } from 'primeng/organizationchart';
|
||||
import { OrganizationChartModule } from '@openng/optimus-ui/organizationchart';
|
||||
|
||||
import { take } from 'rxjs/operators';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
import { PersonService } from './person.service';
|
||||
import { AuthenticationService } from '../user-services';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { TableModule } from '@openng/optimus-ui/table';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { TreeNode } from 'primeng/api';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { DialogService } from 'primeng/dynamicdialog';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { TreeNode } from '@openng/optimus-ui/api';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
import { DialogService } from '@openng/optimus-ui/dynamicdialog';
|
||||
import { PersonEdit } from './person.edit';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { CheckboxModule } from 'primeng/checkbox';
|
||||
import { TreeModule, TreeNodeDoubleClickEvent, TreeNodeSelectEvent } from 'primeng/tree';
|
||||
import { MessageService } from '@openng/optimus-ui/api';
|
||||
import { CheckboxModule } from '@openng/optimus-ui/checkbox';
|
||||
import { TreeModule, TreeNodeDoubleClickEvent, TreeNodeSelectEvent } from '@openng/optimus-ui/tree';
|
||||
import { Utils } from '../shares';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -8,17 +8,17 @@ import { Subscription } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
import { PersonService } from './person.service';
|
||||
import { AuthenticationService } from '../user-services';
|
||||
import { Table, TableModule } from 'primeng/table';
|
||||
import { Table, TableModule } from '@openng/optimus-ui/table';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { DialogService } from 'primeng/dynamicdialog';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
import { DialogService } from '@openng/optimus-ui/dynamicdialog';
|
||||
import { PersonEdit } from './person.edit';
|
||||
import { ConfirmationService, MenuItem, MessageService } from 'primeng/api';
|
||||
import { IconFieldModule } from 'primeng/iconfield';
|
||||
import { InputIconModule } from 'primeng/inputicon';
|
||||
import { Menu, MenuModule } from 'primeng/menu';
|
||||
import { ConfirmationService, MenuItem, MessageService } from '@openng/optimus-ui/api';
|
||||
import { IconFieldModule } from '@openng/optimus-ui/iconfield';
|
||||
import { InputIconModule } from '@openng/optimus-ui/inputicon';
|
||||
import { Menu, MenuModule } from '@openng/optimus-ui/menu';
|
||||
import { FamilyOrga } from './family.orga';
|
||||
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
import { ChangeDetectorRef, Component, inject, OnDestroy, OnInit, signal, ViewChild } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog';
|
||||
import {DynamicDialogConfig} from 'primeng/dynamicdialog';
|
||||
import {DialogService, DynamicDialogRef} from '@openng/optimus-ui/dynamicdialog';
|
||||
import {DynamicDialogConfig} from '@openng/optimus-ui/dynamicdialog';
|
||||
import { FormControl, ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
import { Subject, Subscription} from 'rxjs';
|
||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
||||
import { DatePickerModule } from 'primeng/datepicker';
|
||||
import { Code, RelationShipView, Person, mState, RelationShip, PersonPhotoDto} from '../models';
|
||||
import { ConfirmationService, MessageService } from '@openng/optimus-ui/api';
|
||||
import { DatePickerModule } from '@openng/optimus-ui/datepicker';
|
||||
import { Code, RelationShipView, Person, mState, RelationShip, PersonPhotoDto, enumPhoto } from '../models';
|
||||
import { AppSettingService, LookupService, Utils } from '../shares';
|
||||
import { PersonService } from './person.service';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { SelectModule } from 'primeng/select';
|
||||
import { CheckboxModule } from 'primeng/checkbox';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { SelectModule } from '@openng/optimus-ui/select';
|
||||
import { CheckboxModule } from '@openng/optimus-ui/checkbox';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
import moment from 'moment';
|
||||
import { HttpEvent } from '@angular/common/http';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { TableModule } from '@openng/optimus-ui/table';
|
||||
import { Pickperson } from '../pickperson/pickperson';
|
||||
import { ImageDisplayComponent } from '../pickperson/image.display';
|
||||
import { TooltipModule } from 'primeng/tooltip';
|
||||
import { AutoFocusModule } from 'primeng/autofocus';
|
||||
import { TooltipModule } from '@openng/optimus-ui/tooltip';
|
||||
import { AutoFocusModule } from '@openng/optimus-ui/autofocus';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { PhotoList } from '../attachphoto/photolist';
|
||||
import { InputNumberDesignTokens } from '@openng/optimus-ui-themes/types/inputnumber';
|
||||
|
||||
export interface FileUploadEvent {
|
||||
originalEvent: HttpEvent<any>;
|
||||
@@ -190,9 +191,9 @@ doDeleteFile(): void {
|
||||
this.profileFile = null;
|
||||
}
|
||||
doDeleteImage(fileName:string) : void {
|
||||
const familyId = this.adminuserForm.value.id;
|
||||
const data = { fileName, familyId };
|
||||
const delete$ = this.personService.deleteUploadFile(data);
|
||||
const personId = this.adminuserForm.value.id;
|
||||
const photoType = enumPhoto.Profile;
|
||||
const delete$ = this.personService.deletePersonPhotoFile(personId, photoType);
|
||||
this.subscription.add(delete$.subscribe(
|
||||
{
|
||||
next: x => {
|
||||
@@ -307,6 +308,8 @@ doViewImage(imageName:string): void {
|
||||
const ref = this.dialogService.open(ImageDisplayComponent, {
|
||||
data: {
|
||||
imageName,
|
||||
personId: this._id,
|
||||
photyType: enumPhoto.Profile
|
||||
},
|
||||
header: 'View Image',
|
||||
draggable: true,
|
||||
@@ -358,7 +361,7 @@ assignValue(item:Person): void {
|
||||
}
|
||||
if (item.image && item.image.length > 0)
|
||||
{
|
||||
this.loadImage(item.image);
|
||||
this.loadImage(item.image, item.id, enumPhoto.Profile);
|
||||
}
|
||||
// disable use false//true for not disable.
|
||||
this.subChanged$.next(true);
|
||||
@@ -367,8 +370,10 @@ assignValue(item:Person): void {
|
||||
// convenience getter for easy access in form fields
|
||||
get f() { return this.adminuserForm.controls;}
|
||||
|
||||
loadImage(fileName: string| null): void {
|
||||
const download = this.personService.downloadFile(fileName!);
|
||||
loadImage(fileName: string | null,
|
||||
personId: number, photoType: number): void {
|
||||
if (fileName) {
|
||||
const download = this.personService.downloadPersonPhoto64(fileName, personId, photoType);
|
||||
this.subscription.add(download.subscribe({
|
||||
next: x => {
|
||||
if (x.statusCode == 1)
|
||||
@@ -385,6 +390,8 @@ assignValue(item:Person): void {
|
||||
error: e => console.error("error in download image", e)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
displayIamge64(baseImage: string): void
|
||||
{
|
||||
const changeUrl = (this.sanitizer.bypassSecurityTrustResourceUrl(baseImage) as any).changingThisBreaksApplicationSecurity;
|
||||
@@ -493,10 +500,12 @@ assignValue(item:Person): void {
|
||||
if (x.statusCode >= 1)
|
||||
{
|
||||
item.id = x.data;
|
||||
this._id = item.id;
|
||||
// this.messageService.add({severity:'success', summary: 'Save user', detail: item.firstName + " " + item.lastName });
|
||||
//this.router.navigate([this.returnUrl]);
|
||||
console.log("the person after save", item);
|
||||
|
||||
const list = this.getPhotoListforSave();
|
||||
console.log("the person after save photo, person", list, item);
|
||||
if (list.length > 0)
|
||||
{
|
||||
this.savePhotoList(list, item);
|
||||
@@ -715,7 +724,7 @@ getPhotoListforSave(): PersonPhotoDto[] {
|
||||
let result: PersonPhotoDto[] =[];
|
||||
for (let i = 0; i < this.photoList.length; i++)
|
||||
{
|
||||
if (this.photoList[i].id < 0)
|
||||
if (this.photoList[i].id < 1)
|
||||
{
|
||||
result.push(this.photoList[i]);
|
||||
}
|
||||
@@ -732,17 +741,14 @@ savePhotoList(list: PersonPhotoDto[], item:Person): void {
|
||||
if (file)
|
||||
formData.append("files", file, file.name);
|
||||
}
|
||||
formData.append('personId', this._id.toString());
|
||||
|
||||
formData.append('personId', item.id.toString());
|
||||
console.log("savephotolist person id", item.id, item);
|
||||
const personPhoto$ = this.personService.savePersonPhotoList(formData);
|
||||
this.subscription.add(personPhoto$.subscribe(
|
||||
{
|
||||
next: x => {
|
||||
if (x.statusCode == 1) {
|
||||
//const filename = x.data;
|
||||
//this.adminuserForm.patchValue({ image: filename });
|
||||
this.ref.close(item);
|
||||
//this.cdr.detectChanges();
|
||||
}
|
||||
else
|
||||
this.messageService.add({ severity: 'error', summary: 'Error save attach photos files', detail: 'Fail to photos file: ' + x.message });
|
||||
|
||||
@@ -4,7 +4,7 @@ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Staff,StaffSearch, StaffView, ResultModel,ConfigureUrl,ResetPassword, Person, PersonContainer, RelationShip } from '../models';
|
||||
import { AppSettingService } from '../shares';
|
||||
import { TreeNode } from 'primeng/api';
|
||||
import { TreeNode } from '@openng/optimus-ui/api';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PersonService {
|
||||
@@ -77,33 +77,60 @@ export class PersonService {
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.personUrl + "/UploadImage";
|
||||
return this.http.post<ResultModel<string>>(baseUrl, data);
|
||||
}
|
||||
downloadFile(imageName: string): Observable<ResultModel<string>> {
|
||||
downloadFile_dontusethis(imageName: string, personId: number,
|
||||
photoType: number): Observable<ResultModel<string>> {
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadFile";
|
||||
const data = {
|
||||
fileName: imageName
|
||||
fileName: imageName,
|
||||
id: personId,
|
||||
photoType
|
||||
};
|
||||
return this.http.post<ResultModel<string>>(baseUrl, data);
|
||||
}
|
||||
deleteUploadFile(data: any): Observable<ResultModel<number>> {
|
||||
deleteUploadFile_dotnotuse(data: any): Observable<ResultModel<number>> {
|
||||
//data ={filename};
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.personUrl + "/DeleteUploadFile";
|
||||
return this.http.post<ResultModel<number>>(baseUrl, data);
|
||||
}
|
||||
deletePersonPhotoFile(id: number): Observable<ResultModel<number>> {
|
||||
const data ={id, fileName:''};
|
||||
deletePersonPhotoFile(personId: number, photoType: number): Observable<ResultModel<number>> {
|
||||
const data = {
|
||||
id: personId,
|
||||
fileName: '',
|
||||
photoType
|
||||
};
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DeletePersonPhoto";
|
||||
return this.http.post<ResultModel<number>>(baseUrl, data);
|
||||
}
|
||||
deletePersonPhotoFileById(id: number): Observable<ResultModel<number>> {
|
||||
const data = {
|
||||
id
|
||||
};
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DeletePersonPhotoById";
|
||||
return this.http.post<ResultModel<number>>(baseUrl, data);
|
||||
}
|
||||
savePersonPhotoList(data:FormData): Observable<ResultModel<number>> {
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/SavePersonPhoto";
|
||||
return this.http.post<ResultModel<number>>(baseUrl, data);
|
||||
}
|
||||
downloadPersonPhoto(id: number): Observable<ResultModel<string>> {
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadPersonPhoto";
|
||||
|
||||
downloadPersonPhoto64(imageName: string, personId: number,
|
||||
photoType: number): Observable<ResultModel<string>> {
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadPersonPhoto64";
|
||||
const data = {
|
||||
id,
|
||||
fileName: ''
|
||||
id: personId,
|
||||
photoType,
|
||||
fileName: imageName
|
||||
};
|
||||
return this.http.post<ResultModel<string>>(baseUrl, data);
|
||||
}
|
||||
downloadPersonPhoto(imageName: string, personId: number,
|
||||
photoType: number): Observable<any> {
|
||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadPersonPhoto";
|
||||
const data = {
|
||||
id: personId,
|
||||
photoType,
|
||||
fileName: imageName
|
||||
};
|
||||
return this.http.post<any>(baseUrl, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import { PersonService } from '../person';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { DynamicDialogConfig, DynamicDialogRef } from '@openng/optimus-ui/dynamicdialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-image-display',
|
||||
@@ -28,11 +28,13 @@ export class ImageDisplayComponent implements OnInit, OnDestroy {
|
||||
ngOnInit(): void {
|
||||
|
||||
const imageName = this.config.data.imageName;
|
||||
this.loadImage(imageName);
|
||||
const personId = this.config.data.personId;
|
||||
const photoType = this.config.data.photyType;
|
||||
this.loadImage(imageName, personId, photoType);
|
||||
|
||||
}
|
||||
loadImage(fileName: string| null): void {
|
||||
const download = this.personService.downloadFile(fileName!);
|
||||
loadImage(fileName: string | null, personId: number, photoType: number): void {
|
||||
const download = this.personService.downloadPersonPhoto64(fileName!, personId, photoType);
|
||||
this.subscription.add(download.subscribe({
|
||||
next: x => {
|
||||
if (x.statusCode == 1)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, OnDestroy, OnInit, signal, ViewChild } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { Table, TableModule } from 'primeng/table';
|
||||
import { Table, TableModule } from '@openng/optimus-ui/table';
|
||||
import { Person } from '../models';
|
||||
import { IconFieldModule } from 'primeng/iconfield';
|
||||
import { InputIconModule } from 'primeng/inputicon';
|
||||
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { IconFieldModule } from '@openng/optimus-ui/iconfield';
|
||||
import { InputIconModule } from '@openng/optimus-ui/inputicon';
|
||||
import { DynamicDialogConfig, DynamicDialogRef } from '@openng/optimus-ui/dynamicdialog';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pickperson',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import moment from "moment";
|
||||
import { Person, User, userRole } from "../models"
|
||||
import { TreeNode } from "primeng/api";
|
||||
import { TreeNode } from "@openng/optimus-ui/api";
|
||||
|
||||
type MyProName = "fatherId" | "motherId";
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ import { Subscription } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
import { StaffService } from './staff.service';
|
||||
import { AuthenticationService } from '../user-services';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { TableModule } from '@openng/optimus-ui/table';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
import { selectStaffLoaded,selectStaff } from '../state/staff.selectors';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -2,15 +2,15 @@ import { Component, inject, input, numberAttribute, OnDestroy, OnInit } from '@a
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
import { Subject, Subscription} from 'rxjs';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { MessageService } from '@openng/optimus-ui/api';
|
||||
|
||||
import {Staff, Code, userRole} from '../models';
|
||||
import { LookupService, Utils } from '../shares';
|
||||
import { StaffService } from './staff.service';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { SelectModule } from 'primeng/select';
|
||||
import { CheckboxModule } from 'primeng/checkbox';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
import { SelectModule } from '@openng/optimus-ui/select';
|
||||
import { CheckboxModule } from '@openng/optimus-ui/checkbox';
|
||||
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'staff.edit.component.html',
|
||||
|
||||
@@ -2,13 +2,13 @@ import { Component, inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { FormsModule, ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
import { Subject, Subscription} from 'rxjs';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { MessageService } from '@openng/optimus-ui/api';
|
||||
|
||||
import {Staff, Code, userRole, ResetPassword} from '../models';
|
||||
import { LookupService, Utils } from '../shares';
|
||||
import { StaffService } from './staff.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'staff.pass.component.html',
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
@if (currentUserS() && isAuth)
|
||||
@if (currentUserS() && isAuth == true)
|
||||
{
|
||||
<div class="flex flex-column justify-between md:flex-row rounded" style="background-color:transparent">
|
||||
<div style="margin-top:5px;padding-right:35px; cursor: pointer;width:400px;">
|
||||
<img (click)="onHome()" src="images/application_image.png" alt="Banner" style="height:80px;width:100%" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end items-end flex-row">
|
||||
<div class="flex-column">
|
||||
<label class=" flex justify-end items-end mr-1 mb-2 myname">{{loginUser}}</label>
|
||||
<div>
|
||||
<span class="md:hidden flex justify-end"> <!--hidden on md screen show on small-->
|
||||
<button type="button" pButton icon="pi pi-align-justify" (click)="onemenu.toggle($event);"></button>
|
||||
<p-menu #onemenu [popup]="true" [model]="oneMenu"></p-menu>
|
||||
</span>
|
||||
|
||||
<span class="hidden md:inline-flex"> <!--hidden when small screen-->
|
||||
<p-buttonGroup >
|
||||
<button type="button" pButton icon="pi pi-slack" label="Home" (click)="onHome()"
|
||||
@@ -38,4 +36,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--put in the left new row if in mobile not much room-->
|
||||
<span class="md:hidden flex justify-start"> <!--hidden on md screen show on small-->
|
||||
<button type="button" pButton icon="pi pi-align-justify" (click)="onemenu.toggle($event);"></button>
|
||||
<p-menu #onemenu [popup]="true" [model]="oneMenu"></p-menu>
|
||||
</span>
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Component, OnInit, OnDestroy, effect, computed, Signal, } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MenuItem } from 'primeng/api';
|
||||
import { MenuModule } from 'primeng/menu';
|
||||
import { ButtonModule} from 'primeng/button';
|
||||
import { ButtonGroupModule } from 'primeng/buttongroup';
|
||||
import { MenuItem } from '@openng/optimus-ui/api';
|
||||
import { MenuModule } from '@openng/optimus-ui/menu';
|
||||
import { ButtonModule} from '@openng/optimus-ui/button';
|
||||
import { ButtonGroupModule } from '@openng/optimus-ui/buttongroup';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { AuthenticationService } from '../user-services';
|
||||
import { Utils } from '../shares';
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
@import "tailwindcss";
|
||||
@plugin "tailwindcss-primeui";
|
||||
@import "primeicons/primeicons.css";
|
||||
@plugin "@openng/optimus-ui-tailwindcss";
|
||||
@import "@openng/icons/openng-icons.css";
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"isolatedModules": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "preserve"
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { HttpInterceptorFn } from '@angular/common/http';
|
||||
|
||||
export const credentialsInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
// Clone the request to add the withCredentials property
|
||||
const clonedRequest = req.clone({
|
||||
withCredentials: true
|
||||
});
|
||||
|
||||
return next(clonedRequest);
|
||||
};
|
||||
|
||||
typescriptimport { provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { credentialsInterceptor } from './credentials.interceptor';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideHttpClient(
|
||||
withInterceptors([credentialsInterceptor]) // Register it here
|
||||
)
|
||||
]
|
||||
};
|
||||
|
||||
2. Individual Request ConfigurationIf you only want to send cookies to specific endpoints,
|
||||
pass the withCredentials option directly inside your service.
|
||||
|
||||
typescriptimport { HttpClient } from '@angular/common/http';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ApiService {
|
||||
private http = inject(HttpClient);
|
||||
|
||||
getData() {
|
||||
return this.http.get('https://your-api-domain.com', {
|
||||
withCredentials: true // Enables cookies for this request only
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
docker-compose up
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
docker-compose down
|
||||
@@ -0,0 +1,40 @@
|
||||
networks:
|
||||
dev:
|
||||
driver: bridge
|
||||
services:
|
||||
postgresdb:
|
||||
image: postgres
|
||||
container_name: ${DOCKER_REGISTRY-}postgresql-db
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
- POSTGRES_DB=FamilyTreeDB
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=Positive~1
|
||||
- PGDATA=/var/lib/postgresql/data/pgdata
|
||||
restart: always
|
||||
volumes:
|
||||
- postgresdata:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dev
|
||||
pgadmin:
|
||||
image: dpage/pgadmin4
|
||||
container_name: pgadmin4_container
|
||||
restart: always
|
||||
depends_on:
|
||||
- "postgresdb"
|
||||
volumes:
|
||||
- pgadmin-data:/var/lib/pgadmin
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: postgres@domain.com
|
||||
PGADMIN_DEFAULT_PASSWORD: Positive~1
|
||||
ports:
|
||||
- "5050:5050"
|
||||
networks:
|
||||
- dev
|
||||
|
||||
volumes:
|
||||
pgadmin-data:
|
||||
external: true
|
||||
postgresdata:
|
||||
external: true
|
||||
Binary file not shown.
@@ -1,30 +0,0 @@
|
||||
**/.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
|
||||
!**/.gitignore
|
||||
!.git/HEAD
|
||||
!.git/config
|
||||
!.git/packed-refs
|
||||
!.git/refs/heads/**
|
||||
@@ -1,63 +0,0 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
@@ -1,363 +0,0 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34202.233
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FamilyTreeAPI", "FamilyTreeAPI\FamilyTreeAPI.csproj", "{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}"
|
||||
EndProject
|
||||
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{81DDED9D-158B-E303-5F62-77A2896D2A5A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{81DDED9D-158B-E303-5F62-77A2896D2A5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81DDED9D-158B-E303-5F62-77A2896D2A5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81DDED9D-158B-E303-5F62-77A2896D2A5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81DDED9D-158B-E303-5F62-77A2896D2A5A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C7DF2338-DFC8-47CE-9AA7-C05C3C2ABEF7}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "9.0.8",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace FamilyTreeAPI.Authorization;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class AllowAnonymousAttribute : Attribute
|
||||
{ }
|
||||
@@ -1,36 +0,0 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace FamilyTreeAPI.Authorization;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
|
||||
{
|
||||
// private readonly IList<AdminRole> _roles;
|
||||
/*
|
||||
public AuthorizeAttribute(params AdminRole[] roles)
|
||||
{
|
||||
_roles = roles ?? new AdminRole[] { };
|
||||
}
|
||||
*/
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
// skip authorization if action is decorated with [AllowAnonymous] attribute
|
||||
var allowAnonymous = context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any();
|
||||
if (allowAnonymous)
|
||||
return;
|
||||
|
||||
// authorization
|
||||
// var user = (User)context.HttpContext.Items["User"];
|
||||
// if (user == null || (_roles.Any() && !_roles.Contains(user.Role)))
|
||||
// {
|
||||
// not logged in or role not authorized
|
||||
// context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Authorization;
|
||||
|
||||
public class JwtMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly AppSettings _appSettings;
|
||||
|
||||
public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
|
||||
{
|
||||
_next = next;
|
||||
_appSettings = appSettings.Value;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context, IJwtUtils jwtUtils)
|
||||
{
|
||||
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
if (token != null)
|
||||
{
|
||||
var user = jwtUtils.ValidateJwtToken(token);
|
||||
if (user != null)
|
||||
{
|
||||
// attach user to context on successful jwt validation
|
||||
//here to put in the real user
|
||||
//TODO if you want to add information for User
|
||||
context.Items["User"] = user;
|
||||
}
|
||||
}
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
|
||||
namespace FamilyTreeAPI.Authorization;
|
||||
|
||||
|
||||
public class JwtUtils : IJwtUtils
|
||||
{
|
||||
private readonly AppSettings _appSettings;
|
||||
|
||||
public JwtUtils(IOptions<AppSettings> appSettings)
|
||||
{
|
||||
_appSettings = appSettings.Value;
|
||||
}
|
||||
|
||||
public string GenerateJwtToken(UserDto user)
|
||||
{
|
||||
// generate token that is valid for 2 days
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(new[] {
|
||||
new Claim("id", user.Id.ToString()),
|
||||
new Claim("subject", user.Username),
|
||||
new Claim("firstName", user.FirstName + " " + user.LastName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//add more if we need it
|
||||
}
|
||||
),
|
||||
Expires = DateTime.UtcNow.AddDays(2),
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||
return tokenHandler.WriteToken(token);
|
||||
}
|
||||
// get back id and username. in subject
|
||||
public UserDto? ValidateJwtToken(string token)
|
||||
{
|
||||
if (token == null)
|
||||
return null;
|
||||
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
|
||||
try
|
||||
{
|
||||
tokenHandler.ValidateToken(token, new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(key),
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
// set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
|
||||
ClockSkew = TimeSpan.Zero
|
||||
}, out SecurityToken validatedToken);
|
||||
|
||||
var jwtToken = (JwtSecurityToken)validatedToken;
|
||||
// var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value); //old
|
||||
int userId = 0;
|
||||
string username = "";
|
||||
string firstName = "";
|
||||
Claim claim;
|
||||
for (int i = 0; i< jwtToken.Claims.Count(); i++)
|
||||
{
|
||||
claim = jwtToken.Claims.ElementAt(i);
|
||||
if (claim.Type == "id")
|
||||
{
|
||||
userId = int.Parse(claim.Value);
|
||||
}
|
||||
else if (claim.Type == "subject")
|
||||
{
|
||||
username = claim.Value;
|
||||
}
|
||||
else if (claim.Type == "firstName")
|
||||
{
|
||||
firstName = claim.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(username)
|
||||
&& !string.IsNullOrEmpty(firstName)
|
||||
&& userId > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UserDto user = new UserDto();
|
||||
user.Id = userId;
|
||||
user.Username = username;
|
||||
user.FirstName = firstName;
|
||||
|
||||
// return user id from JWT token if validation successful
|
||||
return user;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// return null if validation fails
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Repository;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers;
|
||||
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class FileUploadController : ControllerBase
|
||||
{
|
||||
private readonly IWebHostEnvironment _hostingEnvironment;
|
||||
private readonly ImportPersonRepository _importPersonRepository;
|
||||
private readonly IConfiguration _config;
|
||||
public FileUploadController(IWebHostEnvironment hostingEnvironment, ImportPersonRepository importPersonRepository, IConfiguration config)
|
||||
{
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
_importPersonRepository = importPersonRepository;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> UploadFile(IFormFile file)
|
||||
{
|
||||
List<CodeDto<string>> output = new ();
|
||||
if (file == null || file.Length == 0)
|
||||
{
|
||||
return BadRequest("No file uploaded.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// Define the upload directory
|
||||
// var uploadsFolder = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
|
||||
string importFolder = _config.GetValue<string>("AppSettings:ImportFolder");
|
||||
var uploadsFolder = Path.Combine(_hostingEnvironment.ContentRootPath, importFolder);
|
||||
if (!Directory.Exists(uploadsFolder))
|
||||
{
|
||||
Directory.CreateDirectory(uploadsFolder);
|
||||
}
|
||||
|
||||
// Create a unique file name to avoid overwriting
|
||||
var uniqueFileName = Path.GetFileNameWithoutExtension(file.FileName)
|
||||
+ "_" + System.Guid.NewGuid().ToString()
|
||||
+ Path.GetExtension(file.FileName);
|
||||
var filePath = Path.Combine(uploadsFolder, uniqueFileName);
|
||||
|
||||
// Save the file to the server
|
||||
using (var stream = new FileStream(filePath, FileMode.Create))
|
||||
{
|
||||
// await file.CopyToAsync(stream);
|
||||
await file.CopyToAsync(stream);
|
||||
// output = await _importPersonRepository.ImportPerson(stream, "Sheet1");
|
||||
|
||||
}
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
await file.CopyToAsync(stream);
|
||||
output = await _importPersonRepository.ImportPerson(stream, "Sheet1");
|
||||
}
|
||||
|
||||
//return Ok(new { FileName = uniqueFileName, FilePath = filePath });
|
||||
return Ok(output);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
return StatusCode(500, $"Internal server error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> DownloadFile(DownloadFileCriteria criteria)
|
||||
{
|
||||
var rev = await _importPersonRepository.DownloadFile(criteria);
|
||||
return Ok(rev);
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class LookupController : ControllerBase
|
||||
{
|
||||
private readonly ILookup _repo;
|
||||
public LookupController(ILookup repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
[HttpGet("[action]")]
|
||||
public async Task<IActionResult> LoadLookup(string type)
|
||||
{
|
||||
var list = await _repo.GetLookupAsync(type);
|
||||
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]")]
|
||||
public async Task<IActionResult> LoadLookupEdit(string type)
|
||||
{
|
||||
var list = await _repo.GetLookupEditAsync(type);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]")]
|
||||
public async Task<IActionResult> GetPersons()
|
||||
{
|
||||
var list = await _repo.GetPersonsAsync();
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]")]
|
||||
public async Task<IActionResult> GetStaffs()
|
||||
{
|
||||
var list = await _repo.GetStaffAsync();
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Lookup([FromBody] LookupEditDto model)
|
||||
{
|
||||
//var currentUser = (User?)(HttpContext.Items["User"]);
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _repo.SaveLookupAsync(model);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Lookup(int id, string type)
|
||||
{
|
||||
//lookup/id?type='abc'
|
||||
/*
|
||||
// only admins can access other user records
|
||||
var currentUser = (User)HttpContext.Items["User"];
|
||||
if (id != currentUser.Id && currentUser.Role != Role.Admin)
|
||||
return Unauthorized(new { message = "Unauthorized" });
|
||||
*/
|
||||
var retval = await _repo.GetLookupEditByIdAsync(id, type);
|
||||
return Ok(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class PersonController : ControllerBase
|
||||
{
|
||||
private readonly IPerson _repo;
|
||||
public PersonController(IPerson repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> UploadImage(IFormFile file)
|
||||
{
|
||||
var keys = Request.Form;
|
||||
var files = Request.Form.Files;
|
||||
ResultModel<string> ret = new();
|
||||
if (files.Count > 0)
|
||||
{
|
||||
StringValues familyId = "";
|
||||
|
||||
keys.TryGetValue("familyId", out familyId);
|
||||
|
||||
UploadCriteria criteria = new();
|
||||
criteria.File = file;
|
||||
criteria.FamilyId = familyId;
|
||||
|
||||
criteria.FileName = file.FileName;
|
||||
|
||||
ret = await _repo.UploadImage(criteria);
|
||||
}
|
||||
return Ok(ret);
|
||||
|
||||
|
||||
}
|
||||
//DeleteUploadFile
|
||||
[HttpPost("[action]")]
|
||||
public ActionResult DeleteUploadFile(DeleteFileCriteria criteria)
|
||||
{
|
||||
|
||||
ResultModel<int> ret = new();
|
||||
if (!string.IsNullOrEmpty(criteria.Filename))
|
||||
{
|
||||
|
||||
ret = _repo.DeleteUploadFile(criteria);
|
||||
}
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SearchPerson(PersonCriteria criteria)
|
||||
{
|
||||
var list = await _repo.GetPerson(criteria);
|
||||
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> GetChildress(ChildCriteria criteria)
|
||||
{
|
||||
var list = await _repo.GetChildren(criteria);
|
||||
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> GetFamilyTreeBy(FamilyCriteria criteria)
|
||||
{
|
||||
var list = await _repo.GetFamilyTreeBy(criteria);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]/{id}")]
|
||||
public async Task<IActionResult> GetByPersonFamily(int id)
|
||||
{
|
||||
var list = await _repo.GetByFamilyAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]/{id}")]
|
||||
public async Task<IActionResult> GetById(int id)
|
||||
{
|
||||
var list = await _repo.GetByIdAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> DeleteById(DeleteCriteria<int> criteria)
|
||||
{
|
||||
var list = await _repo.DeleteAsync(criteria.Id);
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SavePerson([FromBody] PersonForSave model)
|
||||
{
|
||||
//var currentUser = (User?)(HttpContext.Items["User"]);
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _repo.SaveAsync(model);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class RelationShipController : ControllerBase
|
||||
{
|
||||
private readonly IRelationShipd _repo;
|
||||
public RelationShipController(IRelationShipd repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
[HttpGet("[action]/{id}")]
|
||||
public async Task<IActionResult> GetById(int id)
|
||||
{
|
||||
var list = await _repo.GetByIdAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]/{id}")]
|
||||
public async Task<IActionResult> GetByPersonId(int id)
|
||||
{
|
||||
var list = await _repo.GetByPersonIdAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost("[action]/{id}")]
|
||||
public async Task<IActionResult> DeleteById(int id)
|
||||
{
|
||||
var list = await _repo.GetByIdAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SaveRelationShip([FromBody] RelationShiftContainer list)
|
||||
{
|
||||
//var currentUser = (User?)(HttpContext.Items["User"]);
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _repo.SaveAsync(list.relationShips);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers;
|
||||
|
||||
// [Authorize]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class StaffController : ControllerBase
|
||||
{
|
||||
private readonly IStaff _staff;
|
||||
public StaffController(IStaff staff)
|
||||
{
|
||||
_staff = staff;
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SaveStaff([FromBody] StaffDto model)
|
||||
{
|
||||
//var currentUser = (User?)HttpContext.Items["User"];
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _staff.SaveStaff(model);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> ResetPassStaff([FromBody] ResetPassDto model)
|
||||
{
|
||||
//var currentUser = (User?)HttpContext.Items["User"];
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _staff.ResetPassword(model);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SearchStaff([FromBody] StaffCriteria criteria)
|
||||
{
|
||||
|
||||
var retval = await _staff.GetStaff(criteria);
|
||||
return Ok(retval);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> Staff( int id)
|
||||
{
|
||||
/*
|
||||
// only admins can access other user records
|
||||
var currentUser = (User)HttpContext.Items["User"];
|
||||
if (id != currentUser.Id && currentUser.Role != Role.Admin)
|
||||
return Unauthorized(new { message = "Unauthorized" });
|
||||
*/
|
||||
var retval = await _staff.GetStaffById(id);
|
||||
return Ok(retval);
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> DeleteStaff(DeleteCriteria<int> criteria)
|
||||
{
|
||||
var currentUser = (UserDto?)HttpContext.Items["User"];
|
||||
if (null == currentUser)
|
||||
return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var retval = await _staff.Delete(criteria.Id);
|
||||
return Ok(retval);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using FamilyTreeAPI.Entities;
|
||||
namespace FamilyTreeAPI.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public UsersController(IUserService userService)
|
||||
{
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> Login([FromBody] AuthenticateRequest model)
|
||||
{
|
||||
string remoteIpAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
var response = await _userService.Login(model);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
//[AllowAnonymous]
|
||||
//[HttpPost("[action]")]
|
||||
//public async Task<IActionResult> LoginAD(AuthenticateRequest model)
|
||||
//{
|
||||
// var response = await _userService.LoginAD(model);
|
||||
// return Ok(response);
|
||||
//}
|
||||
[AllowAnonymous]
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> LoginApiAD([FromBody] AuthenticateRequest model)
|
||||
{
|
||||
string remoteIpAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
var response = await _userService.LoginApiAD(model, remoteIpAddress);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
var currentUser = (UserDto)HttpContext.Items["User"];
|
||||
if (null == currentUser)
|
||||
return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
string token = Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
string remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();
|
||||
var response = await _userService.Logout(token, currentUser, remoteIpAddress);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
//[AllowAnonymous]
|
||||
//[HttpGet("[action]")]
|
||||
//public async Task<IActionResult> SearchADStaff(string stafflinkNo)
|
||||
//{
|
||||
// var user = await _userService.SearchADStaff(stafflinkNo);
|
||||
// return Ok(user);
|
||||
//}
|
||||
/*
|
||||
[AllowAnonymous]
|
||||
[HttpGet("[action]")]
|
||||
public async Task<ResultModel<User>> SearchADStaff(string stafflinkNo)
|
||||
{
|
||||
var user = await _userService.SearchADStaff(stafflinkNo);
|
||||
return user;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Data.Common;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
|
||||
namespace FamilyTreeAPI.Models
|
||||
{
|
||||
public partial class FamilyTreeDBContext
|
||||
{
|
||||
private enum EnumStaff
|
||||
{
|
||||
Id =0,
|
||||
Firstname,
|
||||
Lastname,
|
||||
Email,
|
||||
Stype,
|
||||
Active,
|
||||
Role,
|
||||
Password
|
||||
};
|
||||
private enum EnumStaffWork
|
||||
{
|
||||
id =0,
|
||||
staffid,
|
||||
description,
|
||||
startdate,
|
||||
sactive,
|
||||
did,
|
||||
starttime,
|
||||
stoptime,
|
||||
task
|
||||
}
|
||||
private enum EnumServiceTask
|
||||
{
|
||||
id = 0,
|
||||
staffid,
|
||||
sdate,
|
||||
description,
|
||||
code,
|
||||
status,
|
||||
assignTo,
|
||||
clientid,
|
||||
serviceno
|
||||
}
|
||||
|
||||
public async Task<List<StaffDto>> LoadStaffAsync(StaffCriteria criteria)
|
||||
{
|
||||
List<StaffDto> list = new();
|
||||
using (DbConnection connect = this.Database.GetDbConnection())
|
||||
{
|
||||
DbCommand command = connect.CreateCommand();
|
||||
command.CommandType = System.Data.CommandType.Text;
|
||||
command.CommandText = "SELECT * From usp_search_user(:iemail,:ifirstname,:ilastname)";
|
||||
|
||||
var loginParam = command.CreateParameter();
|
||||
|
||||
loginParam.ParameterName = "iemail";
|
||||
loginParam.Value = string.IsNullOrEmpty(criteria.Email) ? "" : criteria.Email;
|
||||
|
||||
var fistnameParam = command.CreateParameter();
|
||||
|
||||
fistnameParam.ParameterName = "ifirstname";
|
||||
fistnameParam.Value = string.IsNullOrEmpty(criteria.FirstName) ? "" : criteria.FirstName;
|
||||
|
||||
var surnameParam = command.CreateParameter() ;
|
||||
|
||||
surnameParam.ParameterName = "ilastname";
|
||||
surnameParam.Value = string.IsNullOrEmpty(criteria.LastName) ? "" : criteria.LastName;
|
||||
|
||||
command.Parameters.Add(loginParam);
|
||||
command.Parameters.Add(fistnameParam);
|
||||
command.Parameters.Add(surnameParam);
|
||||
await connect.OpenAsync();
|
||||
DbDataReader reader = await command.ExecuteReaderAsync();
|
||||
StaffDto staff;
|
||||
int idx = 0;
|
||||
while (reader.Read())
|
||||
{
|
||||
staff = new();
|
||||
idx = (int)EnumStaff.Id;
|
||||
staff.Id = reader.GetFieldValue<int>(idx);
|
||||
idx = (int)EnumStaff.Firstname;
|
||||
staff.Firstname = reader.GetFieldValue<string?>(idx);
|
||||
idx = (int) EnumStaff.Lastname;
|
||||
staff.Lastname = reader.GetFieldValue<string?>(idx);
|
||||
idx = (int)EnumStaff.Email;
|
||||
staff.Email = reader.GetFieldValue<string?>(idx);
|
||||
idx = (int)EnumStaff.Active;
|
||||
staff.Active = reader.GetFieldValue<bool?>(idx);
|
||||
idx = (int)EnumStaff.Role;
|
||||
staff.RoleType = reader.GetFieldValue<int?>(idx);
|
||||
idx = (int)EnumStaff.Password;
|
||||
if (!reader.IsDBNull(idx))
|
||||
staff.Password = reader.GetFieldValue<string?>(idx);
|
||||
|
||||
list.Add(staff);
|
||||
}
|
||||
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
# 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.
|
||||
|
||||
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
||||
#FROM mcr.microsoft.com/dotnet/aspnet:9::.0 AS base
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["FamilyTreeAPI/FamilyTreeAPI.csproj", "FamilyTreeAPI/"]
|
||||
RUN dotnet restore "./FamilyTreeAPI/FamilyTreeAPI.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/FamilyTreeAPI"
|
||||
RUN dotnet build "./FamilyTreeAPI.csproj" -c Release -o /app/build
|
||||
|
||||
# create directory for import folder, and image folder
|
||||
RUN mkdir app_import
|
||||
|
||||
RUN mkdir app_images
|
||||
|
||||
VOLUME /app_import
|
||||
|
||||
VOLUME /app_images
|
||||
# docker run -v my_path_name_volume_host:/app_import my_image_name
|
||||
# docker run -v my_path_named_volume_host:/app_images my_image_name
|
||||
# docker cp /home/user/my_app/config.json my_container:/app/config.json
|
||||
# docker cp /home/user/my_app/data my_container:/app/data ### copy folder data
|
||||
# docker cp mycontainer:/app/output.txt /home/user/documents/
|
||||
|
||||
# This stage is used to publish the service project to be copied to the final stage
|
||||
FROM build AS publish
|
||||
|
||||
RUN dotnet publish "./FamilyTreeAPI.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||
WORKDIR /app
|
||||
ENV ASPNETCORE_HTTP_PORTS=8080
|
||||
EXPOSE 8080
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "FamilyTreeAPI.dll"]
|
||||
@@ -1,18 +0,0 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class AppSettings
|
||||
{
|
||||
public string Secret { get; set; }
|
||||
public string SQLConnectionString { get; set; }
|
||||
public string LoginWebAPI { get; set; }
|
||||
|
||||
public string ClientURL { get; set; }
|
||||
}
|
||||
|
||||
/*
|
||||
entity.HasOne(d => d.Staff)
|
||||
.WithMany(p => p.Staffworks)
|
||||
.HasForeignKey(d => d.Staffid)
|
||||
.HasConstraintName("staffwork_staffid_fkey")
|
||||
.OnDelete(DeleteBehavior.ClientCascade);
|
||||
*/
|
||||
@@ -1,15 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class AuthenticateRequest
|
||||
{
|
||||
[Required]
|
||||
public string Username { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Password { get; set; }
|
||||
|
||||
|
||||
// public string Lhd { get; set; }
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class AuthenticateResponse
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Token { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string? Department { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Position { get; set; }
|
||||
public string? ManagerEmail { get; set; }
|
||||
public int Role { get; set; }
|
||||
|
||||
public AuthenticateResponse(UserDto user, string token, int role)
|
||||
{
|
||||
Id = user.Id;
|
||||
FirstName = user.FirstName;
|
||||
LastName = user.LastName;
|
||||
Username = user.Username;
|
||||
Email = user.Email;
|
||||
Department = user.Department;
|
||||
Position = user.Position;
|
||||
ManagerEmail = user.ManagerEmail;
|
||||
Role = role;
|
||||
Token = token;
|
||||
Phone = user.Phone;
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class FileContent
|
||||
{
|
||||
public byte[] Content { get; set; }
|
||||
public string FileName { get; set; }
|
||||
}
|
||||
public class DownloadFileCriteria
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
}
|
||||
public class UploadCriteria
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public string FamilyId { get; set; }
|
||||
|
||||
public IFormFile File { get; set; }
|
||||
}
|
||||
public class DeleteFileCriteria
|
||||
{
|
||||
public int FamilyId { get; set; }
|
||||
public string Filename { get; set; }
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class CodeDto<T>
|
||||
{
|
||||
public T Code { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
|
||||
//using to store id from file then after insert now the real id from db
|
||||
// the put that in and update the db
|
||||
public class MappingFatherMother
|
||||
{
|
||||
public int TId { get; set; }
|
||||
public int IId { get; set; }
|
||||
public int TFatherId { get; set; }
|
||||
public int TMotherId { get; set; }
|
||||
public int IFatherId { get; set; }
|
||||
public int IMotherId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class LookupDto
|
||||
{
|
||||
public int Id { get; set; } = 0;
|
||||
public string CodeId { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
public class LookupEditDto
|
||||
{
|
||||
public int Id { get; set; } = 0;
|
||||
public string CodeId { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool Active { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class ChildCriteria
|
||||
{
|
||||
public int FatherId { get; set; }
|
||||
public int MotherId { get; set; }
|
||||
|
||||
}
|
||||
public class FamilyCriteria
|
||||
{
|
||||
public bool UseFather { get; set; }
|
||||
public bool UseMother { get; set; }
|
||||
|
||||
}
|
||||
public class PersonCriteria
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
}
|
||||
|
||||
public class PersonForSave
|
||||
{
|
||||
public PersonDto Person { get; set; }
|
||||
public string? FormData { get; set; }
|
||||
public string? FileName { get; set; }
|
||||
|
||||
}
|
||||
public partial class PersonDto
|
||||
{
|
||||
public PersonDto()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Image { get; set; }
|
||||
public string? Sex { get; set; }
|
||||
public string? Address { get; set; }
|
||||
public bool? Alive { get; set; }
|
||||
public string? dob { get; set; }
|
||||
public int? FatherId { get; set; }
|
||||
public int? MotherId { get; set; }
|
||||
|
||||
public List<RelationShipDto>? RelationShips { get; set; }
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class RelationShiftContainer
|
||||
{
|
||||
public int familyId {get; set;}
|
||||
public List<RelationShipDto> relationShips {get; set;}
|
||||
}
|
||||
|
||||
public class ImportRelation
|
||||
{
|
||||
public int FatherId { get; set; }
|
||||
public int MotherId { get; set; }
|
||||
}
|
||||
public class RelationShipDto
|
||||
{
|
||||
public enumState State { get; set; }
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PersonId { get; set; }
|
||||
public int RelatePersonId { get; set; }
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public enum enumState
|
||||
{
|
||||
Delete = -1,
|
||||
NoChange = 0,
|
||||
New = 1,
|
||||
Modify = 2,
|
||||
|
||||
}
|
||||
public class ResultModel<T>
|
||||
{
|
||||
public T Data { get; set; }
|
||||
public int StatusCode { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteCriteria<T>
|
||||
{
|
||||
public T Id { get; set; }
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public partial class StaffCriteria
|
||||
{
|
||||
|
||||
public string Email { get; set; } = null!;
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
|
||||
}
|
||||
public partial class StaffDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Phone { get; set; } = null!;
|
||||
public string? Firstname { get; set; }
|
||||
public string? Lastname { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public string? Email { get; set; }
|
||||
|
||||
public int? Type { get; set; }
|
||||
|
||||
public bool? Active { get; set; }
|
||||
public int? RoleType { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public partial class ResetPassDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Password { get; set; } = null!;
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class TreeNode<T>
|
||||
{
|
||||
public string? Label { get; set; }
|
||||
public T? Data { get; set; }
|
||||
public List<TreeNode<T>>? Children { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
public bool? Checked { get; set; }
|
||||
public bool? Leaf { get; set; }
|
||||
public bool? Expanded { get; set; }
|
||||
public string? Type { get; set; }
|
||||
|
||||
public string StyleClass { get; set; }
|
||||
public string? Key { get; set; }
|
||||
public bool? Loading { get; set; }
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
/*
|
||||
* ROLE ID
|
||||
* Normal = 1,
|
||||
Admin = 2,
|
||||
Manager =3,
|
||||
*/
|
||||
|
||||
public class UserDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string? Department { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Position { get; set; }
|
||||
public string? ManagerEmail { get; set; }
|
||||
public int Role { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Models_old\**" />
|
||||
<Content Remove="Models_old\**" />
|
||||
<EmbeddedResource Remove="Models_old\**" />
|
||||
<None Remove="Models_old\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HotChocolate.AspNetCore" Version="15.1.6" />
|
||||
<PackageReference Include="HotChocolate.Data.EntityFramework" Version="15.1.6" />
|
||||
<PackageReference Include="HotChocolate.Pagination.EntityFramework" Version="14.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageReference Include="SpreadsheetLight" Version="3.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,19 +0,0 @@
|
||||
using FamilyTreeAPI.Models;
|
||||
|
||||
namespace FamilyTreeAPI.GraphQL.Query
|
||||
{
|
||||
public class QueryFamilyTree
|
||||
{
|
||||
[UsePaging]
|
||||
[UseProjection]
|
||||
[UseFiltering]
|
||||
[UseSorting]
|
||||
public IQueryable<Person> GetPersons([Service] FamilyTreeDBContext dBContext) => dBContext.Persons;
|
||||
[UsePaging]
|
||||
[UseProjection]
|
||||
[UseFiltering]
|
||||
[UseSorting]
|
||||
public IQueryable<staff> GetStaffs([Service] FamilyTreeDBContext dBContext) => dBContext.staff;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
namespace FamilyTreeAPI.Helper
|
||||
{
|
||||
public class Helpers
|
||||
{
|
||||
public static string? DateToStr(DateTime? date)
|
||||
{
|
||||
string? result = null;
|
||||
if (date.HasValue)
|
||||
{
|
||||
result = date.Value.ToString("yyyy-MM-dd");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static DateTime? DateToDateTime(string? date)
|
||||
{
|
||||
DateTime? result = null;
|
||||
if (!string.IsNullOrEmpty(date))
|
||||
{
|
||||
DateTime dt;
|
||||
if (DateTime.TryParse(date, out dt))
|
||||
{
|
||||
result = dt;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
The family Tree
|
||||
|
||||
Man and Woman
|
||||
|
||||
top level
|
||||
|
||||
1) TAM (M) has partner Jenny (F)
|
||||
|
||||
had child CAO (M)
|
||||
had Child Emmy (F)
|
||||
has Child Loan (F)
|
||||
|
||||
|
||||
2) CAO (M) has partner Lin (F)
|
||||
|
||||
has child Joe (M)
|
||||
has child TOM (M)
|
||||
|
||||
|
||||
3) Joe has partner Sophia (F)
|
||||
|
||||
has child Olivia (F)
|
||||
has child Mai (F)
|
||||
|
||||
|
||||
4) Henry has partner Loan (F)
|
||||
|
||||
has child Enya (F)
|
||||
has child Thanh (M)
|
||||
has child Chuong (M)
|
||||
|
||||
5) Henry has partner Brisa (F)
|
||||
has child Fern (F)
|
||||
has child Tim (M)
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
1)
|
||||
ubuntu
|
||||
$) sudo bash
|
||||
$) apt-get update
|
||||
$) apt-get install -y dotnet-sdk-9.0
|
||||
$) apt-get install -y aspnetcore-runtime-9.0
|
||||
$) apt-get install -y dotnet-runtime-9.0
|
||||
$) dotnet --info
|
||||
$) apt-get install nginx
|
||||
|
||||
windows
|
||||
net 9 bundle.
|
||||
Windows Hosting Bundle Installer!
|
||||
|
||||
Copy the Files to the Linux Server
|
||||
Next, we need to copy the deployment files to the Ubuntu server. Before we move the files,
|
||||
let’s create the destination folder on the server and set the permissions
|
||||
so that we can add files to it:
|
||||
|
||||
$) cd /var/www
|
||||
$) sudo mkdir app
|
||||
$) sudo chmod 777 app
|
||||
|
||||
Run the App on a Kestrel Web Server
|
||||
In a terminal, navigate to the deployment path and run the app in Kestrel:
|
||||
cd /var/www/app
|
||||
sudo dotnet DeployingToLinuxWithNginx.dll
|
||||
|
||||
//edit nginx config file
|
||||
$ sudo nano /etc/nginx/sites-avaible/default
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection keep-alive;
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
sudo nginx -t
|
||||
sudo nginx -s reload
|
||||
|
||||
To create the service, we first need to create the configurations in a systemd unit file.
|
||||
The unit file contains information regarding the unit, which is a service in this case.
|
||||
For services, it should have the .service extension and contain some
|
||||
information about the service. These files are required to be in the
|
||||
/etc/systemd/system directory.
|
||||
|
||||
Let’s use “nano” to create the unit file and name it kestrel-app.service:
|
||||
|
||||
[Unit]
|
||||
Description=ASP.NET Core Web App running on Ubuntu
|
||||
[Service]
|
||||
WorkingDirectory=/var/www/app
|
||||
ExecStart=/usr/bin/dotnet /var/www/app/DeployingToLinuxWithNginx.dll
|
||||
Restart=always
|
||||
# Restart service after 10 seconds if the dotnet service crashes:
|
||||
RestartSec=10
|
||||
KillSignal=SIGINT
|
||||
SyslogIdentifier=dotnet-web-app
|
||||
# This user should exist on the server and have ownership of the deployment directory
|
||||
User=www-data
|
||||
Environment=ASPNETCORE_ENVIRONMENT=Production
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
After adding the content, save it. Then let’s enable and start the service:
|
||||
sudo systemctl enable kestrel-app.service
|
||||
sudo systemctl start kestrel-app.service
|
||||
|
||||
postgresql.conf:
|
||||
|
||||
Edit postgresql.conf:
|
||||
Locate the postgresql.conf file, typically in /etc/postgresql/<version>/main/postgresql.conf.
|
||||
Change the listen_addresses parameter to '*' to allow connections from any IP address, or specify the IP address(es) you want to allow.
|
||||
```
|
||||
|
||||
listen_addresses = '*'
|
||||
|
||||
|
||||
Locate the postgresql.conf file within the container (e.g., /etc/postgresql/<version>/main/postgresql.conf).
|
||||
Modify listen_addresses:
|
||||
Change listen_addresses = 'localhost' to listen_addresses = '*' to allow connections from any IP address.
|
||||
Alternatively, specify the container's IP address.
|
||||
|
||||
host all all 0.0.0.0/0 md5
|
||||
pg_hba.conf
|
||||
|
||||
**Edit `pg_hba.conf`:**
|
||||
* Locate the `pg_hba.conf` file, typically in `/etc/postgresql/<version>/main/pg_hba.conf`.
|
||||
* Add a line to allow connections from your desired network or specific IP addresses. For example, to allow connections from any IP address on the network using MD5 authentication:
|
||||
* ```
|
||||
host all all 0.0.0.0/0 md5
|
||||
|
||||
|
||||
setup password for postgresql
|
||||
sudo -u postgres psql
|
||||
postgres=#
|
||||
then type \password postgres
|
||||
|
||||
docker run -p 5432:5432 -e POSTGRES_PASSWORD=123456789 \
|
||||
-d postgres:9.3.6 \
|
||||
-c config_file=/path/to/postgresql.conf
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface IJwtUtils
|
||||
{
|
||||
public string GenerateJwtToken(UserDto user);
|
||||
public UserDto? ValidateJwtToken(string token);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface ILookup
|
||||
{
|
||||
Task<ResultModel<int>> SaveLookupAsync(LookupEditDto lookup);
|
||||
Task<ResultModel<List<LookupDto>>> GetLookupAsync(string type);
|
||||
Task<ResultModel<Dictionary<string, LookupDto>>> GetLookupDicAsync(string type);
|
||||
Task<ResultModel<List<LookupEditDto>>> GetLookupEditAsync(string type);
|
||||
Task<ResultModel<LookupEditDto>> GetLookupEditByIdAsync(int codeId, string type);
|
||||
Task<ResultModel<List<LookupDto>>> GetPersonsAsync();
|
||||
Task<ResultModel<List<LookupDto>>> GetStaffAsync();
|
||||
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface IPerson
|
||||
{
|
||||
Task<ResultModel<TreeNode<string>>> GetByFamilyAsync(int id);
|
||||
Task<ResultModel<List<TreeNode<string>>>> GetFamilyTreeBy(FamilyCriteria criteria);
|
||||
Task<ResultModel<List<PersonDto>>> GetChildren(ChildCriteria criteria);
|
||||
Task<ResultModel<List<PersonDto>>> GetPerson(PersonCriteria criteria);
|
||||
Task<ResultModel<Dictionary<int,PersonDto>>> GetDicFamily();
|
||||
Task<ResultModel<PersonDto>> GetByIdAsync(int id);
|
||||
Task<ResultModel<int>> DeleteAsync(int id);
|
||||
|
||||
Task<ResultModel<string>> UploadImage(UploadCriteria criteria);
|
||||
ResultModel<int> DeleteUploadFile(DeleteFileCriteria criteria);
|
||||
Task<ResultModel<int>> SaveAsync(PersonForSave dto);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface IRelationShipd
|
||||
{
|
||||
Task<ResultModel<int>> SaveAsync(List<RelationShipDto> dto);
|
||||
//load by personId
|
||||
Task<ResultModel<List<RelationShipDto>>> GetByPersonIdAsync(int personId);
|
||||
Task<ResultModel<RelationShipDto>> GetByIdAsync(int Id);
|
||||
|
||||
Task<ResultModel<int>> DeleteAsync(int personId);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
public interface IReport
|
||||
{
|
||||
// Task<ResultModel<FileContent>> GetMotorVehicleReportAsync(MotorVehicleCriteria criteria);
|
||||
// Task<ResultModel<FileContent>> GetStaffWorkReportAsync(StaffWorkCriteria criteria);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface IStaff
|
||||
{
|
||||
|
||||
Task<ResultModel<Dictionary<int,StaffDto>>> GetDicStaffs();
|
||||
Task<ResultModel<List<StaffDto>>> GetStaff(StaffCriteria criteria);
|
||||
Task<ResultModel<StaffDto>> GetStaffById(int id);
|
||||
Task<ResultModel<int>> SaveStaff(StaffDto code);
|
||||
Task<ResultModel<int>> ResetPassword(ResetPassDto code);
|
||||
Task<ResultModel<int>> SaveStaffNew(StaffDto adminUser);
|
||||
|
||||
Task<ResultModel<int>> Delete(int id);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
public interface IUserService
|
||||
{
|
||||
|
||||
Task<ResultModel<AuthenticateResponse>> LoginApiAD(AuthenticateRequest model, string remoteIpAddress);
|
||||
Task<ResultModel<AuthenticateResponse>> Login(AuthenticateRequest model);
|
||||
Task<ResultModel<int>> Logout(string token, UserDto user, string remoteIpAddress);
|
||||
|
||||
// Task<ResultModel<User>> SearchApiStaff(string staffLinkNo);
|
||||
// Task<ResultModel<User>> SearchADStaff(string staffLinkNo);
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
namespace FamilyTreeAPI.Models
|
||||
{
|
||||
public partial class FamilyTreeDBContext : DbContext
|
||||
{
|
||||
public FamilyTreeDBContext()
|
||||
{
|
||||
}
|
||||
|
||||
public FamilyTreeDBContext(DbContextOptions<FamilyTreeDBContext> options)
|
||||
: base(options)
|
||||
{
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
}
|
||||
|
||||
public virtual DbSet<Person> Persons { get; set; } = null!;
|
||||
public virtual DbSet<RelationShip> RelationShips { get; set; } = null!;
|
||||
public virtual DbSet<Lookup> Lookups { get; set; } = null!;
|
||||
public virtual DbSet<staff> staff { get; set; } = null!;
|
||||
|
||||
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<Person>(entity =>
|
||||
{
|
||||
entity.ToTable("person");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
|
||||
entity.Property(e => e.Address)
|
||||
.HasMaxLength(120)
|
||||
.HasColumnName("address");
|
||||
|
||||
entity.Property(e => e.Alive).HasColumnName("alive");
|
||||
entity.Property(e => e.dob).HasColumnName("dob");
|
||||
entity.Property(e => e.MotherId).HasColumnName("motherid");
|
||||
entity.Property(e => e.FatherId).HasColumnName("fatherid");
|
||||
|
||||
entity.Property(e => e.FirstName)
|
||||
.HasMaxLength(70)
|
||||
.HasColumnName("firstname");
|
||||
entity.Property(e => e.Sex)
|
||||
.HasMaxLength(10)
|
||||
.HasColumnName("sex");
|
||||
entity.Property(e => e.Image)
|
||||
.HasMaxLength(300)
|
||||
.HasColumnName("image");
|
||||
|
||||
entity.Property(e => e.LastName)
|
||||
.HasMaxLength(70)
|
||||
.HasColumnName("lastname");
|
||||
|
||||
entity.Property(e => e.Email)
|
||||
.HasMaxLength(80)
|
||||
.HasColumnName("email");
|
||||
|
||||
entity.Property(e => e.Phone)
|
||||
.HasMaxLength(30)
|
||||
.HasColumnName("phone");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RelationShip>(entity =>
|
||||
{
|
||||
entity.ToTable("relationship");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
entity.Property(e => e.RelatePersonId).HasColumnName("relatepersonid");
|
||||
entity.Property(e => e.PersonId).HasColumnName("personid");
|
||||
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Lookup>(entity =>
|
||||
{
|
||||
entity.ToTable("lookup");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
|
||||
entity.Property(e => e.Code)
|
||||
.HasMaxLength(10)
|
||||
.HasColumnName("code");
|
||||
|
||||
entity.Property(e => e.Description)
|
||||
.HasMaxLength(80)
|
||||
.HasColumnName("description");
|
||||
|
||||
entity.Property(e => e.Lactive).HasColumnName("lactive");
|
||||
|
||||
entity.Property(e => e.Type).HasMaxLength(20)
|
||||
.HasColumnName("ltype");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<staff>(entity =>
|
||||
{
|
||||
entity.ToTable("staff");
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
|
||||
entity.Property(e => e.Email)
|
||||
.HasMaxLength(80)
|
||||
.HasColumnName("email");
|
||||
|
||||
entity.Property(e => e.Firstname)
|
||||
.HasMaxLength(70)
|
||||
.HasColumnName("firstname");
|
||||
|
||||
entity.Property(e => e.Lastname)
|
||||
.HasMaxLength(70)
|
||||
.HasColumnName("lastname");
|
||||
|
||||
entity.Property(e => e.Phone)
|
||||
.HasMaxLength(30)
|
||||
.HasColumnName("phone");
|
||||
|
||||
entity.Property(e => e.Sactive).HasColumnName("sactive");
|
||||
|
||||
entity.Property(e => e.Spassword)
|
||||
.HasMaxLength(200)
|
||||
.HasColumnName("spassword");
|
||||
|
||||
entity.Property(e => e.Srole).HasColumnName("srole");
|
||||
|
||||
entity.Property(e => e.Stype).HasColumnName("stype");
|
||||
});
|
||||
|
||||
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user