3 Commits

Author SHA1 Message Date
Konstantin Hintermayer
7960fcc29d CI: Setup dotnet SDK before running automatic build
Some checks failed
/ build (push) Failing after 1m40s
2025-05-17 14:35:58 +02:00
Konstantin Hintermayer
d967449889 CI: Add CI branch as trigger for testing
Some checks failed
/ build (push) Failing after 48s
2025-05-14 21:50:56 +02:00
Konstantin Hintermayer
02a845c711 Add CI scripts to build the module automatically 2025-05-14 21:07:34 +02:00
22 changed files with 283 additions and 617 deletions

37
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,37 @@
on:
push:
branches:
- main
- ci
pull_request:
branches:
- main
- ci
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout Module
uses: https://github.com/actions/checkout@v4
with:
path: Module.EventRegistration
- name: Checkout Oqtane
uses: https://github.com/actions/checkout@v4
with:
repository: Diplomarbeit-Absolventenverein/oqtane.framework
path: oqtane.framework
ref: v6.1.1
- name: Setup Dotnet SDK
uses: https://github.com/actions/setup-dotnet@v4
with:
dotnet-version: '9.x'
- name: LS
run: ls -lisa
- name: Build Oqtane
run: dotnet build ./oqtane.framework/Oqtane.sln --configuration Debug
- name: Build Module
run: dotnet build ./Module.EventRegistration/SZUAbsolventenverein.Module.EventRegistration.sln --configuration Release
- name: Test
run: dotnet test ./Module.EventRegistration/SZUAbsolventenverein.Module.EventRegistration.sln --configuration Release --no-build

View File

