From 7c3c9c431dd6129d6148504851c31646e4b7559f Mon Sep 17 00:00:00 2001 From: lucas-mrq Date: Tue, 12 Mar 2024 15:23:01 +0100 Subject: [PATCH 001/120] Add Rooms, Planning & Schedule --- .../Mappers/PlanningProfile.cs | 18 +++++ .../Mappers/RoomProfile.cs | 18 +++++ .../Mappers/ScheduleProfile.cs | 18 +++++ .../Services/IPlanningService.cs | 15 ++++ .../Services/IRoomService.cs | 18 +++++ .../Services/IScheduleService.cs | 15 ++++ .../Models/RoomSearchInfo.cs | 10 +++ src/IoTHub.Portal.Client/Program.cs | 3 + .../Services/IPlanningClientService.cs | 14 ++++ .../Services/IRoomClientService.cs | 15 ++++ .../Services/IScheduleClientService.cs | 14 ++++ .../Services/PlanningClientService.cs | 36 +++++++++ .../Services/RoomClientService.cs | 40 ++++++++++ .../Services/ScheduleClientService.cs | 36 +++++++++ src/IoTHub.Portal.Domain/Entities/Planning.cs | 26 +++++++ src/IoTHub.Portal.Domain/Entities/Room.cs | 41 ++++++++++ src/IoTHub.Portal.Domain/Entities/Schedule.cs | 31 ++++++++ .../Repositories/IPlanningRepository.cs | 11 +++ .../Repositories/IRoomRepository.cs | 11 +++ .../Repositories/IScheduleRepository.cs | 11 +++ .../PortalDbContext.cs | 3 + .../Repositories/PlanningRepository.cs | 15 ++++ .../Repositories/RoomRepository.cs | 15 ++++ .../Repositories/ScheduleRepository.cs | 15 ++++ .../Services/PlanningService.cs | 58 ++++++++++++++ .../Services/RoomService.cs | 64 ++++++++++++++++ .../Services/ScheduleService.cs | 58 ++++++++++++++ .../Startup/IServiceCollectionExtension.cs | 8 +- .../Controllers/v1.0/PlanningsController.cs | 72 ++++++++++++++++++ .../Controllers/v1.0/RoomsController.cs | 75 +++++++++++++++++++ .../Controllers/v1.0/SchedulesController.cs | 72 ++++++++++++++++++ .../Models/v1.0/PlanningDto.cs | 47 ++++++++++++ .../Models/v1.0/RoomDto.cs | 32 ++++++++ .../Models/v1.0/ScheduleDto.cs | 37 +++++++++ 34 files changed, 970 insertions(+), 2 deletions(-) create mode 100644 src/IoTHub.Portal.Application/Mappers/PlanningProfile.cs create mode 100644 src/IoTHub.Portal.Application/Mappers/RoomProfile.cs create mode 100644 src/IoTHub.Portal.Application/Mappers/ScheduleProfile.cs create mode 100644 src/IoTHub.Portal.Application/Services/IPlanningService.cs create mode 100644 src/IoTHub.Portal.Application/Services/IRoomService.cs create mode 100644 src/IoTHub.Portal.Application/Services/IScheduleService.cs create mode 100644 src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs create mode 100644 src/IoTHub.Portal.Client/Services/IPlanningClientService.cs create mode 100644 src/IoTHub.Portal.Client/Services/IRoomClientService.cs create mode 100644 src/IoTHub.Portal.Client/Services/IScheduleClientService.cs create mode 100644 src/IoTHub.Portal.Client/Services/PlanningClientService.cs create mode 100644 src/IoTHub.Portal.Client/Services/RoomClientService.cs create mode 100644 src/IoTHub.Portal.Client/Services/ScheduleClientService.cs create mode 100644 src/IoTHub.Portal.Domain/Entities/Planning.cs create mode 100644 src/IoTHub.Portal.Domain/Entities/Room.cs create mode 100644 src/IoTHub.Portal.Domain/Entities/Schedule.cs create mode 100644 src/IoTHub.Portal.Domain/Repositories/IPlanningRepository.cs create mode 100644 src/IoTHub.Portal.Domain/Repositories/IRoomRepository.cs create mode 100644 src/IoTHub.Portal.Domain/Repositories/IScheduleRepository.cs create mode 100644 src/IoTHub.Portal.Infrastructure/Repositories/PlanningRepository.cs create mode 100644 src/IoTHub.Portal.Infrastructure/Repositories/RoomRepository.cs create mode 100644 src/IoTHub.Portal.Infrastructure/Repositories/ScheduleRepository.cs create mode 100644 src/IoTHub.Portal.Infrastructure/Services/PlanningService.cs create mode 100644 src/IoTHub.Portal.Infrastructure/Services/RoomService.cs create mode 100644 src/IoTHub.Portal.Infrastructure/Services/ScheduleService.cs create mode 100644 src/IoTHub.Portal.Server/Controllers/v1.0/PlanningsController.cs create mode 100644 src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs create mode 100644 src/IoTHub.Portal.Server/Controllers/v1.0/SchedulesController.cs create mode 100644 src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs create mode 100644 src/IoTHub.Portal.Shared/Models/v1.0/RoomDto.cs create mode 100644 src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs diff --git a/src/IoTHub.Portal.Application/Mappers/PlanningProfile.cs b/src/IoTHub.Portal.Application/Mappers/PlanningProfile.cs new file mode 100644 index 000000000..407304bc4 --- /dev/null +++ b/src/IoTHub.Portal.Application/Mappers/PlanningProfile.cs @@ -0,0 +1,18 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Mappers +{ + using AutoMapper; + using IoTHub.Portal.Domain.Entities; + using IoTHub.Portal.Shared.Models.v10; + + public class PlanningProfile : Profile + { + public PlanningProfile() + { + _ = CreateMap() + .ReverseMap(); + } + } +} diff --git a/src/IoTHub.Portal.Application/Mappers/RoomProfile.cs b/src/IoTHub.Portal.Application/Mappers/RoomProfile.cs new file mode 100644 index 000000000..879d5322f --- /dev/null +++ b/src/IoTHub.Portal.Application/Mappers/RoomProfile.cs @@ -0,0 +1,18 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Mappers +{ + using AutoMapper; + using IoTHub.Portal.Domain.Entities; + using IoTHub.Portal.Shared.Models.v10; + + public class RoomProfile : Profile + { + public RoomProfile() + { + _ = CreateMap() + .ReverseMap(); + } + } +} diff --git a/src/IoTHub.Portal.Application/Mappers/ScheduleProfile.cs b/src/IoTHub.Portal.Application/Mappers/ScheduleProfile.cs new file mode 100644 index 000000000..3f327d35f --- /dev/null +++ b/src/IoTHub.Portal.Application/Mappers/ScheduleProfile.cs @@ -0,0 +1,18 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Mappers +{ + using AutoMapper; + using IoTHub.Portal.Domain.Entities; + using IoTHub.Portal.Shared.Models.v10; + + public class ScheduleProfile : Profile + { + public ScheduleProfile() + { + _ = CreateMap() + .ReverseMap(); + } + } +} diff --git a/src/IoTHub.Portal.Application/Services/IPlanningService.cs b/src/IoTHub.Portal.Application/Services/IPlanningService.cs new file mode 100644 index 000000000..88b6f2d11 --- /dev/null +++ b/src/IoTHub.Portal.Application/Services/IPlanningService.cs @@ -0,0 +1,15 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Application.Services +{ + using System.Threading.Tasks; + using IoTHub.Portal.Domain.Entities; + using IoTHub.Portal.Shared.Models.v10; + + public interface IPlanningService + { + Task CreatePlanning(PlanningDto planning); + Task GetPlanning(string planningId); + } +} diff --git a/src/IoTHub.Portal.Application/Services/IRoomService.cs b/src/IoTHub.Portal.Application/Services/IRoomService.cs new file mode 100644 index 000000000..d5b7ab9e3 --- /dev/null +++ b/src/IoTHub.Portal.Application/Services/IRoomService.cs @@ -0,0 +1,18 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Application.Services +{ + using System.Threading.Tasks; + using IoTHub.Portal.Domain.Entities; + using IoTHub.Portal.Shared.Models.v1._0; + using IoTHub.Portal.Shared.Models.v10; + using IoTHub.Portal.Shared.Models.v10.Filters; + + public interface IRoomService + { + Task CreateRoom(RoomDto room); + Task> GetRooms(RoomFilter roomFilter); + Task GetRoom(string roomId); + } +} diff --git a/src/IoTHub.Portal.Application/Services/IScheduleService.cs b/src/IoTHub.Portal.Application/Services/IScheduleService.cs new file mode 100644 index 000000000..cd2a6c54f --- /dev/null +++ b/src/IoTHub.Portal.Application/Services/IScheduleService.cs @@ -0,0 +1,15 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Application.Services +{ + using System.Threading.Tasks; + using IoTHub.Portal.Domain.Entities; + using IoTHub.Portal.Shared.Models.v10; + + public interface IScheduleService + { + Task CreateSchedule(ScheduleDto schedule); + Task GetSchedule(string scheduleId); + } +} diff --git a/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs b/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs new file mode 100644 index 000000000..cee031f63 --- /dev/null +++ b/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs @@ -0,0 +1,10 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Models +{ + public class RoomSearchInfo + { + public string? SearchText { get; set; } + } +} diff --git a/src/IoTHub.Portal.Client/Program.cs b/src/IoTHub.Portal.Client/Program.cs index 8a9fed400..2ba4cce9e 100644 --- a/src/IoTHub.Portal.Client/Program.cs +++ b/src/IoTHub.Portal.Client/Program.cs @@ -84,6 +84,9 @@ _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); +_ = builder.Services.AddScoped(); +_ = builder.Services.AddScoped(); +_ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); diff --git a/src/IoTHub.Portal.Client/Services/IPlanningClientService.cs b/src/IoTHub.Portal.Client/Services/IPlanningClientService.cs new file mode 100644 index 000000000..199e2ff2d --- /dev/null +++ b/src/IoTHub.Portal.Client/Services/IPlanningClientService.cs @@ -0,0 +1,14 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Services +{ + using System.Threading.Tasks; + using IoTHub.Portal.Shared.Models.v10; + + public interface IPlanningClientService + { + Task CreatePlanning(PlanningDto planning); + Task GetPlanning(string planningId); + } +} diff --git a/src/IoTHub.Portal.Client/Services/IRoomClientService.cs b/src/IoTHub.Portal.Client/Services/IRoomClientService.cs new file mode 100644 index 000000000..6d6e8e1c2 --- /dev/null +++ b/src/IoTHub.Portal.Client/Services/IRoomClientService.cs @@ -0,0 +1,15 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Services +{ + using System.Threading.Tasks; + using IoTHub.Portal.Shared.Models.v10; + using IoTHub.Portal.Shared.Models.v10.Filters; + + public interface IRoomClientService + { + Task CreateRoom(RoomDto room); + Task GetRoom(string roomId); + } +} diff --git a/src/IoTHub.Portal.Client/Services/IScheduleClientService.cs b/src/IoTHub.Portal.Client/Services/IScheduleClientService.cs new file mode 100644 index 000000000..5fb8a886b --- /dev/null +++ b/src/IoTHub.Portal.Client/Services/IScheduleClientService.cs @@ -0,0 +1,14 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Services +{ + using System.Threading.Tasks; + using IoTHub.Portal.Shared.Models.v10; + + public interface IScheduleClientService + { + Task CreateSchedule(ScheduleDto schedule); + Task GetSchedule(string scheduleId); + } +} diff --git a/src/IoTHub.Portal.Client/Services/PlanningClientService.cs b/src/IoTHub.Portal.Client/Services/PlanningClientService.cs new file mode 100644 index 000000000..53f49baa4 --- /dev/null +++ b/src/IoTHub.Portal.Client/Services/PlanningClientService.cs @@ -0,0 +1,36 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Services +{ + using System.Net.Http; + using System.Net.Http.Json; + using System.Threading.Tasks; + using IoTHub.Portal.Shared.Models.v10; + + public class PlanningClientService : IPlanningClientService + { + private readonly HttpClient http; + + public PlanningClientService(HttpClient http) + { + this.http = http; + } + + public async Task CreatePlanning(PlanningDto planning) + { + var response = await this.http.PostAsJsonAsync("api/planning", planning); + + //Retrieve Device ID + var responseJson = await response.Content.ReadAsStringAsync(); + var updatedPlanning = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); + + return updatedPlanning.Id.ToString(); + } + + public Task GetPlanning(string planningId) + { + return this.http.GetFromJsonAsync($"api/planning/{planningId}")!; + } + } +} diff --git a/src/IoTHub.Portal.Client/Services/RoomClientService.cs b/src/IoTHub.Portal.Client/Services/RoomClientService.cs new file mode 100644 index 000000000..4ead1fc46 --- /dev/null +++ b/src/IoTHub.Portal.Client/Services/RoomClientService.cs @@ -0,0 +1,40 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Services +{ + using System.Net.Http; + using System.Net.Http.Json; + using System.Threading.Tasks; + using IoTHub.Portal.Shared.Models.v10; + using IoTHub.Portal.Shared.Models.v10.Filters; + using Microsoft.AspNetCore.WebUtilities; + + public class RoomClientService : IRoomClientService + { + private readonly HttpClient http; + private readonly string apiUrlBase = "api/building"; + + public RoomClientService(HttpClient http) + { + this.http = http; + } + + public async Task CreateRoom(RoomDto room) + { + var response = await this.http.PostAsJsonAsync("api/building", room); + + //Retrieve Room ID + var responseJson = await response.Content.ReadAsStringAsync(); + var updatedRoom = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); + + return updatedRoom.Id.ToString(); + } + + + public Task GetRoom(string roomId) + { + return this.http.GetFromJsonAsync($"api/building/{roomId}")!; + } + } +} diff --git a/src/IoTHub.Portal.Client/Services/ScheduleClientService.cs b/src/IoTHub.Portal.Client/Services/ScheduleClientService.cs new file mode 100644 index 000000000..8a6d9fa9f --- /dev/null +++ b/src/IoTHub.Portal.Client/Services/ScheduleClientService.cs @@ -0,0 +1,36 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Services +{ + using System.Net.Http; + using System.Net.Http.Json; + using System.Threading.Tasks; + using IoTHub.Portal.Shared.Models.v10; + + public class ScheduleClientService : IScheduleClientService + { + private readonly HttpClient http; + + public ScheduleClientService(HttpClient http) + { + this.http = http; + } + + public async Task CreateSchedule(ScheduleDto schedule) + { + var response = await this.http.PostAsJsonAsync("api/schedule", schedule); + + //Retrieve Device ID + var responseJson = await response.Content.ReadAsStringAsync(); + var updatedSchedule = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); + + return updatedSchedule.Id.ToString(); + } + + public Task GetSchedule(string scheduleId) + { + return this.http.GetFromJsonAsync($"api/schedule/{scheduleId}")!; + } + } +} diff --git a/src/IoTHub.Portal.Domain/Entities/Planning.cs b/src/IoTHub.Portal.Domain/Entities/Planning.cs new file mode 100644 index 000000000..be6ae97ba --- /dev/null +++ b/src/IoTHub.Portal.Domain/Entities/Planning.cs @@ -0,0 +1,26 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Domain.Entities +{ + using IoTHub.Portal.Domain.Base; + + public class Room : EntityBase + { + /// + /// The room friendly name. + /// + public string Name { get; set; } = default!; + + /// + /// Where room is. + /// + public string Father { get; set; } = default!; + + /// + /// The planning associat with the room. + /// + public string Planning { get; set; } = default!; + + } +} diff --git a/src/IoTHub.Portal.Domain/Entities/Room.cs b/src/IoTHub.Portal.Domain/Entities/Room.cs new file mode 100644 index 000000000..d9ede51f5 --- /dev/null +++ b/src/IoTHub.Portal.Domain/Entities/Room.cs @@ -0,0 +1,41 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Domain.Entities +{ + using IoTHub.Portal.Domain.Base; + + public class Planning : EntityBase + { + /// + /// The planning friendly name. + /// + public string Name { get; set; } = default!; + + /// + /// Where planning start. + /// + public int Start { get; set; } = default!; + + /// + /// Where planning end. + /// + public int End { get; set; } = default!; + + /// + /// How much it repeat. + /// + public int Frequency { get; set; } = default!; + + /// + /// When planning is used + /// + public string DayOff { get; set; } = default!; + + /// + /// Day off temperature. + /// + public int TemperatureOff { get; set; } = default!; + + } +} diff --git a/src/IoTHub.Portal.Domain/Entities/Schedule.cs b/src/IoTHub.Portal.Domain/Entities/Schedule.cs new file mode 100644 index 000000000..5ca297793 --- /dev/null +++ b/src/IoTHub.Portal.Domain/Entities/Schedule.cs @@ -0,0 +1,31 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Domain.Entities +{ + using IoTHub.Portal.Domain.Base; + + public class Schedule : EntityBase + { + /// + /// The schedule friendly name. + /// + public int Start { get; set; } = default!; + + /// + /// Where schedule is. + /// + public int End { get; set; } = default!; + + /// + /// The planning associat with the schedule. + /// + public int Temperature { get; set; } = default!; + + /// + /// The planning associat with the schedule. + /// + public string Planning { get; set; } = default!; + + } +} diff --git a/src/IoTHub.Portal.Domain/Repositories/IPlanningRepository.cs b/src/IoTHub.Portal.Domain/Repositories/IPlanningRepository.cs new file mode 100644 index 000000000..8bab55df1 --- /dev/null +++ b/src/IoTHub.Portal.Domain/Repositories/IPlanningRepository.cs @@ -0,0 +1,11 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Domain.Repositories +{ + using Entities; + + public interface IPlanningRepository : IRepository + { + } +} diff --git a/src/IoTHub.Portal.Domain/Repositories/IRoomRepository.cs b/src/IoTHub.Portal.Domain/Repositories/IRoomRepository.cs new file mode 100644 index 000000000..1cf914856 --- /dev/null +++ b/src/IoTHub.Portal.Domain/Repositories/IRoomRepository.cs @@ -0,0 +1,11 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Domain.Repositories +{ + using Entities; + + public interface IRoomRepository : IRepository + { + } +} diff --git a/src/IoTHub.Portal.Domain/Repositories/IScheduleRepository.cs b/src/IoTHub.Portal.Domain/Repositories/IScheduleRepository.cs new file mode 100644 index 000000000..c58b5d927 --- /dev/null +++ b/src/IoTHub.Portal.Domain/Repositories/IScheduleRepository.cs @@ -0,0 +1,11 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Domain.Repositories +{ + using Entities; + + public interface IScheduleRepository : IRepository + { + } +} diff --git a/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs b/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs index 13b3593c6..2d2207885 100644 --- a/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs +++ b/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs @@ -12,6 +12,9 @@ public class PortalDbContext : DbContext, IDataProtectionKeyContext { public DbSet DeviceModelProperties { get; set; } public DbSet DeviceTags { get; set; } + public DbSet Rooms { get; set; } + public DbSet Plannings { get; set; } + public DbSet Schedules { get; set; } public DbSet DeviceModelCommands { get; set; } public DbSet DeviceModels { get; set; } public DbSet Devices { get; set; } diff --git a/src/IoTHub.Portal.Infrastructure/Repositories/PlanningRepository.cs b/src/IoTHub.Portal.Infrastructure/Repositories/PlanningRepository.cs new file mode 100644 index 000000000..b6910edf7 --- /dev/null +++ b/src/IoTHub.Portal.Infrastructure/Repositories/PlanningRepository.cs @@ -0,0 +1,15 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Repositories +{ + using IoTHub.Portal.Domain.Repositories; + using Domain.Entities; + + public class RoomRepository : GenericRepository, IRoomRepository + { + public RoomRepository(PortalDbContext context) : base(context) + { + } + } +} diff --git a/src/IoTHub.Portal.Infrastructure/Repositories/RoomRepository.cs b/src/IoTHub.Portal.Infrastructure/Repositories/RoomRepository.cs new file mode 100644 index 000000000..26776da2e --- /dev/null +++ b/src/IoTHub.Portal.Infrastructure/Repositories/RoomRepository.cs @@ -0,0 +1,15 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Repositories +{ + using IoTHub.Portal.Domain.Repositories; + using Domain.Entities; + + public class PlanningRepository : GenericRepository, IPlanningRepository + { + public PlanningRepository(PortalDbContext context) : base(context) + { + } + } +} diff --git a/src/IoTHub.Portal.Infrastructure/Repositories/ScheduleRepository.cs b/src/IoTHub.Portal.Infrastructure/Repositories/ScheduleRepository.cs new file mode 100644 index 000000000..3208f77cd --- /dev/null +++ b/src/IoTHub.Portal.Infrastructure/Repositories/ScheduleRepository.cs @@ -0,0 +1,15 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Repositories +{ + using IoTHub.Portal.Domain.Repositories; + using Domain.Entities; + + public class ScheduleRepository : GenericRepository, IScheduleRepository + { + public ScheduleRepository(PortalDbContext context) : base(context) + { + } + } +} diff --git a/src/IoTHub.Portal.Infrastructure/Services/PlanningService.cs b/src/IoTHub.Portal.Infrastructure/Services/PlanningService.cs new file mode 100644 index 000000000..8d82bd2a1 --- /dev/null +++ b/src/IoTHub.Portal.Infrastructure/Services/PlanningService.cs @@ -0,0 +1,58 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Services +{ + using System.Threading.Tasks; + using AutoMapper; + using IoTHub.Portal.Domain.Entities; + using Domain; + using Domain.Repositories; + using IoTHub.Portal.Application.Services; + using IoTHub.Portal.Shared.Models.v10; + using IoTHub.Portal.Domain.Exceptions; + + public class PlanningService : IPlanningService + { + private readonly IMapper mapper; + private readonly IUnitOfWork unitOfWork; + private readonly IPlanningRepository planningRepository; + + public PlanningService(IMapper mapper, + IUnitOfWork unitOfWork, + IPlanningRepository planningRepository) + { + this.mapper = mapper; + this.unitOfWork = unitOfWork; + this.planningRepository = planningRepository; + } + public async Task CreatePlanning(PlanningDto planning) + { + var planningEntity = this.mapper.Map(planning); + + await this.planningRepository.InsertAsync(planningEntity); + await this.unitOfWork.SaveAsync(); + + return planning; + } + + /// + /// Get planning. + /// + /// planning id. + /// Planning object. + public async Task GetPlanning(string planningId) + { + var planningEntity = await this.planningRepository.GetByIdAsync(planningId); + + if (planningEntity is null) + { + throw new ResourceNotFoundException($"The planning with id {planningId} doesn't exist"); + } + + var planning = this.mapper.Map(planningEntity); + + return planning; + } + } +} diff --git a/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs b/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs new file mode 100644 index 000000000..6b6bc89a8 --- /dev/null +++ b/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs @@ -0,0 +1,64 @@ +// Copyright(c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Services +{ + using System.Threading.Tasks; + using AutoMapper; + using IoTHub.Portal.Domain.Entities; + using Domain; + using Domain.Repositories; + using IoTHub.Portal.Application.Services; + using IoTHub.Portal.Shared.Models.v10; + using IoTHub.Portal.Domain.Exceptions; + using IoTHub.Portal.Infrastructure.Repositories; + using IoTHub.Portal.Shared.Models.v1._0; + using IoTHub.Portal.Shared.Models.v10.Filters; + using System.Linq.Expressions; + + public class RoomService : IRoomService + { + private readonly IMapper mapper; + private readonly IUnitOfWork unitOfWork; + private readonly IRoomRepository roomRepository; + + public RoomService(IMapper mapper, + IUnitOfWork unitOfWork, + IRoomRepository roomRepository) + { + this.mapper = mapper; + this.unitOfWork = unitOfWork; + this.roomRepository = roomRepository; + } + + public async Task CreateRoom(RoomDto room) + { + var roomEntity = this.mapper.Map(room); + + await this.roomRepository.InsertAsync(roomEntity); + await this.unitOfWork.SaveAsync(); + + return room; + } + + + /// + /// Get room. + /// + /// room id. + /// Room object. + public async Task GetRoom(string roomId) + { + var roomEntity = await this.roomRepository.GetByIdAsync(roomId); + + if (roomEntity is null) + { + throw new ResourceNotFoundException($"The room with id {roomId} doesn't exist"); + } + + var room = this.mapper.Map(roomEntity); + + return room; + } + } +} diff --git a/src/IoTHub.Portal.Infrastructure/Services/ScheduleService.cs b/src/IoTHub.Portal.Infrastructure/Services/ScheduleService.cs new file mode 100644 index 000000000..7d4719f57 --- /dev/null +++ b/src/IoTHub.Portal.Infrastructure/Services/ScheduleService.cs @@ -0,0 +1,58 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Services +{ + using System.Threading.Tasks; + using AutoMapper; + using IoTHub.Portal.Domain.Entities; + using Domain; + using Domain.Repositories; + using IoTHub.Portal.Application.Services; + using IoTHub.Portal.Shared.Models.v10; + using IoTHub.Portal.Domain.Exceptions; + + public class ScheduleService : IScheduleService + { + private readonly IMapper mapper; + private readonly IUnitOfWork unitOfWork; + private readonly IScheduleRepository scheduleRepository; + + public ScheduleService(IMapper mapper, + IUnitOfWork unitOfWork, + IScheduleRepository scheduleRepository) + { + this.mapper = mapper; + this.unitOfWork = unitOfWork; + this.scheduleRepository = scheduleRepository; + } + public async Task CreateSchedule(ScheduleDto schedule) + { + var scheduleEntity = this.mapper.Map(schedule); + + await this.scheduleRepository.InsertAsync(scheduleEntity); + await this.unitOfWork.SaveAsync(); + + return schedule; + } + + /// + /// Get schedule. + /// + /// schedule id. + /// Schedule object. + public async Task GetSchedule(string scheduleId) + { + var scheduleEntity = await this.scheduleRepository.GetByIdAsync(scheduleId); + + if (scheduleEntity is null) + { + throw new ResourceNotFoundException($"The schedule with id {scheduleId} doesn't exist"); + } + + var schedule = this.mapper.Map(scheduleEntity); + + return schedule; + } + } +} diff --git a/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs b/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs index 9a2b4102c..6e40d30bb 100644 --- a/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs +++ b/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs @@ -11,8 +11,6 @@ namespace IoTHub.Portal.Infrastructure.Startup using IoTHub.Portal.Infrastructure.Repositories; using IoTHub.Portal.Infrastructure.Services; using IoTHub.Portal.Infrastructure.ServicesHealthCheck; - using IoTHub.Portal.Models.v10.LoRaWAN; - using IoTHub.Portal.Models.v10; using IoTHub.Portal.Shared.Constants; using EntityFramework.Exceptions.PostgreSQL; using Microsoft.EntityFrameworkCore; @@ -105,6 +103,9 @@ private static IServiceCollection ConfigureRepositories(this IServiceCollection .AddScoped() .AddScoped() .AddScoped() + .AddScoped() + .AddScoped() + .AddScoped() .AddScoped() .AddScoped(); } @@ -115,6 +116,9 @@ private static IServiceCollection ConfigureServices(this IServiceCollection serv .AddTransient() .AddTransient() .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() .AddTransient(); } } diff --git a/src/IoTHub.Portal.Server/Controllers/v1.0/PlanningsController.cs b/src/IoTHub.Portal.Server/Controllers/v1.0/PlanningsController.cs new file mode 100644 index 000000000..acb3a70b2 --- /dev/null +++ b/src/IoTHub.Portal.Server/Controllers/v1.0/PlanningsController.cs @@ -0,0 +1,72 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Server.Controllers.V10 +{ + using System; + using System.Threading.Tasks; + using IoTHub.Portal.Application.Services; + using Microsoft.AspNetCore.Authorization; + using Microsoft.AspNetCore.Http; + using Microsoft.AspNetCore.Mvc; + using Hellang.Middleware.ProblemDetails; + using IoTHub.Portal.Shared.Models.v10; + using Microsoft.Azure.Devices.Common.Exceptions; + + [Authorize] + [ApiController] + [ApiVersion("1.0")] + [Route("api/planning")] + [ApiExplorerSettings(GroupName = "IoT Building")] + public class PlanningsController : ControllerBase + { + private readonly IPlanningService planningService; + + public PlanningsController(IPlanningService planningService) + { + this.planningService = planningService; + } + + /// + /// Creates the planning. + /// + /// The planning. + [HttpPost(Name = "POST Create planning")] + public async Task CreatePlanningAsync(PlanningDto planning) + { + ArgumentNullException.ThrowIfNull(planning, nameof(planning)); + + if (!ModelState.IsValid) + { + var validation = new ValidationProblemDetails(ModelState) + { + Status = StatusCodes.Status422UnprocessableEntity + }; + + throw new ProblemDetailsException(validation); + } + + _ = await this.planningService.CreatePlanning(planning); + + return Ok(planning); + } + + /// + /// Gets the specified Planning. + /// + /// The Planning identifier. + [HttpGet("{PlanningId}", Name = "GET Planning")] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PlanningDto))] + public async Task GetPlanning(string PlanningId) + { + try + { + return Ok(await this.planningService.GetPlanning(PlanningId)); + } + catch (DeviceNotFoundException e) + { + return StatusCode(StatusCodes.Status404NotFound, e.Message); + } + } + } +} diff --git a/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs b/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs new file mode 100644 index 000000000..73f6a3437 --- /dev/null +++ b/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs @@ -0,0 +1,75 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Server.Controllers.V10 +{ + using System; + using System.Threading.Tasks; + using IoTHub.Portal.Application.Services; + using Microsoft.AspNetCore.Authorization; + using Microsoft.AspNetCore.Http; + using Microsoft.AspNetCore.Mvc; + using Hellang.Middleware.ProblemDetails; + using IoTHub.Portal.Shared.Models.v10; + using Microsoft.Azure.Devices.Common.Exceptions; + using IoTHub.Portal.Shared.Models.v10.Filters; + using Microsoft.AspNetCore.Mvc.Routing; + + [Authorize] + [ApiController] + [ApiVersion("1.0")] + [Route("api/building")] + [ApiExplorerSettings(GroupName = "IoT Building")] + public class RoomsController : ControllerBase + { + private readonly IRoomService roomService; + + public RoomsController(IRoomService roomService) + { + this.roomService = roomService; + } + + /// + /// Creates the room. + /// + /// The room. + [HttpPost(Name = "POST Create room")] + public async Task CreateRoomAsync(RoomDto room) + { + ArgumentNullException.ThrowIfNull(room, nameof(room)); + + if (!ModelState.IsValid) + { + var validation = new ValidationProblemDetails(ModelState) + { + Status = StatusCodes.Status422UnprocessableEntity + }; + + throw new ProblemDetailsException(validation); + } + + _ = await this.roomService.CreateRoom(room); + + return Ok(room); + } + + + /// + /// Gets the specified room. + /// + /// The room identifier. + [HttpGet("{roomId}", Name = "GET Room")] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RoomDto))] + public async Task GetRoom(string roomId) + { + try + { + return Ok(await this.roomService.GetRoom(roomId)); + } + catch (DeviceNotFoundException e) + { + return StatusCode(StatusCodes.Status404NotFound, e.Message); + } + } + } +} diff --git a/src/IoTHub.Portal.Server/Controllers/v1.0/SchedulesController.cs b/src/IoTHub.Portal.Server/Controllers/v1.0/SchedulesController.cs new file mode 100644 index 000000000..908a473b9 --- /dev/null +++ b/src/IoTHub.Portal.Server/Controllers/v1.0/SchedulesController.cs @@ -0,0 +1,72 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Server.Controllers.V10 +{ + using System; + using System.Threading.Tasks; + using IoTHub.Portal.Application.Services; + using Microsoft.AspNetCore.Authorization; + using Microsoft.AspNetCore.Http; + using Microsoft.AspNetCore.Mvc; + using Hellang.Middleware.ProblemDetails; + using IoTHub.Portal.Shared.Models.v10; + using Microsoft.Azure.Devices.Common.Exceptions; + + [Authorize] + [ApiController] + [ApiVersion("1.0")] + [Route("api/schedule")] + [ApiExplorerSettings(GroupName = "IoT Building")] + public class SchedulesController : ControllerBase + { + private readonly IScheduleService scheduleService; + + public SchedulesController(IScheduleService scheduleService) + { + this.scheduleService = scheduleService; + } + + /// + /// Creates the schedule. + /// + /// The schedule. + [HttpPost(Name = "POST Create schedule")] + public async Task CreateScheduleAsync(ScheduleDto schedule) + { + ArgumentNullException.ThrowIfNull(schedule, nameof(schedule)); + + if (!ModelState.IsValid) + { + var validation = new ValidationProblemDetails(ModelState) + { + Status = StatusCodes.Status422UnprocessableEntity + }; + + throw new ProblemDetailsException(validation); + } + + _ = await this.scheduleService.CreateSchedule(schedule); + + return Ok(schedule); + } + + /// + /// Gets the specified schedule. + /// + /// The schedule identifier. + [HttpGet("{scheduleId}", Name = "GET Schedule")] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ScheduleDto))] + public async Task GetSchedule(string scheduleId) + { + try + { + return Ok(await this.scheduleService.GetSchedule(scheduleId)); + } + catch (DeviceNotFoundException e) + { + return StatusCode(StatusCodes.Status404NotFound, e.Message); + } + } + } +} diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs new file mode 100644 index 000000000..076cbea36 --- /dev/null +++ b/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs @@ -0,0 +1,47 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Shared.Models.v10 +{ + using System; + + //using System.ComponentModel.DataAnnotations; + + public class PlanningDto + { + /// + /// The room auto ID. + /// + public string Id { get; set; } = Guid.NewGuid().ToString(); + + /// + /// The planning friendly name. + /// + public string Name { get; set; } = default!; + + /// + /// Where planning start. + /// + public int Start { get; set; } = default!; + + /// + /// Where planning end. + /// + public int End { get; set; } = default!; + + /// + /// How much it repeat. + /// + public int Frequency { get; set; } = default!; + + /// + /// When planning is used + /// + public string DayOff { get; set; } = default!; + + /// + /// Day off temperature. + /// + public int TemperatureOff { get; set; } = default!; + } +} diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/RoomDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/RoomDto.cs new file mode 100644 index 000000000..a66562e5b --- /dev/null +++ b/src/IoTHub.Portal.Shared/Models/v1.0/RoomDto.cs @@ -0,0 +1,32 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Shared.Models.v10 +{ + using System; + + //using System.ComponentModel.DataAnnotations; + + public class RoomDto + { + /// + /// The room auto ID. + /// + public string Id { get; set; } = Guid.NewGuid().ToString(); + + /// + /// The room friendly name. + /// + public string Name { get; set; } = default!; + + /// + /// Where room is. + /// + public string Father { get; set; } = default!; + + /// + /// The planning associat with the room. + /// + public string Planning { get; set; } = default!; + } +} diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs new file mode 100644 index 000000000..314d5d0a0 --- /dev/null +++ b/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs @@ -0,0 +1,37 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Shared.Models.v10 +{ + using System; + + //using System.ComponentModel.DataAnnotations; + + public class ScheduleDto + { + /// + /// The room auto ID. + /// + public string Id { get; set; } = Guid.NewGuid().ToString(); + + /// + /// The schedule friendly name. + /// + public int Start { get; set; } = default!; + + /// + /// Where schedule is. + /// + public int End { get; set; } = default!; + + /// + /// The planning associat with the schedule. + /// + public int Temperature { get; set; } = default!; + + /// + /// The planning associat with the schedule. + /// + public string Planning { get; set; } = default!; + } +} From f7d48b4b93a26b0a9236a00f863a4bbde85f50ea Mon Sep 17 00:00:00 2001 From: lucas-mrq Date: Wed, 13 Mar 2024 11:41:46 +0100 Subject: [PATCH 002/120] Add GetLists, Update and Post methods --- .../Services/IPlanningService.cs | 3 + .../Services/IRoomService.cs | 6 +- .../Services/IScheduleService.cs | 3 + .../Models/RoomSearchInfo.cs | 10 --- .../Services/IPlanningClientService.cs | 3 + .../Services/IRoomClientService.cs | 4 +- .../Services/IScheduleClientService.cs | 3 + .../Services/PlanningClientService.cs | 26 +++++-- .../Services/RoomClientService.cs | 20 ++++-- .../Services/ScheduleClientService.cs | 22 +++++- .../Services/PlanningService.cs | 69 ++++++++++++++++++- .../Services/RoomService.cs | 67 +++++++++++++++++- .../Services/ScheduleService.cs | 69 ++++++++++++++++++- .../Controllers/v1.0/PlanningsController.cs | 53 ++++++++++++-- .../Controllers/v1.0/RoomsController.cs | 42 ++++++++++- .../Controllers/v1.0/SchedulesController.cs | 43 +++++++++++- 16 files changed, 403 insertions(+), 40 deletions(-) delete mode 100644 src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs diff --git a/src/IoTHub.Portal.Application/Services/IPlanningService.cs b/src/IoTHub.Portal.Application/Services/IPlanningService.cs index 88b6f2d11..ebdaeccf5 100644 --- a/src/IoTHub.Portal.Application/Services/IPlanningService.cs +++ b/src/IoTHub.Portal.Application/Services/IPlanningService.cs @@ -10,6 +10,9 @@ namespace IoTHub.Portal.Application.Services public interface IPlanningService { Task CreatePlanning(PlanningDto planning); + Task UpdatePlanning(PlanningDto planning); + Task DeletePlanning(string planningId); Task GetPlanning(string planningId); + Task> GetPlannings(); } } diff --git a/src/IoTHub.Portal.Application/Services/IRoomService.cs b/src/IoTHub.Portal.Application/Services/IRoomService.cs index d5b7ab9e3..86ee0ed56 100644 --- a/src/IoTHub.Portal.Application/Services/IRoomService.cs +++ b/src/IoTHub.Portal.Application/Services/IRoomService.cs @@ -5,14 +5,14 @@ namespace IoTHub.Portal.Application.Services { using System.Threading.Tasks; using IoTHub.Portal.Domain.Entities; - using IoTHub.Portal.Shared.Models.v1._0; using IoTHub.Portal.Shared.Models.v10; - using IoTHub.Portal.Shared.Models.v10.Filters; public interface IRoomService { Task CreateRoom(RoomDto room); - Task> GetRooms(RoomFilter roomFilter); + Task UpdateRoom(RoomDto room); + Task DeleteRoom(string roomId); Task GetRoom(string roomId); + Task> GetRooms(); } } diff --git a/src/IoTHub.Portal.Application/Services/IScheduleService.cs b/src/IoTHub.Portal.Application/Services/IScheduleService.cs index cd2a6c54f..c2cbaf6c6 100644 --- a/src/IoTHub.Portal.Application/Services/IScheduleService.cs +++ b/src/IoTHub.Portal.Application/Services/IScheduleService.cs @@ -10,6 +10,9 @@ namespace IoTHub.Portal.Application.Services public interface IScheduleService { Task CreateSchedule(ScheduleDto schedule); + Task UpdateSchedule(ScheduleDto schedule); + Task DeleteSchedule(string scheduleId); Task GetSchedule(string scheduleId); + Task> GetSchedules(); } } diff --git a/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs b/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs deleted file mode 100644 index cee031f63..000000000 --- a/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace IoTHub.Portal.Client.Models -{ - public class RoomSearchInfo - { - public string? SearchText { get; set; } - } -} diff --git a/src/IoTHub.Portal.Client/Services/IPlanningClientService.cs b/src/IoTHub.Portal.Client/Services/IPlanningClientService.cs index 199e2ff2d..84f152474 100644 --- a/src/IoTHub.Portal.Client/Services/IPlanningClientService.cs +++ b/src/IoTHub.Portal.Client/Services/IPlanningClientService.cs @@ -9,6 +9,9 @@ namespace IoTHub.Portal.Client.Services public interface IPlanningClientService { Task CreatePlanning(PlanningDto planning); + Task UpdatePlanning(PlanningDto planning); + Task DeletePlanning(string modelId); Task GetPlanning(string planningId); + Task> GetPlannings(); } } diff --git a/src/IoTHub.Portal.Client/Services/IRoomClientService.cs b/src/IoTHub.Portal.Client/Services/IRoomClientService.cs index 6d6e8e1c2..084c53dcc 100644 --- a/src/IoTHub.Portal.Client/Services/IRoomClientService.cs +++ b/src/IoTHub.Portal.Client/Services/IRoomClientService.cs @@ -5,11 +5,13 @@ namespace IoTHub.Portal.Client.Services { using System.Threading.Tasks; using IoTHub.Portal.Shared.Models.v10; - using IoTHub.Portal.Shared.Models.v10.Filters; public interface IRoomClientService { Task CreateRoom(RoomDto room); + Task UpdateRoom(RoomDto room); + Task DeleteRoom(string modelId); Task GetRoom(string roomId); + Task> GetRooms(); } } diff --git a/src/IoTHub.Portal.Client/Services/IScheduleClientService.cs b/src/IoTHub.Portal.Client/Services/IScheduleClientService.cs index 5fb8a886b..c6d5f6aa0 100644 --- a/src/IoTHub.Portal.Client/Services/IScheduleClientService.cs +++ b/src/IoTHub.Portal.Client/Services/IScheduleClientService.cs @@ -9,6 +9,9 @@ namespace IoTHub.Portal.Client.Services public interface IScheduleClientService { Task CreateSchedule(ScheduleDto schedule); + Task UpdateSchedule(ScheduleDto schedule); + Task DeleteSchedule(string modelId); Task GetSchedule(string scheduleId); + Task> GetSchedules(); } } diff --git a/src/IoTHub.Portal.Client/Services/PlanningClientService.cs b/src/IoTHub.Portal.Client/Services/PlanningClientService.cs index 53f49baa4..a59f06465 100644 --- a/src/IoTHub.Portal.Client/Services/PlanningClientService.cs +++ b/src/IoTHub.Portal.Client/Services/PlanningClientService.cs @@ -11,26 +11,42 @@ namespace IoTHub.Portal.Client.Services public class PlanningClientService : IPlanningClientService { private readonly HttpClient http; + private readonly string apiUrlBase = "api/planning"; public PlanningClientService(HttpClient http) { this.http = http; } - public async Task CreatePlanning(PlanningDto planning) + public async Task CreatePlanning(PlanningDto Planning) { - var response = await this.http.PostAsJsonAsync("api/planning", planning); + var response = await this.http.PostAsJsonAsync(this.apiUrlBase, Planning); - //Retrieve Device ID + //Retrieve Planning ID var responseJson = await response.Content.ReadAsStringAsync(); var updatedPlanning = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); return updatedPlanning.Id.ToString(); } - public Task GetPlanning(string planningId) + public Task UpdatePlanning(PlanningDto Planning) { - return this.http.GetFromJsonAsync($"api/planning/{planningId}")!; + return this.http.PutAsJsonAsync(this.apiUrlBase, Planning); + } + + public Task DeletePlanning(string PlanningId) + { + return this.http.DeleteAsync($"{this.apiUrlBase}/{PlanningId}"); + } + + public Task GetPlanning(string PlanningId) + { + return this.http.GetFromJsonAsync($"{this.apiUrlBase}/{PlanningId}")!; + } + + public async Task> GetPlannings() + { + return await this.http.GetFromJsonAsync>(this.apiUrlBase) ?? new List(); } } } diff --git a/src/IoTHub.Portal.Client/Services/RoomClientService.cs b/src/IoTHub.Portal.Client/Services/RoomClientService.cs index 4ead1fc46..6e4c1332b 100644 --- a/src/IoTHub.Portal.Client/Services/RoomClientService.cs +++ b/src/IoTHub.Portal.Client/Services/RoomClientService.cs @@ -7,8 +7,6 @@ namespace IoTHub.Portal.Client.Services using System.Net.Http.Json; using System.Threading.Tasks; using IoTHub.Portal.Shared.Models.v10; - using IoTHub.Portal.Shared.Models.v10.Filters; - using Microsoft.AspNetCore.WebUtilities; public class RoomClientService : IRoomClientService { @@ -22,7 +20,7 @@ public RoomClientService(HttpClient http) public async Task CreateRoom(RoomDto room) { - var response = await this.http.PostAsJsonAsync("api/building", room); + var response = await this.http.PostAsJsonAsync(this.apiUrlBase, room); //Retrieve Room ID var responseJson = await response.Content.ReadAsStringAsync(); @@ -31,10 +29,24 @@ public async Task CreateRoom(RoomDto room) return updatedRoom.Id.ToString(); } + public Task UpdateRoom(RoomDto room) + { + return this.http.PutAsJsonAsync(this.apiUrlBase, room); + } + + public Task DeleteRoom(string roomId) + { + return this.http.DeleteAsync($"{this.apiUrlBase}/{roomId}"); + } public Task GetRoom(string roomId) { - return this.http.GetFromJsonAsync($"api/building/{roomId}")!; + return this.http.GetFromJsonAsync($"{this.apiUrlBase}/{roomId}")!; + } + + public async Task> GetRooms() + { + return await this.http.GetFromJsonAsync>(this.apiUrlBase) ?? new List(); } } } diff --git a/src/IoTHub.Portal.Client/Services/ScheduleClientService.cs b/src/IoTHub.Portal.Client/Services/ScheduleClientService.cs index 8a6d9fa9f..2872de3c5 100644 --- a/src/IoTHub.Portal.Client/Services/ScheduleClientService.cs +++ b/src/IoTHub.Portal.Client/Services/ScheduleClientService.cs @@ -11,6 +11,7 @@ namespace IoTHub.Portal.Client.Services public class ScheduleClientService : IScheduleClientService { private readonly HttpClient http; + private readonly string apiUrlBase = "api/schedule"; public ScheduleClientService(HttpClient http) { @@ -19,18 +20,33 @@ public ScheduleClientService(HttpClient http) public async Task CreateSchedule(ScheduleDto schedule) { - var response = await this.http.PostAsJsonAsync("api/schedule", schedule); + var response = await this.http.PostAsJsonAsync(this.apiUrlBase, schedule); - //Retrieve Device ID + //Retrieve Schedule ID var responseJson = await response.Content.ReadAsStringAsync(); var updatedSchedule = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); return updatedSchedule.Id.ToString(); } + public Task UpdateSchedule(ScheduleDto schedule) + { + return this.http.PutAsJsonAsync(this.apiUrlBase, schedule); + } + + public Task DeleteSchedule(string scheduleId) + { + return this.http.DeleteAsync($"{this.apiUrlBase}/{scheduleId}"); + } + public Task GetSchedule(string scheduleId) { - return this.http.GetFromJsonAsync($"api/schedule/{scheduleId}")!; + return this.http.GetFromJsonAsync($"{this.apiUrlBase}/{scheduleId}")!; + } + + public async Task> GetSchedules() + { + return await this.http.GetFromJsonAsync>(this.apiUrlBase) ?? new List(); } } } diff --git a/src/IoTHub.Portal.Infrastructure/Services/PlanningService.cs b/src/IoTHub.Portal.Infrastructure/Services/PlanningService.cs index 8d82bd2a1..0b364114f 100644 --- a/src/IoTHub.Portal.Infrastructure/Services/PlanningService.cs +++ b/src/IoTHub.Portal.Infrastructure/Services/PlanningService.cs @@ -1,4 +1,4 @@ -// Copyright (c) CGI France. All rights reserved. +// Copyright(c) CGI France. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. namespace IoTHub.Portal.Infrastructure.Services @@ -11,6 +11,7 @@ namespace IoTHub.Portal.Infrastructure.Services using IoTHub.Portal.Application.Services; using IoTHub.Portal.Shared.Models.v10; using IoTHub.Portal.Domain.Exceptions; + using IoTHub.Portal.Infrastructure.Repositories; public class PlanningService : IPlanningService { @@ -26,6 +27,12 @@ public PlanningService(IMapper mapper, this.unitOfWork = unitOfWork; this.planningRepository = planningRepository; } + + /// + /// Create a planning. + /// + /// Planning + /// Planning object. public async Task CreatePlanning(PlanningDto planning) { var planningEntity = this.mapper.Map(planning); @@ -36,6 +43,47 @@ public async Task CreatePlanning(PlanningDto planning) return planning; } + /// + /// Update the planning. + /// + /// The planning. + /// nothing. + /// + public async Task UpdatePlanning(PlanningDto planning) + { + var planningEntity = await this.planningRepository.GetByIdAsync(planning.Id); + + if (planningEntity == null) + { + throw new ResourceNotFoundException($"The planning with id {planning.Id} doesn't exist"); + } + + _ = this.mapper.Map(planning, planningEntity); + + this.planningRepository.Update(planningEntity); + + await this.unitOfWork.SaveAsync(); + } + + /// + /// Delete planning template + /// + /// The planning indentifier. + /// + /// + public async Task DeletePlanning(string planningId) + { + var planningEntity = await this.planningRepository.GetByIdAsync(planningId); + if (planningEntity == null) + { + return; + } + + this.planningRepository.Delete(planningId); + + await this.unitOfWork.SaveAsync(); + } + /// /// Get planning. /// @@ -54,5 +102,24 @@ public async Task GetPlanning(string planningId) return planning; } + + /// + /// Return the planning list. + /// + /// IEnumerable PlanningDto. + public async Task> GetPlannings() + { + var planningPredicate = PredicateBuilder.True(); + + var plannings = await this.planningRepository.GetAllAsync(); + + return plannings + .Select(model => + { + var planningListItem = this.mapper.Map(model); + return planningListItem; + }) + .ToList(); + } } } diff --git a/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs b/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs index 6b6bc89a8..fa1718d4f 100644 --- a/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs +++ b/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs @@ -12,9 +12,6 @@ namespace IoTHub.Portal.Infrastructure.Services using IoTHub.Portal.Shared.Models.v10; using IoTHub.Portal.Domain.Exceptions; using IoTHub.Portal.Infrastructure.Repositories; - using IoTHub.Portal.Shared.Models.v1._0; - using IoTHub.Portal.Shared.Models.v10.Filters; - using System.Linq.Expressions; public class RoomService : IRoomService { @@ -31,6 +28,11 @@ public RoomService(IMapper mapper, this.roomRepository = roomRepository; } + /// + /// Create a room. + /// + /// Room + /// Room object. public async Task CreateRoom(RoomDto room) { var roomEntity = this.mapper.Map(room); @@ -41,6 +43,46 @@ public async Task CreateRoom(RoomDto room) return room; } + /// + /// Update the room. + /// + /// The room. + /// nothing. + /// + public async Task UpdateRoom(RoomDto room) + { + var roomEntity = await this.roomRepository.GetByIdAsync(room.Id); + + if (roomEntity == null) + { + throw new ResourceNotFoundException($"The room with id {room.Id} doesn't exist"); + } + + _ = this.mapper.Map(room, roomEntity); + + this.roomRepository.Update(roomEntity); + + await this.unitOfWork.SaveAsync(); + } + + /// + /// Delete room template + /// + /// The room indentifier. + /// + /// + public async Task DeleteRoom(string roomId) + { + var roomEntity = await this.roomRepository.GetByIdAsync(roomId); + if (roomEntity == null) + { + return; + } + + this.roomRepository.Delete(roomId); + + await this.unitOfWork.SaveAsync(); + } /// /// Get room. @@ -60,5 +102,24 @@ public async Task GetRoom(string roomId) return room; } + + /// + /// Return the room list. + /// + /// IEnumerable RoomDto. + public async Task> GetRooms() + { + var roomPredicate = PredicateBuilder.True(); + + var rooms = await this.roomRepository.GetAllAsync(); + + return rooms + .Select(model => + { + var roomListItem = this.mapper.Map(model); + return roomListItem; + }) + .ToList(); + } } } diff --git a/src/IoTHub.Portal.Infrastructure/Services/ScheduleService.cs b/src/IoTHub.Portal.Infrastructure/Services/ScheduleService.cs index 7d4719f57..693d33c49 100644 --- a/src/IoTHub.Portal.Infrastructure/Services/ScheduleService.cs +++ b/src/IoTHub.Portal.Infrastructure/Services/ScheduleService.cs @@ -1,4 +1,4 @@ -// Copyright (c) CGI France. All rights reserved. +// Copyright(c) CGI France. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. namespace IoTHub.Portal.Infrastructure.Services @@ -11,6 +11,7 @@ namespace IoTHub.Portal.Infrastructure.Services using IoTHub.Portal.Application.Services; using IoTHub.Portal.Shared.Models.v10; using IoTHub.Portal.Domain.Exceptions; + using IoTHub.Portal.Infrastructure.Repositories; public class ScheduleService : IScheduleService { @@ -26,6 +27,12 @@ public ScheduleService(IMapper mapper, this.unitOfWork = unitOfWork; this.scheduleRepository = scheduleRepository; } + + /// + /// Create a schedule. + /// + /// Schedule + /// Schedule object. public async Task CreateSchedule(ScheduleDto schedule) { var scheduleEntity = this.mapper.Map(schedule); @@ -36,6 +43,47 @@ public async Task CreateSchedule(ScheduleDto schedule) return schedule; } + /// + /// Update the schedule. + /// + /// The schedule. + /// nothing. + /// + public async Task UpdateSchedule(ScheduleDto schedule) + { + var scheduleEntity = await this.scheduleRepository.GetByIdAsync(schedule.Id); + + if (scheduleEntity == null) + { + throw new ResourceNotFoundException($"The schedule with id {schedule.Id} doesn't exist"); + } + + _ = this.mapper.Map(schedule, scheduleEntity); + + this.scheduleRepository.Update(scheduleEntity); + + await this.unitOfWork.SaveAsync(); + } + + /// + /// Delete schedule template + /// + /// The schedule indentifier. + /// + /// + public async Task DeleteSchedule(string scheduleId) + { + var scheduleEntity = await this.scheduleRepository.GetByIdAsync(scheduleId); + if (scheduleEntity == null) + { + return; + } + + this.scheduleRepository.Delete(scheduleId); + + await this.unitOfWork.SaveAsync(); + } + /// /// Get schedule. /// @@ -54,5 +102,24 @@ public async Task GetSchedule(string scheduleId) return schedule; } + + /// + /// Return the schedule list. + /// + /// IEnumerable ScheduleDto. + public async Task> GetSchedules() + { + var schedulePredicate = PredicateBuilder.True(); + + var schedules = await this.scheduleRepository.GetAllAsync(); + + return schedules + .Select(model => + { + var scheduleListItem = this.mapper.Map(model); + return scheduleListItem; + }) + .ToList(); + } } } diff --git a/src/IoTHub.Portal.Server/Controllers/v1.0/PlanningsController.cs b/src/IoTHub.Portal.Server/Controllers/v1.0/PlanningsController.cs index acb3a70b2..3e5cc8806 100644 --- a/src/IoTHub.Portal.Server/Controllers/v1.0/PlanningsController.cs +++ b/src/IoTHub.Portal.Server/Controllers/v1.0/PlanningsController.cs @@ -12,12 +12,14 @@ namespace IoTHub.Portal.Server.Controllers.V10 using Hellang.Middleware.ProblemDetails; using IoTHub.Portal.Shared.Models.v10; using Microsoft.Azure.Devices.Common.Exceptions; + using System.Collections.Generic; + using IoTHub.Portal.Domain.Exceptions; [Authorize] [ApiController] [ApiVersion("1.0")] [Route("api/planning")] - [ApiExplorerSettings(GroupName = "IoT Building")] + [ApiExplorerSettings(GroupName = "IoT Planning")] public class PlanningsController : ControllerBase { private readonly IPlanningService planningService; @@ -52,21 +54,60 @@ public async Task CreatePlanningAsync(PlanningDto planning) } /// - /// Gets the specified Planning. + /// Updates the specified planning. /// - /// The Planning identifier. - [HttpGet("{PlanningId}", Name = "GET Planning")] + /// The planning. + /// The action result. + [HttpPut(Name = "PUT Update the planning")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task UpdatePlanning(PlanningDto Planning) + { + await this.planningService.UpdatePlanning(Planning); + + return Ok(); + } + + /// + /// Delete the planning. + /// + /// the planning id. + /// Http response + /// + [HttpDelete("{planningId}", Name = "DELETE Remove the planning")] + public async Task DeletePlanning(string planningId) + { + await this.planningService.DeletePlanning(planningId); + + return NoContent(); + } + + /// + /// Gets the specified planning. + /// + /// The planning identifier. + [HttpGet("{planningId}", Name = "GET Planning")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PlanningDto))] - public async Task GetPlanning(string PlanningId) + public async Task GetPlanning(string planningId) { try { - return Ok(await this.planningService.GetPlanning(PlanningId)); + return Ok(await this.planningService.GetPlanning(planningId)); } catch (DeviceNotFoundException e) { return StatusCode(StatusCodes.Status404NotFound, e.Message); } } + + /// + /// Gets the planning list. + /// + /// An array representing the plannings. + [HttpGet(Name = "GET Planning list")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task>> GetPlannings() + { + return Ok(await this.planningService.GetPlannings()); + } } } diff --git a/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs b/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs index 73f6a3437..322d8ca2f 100644 --- a/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs +++ b/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs @@ -12,8 +12,8 @@ namespace IoTHub.Portal.Server.Controllers.V10 using Hellang.Middleware.ProblemDetails; using IoTHub.Portal.Shared.Models.v10; using Microsoft.Azure.Devices.Common.Exceptions; - using IoTHub.Portal.Shared.Models.v10.Filters; - using Microsoft.AspNetCore.Mvc.Routing; + using System.Collections.Generic; + using IoTHub.Portal.Domain.Exceptions; [Authorize] [ApiController] @@ -53,6 +53,33 @@ public async Task CreateRoomAsync(RoomDto room) return Ok(room); } + /// + /// Updates the specified room. + /// + /// The room. + /// The action result. + [HttpPut(Name = "PUT Update the room")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task UpdateRoom(RoomDto Room) + { + await this.roomService.UpdateRoom(Room); + + return Ok(); + } + + /// + /// Delete the room. + /// + /// the room id. + /// Http response + /// + [HttpDelete("{roomId}", Name = "DELETE Remove the room")] + public async Task DeleteRoom(string roomId) + { + await this.roomService.DeleteRoom(roomId); + + return NoContent(); + } /// /// Gets the specified room. @@ -71,5 +98,16 @@ public async Task GetRoom(string roomId) return StatusCode(StatusCodes.Status404NotFound, e.Message); } } + + /// + /// Gets the room list. + /// + /// An array representing the rooms. + [HttpGet(Name = "GET Room list")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task>> GetRooms() + { + return Ok(await this.roomService.GetRooms()); + } } } diff --git a/src/IoTHub.Portal.Server/Controllers/v1.0/SchedulesController.cs b/src/IoTHub.Portal.Server/Controllers/v1.0/SchedulesController.cs index 908a473b9..c6d4d94a5 100644 --- a/src/IoTHub.Portal.Server/Controllers/v1.0/SchedulesController.cs +++ b/src/IoTHub.Portal.Server/Controllers/v1.0/SchedulesController.cs @@ -12,12 +12,14 @@ namespace IoTHub.Portal.Server.Controllers.V10 using Hellang.Middleware.ProblemDetails; using IoTHub.Portal.Shared.Models.v10; using Microsoft.Azure.Devices.Common.Exceptions; + using System.Collections.Generic; + using IoTHub.Portal.Domain.Exceptions; [Authorize] [ApiController] [ApiVersion("1.0")] [Route("api/schedule")] - [ApiExplorerSettings(GroupName = "IoT Building")] + [ApiExplorerSettings(GroupName = "IoT Schedule")] public class SchedulesController : ControllerBase { private readonly IScheduleService scheduleService; @@ -51,6 +53,34 @@ public async Task CreateScheduleAsync(ScheduleDto schedule) return Ok(schedule); } + /// + /// Updates the specified schedule. + /// + /// The schedule. + /// The action result. + [HttpPut(Name = "PUT Update the schedule")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task UpdateSchedule(ScheduleDto Schedule) + { + await this.scheduleService.UpdateSchedule(Schedule); + + return Ok(); + } + + /// + /// Delete the schedule. + /// + /// the schedule id. + /// Http response + /// + [HttpDelete("{scheduleId}", Name = "DELETE Remove the schedule")] + public async Task DeleteSchedule(string scheduleId) + { + await this.scheduleService.DeleteSchedule(scheduleId); + + return NoContent(); + } + /// /// Gets the specified schedule. /// @@ -68,5 +98,16 @@ public async Task GetSchedule(string scheduleId) return StatusCode(StatusCodes.Status404NotFound, e.Message); } } + + /// + /// Gets the schedule list. + /// + /// An array representing the schedules. + [HttpGet(Name = "GET Schedule list")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task>> GetSchedules() + { + return Ok(await this.scheduleService.GetSchedules()); + } } } From 802ce203e55c816da3eb4be800caa7bf1e092daf Mon Sep 17 00:00:00 2001 From: lucas-mrq Date: Mon, 18 Mar 2024 11:05:58 +0100 Subject: [PATCH 003/120] Update Room to level --- .../{RoomProfile.cs => LevelProfile.cs} | 6 +- .../{IRoomService.cs => ILevelService.cs} | 12 +- src/IoTHub.Portal.Client/Program.cs | 2 +- ...lientService.cs => ILevelClientService.cs} | 12 +- .../Services/LevelClientService.cs | 52 ++++++++ .../Services/RoomClientService.cs | 52 -------- src/IoTHub.Portal.Domain/Entities/Level.cs | 26 ++++ src/IoTHub.Portal.Domain/Entities/Planning.cs | 27 +++- src/IoTHub.Portal.Domain/Entities/Room.cs | 41 ------ src/IoTHub.Portal.Domain/Entities/Schedule.cs | 6 +- ...IRoomRepository.cs => ILevelRepository.cs} | 2 +- .../PortalDbContext.cs | 2 +- .../{RoomRepository.cs => LevelRepository.cs} | 5 +- .../Repositories/PlanningRepository.cs | 4 +- .../Services/LevelService.cs | 125 ++++++++++++++++++ .../Services/RoomService.cs | 125 ------------------ .../Startup/IServiceCollectionExtension.cs | 4 +- ...RoomsController.cs => LevelsController.cs} | 64 ++++----- .../Models/v1.0/{RoomDto.cs => LevelDto.cs} | 10 +- .../Models/v1.0/PlanningDto.cs | 12 +- .../Models/v1.0/ScheduleDto.cs | 8 +- 21 files changed, 299 insertions(+), 298 deletions(-) rename src/IoTHub.Portal.Application/Mappers/{RoomProfile.cs => LevelProfile.cs} (76%) rename src/IoTHub.Portal.Application/Services/{IRoomService.cs => ILevelService.cs} (55%) rename src/IoTHub.Portal.Client/Services/{IRoomClientService.cs => ILevelClientService.cs} (51%) create mode 100644 src/IoTHub.Portal.Client/Services/LevelClientService.cs delete mode 100644 src/IoTHub.Portal.Client/Services/RoomClientService.cs create mode 100644 src/IoTHub.Portal.Domain/Entities/Level.cs delete mode 100644 src/IoTHub.Portal.Domain/Entities/Room.cs rename src/IoTHub.Portal.Domain/Repositories/{IRoomRepository.cs => ILevelRepository.cs} (79%) rename src/IoTHub.Portal.Infrastructure/Repositories/{RoomRepository.cs => LevelRepository.cs} (65%) create mode 100644 src/IoTHub.Portal.Infrastructure/Services/LevelService.cs delete mode 100644 src/IoTHub.Portal.Infrastructure/Services/RoomService.cs rename src/IoTHub.Portal.Server/Controllers/v1.0/{RoomsController.cs => LevelsController.cs} (54%) rename src/IoTHub.Portal.Shared/Models/v1.0/{RoomDto.cs => LevelDto.cs} (80%) diff --git a/src/IoTHub.Portal.Application/Mappers/RoomProfile.cs b/src/IoTHub.Portal.Application/Mappers/LevelProfile.cs similarity index 76% rename from src/IoTHub.Portal.Application/Mappers/RoomProfile.cs rename to src/IoTHub.Portal.Application/Mappers/LevelProfile.cs index 879d5322f..80d513ccc 100644 --- a/src/IoTHub.Portal.Application/Mappers/RoomProfile.cs +++ b/src/IoTHub.Portal.Application/Mappers/LevelProfile.cs @@ -7,11 +7,11 @@ namespace IoTHub.Portal.Infrastructure.Mappers using IoTHub.Portal.Domain.Entities; using IoTHub.Portal.Shared.Models.v10; - public class RoomProfile : Profile + public class LevelProfile : Profile { - public RoomProfile() + public LevelProfile() { - _ = CreateMap() + _ = CreateMap() .ReverseMap(); } } diff --git a/src/IoTHub.Portal.Application/Services/IRoomService.cs b/src/IoTHub.Portal.Application/Services/ILevelService.cs similarity index 55% rename from src/IoTHub.Portal.Application/Services/IRoomService.cs rename to src/IoTHub.Portal.Application/Services/ILevelService.cs index 86ee0ed56..4906444c5 100644 --- a/src/IoTHub.Portal.Application/Services/IRoomService.cs +++ b/src/IoTHub.Portal.Application/Services/ILevelService.cs @@ -7,12 +7,12 @@ namespace IoTHub.Portal.Application.Services using IoTHub.Portal.Domain.Entities; using IoTHub.Portal.Shared.Models.v10; - public interface IRoomService + public interface ILevelService { - Task CreateRoom(RoomDto room); - Task UpdateRoom(RoomDto room); - Task DeleteRoom(string roomId); - Task GetRoom(string roomId); - Task> GetRooms(); + Task CreateLevel(LevelDto level); + Task UpdateLevel(LevelDto level); + Task DeleteLevel(string levelId); + Task GetLevel(string levelId); + Task> GetLevels(); } } diff --git a/src/IoTHub.Portal.Client/Program.cs b/src/IoTHub.Portal.Client/Program.cs index 2ba4cce9e..6ae028a5f 100644 --- a/src/IoTHub.Portal.Client/Program.cs +++ b/src/IoTHub.Portal.Client/Program.cs @@ -84,7 +84,7 @@ _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); -_ = builder.Services.AddScoped(); +_ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); diff --git a/src/IoTHub.Portal.Client/Services/IRoomClientService.cs b/src/IoTHub.Portal.Client/Services/ILevelClientService.cs similarity index 51% rename from src/IoTHub.Portal.Client/Services/IRoomClientService.cs rename to src/IoTHub.Portal.Client/Services/ILevelClientService.cs index 084c53dcc..b9063a5a1 100644 --- a/src/IoTHub.Portal.Client/Services/IRoomClientService.cs +++ b/src/IoTHub.Portal.Client/Services/ILevelClientService.cs @@ -6,12 +6,12 @@ namespace IoTHub.Portal.Client.Services using System.Threading.Tasks; using IoTHub.Portal.Shared.Models.v10; - public interface IRoomClientService + public interface ILevelClientService { - Task CreateRoom(RoomDto room); - Task UpdateRoom(RoomDto room); - Task DeleteRoom(string modelId); - Task GetRoom(string roomId); - Task> GetRooms(); + Task CreateLevel(LevelDto level); + Task UpdateLevel(LevelDto level); + Task DeleteLevel(string modelId); + Task GetLevel(string levelId); + Task> GetLevels(); } } diff --git a/src/IoTHub.Portal.Client/Services/LevelClientService.cs b/src/IoTHub.Portal.Client/Services/LevelClientService.cs new file mode 100644 index 000000000..6f229c08b --- /dev/null +++ b/src/IoTHub.Portal.Client/Services/LevelClientService.cs @@ -0,0 +1,52 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Services +{ + using System.Net.Http; + using System.Net.Http.Json; + using System.Threading.Tasks; + using IoTHub.Portal.Shared.Models.v10; + + public class LevelClientService : ILevelClientService + { + private readonly HttpClient http; + private readonly string apiUrlBase = "api/building"; + + public LevelClientService(HttpClient http) + { + this.http = http; + } + + public async Task CreateLevel(LevelDto level) + { + var response = await this.http.PostAsJsonAsync(this.apiUrlBase, level); + + //Retrieve Level ID + var responseJson = await response.Content.ReadAsStringAsync(); + var updatedLevel = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); + + return updatedLevel.Id.ToString(); + } + + public Task UpdateLevel(LevelDto level) + { + return this.http.PutAsJsonAsync(this.apiUrlBase, level); + } + + public Task DeleteLevel(string levelId) + { + return this.http.DeleteAsync($"{this.apiUrlBase}/{levelId}"); + } + + public Task GetLevel(string levelId) + { + return this.http.GetFromJsonAsync($"{this.apiUrlBase}/{levelId}")!; + } + + public async Task> GetLevels() + { + return await this.http.GetFromJsonAsync>(this.apiUrlBase) ?? new List(); + } + } +} diff --git a/src/IoTHub.Portal.Client/Services/RoomClientService.cs b/src/IoTHub.Portal.Client/Services/RoomClientService.cs deleted file mode 100644 index 6e4c1332b..000000000 --- a/src/IoTHub.Portal.Client/Services/RoomClientService.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace IoTHub.Portal.Client.Services -{ - using System.Net.Http; - using System.Net.Http.Json; - using System.Threading.Tasks; - using IoTHub.Portal.Shared.Models.v10; - - public class RoomClientService : IRoomClientService - { - private readonly HttpClient http; - private readonly string apiUrlBase = "api/building"; - - public RoomClientService(HttpClient http) - { - this.http = http; - } - - public async Task CreateRoom(RoomDto room) - { - var response = await this.http.PostAsJsonAsync(this.apiUrlBase, room); - - //Retrieve Room ID - var responseJson = await response.Content.ReadAsStringAsync(); - var updatedRoom = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); - - return updatedRoom.Id.ToString(); - } - - public Task UpdateRoom(RoomDto room) - { - return this.http.PutAsJsonAsync(this.apiUrlBase, room); - } - - public Task DeleteRoom(string roomId) - { - return this.http.DeleteAsync($"{this.apiUrlBase}/{roomId}"); - } - - public Task GetRoom(string roomId) - { - return this.http.GetFromJsonAsync($"{this.apiUrlBase}/{roomId}")!; - } - - public async Task> GetRooms() - { - return await this.http.GetFromJsonAsync>(this.apiUrlBase) ?? new List(); - } - } -} diff --git a/src/IoTHub.Portal.Domain/Entities/Level.cs b/src/IoTHub.Portal.Domain/Entities/Level.cs new file mode 100644 index 000000000..eaed9e8ad --- /dev/null +++ b/src/IoTHub.Portal.Domain/Entities/Level.cs @@ -0,0 +1,26 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Domain.Entities +{ + using IoTHub.Portal.Domain.Base; + + public class Level : EntityBase + { + /// + /// The Level friendly name. + /// + public string Name { get; set; } = default!; + + /// + /// Where level is. + /// + public string Father { get; set; } = default!; + + /// + /// The planning associat with the level. + /// + public string Planning { get; set; } = default!; + + } +} diff --git a/src/IoTHub.Portal.Domain/Entities/Planning.cs b/src/IoTHub.Portal.Domain/Entities/Planning.cs index be6ae97ba..452438f48 100644 --- a/src/IoTHub.Portal.Domain/Entities/Planning.cs +++ b/src/IoTHub.Portal.Domain/Entities/Planning.cs @@ -5,22 +5,37 @@ namespace IoTHub.Portal.Domain.Entities { using IoTHub.Portal.Domain.Base; - public class Room : EntityBase + public class Planning : EntityBase { /// - /// The room friendly name. + /// The planning friendly name. /// public string Name { get; set; } = default!; /// - /// Where room is. + /// Where planning start. /// - public string Father { get; set; } = default!; + public string Start { get; set; } = default!; /// - /// The planning associat with the room. + /// Where planning end. /// - public string Planning { get; set; } = default!; + public string End { get; set; } = default!; + + /// + /// How much it repeat. + /// + public bool Frequency { get; set; } = default!; + + /// + /// When planning is used + /// + public string DayOff { get; set; } = default!; + + /// + /// Day off command. + /// + public int CommandOff { get; set; } = default!; } } diff --git a/src/IoTHub.Portal.Domain/Entities/Room.cs b/src/IoTHub.Portal.Domain/Entities/Room.cs deleted file mode 100644 index d9ede51f5..000000000 --- a/src/IoTHub.Portal.Domain/Entities/Room.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace IoTHub.Portal.Domain.Entities -{ - using IoTHub.Portal.Domain.Base; - - public class Planning : EntityBase - { - /// - /// The planning friendly name. - /// - public string Name { get; set; } = default!; - - /// - /// Where planning start. - /// - public int Start { get; set; } = default!; - - /// - /// Where planning end. - /// - public int End { get; set; } = default!; - - /// - /// How much it repeat. - /// - public int Frequency { get; set; } = default!; - - /// - /// When planning is used - /// - public string DayOff { get; set; } = default!; - - /// - /// Day off temperature. - /// - public int TemperatureOff { get; set; } = default!; - - } -} diff --git a/src/IoTHub.Portal.Domain/Entities/Schedule.cs b/src/IoTHub.Portal.Domain/Entities/Schedule.cs index 5ca297793..5995df0e3 100644 --- a/src/IoTHub.Portal.Domain/Entities/Schedule.cs +++ b/src/IoTHub.Portal.Domain/Entities/Schedule.cs @@ -10,17 +10,17 @@ public class Schedule : EntityBase /// /// The schedule friendly name. /// - public int Start { get; set; } = default!; + public string Start { get; set; } = default!; /// /// Where schedule is. /// - public int End { get; set; } = default!; + public string End { get; set; } = default!; /// /// The planning associat with the schedule. /// - public int Temperature { get; set; } = default!; + public int Command { get; set; } = default!; /// /// The planning associat with the schedule. diff --git a/src/IoTHub.Portal.Domain/Repositories/IRoomRepository.cs b/src/IoTHub.Portal.Domain/Repositories/ILevelRepository.cs similarity index 79% rename from src/IoTHub.Portal.Domain/Repositories/IRoomRepository.cs rename to src/IoTHub.Portal.Domain/Repositories/ILevelRepository.cs index 1cf914856..f62c58c34 100644 --- a/src/IoTHub.Portal.Domain/Repositories/IRoomRepository.cs +++ b/src/IoTHub.Portal.Domain/Repositories/ILevelRepository.cs @@ -5,7 +5,7 @@ namespace IoTHub.Portal.Domain.Repositories { using Entities; - public interface IRoomRepository : IRepository + public interface ILevelRepository : IRepository { } } diff --git a/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs b/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs index 2d2207885..b8d9bc8d3 100644 --- a/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs +++ b/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs @@ -12,7 +12,7 @@ public class PortalDbContext : DbContext, IDataProtectionKeyContext { public DbSet DeviceModelProperties { get; set; } public DbSet DeviceTags { get; set; } - public DbSet Rooms { get; set; } + public DbSet Levels { get; set; } public DbSet Plannings { get; set; } public DbSet Schedules { get; set; } public DbSet DeviceModelCommands { get; set; } diff --git a/src/IoTHub.Portal.Infrastructure/Repositories/RoomRepository.cs b/src/IoTHub.Portal.Infrastructure/Repositories/LevelRepository.cs similarity index 65% rename from src/IoTHub.Portal.Infrastructure/Repositories/RoomRepository.cs rename to src/IoTHub.Portal.Infrastructure/Repositories/LevelRepository.cs index 26776da2e..833a064ca 100644 --- a/src/IoTHub.Portal.Infrastructure/Repositories/RoomRepository.cs +++ b/src/IoTHub.Portal.Infrastructure/Repositories/LevelRepository.cs @@ -1,3 +1,4 @@ + // Copyright (c) CGI France. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. @@ -6,9 +7,9 @@ namespace IoTHub.Portal.Infrastructure.Repositories using IoTHub.Portal.Domain.Repositories; using Domain.Entities; - public class PlanningRepository : GenericRepository, IPlanningRepository + public class LevelRepository : GenericRepository, ILevelRepository { - public PlanningRepository(PortalDbContext context) : base(context) + public LevelRepository(PortalDbContext context) : base(context) { } } diff --git a/src/IoTHub.Portal.Infrastructure/Repositories/PlanningRepository.cs b/src/IoTHub.Portal.Infrastructure/Repositories/PlanningRepository.cs index b6910edf7..26776da2e 100644 --- a/src/IoTHub.Portal.Infrastructure/Repositories/PlanningRepository.cs +++ b/src/IoTHub.Portal.Infrastructure/Repositories/PlanningRepository.cs @@ -6,9 +6,9 @@ namespace IoTHub.Portal.Infrastructure.Repositories using IoTHub.Portal.Domain.Repositories; using Domain.Entities; - public class RoomRepository : GenericRepository, IRoomRepository + public class PlanningRepository : GenericRepository, IPlanningRepository { - public RoomRepository(PortalDbContext context) : base(context) + public PlanningRepository(PortalDbContext context) : base(context) { } } diff --git a/src/IoTHub.Portal.Infrastructure/Services/LevelService.cs b/src/IoTHub.Portal.Infrastructure/Services/LevelService.cs new file mode 100644 index 000000000..4b53db819 --- /dev/null +++ b/src/IoTHub.Portal.Infrastructure/Services/LevelService.cs @@ -0,0 +1,125 @@ +// Copyright(c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Infrastructure.Services +{ + using System.Threading.Tasks; + using AutoMapper; + using IoTHub.Portal.Domain.Entities; + using Domain; + using Domain.Repositories; + using IoTHub.Portal.Application.Services; + using IoTHub.Portal.Shared.Models.v10; + using IoTHub.Portal.Domain.Exceptions; + using IoTHub.Portal.Infrastructure.Repositories; + + public class LevelService : ILevelService + { + private readonly IMapper mapper; + private readonly IUnitOfWork unitOfWork; + private readonly ILevelRepository levelRepository; + + public LevelService(IMapper mapper, + IUnitOfWork unitOfWork, + ILevelRepository levelRepository) + { + this.mapper = mapper; + this.unitOfWork = unitOfWork; + this.levelRepository = levelRepository; + } + + /// + /// Create a level. + /// + /// Level + /// Level object. + public async Task CreateLevel(LevelDto level) + { + var levelEntity = this.mapper.Map(level); + + await this.levelRepository.InsertAsync(levelEntity); + await this.unitOfWork.SaveAsync(); + + return level; + } + + /// + /// Update the level. + /// + /// The level. + /// nothing. + /// + public async Task UpdateLevel(LevelDto level) + { + var levelEntity = await this.levelRepository.GetByIdAsync(level.Id); + + if (levelEntity == null) + { + throw new ResourceNotFoundException($"The level with id {level.Id} doesn't exist"); + } + + _ = this.mapper.Map(level, levelEntity); + + this.levelRepository.Update(levelEntity); + + await this.unitOfWork.SaveAsync(); + } + + /// + /// Delete level template + /// + /// The level indentifier. + /// + /// + public async Task DeleteLevel(string levelId) + { + var levelEntity = await this.levelRepository.GetByIdAsync(levelId); + if (levelEntity == null) + { + return; + } + + this.levelRepository.Delete(levelId); + + await this.unitOfWork.SaveAsync(); + } + + /// + /// Get level. + /// + /// level id. + /// Level object. + public async Task GetLevel(string levelId) + { + var levelEntity = await this.levelRepository.GetByIdAsync(levelId); + + if (levelEntity is null) + { + throw new ResourceNotFoundException($"The level with id {levelId} doesn't exist"); + } + + var level = this.mapper.Map(levelEntity); + + return level; + } + + /// + /// Return the level list. + /// + /// IEnumerable LevelDto. + public async Task> GetLevels() + { + var levelPredicate = PredicateBuilder.True(); + + var levels = await this.levelRepository.GetAllAsync(); + + return levels + .Select(model => + { + var levelListItem = this.mapper.Map(model); + return levelListItem; + }) + .ToList(); + } + } +} diff --git a/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs b/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs deleted file mode 100644 index fa1718d4f..000000000 --- a/src/IoTHub.Portal.Infrastructure/Services/RoomService.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright(c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace IoTHub.Portal.Infrastructure.Services -{ - using System.Threading.Tasks; - using AutoMapper; - using IoTHub.Portal.Domain.Entities; - using Domain; - using Domain.Repositories; - using IoTHub.Portal.Application.Services; - using IoTHub.Portal.Shared.Models.v10; - using IoTHub.Portal.Domain.Exceptions; - using IoTHub.Portal.Infrastructure.Repositories; - - public class RoomService : IRoomService - { - private readonly IMapper mapper; - private readonly IUnitOfWork unitOfWork; - private readonly IRoomRepository roomRepository; - - public RoomService(IMapper mapper, - IUnitOfWork unitOfWork, - IRoomRepository roomRepository) - { - this.mapper = mapper; - this.unitOfWork = unitOfWork; - this.roomRepository = roomRepository; - } - - /// - /// Create a room. - /// - /// Room - /// Room object. - public async Task CreateRoom(RoomDto room) - { - var roomEntity = this.mapper.Map(room); - - await this.roomRepository.InsertAsync(roomEntity); - await this.unitOfWork.SaveAsync(); - - return room; - } - - /// - /// Update the room. - /// - /// The room. - /// nothing. - /// - public async Task UpdateRoom(RoomDto room) - { - var roomEntity = await this.roomRepository.GetByIdAsync(room.Id); - - if (roomEntity == null) - { - throw new ResourceNotFoundException($"The room with id {room.Id} doesn't exist"); - } - - _ = this.mapper.Map(room, roomEntity); - - this.roomRepository.Update(roomEntity); - - await this.unitOfWork.SaveAsync(); - } - - /// - /// Delete room template - /// - /// The room indentifier. - /// - /// - public async Task DeleteRoom(string roomId) - { - var roomEntity = await this.roomRepository.GetByIdAsync(roomId); - if (roomEntity == null) - { - return; - } - - this.roomRepository.Delete(roomId); - - await this.unitOfWork.SaveAsync(); - } - - /// - /// Get room. - /// - /// room id. - /// Room object. - public async Task GetRoom(string roomId) - { - var roomEntity = await this.roomRepository.GetByIdAsync(roomId); - - if (roomEntity is null) - { - throw new ResourceNotFoundException($"The room with id {roomId} doesn't exist"); - } - - var room = this.mapper.Map(roomEntity); - - return room; - } - - /// - /// Return the room list. - /// - /// IEnumerable RoomDto. - public async Task> GetRooms() - { - var roomPredicate = PredicateBuilder.True(); - - var rooms = await this.roomRepository.GetAllAsync(); - - return rooms - .Select(model => - { - var roomListItem = this.mapper.Map(model); - return roomListItem; - }) - .ToList(); - } - } -} diff --git a/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs b/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs index 6e40d30bb..bf5770359 100644 --- a/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs +++ b/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs @@ -103,7 +103,7 @@ private static IServiceCollection ConfigureRepositories(this IServiceCollection .AddScoped() .AddScoped() .AddScoped() - .AddScoped() + .AddScoped() .AddScoped() .AddScoped() .AddScoped() @@ -116,7 +116,7 @@ private static IServiceCollection ConfigureServices(this IServiceCollection serv .AddTransient() .AddTransient() .AddTransient() - .AddTransient() + .AddTransient() .AddTransient() .AddTransient() .AddTransient(); diff --git a/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs b/src/IoTHub.Portal.Server/Controllers/v1.0/LevelsController.cs similarity index 54% rename from src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs rename to src/IoTHub.Portal.Server/Controllers/v1.0/LevelsController.cs index 322d8ca2f..d43e2caf7 100644 --- a/src/IoTHub.Portal.Server/Controllers/v1.0/RoomsController.cs +++ b/src/IoTHub.Portal.Server/Controllers/v1.0/LevelsController.cs @@ -20,23 +20,23 @@ namespace IoTHub.Portal.Server.Controllers.V10 [ApiVersion("1.0")] [Route("api/building")] [ApiExplorerSettings(GroupName = "IoT Building")] - public class RoomsController : ControllerBase + public class LevelsController : ControllerBase { - private readonly IRoomService roomService; + private readonly ILevelService levelService; - public RoomsController(IRoomService roomService) + public LevelsController(ILevelService levelService) { - this.roomService = roomService; + this.levelService = levelService; } /// - /// Creates the room. + /// Creates the level. /// - /// The room. - [HttpPost(Name = "POST Create room")] - public async Task CreateRoomAsync(RoomDto room) + /// The level. + [HttpPost(Name = "POST Create level")] + public async Task CreateLevelAsync(LevelDto level) { - ArgumentNullException.ThrowIfNull(room, nameof(room)); + ArgumentNullException.ThrowIfNull(level, nameof(level)); if (!ModelState.IsValid) { @@ -48,50 +48,50 @@ public async Task CreateRoomAsync(RoomDto room) throw new ProblemDetailsException(validation); } - _ = await this.roomService.CreateRoom(room); + _ = await this.levelService.CreateLevel(level); - return Ok(room); + return Ok(level); } /// - /// Updates the specified room. + /// Updates the specified level. /// - /// The room. + /// The level. /// The action result. - [HttpPut(Name = "PUT Update the room")] + [HttpPut(Name = "PUT Update the level")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task UpdateRoom(RoomDto Room) + public async Task UpdateLevel(LevelDto Level) { - await this.roomService.UpdateRoom(Room); + await this.levelService.UpdateLevel(Level); return Ok(); } /// - /// Delete the room. + /// Delete the level. /// - /// the room id. + /// the level id. /// Http response /// - [HttpDelete("{roomId}", Name = "DELETE Remove the room")] - public async Task DeleteRoom(string roomId) + [HttpDelete("{levelId}", Name = "DELETE Remove the level")] + public async Task DeleteLevel(string levelId) { - await this.roomService.DeleteRoom(roomId); + await this.levelService.DeleteLevel(levelId); return NoContent(); } /// - /// Gets the specified room. + /// Gets the specified level. /// - /// The room identifier. - [HttpGet("{roomId}", Name = "GET Room")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RoomDto))] - public async Task GetRoom(string roomId) + /// The level identifier. + [HttpGet("{levelId}", Name = "GET Level")] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(LevelDto))] + public async Task GetLevel(string levelId) { try { - return Ok(await this.roomService.GetRoom(roomId)); + return Ok(await this.levelService.GetLevel(levelId)); } catch (DeviceNotFoundException e) { @@ -100,14 +100,14 @@ public async Task GetRoom(string roomId) } /// - /// Gets the room list. + /// Gets the level list. /// - /// An array representing the rooms. - [HttpGet(Name = "GET Room list")] + /// An array representing the levels. + [HttpGet(Name = "GET Level list")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task>> GetRooms() + public async Task>> GetLevels() { - return Ok(await this.roomService.GetRooms()); + return Ok(await this.levelService.GetLevels()); } } } diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/RoomDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/LevelDto.cs similarity index 80% rename from src/IoTHub.Portal.Shared/Models/v1.0/RoomDto.cs rename to src/IoTHub.Portal.Shared/Models/v1.0/LevelDto.cs index a66562e5b..ecb8214ae 100644 --- a/src/IoTHub.Portal.Shared/Models/v1.0/RoomDto.cs +++ b/src/IoTHub.Portal.Shared/Models/v1.0/LevelDto.cs @@ -7,25 +7,25 @@ namespace IoTHub.Portal.Shared.Models.v10 //using System.ComponentModel.DataAnnotations; - public class RoomDto + public class LevelDto { /// - /// The room auto ID. + /// The level auto ID. /// public string Id { get; set; } = Guid.NewGuid().ToString(); /// - /// The room friendly name. + /// The level friendly name. /// public string Name { get; set; } = default!; /// - /// Where room is. + /// Where level is. /// public string Father { get; set; } = default!; /// - /// The planning associat with the room. + /// The planning associat with the level. /// public string Planning { get; set; } = default!; } diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs index 076cbea36..54a8e043e 100644 --- a/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs +++ b/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs @@ -10,7 +10,7 @@ namespace IoTHub.Portal.Shared.Models.v10 public class PlanningDto { /// - /// The room auto ID. + /// The level auto ID. /// public string Id { get; set; } = Guid.NewGuid().ToString(); @@ -22,17 +22,17 @@ public class PlanningDto /// /// Where planning start. /// - public int Start { get; set; } = default!; + public string Start { get; set; } = default!; /// /// Where planning end. /// - public int End { get; set; } = default!; + public string End { get; set; } = default!; /// /// How much it repeat. /// - public int Frequency { get; set; } = default!; + public bool Frequency { get; set; } = default!; /// /// When planning is used @@ -40,8 +40,8 @@ public class PlanningDto public string DayOff { get; set; } = default!; /// - /// Day off temperature. + /// Day off command. /// - public int TemperatureOff { get; set; } = default!; + public int CommandOff { get; set; } = default!; } } diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs index 314d5d0a0..f82c0173b 100644 --- a/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs +++ b/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs @@ -10,24 +10,24 @@ namespace IoTHub.Portal.Shared.Models.v10 public class ScheduleDto { /// - /// The room auto ID. + /// The level auto ID. /// public string Id { get; set; } = Guid.NewGuid().ToString(); /// /// The schedule friendly name. /// - public int Start { get; set; } = default!; + public string Start { get; set; } = default!; /// /// Where schedule is. /// - public int End { get; set; } = default!; + public string End { get; set; } = default!; /// /// The planning associat with the schedule. /// - public int Temperature { get; set; } = default!; + public int Command { get; set; } = 19; /// /// The planning associat with the schedule. From 72c035dbd42ed4b286758d7fcecbdc9208177173 Mon Sep 17 00:00:00 2001 From: lucas-mrq Date: Thu, 21 Mar 2024 11:18:49 +0100 Subject: [PATCH 004/120] Change Level to Layer --- .../{LevelProfile.cs => LayerProfile.cs} | 6 +-- .../{ILevelService.cs => ILayerService.cs} | 12 ++--- src/IoTHub.Portal.Client/Program.cs | 2 +- ...lientService.cs => ILayerClientService.cs} | 12 ++--- .../Services/LayerClientService.cs | 52 +++++++++++++++++++ .../Services/LevelClientService.cs | 52 ------------------- .../Entities/{Level.cs => Layer.cs} | 9 +++- ...LevelRepository.cs => ILayerRepository.cs} | 2 +- .../PortalDbContext.cs | 2 +- ...{LevelRepository.cs => LayerRepository.cs} | 4 +- .../{LevelService.cs => LayerService.cs} | 34 ++++++------ .../Startup/IServiceCollectionExtension.cs | 4 +- ...evelsController.cs => LayersController.cs} | 34 ++++++------ .../Models/v1.0/{LevelDto.cs => LayerDto.cs} | 7 ++- 14 files changed, 121 insertions(+), 111 deletions(-) rename src/IoTHub.Portal.Application/Mappers/{LevelProfile.cs => LayerProfile.cs} (76%) rename src/IoTHub.Portal.Application/Services/{ILevelService.cs => ILayerService.cs} (55%) rename src/IoTHub.Portal.Client/Services/{ILevelClientService.cs => ILayerClientService.cs} (51%) create mode 100644 src/IoTHub.Portal.Client/Services/LayerClientService.cs delete mode 100644 src/IoTHub.Portal.Client/Services/LevelClientService.cs rename src/IoTHub.Portal.Domain/Entities/{Level.cs => Layer.cs} (74%) rename src/IoTHub.Portal.Domain/Repositories/{ILevelRepository.cs => ILayerRepository.cs} (79%) rename src/IoTHub.Portal.Infrastructure/Repositories/{LevelRepository.cs => LayerRepository.cs} (69%) rename src/IoTHub.Portal.Infrastructure/Services/{LevelService.cs => LayerService.cs} (76%) rename src/IoTHub.Portal.Server/Controllers/v1.0/{LevelsController.cs => LayersController.cs} (74%) rename src/IoTHub.Portal.Shared/Models/v1.0/{LevelDto.cs => LayerDto.cs} (83%) diff --git a/src/IoTHub.Portal.Application/Mappers/LevelProfile.cs b/src/IoTHub.Portal.Application/Mappers/LayerProfile.cs similarity index 76% rename from src/IoTHub.Portal.Application/Mappers/LevelProfile.cs rename to src/IoTHub.Portal.Application/Mappers/LayerProfile.cs index 80d513ccc..ea4702a6e 100644 --- a/src/IoTHub.Portal.Application/Mappers/LevelProfile.cs +++ b/src/IoTHub.Portal.Application/Mappers/LayerProfile.cs @@ -7,11 +7,11 @@ namespace IoTHub.Portal.Infrastructure.Mappers using IoTHub.Portal.Domain.Entities; using IoTHub.Portal.Shared.Models.v10; - public class LevelProfile : Profile + public class LayerProfile : Profile { - public LevelProfile() + public LayerProfile() { - _ = CreateMap() + _ = CreateMap() .ReverseMap(); } } diff --git a/src/IoTHub.Portal.Application/Services/ILevelService.cs b/src/IoTHub.Portal.Application/Services/ILayerService.cs similarity index 55% rename from src/IoTHub.Portal.Application/Services/ILevelService.cs rename to src/IoTHub.Portal.Application/Services/ILayerService.cs index 4906444c5..71ad0d565 100644 --- a/src/IoTHub.Portal.Application/Services/ILevelService.cs +++ b/src/IoTHub.Portal.Application/Services/ILayerService.cs @@ -7,12 +7,12 @@ namespace IoTHub.Portal.Application.Services using IoTHub.Portal.Domain.Entities; using IoTHub.Portal.Shared.Models.v10; - public interface ILevelService + public interface ILayerService { - Task CreateLevel(LevelDto level); - Task UpdateLevel(LevelDto level); - Task DeleteLevel(string levelId); - Task GetLevel(string levelId); - Task> GetLevels(); + Task CreateLayer(LayerDto level); + Task UpdateLayer(LayerDto level); + Task DeleteLayer(string levelId); + Task GetLayer(string levelId); + Task> GetLayers(); } } diff --git a/src/IoTHub.Portal.Client/Program.cs b/src/IoTHub.Portal.Client/Program.cs index 6ae028a5f..3c8e6d791 100644 --- a/src/IoTHub.Portal.Client/Program.cs +++ b/src/IoTHub.Portal.Client/Program.cs @@ -84,7 +84,7 @@ _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); -_ = builder.Services.AddScoped(); +_ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); _ = builder.Services.AddScoped(); diff --git a/src/IoTHub.Portal.Client/Services/ILevelClientService.cs b/src/IoTHub.Portal.Client/Services/ILayerClientService.cs similarity index 51% rename from src/IoTHub.Portal.Client/Services/ILevelClientService.cs rename to src/IoTHub.Portal.Client/Services/ILayerClientService.cs index b9063a5a1..0e734e18d 100644 --- a/src/IoTHub.Portal.Client/Services/ILevelClientService.cs +++ b/src/IoTHub.Portal.Client/Services/ILayerClientService.cs @@ -6,12 +6,12 @@ namespace IoTHub.Portal.Client.Services using System.Threading.Tasks; using IoTHub.Portal.Shared.Models.v10; - public interface ILevelClientService + public interface ILayerClientService { - Task CreateLevel(LevelDto level); - Task UpdateLevel(LevelDto level); - Task DeleteLevel(string modelId); - Task GetLevel(string levelId); - Task> GetLevels(); + Task CreateLayer(LayerDto layer); + Task UpdateLayer(LayerDto layer); + Task DeleteLayer(string modelId); + Task GetLayer(string layerId); + Task> GetLayers(); } } diff --git a/src/IoTHub.Portal.Client/Services/LayerClientService.cs b/src/IoTHub.Portal.Client/Services/LayerClientService.cs new file mode 100644 index 000000000..4cf7a5a4b --- /dev/null +++ b/src/IoTHub.Portal.Client/Services/LayerClientService.cs @@ -0,0 +1,52 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Services +{ + using System.Net.Http; + using System.Net.Http.Json; + using System.Threading.Tasks; + using IoTHub.Portal.Shared.Models.v10; + + public class LayerClientService : ILayerClientService + { + private readonly HttpClient http; + private readonly string apiUrlBase = "api/building"; + + public LayerClientService(HttpClient http) + { + this.http = http; + } + + public async Task CreateLayer(LayerDto layer) + { + var response = await this.http.PostAsJsonAsync(this.apiUrlBase, layer); + + //Retrieve Layer ID + var responseJson = await response.Content.ReadAsStringAsync(); + var updatedLayer = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); + + return updatedLayer.Id.ToString(); + } + + public Task UpdateLayer(LayerDto layer) + { + return this.http.PutAsJsonAsync(this.apiUrlBase, layer); + } + + public Task DeleteLayer(string layerId) + { + return this.http.DeleteAsync($"{this.apiUrlBase}/{layerId}"); + } + + public Task GetLayer(string layerId) + { + return this.http.GetFromJsonAsync($"{this.apiUrlBase}/{layerId}")!; + } + + public async Task> GetLayers() + { + return await this.http.GetFromJsonAsync>(this.apiUrlBase) ?? new List(); + } + } +} diff --git a/src/IoTHub.Portal.Client/Services/LevelClientService.cs b/src/IoTHub.Portal.Client/Services/LevelClientService.cs deleted file mode 100644 index 6f229c08b..000000000 --- a/src/IoTHub.Portal.Client/Services/LevelClientService.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace IoTHub.Portal.Client.Services -{ - using System.Net.Http; - using System.Net.Http.Json; - using System.Threading.Tasks; - using IoTHub.Portal.Shared.Models.v10; - - public class LevelClientService : ILevelClientService - { - private readonly HttpClient http; - private readonly string apiUrlBase = "api/building"; - - public LevelClientService(HttpClient http) - { - this.http = http; - } - - public async Task CreateLevel(LevelDto level) - { - var response = await this.http.PostAsJsonAsync(this.apiUrlBase, level); - - //Retrieve Level ID - var responseJson = await response.Content.ReadAsStringAsync(); - var updatedLevel = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); - - return updatedLevel.Id.ToString(); - } - - public Task UpdateLevel(LevelDto level) - { - return this.http.PutAsJsonAsync(this.apiUrlBase, level); - } - - public Task DeleteLevel(string levelId) - { - return this.http.DeleteAsync($"{this.apiUrlBase}/{levelId}"); - } - - public Task GetLevel(string levelId) - { - return this.http.GetFromJsonAsync($"{this.apiUrlBase}/{levelId}")!; - } - - public async Task> GetLevels() - { - return await this.http.GetFromJsonAsync>(this.apiUrlBase) ?? new List(); - } - } -} diff --git a/src/IoTHub.Portal.Domain/Entities/Level.cs b/src/IoTHub.Portal.Domain/Entities/Layer.cs similarity index 74% rename from src/IoTHub.Portal.Domain/Entities/Level.cs rename to src/IoTHub.Portal.Domain/Entities/Layer.cs index eaed9e8ad..5c3089877 100644 --- a/src/IoTHub.Portal.Domain/Entities/Level.cs +++ b/src/IoTHub.Portal.Domain/Entities/Layer.cs @@ -5,10 +5,10 @@ namespace IoTHub.Portal.Domain.Entities { using IoTHub.Portal.Domain.Base; - public class Level : EntityBase + public class Layer : EntityBase { /// - /// The Level friendly name. + /// The Layer friendly name. /// public string Name { get; set; } = default!; @@ -22,5 +22,10 @@ public class Level : EntityBase /// public string Planning { get; set; } = default!; + /// + /// The planning has a subLayer. + /// + public bool hasSub { get; set; } = default!; + } } diff --git a/src/IoTHub.Portal.Domain/Repositories/ILevelRepository.cs b/src/IoTHub.Portal.Domain/Repositories/ILayerRepository.cs similarity index 79% rename from src/IoTHub.Portal.Domain/Repositories/ILevelRepository.cs rename to src/IoTHub.Portal.Domain/Repositories/ILayerRepository.cs index f62c58c34..3510cd6a7 100644 --- a/src/IoTHub.Portal.Domain/Repositories/ILevelRepository.cs +++ b/src/IoTHub.Portal.Domain/Repositories/ILayerRepository.cs @@ -5,7 +5,7 @@ namespace IoTHub.Portal.Domain.Repositories { using Entities; - public interface ILevelRepository : IRepository + public interface ILayerRepository : IRepository { } } diff --git a/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs b/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs index b8d9bc8d3..58e54d875 100644 --- a/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs +++ b/src/IoTHub.Portal.Infrastructure/PortalDbContext.cs @@ -12,7 +12,7 @@ public class PortalDbContext : DbContext, IDataProtectionKeyContext { public DbSet DeviceModelProperties { get; set; } public DbSet DeviceTags { get; set; } - public DbSet Levels { get; set; } + public DbSet Layers { get; set; } public DbSet Plannings { get; set; } public DbSet Schedules { get; set; } public DbSet DeviceModelCommands { get; set; } diff --git a/src/IoTHub.Portal.Infrastructure/Repositories/LevelRepository.cs b/src/IoTHub.Portal.Infrastructure/Repositories/LayerRepository.cs similarity index 69% rename from src/IoTHub.Portal.Infrastructure/Repositories/LevelRepository.cs rename to src/IoTHub.Portal.Infrastructure/Repositories/LayerRepository.cs index 833a064ca..690dd11af 100644 --- a/src/IoTHub.Portal.Infrastructure/Repositories/LevelRepository.cs +++ b/src/IoTHub.Portal.Infrastructure/Repositories/LayerRepository.cs @@ -7,9 +7,9 @@ namespace IoTHub.Portal.Infrastructure.Repositories using IoTHub.Portal.Domain.Repositories; using Domain.Entities; - public class LevelRepository : GenericRepository, ILevelRepository + public class LayerRepository : GenericRepository, ILayerRepository { - public LevelRepository(PortalDbContext context) : base(context) + public LayerRepository(PortalDbContext context) : base(context) { } } diff --git a/src/IoTHub.Portal.Infrastructure/Services/LevelService.cs b/src/IoTHub.Portal.Infrastructure/Services/LayerService.cs similarity index 76% rename from src/IoTHub.Portal.Infrastructure/Services/LevelService.cs rename to src/IoTHub.Portal.Infrastructure/Services/LayerService.cs index 4b53db819..ca72a38af 100644 --- a/src/IoTHub.Portal.Infrastructure/Services/LevelService.cs +++ b/src/IoTHub.Portal.Infrastructure/Services/LayerService.cs @@ -13,15 +13,15 @@ namespace IoTHub.Portal.Infrastructure.Services using IoTHub.Portal.Domain.Exceptions; using IoTHub.Portal.Infrastructure.Repositories; - public class LevelService : ILevelService + public class LayerService : ILayerService { private readonly IMapper mapper; private readonly IUnitOfWork unitOfWork; - private readonly ILevelRepository levelRepository; + private readonly ILayerRepository levelRepository; - public LevelService(IMapper mapper, + public LayerService(IMapper mapper, IUnitOfWork unitOfWork, - ILevelRepository levelRepository) + ILayerRepository levelRepository) { this.mapper = mapper; this.unitOfWork = unitOfWork; @@ -31,11 +31,11 @@ public LevelService(IMapper mapper, /// /// Create a level. /// - /// Level - /// Level object. - public async Task CreateLevel(LevelDto level) + /// Layer + /// Layer object. + public async Task CreateLayer(LayerDto level) { - var levelEntity = this.mapper.Map(level); + var levelEntity = this.mapper.Map(level); await this.levelRepository.InsertAsync(levelEntity); await this.unitOfWork.SaveAsync(); @@ -49,7 +49,7 @@ public async Task CreateLevel(LevelDto level) /// The level. /// nothing. /// - public async Task UpdateLevel(LevelDto level) + public async Task UpdateLayer(LayerDto level) { var levelEntity = await this.levelRepository.GetByIdAsync(level.Id); @@ -71,7 +71,7 @@ public async Task UpdateLevel(LevelDto level) /// The level indentifier. /// /// - public async Task DeleteLevel(string levelId) + public async Task DeleteLayer(string levelId) { var levelEntity = await this.levelRepository.GetByIdAsync(levelId); if (levelEntity == null) @@ -88,8 +88,8 @@ public async Task DeleteLevel(string levelId) /// Get level. /// /// level id. - /// Level object. - public async Task GetLevel(string levelId) + /// Layer object. + public async Task GetLayer(string levelId) { var levelEntity = await this.levelRepository.GetByIdAsync(levelId); @@ -98,7 +98,7 @@ public async Task GetLevel(string levelId) throw new ResourceNotFoundException($"The level with id {levelId} doesn't exist"); } - var level = this.mapper.Map(levelEntity); + var level = this.mapper.Map(levelEntity); return level; } @@ -106,17 +106,17 @@ public async Task GetLevel(string levelId) /// /// Return the level list. /// - /// IEnumerable LevelDto. - public async Task> GetLevels() + /// IEnumerable LayerDto. + public async Task> GetLayers() { - var levelPredicate = PredicateBuilder.True(); + var levelPredicate = PredicateBuilder.True(); var levels = await this.levelRepository.GetAllAsync(); return levels .Select(model => { - var levelListItem = this.mapper.Map(model); + var levelListItem = this.mapper.Map(model); return levelListItem; }) .ToList(); diff --git a/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs b/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs index bf5770359..3e9f0b804 100644 --- a/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs +++ b/src/IoTHub.Portal.Infrastructure/Startup/IServiceCollectionExtension.cs @@ -103,7 +103,7 @@ private static IServiceCollection ConfigureRepositories(this IServiceCollection .AddScoped() .AddScoped() .AddScoped() - .AddScoped() + .AddScoped() .AddScoped() .AddScoped() .AddScoped() @@ -116,7 +116,7 @@ private static IServiceCollection ConfigureServices(this IServiceCollection serv .AddTransient() .AddTransient() .AddTransient() - .AddTransient() + .AddTransient() .AddTransient() .AddTransient() .AddTransient(); diff --git a/src/IoTHub.Portal.Server/Controllers/v1.0/LevelsController.cs b/src/IoTHub.Portal.Server/Controllers/v1.0/LayersController.cs similarity index 74% rename from src/IoTHub.Portal.Server/Controllers/v1.0/LevelsController.cs rename to src/IoTHub.Portal.Server/Controllers/v1.0/LayersController.cs index d43e2caf7..d22d3003c 100644 --- a/src/IoTHub.Portal.Server/Controllers/v1.0/LevelsController.cs +++ b/src/IoTHub.Portal.Server/Controllers/v1.0/LayersController.cs @@ -20,11 +20,11 @@ namespace IoTHub.Portal.Server.Controllers.V10 [ApiVersion("1.0")] [Route("api/building")] [ApiExplorerSettings(GroupName = "IoT Building")] - public class LevelsController : ControllerBase + public class LayersController : ControllerBase { - private readonly ILevelService levelService; + private readonly ILayerService levelService; - public LevelsController(ILevelService levelService) + public LayersController(ILayerService levelService) { this.levelService = levelService; } @@ -34,7 +34,7 @@ public LevelsController(ILevelService levelService) /// /// The level. [HttpPost(Name = "POST Create level")] - public async Task CreateLevelAsync(LevelDto level) + public async Task CreateLayerAsync(LayerDto level) { ArgumentNullException.ThrowIfNull(level, nameof(level)); @@ -48,7 +48,7 @@ public async Task CreateLevelAsync(LevelDto level) throw new ProblemDetailsException(validation); } - _ = await this.levelService.CreateLevel(level); + _ = await this.levelService.CreateLayer(level); return Ok(level); } @@ -56,13 +56,13 @@ public async Task CreateLevelAsync(LevelDto level) /// /// Updates the specified level. /// - /// The level. + /// The level. /// The action result. [HttpPut(Name = "PUT Update the level")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task UpdateLevel(LevelDto Level) + public async Task UpdateLayer(LayerDto Layer) { - await this.levelService.UpdateLevel(Level); + await this.levelService.UpdateLayer(Layer); return Ok(); } @@ -74,9 +74,9 @@ public async Task UpdateLevel(LevelDto Level) /// Http response /// [HttpDelete("{levelId}", Name = "DELETE Remove the level")] - public async Task DeleteLevel(string levelId) + public async Task DeleteLayer(string levelId) { - await this.levelService.DeleteLevel(levelId); + await this.levelService.DeleteLayer(levelId); return NoContent(); } @@ -85,13 +85,13 @@ public async Task DeleteLevel(string levelId) /// Gets the specified level. /// /// The level identifier. - [HttpGet("{levelId}", Name = "GET Level")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(LevelDto))] - public async Task GetLevel(string levelId) + [HttpGet("{levelId}", Name = "GET Layer")] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(LayerDto))] + public async Task GetLayer(string levelId) { try { - return Ok(await this.levelService.GetLevel(levelId)); + return Ok(await this.levelService.GetLayer(levelId)); } catch (DeviceNotFoundException e) { @@ -103,11 +103,11 @@ public async Task GetLevel(string levelId) /// Gets the level list. /// /// An array representing the levels. - [HttpGet(Name = "GET Level list")] + [HttpGet(Name = "GET Layer list")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task>> GetLevels() + public async Task>> GetLayers() { - return Ok(await this.levelService.GetLevels()); + return Ok(await this.levelService.GetLayers()); } } } diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/LevelDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/LayerDto.cs similarity index 83% rename from src/IoTHub.Portal.Shared/Models/v1.0/LevelDto.cs rename to src/IoTHub.Portal.Shared/Models/v1.0/LayerDto.cs index ecb8214ae..ce6213b16 100644 --- a/src/IoTHub.Portal.Shared/Models/v1.0/LevelDto.cs +++ b/src/IoTHub.Portal.Shared/Models/v1.0/LayerDto.cs @@ -7,7 +7,7 @@ namespace IoTHub.Portal.Shared.Models.v10 //using System.ComponentModel.DataAnnotations; - public class LevelDto + public class LayerDto { /// /// The level auto ID. @@ -28,5 +28,10 @@ public class LevelDto /// The planning associat with the level. /// public string Planning { get; set; } = default!; + + /// + /// The planning has a subLayer. + /// + public bool hasSub { get; set; } = default!; } } From 7d1c92cea8fabbed88479798883dbf36253ad448 Mon Sep 17 00:00:00 2001 From: lucas-mrq Date: Fri, 22 Mar 2024 14:59:50 +0100 Subject: [PATCH 005/120] Update Planning & Schedule --- src/IoTHub.Portal.Domain/Entities/Planning.cs | 4 ++-- src/IoTHub.Portal.Domain/Entities/Schedule.cs | 4 ++-- src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs | 4 ++-- src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/IoTHub.Portal.Domain/Entities/Planning.cs b/src/IoTHub.Portal.Domain/Entities/Planning.cs index 452438f48..8ee2816c0 100644 --- a/src/IoTHub.Portal.Domain/Entities/Planning.cs +++ b/src/IoTHub.Portal.Domain/Entities/Planning.cs @@ -30,12 +30,12 @@ public class Planning : EntityBase /// /// When planning is used /// - public string DayOff { get; set; } = default!; + public string Day { get; set; } = default!; /// /// Day off command. /// - public int CommandOff { get; set; } = default!; + public string CommandId { get; set; } = default!; } } diff --git a/src/IoTHub.Portal.Domain/Entities/Schedule.cs b/src/IoTHub.Portal.Domain/Entities/Schedule.cs index 5995df0e3..9e5647f84 100644 --- a/src/IoTHub.Portal.Domain/Entities/Schedule.cs +++ b/src/IoTHub.Portal.Domain/Entities/Schedule.cs @@ -20,12 +20,12 @@ public class Schedule : EntityBase /// /// The planning associat with the schedule. /// - public int Command { get; set; } = default!; + public string CommandId { get; set; } = default!; /// /// The planning associat with the schedule. /// - public string Planning { get; set; } = default!; + public string PlanningId { get; set; } = default!; } } diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs index 54a8e043e..89c88317e 100644 --- a/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs +++ b/src/IoTHub.Portal.Shared/Models/v1.0/PlanningDto.cs @@ -37,11 +37,11 @@ public class PlanningDto /// /// When planning is used /// - public string DayOff { get; set; } = default!; + public string Day { get; set; } = ""; /// /// Day off command. /// - public int CommandOff { get; set; } = default!; + public string CommandId { get; set; } = default!; } } diff --git a/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs b/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs index f82c0173b..3a9577414 100644 --- a/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs +++ b/src/IoTHub.Portal.Shared/Models/v1.0/ScheduleDto.cs @@ -27,11 +27,11 @@ public class ScheduleDto /// /// The planning associat with the schedule. /// - public int Command { get; set; } = 19; + public string CommandId { get; set; } = default!; /// /// The planning associat with the schedule. /// - public string Planning { get; set; } = default!; + public string PlanningId { get; set; } = default!; } } From 3bbba22fb9583fc565adb58f5c2c5700c09d3936 Mon Sep 17 00:00:00 2001 From: lucas-mrq Date: Fri, 5 Apr 2024 16:41:47 +0200 Subject: [PATCH 006/120] Add Planning Management --- .../Services/IDeviceService.cs | 3 +- .../Services/ISendPlanningCommandService.cs | 10 + .../Components/Layers/EditLayer.razor | 174 +++++++ .../Components/Planning/EditPlanning.razor | 414 +++++++++++++++++ .../Dialogs/Building/DeleteLayerDialog.razor | 41 ++ .../Devices/LinkDeviceLayerDialog.razor | 183 ++++++++ src/IoTHub.Portal.Client/Models/LayerHash.cs | 22 + .../Models/RoomSearchInfo.cs | 10 + .../Pages/Layer/CreateLayerPage.razor | 19 + .../Pages/Layer/LayerDetailsPage.razor | 78 ++++ .../Pages/Layer/LayerListPage.razor | 194 ++++++++ .../Pages/Layer/ThermoDeviceListPage.razor | 431 ++++++++++++++++++ .../Pages/Planning/CreatePlanningsPage.razor | 19 + .../Pages/Planning/PlanningDetailsPage.razor | 30 ++ .../Pages/Planning/PlanningListPage.razor | 135 ++++++ .../Pages/Settings/Layers.razor | 16 + src/IoTHub.Portal.Client/Shared/NavMenu.razor | 8 + src/IoTHub.Portal.Domain/Entities/Device.cs | 5 + src/IoTHub.Portal.Domain/Entities/IDevice.cs | 5 + src/IoTHub.Portal.Domain/Entities/Planning.cs | 5 + .../Repositories/ILayerRepository.cs | 1 + .../Repositories/LayerRepository.cs | 6 + .../Services/DeviceServiceBase.cs | 8 +- .../IoTHub.Portal.Server.csproj | 1 + .../Services/SendPlanningCommandService.cs | 388 ++++++++++++++++ .../Models/v1.0/DeviceDetails.cs | 5 + .../Models/v1.0/DeviceListItem.cs | 5 + .../Models/v1.0/Filters/DeviceListFilter.cs | 2 + .../Models/v1.0/Filters/RoomFilter.cs | 11 + .../Models/v1.0/IDeviceDetails.cs | 5 + .../Models/v1.0/LoRaWAN/LoRaDeviceDetails.cs | 5 + .../Models/v1.0/PlanningDto.cs | 5 + 32 files changed, 2240 insertions(+), 4 deletions(-) create mode 100644 src/IoTHub.Portal.Application/Services/ISendPlanningCommandService.cs create mode 100644 src/IoTHub.Portal.Client/Components/Layers/EditLayer.razor create mode 100644 src/IoTHub.Portal.Client/Components/Planning/EditPlanning.razor create mode 100644 src/IoTHub.Portal.Client/Dialogs/Building/DeleteLayerDialog.razor create mode 100644 src/IoTHub.Portal.Client/Dialogs/Devices/LinkDeviceLayerDialog.razor create mode 100644 src/IoTHub.Portal.Client/Models/LayerHash.cs create mode 100644 src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs create mode 100644 src/IoTHub.Portal.Client/Pages/Layer/CreateLayerPage.razor create mode 100644 src/IoTHub.Portal.Client/Pages/Layer/LayerDetailsPage.razor create mode 100644 src/IoTHub.Portal.Client/Pages/Layer/LayerListPage.razor create mode 100644 src/IoTHub.Portal.Client/Pages/Layer/ThermoDeviceListPage.razor create mode 100644 src/IoTHub.Portal.Client/Pages/Planning/CreatePlanningsPage.razor create mode 100644 src/IoTHub.Portal.Client/Pages/Planning/PlanningDetailsPage.razor create mode 100644 src/IoTHub.Portal.Client/Pages/Planning/PlanningListPage.razor create mode 100644 src/IoTHub.Portal.Client/Pages/Settings/Layers.razor create mode 100644 src/IoTHub.Portal.Server/Services/SendPlanningCommandService.cs create mode 100644 src/IoTHub.Portal.Shared/Models/v1.0/Filters/RoomFilter.cs diff --git a/src/IoTHub.Portal.Application/Services/IDeviceService.cs b/src/IoTHub.Portal.Application/Services/IDeviceService.cs index 63af1d0ea..8c45e13fb 100644 --- a/src/IoTHub.Portal.Application/Services/IDeviceService.cs +++ b/src/IoTHub.Portal.Application/Services/IDeviceService.cs @@ -23,7 +23,8 @@ Task> GetDevices( string[]? orderBy = null, Dictionary? tags = default, string? modelId = null, - List? labels = default); + List? labels = default, + string? layerId = null); Task GetDevice(string deviceId); diff --git a/src/IoTHub.Portal.Application/Services/ISendPlanningCommandService.cs b/src/IoTHub.Portal.Application/Services/ISendPlanningCommandService.cs new file mode 100644 index 000000000..d493bafc9 --- /dev/null +++ b/src/IoTHub.Portal.Application/Services/ISendPlanningCommandService.cs @@ -0,0 +1,10 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Application.Services +{ + public interface ISendPlanningCommandService + { + void ShoudlUpdateDatabase(); + } +} diff --git a/src/IoTHub.Portal.Client/Components/Layers/EditLayer.razor b/src/IoTHub.Portal.Client/Components/Layers/EditLayer.razor new file mode 100644 index 000000000..aff172fe6 --- /dev/null +++ b/src/IoTHub.Portal.Client/Components/Layers/EditLayer.razor @@ -0,0 +1,174 @@ +@using IoTHub.Portal.Client.Dialogs.EdgeModels.EdgeModule +@using IoTHub.Portal.Models +@using IoTHub.Portal.Models.v10 +@using IoTHub.Portal.Shared.Models.v10 +@using IoTHub.Portal.Client.Validators +@using System.Net.Http.Headers +@using IoTHub.Portal.Shared.Constants +@using IoTHub.Portal.Client.Models +@using IoTHub.Portal.Client.Dialogs.Devices; + +@attribute [Authorize] +@inject NavigationManager NavigationManager +@inject PortalSettings Portal + +@inject ILayerClientService LayerClientService +@inject IDialogService DialogService +@inject ISnackbar Snackbar + + + @mode Layer + Save + + + + + + + +
+
+ @if (editItem == item.LayerData.Id) + { + + } + else + { + @item.LayerData.Name + + } +
+
+ @if (printDetails == item.LayerData.Id) + { + + + + } + +
+
+
+
+
+
+
+
+ +@code { + public List LAYER_NAMES = new List() { "Main Layer", "Sub-Layer 1", "Sub-Layer 2" }; + + [CascadingParameter] + public Error Error { get; set; } = default!; + + [Parameter] + public string mode { get; set; } = default!; + [Parameter] + public HashSet layers { get; set; } = new HashSet { }; + [Parameter] + public List initLayers { get; set; } = new List(); + public List deleteLayers { get; set; } = new List(); + + public string printDetails { get; set; } = "Init"; + public string editItem { get; set; } = ""; + + public void AddLayer(LayerHash layer) + { + try + { + if (layer.Level + 1 <= LAYER_NAMES.Count()) + { + LayerDto newLayer = new LayerDto(); + newLayer.Name = "New Layer"; + newLayer.Father = layer.LayerData.Id; + layer.Children.Add(new LayerHash(newLayer, layer.Level + 1, false)); + layer.IsExpanded = true; + } + + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + } + + public void DeleteLayer(LayerHash delLayer, HashSet fatherLayers) + { + foreach (LayerHash layer in fatherLayers) + { + if (layer.Children.Contains(delLayer)) + { + RemoveChild(delLayer); + layer.Children.Remove(delLayer); + } + else + { + DeleteLayer(delLayer, layer.Children); + } + } + } + + public void RemoveChild(LayerHash delLayer) + { + if (delLayer.Children.Count() != 0) + foreach (LayerHash layer in delLayer.Children) RemoveChild(layer); + + deleteLayers.AddRange(initLayers.Where(obj => obj.Id == delLayer.LayerData.Id).ToList()); + } + + public async Task Save(HashSet layerHash, bool quit) + { + await SaveLayer(layerHash, true); + foreach (LayerDto layer in deleteLayers) + { + await LayerClientService.DeleteLayer(layer.Id); + } + if (quit) NavigationManager.NavigateTo($"/layer"); + } + + public async Task SaveLayer(HashSet layerHash, bool isFirst = false) + { + try + { + foreach (LayerHash layer in layerHash) + { + if (initLayers.Any(obj => obj.Id == layer.LayerData.Id)) + { + await LayerClientService.UpdateLayer(layer.LayerData); + } + else + { + layer.LayerData.Planning = "None"; + await LayerClientService.CreateLayer(layer.LayerData); + } + + await SaveLayer(layer.Children); + } + + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + } + + public async void OpenDevices(LayerDto layer) + { + await Save(layers, false); + + var parameter = new DialogParameters { { "Layer", layer } }; + + DialogOptions options = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, CloseOnEscapeKey = true, CloseButton = true }; + + var result = await DialogService.Show("Select your " + layer.Name + " devices", parameter, options).Result; + } + + void HandleKeyPress(KeyboardEventArgs e) + { + if (e.Key == "Enter" || e.Key == "Escape") + { + editItem = ""; + } + } +} + diff --git a/src/IoTHub.Portal.Client/Components/Planning/EditPlanning.razor b/src/IoTHub.Portal.Client/Components/Planning/EditPlanning.razor new file mode 100644 index 000000000..cc00832f8 --- /dev/null +++ b/src/IoTHub.Portal.Client/Components/Planning/EditPlanning.razor @@ -0,0 +1,414 @@ +@using IoTHub.Portal.Client.Dialogs.EdgeModels.EdgeModule +@using IoTHub.Portal.Models +@using IoTHub.Portal.Models.v10 +@using IoTHub.Portal.Shared.Models.v10 +@using IoTHub.Portal.Client.Validators +@using System.Net.Http.Headers +@using IoTHub.Portal.Shared.Constants +@using IoTHub.Portal.Client.Models +@using IoTHub.Portal.Shared.Models +@using IoTHub.Portal.Shared.Models.v10.Filters +@using IoTHub.Portal.Models.v10.LoRaWAN + +@attribute [Authorize] +@inject NavigationManager NavigationManager +@inject PortalSettings Portal + +@inject IPlanningClientService PlanningClientService +@inject IScheduleClientService ScheduleClientService +@inject ILayerClientService LayerClientService +@inject IDeviceModelsClientService DeviceModelsClientService +@inject ILoRaWanDeviceModelsClientService LoRaWanDeviceModelsClientService +@inject IDialogService DialogService +@inject ISnackbar Snackbar + + + @mode Planning + Save + +@if (!isProcessing) +{ + + + + Details + + + + + + + + @foreach (string model in CommandDictionary.Keys.ToList()) + { + @model + } + + + + + + + + + + + Business Day + + + + + + + + + + + From + To + Command + Delete + + + + + + + + + + + @foreach (var command in CommandDictionary[SelectedModel]) + { + @command.Name + } + + + + + + + + Add slot + + +
+ Days: + @foreach (string day in AvailableDay) + { + @day + } +
+
+
+
+
+
+ + + + Off Day + + + + + + + + + + + From + To + Command + Delete + + + + + + + + + + + @foreach (var command in CommandDictionary[SelectedModel]) + { + @command.Name + } + + + + + + + +
+ Days: + @foreach (string day in AvailableDay) + { + @day + } +
+
+
+
+
+
+ + + + Date of application of this planning + + + + @foreach (string month in AvailableMonth) + { + @month + } + + + + + @foreach (string month in AvailableMonth) + { + @month + } + + + + + + + + + + Select your application areas + + + + + + + + + @context.LayerData.Name + + + + + + + + + +} + +@code { + [CascadingParameter] + public Error Error { get; set; } = default!; + + [Parameter] + public string mode { get; set; } = default!; + [Parameter] + public List scheduleList { get; set; } = new List { }; + [Parameter] + public List initScheduleList { get; set; } = new List { }; + [Parameter] + public PlanningDto planning { get; set; } = new PlanningDto(); + [Parameter] + public string SelectedModel { get; set; } = ""; + + public List scheduleOffList { get; set; } = new List { new ScheduleDto() }; + + public IEnumerable AvailableMonth { get; set; } = new List() { "January", "February", "March", "April", "Mai", "June", "July", "August", "September", "October", "Novembre", "December" }; + public IEnumerable AvailableDay { get; set; } = new List() { "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su" }; + + public IEnumerable DeviceModels = new List(); + Dictionary> CommandDictionary = new Dictionary>(); + + private MudForm form = default!; + private bool isProcessing; + + public HashSet Layers { get; set; } = new HashSet { }; + + protected override async Task OnInitializedAsync() + { + try + { + isProcessing = true; + + if (planning.CommandId == null) SelectedModel = "Choose a Device Model"; + + CommandDictionary.Add("Choose a Device Model", new List()); + + List listLayers = await LayerClientService.GetLayers(); + ReloadSubLayers(listLayers); + + var filter = new DeviceModelFilter + { + SearchText = "", + PageNumber = 0, + PageSize = 100, + OrderBy = new string[] + { + string.Empty + } + }; + DeviceModels = (await DeviceModelsClientService.GetDeviceModels(filter)).Items.ToList(); + foreach(var deviceModel in DeviceModels) + { + IList commandList = await LoRaWanDeviceModelsClientService.GetDeviceModelCommands(deviceModel.ModelId); + CommandDictionary.Add(deviceModel.Name, new List(commandList)); + + foreach(var command in commandList) + { + if (command.Id == planning.CommandId) + { + SelectedModel = deviceModel.Name; + } + } + } + CommandDictionary = CommandDictionary.Where(commands => commands.Value.Any() || commands.Key == "Choose a Device Model").ToDictionary(commands => commands.Key, commands => commands.Value); + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + finally + { + isProcessing = false; + } + } + + private void DeleteSchedule(ScheduleDto schedule) + { + if (scheduleList.Count > 1) scheduleList.Remove(schedule); + } + + private void AddSchedule() + { + var last = scheduleList.LastOrDefault(); + + if (scheduleList.Count == 0 || (last?.Start is not null && last?.End is not null && last?.CommandId is not null)) + { + ScheduleDto newSchedule = new ScheduleDto(); + scheduleList.Add(newSchedule); + } + } + + private void ChangeOffDay(string day) + { + string days = planning.Day; + if (days.Contains(day)) days.Replace(day, ""); + else days += day; + planning.Day = days; + StateHasChanged(); + } + + public async void Save() + { + await SavePlanning(); + await SaveLayers(Layers); + NavigationManager.NavigateTo($"/planning"); + } + + public async Task SavePlanning() + { + try + { + planning.DayExceptions = "None"; + if (mode == "New") await PlanningClientService.CreatePlanning(planning); + else await PlanningClientService.UpdatePlanning(planning); + foreach (ScheduleDto schedule in scheduleList) + { + schedule.PlanningId = planning.Id; + + if (initScheduleList.Any(obj => obj.Id == schedule.Id)) + { + await ScheduleClientService.UpdateSchedule(schedule); + } + else + { + await ScheduleClientService.CreateSchedule(schedule); + } + } + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + } + + protected void CheckedChanged(LayerHash item) + { + if (item.LayerData.Planning == planning.Id) item.LayerData.Planning = "None"; + else item.LayerData.Planning = planning.Id; + + if (item.Children.Count() != 0) + { + foreach (LayerHash child in item.Children) + { + CheckedChanged(child); + } + } + } + + private void ReloadSubLayers(List layers) + { + if (layers.Count() == 0) return; + + LayerDto firstLayer = layers[0]; + bool isAdd = false; + + if (firstLayer.Father == "Init") + { + Layers.Add(new LayerHash(firstLayer, 0, false)); + isAdd = true; + } + else isAdd = addSubLayer(Layers, firstLayer); + + layers.RemoveAt(0); + if (!isAdd) layers.Add(firstLayer); + + if (layers.Count() != 0) ReloadSubLayers(layers); + } + + private bool addSubLayer(HashSet childLayers, LayerDto layer) + { + foreach (LayerHash subLayer in childLayers) + { + if (subLayer.LayerData.Id == layer.Father) + { + subLayer.Children.Add(new LayerHash(layer, 0, false)); + return true; + } + else + { + bool isAdd = addSubLayer(subLayer.Children, layer); + if (isAdd) return true; + } + } + return false; + } + + public async Task SaveLayers(HashSet saveLayers) + { + try + { + foreach (LayerHash layer in saveLayers) + { + await LayerClientService.UpdateLayer(layer.LayerData); + + if (layer.Children.Count() != 0) + { + await SaveLayers(layer.Children); + } + } + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + } +} diff --git a/src/IoTHub.Portal.Client/Dialogs/Building/DeleteLayerDialog.razor b/src/IoTHub.Portal.Client/Dialogs/Building/DeleteLayerDialog.razor new file mode 100644 index 000000000..26091ff9b --- /dev/null +++ b/src/IoTHub.Portal.Client/Dialogs/Building/DeleteLayerDialog.razor @@ -0,0 +1,41 @@ +@inject ISnackbar Snackbar +@inject ILayerClientService LayerService + + + +

Delete @layerName ?

+
+

Warning : this cannot be undone.

+
+ + Cancel + Delete + +
+ +@code { + [CascadingParameter] + public Error Error { get; set; } = default!; + + [CascadingParameter] MudDialogInstance MudDialog { get; set; } = default!; + [Parameter] public string layerId { get; set; } = default!; + [Parameter] public string layerName { get; set; } = default!; + + void Submit() => MudDialog.Close(DialogResult.Ok(true)); + void Cancel() => MudDialog.Cancel(); + + private async Task DeleteModel() + { + try + { + await this.LayerService.DeleteLayer(layerId); + + Snackbar.Add($"Device model {layerName} has been successfully deleted!", Severity.Success); + MudDialog.Close(DialogResult.Ok(true)); + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + } +} diff --git a/src/IoTHub.Portal.Client/Dialogs/Devices/LinkDeviceLayerDialog.razor b/src/IoTHub.Portal.Client/Dialogs/Devices/LinkDeviceLayerDialog.razor new file mode 100644 index 000000000..2a793f83a --- /dev/null +++ b/src/IoTHub.Portal.Client/Dialogs/Devices/LinkDeviceLayerDialog.razor @@ -0,0 +1,183 @@ +@using IoTHub.Portal.Shared.Models.v10 +@using IoTHub.Portal.Models.v10 +@using IoTHub.Portal.Shared.Models.v10.Filters +@using IoTHub.Portal.Shared.Models + +@inject ISnackbar Snackbar +@inject IEdgeDeviceClientService EdgeDeviceClientService +@inject IDeviceClientService DeviceClientService +@inject IDeviceModelsClientService DeviceModelsClientService + + + + + + @if (!IsLoading) + { +
+ + @foreach (IDeviceModel model in DeviceModels) + { + @model.Name + } + + Search +
+ } + + + + + + + + + Device + + + + + + + + + @context.DeviceName + + + + + @if (context.LayerId == Layer.Id || DeviceList.Contains(context.DeviceID) ) + { + + } + else if (context.LayerId != null) + { + + } + else + { + + } + + + + + No matching records found + + + Loading... + + +
+
+
+ + Cancel + Save + +
+ +@code { + [CascadingParameter] + public Error Error { get; set; } = default!; + + [CascadingParameter] MudDialogInstance MudDialog { get; set; } = default!; + + [Parameter] public LayerDto Layer { get; set; } = default!; + + private MudTable? table; + private IEnumerable Devices { get; set; } = new List(); + + public IDeviceModel SelectedModel = new DeviceModelDto(); + public IEnumerable DeviceModels = new List(); + + public List DeviceList { get; set; } = new List(); + public List DeviceRemoveList { get; set; } = new List(); + + private bool IsLoading { get; set; } = true; + + void Cancel() => MudDialog.Cancel(); + + protected override async Task OnInitializedAsync() + { + var filter = new DeviceModelFilter + { + SearchText = "", + PageNumber = 0, + PageSize = 100, + OrderBy = new string[] + { + string.Empty + } + }; + + DeviceModels = (await DeviceModelsClientService.GetDeviceModels(filter)).Items.ToList(); + + await LoadItems(); + + if (DeviceModels.Count() != 0) SelectedModel = DeviceModels.First(); + + IsLoading = false; + } + + public async Task LoadItems() + { + try + { + string uri = $"api/devices?pageNumber=0&pageSize=1000"; + + if (!IsLoading) uri = uri + "&modelId=" + SelectedModel.ModelId; + + var result = await DeviceClientService.GetDevices(uri); + + Devices = result.Items; + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + } + + public void UpdateChecked(DeviceListItem device) + { + if (device.LayerId == Layer.Id) + { + if (DeviceRemoveList.Contains(device.DeviceID)) DeviceRemoveList.Remove(device.DeviceID); + else DeviceRemoveList.Add(device.DeviceID); + } + else + { + if (DeviceList.Contains(device.DeviceID)) DeviceList.Remove(device.DeviceID); + else DeviceList.Add(device.DeviceID); + } + } + + private async Task SaveDevice() + { + try + { + List devices = new List(); + foreach(string device in DeviceRemoveList) + { + DeviceDetails updatedDevice = await DeviceClientService.GetDevice(device); + updatedDevice.LayerId = null; + await DeviceClientService.UpdateDevice(updatedDevice); + } + foreach (string device in DeviceList) + { + DeviceDetails updatedDevice = await DeviceClientService.GetDevice(device); + updatedDevice.LayerId = Layer.Id; + await DeviceClientService.UpdateDevice(updatedDevice); + } + + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + finally + { + Cancel(); + } + } +} diff --git a/src/IoTHub.Portal.Client/Models/LayerHash.cs b/src/IoTHub.Portal.Client/Models/LayerHash.cs new file mode 100644 index 000000000..90ffbbfa3 --- /dev/null +++ b/src/IoTHub.Portal.Client/Models/LayerHash.cs @@ -0,0 +1,22 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Models +{ + using IoTHub.Portal.Shared.Models.v10; + + public class LayerHash + { + public LayerDto LayerData { get; set; } + public HashSet Children { get; set; } = new HashSet(); + public int Level { get; set; } + public bool IsExpanded { get; set; } + + public LayerHash(LayerDto layerData, int level = 0, bool isExpanded = true) + { + Level = level; + LayerData = layerData; + IsExpanded = isExpanded; + } + } +} diff --git a/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs b/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs new file mode 100644 index 000000000..cee031f63 --- /dev/null +++ b/src/IoTHub.Portal.Client/Models/RoomSearchInfo.cs @@ -0,0 +1,10 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace IoTHub.Portal.Client.Models +{ + public class RoomSearchInfo + { + public string? SearchText { get; set; } + } +} diff --git a/src/IoTHub.Portal.Client/Pages/Layer/CreateLayerPage.razor b/src/IoTHub.Portal.Client/Pages/Layer/CreateLayerPage.razor new file mode 100644 index 000000000..36415372d --- /dev/null +++ b/src/IoTHub.Portal.Client/Pages/Layer/CreateLayerPage.razor @@ -0,0 +1,19 @@ +@page "/layer/new" + +@using IoTHub.Portal.Client.Components.Layers +@using IoTHub.Portal.Shared.Models.v10 + + + +@code { + public HashSet Layers { get; set; } = new HashSet { }; + public List InitLayers = new List(); + + protected override async Task OnInitializedAsync() + { + LayerDto newLayer = new LayerDto(); + newLayer.Name = "Main Layer"; + newLayer.Father = "Init"; + Layers.Add(new LayerHash(newLayer, 1, true)); + } +} diff --git a/src/IoTHub.Portal.Client/Pages/Layer/LayerDetailsPage.razor b/src/IoTHub.Portal.Client/Pages/Layer/LayerDetailsPage.razor new file mode 100644 index 000000000..cd393b03f --- /dev/null +++ b/src/IoTHub.Portal.Client/Pages/Layer/LayerDetailsPage.razor @@ -0,0 +1,78 @@ +@page "/layer/{LayerId}" + +@using IoTHub.Portal.Client.Components.Layers +@using IoTHub.Portal.Shared.Models.v10 + +@inject ILayerClientService LayerClientService + + + +@code { + public HashSet Layers { get; set; } = new HashSet { }; + public HashSet fullLayers { get; set; } = new HashSet { }; + public List InitLayers = new List(); + + [Parameter] + public string LayerId { get; set; } + + protected override async Task OnInitializedAsync() + { + List listLayers = await LayerClientService.GetLayers(); + ReloadSubLayers(listLayers); + + foreach (LayerHash layer in fullLayers) + if (layer.LayerData.Id == LayerId) + { + Layers.Add(layer); + InitLayers.Add(layer.LayerData); + addInitLayer(layer); + } + } + + private void ReloadSubLayers(List layers) + { + if (layers.Count() == 0) return; + + LayerDto firstLayer = layers[0]; + bool isAdd = false; + + if (firstLayer.Father == "Init") + { + fullLayers.Add(new LayerHash(firstLayer, 1)); + isAdd = true; + } + else isAdd = addSubLayer(fullLayers, firstLayer); + + layers.RemoveAt(0); + if (!isAdd) layers.Add(firstLayer); + + if (layers.Count() != 0) ReloadSubLayers(layers); + } + + private bool addSubLayer(HashSet childLayers, LayerDto layer) + { + foreach (LayerHash subLayer in childLayers) + { + if (subLayer.LayerData.Id == layer.Father) + { + subLayer.Children.Add(new LayerHash(layer, subLayer.Level + 1)); + return true; + } + else + { + bool isAdd = addSubLayer(subLayer.Children, layer); + if (isAdd) return true; + } + } + return false; + } + + private void addInitLayer(LayerHash layer) + { + foreach (LayerHash subLayer in layer.Children) + { + InitLayers.Add(subLayer.LayerData); + addInitLayer(subLayer); + } + } +} diff --git a/src/IoTHub.Portal.Client/Pages/Layer/LayerListPage.razor b/src/IoTHub.Portal.Client/Pages/Layer/LayerListPage.razor new file mode 100644 index 000000000..1a6442816 --- /dev/null +++ b/src/IoTHub.Portal.Client/Pages/Layer/LayerListPage.razor @@ -0,0 +1,194 @@ +@page "/layer" + +@using System.Web +@using System.IO +@using System.Text.RegularExpressions +@using System.Net.Http.Headers + +@using Microsoft.AspNetCore.WebUtilities + +@using IoTHub.Portal +@using IoTHub.Portal.Models +@using IoTHub.Portal.Models.v10 +@using IoTHub.Portal.Models.v10.LoRaWAN +@using IoTHub.Portal.Shared.Models +@using IoTHub.Portal.Shared.Constants; +@using IoTHub.Portal.Shared.Models.v10; +@using IoTHub.Portal.Shared.Models.v10.Filters +@using IoTHub.Portal.Client.Enums +@using IoTHub.Portal.Client.Validators +@using IoTHub.Portal.Client.Pages.Devices +@using IoTHub.Portal.Client.Dialogs.Devices +@using IoTHub.Portal.Client.Dialogs.Building + +@attribute [Authorize] + +@inject NavigationManager navigationManager +@inject PortalSettings Portal +@inject ILayerClientService LayerClientService +@inject IPlanningClientService PlanningClientService +@inject IDialogService DialogService + + + + + + + + @for(int index = 1; index < LAYER_NAMES.Count(); index ++) + { + + } + + + + Layers + + + + + + + + + + Name + @foreach (string layerName in LAYER_NAMES.GetRange(1, LAYER_NAMES.Count() - 1)) + { + @layerName + } + Planning + + + + + + @context.Name + + + + @foreach (List layer in Layers.Where(mainLayers => mainLayers[0][0].Id == context.Id).ToList()[0].GetRange(1, LAYER_NAMES.Count() - 1)) + { + @layer.Count() + } + + @(plannings.FirstOrDefault(item => item.Id == context.Planning)!= null ? plannings.FirstOrDefault(item => item.Id == context.Planning).Name : "None") + + + + + + + No matching records found + + + Loading... + + + + + + +@code { + public List LAYER_NAMES = new List() { "Main Layer", "Sub-Layer 1", "Sub-Layer 2" }; + + [CascadingParameter] + public Error Error { get; set; } = default!; + + [Parameter] + public CreateEditMode context { get; set; } + + private string id = ""; + + private List>> Layers = new List>>(); + private List MainLayers = new List(); + private List plannings = new List(); + + private bool isProcessing { get; set; } = false; + private bool IsLoading { get; set; } = true; + private readonly int[] pageSizeOptions = { 10, 5, 3 }; + + protected override async Task OnInitializedAsync() + { + await GetLayers(); + plannings = await PlanningClientService.GetPlannings(); + } + + private async Task GetLayers() + { + try + { + IsLoading = true; + List listLayers = await LayerClientService.GetLayers(); + ReloadSubLayers(listLayers); + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + finally + { + IsLoading = false; + } + } + + private void ReloadSubLayers(List layers) + { + if (layers.Count() == 0) return; + + LayerDto firstLayer = layers[0]; + bool isAdd = false; + + if (firstLayer.Father == "Init") + { + Layers.Add(new List>() { new List() { firstLayer } }); + MainLayers.Add(firstLayer); + for (int index = 1; index < LAYER_NAMES.Count(); index++) Layers[Layers.Count() - 1].Add(new List()); + isAdd = true; + } + else foreach(List> mainLayers in Layers) + { + if (mainLayers[0][0].Id == firstLayer.Father) + { + mainLayers[1].Add(firstLayer); + isAdd = true; + } + else isAdd = addSubLayer(1, mainLayers, firstLayer); + + if (isAdd) break; + } + + layers.RemoveAt(0); + if (!isAdd) layers.Add(firstLayer); + + if (layers.Count() != 0) ReloadSubLayers(layers); + } + + private bool addSubLayer(int index, List> mainLayers, LayerDto layer) + { + foreach (LayerDto subLayer in mainLayers[index]) + { + if (subLayer.Id == layer.Father) + { + mainLayers[index + 1].Add(layer); + return true; + } + else if (index + 1 < LAYER_NAMES.Count()) + { + bool isAdd = addSubLayer(index + 1, mainLayers, layer); + if (isAdd) return true; + } + } + return false; + } + + private void GoToDetails(LayerDto item) + { + navigationManager.NavigateTo($"/layer/{item.Id}"); + } + + private void AddLayer() + { + navigationManager.NavigateTo($"/layer/new"); + } +} diff --git a/src/IoTHub.Portal.Client/Pages/Layer/ThermoDeviceListPage.razor b/src/IoTHub.Portal.Client/Pages/Layer/ThermoDeviceListPage.razor new file mode 100644 index 000000000..32c746cb4 --- /dev/null +++ b/src/IoTHub.Portal.Client/Pages/Layer/ThermoDeviceListPage.razor @@ -0,0 +1,431 @@ +@page "/thermo/devices" +@using IoTHub.Portal +@using IoTHub.Portal.Models.v10 +@using IoTHub.Portal.Shared.Models.v10; +@using IoTHub.Portal.Client.Dialogs.Devices +@using System.Web +@using System.IO +@using System.Text.RegularExpressions +@using System.Net.Http.Headers +@using IoTHub.Portal.Shared.Models.v10.Filters; + +@attribute [Authorize] + +@inject IDialogService DialogService +@inject NavigationManager navigationManager +@inject PortalSettings Portal +@inject ISnackbar Snackbar +@inject IDeviceTagSettingsClientService DeviceTagSettingsClientService +@inject IDeviceClientService DeviceClientService +@inject IJSRuntime JS +@inject IDeviceModelsClientService DeviceModelsClientService +@inject ILoRaWanDeviceModelsClientService LoRaWanDeviceModelsClientService + + + + + + + + + + Save Changes + @foreach (DeviceTagDto tag in TagList) + { + if (tag.Searchable) + { + + + + } + } + + + + @foreach (var label in labels) + { + + + + } + + + + + this.Model) + Variant="Variant.Outlined" + ToStringFunc="@(x => x?.Name)" + ResetValueOnEmptyText=true + Immediate=true + Clearable=true + CoerceText=true + CoerceValue=false> + + @context.Name + + @((!string.IsNullOrEmpty(@context.Description) && @context.Description.Length > 100) ? @context.Description.Substring(0, 100) + "..." : @context.Description) + + + + + + + Status + + + Enabled + + + Disabled + + + All + + + + + + + + Search + Reset + + + + + + + + + + + + + + + + @if (Portal.IsLoRaSupported) + { + + } + + + + + Devices + + + + + + + + + + Manage devices + + + Export device list + + + Download template file + + + + + + Import device list + + + + + + + + + + + Device + Connection state + See details + + + + + + + + @context.DeviceName + @context.DeviceID + + + + + + + + @if (context.IsConnected) + { + + + + } + else + { + + + + } + + + + + + + + + + + No matching records found + + + Loading... + + + + + + + + +@code { + [CascadingParameter] + public Error? Error { get; set; } + + private string? searchID = ""; + private string? searchStatus; + private string? searchState; + + private MudTable? table; + private Dictionary searchTags = new(); + + private bool IsLoading { get; set; } = true; + + private DeviceModelDto Model { get; set; } = default!; + + private IEnumerable TagList { get; set; } = new List(); + + private IEnumerable labels = new List(); + private IEnumerable selectedLabels = new List(); + + private int[] pageSizeOptions = new int[] { 2, 5, 10 }; + + protected override async Task OnInitializedAsync() + { + try + { + // Gets the custom tags that can be searched via the panel + TagList = await DeviceTagSettingsClientService.GetDeviceTags(); + foreach (var tag in TagList) + { + if (tag.Searchable) + searchTags.Add(tag.Name, ""); + } + labels = await DeviceClientService.GetAvailableLabels(); + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + } + + private async Task> LoadItems(TableState state) + { + try + { + string? orderBy = null; + + switch (state.SortDirection) + { + case SortDirection.Ascending: + orderBy = $"{state.SortLabel} asc"; + break; + case SortDirection.Descending: + orderBy = $"{state.SortLabel} desc"; + break; + } + + var uri = $"api/devices?pageNumber={state.Page}&pageSize={state.PageSize}&searchText={HttpUtility.UrlEncode(searchID)}&searchStatus={searchStatus}&searchState={searchState}&orderBy={orderBy}&modelId={this.Model?.ModelId}"; + + foreach (var searchTag in searchTags.Where(c => !string.IsNullOrEmpty(c.Value))) + { + uri += $"&tag.{searchTag.Key}={searchTag.Value}"; + } + + foreach (var label in selectedLabels) + { + uri += $"&labels={label.Name}"; + } + + var result = await DeviceClientService.GetDevices(uri); + + return new TableData + { + Items = result.Items, + TotalItems = result.TotalItems + }; + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + + return new TableData(); + } + finally + { + IsLoading = false; + } + } + + private void AddDevice() + { + navigationManager.NavigateTo("devices/new"); + } + + /// + /// Reset all the fields in the search panel + /// + /// + private void Reset() + { + searchID = ""; + searchStatus = ""; + searchState = ""; + searchTags = searchTags.ToDictionary(tag => tag.Key, tag => ""); + selectedLabels = new List(); + + Search(); + } + + private void Search() + { + table?.ReloadServerData(); + } + + private void Refresh() + { + table?.ReloadServerData(); + } + + private void GoToDetails(DeviceListItem item) + { + navigationManager.NavigateTo($"devices/{item.DeviceID}{((item.SupportLoRaFeatures && Portal.IsLoRaSupported) ? "?isLora=true" : "")}"); + } + + /// + /// Allows to autocomplete the Device Model field in the form. + /// + /// Text entered in the field + /// Item of the device model list that matches the user's value + public async Task> Search(string value) + { + var filter = new DeviceModelFilter + { + SearchText = value, + PageNumber = 0, + PageSize = 10, + OrderBy = new string[] + { + string.Empty + } + }; + return (await DeviceModelsClientService.GetDeviceModels(filter)).Items.ToList(); + } + + private async Task ExportDeviceList() + { + menuIsOpen = false; + + var export = await this.DeviceClientService.ExportDeviceList(); + var fileName = export?.Headers?.ContentDisposition?.Parameters.Single(c => c.Name == "filename").Value; + + using var streamRef = new DotNetStreamReference(stream: await (export?.ReadAsStreamAsync())!); + await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef); + } + + private async Task ExportTemplateFile() + { + menuIsOpen = false; + + var export = await this.DeviceClientService.ExportTemplateFile(); + var fileName = export?.Headers?.ContentDisposition?.Parameters.Single(c => c.Name == "filename").Value; + + using var streamRef = new DotNetStreamReference(stream: await (export?.ReadAsStreamAsync())!); + await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef); + } + + private async Task ShowDeviceTelemetry(DeviceListItem device) + { + var parameters = new DialogParameters { { "DeviceID", device.DeviceID } }; + var options = new DialogOptions { MaxWidth = MaxWidth.Medium, FullWidth = true, CloseButton = true }; + + await DialogService.Show(string.Empty, parameters, options).Result; + } + + private async Task ImportDeviceList(IBrowserFile file) + { + menuIsOpen = false; + + var fileContent = new StreamContent(file.OpenReadStream()); + fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType); + + var content = new MultipartFormDataContent(); + content.Add(content: fileContent, + name: "\"file\"", + fileName: file.Name); + + var parameters = new DialogParameters { { "Content", content } }; + var options = new DialogOptions { MaxWidth = MaxWidth.Medium, FullWidth = true, CloseButton = true }; + await DialogService.Show("Import summary", parameters, options).Result; + } + + public bool menuIsOpen; + + public void ToggleOpen() + { + menuIsOpen = !menuIsOpen; + } + + private string GetMultiSelectionText(List selectedValues) + { + return $"{selectedValues.Count} label{(selectedValues.Count > 1 ? "s have" : " has")} been selected"; + } + + private async Task Save() + { + //var Room = new RoomDto(); + try + { + //await LoRaWanDeviceModelsClientService.CreateRoom((Room as RoomDto)!); + + Snackbar.Add("Room successfully created.", Severity.Success); + } + + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + } +} diff --git a/src/IoTHub.Portal.Client/Pages/Planning/CreatePlanningsPage.razor b/src/IoTHub.Portal.Client/Pages/Planning/CreatePlanningsPage.razor new file mode 100644 index 000000000..c77ce3d1a --- /dev/null +++ b/src/IoTHub.Portal.Client/Pages/Planning/CreatePlanningsPage.razor @@ -0,0 +1,19 @@ +@page "/planning/new" + +@using IoTHub.Portal.Shared.Models.v10 +@using IoTHub.Portal.Client.Components.Planning + + + +@code { + public List ScheduleList { get; set; } = new List {}; + public PlanningDto Planning { get; set; } = new PlanningDto(); + + protected override async Task OnInitializedAsync() + { + Planning.Day = "SaSo"; + ScheduleDto firstSchedule = new ScheduleDto(); + firstSchedule.Start = "00:00"; + ScheduleList.Add(firstSchedule); + } +} diff --git a/src/IoTHub.Portal.Client/Pages/Planning/PlanningDetailsPage.razor b/src/IoTHub.Portal.Client/Pages/Planning/PlanningDetailsPage.razor new file mode 100644 index 000000000..3af374cac --- /dev/null +++ b/src/IoTHub.Portal.Client/Pages/Planning/PlanningDetailsPage.razor @@ -0,0 +1,30 @@ +@page "/planning/{PlanningId}" + +@using IoTHub.Portal.Shared.Models.v10 +@using IoTHub.Portal.Client.Components.Planning +@using IoTHub.Portal.Models.v10 +@using IoTHub.Portal.Models.v10.LoRaWAN + +@inject IPlanningClientService PlanningClientService +@inject IScheduleClientService ScheduleClientService +@inject IDeviceModelsClientService DeviceModelsClientService +@inject ILoRaWanDeviceModelsClientService LoRaWanDeviceModelsClientService + +(ScheduleList)) mode="Edit" SelectedModel="@DeviceModel.Name" /> + +@code { + public List ScheduleList { get; set; } = new List { }; + public PlanningDto Planning { get; set; } = new PlanningDto(); + public DeviceModelDto DeviceModel { get; set; } = new DeviceModelDto(); + + [Parameter] + public string PlanningId { get; set; } = default!; + + protected override async Task OnInitializedAsync() + { + Planning = await PlanningClientService.GetPlanning(PlanningId); + + List newSchedule = await ScheduleClientService.GetSchedules(); + ScheduleList.AddRange(newSchedule.Where(obj => obj.PlanningId == PlanningId)); + } +} diff --git a/src/IoTHub.Portal.Client/Pages/Planning/PlanningListPage.razor b/src/IoTHub.Portal.Client/Pages/Planning/PlanningListPage.razor new file mode 100644 index 000000000..2e8c35af4 --- /dev/null +++ b/src/IoTHub.Portal.Client/Pages/Planning/PlanningListPage.razor @@ -0,0 +1,135 @@ +@page "/planning" + +@using IoTHub.Portal +@using IoTHub.Portal.Models.v10 +@using IoTHub.Portal.Shared.Models.v10; +@using IoTHub.Portal.Client.Dialogs.Devices +@using System.Web +@using System.IO +@using System.Text.RegularExpressions +@using System.Net.Http.Headers +@using IoTHub.Portal.Shared.Models.v10.Filters +@using IoTHub.Portal.Client.Enums +@using IoTHub.Portal.Client.Pages.Devices +@using IoTHub.Portal.Client.Validators +@using IoTHub.Portal.Shared.Constants; +@using IoTHub.Portal.Shared.Models +@using IoTHub.Portal.Models +@using IoTHub.Portal.Models.v10.LoRaWAN +@using Microsoft.AspNetCore.WebUtilities +@using IoTHub.Portal.Client.Dialogs.Building + +@attribute [Authorize] + +@inject NavigationManager navigationManager +@inject PortalSettings Portal +@inject IPlanningClientService PlanningClientService +@inject IDialogService DialogService + + + + + + + + + + + + Plannings + + + + + + + + + + Name + Start + End + Frequency + + + + + + @context.Name + + + + + @context.Start + + + @context.End + + + @context.Frequency + + + + + + + No matching records found + + + Loading... + + + + + + + +@code { + [Parameter] + public CreateEditMode context { get; set; } + + [CascadingParameter] + public Error Error { get; set; } = default!; + + private PlanningDto Planning { get; set; } = new PlanningDto(); + + private string id = ""; + + private List Plannings = new List(); + + private bool isProcessing { get; set; } = false; + private bool IsLoading { get; set; } = true; + private readonly int[] pageSizeOptions = { 10, 5, 3 }; + + protected override async Task OnInitializedAsync() + { + await GetPlannings(); + } + + private async Task GetPlannings() + { + try + { + IsLoading = true; + Plannings = await PlanningClientService.GetPlannings(); + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + finally + { + IsLoading = false; + } + } + + private void GoToDetails(PlanningDto item) + { + navigationManager.NavigateTo($"/planning/{item.Id}"); + } + + private void AddPlanning() + { + navigationManager.NavigateTo($"/planning/new"); + } +} diff --git a/src/IoTHub.Portal.Client/Pages/Settings/Layers.razor b/src/IoTHub.Portal.Client/Pages/Settings/Layers.razor new file mode 100644 index 000000000..4651fe915 --- /dev/null +++ b/src/IoTHub.Portal.Client/Pages/Settings/Layers.razor @@ -0,0 +1,16 @@ +@page "/settings/layers" + +@attribute [Authorize] +@inject ISnackbar Snackbar + + + + + + + +@code { + [CascadingParameter] + public Error Error { get; set; } = default!; + +} diff --git a/src/IoTHub.Portal.Client/Shared/NavMenu.razor b/src/IoTHub.Portal.Client/Shared/NavMenu.razor index d93dc5542..a3e3772d1 100644 --- a/src/IoTHub.Portal.Client/Shared/NavMenu.razor +++ b/src/IoTHub.Portal.Client/Shared/NavMenu.razor @@ -53,6 +53,13 @@ Edge Models + + Layers + Plannings + + @if (Portal.IsLoRaSupported) { + Layers Device Tags diff --git a/src/IoTHub.Portal.Domain/Entities/Device.cs b/src/IoTHub.Portal.Domain/Entities/Device.cs index 426f18f25..7ded8c921 100644 --- a/src/IoTHub.Portal.Domain/Entities/Device.cs +++ b/src/IoTHub.Portal.Domain/Entities/Device.cs @@ -52,5 +52,10 @@ public class Device : EntityBase /// List of custom device tags and their values. /// public ICollection Tags { get; set; } = new Collection(); + + /// + /// The LayerId of the device. + /// + public string LayerId { get; set; } = "None"; } } diff --git a/src/IoTHub.Portal.Domain/Entities/IDevice.cs b/src/IoTHub.Portal.Domain/Entities/IDevice.cs index 8ab38f418..1965890c9 100644 --- a/src/IoTHub.Portal.Domain/Entities/IDevice.cs +++ b/src/IoTHub.Portal.Domain/Entities/IDevice.cs @@ -39,5 +39,10 @@ internal interface IDevice /// The device labels. /// public ICollection