Skip to content

Commit

Permalink
Merge pull request #6 from rbrands/users/rbrands/2020-07-29
Browse files Browse the repository at this point in the history
Users/rbrands/2020 07 29
  • Loading branch information
rbrands authored Aug 2, 2020
2 parents ec02a6f + bc8da21 commit b912577
Show file tree
Hide file tree
Showing 32 changed files with 749 additions and 59 deletions.
6 changes: 6 additions & 0 deletions MeetUpFunctions/AddParticipantToCalendarItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ public async Task<IActionResult> Run(
}
++counter;
}
int maxRegistrationCount = calendarItem.MaxRegistrationsCount;
if (serverSettings.IsAdmin(keyWord))
{
// Admin can "overbook" a meetup to be able to add some extra guests
maxRegistrationCount *= Constants.ADMINOVERBOOKFACTOR;
}
if (counter >= calendarItem.MaxRegistrationsCount)
{
return new OkObjectResult(new BackendResult(false, "Maximale Anzahl Registrierungen bereits erreicht."));
Expand Down
5 changes: 4 additions & 1 deletion MeetUpFunctions/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public static class Constants
public const string DEFAULT_LINK = "https://robert-brands.com";
public const string DEFAULT_LINK_TITLE = "https://robert-brands.com";

public const string VERSION = "2020-07-28";
public const string VERSION = "2020-08-02";
public const int ADMINOVERBOOKFACTOR = 2;

public const int LOG_TTL = 30 * 24 * 3600; // 30 days TTL for Log items
}
}
118 changes: 118 additions & 0 deletions MeetUpFunctions/ExportTrackingReport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using Newtonsoft.Json;
using MeetUpPlanner.Shared;
using System.Web.Http;
using System.Linq;
using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes;
using System.Collections;

