Skip to content

Commit

Permalink
Merge pull request #20 from romandykyi/implement-invitation-links
Browse files Browse the repository at this point in the history
Implement Invitation Links
  • Loading branch information
romandykyi authored Apr 1, 2024
2 parents 43dd6f7 + 14053bc commit 415a26a
Show file tree
Hide file tree
Showing 27 changed files with 2,051 additions and 6 deletions.
6 changes: 6 additions & 0 deletions AdvancedTodoList.Core/Dtos/InvitationLinkDtos.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace AdvancedTodoList.Core.Dtos;

/// <summary>
/// Represents a DTO for invitation link view.
/// </summary>
public record InvitationLinkDto(int Id, string Value, DateTime ValidTo);
2 changes: 1 addition & 1 deletion AdvancedTodoList.Core/Dtos/TodoListMembersDtos.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace AdvancedTodoList.Core.Dtos;

/// <summary>
/// DTO for a minimal view of a to-do list.
/// DTO for a minimal view of a to-do list member.
/// </summary>
public record TodoListMemberMinimalViewDto(int Id, string UserId, string TodoListId, int? RoleId);

Expand Down
36 changes: 36 additions & 0 deletions AdvancedTodoList.Core/Models/TodoLists/InvitationLink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace AdvancedTodoList.Core.Models.TodoLists;