@@ -0,0 +1,35 @@
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
release:
types:
- published
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v4
- name: Verify commit exists in origin/main
run: |
git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*
git branch --remote --contains | grep origin/main
- name: Set VERSION variable from tag
run: echo "VERSION=${GITEA_REF/refs\/tags\/v/}" >> $GITEA_ENV
- name: Setup Dotnet SDK
uses: https://github.com/actions/setup-dotnet@v4
- name: Build
run: dotnet build --configuration Release /p:Version=${VERSION}
- name: Test
run: dotnet test --configuration Release /p:Version=${VERSION} --no-build
- name: Pack
run: dotnet pack --configuration Release /p:Version=${VERSION} --no-build --output .
- uses: https://github.com/actions/upload-artifact@v4
with:
name: nuget
if-no-files-found: error
retention-days: 7
path: ./*.nupkg

View File

@@ -1,23 +0,0 @@
@inject FileService fileService
<div>
<img src=@profilePictureUrl />
<h4>@user.DisplayName</h4>
<p>@user.Settings["Jahrgang"] - @user.Settings["Fachrichtung"]</p>
</div>
@code {
[Parameter]
public User user { get; set; }
private string profilePictureUrl = "";
protected override async Task OnInitializedAsync()
{
if(user.PhotoFileId != null)
{
File f = await fileService.GetFileAsync(user.PhotoFileId);
profilePictureUrl = f.Url;
}
}
}

View File

@@ -1,61 +1,41 @@
@using Oqtane @using Oqtane.Modules.Controls
@using Oqtane.Modules.Controls
@using Oqtane.Themes.Controls
@using SZUAbsolventenverein.Module.EventRegistration.Services @using SZUAbsolventenverein.Module.EventRegistration.Services
@using SZUAbsolventenverein.Module.EventRegistration.Models @using SZUAbsolventenverein.Module.EventRegistration.Models
@using System.Text.RegularExpressions
@using SZUAbsolventenverein.Module.EventRegistration.Client.Components
@namespace SZUAbsolventenverein.Module.EventRegistration @namespace SZUAbsolventenverein.Module.EventRegistration
@inherits ModuleBase @inherits ModuleBase
@inject IEventRegistrationService EventRegistrationService @inject IEventRegistrationService EventRegistrationService
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IStringLocalizer<Edit> Localizer @inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@inject IUserService UserService
@inject IProfileService ProfileService
@inject ISettingService SettingService
<h3>Anmeldung zum Event</h3> <h3>Anmeldung zum Event</h3>
<p>Willst du am Event (@_name) teilnehmen?</p> <p>Willst du am Event (@_name) teilnehmen?</p>
<span class="mb-6">@_eventDate.ToLocalTime() - @_location</span>
<div>
@((MarkupString) _description)
</div>
@if (PageState.User != null) { @if (PageState.User != null) {
@if (Status != null) @if (Status != null)
{ {
<p class="mt-2"><strong>Status: </strong> <p class="mt-3"><strong>Status:</strong>
@if (Status == true) @if (Status == true)
{ {
<span class ="fontsizeInf">@Localizer["Zugesagt"]</span><br /> @Localizer["Zusage"]
<p><button class="btn btn-danger" @onclick="Reject">@Localizer["Absagen"]</button></p> <button class="btn btn-danger" @onclick="Absage">@Localizer["Absagen"]</button>
} else } else
{ {
<span class="fontsizeInf"> @Localizer["Abgesagt"]</span><br /> @Localizer["Absage"]
<p><button class="btn btn-success" @onclick="Accept">@Localizer["Zusagen"]</button></p> <button class="btn btn-success" @onclick="Zusage">@Localizer["Zusagen"]</button>
} }
</p> </p>
} else { } else {
<div class="buttons"> <div class="buttons">
<button class="btn btn-success" @onclick="Accept">@Localizer["Zusagen"]</button> <button class="btn btn-success" @onclick="Zusage">@Localizer["Zusagen"]</button>
<button class="btn btn-danger" @onclick="Reject">@Localizer["Absagen"]</button> <button class="btn btn-danger" @onclick="Absage">@Localizer["Absagen"]</button>
</div> </div>
} }
@foreach (User u in _users)
{
<UserComponent user="u" />
}
} else } else
{ {
<p class="mt-3">Um dich für dieses Event zu registrieren, muss man sich zuerst anmelden.</p> <p class="mt-3">Um dich für dieses Event zu registrieren, muss man sich zuerst anmelden.</p> <Login />
<div class="gap-2">
<Login />
<UserProfile ShowRegister="true" />
</div>
} }
@code { @code {
@@ -70,23 +50,21 @@
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" } new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
}; };
private ElementReference form;
private bool validated = false;
private int _id; private int _id;
private string _name; private string _name;
private string _description; private string _createdby;
private DateTime _eventDate; private DateTime _createdon;
private string _location; private string _modifiedby;
private DateTime _modifiedon;
private Response _response; private Response _response;
private bool? Status; private bool? Status;
private List<Profile> _profiles = new List<Profile>();
private Dictionary<string, string> _settings;
private List<User> _users = new List<User>();
private async Task SendResponse(bool response) private async Task SendResponse(bool response)
{ {
if(ValidateProfiles()) {
if(_response == null) if(_response == null)
{ {
_response = new Response(); _response = new Response();
@@ -101,22 +79,14 @@
_response = await EventRegistrationService.UpdateResponseAsync(_response); _response = await EventRegistrationService.UpdateResponseAsync(_response);
} }
if(_response != null) Status = _response.ResponseType; if(_response != null) Status = _response.ResponseType;
} else
{
var currentPathAndQuery = new Uri(NavigationManager.Uri).PathAndQuery;
var encodedReturnUrl = Uri.EscapeDataString(currentPathAndQuery);
var link = $"/profile?tab=Profile&returnurl={encodedReturnUrl}";
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], $"Vervollständige hier dein Profil mit deinem Jahrgang und deiner Fachrichtung: <a href=\"{link}\">Link zum Profil</a>"), MessageType.Warning);
}
} }
private async void Accept() private async void Zusage()
{ {
await SendResponse(true); await SendResponse(true);
} }
private async void Reject() private async void Absage()
{ {
await SendResponse(false); await SendResponse(false);
} }
@@ -127,26 +97,16 @@
{ {
_id = Int32.Parse(PageState.QueryString["id"]); _id = Int32.Parse(PageState.QueryString["id"]);
if(PageState.User != null) {
_profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
var user = await UserService.GetUserAsync(PageState.User.UserId, PageState.Site.SiteId);
if (user != null)
{
_settings = user.Settings;
}
_users = await EventRegistrationService.GetRecommendedResponses(_id, ModuleState.ModuleId);
_users.ForEach(u => Console.WriteLine(u.UserId));
}
Event currentEvent; Event currentEvent;
Response rsvp; Response rsvp;
(currentEvent, rsvp) = await EventRegistrationService.GetEventDetails(_id, ModuleState.ModuleId); (currentEvent, rsvp) = await EventRegistrationService.GetEventDetails(_id, ModuleState.ModuleId);
if (currentEvent != null) if (currentEvent != null)
{ {
_name = currentEvent.Name; _name = currentEvent.Name;
_description = currentEvent.Description; _createdby = currentEvent.CreatedBy;
_eventDate = currentEvent.EventDate; _createdon = currentEvent.CreatedOn;
_location = currentEvent.Location; _modifiedby = currentEvent.ModifiedBy;
_modifiedon = currentEvent.ModifiedOn;
} }
if(rsvp != null) if(rsvp != null)
@@ -162,45 +122,40 @@
} }
} }
private async Task Save()
private bool ValidateProfiles()
{ {
foreach (Profile profile in _profiles) try
{ {
var value = GetProfileValue(profile.Name, string.Empty); validated = true;
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue)) var interop = new Oqtane.UI.Interop(JSRuntime);
if (await interop.FormValid(form))
{ {
_settings = SettingService.SetSetting(_settings, profile.Name, profile.DefaultValue); if (PageState.Action == "Add")
}
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{ {
if (profile.IsRequired && string.IsNullOrEmpty(value)) Event EventRegistration = new Event();
EventRegistration.ModuleId = ModuleState.ModuleId;
EventRegistration.Name = _name;
EventRegistration = await EventRegistrationService.AddEventAsync(EventRegistration);
await logger.LogInformation("EventRegistration Added {EventRegistration}", EventRegistration);
}
else
{ {
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning); Event EventRegistration = await EventRegistrationService.GetEventAsync(_id, ModuleState.ModuleId);
return false; EventRegistration.Name = _name;
await EventRegistrationService.UpdateEventAsync(EventRegistration);
await logger.LogInformation("EventRegistration Updated {EventRegistration}", EventRegistration);
} }
if (!string.IsNullOrEmpty(profile.Validation)) NavigationManager.NavigateTo(NavigateUrl());
}
else
{ {
Regex regex = new Regex(profile.Validation); AddModuleMessage(Localizer["Message.SaveValidation"], MessageType.Warning);
bool valid = regex.Match(value).Success; }
if (!valid) }
catch (Exception ex)
{ {
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning); await logger.LogError(ex, "Error Saving EventRegistration {Error}", ex.Message);
return false; AddModuleMessage(Localizer["Message.SaveError"], MessageType.Error);
} }
} }
} }
}
return true;
}
private string GetProfileValue(string SettingName, string DefaultValue)
{
string value = SettingService.GetSetting(_settings, SettingName, DefaultValue);
if (value.Contains("]"))
{
value = value.Substring(value.IndexOf("]") + 1);
}
return value;
}
}

View File

@@ -1,7 +1,6 @@
@using Oqtane.Modules.Controls @using Oqtane.Modules.Controls
@using SZUAbsolventenverein.Module.EventRegistration.Services @using SZUAbsolventenverein.Module.EventRegistration.Services
@using SZUAbsolventenverein.Module.EventRegistration.Models @using SZUAbsolventenverein.Module.EventRegistration.Models
@using Microsoft.AspNetCore.Components.Forms
@namespace SZUAbsolventenverein.Module.EventRegistration @namespace SZUAbsolventenverein.Module.EventRegistration
@inherits ModuleBase @inherits ModuleBase
@@ -17,23 +16,6 @@
<input id="name" class="form-control" @bind="@_name" required /> <input id="name" class="form-control" @bind="@_name" required />
</div> </div>
</div> </div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="location" HelpText="Enter a Location" ResourceKey="Location">Location: </Label>
<div class="col-sm-9">
<input id="location" class="form-control" @bind="@_location" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="eventdate" HelpText="Enter a Date" ResourceKey="EventDate">EventDate: </Label>
<div class="col-sm-9">
<!--<input id="eventdate" class="form-control" @bind="@_eventDate" required />-->
<InputDate id="eventdate" class="form-control" @bind-Value="@_eventDate" Type="InputDateType.DateTimeLocal" />
</div>
</div>
<div class="mb-1 align-items-center">
<Label Class="" For="description" HelpText="Enter a description" ResourceKey="Description">Description: </Label>
<RichTextEditor @ref="@RichTextEditorHtml" Content="@_description" Placeholder="Enter a description"/>
</div>
</div> </div>
<button type="button" class="btn btn-success" @onclick="Save">@Localizer["Save"]</button> <button type="button" class="btn btn-success" @onclick="Save">@Localizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
@@ -56,17 +38,11 @@
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" } new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
}; };
private RichTextEditor RichTextEditorHtml;
private ElementReference form; private ElementReference form;
private bool validated = false; private bool validated = false;
private int _id; private int _id;
private string _name; private string _name;
private string _description;
private DateTime _eventDate = DateTime.Now;
private string _location;
private string _createdby; private string _createdby;
private DateTime _createdon; private DateTime _createdon;
private string _modifiedby; private string _modifiedby;
@@ -83,10 +59,6 @@
if (EventRegistration != null) if (EventRegistration != null)
{ {
_name = EventRegistration.Name; _name = EventRegistration.Name;
_description = EventRegistration.Description;
_eventDate = EventRegistration.EventDate.ToLocalTime();
_location = EventRegistration.Location;
_createdby = EventRegistration.CreatedBy; _createdby = EventRegistration.CreatedBy;
_createdon = EventRegistration.CreatedOn; _createdon = EventRegistration.CreatedOn;
_modifiedby = EventRegistration.ModifiedBy; _modifiedby = EventRegistration.ModifiedBy;
@@ -107,10 +79,6 @@
{ {
validated = true; validated = true;
var interop = new Oqtane.UI.Interop(JSRuntime); var interop = new Oqtane.UI.Interop(JSRuntime);
string content = await RichTextEditorHtml.GetHtml();
content = Utilities.FormatContent(content, PageState.Alias, "save");
if (await interop.FormValid(form)) if (await interop.FormValid(form))
{ {
if (PageState.Action == "Add") if (PageState.Action == "Add")
@@ -118,9 +86,6 @@
Event EventRegistration = new Event(); Event EventRegistration = new Event();
EventRegistration.ModuleId = ModuleState.ModuleId; EventRegistration.ModuleId = ModuleState.ModuleId;
EventRegistration.Name = _name; EventRegistration.Name = _name;
EventRegistration.Description = content;
EventRegistration.EventDate = _eventDate.ToUniversalTime();
EventRegistration.Location = _location;
EventRegistration = await EventRegistrationService.AddEventAsync(EventRegistration); EventRegistration = await EventRegistrationService.AddEventAsync(EventRegistration);
await logger.LogInformation("EventRegistration Added {EventRegistration}", EventRegistration); await logger.LogInformation("EventRegistration Added {EventRegistration}", EventRegistration);
} }
@@ -128,9 +93,6 @@
{ {
Event EventRegistration = await EventRegistrationService.GetEventAsync(_id, ModuleState.ModuleId); Event EventRegistration = await EventRegistrationService.GetEventAsync(_id, ModuleState.ModuleId);
EventRegistration.Name = _name; EventRegistration.Name = _name;
EventRegistration.Description = content;
EventRegistration.EventDate = _eventDate.ToUniversalTime();
EventRegistration.Location = _location;
await EventRegistrationService.UpdateEventAsync(EventRegistration); await EventRegistrationService.UpdateEventAsync(EventRegistration);
await logger.LogInformation("EventRegistration Updated {EventRegistration}", EventRegistration); await logger.LogInformation("EventRegistration Updated {EventRegistration}", EventRegistration);
} }

View File

@@ -16,38 +16,24 @@ else
<ActionLink Action="Add" Security="SecurityAccessLevel.Edit" Text="Add Event" ResourceKey="Add" /> <ActionLink Action="Add" Security="SecurityAccessLevel.Edit" Text="Add Event" ResourceKey="Add" />
<br /> <br />
<br /> <br />
<p>@Status</p>
@if (@_EventRegistrations.Count != 0) @if (@_EventRegistrations.Count != 0)
{ {
<Pager Items="@_EventRegistrations">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["Name"]</th>
<th style="width: 1px;">&nbsp;</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.EventId.ToString())" ResourceKey="Edit" /></td>
<td><ActionDialog Header="Delete EventRegistration" Message="Are You Sure You Wish To Delete This EventRegistration?" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" ResourceKey="Delete" Id="@context.EventId.ToString()" /></td>
<td>@context.Name</td>
<div class="event-list"> <td><ActionLink Action="Details" Parameters="@($"id=" + context.EventId.ToString())" ResourceKey="Details"/></td>
<div class="event-list"> </Row>
@foreach (var context in _EventRegistrations) </Pager>
{
<div class="event-card">
<h3>@context.Name</h3>
<p><strong>@Localizer["Date"]:</strong> @context.EventDate.ToLocalTime()</p>
<p><strong>@Localizer["Location"]:</strong> @context.Location</p>
<div class="event-actions">
<ActionLink Action="Edit"
Parameters="@($"id={context.EventId}")"
ResourceKey="Edit" />
<ActionDialog Action="Delete"
Security="SecurityAccessLevel.Edit"
Class="btn btn-danger"
OnClick="@(async () => await Delete(context))"
ResourceKey="Delete"
Id="@context.EventId.ToString()" />
<ActionLink Action="Details"
Parameters="@($"id={context.EventId}")"
ResourceKey="Details" />
</div>
</div>
}
</div>
</div>
} }
else else
{ {
@@ -56,6 +42,8 @@ else
} }
@code { @code {
private string Status;
public override List<Resource> Resources => new List<Resource>() public override List<Resource> Resources => new List<Resource>()
{ {
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }, new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
@@ -92,4 +80,15 @@ else
AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error); AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error);
} }
} }
private async Task Accept(Event eventRegistration)
{
Status = ("EventRegistration Accepted " + eventRegistration.Name);
await logger.LogInformation("EventRegistration Accepted {EventRegistration}", eventRegistration);
}
private void Reject()
{
Status = "EventRegistration Rejected 1";
}
} }

View File

@@ -9,9 +9,9 @@ namespace SZUAbsolventenverein.Module.EventRegistration
{ {
Name = "EventRegistration", Name = "EventRegistration",
Description = "A module to manage registration for events", Description = "A module to manage registration for events",
Version = "1.0.17", Version = "1.0.0",
ServerManagerType = "SZUAbsolventenverein.Module.EventRegistration.Manager.EventRegistrationManager, SZUAbsolventenverein.Module.EventRegistration.Server.Oqtane", ServerManagerType = "SZUAbsolventenverein.Module.EventRegistration.Manager.EventRegistrationManager, SZUAbsolventenverein.Module.EventRegistration.Server.Oqtane",
ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,1.0.5,1.0.6,1.0.7,1.0.8,1.0.9,1.0.10,1.0.11,1.0.12,1.0.13,1.0.14,1.0.15,1.0.16,1.0.17", ReleaseVersions = "1.0.0",
Dependencies = "SZUAbsolventenverein.Module.EventRegistration.Shared.Oqtane", Dependencies = "SZUAbsolventenverein.Module.EventRegistration.Shared.Oqtane",
PackageName = "SZUAbsolventenverein.Module.EventRegistration" PackageName = "SZUAbsolventenverein.Module.EventRegistration"
}; };

View File

@@ -127,10 +127,10 @@
<value>Delete</value> <value>Delete</value>
</data> </data>
<data name="Delete.Header" xml:space="preserve"> <data name="Delete.Header" xml:space="preserve">
<value>Delete</value> <value>Delete Event</value>
</data> </data>
<data name="Delete.Message" xml:space="preserve"> <data name="Delete.Message" xml:space="preserve">
<value>Are You Sure You Wish To Delete This Event? If you delete an event, all existing registrations will be deleted as well.</value> <value>Are You Sure You Wish To Delete This Event?</value>
</data> </data>
<data name="Message.DisplayNone" xml:space="preserve"> <data name="Message.DisplayNone" xml:space="preserve">
<value>No Events To Display</value> <value>No Events To Display</value>
@@ -142,15 +142,6 @@
<value>Error Deleting Event</value> <value>Error Deleting Event</value>
</data> </data>
<data name="Details.Text" xml:space="preserve"> <data name="Details.Text" xml:space="preserve">
<value>Details</value> <value>Reject</value>
</data>
<data name="Name" xml:space="preserve">
<value>Name</value>
</data>
<data name="Date" xml:space="preserve">
<value>Date</value>
</data>
<data name="Location" xml:space="preserve">
<value>Location</value>
</data> </data>
</root> </root>

View File

@@ -13,11 +13,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.9" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.9" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.Http" Version="9.0.3" />
<PackageReference Include="System.Net.Http.Json" Version="9.0.9" /> <PackageReference Include="System.Net.Http.Json" Version="9.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -3,7 +3,6 @@ using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Oqtane.Models;
using Oqtane.Services; using Oqtane.Services;
using Oqtane.Shared; using Oqtane.Shared;
using SZUAbsolventenverein.Module.EventRegistration.Models; using SZUAbsolventenverein.Module.EventRegistration.Models;
@@ -16,6 +15,27 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
private string Apiurl => CreateApiUrl("EventRegistration"); private string Apiurl => CreateApiUrl("EventRegistration");
/*public async Task<List<Models.Event>> GetEventRegistrationsAsync(int ModuleId)
{
List<Models.Event> EventRegistrations = await GetJsonAsync<List<Models.Event>>(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", EntityNames.Module, ModuleId), Enumerable.Empty<Models.Event>().ToList());
return EventRegistrations.OrderBy(item => item.Name).ToList();
}
public async Task<Models.Event> GetEventRegistrationAsync(int EventRegistrationId, int ModuleId)
{
return await GetJsonAsync<Models.Event>(CreateAuthorizationPolicyUrl($"{Apiurl}/{EventRegistrationId}/{ModuleId}", EntityNames.Module, ModuleId));
}
public async Task<Models.Event> AddEventRegistrationAsync(Models.Event EventRegistration)
{
return await PostJsonAsync<Models.Event>(CreateAuthorizationPolicyUrl($"{Apiurl}", EntityNames.Module, EventRegistration.ModuleId), EventRegistration);
}
public async Task<Models.Event> UpdateEventRegistrationAsync(Models.Event EventRegistration)
{
return await PutJsonAsync<Models.Event>(CreateAuthorizationPolicyUrl($"{Apiurl}/{EventRegistration.EventRegistrationId}", EntityNames.Module, EventRegistration.ModuleId), EventRegistration);
}*/
public async Task<List<Event>> GetEventsAsync(int ModuleId) public async Task<List<Event>> GetEventsAsync(int ModuleId)
{ {
List<Event> EventRegistrations = await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", EntityNames.Module, ModuleId), Enumerable.Empty<Event>().ToList()); List<Event> EventRegistrations = await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", EntityNames.Module, ModuleId), Enumerable.Empty<Event>().ToList());
@@ -60,10 +80,5 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }
public Task<List<User>> GetRecommendedResponses(int EventId, int ModuleId)
{
throw new System.NotImplementedException();
}
} }
} }

