Skip to content

Commit

Permalink
Merge branch 'main' into woodford/#12-RenderData
Browse files Browse the repository at this point in the history
  • Loading branch information
meghanmae committed Mar 4, 2023
2 parents 218246f + 8f07cd5 commit 78a4f78
Show file tree
Hide file tree
Showing 32 changed files with 1,396 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.*" />
<PackageReference Include="IntelliTect.Coalesce" Version="$(CoalesceVersion)" />
</ItemGroup>

<ItemGroup>
<Folder Include="Services\" />
</ItemGroup>
</Project>
7 changes: 3 additions & 4 deletions src/IntelliTect.TextTrolley.Data/Models/ApplicationUser.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Microsoft.AspNetCore.Identity;

namespace IntelliTect.TextTrolley.Data.Models;


public class ApplicationUser
public class ApplicationUser : IdentityUser
{
public int ApplicationUserId { get; set; }

[Required]
[MaxLength(150)]
public required string Name { get; set; }



}
3 changes: 3 additions & 0 deletions src/IntelliTect.TextTrolley.Data/Models/InboundMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace IntelliTect.TextTrolley.Data.Models;

public record InboundMessage(string MessageSid, string Body, string MessageStatus, string? OptOutType, string MessagingServiceSid, string From);
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using IntelliTect.TextTrolley.Data.Models;

namespace IntelliTect.TextTrolley.Data.Repositories;

public interface IRequesterRepository
{
Task<Requester?> ExistingByPhoneNumber(string phoneNumber);

Task<Requester> Create(string phoneNumber, string name);
}

