Restliche Funktionen Hinzugefügt

Siehe Projekttagebuch
This commit is contained in:
2026-02-04 14:32:53 +01:00
parent 34366d782c
commit 6dfd21da3b
420 changed files with 8088 additions and 114 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,37 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{0BBF8E29-1D9F-41AD-A1A2-637C72FA90D1}|TicketSystem.csproj|c:\\users\\tweee\\source\\repos\\projekt-dev-env\\src\\project-cbackend\\ticketsystem\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{0BBF8E29-1D9F-41AD-A1A2-637C72FA90D1}|TicketSystem.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "Program.cs",
"DocumentMoniker": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\Program.cs",
"RelativeDocumentMoniker": "Program.cs",
"ToolTip": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\Program.cs",
"RelativeToolTip": "Program.cs",
"ViewState": "AgIAAHwAAAAAAAAAAAAAAIEAAABEAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-03T10:53:32.912Z",
"EditorCaption": ""
}
]
}
]
}
]
}

View File

@@ -0,0 +1,37 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{0BBF8E29-1D9F-41AD-A1A2-637C72FA90D1}|TicketSystem.csproj|c:\\users\\tweee\\source\\repos\\projekt-dev-env\\src\\project-cbackend\\ticketsystem\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{0BBF8E29-1D9F-41AD-A1A2-637C72FA90D1}|TicketSystem.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "Program.cs",
"DocumentMoniker": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\Program.cs",
"RelativeDocumentMoniker": "Program.cs",
"ToolTip": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\Program.cs",
"RelativeToolTip": "Program.cs",
"ViewState": "AgIAACoAAAAAAAAAAAAAADIAAAA4AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-03T10:53:32.912Z",
"EditorCaption": ""
}
]
}
]
}
]
}

View File