View File

@@ -1,6 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Oqtane.Services; using Oqtane.Services;
using System.Linq;
using SZUAbsolventenverein.Module.EventRegistration.Services; using SZUAbsolventenverein.Module.EventRegistration.Services;
namespace SZUAbsolventenverein.Module.EventRegistration.Startup namespace SZUAbsolventenverein.Module.EventRegistration.Startup
@@ -8,11 +7,8 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Startup
public class ClientStartup : IClientStartup public class ClientStartup : IClientStartup
{ {
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{
if (!services.Any(s => s.ServiceType == typeof(IEventRegistrationService)))
{ {
services.AddScoped<IEventRegistrationService, EventRegistrationService>(); services.AddScoped<IEventRegistrationService, EventRegistrationService>();
} }
} }
} }
}

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>$projectname$</id> <id>$projectname$</id>
<version>1.0.17</version> <version>1.0.0</version>
<authors>SZUAbsolventenverein</authors> <authors>SZUAbsolventenverein</authors>
<owners>SZUAbsolventenverein</owners> <owners>SZUAbsolventenverein</owners>
<title>EventRegistration</title> <title>EventRegistration</title>
@@ -16,7 +16,7 @@
<releaseNotes></releaseNotes> <releaseNotes></releaseNotes>
<summary></summary> <summary></summary>
<dependencies> <dependencies>
<dependency id="Oqtane.Framework" version="6.2.0" /> <dependency id="Oqtane.Framework" version="6.1.1" />
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>

