15 Commits

Author SHA1 Message Date
a9baccb998 Cosmetic: Komment ERS entfernt und kleiner Cleanup beim Server Service 2025-12-22 18:29:32 +01:00
38daf1801b Serverseitig: 10 Benutzer Scoring Serverseiting reimplementiert 2025-12-18 13:27:22 +01:00
9c52e734c5 Client Side structure for recommended 10 Users (ready for Florian) 2025-12-18 11:06:36 +01:00
81ac7cf761 Fix: Linux debug.sh ($ after the path) 2025-12-04 09:06:39 +01:00
9b1ea5ada1 Revert: 234 2025-11-20 11:39:51 +01:00
9eca4dd779 Merge branch 'kh-test' 2025-11-20 11:38:54 +01:00
ce68c5eb1d Bump Version 2025-11-20 11:36:52 +01:00
1359aee2b1 Code-Style: DRO: Validate Profile erst in SendResponse machen 2025-11-20 11:34:24 +01:00
7929f0bed6 Reintroduce the Register Button 2025-11-20 11:33:13 +01:00
f86287783c Bug: Loading Userprofile while not signed in interrupts Loading of the event 2025-11-20 11:29:26 +01:00
669cc79678 Oqtane 6.2.1 Dependency Bump 2025-11-20 11:26:22 +01:00
7694fc1e08 ValidateProfiles gemacht, Link zu Profiles wenn Jahrgang und fachrichtung fehlt und bei save wieder zurück zum Event gemacht 2025-11-06 14:39:45 +01:00
835795f526 ein fehler ist wieder zurückgekommen aber ist jetzt wieder gefixed 2025-11-05 09:40:36 +01:00
e12e4c5325 noch ein kleiner fix bei den buttons 2025-11-04 20:30:05 +01:00
2ed210e20f 234as 2025-05-19 11:31:24 +02:00
11 changed files with 242 additions and 126 deletions

View File

@ -0,0 +1,6 @@
<h3>@user.DisplayName</h3>
@code {
[Parameter]
public User user { get; set; }
}

View File

@ -1,19 +1,27 @@
@using Oqtane.Modules.Controls
@using Oqtane
@using Oqtane.Modules.Controls
@using Oqtane.Themes.Controls
@using SZUAbsolventenverein.Module.EventRegistration.Services
@using SZUAbsolventenverein.Module.EventRegistration.Models
@using System.Text.RegularExpressions
@using SZUAbsolventenverein.Module.EventRegistration.Client.Components
@namespace SZUAbsolventenverein.Module.EventRegistration
@inherits ModuleBase
@inject IEventRegistrationService EventRegistrationService
@inject NavigationManager NavigationManager
@inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@inject IUserService UserService
@inject IProfileService ProfileService
@inject ISettingService SettingService
<h3>Anmeldung zum Event</h3>
<p>Willst du am Event (@_name) teilnehmen?</p>
<span class="mb-6">@_eventDate.ToLocalTime() - @_location</span>
<div>
@((MarkupString)_description)
@((MarkupString) _description)
</div>
@if (PageState.User != null) {
@ -23,32 +31,31 @@
<p class="mt-2"><strong>Status: </strong>
@if (Status == true)
{
<span class ="fontsizeInf">@Localizer["Zugesagt"]</span>
<br />
<button class="btn btn-danger" @onclick="Absage">@Localizer["Absagen"]</button>
<span class ="fontsizeInf">@Localizer["Zugesagt"]</span><br />
<p><button class="btn btn-danger" @onclick="Reject">@Localizer["Absagen"]</button></p>
} else
{
<span class="fontsizeInf"> @Localizer["Abgesagt"]</span>
<br class="mt-2" />
<button class="btn btn-success" @onclick="Zusage">@Localizer["Zusagen"]</button>
<span class="fontsizeInf"> @Localizer["Abgesagt"]</span><br />
<p><button class="btn btn-success" @onclick="Accept">@Localizer["Zusagen"]</button></p>
}
</p>
} else {
<div class="buttons">
<button class="btn btn-success" @onclick="Zusage">@Localizer["Zusagen"]</button>
<button class="btn btn-danger" @onclick="Absage">@Localizer["Absagen"]</button>
<button class="btn btn-success" @onclick="Accept">@Localizer["Zusagen"]</button>
<button class="btn btn-danger" @onclick="Reject">@Localizer["Absagen"]</button>
</div>
}
@foreach (User u in _users)
{
<UserComponent user="u" />
}
} else
{
<p class="mt-3">Um dich für dieses Event zu registrieren, muss man sich zuerst anmelden.</p>
<div class="gap-2">
<Login />
@* @if(PageState.Site.AllowRegistration)
{
<Register />
} *@
<UserProfile ShowRegister="true" />
</div>
}
@code {
@ -63,9 +70,6 @@
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
};
// private ElementReference form;
// private bool validated = false;
private int _id;
private string _name;
private string _description;
@ -75,8 +79,14 @@
private Response _response;
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)
{
if(ValidateProfiles()) {
if(_response == null)
{
_response = new Response();
@ -91,14 +101,22 @@
_response = await EventRegistrationService.UpdateResponseAsync(_response);
}
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 Zusage()
private async void Accept()
{
await SendResponse(true);
}
private async void Absage()
private async void Reject()
{
await SendResponse(false);
}
@ -109,6 +127,17 @@
{
_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;
Response rsvp;
(currentEvent, rsvp) = await EventRegistrationService.GetEventDetails(_id, ModuleState.ModuleId);
@ -132,4 +161,46 @@
AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error);
}
}
private bool ValidateProfiles()
{
foreach (Profile profile in _profiles)
{
var value = GetProfileValue(profile.Name, string.Empty);
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
{
_settings = SettingService.SetSetting(_settings, profile.Name, profile.DefaultValue);
}
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{
if (profile.IsRequired && string.IsNullOrEmpty(value))
{
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
return false;
}
if (!string.IsNullOrEmpty(profile.Validation))
{
Regex regex = new Regex(profile.Validation);
bool valid = regex.Match(value).Success;
if (!valid)
{
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
return false;
}
}
}
}
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

@ -9,9 +9,9 @@ namespace SZUAbsolventenverein.Module.EventRegistration
{
Name = "EventRegistration",
Description = "A module to manage registration for events",
Version = "1.0.14",
Version = "1.0.17",
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",
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",
Dependencies = "SZUAbsolventenverein.Module.EventRegistration.Shared.Oqtane",
PackageName = "SZUAbsolventenverein.Module.EventRegistration"
};

View File

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

View File

@ -3,6 +3,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Oqtane.Models;
using Oqtane.Services;
using Oqtane.Shared;
using SZUAbsolventenverein.Module.EventRegistration.Models;
@ -15,27 +16,6 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
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)
{
List<Event> EventRegistrations = await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", EntityNames.Module, ModuleId), Enumerable.Empty<Event>().ToList());
@ -80,5 +60,10 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
{
throw new System.NotImplementedException();
}
public Task<List<User>> GetRecommendedResponses(int EventId, int ModuleId)
{
throw new System.NotImplementedException();
}
}
}

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>$projectname$</id>
<version>1.0.14</version>
<version>1.0.17</version>
<authors>SZUAbsolventenverein</authors>
<owners>SZUAbsolventenverein</owners>
<title>EventRegistration</title>

