Skip to content

Commit

Permalink
Merge pull request #25 from eurofurence/feature/lost-and-found
Browse files Browse the repository at this point in the history
Lost & Found First Version
  • Loading branch information
Pinselohrkater authored Jul 21, 2022
2 parents 0bd9fd3 + 8ba9c2e commit 2eaf47c
Show file tree
Hide file tree
Showing 16 changed files with 345 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
using Eurofurence.App.Domain.Model.Fursuits.CollectingGame;
using Eurofurence.App.Domain.Model.Images;
using Eurofurence.App.Domain.Model.Knowledge;
using Eurofurence.App.Domain.Model.LostAndFound;
using Eurofurence.App.Domain.Model.Maps;
using Eurofurence.App.Domain.Model.MongoDb.ArtShow;
using Eurofurence.App.Domain.Model.MongoDb.Fursuits;
using Eurofurence.App.Domain.Model.MongoDb.Fursuits.CollectingGame;
using Eurofurence.App.Domain.Model.MongoDb.LostAndFound;
using Eurofurence.App.Domain.Model.MongoDb.Repositories;
using Eurofurence.App.Domain.Model.MongoDb.Security;
using Eurofurence.App.Domain.Model.MongoDb.Telegram;
Expand Down Expand Up @@ -174,6 +176,7 @@ protected override void Load(ContainerBuilder builder)
Builders<AgentClosingResultRecord>.IndexKeys.Ascending(a => a.ImportHash))));

Register<TableRegistrationRepository, IEntityRepository<TableRegistrationRecord>, TableRegistrationRecord>(builder);
Register<LostAndFoundRepository, IEntityRepository<LostAndFoundRecord>, LostAndFoundRecord>(builder);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Eurofurence.App.Domain.Model.LostAndFound;
using Eurofurence.App.Domain.Model.MongoDb.Repositories;
using MongoDB.Driver;

