Skip to content

Commit

Permalink
Merge pull request #186 from leoslopez/DOP-1492_save_n_get_time_restr…
Browse files Browse the repository at this point in the history
…ictions_hours_in_utc

Dop 1492 save n get time restrictions hours in utc
  • Loading branch information
leoslopez authored Mar 4, 2024
2 parents cfcc82c + 4b35366 commit 0000a6e
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public async Task
.Create();
var expectedTimeRestriction = fixture.Build<ContactPoliciesTimeRestriction>()
.With(x => x.AccountName, accountName)
.With(x => x.HourFrom, 1)
.With(x => x.HourTo, 2)
.Create();

var contactPoliciesRepositoryMock = new Mock<IContactPoliciesSettingsRepository>();
Expand All @@ -44,6 +46,147 @@ public async Task
Assert.True(actual.Active);
}

[Theory]
[InlineData(22, 23, 19, 20, -180)]
[InlineData(1, 2, 22, 23, -180)]
[InlineData(22, 23, 1, 2, 180)]
[InlineData(1, 2, 4, 5, 180)]
public async Task
GetContactPoliciesSettings_Should_Convert_TimeRestrictionHours_To_UserTimeZone_When_OffsetMinutes_ExactHours
(
int hourFromInDB,
int hourToInDB,
int hourFromForResponse,
int hourToFoResponse,
int offsetMinutes
)
{
// Arrange
var fixture = new Fixture();
string accountName = "prueba@makingsense.com";
var expected = fixture.Build<ContactPoliciesSettings>()
.With(x => x.AccountName, accountName)
.With(x => x.Active, true)
.Create();
var expectedTimeRestriction = fixture.Build<ContactPoliciesTimeRestriction>()
.With(x => x.AccountName, accountName)
.With(x => x.HourFrom, hourFromInDB)
.With(x => x.HourTo, hourToInDB)
.With(x => x.TimeZoneOffsetMinutes, offsetMinutes)
.Create();

var contactPoliciesRepositoryMock = new Mock<IContactPoliciesSettingsRepository>();
contactPoliciesRepositoryMock.Setup(x => x.GetContactPoliciesSettingsByIdUserAsync(It.IsAny<int>()))
.ReturnsAsync(expected).Verifiable();
contactPoliciesRepositoryMock.Setup(x => x.GetContactPoliciesTimeRestrictionByIdUserAsync(It.IsAny<int>()))
.ReturnsAsync(expectedTimeRestriction).Verifiable();

var contactPoliciesSut = new ContactPoliciesService(contactPoliciesRepositoryMock.Object);

// Act
var actual = await contactPoliciesSut.GetContactPoliciesSettingsByIdUserAsync(It.IsAny<int>());

// Assert
contactPoliciesRepositoryMock.Verify();
Assert.Equal(actual.AccountName, expected.AccountName);
Assert.True(actual.Active);
Assert.Equal(actual.TimeRestriction.HourFrom, hourFromForResponse);
Assert.Equal(actual.TimeRestriction.HourTo, hourToFoResponse);
}

[Theory]
[InlineData(22, 23, 19, 20, -150)]
[InlineData(1, 2, 22, 23, -150)]
[InlineData(22, 23, 0, 1, 150)]
[InlineData(1, 2, 3, 4, 150)]
public async Task
GetContactPoliciesSettings_Should_Convert_TimeRestrictionHours_To_UserTimeZone_When_OffsetMinutes_NonExactHours
(
int hourFromInDB,
int hourToInDB,
int hourFromForResponse,
int hourToFoResponse,
int offsetMinutes
)
{
// Arrange
var fixture = new Fixture();
string accountName = "prueba@makingsense.com";
var expected = fixture.Build<ContactPoliciesSettings>()
.With(x => x.AccountName, accountName)
.With(x => x.Active, true)
.Create();
var expectedTimeRestriction = fixture.Build<ContactPoliciesTimeRestriction>()
.With(x => x.AccountName, accountName)
.With(x => x.HourFrom, hourFromInDB)
.With(x => x.HourTo, hourToInDB)
.With(x => x.TimeZoneOffsetMinutes, offsetMinutes)
.Create();

var contactPoliciesRepositoryMock = new Mock<IContactPoliciesSettingsRepository>();
contactPoliciesRepositoryMock.Setup(x => x.GetContactPoliciesSettingsByIdUserAsync(It.IsAny<int>()))
.ReturnsAsync(expected).Verifiable();
contactPoliciesRepositoryMock.Setup(x => x.GetContactPoliciesTimeRestrictionByIdUserAsync(It.IsAny<int>()))
.ReturnsAsync(expectedTimeRestriction).Verifiable();

var contactPoliciesSut = new ContactPoliciesService(contactPoliciesRepositoryMock.Object);

// Act
var actual = await contactPoliciesSut.GetContactPoliciesSettingsByIdUserAsync(It.IsAny<int>());

// Assert
contactPoliciesRepositoryMock.Verify();
Assert.Equal(actual.AccountName, expected.AccountName);
Assert.True(actual.Active);
Assert.Equal(actual.TimeRestriction.HourFrom, hourFromForResponse);
Assert.Equal(actual.TimeRestriction.HourTo, hourToFoResponse);
}