View File

@@ -3,10 +3,10 @@
TargetFramework=$1 TargetFramework=$1
ProjectName=$2 ProjectName=$2
cp -f "../Client/bin/Debug/$TargetFramework/$ProjectName.Client.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" cp -f "../Client/bin/Debug/$TargetFramework/$ProjectName$.Client.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/"
cp -f "../Client/bin/Debug/$TargetFramework/$ProjectName.Client.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" cp -f "../Client/bin/Debug/$TargetFramework/$ProjectName$.Client.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/"
cp -f "../Server/bin/Debug/$TargetFramework/$ProjectName.Server.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" cp -f "../Server/bin/Debug/$TargetFramework/$ProjectName$.Server.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/"
cp -f "../Server/bin/Debug/$TargetFramework/$ProjectName.Server.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" cp -f "../Server/bin/Debug/$TargetFramework/$ProjectName$.Server.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/"
cp -f "../Shared/bin/Debug/$TargetFramework/$ProjectName.Shared.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" cp -f "../Shared/bin/Debug/$TargetFramework/$ProjectName$.Shared.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/"
cp -f "../Shared/bin/Debug/$TargetFramework/$ProjectName.Shared.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" cp -f "../Shared/bin/Debug/$TargetFramework/$ProjectName$.Shared.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/"
cp -rf "../Server/wwwroot/"* "../../oqtane.framework/Oqtane.Server/wwwroot/" cp -rf "../Server/wwwroot/"* "../../oqtane.framework/Oqtane.Server/wwwroot/"