/// <summary>
/// Represents a to-do list invitation link entity.
/// </summary>
public class InvitationLink : IEntity<int>
{
/// <summary>
/// A unique identifier for the to-do list item.
/// </summary>
[Key]
public int Id { get; set; }

/// <summary>
/// Foreign key of the to-do list where the link is active.
/// </summary>
[ForeignKey(nameof(TodoList))]
public required string TodoListId { get; set; }
/// <summary>
/// Navigation property to the to-do list associated with this link.
/// </summary>
public TodoList TodoList { get; set; } = null!;

/// <summary>
/// A unique string value representing the link.
/// </summary>
public required string Value { get; set; }

/// <summary>
/// Date after which the link becomes invalid.
/// </summary>
public DateTime ValidTo { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
/// <param name="AddItems">A flag that determines whether user can add to-do list items.</param>
/// <param name="EditItems">A flag that determines whether user can edit to-do list items of other users and the to-do list itself.</param>
/// <param name="DeleteItems"> A flag that determines whether user can delete to-do list items of other users.</param>
/// <param name="AddMembers">A flag that determines whether user can add members.</param>
/// <param name="AddMembers">A flag that determines whether user can add members and create invitation links.</param>
/// <param name="RemoveMembers">A flag that determines whether user can remove members.</param>
/// <param name="AssignRoles">A flag that determines whether user can assign a role to other member.</param>
/// <param name="EditRoles">A flag that determines whether user can edit/delete existing roles and add new roles.</param>
/// <param name="EditRoles">A flag that determines whether user can cedit/delete existing categories and add new categories.</param>
/// <param name="EditCategories">A flag that determines whether user can edit/delete existing categories and add new categories.</param>
/// <param name="ManageInvitationLinks">A flag that determines whether user can view/delete existing invitation links.</param>
public record struct RolePermissions(
bool SetItemsState = false,
bool AddItems = false,
Expand All @@ -21,11 +22,12 @@ public record struct RolePermissions(
bool RemoveMembers = false,
bool AssignRoles = false,
bool EditRoles = false,
bool EditCategories = false
bool EditCategories = false,
bool ManageInvitationLinks = false
)
{
/// <summary>
/// Instance of a structure with all permissions.
/// </summary>
public static readonly RolePermissions All = new(true, true, true, true, true, true, true, true, true);
public static readonly RolePermissions All = new(true, true, true, true, true, true, true, true, true, true);
}
17 changes: 17 additions & 0 deletions AdvancedTodoList.Core/Options/InvitationLinkOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace AdvancedTodoList.Core.Options;

/// <summary>
/// A class that contains invitation link options.
/// </summary>
public class InvitationLinkOptions
{
/// <summary>
/// Size of the refresh token in bytes.
/// </summary>
public int Size { get; set; }

/// <summary>
/// Days before token expires.
/// </summary>
public int ExpirationDays { get; set; }
}
16 changes: 16 additions & 0 deletions AdvancedTodoList.Core/Repositories/IInvitationLinksRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using AdvancedTodoList.Core.Models.TodoLists;

namespace AdvancedTodoList.Core.Repositories;

public interface IInvitationLinksRepository : IRepository<InvitationLink, int>
{
/// <summary>
/// Finds an invintation link by its value asynchronously.
/// </summary>
/// <param name="linkValue">Value of the link.</param>
/// <returns>
/// A task representing asynchronous operation which contains requested link or
/// <see cref="null" /> it was not found.
/// </returns>
Task<InvitationLink?> FindAsync(string linkValue);
}
54 changes: 54 additions & 0 deletions AdvancedTodoList.Core/Services/IInvitationLinksService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using AdvancedTodoList.Core.Dtos;
using AdvancedTodoList.Core.Pagination;

namespace AdvancedTodoList.Core.Services;

/// <summary>
/// An interface for a service that manages invitation links.
/// </summary>
public interface IInvitationLinksService
{
/// <summary>
/// Joins the caller to the to-do list by invitation list asynchronously.
/// </summary>
/// <param name="callerId">ID of the caller.</param>
/// <param name="invitationLinkValue">Invitation link to use.</param>
/// <returns>
/// A task representing the asynchronous operation. The task contains
/// a result of the operation.
/// </returns>
Task<JoinByInvitationLinkResult> JoinAsync(string callerId, string invitationLinkValue);

/// <summary>
/// Gets invitation links associated with the to-do list asynchronously.
/// </summary>
/// <param name="context">To-do list context of the operation.</param>
/// <param name="parameters">Pagination parameters to use.</param>
/// <returns>
/// A task representing the asynchronous operation. The task contains
/// a result of the operation.
/// </returns>
Task<ServiceResponse<Page<InvitationLinkDto>>> GetInvitationLinksAsync(TodoListContext context,
PaginationParameters parameters);

/// <summary>
/// Creates an invitation link associated to the to-do list asynchronously.
/// </summary>
/// <param name="context">To-do list context.</param>
/// <returns>
/// A task representing the asynchronous operation. The task contains
/// a result of the operation.
/// </returns>
Task<ServiceResponse<InvitationLinkDto>> CreateAsync(TodoListContext context);

/// <summary>
/// Deletes an invitation link associted to the to-do list asynchronously.
/// </summary>
/// <param name="context">To-do list context.</param>
/// <param name="linkId">ID of the link.</param>
/// <returns>
/// A task representing the asynchronous operation. The task contains
/// a result of the operation.
/// </returns>
Task<ServiceResponseStatus> DeleteAsync(TodoListContext context, int linkId);
}
42 changes: 42 additions & 0 deletions AdvancedTodoList.Core/Services/JoinByInvitationLinkResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using AdvancedTodoList.Core.Dtos;

namespace AdvancedTodoList.Core.Services;

/// <summary>
/// Represents possible results of the join to-do list by invitatation link operation.
/// </summary>
public class JoinByInvitationLinkResult(JoinByInvitationLinkStatus status, TodoListMemberMinimalViewDto? dto = null)
{
/// <summary>
/// Status of the operation.
/// </summary>
public JoinByInvitationLinkStatus Status { get; } = status;

/// <summary>
/// Gets additional DTO of the member, can be <see langword="null" />.
/// </summary>
public TodoListMemberMinimalViewDto? Dto { get; } = dto;
}

/// <summary>
/// Enum that represents possible result statuses of the join to-do list by invitatation link operation.
/// </summary>
public enum JoinByInvitationLinkStatus
{
/// <summary>
/// Operation was successfull.
/// </summary>
Success,
/// <summary>
/// Invitation link was not found.
/// </summary>
NotFound,
/// <summary>
/// Invitation link is expired.
/// </summary>
Expired,
/// <summary>
/// User is already a member of the to-do list.
/// </summary>
UserIsAlreadyMember
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options
public DbSet<TodoList> TodoLists { get; set; }
public DbSet<TodoItem> TodoItems { get; set; }
public DbSet<TodoItemCategory> TodoItemCategories { get; set; }
public DbSet<InvitationLink> InvitationLinks { get; set; }
public DbSet<TodoListMember> TodoListsMembers { get; set; }
public DbSet<TodoListRole> TodoListRoles { get; set; }
public DbSet<UserRefreshToken> UserRefreshTokens { get; set; }
Expand Down
Loading

0 comments on commit 415a26a

Please sign in to comment.