[Theory]
[InlineData(null, null, null, null, 180)]
[InlineData(1, 2, 1, 2, 0)]
public async Task GetContactPoliciesSettings_ShouldNot_Convert_TimeRestrictionHours_When_OffsetMinutesIsZero_Or_HoursAreNull
(
int? hourFromInDB,
int? hourToInDB,
int? hourFromForResponse,
int? hourToFoResponse,
int offsetMinutes
)
{
// Arrange
var fixture = new Fixture();
string accountName = "prueba@makingsense.com";
var expected = fixture.Build<ContactPoliciesSettings>()
.With(x => x.AccountName, accountName)
.With(x => x.Active, true)
.Create();
var expectedTimeRestriction = fixture.Build<ContactPoliciesTimeRestriction>()
.With(x => x.AccountName, accountName)
.With(x => x.HourFrom, hourFromInDB)
.With(x => x.HourTo, hourToInDB)
.With(x => x.TimeZoneOffsetMinutes, offsetMinutes)
.Create();

var contactPoliciesRepositoryMock = new Mock<IContactPoliciesSettingsRepository>();
contactPoliciesRepositoryMock.Setup(x => x.GetContactPoliciesSettingsByIdUserAsync(It.IsAny<int>()))
.ReturnsAsync(expected).Verifiable();
contactPoliciesRepositoryMock.Setup(x => x.GetContactPoliciesTimeRestrictionByIdUserAsync(It.IsAny<int>()))
.ReturnsAsync(expectedTimeRestriction).Verifiable();

var contactPoliciesSut = new ContactPoliciesService(contactPoliciesRepositoryMock.Object);

// Act
var actual = await contactPoliciesSut.GetContactPoliciesSettingsByIdUserAsync(It.IsAny<int>());

// Assert
contactPoliciesRepositoryMock.Verify();
Assert.Equal(actual.AccountName, expected.AccountName);
Assert.True(actual.Active);
Assert.Equal(actual.TimeRestriction.HourFrom, hourFromForResponse);
Assert.Equal(actual.TimeRestriction.HourTo, hourToFoResponse);
}

[Fact]
public async Task
UpdateContactPoliciesSettings_Should_InvokeContactPoliciesSettingsRepository_With_ProperParameters()
Expand Down Expand Up @@ -91,5 +234,139 @@ public async Task
Times.Once
);
}

