diff --git a/SurveyBackend/SurveyBackend.API/Contexts/UserContext.cs b/SurveyBackend/SurveyBackend.API/Contexts/UserContext.cs
index 298cc59..de5e7f1 100644
--- a/SurveyBackend/SurveyBackend.API/Contexts/UserContext.cs
+++ b/SurveyBackend/SurveyBackend.API/Contexts/UserContext.cs
@@ -1,19 +1,31 @@
using System.Security.Claims;
using SurveyBackend.Core.Contexts;
+using SurveyBackend.Services.Exceptions;
namespace SurveyBackend.Contexts;
+///
+/// Упрощает получение UserId из JWT-токена
+///
public class UserContext : IUserContext
{
private readonly IHttpContextAccessor _httpContextAccessor;
+ ///
+ /// Добавьте HttpContextAccessor в DI и будет счастье
+ ///
+ ///
public UserContext(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
+ ///
+ /// Возвращает UserId из токена, при отсуствии кидает Unauthorized
+ ///
+ ///
public int UserId =>
int.Parse(
_httpContextAccessor.HttpContext?.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)
- ?.Value ?? throw new UnauthorizedAccessException());
+ ?.Value ?? throw new UnauthorizedException("Where's your token mister"));
}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/Controllers/AuthController.cs b/SurveyBackend/SurveyBackend.API/Controllers/AuthController.cs
index 6e5148a..a4ee704 100644
--- a/SurveyBackend/SurveyBackend.API/Controllers/AuthController.cs
+++ b/SurveyBackend/SurveyBackend.API/Controllers/AuthController.cs
@@ -6,17 +6,32 @@ using IAuthorizationService = SurveyBackend.Core.Services.IAuthorizationService;
namespace SurveyBackend.Controllers;
+///
+/// Контроллер для всего связанного с авторизацией пользователей
+///
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly IAuthorizationService _authorizationService;
+ ///
+ /// Нет ну вы прикалываетесь что ли мне ща каждый контроллер описывать?
+ ///
+ ///
public AuthController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
+ ///
+ /// Авторизация
+ ///
+ /// Принимает на вход email и password. При отсутствии такого email вернет 404, при неправильном пароле 401, при успехе 200 и валидный токен
+ ///
+ /// Success: Возвращает токен
+ /// Unauthorized: Неправильный пароль
+ ///
[AllowAnonymous]
[HttpPost("login")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
@@ -27,6 +42,12 @@ public class AuthController : ControllerBase
return Ok(new { token = token });
}
+ ///
+ /// Регистрация
+ ///
+ /// Принимает на вход кучу всяких полей, потом разберемся
+ ///
+ ///
[AllowAnonymous]
[HttpPost("register")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
diff --git a/SurveyBackend/SurveyBackend.API/Controllers/QuestionController.cs b/SurveyBackend/SurveyBackend.API/Controllers/QuestionController.cs
index a8b5764..e9ac6a0 100644
--- a/SurveyBackend/SurveyBackend.API/Controllers/QuestionController.cs
+++ b/SurveyBackend/SurveyBackend.API/Controllers/QuestionController.cs
@@ -7,17 +7,25 @@ using SurveyLib.Core.Services;
namespace SurveyBackend.Controllers;
+///
[ApiController]
[Route("api/surveys/{surveyId}/questions")]
public class QuestionController : ControllerBase
{
private readonly IQuestionService _questionService;
+ ///
public QuestionController(IQuestionService questionService, IUserContext userContext)
{
_questionService = questionService;
}
+ ///
+ /// Возвращает список вопросов из опроса по его ID
+ ///
+ /// Получение вопросов по ID опроса. В случае отсутствия опроса с таким идентификатором выкидывает 404
+ ///
+ ///
[AllowAnonymous]
[HttpGet]
[ProducesResponseType(StatusCodes.Status404NotFound)]
@@ -29,6 +37,13 @@ public class QuestionController : ControllerBase
return Ok(result);
}
+ ///
+ /// Добавить вопрос к опросу
+ ///
+ /// К опросу с указанным ID добавляет вопрос. Если я правильно написал, при отсутствии такого опроса кинет 404
+ ///
+ ///
+ ///
[Authorize]
[HttpPost]
[ProducesResponseType(StatusCodes.Status404NotFound)]
diff --git a/SurveyBackend/SurveyBackend.API/Controllers/SurveyController.cs b/SurveyBackend/SurveyBackend.API/Controllers/SurveyController.cs
index d471152..24f1cd2 100644
--- a/SurveyBackend/SurveyBackend.API/Controllers/SurveyController.cs
+++ b/SurveyBackend/SurveyBackend.API/Controllers/SurveyController.cs
@@ -10,6 +10,7 @@ using SurveyLib.Core.Services;
namespace SurveyBackend.Controllers;
+///
[ApiController]
[Route("api/surveys")]
public class SurveyController : ControllerBase
@@ -17,12 +18,18 @@ public class SurveyController : ControllerBase
private readonly ISurveyService _surveyService;
private readonly IUserContext _userContext;
+ ///
public SurveyController(ISurveyService surveyService, IUserContext userContext)
{
_surveyService = surveyService;
_userContext = userContext;
}
+ ///
+ /// Получить ВСЕ опросы
+ ///
+ /// Возвращает массив вообще всех опросов
+ ///
[AllowAnonymous]
[HttpGet]
[ProducesResponseType(typeof(List), StatusCodes.Status200OK)]
@@ -33,6 +40,12 @@ public class SurveyController : ControllerBase
return Ok(result);
}
+ ///
+ /// Получить опрос по ID
+ ///
+ /// А что тут говорить то
+ ///
+ ///
[AllowAnonymous]
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
@@ -44,6 +57,12 @@ public class SurveyController : ControllerBase
return Ok(result);
}
+ ///
+ /// Добавить новый опрос
+ ///
+ ///
+ ///
+ ///
[Authorize]
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
@@ -56,6 +75,12 @@ public class SurveyController : ControllerBase
return Created();
}
+ ///
+ /// Удалить опрос по ID
+ ///
+ /// Опрос должен быть создан тобой чтоб его удалить
+ ///
+ ///
[Authorize]
[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
@@ -67,6 +92,11 @@ public class SurveyController : ControllerBase
return Ok();
}
+ ///
+ /// Получить МОИ опроса
+ ///
+ /// Возвращает только опросы созданные нынешним юзером
+ ///
[Authorize]
[HttpGet("my")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
diff --git a/SurveyBackend/SurveyBackend.API/Controllers/TestController.cs b/SurveyBackend/SurveyBackend.API/Controllers/TestController.cs
index cbf5688..2d7a6ca 100644
--- a/SurveyBackend/SurveyBackend.API/Controllers/TestController.cs
+++ b/SurveyBackend/SurveyBackend.API/Controllers/TestController.cs
@@ -3,6 +3,9 @@ using SurveyLib.Core.Services;
namespace SurveyBackend.Controllers;
+///
+/// Удалим когда-нибудь
+///
[ApiController]
[Route("api/test")]
public class TestController : ControllerBase
diff --git a/SurveyBackend/SurveyBackend.API/DTOs/Question/CreateQuestionDTO.cs b/SurveyBackend/SurveyBackend.API/DTOs/Question/CreateQuestionDTO.cs
index 2379b73..5fc9692 100644
--- a/SurveyBackend/SurveyBackend.API/DTOs/Question/CreateQuestionDTO.cs
+++ b/SurveyBackend/SurveyBackend.API/DTOs/Question/CreateQuestionDTO.cs
@@ -1,9 +1,21 @@
namespace SurveyBackend.DTOs.Question;
+///
+/// Схема для создания нового Question
+///
public class CreateQuestionDto
{
+ ///
+ /// Название вопроса
+ ///
public required string Title { get; set; }
+ ///
+ /// Тип вопроса
+ ///
public required string QuestionType { get; set; }
+ ///
+ /// Варианты ответа (только если вопрос с выбором)
+ ///
public List? AnswerVariants { get; set; }
}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/DTOs/Question/OutputAnswerVariantDTO.cs b/SurveyBackend/SurveyBackend.API/DTOs/Question/OutputAnswerVariantDTO.cs
index 9112795..ff1b77b 100644
--- a/SurveyBackend/SurveyBackend.API/DTOs/Question/OutputAnswerVariantDTO.cs
+++ b/SurveyBackend/SurveyBackend.API/DTOs/Question/OutputAnswerVariantDTO.cs
@@ -1,8 +1,20 @@
namespace SurveyBackend.DTOs.Question;
+///
+/// Выходная схема вариантов ответа
+///
public class OutputAnswerVariantDto
{
+ ///
+ /// ID варианта ответа
+ ///
public required int Id { get; set; }
+ ///
+ /// ID родительского вопроса
+ ///
public required int QuestionId { get; set; }
+ ///
+ /// Текст варианта ответа
+ ///
public required string Text { get; set; }
}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/DTOs/Question/OutputQuestionDto.cs b/SurveyBackend/SurveyBackend.API/DTOs/Question/OutputQuestionDto.cs
index bfae54c..f850365 100644
--- a/SurveyBackend/SurveyBackend.API/DTOs/Question/OutputQuestionDto.cs
+++ b/SurveyBackend/SurveyBackend.API/DTOs/Question/OutputQuestionDto.cs
@@ -1,10 +1,32 @@
namespace SurveyBackend.DTOs.Question;
+///
+/// Выходнпя схема вопроса
+///
public class OutputQuestionDto
{
+ ///
+ /// ID вопроса
+ ///
public required int Id { get; set; }
+
+ ///
+ /// ID родительского опроса
+ ///
public required int SurveyId { get; set; }
+
+ ///
+ /// Заголовок вопроса
+ ///
public required string Title { get; set; }
+
+ ///
+ /// Тип вопроса
+ ///
public required string QuestionType { get; set; }
+
+ ///
+ /// Варианты ответа
+ ///
public List? AnswerVariants { get; set; }
}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/DTOs/Survey/CreateSurveyDTO.cs b/SurveyBackend/SurveyBackend.API/DTOs/Survey/CreateSurveyDTO.cs
index 67bfaf6..0383257 100644
--- a/SurveyBackend/SurveyBackend.API/DTOs/Survey/CreateSurveyDTO.cs
+++ b/SurveyBackend/SurveyBackend.API/DTOs/Survey/CreateSurveyDTO.cs
@@ -1,7 +1,16 @@
namespace SurveyBackend.DTOs.Survey;
+///
+/// Схема для создания нового опроса
+///
public class CreateSurveyDto
{
+ ///
+ /// Название опроса
+ ///
public required string Title { get; set; }
+ ///
+ /// Опциональное описание опроса
+ ///
public string Description { get; set; } = string.Empty;
}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/DTOs/Survey/OutputSurveyDto.cs b/SurveyBackend/SurveyBackend.API/DTOs/Survey/OutputSurveyDto.cs
index faec104..dea522b 100644
--- a/SurveyBackend/SurveyBackend.API/DTOs/Survey/OutputSurveyDto.cs
+++ b/SurveyBackend/SurveyBackend.API/DTOs/Survey/OutputSurveyDto.cs
@@ -1,9 +1,24 @@
namespace SurveyBackend.DTOs.Survey;
+///
+/// Выходная схема опроса
+///
public class OutputSurveyDto
{
+ ///
+ /// ID опроса
+ ///
public required int Id { get; set; }
+ ///
+ /// Название опроса
+ ///
public required string Title { get; set; }
+ ///
+ /// Описание опроса
+ ///
public required string Description { get; set; }
+ ///
+ /// Создатель опроса (опционально)
+ ///
public int? CreatedBy { get; set; }
}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/DTOs/UserLoginDto.cs b/SurveyBackend/SurveyBackend.API/DTOs/UserLoginDto.cs
index 8e58ee2..2cf7002 100644
--- a/SurveyBackend/SurveyBackend.API/DTOs/UserLoginDto.cs
+++ b/SurveyBackend/SurveyBackend.API/DTOs/UserLoginDto.cs
@@ -1,7 +1,16 @@
namespace SurveyBackend.DTOs;
+///
+/// Схема авторизации пользователя
+///
public record UserLoginDto
{
+ ///
+ /// Почта
+ ///
public required string Email { get; set; }
+ ///
+ /// Пароль
+ ///
public required string Password { get; set; }
}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/DTOs/UserRegistrationDto.cs b/SurveyBackend/SurveyBackend.API/DTOs/UserRegistrationDto.cs
index 3c0808d..b67622e 100644
--- a/SurveyBackend/SurveyBackend.API/DTOs/UserRegistrationDto.cs
+++ b/SurveyBackend/SurveyBackend.API/DTOs/UserRegistrationDto.cs
@@ -1,10 +1,32 @@
namespace SurveyBackend.DTOs;
+///
+/// Схема регистрации пользователя
+///
public record UserRegistrationDto
{
- public string Email { get; set; }
+ ///
+ /// Почта
+ ///
+ public required string Email { get; set; }
+
+ ///
+ /// Юзернейм
+ ///
public string Username { get; set; }
+
+ ///
+ /// Имя
+ ///
public string FirstName { get; set; }
+
+ ///
+ /// Фамилия
+ ///
public string LastName { get; set; }
+
+ ///
+ /// Пароль
+ ///
public string Password { get; set; }
}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/Filters/EndpointAuthRequirementFilter.cs b/SurveyBackend/SurveyBackend.API/Filters/EndpointAuthRequirementFilter.cs
new file mode 100644
index 0000000..d93194f
--- /dev/null
+++ b/SurveyBackend/SurveyBackend.API/Filters/EndpointAuthRequirementFilter.cs
@@ -0,0 +1,38 @@
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.OpenApi.Models;
+using Swashbuckle.AspNetCore.SwaggerGen;
+
+namespace SurveyBackend.Filters;
+
+///
+public class EndpointAuthRequirementFilter : IOperationFilter
+{
+ ///
+ public void Apply(OpenApiOperation operation, OperationFilterContext context)
+ {
+ if (!context.ApiDescription
+ .ActionDescriptor
+ .EndpointMetadata
+ .OfType()
+ .Any())
+ {
+ return;
+ }
+
+ operation.Security = new List
+ {
+ new OpenApiSecurityRequirement
+ {
+ [new OpenApiSecurityScheme
+ {
+ Reference = new OpenApiReference
+ {
+ Type = ReferenceType.SecurityScheme,
+ Id = JwtBearerDefaults.AuthenticationScheme
+ }
+ }] = new List()
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/SurveyBackend/SurveyBackend.API/Mappers/AuthMapper.cs b/SurveyBackend/SurveyBackend.API/Mappers/AuthMapper.cs
index 50b1980..47a01e6 100644
--- a/SurveyBackend/SurveyBackend.API/Mappers/AuthMapper.cs
+++ b/SurveyBackend/SurveyBackend.API/Mappers/AuthMapper.cs
@@ -3,8 +3,16 @@ using SurveyBackend.DTOs;
namespace SurveyBackend.Mappers;
+///
+/// Маппер всего связанного с авторизацией
+///
public static class AuthMapper
{
+ ///
+ /// Перегнать схему регистрации в нового юзера
+ ///
+ ///
+ ///
public static User UserRegistrationToModel(UserRegistrationDto dto) => new User
{
Email = dto.Email,
diff --git a/SurveyBackend/SurveyBackend.API/Mappers/QuestionMapper.cs b/SurveyBackend/SurveyBackend.API/Mappers/QuestionMapper.cs
index b6fd399..dab60b9 100644
--- a/SurveyBackend/SurveyBackend.API/Mappers/QuestionMapper.cs
+++ b/SurveyBackend/SurveyBackend.API/Mappers/QuestionMapper.cs
@@ -5,8 +5,18 @@ using SurveyLib.Core.Models.QuestionVariants;
namespace SurveyBackend.Mappers;
+///
+/// Маппер всего про вопросы
+///
public static class QuestionMapper
{
+ ///
+ /// Создание вопроса в модель
+ ///
+ ///
+ ///
+ ///
+ ///
public static QuestionBase QuestionCreationToModel(CreateQuestionDto dto, int surveyId)
{
return dto.QuestionType.ToLower() switch
@@ -32,6 +42,11 @@ public static class QuestionMapper
};
}
+ ///
+ /// Модель в выходную схему
+ ///
+ ///
+ ///
public static OutputQuestionDto ModelToQuestionDto(QuestionBase question)
{
var withAnswerVariants = question.GetType() != typeof(TextQuestion);
diff --git a/SurveyBackend/SurveyBackend.API/Mappers/SurveyMapper.cs b/SurveyBackend/SurveyBackend.API/Mappers/SurveyMapper.cs
index 46f85cb..bbcc51f 100644
--- a/SurveyBackend/SurveyBackend.API/Mappers/SurveyMapper.cs
+++ b/SurveyBackend/SurveyBackend.API/Mappers/SurveyMapper.cs
@@ -3,8 +3,17 @@ using SurveyLib.Core.Models;
namespace SurveyBackend.Mappers;
+///
+/// Маппер всего про опросы
+///
public static class SurveyMapper
{
+ ///
+ /// Схема создания в модель
+ ///
+ ///
+ ///
+ ///
public static Survey CreateDtoToModel(CreateSurveyDto dto, int userId)
{
return new Survey
@@ -15,6 +24,11 @@ public static class SurveyMapper
};
}
+ ///
+ /// Модель в выходную схему
+ ///
+ ///
+ ///
public static OutputSurveyDto ModelToOutputDto(Survey survey)
{
return new OutputSurveyDto
diff --git a/SurveyBackend/SurveyBackend.API/Middlewares/ExceptionsMiddleware.cs b/SurveyBackend/SurveyBackend.API/Middlewares/ExceptionsMiddleware.cs
index 65c94f8..1898da8 100644
--- a/SurveyBackend/SurveyBackend.API/Middlewares/ExceptionsMiddleware.cs
+++ b/SurveyBackend/SurveyBackend.API/Middlewares/ExceptionsMiddleware.cs
@@ -2,17 +2,29 @@ using SurveyBackend.Services.Exceptions;
namespace SurveyBackend.Middlewares;
+///
+/// Имбовая миддлваря, ловит все эксепшны, кастомные прокидывает как HTTP-exception, остальные кидает 502 и кайфуем
+///
public class ExceptionsMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
+ ///
+ /// Ну типа конструктор хз
+ ///
+ ///
+ ///
public ExceptionsMiddleware(RequestDelegate next, ILogger logger)
{
_next = next;
_logger = logger;
}
+ ///
+ ///
+ ///
+ ///
public async Task InvokeAsync(HttpContext context)
{
try
diff --git a/SurveyBackend/SurveyBackend.API/Program.cs b/SurveyBackend/SurveyBackend.API/Program.cs
index 4c1f57b..f0669cb 100644
--- a/SurveyBackend/SurveyBackend.API/Program.cs
+++ b/SurveyBackend/SurveyBackend.API/Program.cs
@@ -7,6 +7,7 @@ using SurveyBackend.Contexts;
using SurveyBackend.Core.Contexts;
using SurveyBackend.Core.Repositories;
using SurveyBackend.Core.Services;
+using SurveyBackend.Filters;
using SurveyBackend.Infrastructure.Data;
using SurveyBackend.Infrastructure.Repositories;
using SurveyBackend.Middlewares;
@@ -84,20 +85,11 @@ public class Program
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
- c.AddSecurityRequirement(new OpenApiSecurityRequirement
- {
- {
- new OpenApiSecurityScheme
- {
- Reference = new OpenApiReference
- {
- Type = ReferenceType.SecurityScheme,
- Id = JwtBearerDefaults.AuthenticationScheme
- }
- },
- Array.Empty()
- }
- });
+
+ c.OperationFilter();
+
+ var filePath = Path.Combine(System.AppContext.BaseDirectory, "SurveyBackend.API.xml");
+ c.IncludeXmlComments(filePath);
});
var app = builder.Build();
diff --git a/SurveyBackend/SurveyBackend.API/SurveyBackend.API.csproj b/SurveyBackend/SurveyBackend.API/SurveyBackend.API.csproj
index fef66e7..85458f2 100644
--- a/SurveyBackend/SurveyBackend.API/SurveyBackend.API.csproj
+++ b/SurveyBackend/SurveyBackend.API/SurveyBackend.API.csproj
@@ -7,6 +7,14 @@
SurveyBackend
+
+ bin\Debug\SurveyBackend.API.xml
+
+
+
+ bin\Release\SurveyBackend.API.xml
+
+
Never
diff --git a/SurveyBackend/SurveyBackend.Services/Services/SurveyService.cs b/SurveyBackend/SurveyBackend.Services/Services/SurveyService.cs
index 9911697..fbdc2e7 100644
--- a/SurveyBackend/SurveyBackend.Services/Services/SurveyService.cs
+++ b/SurveyBackend/SurveyBackend.Services/Services/SurveyService.cs
@@ -26,7 +26,7 @@ public class SurveyService : ISurveyService
public async Task UpdateSurveyAsync(Survey survey)
{
if (survey.CreatedBy != _userContext.UserId)
- throw new UnauthorizedAccessException("You are not authorized to update this survey.");
+ throw new UnauthorizedException("You are not authorized to update this survey.");
await _surveyRepository.UpdateAsync(survey);
}
@@ -40,7 +40,7 @@ public class SurveyService : ISurveyService
if (survey.CreatedBy != _userContext.UserId)
{
- throw new UnauthorizedAccessException("You are not authorized to delete this survey.");
+ throw new UnauthorizedException("You are not authorized to delete this survey.");
}
await _surveyRepository.DeleteAsync(survey);