View File

@@ -1,5 +1,27 @@
TargetFramework=$1 TargetFramework=$1
ProjectName=$2 ProjectName=$2
"..\..\oqtane.framework\oqtane.package\nuget.exe" pack %ProjectName%.nuspec -Properties targetframework=%TargetFramework%;projectname=%ProjectName% ../../oqtane.framework/oqtane.package/nuget.exe pack %ProjectName%.nuspec -Properties targetframework=%TargetFramework%;projectname=%ProjectName%
echo "ls"
ls # JUST FOR DEBUGGING
echo "ls .."
ls .. # JUST FOR DEBUGGING
echo "ls ../.."
ls ../.. # JUST FOR DEBUGGING
echo "ls ../../of"
ls ../../oqtane.framework # JUST FOR DEBUGGING
echo "ls ../../of/of"
ls ../../oqtane.framework/oqtane.framework # JUST FOR DEBUGGING
echo "ls ../../of/op"
ls ../../oqtane.framework/oqtane.package # JUST FOR DEBUGGING
echo "ls ../../of/of/op"
ls ../../oqtane.framework/oqtane.framework/oqtane.package # JUST FOR DEBUGGING
pwd # JUST FOR DEBUGGING
cp -f "*.nupkg" "..\..\oqtane.framework\Oqtane.Server\Packages\" cp -f "*.nupkg" "..\..\oqtane.framework\Oqtane.Server\Packages\"

View File