namespace Eurofurence.App.Domain.Model.MongoDb.LostAndFound
{
public class LostAndFoundRepository : MongoDbEntityRepositoryBase<LostAndFoundRecord>
{
public LostAndFoundRepository(IMongoCollection<LostAndFoundRecord> collection)
: base(collection)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;

namespace Eurofurence.App.Domain.Model.LostAndFound
{
[DataContract]
public class LostAndFoundRecord : EntityBase
{
public enum LostAndFoundStatusEnum
{
Unknown,
Lost,
Found,
Returned
}

[Required]
[DataMember]
public int ExternalId { get; set; }

[DataMember]
public string ImageUrl { get; set; }

[DataMember]
public string Title { get; set; }

[DataMember]
public string Description { get; set; }

[DataMember]
public LostAndFoundStatusEnum Status { get; set; }

[DataMember]
public DateTime? LostDateTimeUtc { get; set; }
[DataMember]
public DateTime? FoundDateTimeUtc { get; set; }
[DataMember]
public DateTime? ReturnDateTimeUtc { get; set; }



}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Threading.Tasks;

namespace Eurofurence.App.Server.Services.Abstractions.Lassie
{
public interface ILassieApiClient
{
public Task<LostAndFoundResponse[]> QueryLostAndFoundDbAsync(string command = "lostandfound");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.Configuration;

namespace Eurofurence.App.Server.Services.Abstractions.Lassie
{
public class LassieConfiguration
{
public bool IsConfigured => !string.IsNullOrEmpty(ApiKey);
public string BaseApiUrl { get; set; }
public string ApiKey { get; set; }

public static LassieConfiguration FromConfiguration(IConfiguration configuration)
=> new LassieConfiguration
{
BaseApiUrl = configuration["lassie:baseApiUrl"],
ApiKey = configuration["lassie:apiKey"]
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Newtonsoft.Json;
using System;

namespace Eurofurence.App.Server.Services.Abstractions.Lassie
{
public class LostAndFoundResponse
{
[JsonProperty("id")]
public int Id { get; set; }

[JsonProperty("image")]
public string ImageUrl { get; set; }

[JsonProperty("title")]
public string Title { get; set; }

[JsonProperty("description")]
public string Description { get; set; }

[JsonProperty("status")]
public string Status { get; set; }

[JsonProperty("lost_timestamp")]
public DateTime? LostDateTimeLocal { get; set; }

[JsonProperty("found_timestamp")]
public DateTime? FoundDateTimeLocal { get; set; }

[JsonProperty("return_timestamp")]
public DateTime? ReturnDateTimeLocal { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Threading.Tasks;

namespace Eurofurence.App.Server.Services.Abstractions.LostAndFound
{
public interface ILostAndFoundLassieImporter
{
Task RunImportAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Eurofurence.App.Domain.Model.LostAndFound;

namespace Eurofurence.App.Server.Services.Abstractions.LostAndFound
{
public interface ILostAndFoundService :
IEntityServiceOperations<LostAndFoundRecord>,
IPatchOperationProcessor<LostAndFoundRecord>
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using Eurofurence.App.Server.Services.Abstractions.Fursuits;
using Eurofurence.App.Server.Services.Abstractions.Images;
using Eurofurence.App.Server.Services.Abstractions.Knowledge;
using Eurofurence.App.Server.Services.Abstractions.Lassie;
using Eurofurence.App.Server.Services.Abstractions.LostAndFound;
using Eurofurence.App.Server.Services.Abstractions.Maps;
using Eurofurence.App.Server.Services.Abstractions.PushNotifications;
using Eurofurence.App.Server.Services.Abstractions.Security;
Expand All @@ -23,6 +25,8 @@
using Eurofurence.App.Server.Services.Fursuits;
using Eurofurence.App.Server.Services.Images;
using Eurofurence.App.Server.Services.Knowledge;
using Eurofurence.App.Server.Services.Lassie;
using Eurofurence.App.Server.Services.LostAndFound;
using Eurofurence.App.Server.Services.Maps;
using Eurofurence.App.Server.Services.PushNotifications;
using Eurofurence.App.Server.Services.Security;
Expand Down Expand Up @@ -60,6 +64,7 @@ private void RegisterConfigurations(ContainerBuilder builder)
builder.RegisterInstance(TelegramConfiguration.FromConfiguration(_configuration));
builder.RegisterInstance(CollectionGameConfiguration.FromConfiguration(_configuration));
builder.RegisterInstance(ArtistAlleyConfiguration.FromConfiguration(_configuration));
builder.RegisterInstance(LassieConfiguration.FromConfiguration(_configuration));
}

private void RegisterServices(ContainerBuilder builder)
Expand All @@ -83,7 +88,10 @@ private void RegisterServices(ContainerBuilder builder)
builder.RegisterType<ItemActivityService>().As<IItemActivityService>();
builder.RegisterType<KnowledgeEntryService>().As<IKnowledgeEntryService>();
builder.RegisterType<KnowledgeGroupService>().As<IKnowledgeGroupService>();
builder.RegisterType<LassieApiClient>().As<ILassieApiClient>();
builder.RegisterType<LinkFragmentValidator>().As<ILinkFragmentValidator>();
builder.RegisterType<LostAndFoundService>().As<ILostAndFoundService>();
builder.RegisterType<LostAndFoundLassieImporter>().As<ILostAndFoundLassieImporter>();
builder.RegisterType<MapService>().As<IMapService>();
builder.RegisterType<PrivateMessageService>()
.As<IPrivateMessageService>()
Expand Down
44 changes: 44 additions & 0 deletions src/Eurofurence.App.Server.Services/Lassie/LassieApiClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Eurofurence.App.Server.Services.Abstractions.Lassie;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;

namespace Eurofurence.App.Server.Services.Lassie
{
public class LassieApiClient : ILassieApiClient
{
private class DataResponseWrapper<T>
{
public T[] Data { get; set; }
}

private LassieConfiguration _configuration;

public LassieApiClient(LassieConfiguration configuration)
{
_configuration = configuration;
}

public async Task<LostAndFoundResponse[]> QueryLostAndFoundDbAsync(string command = "lostandfound")
{
var outgoingQuery = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("apikey", _configuration.ApiKey),
new KeyValuePair<string, string>("request", "lostandfounddb"),
new KeyValuePair<string, string>("command", command)
};

using (var client = new HttpClient())
{
var response = await client.PostAsync(_configuration.BaseApiUrl, new FormUrlEncodedContent(outgoingQuery));
var content = await response.Content.ReadAsStringAsync();

var dataResponse = JsonConvert.DeserializeObject<DataResponseWrapper<LostAndFoundResponse>>(content,
new JsonSerializerSettings() { DateTimeZoneHandling = DateTimeZoneHandling.Local });

return dataResponse.Data;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Eurofurence.App.Common.DataDiffUtils;
using Eurofurence.App.Domain.Model.LostAndFound;
using Eurofurence.App.Server.Services.Abstractions.Lassie;
using Eurofurence.App.Server.Services.Abstractions.LostAndFound;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace Eurofurence.App.Server.Services.LostAndFound
{
public class LostAndFoundLassieImporter : ILostAndFoundLassieImporter
{
private ILostAndFoundService _lostAndFoundService;
private ILassieApiClient _lassieApiClient;

public LostAndFoundLassieImporter(
ILostAndFoundService lostAndFoundService,
ILassieApiClient lassieApiClient
)
{
_lostAndFoundService = lostAndFoundService;
_lassieApiClient = lassieApiClient;
}

public async Task RunImportAsync()
{
var existingRecords = await _lostAndFoundService.FindAllAsync();
var newRecords = await _lassieApiClient.QueryLostAndFoundDbAsync();

var patch = new PatchDefinition<LostAndFoundResponse, LostAndFoundRecord>((source, list) =>
list.SingleOrDefault(a => a.ExternalId == source.Id));

var statusConverter = new Func<string, LostAndFoundRecord.LostAndFoundStatusEnum>(input =>
{
switch(input.ToLowerInvariant())
{
case "l": return LostAndFoundRecord.LostAndFoundStatusEnum.Lost;
case "f": return LostAndFoundRecord.LostAndFoundStatusEnum.Found;
case "r": return LostAndFoundRecord.LostAndFoundStatusEnum.Returned;
default: return LostAndFoundRecord.LostAndFoundStatusEnum.Unknown;
}
});

patch
.Map(s => s.Id, t => t.ExternalId)
.Map(s => s.Title, t => t.Title)
.Map(s => s.Description, t => t.Description)
.Map(s => s.ImageUrl, t => t.ImageUrl)
.Map(s => statusConverter(s.Status), t => t.Status)
.Map(s => s.LostDateTimeLocal?.ToUniversalTime(), t => t.LostDateTimeUtc)
.Map(s => s.ReturnDateTimeLocal?.ToUniversalTime(), t => t.ReturnDateTimeUtc)
.Map(s => s.FoundDateTimeLocal?.ToUniversalTime(), t => t.FoundDateTimeUtc);

var patchResult = patch.Patch(newRecords, existingRecords);

await _lostAndFoundService.ApplyPatchOperationAsync(patchResult);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Eurofurence.App.Domain.Model.Abstractions;
using Eurofurence.App.Domain.Model.LostAndFound;
using Eurofurence.App.Server.Services.Abstractions;
using Eurofurence.App.Server.Services.Abstractions.LostAndFound;

namespace Eurofurence.App.Server.Services.LostAndFound
{
public class LostAndFoundService : EntityServiceBase<LostAndFoundRecord>, ILostAndFoundService
{
public LostAndFoundService(
IEntityRepository<LostAndFoundRecord> entityRepository,
IStorageServiceFactory storageServiceFactory
)
: base(entityRepository, storageServiceFactory)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Eurofurence.App.Domain.Model.LostAndFound;
using Eurofurence.App.Server.Services.Abstractions.LostAndFound;
using Eurofurence.App.Server.Services.Abstractions.Security;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Eurofurence.App.Server.Web.Controllers
{
[Route("Api/[controller]")]
public class LostAndFoundController : BaseController
{
private readonly ILostAndFoundService _lostAndFoundService;
private readonly IApiPrincipal _apiPrincipal;

public LostAndFoundController(
ILostAndFoundService lostAndFoundService,
IApiPrincipal apiPrincipal
)
{
_lostAndFoundService = lostAndFoundService;
_apiPrincipal = apiPrincipal;
}

[Authorize(Roles = "Attendee")]
[HttpGet("Items")]
public Task<IEnumerable<LostAndFoundRecord>> GetItemsAsync()
{
return _lostAndFoundService.FindAllAsync();
}
}
}
1 change: 1 addition & 0 deletions src/Eurofurence.App.Server.Web/Jobs/JobRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public JobRegistry(IConfiguration configuration)

Schedule<FlushPrivateMessageNotificationsJob>().ToRunEvery(1).Seconds();
Schedule<UpdateNewsJob>().ToRunNow().AndEvery(Convert.ToInt32(configuration["updateNews:secondsInterval"])).Seconds();
Schedule<UpdateLostAndFoundJob>().ToRunNow().AndEvery(60).Seconds();
}
}
}
Loading

0 comments on commit 2eaf47c

Please sign in to comment.