namespace MeetUpPlanner.Functions
{
public class ExportTrackingReport
{
private readonly ILogger _logger;
private ServerSettingsRepository _serverSettingsRepository;
private CosmosDBRepository<CalendarItem> _cosmosRepository;
private CosmosDBRepository<Participant> _participantRepository;
private CosmosDBRepository<ExportLogItem> _logRepository;

public ExportTrackingReport(ILogger<GetExtendedCalendarItems> logger,
ServerSettingsRepository serverSettingsRepository,
CosmosDBRepository<CalendarItem> cosmosRepository,
CosmosDBRepository<Participant> participantRepository,
CosmosDBRepository<ExportLogItem> logRepository)
{
_logger = logger;
_serverSettingsRepository = serverSettingsRepository;
_cosmosRepository = cosmosRepository;
_participantRepository = participantRepository;
_logRepository = logRepository;
}

[FunctionName("ExportTrackingReport")]
[OpenApiOperation(Summary = "Export a list of participants of the given user sharing rides",
Description = "All CalendarItems still in database are scanned for participants who had shared an envent with the given person. To be able to read all ExtendedCalenderItems the admin keyword must be set as header x-meetup-keyword.")]
[OpenApiRequestBody("application/json", typeof(TrackingReportRequest), Description = "Holds all information needed to assemble a tracking report")]
[OpenApiResponseBody(System.Net.HttpStatusCode.OK, "application/json", typeof(TrackingReport))]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function ExportTrackingReport processed a request.");
ServerSettings serverSettings = await _serverSettingsRepository.GetServerSettings();

string keyWord = req.Headers[Constants.HEADER_KEYWORD];
if (String.IsNullOrEmpty(keyWord) || !serverSettings.IsAdmin(keyWord))
{
_logger.LogWarning("ExportTrackingReport called with wrong keyword.");
return new BadRequestErrorMessageResult("Keyword is missing or wrong.");
}
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
TrackingReportRequest trackingRequest = JsonConvert.DeserializeObject<TrackingReportRequest>(requestBody);
if (String.IsNullOrEmpty(trackingRequest.RequestorFirstName) || String.IsNullOrEmpty(trackingRequest.RequestorLastName))
{
_logger.LogWarning("ExportTrackingReport called without name of requestor.");
return new BadRequestErrorMessageResult("Requestor name missing.");
}
if (String.IsNullOrEmpty(trackingRequest.TrackFirstName) || String.IsNullOrEmpty(trackingRequest.TrackLastName))
{
_logger.LogWarning("ExportTrackingReport called without name of person to track.");
return new BadRequestErrorMessageResult("Track name missing.");
}
// Get a list of all CalendarItems
IEnumerable<CalendarItem> rawListOfCalendarItems = await _cosmosRepository.GetItems();
List<ExtendedCalendarItem> resultCalendarItems = new List<ExtendedCalendarItem>(50);
// Filter the CalendarItems that are relevant
foreach (CalendarItem item in rawListOfCalendarItems)
{
// Read all participants for this calendar item
IEnumerable<Participant> participants = await _participantRepository.GetItems(p => p.CalendarItemId.Equals(item.Id));
// Only events where the person was part of will be used.
if (item.EqualsHost(trackingRequest.TrackFirstName, trackingRequest.TrackLastName) || null != participants.Find(trackingRequest.TrackFirstName, trackingRequest.TrackLastName))
{
ExtendedCalendarItem extendedItem = new ExtendedCalendarItem(item);
extendedItem.ParticipantsList = participants;
resultCalendarItems.Add(extendedItem);
}

}
IEnumerable<ExtendedCalendarItem> orderedList = resultCalendarItems.OrderBy(d => d.StartDate);
// Build template for marker list corresponding to orderedList above
List<CompanionCalendarInfo> relevantCalendarList = new List<CompanionCalendarInfo>(50);
int calendarSize = 0;
foreach (ExtendedCalendarItem e in orderedList)
{
relevantCalendarList.Add(new CompanionCalendarInfo(e));
++calendarSize;
}

// Assemble report
TrackingReport report = new TrackingReport(trackingRequest);
report.CompanionList = new List<Companion>(50);
report.CalendarList = relevantCalendarList;
int calendarIndex = 0;
foreach (ExtendedCalendarItem calendarItem in orderedList)
{
report.CompanionList.AddCompanion(calendarItem.HostFirstName, calendarItem.HostLastName, calendarItem.HostAdressInfo, calendarSize, calendarIndex);
foreach (Participant p in calendarItem.ParticipantsList)
{
report.CompanionList.AddCompanion(p.ParticipantFirstName, p.ParticipantLastName, p.ParticipantAdressInfo, calendarSize, calendarIndex);
}
++calendarIndex;
}
report.CreationDate = DateTime.Now;
ExportLogItem log = new ExportLogItem(trackingRequest);
log.TimeToLive = Constants.LOG_TTL;
await _logRepository.CreateItem(log);

return new OkObjectResult(report);
}
}
}
53 changes: 53 additions & 0 deletions MeetUpFunctions/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MeetUpPlanner.Shared;

namespace MeetUpPlanner.Functions
{
public static class Extensions
{
/// <summary>
/// Extension method to find a given person with given firstName and lastName. Case is ignored for comparison.
/// </summary>
/// <param name="participantList"></param>
/// <param name="firstName"></param>
/// <param name="lastName"></param>
/// <returns></returns>
public static Participant Find(this IEnumerable<Participant> participantList, string firstName, string lastName)
{
Participant participant = null;
foreach (Participant p in participantList)
{
if (p.ParticipantFirstName.Equals(firstName, StringComparison.InvariantCultureIgnoreCase) && p.ParticipantLastName.Equals(lastName, StringComparison.InvariantCultureIgnoreCase))
{
participant = p;
break;
}
}
return participant;
}
public static void AddCompanion(this IList<Companion> companionList, string firstName, string lastName, string addressInfo, int sizeOfCalendarList, int calendarIndex)
{
Companion companion = companionList.FirstOrDefault<Companion>(c => c.FirstName.Equals(firstName, StringComparison.InvariantCultureIgnoreCase)
&& c.LastName.Equals(lastName, StringComparison.InvariantCultureIgnoreCase));
if (null == companion)
{
companion = new Companion(firstName, lastName, addressInfo, sizeOfCalendarList);
companionList.Add(companion);
}
else
{
// Add addressInfo to get the latest info.
companion.AddressInfo = addressInfo;
}
companion.EventList[calendarIndex] = true;
}

public static bool EqualsHost(this CalendarItem calendarItem, string firstName, string lastName)
{
return (calendarItem.HostFirstName.Equals(firstName, StringComparison.InvariantCultureIgnoreCase) && calendarItem.HostLastName.Equals(lastName, StringComparison.InvariantCultureIgnoreCase));
}
}
}
71 changes: 71 additions & 0 deletions MeetUpFunctions/GetAllExtendedCalendarItems.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using Newtonsoft.Json;
using MeetUpPlanner.Shared;
using System.Web.Http;
using System.Linq;
using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes;