@@ -40,19 +40,10 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Manager
{ {
// TODO: Export event Responses as well. // TODO: Export event Responses as well.
string content = ""; string content = "";
List<object> exportData = new List<object>(); List<Models.Event> EventRegistrations = _EventRepository.GetEvents(module.ModuleId).ToList();
foreach (var events in _EventRepository.GetEvents(module.ModuleId)) if (EventRegistrations != null)
{ {
var responses = _ResponseRepository.GetResponses(events.EventId, module.ModuleId); content = JsonSerializer.Serialize(EventRegistrations);
exportData.Add(new
{
Event = events,
Responses = responses.ToList()
});
};
if (exportData != null)
{
content = JsonSerializer.Serialize(exportData);
} }
return content; return content;
} }

View File

@@ -26,10 +26,10 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Migrations
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
var responseEB = new EventResponseEntityBuilder(migrationBuilder, ActiveDatabase); var entityBuilder = new EventEntityBuilder(migrationBuilder, ActiveDatabase);
responseEB.Drop(); entityBuilder.Drop();
var eventEB = new EventEntityBuilder(migrationBuilder, ActiveDatabase); var entityBuilder2 = new EventResponseEntityBuilder(migrationBuilder, ActiveDatabase);
eventEB.Drop(); entityBuilder2.Drop();
} }
} }
} }

View File

@@ -1,35 +0,0 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Oqtane.Databases.Interfaces;
using Oqtane.Migrations;
using System;
using SZUAbsolventenverein.Module.EventRegistration.Migrations.EntityBuilders;
using SZUAbsolventenverein.Module.EventRegistration.Repository;
namespace SZUAbsolventenverein.Module.EventRegistration.Migrations
{
[DbContext(typeof(EventRegistrationContext))]
[Migration("SZUAbsolventenverein.Module.EventRegistration.01.00.00.05")]
public class AddDescriptionDateTimeLocation : MultiDatabaseMigration
{
public AddDescriptionDateTimeLocation(IDatabase database) : base(database)
{
}
protected override void Up(MigrationBuilder migrationBuilder)
{
var entityBuilder = new EventEntityBuilder(migrationBuilder, ActiveDatabase);
entityBuilder.AddMaxStringColumn("Description", false, true, ""); // Contents for RichTextEditor
entityBuilder.AddDateTimeColumn("EventDate", false, new DateTime()); // DateTime for the event
entityBuilder.AddStringColumn("Location", 100, false, true, ""); // Location of the event
}
protected override void Down(MigrationBuilder migrationBuilder)
{
var entityBuilder = new EventEntityBuilder(migrationBuilder, ActiveDatabase);
entityBuilder.DropColumn("Description"); // RichTextEditor
entityBuilder.DropColumn("EventDate"); // DateTime
entityBuilder.DropColumn("Location"); // Location 0
}
}
}

View File

