Modernize and Dockerize server
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,7 +4,8 @@
|
||||
client/node_modules
|
||||
client/dist
|
||||
|
||||
.vs
|
||||
.vs/
|
||||
.user
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
|
||||
30
server/.dockerignore
Normal file
30
server/.dockerignore
Normal file
@@ -0,0 +1,30 @@
|
||||
**/.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,13 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<UserSecretsId>a7b40068-a2f6-4c63-bbd9-0fd346908fb0</UserSecretsId>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerfileContext>..\..</DockerfileContext>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.1.72" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
@@ -1,40 +1,29 @@
|
||||
using CPATapi.Server.Interfaces;
|
||||
using CPATapi.Server.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Dapper;
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace CPATapi.Server.Controllers
|
||||
namespace CPATapi.Server.Controllers;
|
||||
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
public class AvailabilityController(IZeitConsensRepository zeitConsens) : ControllerBase
|
||||
{
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
public class AvailabilityController(IConfiguration config) : ControllerBase
|
||||
[HttpGet]
|
||||
[Route("users")]
|
||||
[ProducesResponseType<IEnumerable<string>>(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetUsers()
|
||||
{
|
||||
[HttpGet, Route("users")]
|
||||
public async Task<IEnumerable<string>> GetUsers()
|
||||
{
|
||||
await using var con = new SqlConnection(config["Db:ConnectionStringZc"]);
|
||||
await con.OpenAsync();
|
||||
return await con.QueryAsync<string>("""
|
||||
SELECT DISTINCT MA_USER_NAME
|
||||
FROM dbo.MA_DATEN
|
||||
WHERE MA_USER_NAME IS NOT NULL AND MA_USER_AKTIV = 1
|
||||
ORDER BY MA_USER_NAME
|
||||
""");
|
||||
return Ok(await zeitConsens.GetUsersAsync());
|
||||
}
|
||||
|
||||
[HttpGet, Route("{user}")]
|
||||
public async Task<object> GetAvailability(string user)
|
||||
[HttpGet]
|
||||
[Route("{user}")]
|
||||
[ProducesResponseType<Availability>(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetAvailability(string user)
|
||||
{
|
||||
await using var con = new SqlConnection(config["Db:ConnectionStringZc"]);
|
||||
await con.OpenAsync();
|
||||
var stampCount = (await con.QueryAsync("""
|
||||
SELECT *
|
||||
FROM dbo.BU
|
||||
INNER JOIN dbo.MA_DATEN on MA_NR = BU_MA_NR
|
||||
WHERE
|
||||
MA_USER_NAME = @user AND
|
||||
BU_BU >= @date AND BU_BU < @tomorrow
|
||||
""", new { user, date = DateTime.Now.Date, tomorrow = DateTime.Now.AddDays(1).Date })).Count();
|
||||
return new { user, loggedIn = stampCount % 2 != 0 };
|
||||
}
|
||||
var stampCount = (await zeitConsens.GetStampsAsync(user, DateTime.Now.Date, DateTime.Now.AddDays(1).Date)).Count();
|
||||
return Ok(new Availability { User = user, LoggedIn = stampCount % 2 != 0 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
using CPATapi.Server.Interfaces;
|
||||
using CPATapi.Server.Models;
|
||||
using Dapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace CPATapi.Server.Controllers
|
||||
namespace CPATapi.Server.Controllers;
|
||||
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
public class CallerIdController(ITapiDirectoryRepository tapiDirectory) : ControllerBase
|
||||
{
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
public class CallerIdController(IConfiguration config) : ControllerBase
|
||||
{
|
||||
[HttpGet, Route("{number}")]
|
||||
public async Task<TapiContact> CallerIdAsync([FromRoute] string number)
|
||||
[HttpGet]
|
||||
[Route("{number}")]
|
||||
[ProducesResponseType<TapiContact>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> CallerIdAsync([FromRoute] string number)
|
||||
{
|
||||
if (number.Length >= 5)
|
||||
{
|
||||
@@ -18,20 +20,11 @@ namespace CPATapi.Server.Controllers
|
||||
number = "%" + minMatch;
|
||||
}
|
||||
|
||||
await using var con = new SqlConnection(config["Db:ConnectionString"]);
|
||||
await con.OpenAsync();
|
||||
|
||||
var result = await con.QueryFirstOrDefaultAsync<TapiContact>("""
|
||||
SELECT
|
||||
TD_ID,
|
||||
TD_NAME,
|
||||
TD_NUMBER,
|
||||
TD_NUMBER_TAPI,
|
||||
TD_MEDIUM
|
||||
FROM dbo.CP_TAPI_DIRECTORY
|
||||
WHERE TD_NUMBER_TAPI LIKE @number
|
||||
""", new {number});
|
||||
return result;
|
||||
var result = await tapiDirectory.SearchByNumberAsync(number);
|
||||
if (result != null)
|
||||
{
|
||||
return Ok(result);
|
||||
}
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,21 @@
|
||||
using CPATapi.Server.Interfaces;
|
||||
using CPATapi.Server.Models;
|
||||
using Dapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace CPATapi.Server.Controllers
|
||||
namespace CPATapi.Server.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class ContactController(ILogger<ContactController> logger, ITapiDirectoryRepository tapiDirectory) : ControllerBase
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class ContactController(ILogger<ContactController> logger, IConfiguration config) : ControllerBase
|
||||
{
|
||||
|
||||
private readonly ILogger<ContactController> _logger = logger;
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<TapiContact>> GetAsync()
|
||||
[Produces("application/json")]
|
||||
[ProducesResponseType<IEnumerable<TapiContact>>(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetAsync()
|
||||
{
|
||||
await using var con = new SqlConnection(config["Db:ConnectionString"]);
|
||||
await con.OpenAsync();
|
||||
|
||||
var contacts = await con.QueryAsync<TapiContact>("""
|
||||
SELECT
|
||||
TD_ID,
|
||||
TD_NAME,
|
||||
TD_NUMBER,
|
||||
TD_NUMBER_TAPI,
|
||||
TD_MEDIUM
|
||||
FROM dbo.CP_TAPI_DIRECTORY
|
||||
""");
|
||||
return contacts;
|
||||
}
|
||||
return Ok(await tapiDirectory.GetAllAsync());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,25 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using CPATapi.Server.Interfaces;
|
||||
using CPATapi.Server.Models;
|
||||
using Dapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace CPATapi.Server.Controllers
|
||||
namespace CPATapi.Server.Controllers;
|
||||
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
public class SearchController(ITapiDirectoryRepository tapiDirectory) : ControllerBase
|
||||
{
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
public class SearchController(IConfiguration config) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<TapiContact>> SearchAsync([FromQuery] string query)
|
||||
[ProducesResponseType<IEnumerable<TapiContact>>(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> SearchAsync([FromQuery] string query)
|
||||
{
|
||||
if (query == null)
|
||||
{
|
||||
return new List<TapiContact>();
|
||||
return Ok(new List<TapiContact>());
|
||||
}
|
||||
|
||||
var args = Regex.Split(query, "\\s").Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).ToArray();
|
||||
|
||||
if (args.Length == 0)
|
||||
{
|
||||
return new List<TapiContact>();
|
||||
}
|
||||
|
||||
await using var con = new SqlConnection(config["Db:ConnectionString"]);
|
||||
await con.OpenAsync();
|
||||
var sql = new StringBuilder("""
|
||||
SELECT TOP 10
|
||||
TD_ID,
|
||||
TD_NAME,
|
||||
TD_NUMBER,
|
||||
TD_NUMBER_TAPI,
|
||||
TD_MEDIUM
|
||||
FROM dbo.CP_TAPI_DIRECTORY
|
||||
WHERE
|
||||
""");
|
||||
var first = true;
|
||||
var dp = new DynamicParameters();
|
||||
for (var i = 1; i <= args.Length; i++)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
sql.AppendLine("AND");
|
||||
}
|
||||
first = false;
|
||||
sql.AppendLine($"(TD_NAME LIKE @s{i} OR");
|
||||
sql.AppendLine($" TD_NUMBER_TAPI LIKE @s{i})");
|
||||
dp.Add($"s{i}", $"%{args[i-1]}%");
|
||||
}
|
||||
|
||||
return await con.QueryAsync<TapiContact>(sql.ToString(), dp);
|
||||
}
|
||||
return Ok(await tapiDirectory.SearchAsync(args));
|
||||
}
|
||||
}
|
||||
|
||||
28
server/src/CPATapi.Server/Dockerfile
Normal file
28
server/src/CPATapi.Server/Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
||||
# 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:10.0 AS base
|
||||
USER $APP_UID
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
|
||||
# This stage is used to build the service project
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["CPATapi.Server/CPATapi.Server.csproj", "CPATapi.Server/"]
|
||||
RUN dotnet restore "CPATapi.Server/CPATapi.Server.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/CPATapi.Server"
|
||||
RUN dotnet build "./CPATapi.Server.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
# This stage is used to publish the service project to be copied to the final stage
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "./CPATapi.Server.csproj" -c $BUILD_CONFIGURATION -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 base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "CPATapi.Server.dll"]
|
||||
5
server/src/CPATapi.Server/Interfaces/IRepository.cs
Normal file
5
server/src/CPATapi.Server/Interfaces/IRepository.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace CPATapi.Server.Interfaces;
|
||||
|
||||
public interface IRepository
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using CPATapi.Server.Models;
|
||||
|
||||
namespace CPATapi.Server.Interfaces;
|
||||
|
||||
public interface ITapiDirectoryRepository : IRepository
|
||||
{
|
||||
Task<IEnumerable<TapiContact>> SearchAsync(string[] args);
|
||||
Task<TapiContact?> SearchByNumberAsync(string number);
|
||||
Task<IEnumerable<TapiContact>> GetAllAsync();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using CPATapi.Server.Models;
|
||||
|
||||
namespace CPATapi.Server.Interfaces;
|
||||
|
||||
public interface IZeitConsensRepository : IRepository
|
||||
{
|
||||
Task<IEnumerable<string>> GetUsersAsync();
|
||||
Task<IEnumerable<Stamp>> GetStampsAsync(string user, DateTime from, DateTime to);
|
||||
}
|
||||
11
server/src/CPATapi.Server/Models/Availability.cs
Normal file
11
server/src/CPATapi.Server/Models/Availability.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace CPATapi.Server.Models;
|
||||
|
||||
public class Availability
|
||||
{
|
||||
[JsonPropertyName("user")]
|
||||
public string User { get; set; }
|
||||
[JsonPropertyName("loggedIn")]
|
||||
public bool LoggedIn { get; set; }
|
||||
}
|
||||
7
server/src/CPATapi.Server/Models/Stamp.cs
Normal file
7
server/src/CPATapi.Server/Models/Stamp.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace CPATapi.Server.Models;
|
||||
|
||||
public class Stamp
|
||||
{
|
||||
public int MA_NR { get; set; }
|
||||
public DateTime BU_BU { get; set; }
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace CPATapi.Server.Models
|
||||
namespace CPATapi.Server.Models;
|
||||
|
||||
public class TapiContact
|
||||
{
|
||||
public class TapiContact
|
||||
{
|
||||
public string TD_ID { get; set; }
|
||||
public string TD_NAME { get; set; }
|
||||
public string TD_NUMBER { get; set; }
|
||||
public string TD_NUMBER_TAPI { get; set; }
|
||||
public string TD_MEDIUM { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
using CPATapi.Server.Interfaces;
|
||||
using CPATapi.Server.Repository;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddTransient<ITapiDirectoryRepository, TapiDirectoryRepository>();
|
||||
builder.Services.AddTransient<IZeitConsensRepository, ZeitConsensRepository>();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
|
||||
var app = builder.Build();
|
||||
@@ -13,4 +19,4 @@ app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
await app.RunAsync();
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:62406",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
@@ -20,11 +11,30 @@
|
||||
"CPATapiServer": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "weatherforecast",
|
||||
"launchUrl": "availability/users",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
||||
"applicationUrl": "https://3cxtapi.cp-austria.at:5001;https://localhost:5001;http://localhost:5000"
|
||||
},
|
||||
"Container (Dockerfile)": {
|
||||
"commandName": "Docker",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/contact",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_HTTP_PORTS": "8080"
|
||||
},
|
||||
"publishAllPorts": true,
|
||||
"useSSL": false
|
||||
}
|
||||
},
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:62406",
|
||||
"sslPort": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
21
server/src/CPATapi.Server/Repository/Repository.cs
Normal file
21
server/src/CPATapi.Server/Repository/Repository.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Data.Common;
|
||||
using CPATapi.Server.Interfaces;
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace CPATapi.Server.Repository;
|
||||
|
||||
public class Repository: IRepository
|
||||
{
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
protected Repository(IConfiguration config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
protected async Task<DbConnection> OpenAsync(string name)
|
||||
{
|
||||
var db = new SqlConnection(_config.GetConnectionString(name));
|
||||
await db.OpenAsync();
|
||||
return db;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Text;
|
||||
using CPATapi.Server.Interfaces;
|
||||
using CPATapi.Server.Models;
|
||||
using Dapper;
|
||||
|
||||
namespace CPATapi.Server.Repository;
|
||||
|
||||
internal class TapiDirectoryRepository(IConfiguration config) : Repository(config), ITapiDirectoryRepository
|
||||
{
|
||||
public async Task<IEnumerable<TapiContact>> SearchAsync(string[] args)
|
||||
{
|
||||
await using var con = await OpenAsync("Tapi");
|
||||
var sql = new StringBuilder("""
|
||||
SELECT TOP 10
|
||||
TD_ID,
|
||||
TD_NAME,
|
||||
TD_NUMBER,
|
||||
TD_NUMBER_TAPI,
|
||||
TD_MEDIUM
|
||||
FROM dbo.CP_TAPI_DIRECTORY
|
||||
WHERE
|
||||
""");
|
||||
var first = true;
|
||||
var dp = new DynamicParameters();
|
||||
for (var i = 1; i <= args.Length; i++)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
sql.AppendLine("AND");
|
||||
}
|
||||
first = false;
|
||||
sql.AppendLine($"(TD_NAME LIKE @s{i} OR");
|
||||
sql.AppendLine($" TD_NUMBER_TAPI LIKE @s{i})");
|
||||
dp.Add($"s{i}", $"%{args[i-1]}%");
|
||||
}
|
||||
|
||||
return await con.QueryAsync<TapiContact>(sql.ToString(), dp);
|
||||
}
|
||||
|
||||
public async Task<TapiContact?> SearchByNumberAsync(string number)
|
||||
{
|
||||
await using var con = await OpenAsync("Tapi");
|
||||
|
||||
var result = await con.QueryFirstOrDefaultAsync<TapiContact>("""
|
||||
SELECT
|
||||
TD_ID
|
||||
,TD_NAME
|
||||
,TD_NUMBER
|
||||
,TD_NUMBER_TAPI
|
||||
,TD_MEDIUM
|
||||
FROM dbo.CP_TAPI_DIRECTORY
|
||||
WHERE TD_NUMBER_TAPI LIKE @number
|
||||
""", new {number});
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TapiContact>> GetAllAsync()
|
||||
{
|
||||
await using var con = await OpenAsync("Tapi");
|
||||
|
||||
return await con.QueryAsync<TapiContact>("""
|
||||
SELECT
|
||||
TD_ID
|
||||
,TD_NAME
|
||||
,TD_NUMBER
|
||||
,TD_NUMBER_TAPI
|
||||
,TD_MEDIUM
|
||||
FROM dbo.CP_TAPI_DIRECTORY
|
||||
""");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using CPATapi.Server.Interfaces;
|
||||
using CPATapi.Server.Models;
|
||||
using Dapper;
|
||||
|
||||
namespace CPATapi.Server.Repository;
|
||||
|
||||
internal class ZeitConsensRepository(IConfiguration config) : Repository(config), IZeitConsensRepository
|
||||
{
|
||||
public async Task<IEnumerable<string>> GetUsersAsync()
|
||||
{
|
||||
await using var con = await OpenAsync("ZeitConsens");
|
||||
return await con.QueryAsync<string>("""
|
||||
SELECT DISTINCT MA_USER_NAME
|
||||
FROM dbo.MA_DATEN
|
||||
WHERE MA_USER_NAME IS NOT NULL AND MA_USER_AKTIV = 1
|
||||
ORDER BY MA_USER_NAME
|
||||
""");
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Stamp>> GetStampsAsync(string user, DateTime from, DateTime to)
|
||||
{
|
||||
await using var con = await OpenAsync("ZeitConsens");
|
||||
return await con.QueryAsync<Stamp>("""
|
||||
SELECT
|
||||
MA_NR
|
||||
,BU_BU
|
||||
FROM dbo.BU
|
||||
INNER JOIN dbo.MA_DATEN on MA_NR = BU_MA_NR
|
||||
WHERE
|
||||
MA_USER_NAME = @user AND
|
||||
BU_BU >= @from AND BU_BU < @to
|
||||
""", new { user, from, to });
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"Db": {
|
||||
"ConnectionString": "",
|
||||
"ConnectionStringZc": ""
|
||||
"ConnectionStrings": {
|
||||
"Tapi": "",
|
||||
"ZeitConsens": ""
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
19
server/src/CPATapi.Server/publish.bat
Normal file
19
server/src/CPATapi.Server/publish.bat
Normal file
@@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
setlocal
|
||||
cd /d %~dp0
|
||||
|
||||
docker build -t source.cp-austria.at/cpatrd/3cx_tapi:latest -f Dockerfile ..
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo ERROR: Docker build failed!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
|
||||
SET /P AREYOUSURE=Publish to source.cp-austria.at? (Y/[N])
|
||||
IF /I "%AREYOUSURE%" NEQ "Y" GOTO END
|
||||
|
||||
docker push source.cp-austria.at/cpatrd/3cx_tapi:latest
|
||||
|
||||
:END
|
||||
endlocal
|
||||
Reference in New Issue
Block a user