[Theory]
[InlineData(22, 23, 19, 20, -180)]
[InlineData(1, 2, 22, 23, -180)]
[InlineData(22, 23, 1, 2, 180)]
[InlineData(1, 2, 4, 5, 180)]
public async Task
UpdateContactPoliciesSettings_Should_Convert_TimeRestrictionHours_To_UTC_When_OffsetMinutes_ExactHours
(
int hourFromForDB,
int hourToForDB,
int hourFromInRequest,
int hourToInRequest,
int offsetMinutes
)
{
// Arrange
var idUser = 1000;

var excludedLists = new List<ExcludedSubscribersLists>
{
new ExcludedSubscribersLists() { Id = 1, Name = "Test" }
};

var fixture = new Fixture();
var timeRestriction = new ContactPoliciesTimeRestrictionDto()
{
HourFrom = hourFromInRequest,
HourTo = hourToInRequest,
};
var contactPoliciesSettingsDto = fixture.Build<ContactPoliciesSettingsDto>()
.With(x => x.ExcludedSubscribersLists, excludedLists)
.With(x => x.TimeRestriction, timeRestriction)
.Create();

var contactPoliciesSettingsRepositoryMock = new Mock<IContactPoliciesSettingsRepository>();
contactPoliciesSettingsRepositoryMock.Setup(x => x.GetTimezoneOffsetMinutes(It.IsAny<int>()))
.ReturnsAsync(offsetMinutes).Verifiable();

var contactPoliciesSut = new ContactPoliciesService(contactPoliciesSettingsRepositoryMock.Object);

// Act
await contactPoliciesSut.UpdateContactPoliciesSettingsAsync(idUser, contactPoliciesSettingsDto);

// Assert
contactPoliciesSettingsRepositoryMock.Verify(
repo => repo.UpdateContactPoliciesSettingsAsync(
idUser,
It.Is<ContactPoliciesSettings>(cps =>
cps.AccountName == null
&& cps.Active == contactPoliciesSettingsDto.Active
&& cps.EmailsAmountByInterval == contactPoliciesSettingsDto.EmailsAmountByInterval
&& cps.IntervalInDays == contactPoliciesSettingsDto.IntervalInDays
&& cps.UserHasContactPolicies == false
&& cps.ExcludedSubscribersLists.Count == contactPoliciesSettingsDto.ExcludedSubscribersLists.Count
&& cps.ExcludedSubscribersLists[0] == contactPoliciesSettingsDto.ExcludedSubscribersLists[0]
),
It.Is<ContactPoliciesTimeRestriction>(cptr =>
cptr.TimeSlotEnabled == contactPoliciesSettingsDto.TimeRestriction.TimeSlotEnabled
&& cptr.HourFrom == hourFromForDB
&& cptr.HourTo == hourToForDB
&& cptr.WeekdaysEnabled == contactPoliciesSettingsDto.TimeRestriction.WeekdaysEnabled
)
),
Times.Once
);
}

