3 Commits

9 changed files with 166 additions and 208 deletions

View File

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

View File

@ -11,20 +11,5 @@ namespace SZUAbsolventenverein.Module.EventRegistration
{
_jsRuntime = jsRuntime;
}
public async Task CreateChart(string divid, string type, string[] labels, object[] datasets, object options)
{
try
{
await _jsRuntime.InvokeVoidAsync(
"SZUAbsolventenverein.EventRegistration.createChart",
divid, type, (object) labels, (object) datasets, options);
}
catch
{
// handle exception
}
}
}
}

View File

@ -4,6 +4,7 @@
@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
@ -31,19 +32,23 @@
@if (Status == true)
{
<span class ="fontsizeInf">@Localizer["Zugesagt"]</span><br />
<p><button class="btn btn-danger" @onclick="Absage">@Localizer["Absagen"]</button></p>
<p><button class="btn btn-danger" @onclick="Reject">@Localizer["Absagen"]</button></p>
} else
{
<span class="fontsizeInf"> @Localizer["Abgesagt"]</span><br />
<p><button class="btn btn-success" @onclick="Zusage">@Localizer["Zusagen"]</button></p>
<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>
@ -65,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;
@ -79,6 +81,8 @@
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)
{
@ -107,12 +111,12 @@
}
}
private async void Zusage()
private async void Accept()
{
await SendResponse(true);
}
private async void Absage()
private async void Reject()
{
await SendResponse(false);
}
@ -121,6 +125,8 @@
{
try
{
_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);
@ -128,10 +134,10 @@
{
_settings = user.Settings;
}
_users = await EventRegistrationService.GetRecommendedResponses(_id, ModuleState.ModuleId);
_users.ForEach(u => Console.WriteLine(u.UserId));
}
_id = Int32.Parse(PageState.QueryString["id"]);
Event currentEvent;
Response rsvp;
(currentEvent, rsvp) = await EventRegistrationService.GetEventDetails(_id, ModuleState.ModuleId);

View File

@ -42,7 +42,6 @@
{
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
}
<div id="chart"></div>
</form>
@code {
@ -54,9 +53,7 @@
public override List<Resource> Resources => new List<Resource>()
{
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
new Resource { ResourceType = ResourceType.Script, Bundle = "ChartJS", Url = "https://cdn.jsdelivr.net/npm/chart.js" },
new Resource { ResourceType = ResourceType.Script, Bundle = "ChartJS", Url = ModulePath() + "Module.js"}
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
};
@ -74,9 +71,6 @@
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
bool _refresh = false;
private List<Response> _responses;
protected override async Task OnInitializedAsync()
{
@ -98,10 +92,6 @@
_modifiedby = EventRegistration.ModifiedBy;
_modifiedon = EventRegistration.ModifiedOn;
}
_responses = await EventRegistrationService.GetEventResponses(_id, ModuleState.ModuleId);
Console.WriteLine("Responses count: " + (_responses != null ? _responses.Count.ToString() : "null"));
_refresh = true;
}
}
catch (Exception ex)
@ -111,37 +101,6 @@
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
try
{
await base.OnAfterRenderAsync(firstRender);
Console.WriteLine("Responses count: " + (_responses != null ? _responses.Count.ToString() : "null"));
if (_refresh && _responses != null)
{
List<string> labels = new List<string>();
List<object> datasets = new List<object>();
string[] colors = new string[] { "#FF0000", "#FF8000", "#FFFF00", "#00FF00", "#00FFFF", "#0080FF", "#0000FF", "#8000FF", "#FF00FF", "#CCCCCC" };
labels.AddRange("Zusage", "Absage");
datasets.Add(new { label = "DS1", data = new int[] { _responses.Count(r => r.ResponseType == true), _responses.Count(r => r.ResponseType == false) }, fill = false, backgroundColor = colors });
object options = new { maintainAspectRatio = false, legend = new { display = true, position = "bottom", labels = new { fontColor = "white", fontSize = 16 } } };
var interop = new Interop(JSRuntime);
await interop.CreateChart("chart", "pie", labels.ToArray(), datasets.ToArray(), options);
_refresh = false;
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Rendering Chart {Error}", ex.Message);
AddModuleMessage("Error Rendering Chart", MessageType.Error);
}
}
private async Task Save()
{
try

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;
@ -14,7 +15,7 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
public EventRegistrationService(HttpClient http, SiteState siteState) : base(http, siteState) { }
private string Apiurl => CreateApiUrl("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());
@ -30,9 +31,9 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}", EntityNames.Module, NewEvent.ModuleId), NewEvent);
}
public async Task<Event> UpdateEventAsync(Event UpdatedEvent)
public async Task<Event> UpdateEventAsync(Event NewEvent)
{
return await PutJsonAsync<Event>(CreateAuthorizationPolicyUrl($"{Apiurl}/{UpdatedEvent.EventId}", EntityNames.Module, UpdatedEvent.ModuleId), UpdatedEvent);
return await PutJsonAsync<Event>(CreateAuthorizationPolicyUrl($"{Apiurl}/{NewEvent.EventId}", EntityNames.Module, NewEvent.ModuleId), NewEvent);
}
public async Task DeleteEventAsync(int EventId, int ModuleId)
@ -55,12 +56,12 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
return await GetJsonAsync<(Event, Response)>(CreateAuthorizationPolicyUrl($"{Apiurl}/details/{EventId}/{ModuleId}", EntityNames.Module, ModuleId));
}
public async Task<List<Response>> GetEventResponses(int EventId, int ModuleId)
public Task<List<Response>> GetEventResponses(int EventId, int ModuleId)
{
return await GetJsonAsync<List<Response>>(CreateAuthorizationPolicyUrl($"{Apiurl}/all-responses/{EventId}/{ModuleId}", EntityNames.Module, ModuleId));
throw new System.NotImplementedException();
}
public Task<List<Response>> GetRecommendedEventResponses(int EventId, int MouleId)
public Task<List<User>> GetRecommendedResponses(int EventId, int ModuleId)
{
throw new System.NotImplementedException();
}