View File

@ -3,10 +3,10 @@
TargetFramework=$1
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.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.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.pdb" "../../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 "../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 "../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 -rf "../Server/wwwroot/"* "../../oqtane.framework/Oqtane.Server/wwwroot/"

View File

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

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Oqtane.Enums;
@ -23,9 +25,10 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
private readonly IUserPermissions _userPermissions;
private readonly ILogManager _logger;
private readonly IHttpContextAccessor _accessor;
private readonly ISettingRepository _settingRepository;
private readonly Alias _alias;
public ServerEventRegistrationService(IEventRepository EventRepository, IResponseRepository ResponseRepository, INotificationRepository NotificationRepository, IUserRepository UserRepository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor)
public ServerEventRegistrationService(IEventRepository EventRepository, IResponseRepository ResponseRepository, INotificationRepository NotificationRepository, IUserRepository UserRepository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor, ISettingRepository settingRepository)
{
_EventRepository = EventRepository;
_ResponseRepository = ResponseRepository;
@ -34,6 +37,7 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
_userPermissions = userPermissions;
_logger = logger;
_accessor = accessor;
_settingRepository = settingRepository;
_alias = tenantManager.GetAlias();
}
@ -148,7 +152,32 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Response Get Attempt {ModuleId}", ModuleId);
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)
@ -179,55 +208,6 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
return Task.FromResult(NewEvent);
}
// TODO: Implement the methods for EventResponses
/*
public Task<Models.Event> GetEventRegistrationAsync(int EventRegistrationId, int ModuleId)
{
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View))
{
return Task.FromResult(_EventRegistrationRepository.GetEventRegistration(EventRegistrationId));
}
else
{
_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);
}
}*/
private void SendEventResponseNotification(string subject, string body)
{
User user = _UserRepository.GetUser(_accessor.HttpContext.User.UserId());
@ -235,4 +215,76 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
_NotificationRepository.AddNotification(notification);
}
}
public class GroupingUser
{
private User _user;
private Response _response;
private string _fachrichtung;
private int _startjahr;
private int _targetyear;
private string _targetfachrichtung;
public User User { get { return _user; } }
public IEnumerable<Setting> Settings
{
set
{
if (value == null)
{
_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
{
return 0;
}
}
}
}

View File

@ -70,7 +70,7 @@
@media (hover: hover) and (pointer: fine) {
.event-card:hover {
border-color: #66ccff;
transform: translateY(-4px);
box-shadow: 0 6px 14px rgba(0,0,0,.5);
}
}

View File

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