@@ -19,10 +19,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.9" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.9" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.9" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Oqtane.Enums; using Oqtane.Enums;
using Oqtane.Extensions; using Oqtane.Extensions;
using Oqtane.Infrastructure; using Oqtane.Infrastructure;
using Oqtane.Models; using Oqtane.Models;
using Oqtane.Repository;
using Oqtane.Security; using Oqtane.Security;
using Oqtane.Shared; using Oqtane.Shared;
using SZUAbsolventenverein.Module.EventRegistration.Models; using SZUAbsolventenverein.Module.EventRegistration.Models;
@@ -20,24 +17,18 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
{ {
private readonly IEventRepository _EventRepository; private readonly IEventRepository _EventRepository;
private readonly IResponseRepository _ResponseRepository; private readonly IResponseRepository _ResponseRepository;
private readonly INotificationRepository _NotificationRepository;
private readonly IUserRepository _UserRepository;
private readonly IUserPermissions _userPermissions; private readonly IUserPermissions _userPermissions;
private readonly ILogManager _logger; private readonly ILogManager _logger;
private readonly IHttpContextAccessor _accessor; private readonly IHttpContextAccessor _accessor;
private readonly ISettingRepository _settingRepository;
private readonly Alias _alias; private readonly Alias _alias;
public ServerEventRegistrationService(IEventRepository EventRepository, IResponseRepository ResponseRepository, INotificationRepository NotificationRepository, IUserRepository UserRepository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor, ISettingRepository settingRepository) public ServerEventRegistrationService(IEventRepository EventRepository, IResponseRepository ResponseRepository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor)
{ {
_EventRepository = EventRepository; _EventRepository = EventRepository;
_ResponseRepository = ResponseRepository; _ResponseRepository = ResponseRepository;
_NotificationRepository = NotificationRepository;
_UserRepository = UserRepository;
_userPermissions = userPermissions; _userPermissions = userPermissions;
_logger = logger; _logger = logger;
_accessor = accessor; _accessor = accessor;
_settingRepository = settingRepository;
_alias = tenantManager.GetAlias(); _alias = tenantManager.GetAlias();
} }
@@ -61,12 +52,6 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, Response.ModuleId, PermissionNames.View)) if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, Response.ModuleId, PermissionNames.View))
{ {
Response = _ResponseRepository.AddResponse(Response); Response = _ResponseRepository.AddResponse(Response);
Event currentEvent = _EventRepository.GetEvent(Response.EventRegistrationId);
string subject = Response.ResponseType ? $"Du bist erfolgreich für '{currentEvent.Name}' Registriert worden." : $"Du hast erfolgreich für '{currentEvent.Name}' abgesagt.";
string body = "Hier kann man die Infos des Events hineinpacken (HTML ist erlaubt)";
SendEventResponseNotification(subject, body);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "EventRegistration Added {NewEvent}", Response); _logger.Log(LogLevel.Information, this, LogFunction.Create, "EventRegistration Added {NewEvent}", Response);
} }
else else
@@ -83,12 +68,6 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, Response.ModuleId, PermissionNames.View)) if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, Response.ModuleId, PermissionNames.View))
{ {
Response = _ResponseRepository.UpdateResponse(Response); Response = _ResponseRepository.UpdateResponse(Response);
Event currentEvent = _EventRepository.GetEvent(Response.EventRegistrationId);
string subject = Response.ResponseType ? $"Du bist erfolgreich für '{currentEvent.Name}' registriert." : $"Du hast erfolgreich für '{currentEvent.Name}' abgesagt.";
string body = currentEvent.Description;
SendEventResponseNotification(subject, body);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "EventRegistration Added {NewEvent}", Response); _logger.Log(LogLevel.Information, this, LogFunction.Create, "EventRegistration Added {NewEvent}", Response);
} }
else else
@@ -152,32 +131,7 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Response Get Attempt {ModuleId}", ModuleId); _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Response Get Attempt {ModuleId}", ModuleId);
return null; return null;
} }
} throw new System.NotImplementedException();
public async Task<List<User>> GetRecommendedResponses(int EventId, int ModuleId)
{
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View))
{
IEnumerable<Response> responses = _ResponseRepository.GetResponses(EventId, ModuleId).DistinctBy(r => r.OwnerId).Where(r => r.OwnerId != _accessor.HttpContext.User.UserId() && r.ResponseType);
IEnumerable<User> users = _UserRepository.GetUsers();
List<Setting> userSettings = _settingRepository.GetSettings("User").ToList();
List<Setting> requestorSettings = userSettings.FindAll(s => s.EntityId == _accessor.HttpContext.User.UserId());
string targetFachrichtung = requestorSettings.FirstOrDefault(s => s.SettingName == "Fachrichtung")?.SettingValue;
int targetStartjahr = int.Parse(requestorSettings.FirstOrDefault(s => s.SettingName == "Jahrgang")?.SettingValue ?? "0");
IEnumerable<GroupingUser> gu = responses.Join(users, r => r.OwnerId, u => u.UserId,
(response, user) => (response, user)).GroupJoin(userSettings, ru => ru.user.UserId,
s => s.EntityId, (ru, s) => new GroupingUser(ru.user, ru.response, s, targetStartjahr, targetFachrichtung)).OrderBy(gu => gu.Score());
return gu.Select(gu => gu.User).Take(10).ToList();
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Response Get Attempt {ModuleId}", ModuleId);
return null;
}
} }
public Task<List<Event>> GetEventsAsync(int ModuleId) public Task<List<Event>> GetEventsAsync(int ModuleId)
@@ -208,83 +162,56 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
return Task.FromResult(NewEvent); return Task.FromResult(NewEvent);
} }
private void SendEventResponseNotification(string subject, string body) // TODO: Implement the methods for EventResponses
{
User user = _UserRepository.GetUser(_accessor.HttpContext.User.UserId());
Notification notification = new Notification(_alias.SiteId, user, subject, body);
_NotificationRepository.AddNotification(notification);
}
}
public class GroupingUser /*
{
private User _user;
private Response _response;
private string _fachrichtung; public Task<Models.Event> GetEventRegistrationAsync(int EventRegistrationId, int ModuleId)
private int _startjahr;
private int _targetyear;
private string _targetfachrichtung;
public User User { get { return _user; } }
public IEnumerable<Setting> Settings
{ {
set if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View))
{ {
if (value == null) return Task.FromResult(_EventRegistrationRepository.GetEventRegistration(EventRegistrationId));
{
_fachrichtung = "-";
_startjahr = 0;
return;
}
_fachrichtung = value.FirstOrDefault(v => v.SettingName == "Fachrichtung", new Setting(){SettingValue = "-"}).SettingValue;
_startjahr = int.Parse(value.FirstOrDefault(v => v.SettingName == "Jahrgang", new Setting(){SettingValue = "0"}).SettingValue);
}
}
public string TargetFachrichtung
{
set { _targetfachrichtung = value; }
}
public int TargetJahr
{
set { _targetyear = value; }
}
public GroupingUser(User user, Response response, IEnumerable<Setting> settings, int targetyear, string targetfachrichtung)
{
_user = user;
_response = response;
Settings = settings;
TargetJahr = targetyear;
TargetFachrichtung = targetfachrichtung;
}
public int Score()
{
int total = 0;
total += ScoreYear() * 5;
total += ScoreFachrichtung() * 3;
return total;
}
private int ScoreYear()
{
return Math.Abs(_targetyear - _startjahr);
}
private int ScoreFachrichtung()
{
if (_fachrichtung == _targetfachrichtung)
{
return 1;
} }
else else
{ {
return 0; _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized EventRegistration Get Attempt {EventRegistrationId} {ModuleId}", EventRegistrationId, ModuleId);
return null;
} }
} }
public Task<Models.Event> AddEventRegistrationAsync(Models.Event EventRegistration)
{
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, EventRegistration.ModuleId, PermissionNames.Edit))
{
EventRegistration = _EventRegistrationRepository.AddEventRegistration(EventRegistration);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "EventRegistration Added {EventRegistration}", EventRegistration);
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized EventRegistration Add Attempt {EventRegistration}", EventRegistration);
EventRegistration = null;
}
return Task.FromResult(EventRegistration);
}
public Task<Models.Event> UpdateEventRegistrationAsync(Models.Event EventRegistration)
{
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, EventRegistration.ModuleId, PermissionNames.Edit))
{
EventRegistration = _EventRegistrationRepository.UpdateEventRegistration(EventRegistration);
_logger.Log(LogLevel.Information, this, LogFunction.Update, "EventRegistration Updated {EventRegistration}", EventRegistration);
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized EventRegistration Update Attempt {EventRegistration}", EventRegistration);
EventRegistration = null;
}
return Task.FromResult(EventRegistration);
}
}*/
} }
} }