View File

@ -130,24 +130,6 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Controllers
return (null, null);
}
}
// GET api/<controller>/5
[HttpGet("all-respones/{id}/{moduleid}")]
[Authorize(Policy = PolicyNames.ViewModule)]
public async Task<List<Models.Response>> GetResponses(int id, int moduleid)
{
List<Models.Response> eventResponses = await _EventRegistrationService.GetEventResponses(id, moduleid);
if (eventResponses != null && IsAuthorizedEntityId(EntityNames.Module, moduleid))
{
return eventResponses;
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized EventRegistration Get Attempt {EventRegistrationId} {ModuleId}", id, moduleid);
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return null;
}
}
// TODO: Add Event Response Endpoints.
}

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();
}
@ -121,34 +125,6 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
return null;
}
}
public Task<List<Event>> GetEventsAsync(int ModuleId)
{
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View))
{
return Task.FromResult(_EventRepository.GetEvents(ModuleId).ToList());
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Events Get Attempt {ModuleId}", ModuleId);
return null;
}
}
public Task<Event> UpdateEventAsync(Event UpdatedEvent)
{
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, UpdatedEvent.ModuleId, PermissionNames.Edit))
{
UpdatedEvent = _EventRepository.UpdateEvent(UpdatedEvent);
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Event Updated {NewEvent}", UpdatedEvent);
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Update Attempt {NewEvent}", UpdatedEvent);
UpdatedEvent = null;
}
return Task.FromResult(UpdatedEvent);
}
public Task<(Event, Response)> GetEventDetails(int EventId, int ModuleId)
{
@ -178,12 +154,60 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services
}
}
public Task<List<Response>> GetRecommendedEventResponses(int EventId, int MouleId)
public async Task<List<User>> GetRecommendedResponses(int EventId, int ModuleId)
{
throw new System.NotImplementedException();
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)
{
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View))
{
return Task.FromResult(_EventRepository.GetEvents(ModuleId).ToList());
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Events Get Attempt {ModuleId}", ModuleId);
return null;
}
}
public Task<Event> UpdateEventAsync(Event NewEvent)
{
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, NewEvent.ModuleId, PermissionNames.Edit))
{
NewEvent = _EventRepository.UpdateEvent(NewEvent);
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Event Updated {NewEvent}", NewEvent);
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Update Attempt {NewEvent}", NewEvent);
NewEvent = null;
}
return Task.FromResult(NewEvent);
}
private void SendEventResponseNotification(string subject, string body)
{
User user = _UserRepository.GetUser(_accessor.HttpContext.User.UserId());
@ -191,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

@ -2,25 +2,4 @@
var SZUAbsolventenverein = SZUAbsolventenverein || {};
SZUAbsolventenverein.EventRegistration = {
createChart: async function (divid, type, labels, datasets, options) {
var container = document.getElementById(divid);
if (container.hasChildNodes()) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
}
var canvas = document.createElement('canvas');
canvas.id = divid + '-canvas';
container.appendChild(canvas);
var ctx = canvas.getContext('2d');
var chart = new Chart(ctx, {
type: type,
data: {
labels: labels,
datasets: datasets
},
options: options
});
}
};