namespace MeetUpPlanner.Functions
{
public class GetAllExtendedCalendarItems
{
private readonly ILogger _logger;
private ServerSettingsRepository _serverSettingsRepository;
private CosmosDBRepository<CalendarItem> _cosmosRepository;
private CosmosDBRepository<Participant> _participantRepository;
private CosmosDBRepository<CalendarComment> _commentRepository;

public GetAllExtendedCalendarItems(ILogger<GetExtendedCalendarItems> logger, ServerSettingsRepository serverSettingsRepository,
CosmosDBRepository<CalendarItem> cosmosRepository,
CosmosDBRepository<Participant> participantRepository,
CosmosDBRepository<CalendarComment> commentRepository)
{
_logger = logger;
_serverSettingsRepository = serverSettingsRepository;
_cosmosRepository = cosmosRepository;
_participantRepository = participantRepository;
_commentRepository = commentRepository;
}

[FunctionName("GetAllExtendedCalendarItems")]
[OpenApiOperation(Summary = "Gets all ExtendedCalendarIitems",
Description = "Reading all ExtendedCalendarItems (including particpants and comments) for tracking issues. To be able to read all ExtendedCalenderItems the admin keyword must be set as header x-meetup-keyword.")]
[OpenApiResponseBody(System.Net.HttpStatusCode.OK, "application/json", typeof(IEnumerable<ExtendedCalendarItem>))]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function GetAllExtendedCalendarItems processed a request.");
ServerSettings serverSettings = await _serverSettingsRepository.GetServerSettings();

string keyWord = req.Headers[Constants.HEADER_KEYWORD];
if (String.IsNullOrEmpty(keyWord) || !serverSettings.IsAdmin(keyWord))
{
_logger.LogWarning("GetAllExtendedCalendarItems called with wrong keyword.");
return new BadRequestErrorMessageResult("Keyword is missing or wrong.");
}
// Get a list of all CalendarItems

IEnumerable<CalendarItem> rawListOfCalendarItems = await _cosmosRepository.GetItems();
List<ExtendedCalendarItem> resultCalendarItems = new List<ExtendedCalendarItem>(50);
foreach (CalendarItem item in rawListOfCalendarItems)
{
ExtendedCalendarItem extendedItem = new ExtendedCalendarItem(item);
resultCalendarItems.Add(extendedItem);
// Read all participants for this calendar item
extendedItem.ParticipantsList = await _participantRepository.GetItems(p => p.CalendarItemId.Equals(extendedItem.Id));
// Read all comments
extendedItem.CommentsList = await _commentRepository.GetItems(c => c.CalendarItemId.Equals(extendedItem.Id));
}
IEnumerable<ExtendedCalendarItem> orderedList = resultCalendarItems.OrderBy(d => d.StartDate);
return new OkObjectResult(orderedList);
}
}
}
54 changes: 54 additions & 0 deletions MeetUpFunctions/GetExportLog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using Newtonsoft.Json;
using MeetUpPlanner.Shared;
using System.Web.Http;
using System.Linq;
using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes;

namespace MeetUpPlanner.Functions
{
public class GetExportLog
{
private readonly ILogger _logger;
private ServerSettingsRepository _serverSettingsRepository;
private CosmosDBRepository<ExportLogItem> _cosmosRepository;

public GetExportLog(ILogger<GetExportLog> logger, ServerSettingsRepository serverSettingsRepository, CosmosDBRepository<ExportLogItem> cosmosRepository)
{
_logger = logger;
_serverSettingsRepository = serverSettingsRepository;
_cosmosRepository = cosmosRepository;
}

[FunctionName("GetExportLog")]
[OpenApiOperation(Summary = "Returns all export log items",
Description = "Reading all ExportLogItems. To be able to read ExportLogItems the admin keyword must be set as header x-meetup-keyword.")]
[OpenApiResponseBody(System.Net.HttpStatusCode.OK, "application/json", typeof(IEnumerable<ExportLogItem>))]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function GetExportLog processed a request.");
ServerSettings serverSettings = await _serverSettingsRepository.GetServerSettings();

string keyWord = req.Headers[Constants.HEADER_KEYWORD];
if (String.IsNullOrEmpty(keyWord) || !serverSettings.IsAdmin(keyWord))
{
_logger.LogWarning("GetExportLog called with wrong keyword.");
return new BadRequestErrorMessageResult("Keyword is missing or wrong.");
}


IEnumerable<ExportLogItem> exportLog = await _cosmosRepository.GetItems();
IEnumerable<ExportLogItem> orderedList = exportLog.OrderByDescending(l => l.RequestDate);
return new OkObjectResult(orderedList);
}
}
}
4 changes: 2 additions & 2 deletions MeetUpFunctions/GetExtendedCalendarItems.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public GetExtendedCalendarItems(ILogger<GetExtendedCalendarItems> logger, Server
}