View File

@@ -1,201 +1 @@
/* Module Custom Styles */ /* Module Custom Styles */
.mb-6 {
margin-bottom: 6rem;
}
.mt-3 {
margin-top: 3rem;
}
.mt-2 strong {
font-size: 1.4rem; /* Textgr<67><72>e <20> Standard ist ca. 1rem */
font-weight: 700;
}
.fontsizeInf {
font-size: 1.4rem; /* Textgr<67><72>e <20> Standard ist ca. 1rem */
}
.event-list {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
justify-content: center;
}
.event-card {
/*background-color: var(--bs-gray-dark); */
border: 2px solid rgb(128 128 128); /* Umrandung */
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
padding: 1.5rem;
width: 280px;
/* color: #ddd; */
transition: all 0.3s ease;
}
.event-card h3 {
margin-top: 0;
margin-bottom: 0.5rem;
}
.event-card p {
margin: 0.2rem 0;
}
.event-actions {
margin-top: 1rem;
display: flex;
justify-content: space-between;
}
/* vorher:
.event-card:hover {
border-color: #66ccff;
transform: translateY(-4px); <-- das ist der <20>belt<6C>ter
box-shadow: 0 6px 14px rgba(0,0,0,0.5);
}
*/
/* nachher <20> kein transform mehr */
.event-card:hover {
border-color: #66ccff;
/* statt transform die Karte minimal "anheben" */
margin-top: -4px; /* optischer Lift */
box-shadow: 0 6px 14px rgba(0,0,0,0.5);
}
/* sicherheitshalber: Overlay darf nicht abgeschnitten werden */
.event-card {
overflow: visible;
}
/* ---------- A) Hover nur auf Ger<65>ten mit Maus ---------- */
@media (hover: hover) and (pointer: fine) {
.event-card:hover {
border-color: #66ccff;
box-shadow: 0 6px 14px rgba(0,0,0,.5);
}
}
/* Auf Touch-Ger<65>ten kein transform (verhindert Modal-Probleme) */
@media (hover: none), (pointer: coarse) {
.event-card:hover {
transform: none;
box-shadow: 0 6px 14px rgba(0,0,0,.5);
}
}
/* Sicherheitshalber: nichts abschneiden */
.event-card {
overflow: visible;
}
/* ---------- B) Overlay/Modal (Desktop-Basis) ---------- */
/* Falls schon vorhanden, kannst du diese Werte als Override nutzen */
.overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,.45);
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
z-index: 2000;
overscroll-behavior: contain;
}
.modal {
background: #fff;
border-radius: 10px;
box-shadow: 0 20px 60px rgba(0,0,0,.35);
width: min(92vw, 720px);
max-height: 85vh;
display: flex;
flex-direction: column;
overflow: hidden; /* f<>r sticky header/footer */
}
.modal-header,
.modal-footer {
padding: 1rem 1.25rem;
background: #fff;
}
.modal-header {
border-bottom: 1px solid rgba(0,0,0,.1);
}
.modal-footer {
border-top: 1px solid rgba(0,0,0,.1);
display: flex;
gap: .75rem;
justify-content: flex-end;
}
.modal-body {
padding: 1rem 1.25rem;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
/* Medien responsiv im Detail-Dialog */
.modal-body img,
.modal-body video,
.modal-body canvas,
.modal-body iframe {
max-width: 100% !important;
height: auto !important;
display: block;
}
/* ---------- C) Mobile-Vollbild & Sticky-Header/Footer ---------- */
@supports (height: 100dvh) {
.modal {
max-height: 100dvh;
}
}
@media (max-width: 768px) {
.overlay {
padding: 0;
}
.modal {
width: 100vw;
height: 100vh; /* nutzt auf modernen Browsern 100dvh (s.o.) */
max-height: 100vh;
border-radius: 0;
}
.modal-header {
position: sticky;
top: 0;
z-index: 1;
}
.modal-footer {
position: sticky;
bottom: 0;
z-index: 1;
}
.modal-body {
padding: 1rem;
}
/* Lesbare <20>berschriften auf Mobile */
.modal-body h1 {
font-size: clamp(1.25rem, 5.5vw, 2rem);
}
.modal-body h2 {
font-size: clamp(1.125rem, 5vw, 1.5rem);
}
}
/* iOS Safe-Area (Notch) */
@supports (padding: max(0px)) {
.modal {
padding-bottom: max(0px, env(safe-area-inset-bottom));
}
}

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Oqtane.Models;
using SZUAbsolventenverein.Module.EventRegistration.Models; using SZUAbsolventenverein.Module.EventRegistration.Models;
namespace SZUAbsolventenverein.Module.EventRegistration.Services namespace SZUAbsolventenverein.Module.EventRegistration.Services
@@ -27,6 +26,5 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
Task<(Event, Response)> GetEventDetails(int EventId, int ModuleId); Task<(Event, Response)> GetEventDetails(int EventId, int ModuleId);
Task<List<Response>> GetEventResponses(int EventId, int ModuleId); Task<List<Response>> GetEventResponses(int EventId, int ModuleId);
Task<List<User>> GetRecommendedResponses(int EventId, int ModuleId);
} }
} }

View File

@@ -13,10 +13,6 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Models
public int ModuleId { get; set; } public int ModuleId { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Description { get; set; }
public DateTime EventDate { get; set; }
public string Location { get; set; }
public string CreatedBy { get; set; } public string CreatedBy { get; set; }
public DateTime CreatedOn { get; set; } public DateTime CreatedOn { get; set; }
public string ModifiedBy { get; set; } public string ModifiedBy { get; set; }