View File

@ -1,88 +1,32 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Oqtane.Models;
using SZUAbsolventenverein.Module.EventRegistration.Models;
namespace SZUAbsolventenverein.Module.EventRegistration.Services
{
/// <summary>
/// Methods for managing events and their responses
/// </summary>
public interface IEventRegistrationService
{
/// <summary>
/// Alle Events eines Moduls abrufen
/// </summary>
/// <param name="ModuleId">das aufrufende Modul</param>
/// <returns>Liste aller Veranstaltungen</returns>
/* Reine Events */
Task<List<Event>> GetEventsAsync(int ModuleId);
/// <summary>
/// Ein bestimmtes Event abrufen
/// </summary>
/// <param name="EventId">das aufzurufende Event</param>
/// <param name="ModuleId">das aufrufende Modul</param>
/// <returns>Das Event selbst</returns>
Task<Event> GetEventAsync(int EventId, int ModuleId);
/// <summary>
/// Ein neues Event anlegen
/// </summary>
/// <param name="NewEvent">das anzulegende Event</param>
/// <returns>das angelegte Event</returns>
Task<Event> AddEventAsync(Event NewEvent);
/// <summary>
/// Ändern eines bestehenden Events
/// </summary>
/// <param name="UpdatedEvent">Das Eventobjekt mit aktualisierte Event</param>
/// <returns>das gespeicherte Event</returns>
Task<Event> UpdateEventAsync(Event UpdatedEvent);
Task<Event> UpdateEventAsync(Event NewEvent);
/// <summary>
/// Löschen eines Events
/// </summary>
/// <param name="EventId">das zu löschende Event</param>
/// <param name="ModuleId">das aufrufende Modul</param>
/// <returns></returns>
Task DeleteEventAsync(int EventId, int ModuleId);
/// <summary>
/// Eine neue Antwort zu einem Event hinzufügen
/// </summary>
/// <param name="Response">die Antwort</param>
/// <returns>die gespeicherte Antwort</returns>
/* Events & Responses */
Task<Response> AddResponseAsync(Response Response);
/// <summary>
/// Eine bestehende Antwort zu einem Event aktualisieren
/// </summary>
/// <param name="Response">die neue Antwort</param>
/// <returns>die gespeicherte neue Antwort</returns>
Task<Response> UpdateResponseAsync(Response Response);
/// <summary>
/// Details zu einem Event abrufen (Event + Antwort vom auktuellen Benutzer)
/// </summary>
/// <param name="EventId">das aufzurufende Event</param>
/// <param name="ModuleId">das aufrufende Modul</param>
/// <returns>Tuple aus Event und Antwort</returns>
Task<(Event, Response)> GetEventDetails(int EventId, int ModuleId);
/// <summary>
/// Alle Antworten zu einem Event abrufen
/// </summary>
/// <param name="EventId">das Event, dessen Antworten geladen werden sollen</param>
/// <param name="ModuleId">das aufrufende Modul</param>
/// <returns>Liste aller Antworten auf das Event</returns>
Task<List<Response>> GetEventResponses(int EventId, int ModuleId);
/// <summary>
/// 10 Antworten eines Events abrufen, welche gewichtet zurückgeliefert werden
/// </summary>
/// <param name="EventId">das aufzurufende Event</param>
/// <param name="MouleId">das aufrufende Modul</param>
/// <returns>Liste mit 10 </returns>
Task<List<Response>> GetRecommendedEventResponses(int EventId, int MouleId);
Task<List<User>> GetRecommendedResponses(int EventId, int ModuleId);
}
}