public class RequesterRepository : IRequesterRepository
{
private AppDbContext Context { get; }

public RequesterRepository(AppDbContext context)
{
Context = context;
}

public async Task<Requester?> ExistingByPhoneNumber(string phoneNumber)
{
return await Context.Requester.SingleOrDefaultAsync(x => x.RequesterNumber == phoneNumber);
}

public async Task<Requester> Create(string phoneNumber, string name)
{
Requester requester = new()
{
RequesterName = name,
RequesterNumber = phoneNumber,
ActiveShoppingList = new ()
{
IsComplete = false,
IsDelivered = false,
Items = Enumerable.Empty<ShoppingListItem>().ToList(),
ApplicationUsers = Enumerable.Empty<ApplicationUser>().ToList()
}
};

await Context.AddAsync(requester);
await Context.SaveChangesAsync();
return requester;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using IntelliTect.TextTrolley.Data.Models;

namespace IntelliTect.TextTrolley.Data.Repositories;

public interface IShoppingListItemRepository
{
Task AddItem(ShoppingListItem item);
}

public class ShoppingListItemRepository : IShoppingListItemRepository
{
public ShoppingListItemRepository(AppDbContext context)
{
Context = context;
}

protected AppDbContext Context { get; }

public async Task AddItem(ShoppingListItem item)
{
await Context.ShoppingListItem.AddAsync(item);
await Context.SaveChangesAsync();
}
}
17 changes: 17 additions & 0 deletions src/IntelliTect.TextTrolley.Data/Services/ILoginService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using IntelliTect.Coalesce;
using IntelliTect.Coalesce.DataAnnotations;
using IntelliTect.Coalesce.Models;
using IntelliTect.TextTrolley.Data;
using System.Threading.Tasks;

namespace IntelliTect.TextTrolley.Data.Services;

[Coalesce, Service]
public interface ILoginService
{
[Execute(PermissionLevel = SecurityPermissionLevels.AllowAll)]
Task<ItemResult> LoginUser([Inject] AppDbContext db, string email, string password);

[Execute(PermissionLevel = SecurityPermissionLevels.AllowAll)]
Task<ItemResult> RegisterUser([Inject] AppDbContext db, string firstName, string lastName, string email, string password, string phoneNumber);
}
12 changes: 12 additions & 0 deletions src/IntelliTect.TextTrolley.Data/Services/IMessagingService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using IntelliTect.TextTrolley.Data.Models;

namespace IntelliTect.TextTrolley.Data.Services;

public interface IMessagingService
{
Task<Requester> GetOrCreateRequester(InboundMessage message);

ShoppingListItem ConvertMessageToListItem(Requester requester, InboundMessage message);

Task AddNewListItem(ShoppingListItem item);
}
97 changes: 97 additions & 0 deletions src/IntelliTect.TextTrolley.Data/Services/LoginService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IntelliTect.TextTrolley.Data.Models;
using IntelliTect.Coalesce.Models;
using System.Net.Mail;

namespace IntelliTect.TextTrolley.Data.Services;

public class LoginService : ILoginService
{
private SignInManager<ApplicationUser> SignInManager { get; }
private UserManager<ApplicationUser> UserManager { get; }
private IHttpContextAccessor ContextAccessor { get; }

public IList<AuthenticationScheme> ExternalLogins { get; set; } = new List<AuthenticationScheme>();

public LoginService(SignInManager<ApplicationUser> signInManager, UserManager<ApplicationUser> userManager, IHttpContextAccessor contextAccessor)
{
SignInManager = signInManager;
UserManager = userManager;
ContextAccessor = contextAccessor;
}

public async Task<ItemResult> LoginUser([Inject] AppDbContext db, string email, string password)
{
SignInResult? result = await SignInManager.PasswordSignInAsync(email, password, true, lockoutOnFailure: false);

ApplicationUser? user = db.ApplicationUsers.Where(u => u.Email == email).FirstOrDefault();

if (user == null)
{
return $"User cannot be found, please check credentials.";
}
if (result.IsLockedOut)
{
return "This account is currently disabled.";
}
if (!result.Succeeded || user is null)
{
return "Username or password are incorrect.";
}
else
{
return "Something has gone wrong on our end, please try again later.";
}
}

public async Task<ItemResult> RegisterUser([Inject] AppDbContext db, string firstName, string lastName, string email, string password, string? phoneNumber)
{
try
{
MailAddress m = new(email);
}
catch (FormatException)
{
return "This email address is invalid";
}

ApplicationUser? user = new ApplicationUser() { Name = $"{firstName} {lastName}", UserName = email, PhoneNumber = phoneNumber};
IdentityResult? createUserResult = await UserManager.CreateAsync(user, password);
//await UserManager.AddToRoleAsync(user, Roles.User);

if (createUserResult.Succeeded)
{
//potentially need to new up other details
//try
//{
// await CreateTextTrolleyAccount(db, user);
//}
//catch (Exception ex)
//{
// return ex.Message;
//}

return "User successfully registered!";
}
else
{
if (createUserResult.Errors.Any())
{
List<string> errors = new();
foreach (IdentityError? error in createUserResult.Errors)
{
errors.Add(error.Description);
}
return string.Join(" ", errors);
}
return "Could not create an account. Please try again later.";
}
}
}
38 changes: 38 additions & 0 deletions src/IntelliTect.TextTrolley.Data/Services/MessagingService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using IntelliTect.TextTrolley.Data.Models;
using IntelliTect.TextTrolley.Data.Repositories;

namespace IntelliTect.TextTrolley.Data.Services;

public class MessagingService : IMessagingService
{
protected IRequesterRepository RequesterRepo { get; }
protected IShoppingListItemRepository ShoppingListItemRepo { get; }

public MessagingService(IRequesterRepository requesterRepo, IShoppingListItemRepository shoppingListItemRepo)
{
RequesterRepo = requesterRepo;
ShoppingListItemRepo = shoppingListItemRepo;
}

public async Task<Requester> GetOrCreateRequester(InboundMessage message)
{
return await RequesterRepo.ExistingByPhoneNumber(message.From) ?? await RequesterRepo.Create(message.From, "unknown sender");
}

public ShoppingListItem ConvertMessageToListItem(Requester requester, InboundMessage message)
{
return new ShoppingListItem()
{
Name = message.Body,
OriginalName = message.Body,
Purchased = false,
ShoppingList = requester.ActiveShoppingList,
ShoppingListItemId = requester.ActiveShoppingListKey
};
}

public async Task AddNewListItem(ShoppingListItem item)
{
await ShoppingListItemRepo.AddItem(item);
}
}
47 changes: 47 additions & 0 deletions src/IntelliTect.TextTrolley.Tests/ListToolsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using IntelliTect.TextTrolley.Web.Utility;
using OpenAI_API;

namespace IntelliTect.TextTrolley.Tests;

public class ListToolsTests
{

public static IEnumerable<object[]> TestData =>
new List<object[]>
{
new object[]
{
new List<string>() { "apple", "banana" },
new List<string>() { "banana" },
new int[] { 1 }
},
new object[]
{
new List<string>() { "ice", "ice cream" },
new List<string>() { "ice" },
new int[] { 0 }
},
new object[]
{
new List<string>() { "ice", "ice cream", "shaving cream" },
new List<string>() { "cream" },
new int[] { 1 }
},
new object[]
{
new List<string>() { "ice", "ice cream", "shaving cream", "cream" },
new List<string>() { "cream" },
new int[] { 3 }
},
};

[Theory]
[MemberData(nameof(TestData))]
public void GetIndicesInFirstListWhereInSecondList(List<string> list1, List<string> list2, int[] expectedIndices)
{
List<int> result = ListTools.GetIndincesToRemove(list1, list2);

Assert.Equal(expectedIndices, result);
}
}

Loading

0 comments on commit 78a4f78

Please sign in to comment.