Skip to content

Commit

Permalink
Merge pull request #556 from SCCapstone/main
Browse files Browse the repository at this point in the history
1.0 Release
  • Loading branch information
evan-scales authored Apr 22, 2024
2 parents c6a6e4e + 33d16b2 commit 7f56ff8
Show file tree
Hide file tree
Showing 67 changed files with 866 additions and 162 deletions.
4 changes: 4 additions & 0 deletions FU.API/FU.API/DTOs/Chat/ChatResponseDTO.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
namespace FU.API.DTOs.Chat;

/// <summary>
/// The response DTO for chat.
/// Members is a collection of usernames.
/// </summary>
public class ChatResponseDTO
{
public int Id { get; set; }
Expand Down
4 changes: 4 additions & 0 deletions FU.API/FU.API/DTOs/Chat/MessageResponseDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

using FU.API.Models;

/// <summary>
/// The response DTO for message.
/// Sender is the user who sent the message, and contains the username and avatar.
/// </summary>
public class MessageResponseDTO
{
public int Id { get; set; }
Expand Down
4 changes: 4 additions & 0 deletions FU.API/FU.API/DTOs/Game/GameDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
using FU.API.Validation;
using System.ComponentModel.DataAnnotations;

/// <summary>
/// The DTO for creating/retrieving games.
/// Name is the name of the game.
/// </summary>
public class GameDTO
{
public int Id { get; set; }
Expand Down
4 changes: 4 additions & 0 deletions FU.API/FU.API/DTOs/Game/UpdateGameDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
using FU.API.Validation;
using System.ComponentModel.DataAnnotations;

/// <summary>
/// The DTO for updating games.
/// Only Name and ImageUrl can be updated.
/// </summary>
public class UpdateGameDTO
{
[NonEmptyString]
Expand Down
4 changes: 4 additions & 0 deletions FU.API/FU.API/DTOs/LoginRequestDTO.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
namespace FU.API.DTOs;

/// <summary>
/// The request DTO for login.
/// Used for logging in.
/// </summary>
public class LoginRequestDTO
{
public string Username { get; set; } = string.Empty;
Expand Down
5 changes: 5 additions & 0 deletions FU.API/FU.API/DTOs/Post/PostRequestDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
using FU.API.Validation;
using System.ComponentModel.DataAnnotations;

/// <summary>
/// The DTO for creating posts.
/// Needs a title and a gameId.
/// TagIds is a list of tag ids.
/// </summary>
public class PostRequestDTO
{
[NonEmptyString]
Expand Down
7 changes: 7 additions & 0 deletions FU.API/FU.API/DTOs/Post/PostResponseDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
using FU.API.DTOs.Chat;
using FU.API.Models;

/// <summary>
/// The response DTO for post.
/// May contain reference to the last message in the chat.
/// Includes the creator of the post.
/// Include the game name, and list of tag names.
/// Indicates if the current user has joined the post.
/// </summary>
public class PostResponseDTO
{
public int Id { get; set; }
Expand Down
4 changes: 4 additions & 0 deletions FU.API/FU.API/DTOs/ResendConfirmationDTO.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
namespace FU.API.DTOs;

/// <summary>
/// The DTO for resending a confirmation email.
/// May be trying to find the user by email or username.
/// </summary>
public class ResendConfirmationDTO
{
public string? Email { get; set; }
Expand Down
5 changes: 5 additions & 0 deletions FU.API/FU.API/DTOs/Search/PostSearchRequestDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ namespace FU.API.DTOs.Search;

using Microsoft.AspNetCore.Mvc;

/// <summary>
/// Represents a request to search for posts.
/// All properties are optional.
/// Will be converted to a PostQuery.
/// </summary>
public record PostSearchRequestDTO
{
[FromQuery]
Expand Down
5 changes: 5 additions & 0 deletions FU.API/FU.API/DTOs/Search/UserSearchRequestDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ namespace FU.API.DTOs.Search;

using Microsoft.AspNetCore.Mvc;

/// <summary>
/// The request DTO for searching for users.
/// All properties are optional.
/// Will be converted to a UserQuery.
/// </summary>
public record UserSearchRequestDTO
{
[FromQuery]
Expand Down
4 changes: 4 additions & 0 deletions FU.API/FU.API/DTOs/Tag/TagRequestDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
using System.ComponentModel.DataAnnotations;
using FU.API.Validation;

/// <summary>
/// The DTO for creating tags.
/// Tag names can't be longer than 20 characters.
/// </summary>
public class TagRequestDTO
{
[NoSpaces]
Expand Down
4 changes: 4 additions & 0 deletions FU.API/FU.API/DTOs/Tag/TagResponseDTO.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
namespace FU.API.DTOs.Tag;

/// <summary>
/// The response DTO for tags.
/// Includes the tag's id and name.
/// </summary>
public class TagResponseDTO
{
public int Id { get; set; }
Expand Down
3 changes: 3 additions & 0 deletions FU.API/FU.API/DTOs/UpdateCredentialDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
using FU.API.Validation;
using System.ComponentModel.DataAnnotations;

/// <summary>
/// Used for updating credentials.
/// </summary>
public record UpdateCredentailsDTO
{
[NonEmptyString]
Expand Down
3 changes: 3 additions & 0 deletions FU.API/FU.API/DTOs/User/UserRelationDTO.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace FU.API.DTOs.User;

/// <summary>
/// The response DTO for user relations.
/// </summary>
public class UserRelationDTO
{
public string Status { get; set; } = string.Empty;
Expand Down
4 changes: 4 additions & 0 deletions FU.API/FU.API/Helpers/AuthHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
using System.Security.Claims;
using System.Text;

/// <summary>
/// Helper class for creating authentication tokens.
/// Used when a user logs in or sending account verification emails.
/// </summary>
public static class AuthHelper
{
public static AuthenticationInfo CreateAuthInfo(IConfiguration configuration, DateTime expires, int userId)
Expand Down
5 changes: 5 additions & 0 deletions FU.API/FU.API/Helpers/Mapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ namespace FU.API.Helpers;
using FU.API.DTOs.User;
using FU.API.DTOs;

/// <summary>
/// A static class that contains extension methods for mapping between DTOs and models.
/// Used to keep the controllers clean.
/// Simple mapping, and no complex logic.
/// </summary>
public static class Mapper
{
public static UserProfile ToProfile(this ApplicationUser appUser, Message? lastChatMessage = null)
Expand Down
2 changes: 2 additions & 0 deletions FU.API/FU.API/Services/PostService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public async Task<Post> UpdatePost(Post postChanges)
throw new PostException("The updated post's creator does not match the old post's creator", HttpStatusCode.UnprocessableEntity);
}

AssertValidDateAndTime(postChanges);

ogPost.Game = await _dbContext.Games.FindAsync(postChanges.GameId) ?? throw new NonexistentGameException();
ogPost.Description = postChanges.Description;
ogPost.MaxPlayers = postChanges.MaxPlayers;
Expand Down
180 changes: 128 additions & 52 deletions FU.API/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,76 @@
- Azure Communication Service is used to send emails
- Docker can be used for containerization

## Development

### External Requirements

In order to run the project you first have to install:

- [ASP.NET Core 7](https://learn.microsoft.com/en-us/aspnet/core/introduction-to-aspnet-core?view=aspnetcore-7.0)
- [PostgreSQL](https://www.postgresql.org/download/)

### Postgres Setup

Install and start the database by installing Docker and running the following command.

```
docker run --name postgres-490 -e POSTGRES_DB=fu_dev -e POSTGRES_PASSWORD=dev -e POSTGRES_USER=dev -p 5432:5432 postgres:alpine
```

To run the container at a later time, run:

```
docker container start postgres-490
```

Alternatively, install and start a PostgreSQL database manually.

### Config Setup

Config settings are loaded from the environment variables. To automatically load the environment variable from a file, create a `.env` file in this folder.

#### Blob storage

An azure storage account is needed with a storage container. Public anonymous access must be enabled. The `STORAGE_CONNECTION_STRING` and `AVATAR_CONTAINER_NAME` environment variables must be set.

```
STORAGE_CONNECTION_STRING="XXXXXXXX"
AVATAR_CONTAINER_NAME="some-container-name"
```

#### Jwt Secret

A random string of 32+ characters is required in the `JWT_SECRET` environment variable as a Jwt Secret.

```
JWT_SECRET="my-32-character-ultra-secure-and-ultra-long-secret"
```

#### Email service

An azure communication service is needed to send emails.

```
EMAIL_CONNECTION_STRING="XXXXXXXX"
```

#### Connect to Postgres

Set the postgres `CONNECTION_STRING` environment variable.

```
CONNECTION_STRING="Host=localhost; Database=fu_dev; Username=dev; Password=dev"
```

### Coding Style

Follow Google's C# [style guide](https://google.github.io/styleguide/csharp-style.html)

## Testing

Run tests on the backend with `dotnet test`. Tests are located in `FU.API.Tests/`. They consist of service unit tests as behavioral testing is done by the SPA.

## Understanding Controllers

The controllers serve as wrappers around the Services. They take an http request, run a corresponding service calls, and return an http result. For example consider the following `GameController` class.
Expand Down Expand Up @@ -73,72 +143,78 @@ When users navigate to a pages with a chat, they will be connected the chat grou

First an avatar is uploaded to the server via `AvatarController.UploadAvatar`. Then it is validated to be an image, cropped to be square, resized, and converted to a JPEG using the `SkiaSharp` library. Then the image is uploaded to a public azure storage blob and its a url is returned to the user for previewing. If the user wants to use the image, they call `UsersController.UpdateProfile` to set it as their new avatar. After awhile, unused profile pictures are deleted by `PeriodicRemoteStorageCleanerHostedService`.

## Development
## Understanding DTOs

### External Requirements
DTOs, or Data Transfer Objects, serve as simple objects that carry data between processes, typically between a client and a server.

In order to run the project you first have to install:
Consider the following DTO as an example:

- [ASP.NET Core 7](https://learn.microsoft.com/en-us/aspnet/core/introduction-to-aspnet-core?view=aspnetcore-7.0)
- [PostgreSQL](https://www.postgresql.org/download/)

### Postgres Setup

Install and start the database by installing Docker and running the following command.

```
docker run --name postgres-490 -e POSTGRES_DB=fu_dev -e POSTGRES_PASSWORD=dev -e POSTGRES_USER=dev -p 5432:5432 postgres:alpine
```
public record UserSearchRequestDTO
{
[FromQuery]
public string? Keywords { get; set; }
To run the container at a later time, run:
[FromQuery]
public string? Sort { get; set; }
```
docker container start postgres-490
```

Alternatively, install and start a PostgreSQL database manually.

### Config Setup

Config settings are loaded from the environment variables. To automatically load the environment variable from a file, create a `.env` file in this folder.

#### Blob storage

An azure storage account is needed with a storage container. Public anonymous access must be enabled. The `STORAGE_CONNECTION_STRING` and `AVATAR_CONTAINER_NAME` environment variables must be set.
[FromQuery]
public int? Limit { get; set; }
[FromQuery]
public int? Page { get; set; }
}
```
STORAGE_CONNECTION_STRING="XXXXXXXX"
AVATAR_CONTAINER_NAME="some-container-name"
```

In this example, UserSearchRequestDTO is a DTO used for handling user search requests. It contains properties for keywords, sorting criteria, pagination limits, and page numbers. The [FromQuery] attribute indicates that the properties should be bound from the query string when used in our ASP.NET Web API.

#### Jwt Secret

A random string of 32+ characters is required in the `JWT_SECRET` environment variable as a Jwt Secret.
To process the user search request, a static mapper class is utilized to convert the UserSearchRequestDTO to a UserQuery. Here's an example of how it's done:

```
JWT_SECRET="my-32-character-ultra-secure-and-ultra-long-secret"
```

#### Email service

An azure communication service is needed to send emails.
public static class Mapper
{
...
public static UserQuery ToUserQuery(this UserSearchRequestDTO dto)
{
var query = new UserQuery()
{
Limit = dto.Limit ?? 20,
Page = dto.Page ?? 1,
SortType = UserSortType.Username, // Default value
SortDirection = SortDirection.Ascending // Default value
};
// Splitting keywords if provided
if (dto.Keywords is not null)
{
query.Keywords = dto.Keywords.Split(" ").ToList();
}
```
EMAIL_CONNECTION_STRING="XXXXXXXX"
```
// Setting default sort if not provided
dto.Sort ??= "newest:desc";
#### Connect to Postgres
// Parsing and setting sort type and direction
var arr = dto.Sort.ToLower().Split(":");
query.SortType = arr[0] switch
{
"username" => UserSortType.Username,
"dob" => UserSortType.DOB,
"chatactivity" => UserSortType.ChatActivity,
_ => UserSortType.Username,
};
Set the postgres `CONNECTION_STRING` environment variable.
if (arr.Length > 1 && arr[1].StartsWith("desc"))
{
query.SortDirection = SortDirection.Descending;
}
else
{
query.SortDirection = SortDirection.Ascending;
}
return query;
}
}
```
CONNECTION_STRING="Host=localhost; Database=fu_dev; Username=dev; Password=dev"
```

### Coding Style

Follow Google's C# [style guide](https://google.github.io/styleguide/csharp-style.html)

## Testing

Run tests on the backend with `dotnet test`. Tests are located in `FU.API.Tests/`. They consist of service unit tests as behavioral testing is done by the SPA.
This static mapper class contains a method ToUserQuery which takes a UserSearchRequestDTO and converts it into a UserQuery object, which is then used in the search service to perform the actual search operation.
Loading

0 comments on commit 7f56ff8

Please sign in to comment.