Skip to content

Commit

Permalink
Merge pull request #536 from SCCapstone/main
Browse files Browse the repository at this point in the history
528: Deploy landing page
  • Loading branch information
evan-scales authored Apr 17, 2024
2 parents 98349d8 + 3572a1e commit 1d8a989
Show file tree
Hide file tree
Showing 60 changed files with 1,369 additions and 1,088 deletions.
4 changes: 2 additions & 2 deletions FU.API/FU.API.Tests/AccountServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void Dispose()
public async void CreateUser_WithValidCredentials_ReturnsUser()
{
// Arange
Credentials credentials = new() { Username = "Test", Password = "Test" };
Credentials credentials = new() { Username = "Test", Password = "Test12345" };

// Act
ApplicationUser user = await _accountsService.Register(credentials);
Expand All @@ -62,7 +62,7 @@ public async void CreateUser_WithValidCredentials_ReturnsUser()
public async void ChangeUsername_WithValidUsername_ChangesUsername()
{
// Arange
Credentials credentials = new() { Username = "Username1", Password = "Test" };
Credentials credentials = new() { Username = "Username1", Password = "Test12345" };
string newUsername = "Username2";
ApplicationUser user = await _accountsService.Register(credentials);

Expand Down
6 changes: 3 additions & 3 deletions FU.API/FU.API.Tests/PostServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public async void GetPostUsers_WithMultipleUsers_ReturnsCorrectUserCount()
// Arrange
// Note: CreateTestPostAsync creates one user as part of creating a post
Post post = await TestsHelper.CreateTestPostAsync(_dbContext);
var user2 = await TestsHelper.CreateUserAsync(_dbContext, new Credentials() { Username = "user2", Password = "pass2", Email = "[email protected]" });
var user2 = await TestsHelper.CreateUserAsync(_dbContext, new Credentials() { Username = "user2", Password = "Test12345", Email = "[email protected]" });
await _postService.JoinPost(post.Id, user2);

// Act
Expand Down Expand Up @@ -166,7 +166,7 @@ public async void JoinPost_WhenAlreadyMember_ThrowsConflictException()
{
// Arrange
Post post = await TestsHelper.CreateTestPostAsync(_dbContext);
var user2 = await TestsHelper.CreateUserAsync(_dbContext, new Credentials() { Username = "user2", Password = "pass2", Email = "[email protected]" });
var user2 = await TestsHelper.CreateUserAsync(_dbContext, new Credentials() { Username = "user2", Password = "Test12345", Email = "[email protected]" });
await _postService.JoinPost(post.Id, user2);

// Act & Assert
Expand All @@ -180,7 +180,7 @@ public async void LeavePost_WhenMember_LeavesPost()
{
// Arrange
Post post = await TestsHelper.CreateTestPostAsync(_dbContext);
var user2 = await TestsHelper.CreateUserAsync(_dbContext, new Credentials() { Username = "user2", Password = "pass2", Email = "[email protected]" });
var user2 = await TestsHelper.CreateUserAsync(_dbContext, new Credentials() { Username = "user2", Password = "Test12345", Email = "[email protected]" });
await _postService.JoinPost(post.Id, user2);

// Act
Expand Down
6 changes: 3 additions & 3 deletions FU.API/FU.API.Tests/SearchServiceSearchPostsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public async Task Search_WithSearchStartDate_FiltersOne()
// Act
(List<Post> posts, var totalResults) = await _searchService.SearchPosts(new PostQuery()
{
StartOnOrAfterDate = searchDate,
StartOnOrAfterDateTime = searchDate.ToDateTime(new TimeOnly(1, 1, 1)),
});

// Assert
Expand Down Expand Up @@ -196,7 +196,7 @@ public async Task Search_WithSearchEndDateDate_FiltersOne()
// Act
(List<Post> posts, var totalResults) = await _searchService.SearchPosts(new PostQuery()
{
EndOnOrBeforeDate = searchDate,
EndOnOrBeforeDateTime = searchDate.ToDateTime(new TimeOnly(1, 1, 1)),
});

// Assert
Expand Down Expand Up @@ -232,7 +232,7 @@ public async Task Search_WithSearchDateAsToday_SearchesAfterNow()
// Act
(List<Post> posts, var totalResults) = await _searchService.SearchPosts(new PostQuery()
{
StartOnOrAfterDate = DateOnly.FromDateTime(DateTime.UtcNow),
StartOnOrAfterDateTime = DateTime.UtcNow,
});

// Assert
Expand Down
6 changes: 3 additions & 3 deletions FU.API/FU.API.Tests/SearchServiceSearchUsersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,19 @@ public async Task Search_WithKeyword_SearchesTitleAndBio()
{
Username = "User1",
Email = "[email protected]",
Password = "Pass1"
Password = "Test12345"
});
var user2 = await TestsHelper.CreateUserAsync(_dbContext, new Credentials()
{
Username = "User2",
Email = "[email protected]",
Password = "Pass2"
Password = "Test12345"
});
var user3 = await TestsHelper.CreateUserAsync(_dbContext, new Credentials()
{
Username = "User3",
Email = "[email protected]",
Password = "Pass3"
Password = "Test12345"
});
await _userService.UpdateUserProfile(new UserProfile() { Bio = "Bio3", Id = user3.UserId });

Expand Down
2 changes: 1 addition & 1 deletion FU.API/FU.API.Tests/TestsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static async Task<Game> CreateTestGameAsync(AppDbContext dbContext)

public static async Task<ApplicationUser> CreateUserAsync(AppDbContext context)
{
Credentials credentials = new() { Username = "Test", Password = "Test", Email = "[email protected]" };
Credentials credentials = new() { Username = "Test", Password = "Test12345", Email = "[email protected]" };
return await CreateUserAsync(context, credentials);
}

Expand Down
6 changes: 6 additions & 0 deletions FU.API/FU.API/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
bin/
obj/
Dockerfile
docker-compose.yml
README.md
.env
27 changes: 25 additions & 2 deletions FU.API/FU.API/Controllers/UsersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ public class UsersController : ControllerBase
{
private readonly IUserService _userService;
private readonly ISearchService _searchService;
private readonly IStorageService _storageService;

public UsersController(IUserService userService, ISearchService searchService)
public UsersController(IUserService userService, ISearchService searchService, IStorageService storageService)
{
_userService = userService;
_searchService = searchService;
_storageService = storageService;
}

[HttpGet]
Expand Down Expand Up @@ -74,7 +76,28 @@ public async Task<IActionResult> UpdateProfile([FromBody] UserProfile profileCha
// Overrides any client given id that may differ from userId.
profileChanges.Id = userId;

var newProfile = await _userService.UpdateUserProfile(profileChanges);
// Make sure its an image already in our blob storage
// Otherwise we are unure if the image is cropped, resized, and in the right format
if (profileChanges?.PfpUrl is not null)
{
Uri avatarUri;

try
{
avatarUri = new(profileChanges.PfpUrl);
}
catch (UriFormatException)
{
throw new UnprocessableException("Invalid avatar url format.");
}

if (!(await _storageService.IsInStorageAsync(avatarUri)))
{
throw new UnprocessableException("Invalid profile picture. The image must be uploaded to our storage system");
}
}

var newProfile = await _userService.UpdateUserProfile(profileChanges!);

return Ok(newProfile);
}
Expand Down
4 changes: 2 additions & 2 deletions FU.API/FU.API/DTOs/Search/PostSearchRequestDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ public record PostSearchRequestDTO
public string? Games { get; set; }

[FromQuery]
public DateOnly? StartOnOrAfterDate { get; set; }
public DateTime? StartOnOrAfterDateTime { get; set; }

[FromQuery]
public DateOnly? EndOnOrBeforeDate { get; set; }
public DateTime? EndOnOrBeforeDateTime { get; set; }

[FromQuery]
public TimeOnly? StartOnOrAfterTime { get; set; }
Expand Down
15 changes: 15 additions & 0 deletions FU.API/FU.API/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# https://hub.docker.com/_/microsoft-dotnet
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build

# copy everything and build app
WORKDIR /source
COPY . .
RUN mkdir /app
RUN dotnet publish -o /app

# final stage/image
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build /app ./
ENTRYPOINT ["dotnet", "FU.API.dll"]

2 changes: 1 addition & 1 deletion FU.API/FU.API/FU.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
1 change: 0 additions & 1 deletion FU.API/FU.API/Helpers/AuthHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,4 @@ private static string GetJwtSecretFromConfig(this IConfiguration configuration)
{
return configuration[ConfigKey.JwtSecret] ?? string.Empty;
}

}
4 changes: 2 additions & 2 deletions FU.API/FU.API/Helpers/Mapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ public static PostQuery ToPostQuery(this PostSearchRequestDTO dto)
{
var query = new PostQuery()
{
StartOnOrAfterDate = dto.StartOnOrAfterDate,
EndOnOrBeforeDate = dto.EndOnOrBeforeDate,
StartOnOrAfterDateTime = dto.StartOnOrAfterDateTime,
EndOnOrBeforeDateTime = dto.EndOnOrBeforeDateTime,
StartOnOrAfterTime = dto.StartOnOrAfterTime,
EndOnOrBeforeTime = dto.EndOnOrBeforeTime,
MinimumRequiredPlayers = dto.MinPlayers ?? 0,
Expand Down
2 changes: 2 additions & 0 deletions FU.API/FU.API/Interfaces/IStorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ public interface IStorageService
public Task<Uri> UploadAsync(Stream stream, string fileName);

public Task DeleteOldUnusedFilesAsync();

public Task<bool> IsInStorageAsync(Uri uri);
}
8 changes: 4 additions & 4 deletions FU.API/FU.API/Migrations/20240317012258_ConfirmAccount.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable
#nullable disable

namespace FU.API.Migrations
{
using Microsoft.EntityFrameworkCore.Migrations;

/// <inheritdoc />
public partial class ConfirmAccount : Migration
{
Expand All @@ -22,7 +22,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
table: "Users",
type: "text",
nullable: false,
defaultValue: "");
defaultValue: string.Empty);
}

/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable
#nullable disable

namespace FU.API.Migrations
{
using Microsoft.EntityFrameworkCore.Migrations;

/// <inheritdoc />
public partial class AddChatToUserRelation : Migration
{
Expand Down
4 changes: 2 additions & 2 deletions FU.API/FU.API/Models/PostQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ public record PostQuery
{
public List<int> GameIds { get; set; } = new();
public List<int> TagIds { get; set; } = new();
public DateOnly? StartOnOrAfterDate { get; set; } = null;
public DateOnly? EndOnOrBeforeDate { get; set; } = null;
public DateTime? StartOnOrAfterDateTime { get; set; } = null;
public DateTime? EndOnOrBeforeDateTime { get; set; } = null;
public TimeOnly? StartOnOrAfterTime { get; set; } = null;
public TimeOnly? EndOnOrBeforeTime { get; set; } = null;
public int MinimumRequiredPlayers { get; set; } = 0;
Expand Down
42 changes: 31 additions & 11 deletions FU.API/FU.API/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ private static void Main(string[] args)
{
WebApplication app = BuildApp(args);
ConfigureApp(app);
ApplyDbMigrations(app.Configuration);
app.Run();
}

Expand Down Expand Up @@ -56,6 +57,17 @@ private static void ConfigureApp(in WebApplication app)
app.MapHub<ChatHub>("/chathub");
}

private static void ApplyDbMigrations(IConfiguration config)
{
// Create a DbContext
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
optionsBuilder.UseNpgsql(config[ConfigKey.ConnectionString]);
using AppDbContext dbContext = new(optionsBuilder.Options);

// Dangerous. See https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/applying?tabs=dotnet-core-cli#apply-migrations-at-runtime
dbContext.Database.Migrate();
}

private static WebApplication BuildApp(string[] args)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
Expand Down Expand Up @@ -115,7 +127,25 @@ private static WebApplication BuildApp(string[] args)
builder.Services.AddScoped<IRelationService, RelationService>();
builder.Services.AddScoped<ICommonService, CommonService>();
builder.Services.AddScoped<IStorageService, AzureBlobStorageService>();
builder.Services.AddSingleton<IEmailService, EmailService>();

if (builder.Configuration[ConfigKey.BaseSpaUrl] is null || builder.Configuration[ConfigKey.EmailConnectionString] is null)
{
if (builder.Configuration[ConfigKey.EmailConnectionString] is null)
{
Console.WriteLine($"Email service connection string is not configured. Missing {ConfigKey.EmailConnectionString}. See README for adding. Will use mock email service.");
}

if (builder.Configuration[ConfigKey.BaseSpaUrl] is null)
{
Console.WriteLine($"The base SPA Url is not configured. Missing {ConfigKey.BaseSpaUrl}. See README for adding. Will use mock email service.");
}

builder.Services.AddSingleton<IEmailService, MockEmailService>();
}
else
{
builder.Services.AddSingleton<IEmailService, EmailService>();
}

builder.Services.AddSignalR(options =>
{
Expand Down Expand Up @@ -200,15 +230,5 @@ private static void AssertCriticalConfigValuesExist(in ConfigurationManager conf
{
throw new Exception($"Storage connection string is not configured. Missing {ConfigKey.StorageConnectionString}. See README for adding.");
}

if (config[ConfigKey.EmailConnectionString] is null)
{
throw new Exception($"Email service connection string is not configured. Missing {ConfigKey.EmailConnectionString}. See README for adding.");
}

if (config[ConfigKey.BaseSpaUrl] is null)
{
throw new Exception($"The base SPA Url is not configured. Missing {ConfigKey.BaseSpaUrl}. See README for adding.");
}
}
}
7 changes: 7 additions & 0 deletions FU.API/FU.API/Services/AccountsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ public async Task<ApplicationUser> Register(Credentials credentials)
throw new ConflictException("User with email already exists");
}

// Make sure the password is valid
// Must be 5 characters or longer, and contain at least one special character or number
if (credentials.Password.Length < 8 || !credentials.Password.Any(c => char.IsDigit(c) || char.IsPunctuation(c)))
{
throw new BadRequestException("Password must be at least 8 characters long and contain at least one special character or number");
}

_dbContext.Users.Add(new ApplicationUser()
{
Username = credentials.Username,
Expand Down
Loading

0 comments on commit 1d8a989

Please sign in to comment.