@@ -1,12 +1,20 @@
using BCrypt.Net; using BCrypt.Net;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Identity.Data; using Microsoft.AspNetCore.Identity.Data;
using Microsoft.AspNetCore.WebSockets;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using MySqlConnector; using MySqlConnector;
using SIPSorcery.Net;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Net.WebSockets;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using System.Text.Json;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@@ -17,13 +25,24 @@ var jwtAudience = builder.Configuration["Jwt:Audience"] ?? "Ticket-System";
builder.Services.AddTransient(_ => new MySqlConnection(connectionString)); builder.Services.AddTransient(_ => new MySqlConnection(connectionString));
builder.Services.AddWebSockets(options =>
{
options.KeepAliveInterval = TimeSpan.FromSeconds(120);
});
var app = builder.Build(); var app = builder.Build();
app.UseWebSockets();
app.Use(async (context, next) => app.Use(async (context, next) =>
{ {
var path = context.Request.Path.Value ?? ""; var path = context.Request.Path.Value ?? "";
if (path.Equals("/signin", StringComparison.OrdinalIgnoreCase)) //|| path.Equals("/user/create", StringComparison.OrdinalIgnoreCase)) if (path.Equals("/signin", StringComparison.OrdinalIgnoreCase)
|| path.Equals("/webrtc", StringComparison.OrdinalIgnoreCase)
|| path.Equals("/user/create", StringComparison.OrdinalIgnoreCase))
{ {
await next(); await next();
return; return;
@@ -55,40 +74,365 @@ app.Use(async (context, next) =>
await context.Response.WriteAsJsonAsync(new { error = "Invalid token specified" }); await context.Response.WriteAsJsonAsync(new { error = "Invalid token specified" });
return; return;
} }
context.Items["user"] = principal.FindFirstValue(ClaimTypes.NameIdentifier) ?? "";
context.Items["user"] = principal.Identity?.Name ?? principal.FindFirstValue(ClaimTypes.Name) ?? ""; //context.Items["user"] = principal.Identity?.Name ?? principal.FindFirstValue(ClaimTypes.Name) ?? "";
await next(); await next();
}); });
app.MapPost("/signin", async (SignInRequest req, MySqlConnection conn) => app.MapPost("/signin", async (SignInRequest req, MySqlConnection conn) =>
{ {
const string sql = "SELECT userID, username, password FROM User WHERE username = @username LIMIT 1;"; try
{
const string sql = "SELECT userID, username, password FROM User WHERE username = @username LIMIT 1;";
await conn.OpenAsync();
await using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@username", req.user);
await using var reader = await cmd.ExecuteReaderAsync();
if (!await reader.ReadAsync())
return Results.Unauthorized();
var userId = reader.GetInt32("userID").ToString();
var username = reader.GetString("username");
var pwHash = reader.GetString("password");
var ok = BCrypt.Net.BCrypt.Verify(req.password, pwHash);
if (!ok)
return Results.Unauthorized();
conn.Close();
await conn.OpenAsync();
var token = CreateJwt(userId, username, jwtSecret, jwtIssuer, jwtAudience, minutesValid: 120);
const string cleanupSql = "DELETE FROM ValidateToken\r\nWHERE STR_TO_DATE(validationDate, '%Y-%m-%d %H:%i:%s')\r\n < (UTC_TIMESTAMP() - INTERVAL 24 HOUR);\r\n";
await using (var cleanup = new MySqlCommand(cleanupSql, conn))
{
await cleanup.ExecuteNonQueryAsync();
}
conn.Close();
await conn.OpenAsync();
const string insertTokenSql = """
INSERT INTO ValidateToken (validationDate, token)
VALUES (@validationdate, @token);
""";
await using (var ins = new MySqlCommand(insertTokenSql, conn))
{
ins.Parameters.AddWithValue("@token", token);
ins.Parameters.AddWithValue("@validationdate", DateTime.Now);
await ins.ExecuteNonQueryAsync();
}
conn.Close();
return Results.Ok(new ResponseToken(token));
}
catch (Exception ex)
{
return Results.Problem(ex.Message);
}
});
#region web rtc
app.Map("/webrtc", async context =>
{
if (!context.WebSockets.IsWebSocketRequest)
{
context.Response.StatusCode = 400;
return;
}
var token = context.Request.Query["token"].ToString();
var principal = string.IsNullOrWhiteSpace(token) ? null : ValidateJwt(token, jwtSecret, jwtIssuer, jwtAudience);
if (principal == null)
{
context.Response.StatusCode = 401;
return;
}
using var socket = await context.WebSockets.AcceptWebSocketAsync();
var pc = new RTCPeerConnection(new RTCConfiguration
{
iceServers = new List<RTCIceServer>
{
new RTCIceServer { urls = "http://10.204.192.64:3000" }
}
});
pc.oniceconnectionstatechange += (state) =>
Console.WriteLine($"[webrtc] ICE: {state}");
pc.onconnectionstatechange += (state) =>
Console.WriteLine($"[webrtc] PC: {state}");
// Server -> Client: ICE candidates
pc.onicecandidate += async cand =>
{
if (cand == null || socket.State != WebSocketState.Open) return;
var json = JsonSerializer.Serialize(cand);
await socket.SendAsync(Encoding.UTF8.GetBytes(json),
WebSocketMessageType.Text, true, CancellationToken.None);
};
var buffer = new byte[32 * 1024];
var jsonOpts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
while (socket.State == WebSocketState.Open)
{
using var ms = new MemoryStream();
WebSocketReceiveResult res;
do
{
res = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (res.MessageType == WebSocketMessageType.Close)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None);
return;
}
ms.Write(buffer, 0, res.Count);
}
while (!res.EndOfMessage);
var msg = Encoding.UTF8.GetString(ms.ToArray());
if (msg.Contains("\"sdp\"", StringComparison.OrdinalIgnoreCase))
{
// Browser sendet meist { type: "offer", sdp: "..." }
var sdp = JsonSerializer.Deserialize<RTCSessionDescriptionInit>(msg, jsonOpts);
if (sdp == null)
{
Console.WriteLine("[webrtc] SDP deserialize = null");
continue;
}
// SIPSorcery kann je nach Version sync/async sein -> wir behandeln BEIDES:
var setRemoteOk = await SetRemote(pc, sdp);
if (!setRemoteOk)
{
Console.WriteLine("[webrtc] setRemoteDescription failed");
continue;
}
if (sdp.type == RTCSdpType.offer)
{
var answer = pc.createAnswer(null);
var setLocalOk = await SetLocal(pc, answer);
if (!setLocalOk)
{
Console.WriteLine("[webrtc] setLocalDescription failed");
continue;
}
var json = JsonSerializer.Serialize(answer, jsonOpts);
await socket.SendAsync(Encoding.UTF8.GetBytes(json),
WebSocketMessageType.Text, true, CancellationToken.None);
}
continue;
}
// ---- ICE candidate from client
if (msg.Contains("candidate", StringComparison.OrdinalIgnoreCase))
{
var ice = JsonSerializer.Deserialize<RTCIceCandidateInit>(msg, jsonOpts);
if (ice == null)
{
Console.WriteLine("[webrtc] ICE deserialize = null");
continue;
}
pc.addIceCandidate(ice);
continue;
}
Console.WriteLine($"[webrtc] unknown msg: {msg}");
}
});
static async Task HandleWebRtc(WebSocket socket)
{
var pc = new RTCPeerConnection(new RTCConfiguration
{
iceServers = new List<RTCIceServer>
{
new RTCIceServer { urls = "stun:stun.l.google.com:19302" }
}
});
pc.onicecandidate += async candidate =>
{
if (candidate != null)
{
var json = JsonSerializer.Serialize(candidate);
await socket.SendAsync(
Encoding.UTF8.GetBytes(json),
WebSocketMessageType.Text,
true,
CancellationToken.None
);
}
};
pc.onconnectionstatechange += (state) =>
{
Console.WriteLine($"[webrtc] connection state: {state}");
};
pc.oniceconnectionstatechange += (state) =>
{
Console.WriteLine($"[webrtc] ICE state: {state}");
};
pc.onicecandidate += (cand) =>
{
if (cand != null) Console.WriteLine("[webrtc] ICE candidate generated");
};
var buffer = new byte[8192];
var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
while (socket.State == WebSocketState.Open)
{
var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
break;
var msg = Encoding.UTF8.GetString(buffer, 0, result.Count);
if (msg.Contains("\"sdp\""))
{
var sdp = JsonSerializer.Deserialize<RTCSessionDescriptionInit>(msg, jsonOptions);
if (sdp == null) continue;
var r1 = pc.setRemoteDescription(sdp);
if (r1 != SetDescriptionResultEnum.OK)
{
Console.WriteLine($"setRemoteDescription failed: {r1}");
continue;
}
if (sdp.type == RTCSdpType.offer)
{
var answer = pc.createAnswer(null);
var r2 = pc.setLocalDescription(answer);
var json = JsonSerializer.Serialize(answer, jsonOptions);
await socket.SendAsync(
Encoding.UTF8.GetBytes(json),
WebSocketMessageType.Text,
true,
CancellationToken.None
);
}
}
else if (msg.Contains("candidate"))
{
var ice = JsonSerializer.Deserialize<RTCIceCandidateInit>(msg, jsonOptions);
if (ice == null) continue;
pc.addIceCandidate(ice);
}
}
}
static async Task<bool> SetRemote(RTCPeerConnection pc, RTCSessionDescriptionInit sdp)
{
var r = pc.setRemoteDescription(sdp);
if (r is SetDescriptionResultEnum e)
return e == SetDescriptionResultEnum.OK;
if (r != null && r.GetType().Name.Contains("SetDescriptionResult"))
{
var prop = r.GetType().GetProperty("Result");
if (prop?.GetValue(r) is SetDescriptionResultEnum e2)
return e2 == SetDescriptionResultEnum.OK;
}
return false;
}
static async Task<bool> SetLocal(RTCPeerConnection pc, RTCSessionDescriptionInit sdp)
{
var r = pc.setLocalDescription(sdp);
//if (r is SetDescriptionResultEnum e)
// return e == SetDescriptionResultEnum.OK;
//if (r != SetDescriptionResultEnum.OK)
//{
// Console.WriteLine($"setLocalDescription failed: {r}");
// //continue;
//}
if (r is Task<SetDescriptionResultEnum> t)
return (await t) == SetDescriptionResultEnum.OK;
if (r != null && r.GetType().Name.Contains("SetDescriptionResult"))
{
var prop = r.GetType().GetProperty("Result");
if (prop?.GetValue(r) is SetDescriptionResultEnum e2)
return e2 == SetDescriptionResultEnum.OK;
}
return false;
}
#endregion
static ClaimsPrincipal? ValidateJwtFromQuery(HttpContext ctx, string secret, string issuer, string audience)
{
var token = ctx.Request.Query["token"].ToString();
if (string.IsNullOrEmpty(token)) return null;
return ValidateJwt(token, secret, issuer, audience);
}
app.MapGet("/token/validate", async (HttpContext ctx, MySqlConnection conn) =>
{
if (!ctx.Request.Headers.TryGetValue("Authorization", out var authHeaderValues))
return Results.Unauthorized();
var parts = authHeaderValues.ToString().Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2 || !parts[0].Equals("Bearer", StringComparison.OrdinalIgnoreCase))
return Results.Unauthorized();
var token = parts[1];
await conn.OpenAsync(); await conn.OpenAsync();
await using var cmd = new MySqlCommand(sql, conn); const string checkSql = """
cmd.Parameters.AddWithValue("@username", req.name); SELECT 1
FROM ValidateToken
WHERE token = @token
AND STR_TO_DATE(validationDate, '%Y-%m-%d %H:%i') >= (UTC_TIMESTAMP() - INTERVAL 24 HOUR)
LIMIT 1;
""";
await using var reader = await cmd.ExecuteReaderAsync(); await using var cmd = new MySqlCommand(checkSql, conn);
cmd.Parameters.AddWithValue("@token", token);
if (!await reader.ReadAsync()) var ok = (await cmd.ExecuteScalarAsync()) != null;
return Results.Unauthorized(); return Results.Ok(new TokenIsValid(ok));
var userId = reader.GetInt32("userID").ToString();
var username = reader.GetString("username");
var pwHash = reader.GetString("password");
var ok = BCrypt.Net.BCrypt.Verify(req.password, pwHash);
if (!ok)
return Results.Unauthorized();
var token = CreateJwt(userId, username, jwtSecret, jwtIssuer, jwtAudience, minutesValid: 120);
return Results.Ok(new ResponseToken(token));
});
app.MapGet("/token/validate", (HttpContext ctx) =>
{
return Results.Ok(new TokenIsValid(true));
}); });
app.MapGet("/me", (HttpContext ctx) => app.MapGet("/me", (HttpContext ctx) =>
@@ -112,19 +456,19 @@ app.MapPost("/user/create", async (RegisterRequest req, MySqlConnection conn) =>
await using var cmd = new MySqlCommand(insertSql, conn); await using var cmd = new MySqlCommand(insertSql, conn);
cmd.Parameters.AddWithValue("@userID", userId); cmd.Parameters.AddWithValue("@userID", userId);
cmd.Parameters.AddWithValue("@username", req.name); cmd.Parameters.AddWithValue("@username", req.user);
cmd.Parameters.AddWithValue("@password", pwHash); cmd.Parameters.AddWithValue("@password", pwHash);
var rows = await cmd.ExecuteNonQueryAsync(); var rows = await cmd.ExecuteNonQueryAsync();
if (rows != 1) if (rows != 1)
return Results.Problem("User konnte nicht angelegt werden."); return Results.Problem("User konnte nicht angelegt werden.");
var token = CreateJwt(userId, req.name, jwtSecret, jwtIssuer, jwtAudience, minutesValid: 120); var token = CreateJwt(userId, req.user, jwtSecret, jwtIssuer, jwtAudience, minutesValid: 120);
return Results.Created($"/user/{userId}", new ResponseToken(token)); return Results.Created($"/user/{userId}", new ResponseToken(token));
}); });
app.MapPost("/ticket/create", async (HttpContext ctx, CreateTicketRequest req, MySqlConnection conn) => app.MapGet("/user/show/all", async (HttpContext ctx, MySqlConnection conn) =>
{ {
var userId = ctx.Items["user"]?.ToString(); var userId = ctx.Items["user"]?.ToString();
if (string.IsNullOrEmpty(userId)) if (string.IsNullOrEmpty(userId))
@@ -132,19 +476,182 @@ app.MapPost("/ticket/create", async (HttpContext ctx, CreateTicketRequest req, M
await conn.OpenAsync(); await conn.OpenAsync();
const string insertSql = """ const string sql = """
INSERT INTO ticket (userID, ticketID, ticketname, status, priority, OpenAt, property) SELECT *
VALUES (@userID,(select max(ticketID) from ticket) + 1, @ticketname, @beschreibung, @status, @priority, @openAt, @property); FROM User
"""; """;
await using var cmd = new MySqlCommand(insertSql, conn); await using var cmd = new MySqlCommand(sql, conn);
await using var reader = await cmd.ExecuteReaderAsync();
var user = new List<object>();
while (await reader.ReadAsync())
{
user.Add(new
{
userID = reader.GetInt64("userID"),
username = reader.GetString("username"),
isEmployee = reader.GetInt32("isEmployee"),
});
}
return Results.Ok(user);
});
app.MapGet("/categories", async (HttpContext ctx, MySqlConnection conn) =>
{
await conn.OpenAsync();
const string sql = """
SELECT categoryname
FROM Category
""";
await using var cmd = new MySqlCommand(sql, conn);
await using var reader = await cmd.ExecuteReaderAsync();
List<string> categories = new List<string>();
while (await reader.ReadAsync())
{
categories.Add(reader.GetString("categoryname"));
}
return Results.Ok(categories);
});
app.MapGet("/user/hasrights/categories", async (HttpContext ctx, MySqlConnection conn) =>
{
await conn.OpenAsync();
var userId = ctx.Items["user"]?.ToString();
if (string.IsNullOrEmpty(userId))
return Results.Unauthorized();
const string sql = """
SELECT c.categoryname
FROM User u
JOIN Category c ON c.categoryId = u.categoryId
WHERE u.userId = @userId;
""";
await using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@userID", userId); cmd.Parameters.AddWithValue("@userID", userId);
cmd.Parameters.AddWithValue("@status", req.status);
await using var reader = await cmd.ExecuteReaderAsync();
List<string> categorys = new List<string>();
while (await reader.ReadAsync())
{
categorys.Add(reader.GetString("categoryname"));
}
return Results.Ok(categorys);
});
app.MapGet("/user/hasrights", async (HttpContext ctx, MySqlConnection conn) =>
{
var userId = ctx.Items["user"]?.ToString();
if (string.IsNullOrEmpty(userId))
return Results.Unauthorized();
await conn.OpenAsync();
const string sql = """
SELECT isEmployee
FROM User
WHERE userID = @userID
""";
await using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@userID", userId);
await using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
if (reader.GetInt32("isEmployee") == 1)
{
return Results.Ok($"User: {userId} has rights = true");
}
else
{
return Results.Ok($"User: {userId} has rights = false");
}
}
return Results.Unauthorized();
});
app.MapPost("/ticket/create", async (HttpContext ctx, Ticket req, MySqlConnection conn) =>
{
var userId = ctx.Items["user"]?.ToString();
if (string.IsNullOrEmpty(userId))
return Results.Unauthorized();
int categoryId = 0;
switch (req.category)
{
case "Hardware":
categoryId = 1;
break;
case "Software":
categoryId = 2;
break;
case "Schäden":
categoryId = 3;
break;
case "Personal-Probleme":
categoryId = 4;
break;
}
await conn.OpenAsync();
const string insertSql = """
INSERT INTO Ticket (
userID,
ticketname,
status,
category,
description,
categoryId,
priority,
opendAt
)
VALUES (
@userID,
@ticketname,
@status,
@category,
@description,
@categoryId,
@priority,
@opendAt
);
""";
await using var cmd = new MySqlCommand(insertSql, conn);
cmd.Parameters.AddWithValue("@userID", Convert.ToInt32(userId));
cmd.Parameters.AddWithValue("@ticketname", req.ticketname); cmd.Parameters.AddWithValue("@ticketname", req.ticketname);
cmd.Parameters.AddWithValue("@beschreibung", req.beschreibung); cmd.Parameters.AddWithValue("@category", req.category);
cmd.Parameters.AddWithValue("@priority", req.priority); cmd.Parameters.AddWithValue("@categoryId", categoryId);
cmd.Parameters.AddWithValue("@openAt", DateTime.UtcNow); cmd.Parameters.AddWithValue("@description", req.description);
cmd.Parameters.AddWithValue("@property", req.property); cmd.Parameters.AddWithValue("@status", Convert.ToInt32(req.status));
cmd.Parameters.AddWithValue("@priority", Convert.ToInt32(req.priority));
cmd.Parameters.AddWithValue("@opendAt", DateTime.UtcNow);
var rows = await cmd.ExecuteNonQueryAsync(); var rows = await cmd.ExecuteNonQueryAsync();
if (rows != 1) if (rows != 1)
@@ -152,10 +659,9 @@ app.MapPost("/ticket/create", async (HttpContext ctx, CreateTicketRequest req, M
var ticketId = cmd.LastInsertedId; var ticketId = cmd.LastInsertedId;
return Results.Created($"/ticket/{ticketId}", new return Results.Created($"/ticket/show/{ticketId}", new
{ {
ticketID = ticketId, ticketID = ticketId
userID = userId
}); });
}); });
@@ -168,17 +674,19 @@ app.MapGet("/ticket/show/all", async (HttpContext ctx, MySqlConnection conn) =>
await conn.OpenAsync(); await conn.OpenAsync();
const string sql = """ const string sql = """
SELECT SELECT
t.ticketID, t.ticketID,
t.ticketname, t.ticketname,
u.username, owner.username AS owner_name,
t.status, t.status,
t.priority, t.priority,
t.category t.categoryId
FROM ticket t FROM Ticket t
JOIN User u ON t.userID = u.userID LEFT JOIN User owner ON t.userID = owner.userID
WHERE t.userID = @userID CROSS JOIN User u_search
ORDER BY t.priority; WHERE u_search.userID = @userID
AND (t.userID = u_search.userID OR t.categoryId = u_search.categoryId)
ORDER BY t.priority;
"""; """;
await using var cmd = new MySqlCommand(sql, conn); await using var cmd = new MySqlCommand(sql, conn);
@@ -194,46 +702,122 @@ app.MapGet("/ticket/show/all", async (HttpContext ctx, MySqlConnection conn) =>
{ {
ticketID = reader.GetInt64("ticketID"), ticketID = reader.GetInt64("ticketID"),
ticketname = reader.GetString("ticketname"), ticketname = reader.GetString("ticketname"),
username = reader.GetString("username"), username = reader.IsDBNull("owner_name") ? "" : reader.GetString("owner_name"),
status = reader.GetInt32("status"), status = reader.GetInt32("status"),
priority = reader.GetInt32("priority"), priority = reader.GetInt32("priority"),
category = reader.GetString("category") categoryId = reader.IsDBNull("categoryId") ? 0 : Convert.ToInt32(reader.GetInt32("categoryId")),
}); });
} }
return Results.Ok(tickets); return Results.Ok(tickets);
}); });
app.MapPost("/ticket/update/{ticketId:int}", async (HttpContext ctx, int ticketID, Ticket req, MySqlConnection conn) =>
app.MapGet("/ticket/show/{ticketId:int}", async (
HttpContext ctx,
long ticketId,
MySqlConnection conn) =>
{ {
var userId = ctx.Items["user"]?.ToString(); var userId = ctx.Items["user"]?.ToString();
if (string.IsNullOrEmpty(userId)) if (string.IsNullOrEmpty(userId))
return Results.Unauthorized(); return Results.Unauthorized();
int categoryId = 0;
switch (req.category)
{
case "Hardware":
categoryId = 1;
break;
case "Software":
categoryId = 2;
break;
case "Schäden":
categoryId = 3;
break;
case "Personal-Probleme":
categoryId = 4;
break;
}
await conn.OpenAsync();
const string updateSql = """
UPDATE Ticket
SET
ticketname = @ticketname,
status = @status,
priority = @priority,
opendAt = @opendAt,
description = @description,
category = @category,
categoryID = @categoryId
WHERE
ticketID = @ticketID
AND userID = @userID;
""";
await using var cmd = new MySqlCommand(updateSql, conn);
cmd.Parameters.AddWithValue("@ticketID", ticketID);
cmd.Parameters.AddWithValue("@userID", Convert.ToInt32(userId));
cmd.Parameters.AddWithValue("@ticketname", req.ticketname);
cmd.Parameters.AddWithValue("@category", req.category);
cmd.Parameters.AddWithValue("@categoryId", categoryId);
cmd.Parameters.AddWithValue("@description", req.description);
cmd.Parameters.AddWithValue("@status", Convert.ToInt32(req.status));
cmd.Parameters.AddWithValue("@priority", Convert.ToInt32(req.priority));
cmd.Parameters.AddWithValue("@opendAt", DateTime.UtcNow);
var rows = await cmd.ExecuteNonQueryAsync();
if (rows != 1)
return Results.Problem("Ticket konnte nicht aktualisiert werden");
return Results.Ok(new
{
ticketID = ticketID,
updated = true
});
});
app.MapGet("/ticket/show/{ticketId:int}", async (
HttpContext ctx,
int ticketId,
MySqlConnection conn) =>
{
var userId = ctx.Items["user"]?.ToString();
if (string.IsNullOrWhiteSpace(userId))
return Results.Unauthorized();
await conn.OpenAsync(); await conn.OpenAsync();
const string ticketSql = """ const string ticketSql = """
SELECT SELECT
t.TicketID, t.ticketID,
t.Ticketname, t.ticketname,
t.UserID, t.userID,
u.Username AS OwnerUsername, u.username,
t.Status, t.status,
t.Priority, t.description,
t.OpenAt, t.priority,
t.ClosedAt, t.opendAt,
t.closedAt,
t.category t.category
FROM Ticket t FROM Ticket t
JOIN User u ON u.UserID = t.UserID JOIN User u ON u.userID = t.userID
WHERE t.TicketID = @ticketId WHERE t.ticketID = @ticketId
AND t.UserID = @userId; AND t.userID = @userId
LIMIT 1;
"""; """;
object? ticket = null; long vticketID;
string vticketname;
long vuserID;
string vusername;
int vstatus;
string vdescription;
int vpriority;
string vopenAt;
string? vclosedAt;
string vcategory;
await using (var cmd = new MySqlCommand(ticketSql, conn)) await using (var cmd = new MySqlCommand(ticketSql, conn))
{ {
@@ -244,38 +828,34 @@ app.MapGet("/ticket/show/{ticketId:int}", async (
if (!await reader.ReadAsync()) if (!await reader.ReadAsync())
return Results.NotFound("Ticket nicht gefunden"); return Results.NotFound("Ticket nicht gefunden");
ticket = new vticketID = reader.GetInt64("ticketID");
{ vticketname = reader.GetString("ticketname");
ticketID = reader.GetInt64("TicketID"), vuserID = reader.GetInt64("userID");
ticketname = reader.GetString("Ticketname"), vusername = reader.GetString("username");
userID = reader.GetInt64("UserID"), vstatus = reader.GetInt32("status");
ownerUsername = reader.GetString("OwnerUsername"), vdescription = reader.IsDBNull("description") ? "" : reader.GetString("description");
status = reader.GetInt32("Status"),
priority = reader.GetInt32("Priority"), vpriority = reader.GetInt32("priority");
openAt = reader.GetString("OpenAt"), vopenAt = reader.GetString("opendAt");
closedAt = reader.IsDBNull("ClosedAt") ? null : reader.GetString("ClosedAt"), vclosedAt = reader.IsDBNull("closedAt") ? null : reader.GetString("closedAt");
category = reader.GetString("category") vcategory = reader.GetString("category");
};
} }
const string messagesSql = """ const string messagesSql = """
SELECT SELECT
m.MessageID, m.messageID,
m.Sequence, m.sequence,
m.SendAt, m.sendAt,
m.Content, m.content,
m.Sender, m.sender,
su.Username AS SenderUsername, u.username AS senderUsername
m.Reciver,
ru.Username AS ReciverUsername
FROM Messages m FROM Messages m
LEFT JOIN User su ON su.UserID = m.Sender LEFT JOIN User u ON u.userID = m.sender
LEFT JOIN User ru ON ru.UserID = m.Reciver WHERE m.ticketID = @ticketId
WHERE m.TicketID = @ticketId ORDER BY m.sequence ASC;
ORDER BY m.Sequence ASC;
"""; """;
var messages = new List<object>(); var vmessages = new List<object>();
await using (var cmd = new MySqlCommand(messagesSql, conn)) await using (var cmd = new MySqlCommand(messagesSql, conn))
{ {
@@ -284,27 +864,59 @@ app.MapGet("/ticket/show/{ticketId:int}", async (
await using var reader = await cmd.ExecuteReaderAsync(); await using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync()) while (await reader.ReadAsync())
{ {
messages.Add(new vmessages.Add(new
{ {
messageID = reader.GetInt64("MessageID"), messageID = reader.GetInt64("messageID"),
sequence = reader.GetInt32("Sequence"), sequence = reader.GetInt32("sequence"),
sendAt = reader.GetString("SendAt"), sendAt = reader.GetString("sendAt"),
content = reader.GetString("Content"), content = reader.GetString("content"),
sender = reader.GetInt64("Sender"), sender = reader.GetInt64("sender"),
senderUsername = reader.IsDBNull("SenderUsername") ? null : reader.GetString("SenderUsername"), senderUsername = reader.IsDBNull("senderUsername") ? null : reader.GetString("senderUsername")
reciver = reader.GetInt64("Reciver"),
reciverUsername = reader.IsDBNull("ReciverUsername") ? null : reader.GetString("ReciverUsername")
}); });
} }
} }
return Results.Ok(new return Results.Ok(new
{ {
ticket, ticketID = vticketID,
messages ticketname = vticketname,
userID = vuserID,
username = vusername,
description = vdescription,
status = vstatus,
priority = vpriority,
openAt = vopenAt,
closedAt = vclosedAt,
category = vcategory,
messages = vmessages
}); });
}); });
app.MapPost("/message/attachment", async (HttpContext ctx, AddAttachments req, MySqlConnection conn) =>
{
var userId = ctx.Items["user"]?.ToString();
if (string.IsNullOrEmpty(userId))
return Results.Unauthorized();
await conn.OpenAsync();
const string sql = """
INSERT INTO Attachments (ticketID, messageID, attachment) values (@ticketId, @messageId, @attachment);
""";
await using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ticketId", req.ticketId);
cmd.Parameters.AddWithValue("@messageID", req.messageId);
cmd.Parameters.AddWithValue("@attachments", req.attachments);
var rows = await cmd.ExecuteNonQueryAsync();
if (rows != 1)
return Results.Problem("User konnte nicht angelegt werden.");
return Results.Ok();
});
static string CreateJwt(string userId, string username, string secret, string issuer, string audience, int minutesValid) static string CreateJwt(string userId, string username, string secret, string issuer, string audience, int minutesValid)
{ {
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
@@ -358,14 +970,18 @@ static ClaimsPrincipal? ValidateJwt(string token, string secret, string issuer,
app.Run(); app.Run();
public record RegisterRequest(string name, string password); public record RegisterRequest(string user, string password);
public record SignInRequest(string name, string password); public record SignInRequest(string user, string password);
public record AddAttachments(string ticketId, string messageId, Blob attachments);
public record ResponseToken(string token); public record ResponseToken(string token);
public record TokenIsValid(bool is_valid); public record TokenIsValid(bool is_valid);
public record CreateTicketRequest( public record Ticket(
int status, int status,
int priority, int priority,
string property, string category,
string username,
string ticketname, string ticketname,
string beschreibung string description
); );

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\net10.0\publish\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<ProjectGuid>0bbf8e29-1d9f-41ad-a1a2-637c72fa90d1</ProjectGuid>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<_PublishTargetUrl>C:\Users\tweee\source\repos\Projekt-dev-env\src\Project-CBackend\TicketSystem\bin\Release\net10.0\publish\</_PublishTargetUrl>
<History>True|2026-02-02T09:49:50.3650629Z||;True|2026-02-02T10:49:37.6510863+01:00||;True|2026-02-02T10:48:37.6053205+01:00||;True|2026-01-30T13:56:01.7191901+01:00||;False|2026-01-30T12:51:03.0995895+01:00||;True|2026-01-30T12:33:58.6336798+01:00||;True|2026-01-30T12:29:43.4279844+01:00||;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

View File

@@ -1,11 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<PublishAot>false</PublishAot>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\TicketSystem</DockerfileContext> <DockerfileContext>..\TicketSystem</DockerfileContext>
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -13,6 +15,7 @@
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.2" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.2" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.15.0" /> <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.15.0" />
<PackageReference Include="MySqlConnector" Version="2.5.0" /> <PackageReference Include="MySqlConnector" Version="2.5.0" />
<PackageReference Include="SIPSorcery" Version="10.0.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.15.0" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.15.0" />
</ItemGroup> </ItemGroup>

View File

@@ -2,5 +2,6 @@
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<ActiveDebugProfile>https</ActiveDebugProfile> <ActiveDebugProfile>https</ActiveDebugProfile>
<NameOfLastUsedPublishProfile>C:\Users\tweee\source\repos\Projekt-dev-env\src\Project-CBackend\TicketSystem\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -1,3 +1,3 @@
<Solution> <Solution>
<Project Path="../TicketSystem/TicketSystem.csproj" Id="0bbf8e29-1d9f-41ad-a1a2-637c72fa90d1" /> <Project Path="TicketSystem.csproj" Id="0bbf8e29-1d9f-41ad-a1a2-637c72fa90d1" />
</Solution> </Solution>

View File

@@ -1,6 +1,7 @@
{ {
"ConnectionStrings": { "ConnectionStrings": {
"Default": "Server=10.204.192.110;Port=3306;Database=ticket_sys;User Id=root;Password=example;SslMode=None;AllowPublicKeyRetrieval=True;", "Default": "Server=10.204.192.64;Port=3306;Database=ticket_sys;User Id=root;Password=example;SslMode=None;AllowPublicKeyRetrieval=True;"
//"Default": "jdbc:mysql://10.204.192.110:3306/ticket_sys"
}, },
"Jwt": { "Jwt": {
"Secret": "CHANGE_ME_TO_A_LONG_RANDOM_SECRET_32+_CHARS", "Secret": "CHANGE_ME_TO_A_LONG_RANDOM_SECRET_32+_CHARS",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,279 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v10.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v10.0": {
"TicketSystem/1.0.0": {
"dependencies": {
"BCrypt.Net-Next": "4.0.3",
"Microsoft.AspNetCore.OpenApi": "10.0.2",
"Microsoft.IdentityModel.JsonWebTokens": "8.15.0",
"MySqlConnector": "2.5.0",
"SIPSorcery": "10.0.3",
"System.IdentityModel.Tokens.Jwt": "8.15.0"
},
"runtime": {
"TicketSystem.dll": {}
}
},
"BCrypt.Net-Next/4.0.3": {
"runtime": {
"lib/net6.0/BCrypt.Net-Next.dll": {
"assemblyVersion": "4.0.3.0",
"fileVersion": "4.0.3.0"
}
}
},
"BouncyCastle.Cryptography/2.6.2": {
"runtime": {
"lib/net6.0/BouncyCastle.Cryptography.dll": {
"assemblyVersion": "2.0.0.0",
"fileVersion": "2.6.2.46322"
}
}
},
"Concentus/2.2.2": {
"runtime": {
"lib/net8.0/Concentus.dll": {
"assemblyVersion": "2.2.2.0",
"fileVersion": "2.2.2.0"
}
}
},
"DnsClient/1.8.0": {
"runtime": {
"lib/net8.0/DnsClient.dll": {
"assemblyVersion": "1.8.0.0",
"fileVersion": "1.8.0.0"
}
}
},
"Microsoft.AspNetCore.OpenApi/10.0.2": {
"dependencies": {
"Microsoft.OpenApi": "2.0.0"
},
"runtime": {
"lib/net10.0/Microsoft.AspNetCore.OpenApi.dll": {
"assemblyVersion": "10.0.2.0",
"fileVersion": "10.0.225.61305"
}
}
},
"Microsoft.IdentityModel.Abstractions/8.15.0": {
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.Abstractions.dll": {
"assemblyVersion": "8.15.0.0",
"fileVersion": "8.15.0.61118"
}
}
},
"Microsoft.IdentityModel.JsonWebTokens/8.15.0": {
"dependencies": {
"Microsoft.IdentityModel.Tokens": "8.15.0"
},
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.JsonWebTokens.dll": {
"assemblyVersion": "8.15.0.0",
"fileVersion": "8.15.0.61118"
}
}
},
"Microsoft.IdentityModel.Logging/8.15.0": {
"dependencies": {
"Microsoft.IdentityModel.Abstractions": "8.15.0"
},
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.Logging.dll": {
"assemblyVersion": "8.15.0.0",
"fileVersion": "8.15.0.61118"
}
}
},
"Microsoft.IdentityModel.Tokens/8.15.0": {
"dependencies": {
"Microsoft.IdentityModel.Logging": "8.15.0"
},
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.Tokens.dll": {
"assemblyVersion": "8.15.0.0",
"fileVersion": "8.15.0.61118"
}
}
},
"Microsoft.OpenApi/2.0.0": {
"runtime": {
"lib/net8.0/Microsoft.OpenApi.dll": {
"assemblyVersion": "2.0.0.0",
"fileVersion": "2.0.0.0"
}
}
},
"MySqlConnector/2.5.0": {
"runtime": {
"lib/net10.0/MySqlConnector.dll": {
"assemblyVersion": "2.0.0.0",
"fileVersion": "2.5.0.0"
}
}
},
"SIPSorcery/10.0.3": {
"dependencies": {
"BouncyCastle.Cryptography": "2.6.2",
"Concentus": "2.2.2",
"DnsClient": "1.8.0",
"SIPSorcery.WebSocketSharp": "0.0.1",
"SIPSorceryMedia.Abstractions": "8.0.12"
},
"runtime": {
"lib/net10.0/SIPSorcery.dll": {
"assemblyVersion": "10.0.3.0",
"fileVersion": "10.0.3.0"
}
}
},
"SIPSorcery.WebSocketSharp/0.0.1": {
"runtime": {
"lib/netstandard2.0/websocket-sharp.dll": {
"assemblyVersion": "0.0.1.0",
"fileVersion": "0.0.1.0"
}
}
},
"SIPSorceryMedia.Abstractions/8.0.12": {
"runtime": {
"lib/net8.0/SIPSorceryMedia.Abstractions.dll": {
"assemblyVersion": "8.0.12.0",
"fileVersion": "8.0.12.0"
}
}
},
"System.IdentityModel.Tokens.Jwt/8.15.0": {
"dependencies": {
"Microsoft.IdentityModel.JsonWebTokens": "8.15.0",
"Microsoft.IdentityModel.Tokens": "8.15.0"
},
"runtime": {
"lib/net10.0/System.IdentityModel.Tokens.Jwt.dll": {
"assemblyVersion": "8.15.0.0",
"fileVersion": "8.15.0.61118"
}
}
}
}
},
"libraries": {
"TicketSystem/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"BCrypt.Net-Next/4.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-W+U9WvmZQgi5cX6FS5GDtDoPzUCV4LkBLkywq/kRZhuDwcbavOzcDAr3LXJFqHUi952Yj3LEYoWW0jbEUQChsA==",
"path": "bcrypt.net-next/4.0.3",
"hashPath": "bcrypt.net-next.4.0.3.nupkg.sha512"
},
"BouncyCastle.Cryptography/2.6.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-7oWOcvnntmMKNzDLsdxAYqApt+AjpRpP2CShjMfIa3umZ42UQMvH0tl1qAliYPNYO6vTdcGMqnRrCPmsfzTI1w==",
"path": "bouncycastle.cryptography/2.6.2",
"hashPath": "bouncycastle.cryptography.2.6.2.nupkg.sha512"
},
"Concentus/2.2.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-2B9YmHPKO+k7YpAAnqmiXwiMJnfjfj1C868RszOll2iZWLnGTAiC1q21L/d7CvTan7T+hyqU8dR0Dcy3cpjVfQ==",
"path": "concentus/2.2.2",
"hashPath": "concentus.2.2.2.nupkg.sha512"
},
"DnsClient/1.8.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-RRwtaCXkXWsx0mmsReGDqCbRLtItfUbkRJlet1FpdciVhyMGKcPd57T1+8Jki9ojHlq9fntVhXQroOOgRak8DQ==",
"path": "dnsclient/1.8.0",
"hashPath": "dnsclient.1.8.0.nupkg.sha512"
},
"Microsoft.AspNetCore.OpenApi/10.0.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-YuEjUNpsoZLs0I5ONt013Z+Udsz3f9sPUh1Xm59LN7+/Z8oVG/swCUYLBbANtfreiunWnoT2uk+5kst4s2jr3Q==",
"path": "microsoft.aspnetcore.openapi/10.0.2",
"hashPath": "microsoft.aspnetcore.openapi.10.0.2.nupkg.sha512"
},
"Microsoft.IdentityModel.Abstractions/8.15.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-e/DApa1GfxUqHSBHcpiQg8yaghKAvFVBQFcWh25jNoRobDZbduTUACY8bZ54eeGWXvimGmEDdF0zkS5Dq16XPQ==",
"path": "microsoft.identitymodel.abstractions/8.15.0",
"hashPath": "microsoft.identitymodel.abstractions.8.15.0.nupkg.sha512"
},
"Microsoft.IdentityModel.JsonWebTokens/8.15.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3513f5VzvOZy3ELd42wGnh1Q3e83tlGAuXFSNbENpgWYoAhLLzgFtd5PiaOPGAU0gqKhYGVzKavghLUGfX3HQg==",
"path": "microsoft.identitymodel.jsonwebtokens/8.15.0",
"hashPath": "microsoft.identitymodel.jsonwebtokens.8.15.0.nupkg.sha512"
},
"Microsoft.IdentityModel.Logging/8.15.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-1gJLjhy0LV2RQMJ9NGzi5Tnb2l+c37o8D8Lrk2mrvmb6OQHZ7XJstd/XxvncXgBpad4x9CGXdipbZzJJCXKyAg==",
"path": "microsoft.identitymodel.logging/8.15.0",
"hashPath": "microsoft.identitymodel.logging.8.15.0.nupkg.sha512"
},
"Microsoft.IdentityModel.Tokens/8.15.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-zUE9ysJXBtXlHHRtcRK3Sp8NzdCI1z/BRDTXJQ2TvBoI0ENRtnufYIep0O5TSCJRJGDwwuLTUx+l/bEYZUxpCA==",
"path": "microsoft.identitymodel.tokens/8.15.0",
"hashPath": "microsoft.identitymodel.tokens.8.15.0.nupkg.sha512"
},
"Microsoft.OpenApi/2.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-GGYLfzV/G/ct80OZ45JxnWP7NvMX1BCugn/lX7TH5o0lcVaviavsLMTxmFV2AybXWjbi3h6FF1vgZiTK6PXndw==",
"path": "microsoft.openapi/2.0.0",
"hashPath": "microsoft.openapi.2.0.0.nupkg.sha512"
},
"MySqlConnector/2.5.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-hoAwfHHF8DlRRqwHOhN3u1KLi+XbX/4LPS7Anfa+SYC97vRyIfdEOEEfj1L50q01Ik8aDNvmDrNmu/VPFiAiaQ==",
"path": "mysqlconnector/2.5.0",
"hashPath": "mysqlconnector.2.5.0.nupkg.sha512"
},
"SIPSorcery/10.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-+VnD/wvg5myZY2Gj3CXWKdTnfoigv1WyU0uh55pmksT28MBMXBSULLSQt6csNV8VYTJ2aT1CYr9LvBEZrbX6aw==",
"path": "sipsorcery/10.0.3",
"hashPath": "sipsorcery.10.0.3.nupkg.sha512"
},
"SIPSorcery.WebSocketSharp/0.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-lBlR9rZmMty2v5kPzCseAyuSv95FSoGuYZJgDy6M/qqZ/xq1ejFnOVEpXMDqBIthiTUOH8rvMcpnva7HXK0ZVw==",
"path": "sipsorcery.websocketsharp/0.0.1",
"hashPath": "sipsorcery.websocketsharp.0.0.1.nupkg.sha512"
},
"SIPSorceryMedia.Abstractions/8.0.12": {
"type": "package",
"serviceable": true,
"sha512": "sha512-70bYl3RFc0lkL6Z2M2GD/vymnWvmnvTSJfEpFHE4Uh+bp5Rz9DWsEvuF8EZEhaW3foPGvpNIfP5nGj52cCXjgw==",
"path": "sipsorcerymedia.abstractions/8.0.12",
"hashPath": "sipsorcerymedia.abstractions.8.0.12.nupkg.sha512"
},
"System.IdentityModel.Tokens.Jwt/8.15.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-dpodi7ixz6hxK8YCBYAWzm0IA8JYXoKcz0hbCbNifo519//rjUI0fBD8rfNr+IGqq+2gm4oQoXwHk09LX5SqqQ==",
"path": "system.identitymodel.tokens.jwt/8.15.0",
"hashPath": "system.identitymodel.tokens.jwt.8.15.0.nupkg.sha512"
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,20 @@
{
"runtimeOptions": {
"tfm": "net10.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "10.0.0"
},
{
"name": "Microsoft.AspNetCore.App",
"version": "10.0.0"
}
],
"configProperties": {
"System.GC.Server": true,
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}

View File

@@ -0,0 +1 @@
{"Version":1,"ManifestType":"Build","Endpoints":[]}

View File

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

View File

@@ -0,0 +1,11 @@
{
"ConnectionStrings": {
"Default": "Server=10.204.192.64;Port=3306;Database=ticket_sys;User Id=root;Password=example;SslMode=None;AllowPublicKeyRetrieval=True;"
//"Default": "jdbc:mysql://10.204.192.110:3306/ticket_sys"
},
"Jwt": {
"Secret": "CHANGE_ME_TO_A_LONG_RANDOM_SECRET_32+_CHARS",
"Issuer": "Ticket-System",
"Audience": "Ticket-System"
}
}

View File

@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "10.0.2",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}

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