[FunctionName("GetExtendedCalendarItems")]
[OpenApiOperation(Summary = "Gets the relevant CalendarIitems",
Description = "Reading current CalendarItems starting in the future or the configured past (in hours). To be able to read CalenderItems the user keyword must be set as header x-meetup-keyword.")]
[OpenApiOperation(Summary = "Gets the relevant ExtendedCalendarIitems",
Description = "Reading current ExtendedCalendarItems (CalendarItem including correpondent participants and comments) starting in the future or the configured past (in hours). To be able to read CalenderItems the user keyword must be set as header x-meetup-keyword.")]
[OpenApiResponseBody(System.Net.HttpStatusCode.OK, "application/json", typeof(IEnumerable<ExtendedCalendarItem>))]
[OpenApiParameter("privatekeywords", Description = "Holds a list of private keywords, separated by ;")]
public async Task<IActionResult> Run(
Expand Down
1 change: 1 addition & 0 deletions MeetUpFunctions/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public override void Configure(IFunctionsHostBuilder builder)
builder.Services.AddSingleton(new CosmosDBRepository<CalendarItem>(config, cosmosClient));
builder.Services.AddSingleton(new CosmosDBRepository<Participant>(config, cosmosClient));
builder.Services.AddSingleton(new CosmosDBRepository<CalendarComment>(config, cosmosClient));
builder.Services.AddSingleton(new CosmosDBRepository<ExportLogItem>(config, cosmosClient));
builder.Services.AddSingleton(new ServerSettingsRepository(config, cosmosClient));
}
}
Expand Down
2 changes: 1 addition & 1 deletion MeetUpPlanner/Client/App.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
<p>Ups, aber der Link ist falsch.</p>
</LayoutView>
</NotFound>
</Router>
2 changes: 1 addition & 1 deletion MeetUpPlanner/Client/AppState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public ClientSettings ClientSettings
[MaxLength(80, ErrorMessage = "Der Nachname ist zu lang."), MinLength(3, ErrorMessage = "Der Nachname ist zu kurz.")]
[Required(ErrorMessage = "Der Nachname fehlt.")]
public string LastName { get; set; }
[MaxLength(60, ErrorMessage = "Die Tel-Nr/Mail-Adresse ist zu lang"), MinLength(8, ErrorMessage = "Die Tel-Nr/Mail-Adresse ist zu kurz.")]
[MaxLength(120, ErrorMessage = "Die Tel-Nr/Mail-Adresse ist zu lang"), MinLength(8, ErrorMessage = "Die Tel-Nr/Mail-Adresse ist zu kurz.")]
[Required(ErrorMessage = "Tel-Nr/Mail-Adresse fehlen.")]
public string PhoneMail { get; set; }
public bool SaveSettings { get; set; } = true;
Expand Down
5 changes: 4 additions & 1 deletion MeetUpPlanner/Client/BlazorTimer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ public void SetTimer(double interval)
}
public void DisableTimer()
{
_timer.Enabled = false;
if ( null != _timer )
{
_timer.Enabled = false;
}
}

public event Action OnElapsed;
Expand Down
1 change: 1 addition & 0 deletions MeetUpPlanner/Client/MeetUpPlanner.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BlazorDownloadFile" Version="2.0.0" />
<PackageReference Include="Blazored.LocalStorage" Version="3.0.0" />
<PackageReference Include="Blazored.TextEditor" Version="1.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.1" />
Expand Down
Loading

0 comments on commit b912577

Please sign in to comment.