Compare commits
12 Commits
update2025
...
701388ee34
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
701388ee34 | ||
|
|
3e099988bc | ||
|
|
ee967cd046 | ||
|
|
76c3e6ddde | ||
|
|
aea858a1ef | ||
|
|
85c90e4657 | ||
|
|
840ecedbd0 | ||
|
|
916c3142d4 | ||
|
|
f9426679ea | ||
|
|
a68994d00b | ||
|
|
fcda568905 | ||
|
|
ac178e60e0 |
56
.gitea/workflows/docker-image.yml
Normal file
56
.gitea/workflows/docker-image.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
name: Build And Push Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "image"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOTNET_ROLL_FORWARD: Major
|
||||
REGISTRY: git.beging.de
|
||||
BASE_IMAGE: git.beging.de/troogs/fs-onboarding-server
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: "9.0.x"
|
||||
|
||||
- name: Publish server project
|
||||
run: dotnet publish ./FoodsharingSiegen.Server/FoodsharingSiegen.Server.csproj -c Release -o ./Publish/Server
|
||||
|
||||
- name: Login to Gitea registry
|
||||
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login "${{ env.REGISTRY }}" -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||
|
||||
- name: Determine next timestamp tag
|
||||
shell: bash
|
||||
run: |
|
||||
TODAY="$(date -u +%Y%m%d)"
|
||||
i=1
|
||||
while docker manifest inspect "${BASE_IMAGE}:${TODAY}-${i}" > /dev/null 2>&1; do
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
DATE_TAG="${TODAY}-${i}"
|
||||
echo "DATE_TAG=${DATE_TAG}" >> "$GITHUB_ENV"
|
||||
echo "Using image tag: ${DATE_TAG}"
|
||||
|
||||
- name: Build docker image
|
||||
run: |
|
||||
docker build \
|
||||
-f ./Docker/dockerfile.server \
|
||||
-t "${{ env.BASE_IMAGE }}:latest" \
|
||||
-t "${{ env.BASE_IMAGE }}:${{ env.DATE_TAG }}" \
|
||||
.
|
||||
|
||||
- name: Push docker images
|
||||
run: |
|
||||
docker push "${{ env.BASE_IMAGE }}:latest"
|
||||
docker push "${{ env.BASE_IMAGE }}:${{ env.DATE_TAG }}"
|
||||
50
.gitea/workflows/test.yml
Normal file
50
.gitea/workflows/test.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Build And Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: "Tag for the release (for example: v1.0.0)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.inputs.tag_name || github.ref_name }}
|
||||
DOTNET_ROLL_FORWARD: Major
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: "9.0.x"
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore FoodsharingSiegen.sln
|
||||
|
||||
- name: Publish server build
|
||||
run: dotnet publish ./FoodsharingSiegen.Server/FoodsharingSiegen.Server.csproj -c Release -o ./artifacts/publish
|
||||
|
||||
- name: Create zip package
|
||||
run: |
|
||||
cd artifacts
|
||||
zip -r FoodsharingSiegen.Server-${{ env.RELEASE_TAG }}.zip publish
|
||||
|
||||
- name: Create release and upload artifact
|
||||
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||
with:
|
||||
files: artifacts/FoodsharingSiegen.Server-${{ env.RELEASE_TAG }}.zip
|
||||
tag_name: ${{ env.RELEASE_TAG }}
|
||||
name: Release ${{ env.RELEASE_TAG }}
|
||||
target_commitish: ${{ github.sha }}
|
||||
token: ${{ github.token }}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
|
||||
Publish/
|
||||
app.db
|
||||
19
.vscode/launch.json
vendored
Normal file
19
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug FoodsharingSiegen.Server",
|
||||
"type": "dotnet",
|
||||
"request": "launch",
|
||||
"projectPath": "${workspaceFolder}/FoodsharingSiegen.Server/FoodsharingSiegen.Server.csproj",
|
||||
"env": {
|
||||
"DOTNET_ROLL_FORWARD": "Major"
|
||||
},
|
||||
"launchBrowser": true,
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
53
.vscode/tasks.json
vendored
Normal file
53
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Watch FoodsharingSiegen.Server",
|
||||
"type": "shell",
|
||||
"command": "dotnet watch --project ./FoodsharingSiegen.Server/FoodsharingSiegen.Server.csproj run",
|
||||
"isBackground": true,
|
||||
"problemMatcher": "$msCompile",
|
||||
"options": {
|
||||
"statusbar": {
|
||||
"hide": false,
|
||||
"label": "Watch Server",
|
||||
"color": "#3a96ff",
|
||||
"icon": {
|
||||
"id": "eye"
|
||||
},
|
||||
"running": {
|
||||
"color": "#f7df06",
|
||||
"icon": {
|
||||
"id": "loading~spin"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Debug FoodsharingSiegen.Server",
|
||||
"type": "shell",
|
||||
"command": "dotnet run --project ./FoodsharingSiegen.Server/FoodsharingSiegen.Server.csproj",
|
||||
"problemMatcher": "$msCompile",
|
||||
"options": {
|
||||
"env": {
|
||||
"DOTNET_ROLL_FORWARD": "Major"
|
||||
},
|
||||
"statusbar": {
|
||||
"hide": false,
|
||||
"label": "Debug Server",
|
||||
"color": "#3a96ff",
|
||||
"icon": {
|
||||
"id": "debug-start"
|
||||
},
|
||||
"running": {
|
||||
"color": "#f7df06",
|
||||
"icon": {
|
||||
"id": "loading~spin"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
10
FoodsharingSiegen.Contracts/Enums/ProspectSortOption.cs
Normal file
10
FoodsharingSiegen.Contracts/Enums/ProspectSortOption.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace FoodsharingSiegen.Contracts.Enums
|
||||
{
|
||||
public enum ProspectSortOption
|
||||
{
|
||||
NameAscending,
|
||||
NameDescending,
|
||||
ModifiedAscending,
|
||||
ModifiedDescending
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,23 @@
|
||||
<div class="@divClass">
|
||||
<h5 class="mb-2 d-flex">
|
||||
<div class="flex-grow-1">
|
||||
@if(string.IsNullOrWhiteSpace(Prospect?.Name))
|
||||
{
|
||||
<i class="fa-solid fa-exclamation-triangle text-warning"></i>
|
||||
<doublearrows></doublearrows>
|
||||
|
||||
<em>»Name fehlt«</em>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Prospect?.Name
|
||||
<small style="font-size: .9rem;">@Prospect?.FsId</small>
|
||||
}
|
||||
|
||||
@if (Prospect?.FsId != null && Prospect.FsId != 0)
|
||||
{
|
||||
<small style="font-size: .9rem; margin-left: 0.5rem;">@Prospect?.FsId</small>
|
||||
}
|
||||
|
||||
</div>
|
||||
<div>
|
||||
@if (CurrentUser.IsInGroup(UserGroup.WelcomeTeam, UserGroup.Ambassador))
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@inherits FsBase
|
||||
@using FoodsharingSiegen.Contracts.Enums
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<Button Color="@GetSortButtonColor(ProspectSortOption.NameAscending)" Clicked="() => SelectAsync(ProspectSortOption.NameAscending)">Name (aufsteigend)</Button>
|
||||
<Button Color="@GetSortButtonColor(ProspectSortOption.NameDescending)" Clicked="() => SelectAsync(ProspectSortOption.NameDescending)">Name (absteigend)</Button>
|
||||
<Button Color="@GetSortButtonColor(ProspectSortOption.ModifiedAscending)" Clicked="() => SelectAsync(ProspectSortOption.ModifiedAscending)">Geändert (aufsteigend)</Button>
|
||||
<Button Color="@GetSortButtonColor(ProspectSortOption.ModifiedDescending)" Clicked="() => SelectAsync(ProspectSortOption.ModifiedDescending)">Geändert (absteigend)</Button>
|
||||
</div>
|
||||
39
FoodsharingSiegen.Server/Dialogs/ProspectSortDialog.razor.cs
Normal file
39
FoodsharingSiegen.Server/Dialogs/ProspectSortDialog.razor.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Blazorise;
|
||||
using FoodsharingSiegen.Contracts.Enums;
|
||||
using FoodsharingSiegen.Server.BaseClasses;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace FoodsharingSiegen.Server.Dialogs
|
||||
{
|
||||
public partial class ProspectSortDialog : FsBase
|
||||
{
|
||||
[Parameter]
|
||||
public ProspectSortOption CurrentSort { get; set; } = ProspectSortOption.NameAscending;
|
||||
|
||||
[Parameter]
|
||||
public Func<ProspectSortOption, Task>? OnSortSelected { get; set; }
|
||||
|
||||
public static async Task ShowAsync(IModalService modalService, ProspectSortOption currentSort, Func<ProspectSortOption, Task> onSortSelected)
|
||||
{
|
||||
await modalService.Show<ProspectSortDialog>("Sortieren", p =>
|
||||
{
|
||||
p.Add(nameof(CurrentSort), currentSort);
|
||||
p.Add(nameof(OnSortSelected), onSortSelected);
|
||||
}, new ModalInstanceOptions
|
||||
{
|
||||
Size = ModalSize.Small,
|
||||
});
|
||||
}
|
||||
|
||||
private Color GetSortButtonColor(ProspectSortOption option)
|
||||
{
|
||||
return CurrentSort == option ? Color.Success : Color.Secondary;
|
||||
}
|
||||
|
||||
private async Task SelectAsync(ProspectSortOption option)
|
||||
{
|
||||
if (OnSortSelected != null) await OnSortSelected(option);
|
||||
await ModalService.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,20 +16,44 @@
|
||||
|
||||
<Button
|
||||
Color="Color.Primary"
|
||||
Width="Width.Px(50)"
|
||||
Height="Height.Px(50)"
|
||||
title="Hinzufügen"
|
||||
style="min-width: auto;"
|
||||
Clicked="@CreateProspectAsync"
|
||||
Visibility="@(CurrentUser.IsInGroup(UserGroup.WelcomeTeam, UserGroup.Ambassador) ? Visibility.Default : Visibility.Invisible)"
|
||||
>Hinzufügen
|
||||
><i class="fa-solid fa-plus"></i>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
Color="Color.Primary"
|
||||
Width="Width.Px(50)"
|
||||
Height="Height.Px(50)"
|
||||
title="Sortieren"
|
||||
style="min-width: auto;"
|
||||
Clicked="@OpenSortDialogAsync"
|
||||
><i class="fa-solid fa-sort"></i>
|
||||
</Button>
|
||||
|
||||
<div class="badge-row mt-2">
|
||||
@if (HasCustomSort)
|
||||
{
|
||||
<Badge Color="Color.Primary" Closable="true" CloseClicked="@EventCallback.Factory.Create(this, ResetSortAsync)">@CurrentSortText</Badge>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@{
|
||||
var filterList = ProspectList.ApplyFilter(Filter);
|
||||
var sortList = SortProspects(filterList);
|
||||
}
|
||||
|
||||
<hr/>
|
||||
<ProspectFilterControl Filter="Filter" FilterChanged="FilterChangedAsync" StateFilter="ProspectStateFilter.OnBoarding"></ProspectFilterControl>
|
||||
<hr />
|
||||
<ProspectGrid
|
||||
Prospects="filterList"
|
||||
Prospects="sortList"
|
||||
OnDataChanged="@LoadProspects"
|
||||
StateFilter="ProspectStateFilter.OnBoarding">
|
||||
</ProspectGrid>
|
||||
@@ -36,6 +36,8 @@ namespace FoodsharingSiegen.Server.Pages
|
||||
/// </summary>
|
||||
private List<Prospect>? ProspectList { get; set; }
|
||||
|
||||
private ProspectSortOption CurrentSort { get; set; } = ProspectSortOption.NameAscending;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Override InitializeDataAsync
|
||||
@@ -63,6 +65,32 @@ namespace FoodsharingSiegen.Server.Pages
|
||||
await EditProspectDialog.ShowAsync(ModalService, LoadProspects);
|
||||
}
|
||||
|
||||
private async Task OpenSortDialogAsync()
|
||||
{
|
||||
await ProspectSortDialog.ShowAsync(ModalService, CurrentSort, async option =>
|
||||
{
|
||||
CurrentSort = option;
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
}
|
||||
|
||||
private bool HasCustomSort => CurrentSort != ProspectSortOption.NameAscending;
|
||||
|
||||
private string CurrentSortText => CurrentSort switch
|
||||
{
|
||||
ProspectSortOption.NameDescending => "Sortierung: Name (absteigend)",
|
||||
ProspectSortOption.ModifiedAscending => "Sortierung: Zuletzt geaendert (aufsteigend) ",
|
||||
ProspectSortOption.ModifiedDescending => "Sortierung: Zuletzt geaendert (absteigend) ",
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
private async Task ResetSortAsync()
|
||||
{
|
||||
CurrentSort = ProspectSortOption.NameAscending;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Method FilterChangedAsync
|
||||
@@ -78,6 +106,18 @@ namespace FoodsharingSiegen.Server.Pages
|
||||
await LocalStorageService.SetItem(StorageKeys.ProspectFilter, Filter);
|
||||
}
|
||||
|
||||
private List<Prospect> SortProspects(List<Prospect> prospects)
|
||||
{
|
||||
return CurrentSort switch
|
||||
{
|
||||
ProspectSortOption.NameAscending => prospects.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase).ToList(),
|
||||
ProspectSortOption.NameDescending => prospects.OrderByDescending(x => x.Name, StringComparer.OrdinalIgnoreCase).ToList(),
|
||||
ProspectSortOption.ModifiedAscending => prospects.OrderBy(x => x.Modified ?? x.Created).ToList(),
|
||||
ProspectSortOption.ModifiedDescending => prospects.OrderByDescending(x => x.Modified ?? x.Created).ToList(),
|
||||
_ => prospects
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Method LoadProspects
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
</div>
|
||||
|
||||
<script src="_framework/blazor.server.js"></script>
|
||||
<script src="_content/Blazorise/blazorise.js"></script>
|
||||
<script src="_content/Blazorise.Material/blazorise.material.js?v=1.7.5.0"></script>
|
||||
</body>
|
||||
</html>
|
||||
1
FoodsharingSiegen.Server/wwwroot/buildinfo.txt
Normal file
1
FoodsharingSiegen.Server/wwwroot/buildinfo.txt
Normal file
@@ -0,0 +1 @@
|
||||
20260416
|
||||
@@ -28,7 +28,7 @@ namespace FoodsharingSiegen.Shared.Helper
|
||||
InteractionType.Verify => "Verifizierung",
|
||||
InteractionType.Complete => "Fertig",
|
||||
InteractionType.StepInBriefing => appSettings.Terms.StepInName ?? "StepIn",
|
||||
InteractionType.ReleasedForVerification => "Freigabe zum Freischalten",
|
||||
InteractionType.ReleasedForVerification => "Freigabe Freischalten",
|
||||
_ => type.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
53
Scripts/kill-port-56000.ps1
Normal file
53
Scripts/kill-port-56000.ps1
Normal file
@@ -0,0 +1,53 @@
|
||||
param(
|
||||
[int]$Port = 56000
|
||||
)
|
||||
|
||||
$killedAny = $false
|
||||
|
||||
# Try modern cmdlet first.
|
||||
$connections = Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue
|
||||
if ($connections) {
|
||||
$pids = $connections | Select-Object -ExpandProperty OwningProcess -Unique
|
||||
foreach ($procId in $pids) {
|
||||
try {
|
||||
Stop-Process -Id $procId -Force -ErrorAction Stop
|
||||
Write-Host "Stopped process $procId listening on port $Port."
|
||||
$killedAny = $true
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to stop process ${procId}: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Fallback for environments where Get-NetTCPConnection is unavailable.
|
||||
if (-not $killedAny) {
|
||||
$netstatLines = netstat -ano | Select-String ":$Port\s"
|
||||
$listenLines = $netstatLines | Where-Object { $_.Line -match "LISTENING" }
|
||||
|
||||
$fallbackPids = @()
|
||||
foreach ($line in $listenLines) {
|
||||
$parts = ($line.Line -replace "\s+", " ").Trim().Split(" ")
|
||||
if ($parts.Length -ge 5) {
|
||||
$fallbackPids += $parts[-1]
|
||||
}
|
||||
}
|
||||
|
||||
$fallbackPids = $fallbackPids | Sort-Object -Unique
|
||||
foreach ($pidText in $fallbackPids) {
|
||||
if ($pidText -match "^\d+$") {
|
||||
try {
|
||||
Stop-Process -Id ([int]$pidText) -Force -ErrorAction Stop
|
||||
Write-Host "Stopped process $pidText listening on port $Port."
|
||||
$killedAny = $true
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to stop process ${pidText}: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $killedAny) {
|
||||
Write-Host "No listening process found on port $Port."
|
||||
}
|
||||
Reference in New Issue
Block a user