[Theory]
[InlineData(22, 23, 19, 20, -150)]
[InlineData(1, 2, 22, 23, -150)]
[InlineData(22, 23, 0, 1, 150)]
[InlineData(1, 2, 3, 4, 150)]
public async Task
UpdateContactPoliciesSettings_Should_Convert_TimeRestrictionHours_To_UTC_When_OffsetMinutes_NonExactHours
(
int hourFromForDB,
int hourToForDB,
int hourFromInRequest,
int hourToInRequest,
int offsetMinutes
)
{
// Arrange
var idUser = 1000;

var excludedLists = new List<ExcludedSubscribersLists>
{
new ExcludedSubscribersLists() { Id = 1, Name = "Test" }
};

var fixture = new Fixture();
var timeRestriction = new ContactPoliciesTimeRestrictionDto()
{
HourFrom = hourFromInRequest,
HourTo = hourToInRequest,
};
var contactPoliciesSettingsDto = fixture.Build<ContactPoliciesSettingsDto>()
.With(x => x.ExcludedSubscribersLists, excludedLists)
.With(x => x.TimeRestriction, timeRestriction)
.Create();

var contactPoliciesSettingsRepositoryMock = new Mock<IContactPoliciesSettingsRepository>();
contactPoliciesSettingsRepositoryMock.Setup(x => x.GetTimezoneOffsetMinutes(It.IsAny<int>()))
.ReturnsAsync(offsetMinutes).Verifiable();

var contactPoliciesSut = new ContactPoliciesService(contactPoliciesSettingsRepositoryMock.Object);

// Act
await contactPoliciesSut.UpdateContactPoliciesSettingsAsync(idUser, contactPoliciesSettingsDto);

// Assert
contactPoliciesSettingsRepositoryMock.Verify(
repo => repo.UpdateContactPoliciesSettingsAsync(
idUser,
It.Is<ContactPoliciesSettings>(cps =>
cps.AccountName == null
&& cps.Active == contactPoliciesSettingsDto.Active
&& cps.EmailsAmountByInterval == contactPoliciesSettingsDto.EmailsAmountByInterval
&& cps.IntervalInDays == contactPoliciesSettingsDto.IntervalInDays
&& cps.UserHasContactPolicies == false
&& cps.ExcludedSubscribersLists.Count == contactPoliciesSettingsDto.ExcludedSubscribersLists.Count
&& cps.ExcludedSubscribersLists[0] == contactPoliciesSettingsDto.ExcludedSubscribersLists[0]
),
It.Is<ContactPoliciesTimeRestriction>(cptr =>
cptr.TimeSlotEnabled == contactPoliciesSettingsDto.TimeRestriction.TimeSlotEnabled
&& cptr.HourFrom == hourFromForDB
&& cptr.HourTo == hourToForDB
&& cptr.WeekdaysEnabled == contactPoliciesSettingsDto.TimeRestriction.WeekdaysEnabled
)
),
Times.Once
);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
using Doppler.ContactPolicies.Business.Logic.DTO;
using Doppler.ContactPolicies.Data.Access.Entities;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Doppler.ContactPolicies.Business.Logic.Extensions
{
public enum TimeZoneConversionEnum
{
CONVERT_TO_UTC,
CONVERT_TO_USERTIMEZONE,
}

public static class MapperExtension
{
public static ContactPoliciesSettingsDto ToDto(
Expand Down Expand Up @@ -49,14 +56,15 @@ public static ContactPoliciesTimeRestrictionDto ToDto(
return new ContactPoliciesTimeRestrictionDto
{
TimeSlotEnabled = timeRestriction.TimeSlotEnabled,
HourFrom = timeRestriction.HourFrom,
HourTo = timeRestriction.HourTo,
HourFrom = ApplyHourOffset(timeRestriction.HourFrom, timeRestriction.TimeZoneOffsetMinutes, TimeZoneConversionEnum.CONVERT_TO_USERTIMEZONE),
HourTo = ApplyHourOffset(timeRestriction.HourTo, timeRestriction.TimeZoneOffsetMinutes, TimeZoneConversionEnum.CONVERT_TO_USERTIMEZONE),
WeekdaysEnabled = timeRestriction.WeekdaysEnabled
};
}

public static ContactPoliciesTimeRestriction ToDao(
this ContactPoliciesTimeRestrictionDto contactPoliciesTimeRestrictionDto)
this ContactPoliciesTimeRestrictionDto contactPoliciesTimeRestrictionDto,
int timezoneOffsetMinutes)
{
if (contactPoliciesTimeRestrictionDto == null)
{
Expand All @@ -66,10 +74,36 @@ public static ContactPoliciesTimeRestriction ToDao(
return new ContactPoliciesTimeRestriction
{
TimeSlotEnabled = contactPoliciesTimeRestrictionDto.TimeSlotEnabled,
HourFrom = contactPoliciesTimeRestrictionDto.HourFrom,
HourTo = contactPoliciesTimeRestrictionDto.HourTo,
HourFrom = ApplyHourOffset(contactPoliciesTimeRestrictionDto.HourFrom, timezoneOffsetMinutes, TimeZoneConversionEnum.CONVERT_TO_UTC),
HourTo = ApplyHourOffset(contactPoliciesTimeRestrictionDto.HourTo, timezoneOffsetMinutes, TimeZoneConversionEnum.CONVERT_TO_UTC),
WeekdaysEnabled = contactPoliciesTimeRestrictionDto.WeekdaysEnabled
};
}

private static int? ApplyHourOffset(int? hour, int offset, TimeZoneConversionEnum conversion)
{
if (!hour.HasValue || offset == 0)
{
return hour;
}

DateTime now = DateTime.Now;
DateTime auxDate = new DateTime(now.Year, now.Month, now.Day, hour.Value, 0, 0);

int offsetMinutes = offset * (conversion == TimeZoneConversionEnum.CONVERT_TO_UTC ? -1 : 1);
DateTime resultDate = auxDate.AddMinutes(offsetMinutes);

var hour24 = resultDate.ToString("HH");

// when the offset is not an exact quantity of hours, for example: (GMT+09:30) Adelaide.
if (resultDate.Minute > 0)
{
return (int.Parse(hour24) + (conversion == TimeZoneConversionEnum.CONVERT_TO_UTC ? 1 : 0)) % 24;
}
else
{
return int.Parse(hour24);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public async Task<ContactPoliciesSettingsDto> GetContactPoliciesSettingsByIdUser
public async Task UpdateContactPoliciesSettingsAsync(int idUser, ContactPoliciesSettingsDto contactPoliciesSettings)
{
var contactPoliciesToUpdate = contactPoliciesSettings.ToDao();
var timeRestrictionToUpdate = contactPoliciesSettings.TimeRestriction.ToDao();
var timezoneOffsetMinutes = await _contactPoliciesSettingsRepository.GetTimezoneOffsetMinutes(idUser);
var timeRestrictionToUpdate = contactPoliciesSettings.TimeRestriction.ToDao(timezoneOffsetMinutes);
await _contactPoliciesSettingsRepository.UpdateContactPoliciesSettingsAsync(idUser, contactPoliciesToUpdate, timeRestrictionToUpdate);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public sealed class ContactPoliciesTimeRestriction
public int? HourFrom { get; set; }
public int? HourTo { get; set; }
public bool WeekdaysEnabled { get; set; }
public int TimeZoneOffsetMinutes { get; set; }
}
}
Loading

0 comments on commit 0000a6e

Please sign in to comment.