diff --git "a/Homeworks/v2/01 \320\222\321\213\320\261\320\276\321\200 \321\202\320\265\320\274\321\213 \320\264\320\273\321\217 \320\277\321\200\320\276\320\265\320\272\321\202\320\275\320\276\320\271 \321\200\320\260\320\261\320\276\321\202\321\213/Task.md" "b/Homeworks/v2/01 \320\222\321\213\320\261\320\276\321\200 \321\202\320\265\320\274\321\213 \320\264\320\273\321\217 \320\277\321\200\320\276\320\265\320\272\321\202\320\275\320\276\320\271 \321\200\320\260\320\261\320\276\321\202\321\213/Task.md" new file mode 100644 index 0000000..3cf6f6d --- /dev/null +++ "b/Homeworks/v2/01 \320\222\321\213\320\261\320\276\321\200 \321\202\320\265\320\274\321\213 \320\264\320\273\321\217 \320\277\321\200\320\276\320\265\320\272\321\202\320\275\320\276\320\271 \321\200\320\260\320\261\320\276\321\202\321\213/Task.md" @@ -0,0 +1,23 @@ +### Цель + +Целью этой домашней работы является получение одобрения по выбранной теме, функциям и ролям проектной работы. + +--- + +### Описание + +1. Выберите название темы +2. Напишите список ролей для максимально возможной версии вашего приложения, то есть все ваши, даже самые смелые, пожелания. +3. Напишите какие функции будут у каждой роли. +4. Напишите список из максимум 4 самых базовых функций. + +--- + +### Критерии оценивания + +- Пункт 1 - 2 баллов +- Пункт 2 - 2 балла +- Пункт 3 - 4 балла +- Пункт 4 - 2 балла + +Минимальный проходной балл - 6. diff --git "a/Homeworks/v2/02 \320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260 \320\270\320\275\321\202\320\265\321\200\320\260\320\272\321\202\320\270\320\262\320\275\320\276\320\263\320\276 \320\272\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\263\320\276 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217/Task.md" "b/Homeworks/v2/02 \320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260 \320\270\320\275\321\202\320\265\321\200\320\260\320\272\321\202\320\270\320\262\320\275\320\276\320\263\320\276 \320\272\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\263\320\276 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217/Task.md" new file mode 100644 index 0000000..a56a9bc --- /dev/null +++ "b/Homeworks/v2/02 \320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260 \320\270\320\275\321\202\320\265\321\200\320\260\320\272\321\202\320\270\320\262\320\275\320\276\320\263\320\276 \320\272\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\263\320\276 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217/Task.md" @@ -0,0 +1,35 @@ +### Цель + +В этом задании мы закрепим знания, полученные в ходе занятий, и создадим базовое интерактивное консольное приложение, используя основные принципы работы с переменными, методами и операторами управления. + +--- + +### Описание + +Вам предстоит создать консольное приложение с интерактивным меню: + +1. Приветствие: При запуске программы отображается сообщение приветствия со списком доступных команд: /start, /help, /info, /exit. +2. Обработка команды /start: Если пользователь вводит команду /start, программа просит его ввести своё имя. Сохраните введенное имя в переменную. Программа должна обращаться к пользователю по имени в каждом следующем ответе. +3. Обработка команды /help: Отображает краткую справочную информацию о том, как пользоваться программой. +4. Обработка команды /info: Предоставляет информацию о версии программы и дате её создания. +5. Доступ к команде /echo: После ввода имени становится доступной команда /echo. При вводе этой команды с аргументом (например, /echo Hello), программа возвращает введенный текст (в данном примере "Hello"). +6. Основной цикл программы: Программа продолжает ожидать ввод команды от пользователя, пока не будет введена команда /exit. + +### Примечание + +Для получения информации из консоли используйте `Console.ReadLine()`. + +--- + +### Критерии оценивания + +- Отображение приветственного сообщения и списка команд: 1 балл +- Правильная обработка команды /start и сохранение имени: 2 балла +- Корректное обращение к пользователю по имени: 1 балл +- Отображение справочной информации по команде /help: 1 балл +- Отображение информации о версии и дате создания по команде /info: 1 балл +- Обработка команды /echo с аргументом: 2 балла +- Поддержка цикла для продолжения работы программы: 1 балл +- Код написан аккуратно и без ошибок: 1 балл + +Минимальное количество баллов для сдачи ДЗ: 6 баллов diff --git "a/Homeworks/v2/03 \320\240\320\260\321\201\321\210\320\270\321\200\320\265\320\275\320\270\320\265 \320\262\320\276\320\267\320\274\320\276\320\266\320\275\320\276\321\201\321\202\320\265\320\271 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \321\201 \320\277\320\276\320\274\320\276\321\211\321\214\321\216 \321\201\320\277\320\270\321\201\320\272\320\260/Task.md" "b/Homeworks/v2/03 \320\240\320\260\321\201\321\210\320\270\321\200\320\265\320\275\320\270\320\265 \320\262\320\276\320\267\320\274\320\276\320\266\320\275\320\276\321\201\321\202\320\265\320\271 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \321\201 \320\277\320\276\320\274\320\276\321\211\321\214\321\216 \321\201\320\277\320\270\321\201\320\272\320\260/Task.md" new file mode 100644 index 0000000..812f008 --- /dev/null +++ "b/Homeworks/v2/03 \320\240\320\260\321\201\321\210\320\270\321\200\320\265\320\275\320\270\320\265 \320\262\320\276\320\267\320\274\320\276\320\266\320\275\320\276\321\201\321\202\320\265\320\271 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \321\201 \320\277\320\276\320\274\320\276\321\211\321\214\321\216 \321\201\320\277\320\270\321\201\320\272\320\260/Task.md" @@ -0,0 +1,74 @@ +### Цель + +Вам предстоит расширить функционал консольного приложения из ДЗ 2, добавив работу со структурой данных `List`. Приложение будет управлять списком задач с помощью трёх новых команд. + +--- + +### Описание + +1. Создайте новую команду /addtask +- Пользователь сможет добавлять задачи в список. +- После ввода команды /addtask, бот должен попросить ввести описание задачи. +- Сохраните задачу в список (или массив) и отобразите сообщение о том, что задача добавлена. + +2. Создайте новую команду /showtasks +- При вводе команды /showtasks бот должен отобразить список всех добавленных задач. +- Если задачи ещё не добавлены, необходимо вывести сообщение о том, что список пуст. + +3. Создайте новую команду /removetask +- Бот должен позволить пользователю удалять задачи по номеру в списке. +- После ввода команды /removetask, бот должен отобразить список задач с номерами. +- Затем бот должен запросить у пользователя номер задачи для удаления и удалить выбранную задачу из списка. + +4. Модифицируйте команду /help +- Обновите команду /help, добавив к ней описание новых команд: /addtask, /showtasks и /removetask. + +5. Реализуйте обработку ошибок +- Если пользователь пытается удалить задачу, когда список пуст, программа должна уведомить его об этом. +- Также, если введён неверный номер задачи при удалении, бот должен уведомить об этом и попросить ввести корректный номер. + + +По завершению укажите сколько времени вам понадобилось, чтобы выполнить это задание. + +Пример работы программы: + +``` +Добро пожаловать! Доступные команды: /start, /help, /info, /echo, /addtask, /showtasks, /removetask, /exit + +/start +Пожалуйста, введите ваше имя: Иван +Привет, Иван! Чем могу помочь? + +/addtask +Пожалуйста, введите описание задачи: Купить продукты +Задача "Купить продукты" добавлена. + +/addtask +Пожалуйста, введите описание задачи: Сделать домашнее задание +Задача "Сделать домашнее задание" добавлена. + +/showtasks +1. Купить продукты +2. Сделать домашнее задание + +/removetask +Вот ваш список задач: +1. Купить продукты +2. Сделать домашнее задание +Введите номер задачи для удаления: 1 +Задача "Купить продукты" удалена. + +/showtasks +1. Сделать домашнее задание + +Важно! Используйте List для хранения задач. +``` +--- + +### Критерии оценивания + +- Пункты 1-3 - 6 баллов +- Пункт 4 - 2 балла +- Пункт 5 - 2 балла + +Для зачёта домашнего задания достаточно 6 баллов. \ No newline at end of file diff --git "a/Homeworks/v2/04 \320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260 \320\276\321\210\320\270\320\261\320\276\320\272 \320\270 \320\262\320\260\320\273\320\270\320\264\320\260\321\206\320\270\321\217 \320\264\320\260\320\275\320\275\321\213\321\205/Task.md" "b/Homeworks/v2/04 \320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260 \320\276\321\210\320\270\320\261\320\276\320\272 \320\270 \320\262\320\260\320\273\320\270\320\264\320\260\321\206\320\270\321\217 \320\264\320\260\320\275\320\275\321\213\321\205/Task.md" new file mode 100644 index 0000000..34f8fd2 --- /dev/null +++ "b/Homeworks/v2/04 \320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260 \320\276\321\210\320\270\320\261\320\276\320\272 \320\270 \320\262\320\260\320\273\320\270\320\264\320\260\321\206\320\270\321\217 \320\264\320\260\320\275\320\275\321\213\321\205/Task.md" @@ -0,0 +1,52 @@ +### Цель + +Расширение функционала приложения, разработанного в предыдущих домашних заданиях: + +- Работа с исключениями +- Создание собственного типа исключения +- Валидация данных + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Добавить глобальный try catch + - Добавьте try catch в метод Main + - catch должен отлавливать все виды исключений и выводить в консоль сообщение “Произошла непредвиденная ошибка: “ с информацией об исключении (Type, Message, StackTrace, InnerException) +2. Добавить ограничение на максимальное количество задач + - При старте приложения выводите текст «Введите максимально допустимое количество задач» + - Ожидайте ввод из консоли. Это должно быть число от 1 до 100, иначе нужно выбросить исключение `ArgumentException` с сообщением. + - В методе Main добавьте отдельный catch для типа ArgumentException и в нем выводите в консоль только сообщение из исключения. + - Создайте свой тип исключения `TaskCountLimitException`, который в конструкторе должен принимать только int taskCountLimit, а сообщение должно быть вида $“Превышено максимальное количество задач равное {taskCountLimit}“ https://learn.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions + - Добавьте проверку на максимально допустимое количество задач в обработчик команды /addtask. Если количество превышено, то нужно выбросить исключение `TaskCountLimitException`. + - В методе Main добавьте отдельный catch для типа `TaskCountLimitException` и в нем выводите в консоль только сообщение из исключения. + - Попадание в catch не должно останавливать работу приложения +3. Добавить ограничение на максимальную длину задачи + - При старте приложения выводите текст «Введите максимально допустимую длину задачи» + - Ожидайте ввод из консоли. Это должно быть число от 1 до 100, иначе нужно выбросить исключение `ArgumentException` с сообщением. + - Создайте свой тип исключения `TaskLengthLimitException`, который в конструкторе должен принимать int taskLength, int taskLengthLimit, а сообщение должно быть вида $“Длина задачи ‘{taskLength}’ превышает максимально допустимое значение {taskLengthLimit}“. + - Добавьте проверку на максимально допустимую длину задачи в обработчик команды /addtask. Если длина превышена, то нужно выбросить исключение `TaskLengthLimitException`. + - В методе Main добавьте отдельный catch для типа `TaskLengthLimitException` и в нем выводите в консоль только сообщение из исключения. + - Попадание в catch не должно останавливать работу приложения +4. Добавить проверку на дубликаты задач + - Создайте свой тип исключения `DuplicateTaskException`, который в конструкторе должен принимать string task, а сообщение должно быть вида $“Задача ‘{task}’ уже существует“. + - Добавьте проверку на дубликаты задач в обработчик команды /addtask. Если пользователь пытается добавить уже существующую задачу., то нужно выбросить исключение `DuplicateTaskException`. + - В методе Main добавьте отдельный catch для типа `DuplicateTaskException`и в нем выводите в консоль только сообщение из исключения. + - Попадание в catch не должно останавливать работу приложения +5. Добавить метод int ParseAndValidateInt(string? str, int min, int max), который приводит полученную строку к int и проверяет, что оно находится в диапазоне min и max. В противном случае выбрасывать ArgumentException с сообщением. Добавить использование этого метода в приложение. +6. Добавить метод void ValidateString(string? str), который проверяет, что строка не равна null, не равна пустой строке и имеет какие-то символы кроме проблема. В противном случае выбрасывать ArgumentException с сообщением. Добавить использование этого метода в приложение. +7. Вынести обработчики команд в отдельные методы + +--- + +### Критерии оценивания + +- Пункты 1-3 - 6 баллов +- Пункт 4 - 1 балл +- Пункт 5 - 1 балл +- Пункт 6 - 1 балл +- Пункт 7 - 1 балл + +Для зачёта домашнего задания достаточно 6 баллов. \ No newline at end of file diff --git "a/Homeworks/v2/05 \320\236\320\236\320\237 \320\272\320\273\320\260\321\201\321\201\321\213/Task.md" "b/Homeworks/v2/05 \320\236\320\236\320\237 \320\272\320\273\320\260\321\201\321\201\321\213/Task.md" new file mode 100644 index 0000000..fcdb848 --- /dev/null +++ "b/Homeworks/v2/05 \320\236\320\236\320\237 \320\272\320\273\320\260\321\201\321\201\321\213/Task.md" @@ -0,0 +1,61 @@ +### Цель + +Расширение функционала приложения, разработанного в предыдущих домашних заданиях: + +- Работа с классами +- Добавление новых команд + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Изменение логики команды `/start` + - Добавить класс `ToDoUser` + - Свойства + - Guid UserId //Заполняется в конструкторе. Guid.NewGuid() + - string UserName //Имя пользователя + - DateTime RegisteredAt //Заполняется в конструкторе. DateTime.UtcNow + - У класса должен быть один конструктор с аргументом string userName + - Добавить использование класса `ToDoUser` для сохранения информации о пользователе вместо хранения только имени. +2. Добавление класса `ToDoItem` + - Добавить enum `ToDoItemState` с двумя значениями + - Active + - Completed + - Добавить класс `ToDoItem` + - Свойства + - Guid Id //Заполняется в конструкторе. Guid.NewGuid() + - ToDoUser User + - string Name + - DateTime CreatedAt //Заполняется в конструкторе. DateTime.UtcNow + - ToDoItemState State //Заполняется в конструкторе. ToDoItemState.Active + - DateTime? StateChangedAt + - У класса должен быть один конструктор с аргументами ToDoUser user, string name + - Добавить использование класса `ToDoItem` вместо хранения только имени задачи +3. Изменение логики `/showtasks` + - Выводить только задачи с `ToDoItemState.Active` + - Добавить вывод CreatedAt и Id. Пример: Имя задачи - 01.01.2025 00:00:00 - 17056344-0e03-4a21-b0dd-f0d30a5abf49 +4. Добавление команды `/completetask` + - Добавить обработку новой команды `/completetask` + - Найти задачу по Id + - Обновить State на ToDoItemState.Completed + - Обновить StateChangedAt + - Пример: `/completetask 73c7940a-ca8c-4327-8a15-9119bffd1d5e` +5. Добавление команды `/showalltasks` + - Добавить обработку новой команды `/showalltasks`. По ней выводить команды с любым `State` и добавить `State` в вывод + - Пример: (Active) Имя задачи - 01.01.2025 00:00:00 - ffbfe448-4b39-4778-98aa-1aed98f7eed8 +6. Обновить `/help` + +--- + +### Критерии оценивания + +- Пункт 1 - 2 балла +- Пункт 2 - 2 балла +- Пункт 3 - 2 балла +- Пункт 4 - 2 балла +- Пункт 5 - 1 балл +- Пункт 6 - 1 балл + +Для зачёта домашнего задания достаточно 8 баллов. diff --git "a/Homeworks/v2/06 \320\236\320\236\320\237 \320\270\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201\321\213/Demo.gif" "b/Homeworks/v2/06 \320\236\320\236\320\237 \320\270\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201\321\213/Demo.gif" new file mode 100644 index 0000000..8c1a467 Binary files /dev/null and "b/Homeworks/v2/06 \320\236\320\236\320\237 \320\270\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201\321\213/Demo.gif" differ diff --git "a/Homeworks/v2/06 \320\236\320\236\320\237 \320\270\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201\321\213/Task.md" "b/Homeworks/v2/06 \320\236\320\236\320\237 \320\270\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201\321\213/Task.md" new file mode 100644 index 0000000..b075e42 --- /dev/null +++ "b/Homeworks/v2/06 \320\236\320\236\320\237 \320\270\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201\321\213/Task.md" @@ -0,0 +1,71 @@ +### Цель + +Расширение функционала приложения, разработанного в предыдущих домашних заданиях: + +- Работа с интерфейсами +- Выделение сервисного слоя + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Структура проекта + ``` + Project/ + ├── Core/ + │ ├── Entities/ + │ ├── Services/ + │ └── Exceptions/ + └── Program.cs + ``` +2. Удалить команду `/echo` +3. Добавление класса сервиса `UserService` + - Добавить интерфейс `IUserService` + ```csharp + interface IUserService + { + ToDoUser RegisterUser(string userName); + ToDoUser? GetUser(Guid userId); + } + ``` + - Создать класс `UserService`, который реализует интерфейс `IUserService` +4. Изменение логики команды команды `/start` + - Регистрировать пользователя нужно через `RegisterUser` + - Для обработки команды нужно использовать `IUserService.GetUser`. Если пользователь не найден, то вызывать `IUserService.RegisterUser` + - Если пользователь не зарегистрирован, то ему доступны только команды `/help` `/info` +5. Добавление класса сервиса `ToDoService` + - Добавить интерфейс `IToDoService` + ```csharp + public interface IToDoService + { + IReadOnlyList GetAllByUserId(Guid userId); + //Возвращает ToDoItem для UserId со статусом Active + IReadOnlyList GetActiveByUserId(Guid userId); + ToDoItem Add(ToDoUser user, string name); + void MarkCompleted(Guid id); + void Delete(Guid id); + } + ``` + - Создать класс `ToDoService`, который реализует интерфейс `IToDoService`. Перенести в него логику обработки команд. Проверки на максимальное количество задач, на максимальную длину задачи и на дубликаты тоже нужно перенести в `ToDoService`. +6. Изменение команд `/addtask` `/removetask` `/completetask` + - Добавить использование `IToDoService` при обработке команд + - Изменить формат обработки команды `/addtask`. Нужно сразу передавать имя задачи в команде. Пример: `/addtask Новая задача` + - Изменить формат обработки команды `/removetask`. Нужно сразу передавать Id задачи в команде. Пример: `/removetask ffbfe448-4b39-4778-98aa-1aed98f7eed8` + - Изменить формат обработки команды `/completetask`. Нужно сразу передавать Id задачи в команде. Пример: `/completetask ffbfe448-4b39-4778-98aa-1aed98f7eed8` + +Примечание: Можно заменить catch с разными типами исключений, если в них нет кастомной логики, на один catch(Exception ex). Так как в предыдущем задание сatch с разными типами исключений добавлялись в учебных целям и в реальных проектах не нужно делать catch на каждый тип исключения, если в них нет специальной логики. + +--- + +### Критерии оценивания + +- Пункт 1 - 1 балла +- Пункт 2 - 1 балл +- Пункт 3 - 2 балл +- Пункт 4 - 2 балла +- Пункт 5 - 2 балла +- Пункт 6 - 2 балла + +Для зачёта домашнего задания достаточно 8 баллов. diff --git "a/Homeworks/v2/07 \320\240\320\260\321\201\321\210\320\270\321\200\320\265\320\275\320\270\320\265 \321\204\321\203\320\275\320\272\321\206\320\270\320\276\320\275\320\260\320\273\320\260 \320\261\320\276\321\202\320\260/Task.md" "b/Homeworks/v2/07 \320\240\320\260\321\201\321\210\320\270\321\200\320\265\320\275\320\270\320\265 \321\204\321\203\320\275\320\272\321\206\320\270\320\276\320\275\320\260\320\273\320\260 \320\261\320\276\321\202\320\260/Task.md" new file mode 100644 index 0000000..802b534 --- /dev/null +++ "b/Homeworks/v2/07 \320\240\320\260\321\201\321\210\320\270\321\200\320\265\320\275\320\270\320\265 \321\204\321\203\320\275\320\272\321\206\320\270\320\276\320\275\320\260\320\273\320\260 \320\261\320\276\321\202\320\260/Task.md" @@ -0,0 +1,104 @@ +### Цель + +Расширение функционала приложения, разработанного в предыдущих домашних заданиях: + +- Работа с классами и интерфейсами. Добавление репозиториев +- Добавление новых команд +- Работа с лямбдами и кортежами + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Добавление репозитория `IUserRepository` + - Добавить интерфейс `IUserRepository` + ```csharp + interface IUserRepository + { + ToDoUser? GetUser(Guid userId); + ToDoUser? GetUser(Guid userId); + void Add(ToDoUser user); + } + ``` + - Создать класс `InMemoryUserRepository`, который реализует интерфейс `IUserRepository`. В качестве хранилища использовать List + - Добавить использование `IUserRepository` в `UserService`. Получать `IUserRepository` нужно через конструктор +2. Добавление репозитория `IToDoRepository` + - Добавить интерфейс `IToDoRepository` + ```csharp + interface IToDoRepository + { + IReadOnlyList GetAllByUserId(Guid userId); + //Возвращает ToDoItem для UserId со статусом Active + IReadOnlyList GetActiveByUserId(Guid userId); + ToDoItem? Get(Guid id); + void Add(ToDoItem item); + void Update(ToDoItem item); + void Delete(Guid id); + //Проверяет есть ли задача с таким именем у пользователя + bool ExistsByName(Guid userId, string name); + //Возвращает количество активных задач у пользователя + int CountActive(Guid userId); + } + ``` + - Создать класс `InMemoryToDoRepository`, который реализует интерфейс `IToDoRepository`. В качестве хранилища использовать List + - Добавить использование `IToDoRepository` в `ToDoService`. Получать `IToDoRepository` нужно через конструктор +3. Кортежи. Добавление команды `/report` + - Добавить метод `IReadOnlyList GetAllByUserId(Guid userId);` в интерфейс `IToDoRepository`. Метод должен возвращать все задачи пользователя + - Добавить интерфейс `IToDoReportService` + ```csharp + interface IToDoReportService + { + (int total, int completed, int active, DateTime generatedAt) GetUserStats(Guid userId); + } + ``` + - Создать класс `ToDoReportService`, который реализует интерфейс `IToDoReportService`. + - Добавить обработку новой команды `/report`. Нужно использовать `IToDoReportService` + - Пример вывода: Статистика по задачам на 01.01.2025 00:00:00. Всего: 10; Завершенных: 7; Активных: 3; +4. Лямбды. Добавление команды `/find` + - Добавить метод `IReadOnlyList Find(Guid userId, Func predicate);` в интерфейс `IToDoRepository`. Метод должен возвращать все задачи пользователя, которые удовлетворяют предикату. + - Добавить метод `IReadOnlyList Find(ToDoUser user, string namePrefix);` в интерфейс `IToDoService`. Метод должен возвращать все задачи пользователя, которые начинаются на namePrefix. Для этого нужно использовать метод `IToDoRepository.Find` + - Добавить обработку новой команды `/find`. + - Пример команды: `/find Имя` + - Вывод в консоль должен быть как в `/showtask` +5. Рекомендуемая структура проекта + ``` + Project/ + ├── Core/ + │ ├── DataAccess/ + │ │ ├── IUserRepository.cs + │ │ ├── IToDoRepository.cs + │ │ └── ... + │ ├── Entities/ + │ │ ├── ToDoUser.cs + │ │ ├── ToDoItem.cs + │ │ └── ... + │ ├── Exceptions/ + │ │ ├── TaskCountLimitException.cs + │ │ ├── TaskLengthLimitException.cs + │ │ └── ... + │ └── Services/ + │ ├── IUserService.cs + │ ├── UserService.cs + │ └── ... + │ + ├── Infrastructure/ + │ └── DataAccess/ + │ ├── InMemoryUserRepository.cs + │ ├── InMemoryToDoRepository.cs + │ └── ... + │ + └── Program.cs + ``` +6. Обновить `/help` +--- + +### Критерии оценивания + +- Пункты 1-2 - 5 баллов +- Пункт 3 - 2 балла +- Пункт 4 - 2 балла +- Пункт 5 - 1 балл + +Для зачёта домашнего задания достаточно 8 баллов. diff --git "a/Homeworks/v2/08 \320\220\321\201\320\270\320\275\321\205\321\200\320\276\320\275\320\275\320\276\321\201\321\202\321\214/Task.md" "b/Homeworks/v2/08 \320\220\321\201\320\270\320\275\321\205\321\200\320\276\320\275\320\275\320\276\321\201\321\202\321\214/Task.md" new file mode 100644 index 0000000..e2b6009 --- /dev/null +++ "b/Homeworks/v2/08 \320\220\321\201\320\270\320\275\321\205\321\200\320\276\320\275\320\275\320\276\321\201\321\202\321\214/Task.md" @@ -0,0 +1,32 @@ +### Цель + +Расширение функционала приложения, разработанного в предыдущих домашних заданиях: + +- Добавление асинхронности + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Перевести методы **всех интерфейсов** сервисов и репозиториев на асинхронные: + - Возвращать `Task` или `Task<>` + - Принимать `CancellationToken` + - Использовать `await` + - `IUserService`, `IUserRepository`, `IToDoService`, `IToDoRepository` и т.д. +2. В `Program.cs` использовать `await` при вызове сервисов. +3. Добавление `CancellationTokenSource` + отмена по клавише (например, `A`). + - Создавать CancellationTokenSource в Program.cs. Не забыть, то что он реализует IDisposable + - Использовать CancellationToken из CancellationTokenSource для всех асинхронных операций. + - При нажатии клавиши `A` вызывать отмену на CancellationTokenSource и завершать работу приложения + +--- + +### Критерии оценивания + +- Пункт 1 — 7 баллов +- Пункт 2 — 1 балл +- Пункт 3 — 2 балла + +Для зачёта домашнего задания достаточно 8 баллов. diff --git "a/Homeworks/v2/09 \320\241\320\276\320\267\320\264\320\260\320\275\320\270\320\265 Web API/Task.md" "b/Homeworks/v2/09 \320\241\320\276\320\267\320\264\320\260\320\275\320\270\320\265 Web API/Task.md" new file mode 100644 index 0000000..1a24526 --- /dev/null +++ "b/Homeworks/v2/09 \320\241\320\276\320\267\320\264\320\260\320\275\320\270\320\265 Web API/Task.md" @@ -0,0 +1,54 @@ +### Цель + +Расширение функционала приложения, разработанного в предыдущих домашних заданиях: + +- Создание Web API на ASP.NET Core +- Знакомство с Dependency Injection +- API Controllers +- Swagger + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Создайте проект `Otus.ToDo.Api` (ASP.NET Core Web API). +2. Перенесите папки `Core` и `Infrastructure` из предыдущих ДЗ (сервисы, репозитории, сущности). +3. Зарегистрировать сервисы и репозитории в DI. +4. Создайте **Controllers** : + - `UsersController` — регистрация пользователя, отчёт. [Route("api/users")] + - `TasksController` — задачи (Add, list, complete, delete, find). [Route("api/users/{userId:guid}/tasks")] + - Отдельные DTO классы для API положить в папку `Dto/`: + - CreateUserRequest, UserResponse + - CreateTaskRequest, TaskReponse + - Набор свойств для этих классов определите при реализации пункта 5 +5. Реализуйте endpoints: + +| Бывшая команда | HTTP | +|----------------|------| +| `/start` | `POST /api/users` — body: `{ "userName": "..." }` | +| `/addtask` | `POST /api/users/{userId}/tasks` | +| `/showtasks` | `GET /api/users/{userId}/tasks?state=active` | +| `/showalltasks` | `GET /api/users/{userId}/tasks` | +| `/completetask` | `PATCH /api/tasks/{taskId}/complete` | +| `/removetask` | `DELETE /api/tasks/{taskId}` | +| `/report` | `GET /api/users/{userId}/report` | +| `/find` | `GET /api/users/{userId}/tasks?prefix=...` | + +6. Подключите Swagger (`AddSwaggerGen`, `UseSwaggerUI`). +7. Обрабатывайте доменные исключения (`TaskCountLimitException`, `DuplicateTaskException` и т.д.) — возвращайте `Bad Request` и `Conflict` с сообщением. + +--- + +### Критерии оценивания + +- Пункт 1 - 1 балл +- Пункт 2 - 1 балл +- Пункт 3 - 1 балл +- Пункт 4 - 2 балла +- Пункт 5 - 2 балла +- Пункт 6 - 2 балл +- Пункт 7 - 1 балл + +Для зачёта домашнего задания достаточно 8 баллов. diff --git "a/Homeworks/v2/10 \320\240\320\260\320\261\320\276\321\202\320\260 \321\201 \321\204\320\260\320\271\320\273\320\260\320\274\320\270/Task.md" "b/Homeworks/v2/10 \320\240\320\260\320\261\320\276\321\202\320\260 \321\201 \321\204\320\260\320\271\320\273\320\260\320\274\320\270/Task.md" new file mode 100644 index 0000000..e0e9fc7 --- /dev/null +++ "b/Homeworks/v2/10 \320\240\320\260\320\261\320\276\321\202\320\260 \321\201 \321\204\320\260\320\271\320\273\320\260\320\274\320\270/Task.md" @@ -0,0 +1,50 @@ +### Цель + +Расширение функционала приложения, разработанного в предыдущих домашних заданиях: + +- Работа с файлами +- Работа с json + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Перенос хранения `ToDoItem` данных в файлы + - Создать класс `FileToDoRepository`, который реализует интерфейс `IToDoRepository` + - Реализовать хранение `ToDoItem` в отдельных json файлах. + - Имя файла: `"{ToDoItem.Id}.json"` + - Имя базовой папки нужно получать через конструктор. Папку нужно создавать если её нет. + - Для хранения данных в файлах использовать json формат. Для этого нужно использовать библиотеку `System.Text.Json` и методы `JsonSerializer.Serialize` `JsonSerializer.Deserialize`. Можно использовать асинхронные варианты. [Документация](https://learn.microsoft.com/ru-ru/dotnet/standard/serialization/) + - Заменить использование `InMemoryToDoRepository` на `FileToDoRepository` в API-проекте (регистрация в DI) +2. Перенос хранения `ToDoUser` данных в файлы + - Создать класс `FileUserRepository`, который реализует интерфейс `IUserRepository` + - Реализовать хранение `ToDoUser` в отдельных json файлах. + - Имя файла: `"{ToDoUser.UserId}.json"` + - Имя базовой папки нужно получать через конструктор. Папку нужно создавать если её нет. + - Для хранения данных в файлах использовать JSON формат. Для этого нужно использовать библиотеку `System.Text.Json`. + - Заменить использование `InMemoryUserRepository` на `FileUserRepository` в проекте +3. Оптимизация поиска `ToDoItem` по `UserId` + - Реализовать в `FileToDoRepository` хранение `ToDoItem` в отдельных json файлах, сгуппированных по `UserId` в папках + - Имя папки: `"{ToDoItem.User.UserId}"` + - Имя файла: `"{ToDoItem.Id}.json"` +4. Индекс для оптимизации удаления `ToDoItem` + - Добавить в `FileToDoRepository` файл индекс в json формате, в котором хранятся связки `ToDoItemId` и `UserId` + - Наполнять индекс в методе `FileToDoRepository.Add` + - Использовать и обновлять индекс в методе `FileToDoRepository.Delete` + - Если файла индекса нет, то создать файл и наполнить его актуальными данными через сканирование всех папок + +**Ознакомительное примечание (выполнять не нужно):** +Для безопасной работы с файлами в многопоточной среде рекомендуется использовать синхронизацию потоков, чтобы в один момент времени с файлом работал только один поток. Это поможет избежать race conditions, повреждение данных, IO исключений и тд. Для этого хорошо подходит [SemaphoreSlim](https://learn.microsoft.com/ru-ru/dotnet/api/system.threading.semaphoreslim), так как он поддерживает асинхронность, оптимизирован для внутрипроцессной синхронизации и не использует объекты ядра ОС. Например, в нашем случае можно было использовать отдельные `SemaphoreSlim` для каждого `UserId`. Данная тема выходит за рамки курса. + +--- + +### Критерии оценивания + +- Пункт 1 - 3 балла +- Пункт 2 - 3 балла +- Пункт 3 - 2 балла +- Пункт 4 - 2 балла + +Для зачёта домашнего задания достаточно 6 баллов. \ No newline at end of file diff --git "a/Homeworks/v2/11 \320\241\320\277\320\270\321\201\320\272\320\270 \320\264\320\273\321\217 \320\267\320\260\320\264\320\260\321\207/Task.md" "b/Homeworks/v2/11 \320\241\320\277\320\270\321\201\320\272\320\270 \320\264\320\273\321\217 \320\267\320\260\320\264\320\260\321\207/Task.md" new file mode 100644 index 0000000..d93b36e --- /dev/null +++ "b/Homeworks/v2/11 \320\241\320\277\320\270\321\201\320\272\320\270 \320\264\320\273\321\217 \320\267\320\260\320\264\320\260\321\207/Task.md" @@ -0,0 +1,70 @@ +### Цель + +Расширение Web API приложения: + +- Сущность `ToDoList` +- CRUD списков через Controllers +- Пагинация задач (LINQ) + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Добавление сущности `ToDoList` + - Добавить класс `ToDoList` по пути Core/Entities + - Свойства + - Guid Id + - string Name + - ToDoUser User + - DateTime CreatedAt + - Добавить свойство ToDoList? List в `ToDoItem` + - Добавить аргумент ToDoList? list в `IToDoService.Add` +2. Добавление репозитория для `ToDoList` + - Добавить интерфейс `IToDoListRepository` + ```csharp + public interface IToDoListRepository + { + //Если списка нет, то возвращает null + Task Get(Guid id, CancellationToken ct); + Task> GetByUserId(Guid userId, CancellationToken ct); + Task Add(ToDoList list, CancellationToken ct); + Task Delete(Guid id, CancellationToken ct); + //Проверяет, есть ли у пользователя список с таким именем + Task ExistsByName(Guid userId, string name, CancellationToken ct); + } + ``` + - Создать класс `FileToDoListRepository`, который реализует интерфейс `IToDoListRepository`. Реализовать класс аналогично `FileUserRepository` +3. Добавление класса сервиса для `ToDoList` + - Добавить интерфейс `IToDoListService` + ```csharp + public interface IToDoListService + { + Task Add(ToDoUser user, string name, CancellationToken ct); + Task Get(Guid id, CancellationToken ct); + Task Delete(Guid id, CancellationToken ct); + Task> GetUserLists(Guid userId, CancellationToken ct); + } + ``` + - Создать класс `ToDoListService`, который реализует интерфейс `IToDoListService` + - Размер имени списка не может быть больше 10 символов + - Название списка должно быть уникально в рамках одного ToDoUser + - Добавить метод `Task> GetByUserIdAndList(Guid userId, Guid? listId, CancellationToken ct);` в интерфейс `IToDoService` и реализовать его +4. Добавьте контроллер `ListsController` и соответствующие DTO-классы (CreateListRequest, ListResponse): + - [Route("api/users/{userId:guid}/lists")] + - `GET /api/users/{userId}/lists` + - `GET /api/users/{userId}/lists/{listId}/tasks` — получить задачи списка + - `POST /api/users/{userId}/lists` + - `DELETE /api/users/{userId}/lists/{listId}` + - В `TaskResponse` нужно добавить информацию о списке +--- + +### Критерии оценивания + +- Пункт 1 — 2 балла +- Пункт 2 — 2 балла +- Пункт 3 — 2 балла +- Пункт 4 — 4 балла + +Для зачёта домашнего задания достаточно 8 баллов. diff --git "a/Homeworks/v2/12 \320\237\320\276\321\201\321\202\321\200\320\260\320\275\320\270\321\207\320\275\320\260\321\217 \320\275\320\260\320\262\320\270\320\263\320\260\321\206\320\270\321\217/Task.md" "b/Homeworks/v2/12 \320\237\320\276\321\201\321\202\321\200\320\260\320\275\320\270\321\207\320\275\320\260\321\217 \320\275\320\260\320\262\320\270\320\263\320\260\321\206\320\270\321\217/Task.md" new file mode 100644 index 0000000..f523a22 --- /dev/null +++ "b/Homeworks/v2/12 \320\237\320\276\321\201\321\202\321\200\320\260\320\275\320\270\321\207\320\275\320\260\321\217 \320\275\320\260\320\262\320\270\320\263\320\260\321\206\320\270\321\217/Task.md" @@ -0,0 +1,59 @@ +### Цель + +Расширение Web API приложения, разработанного в предыдущих домашних заданиях: + +- Добавление постраничной навигации для получения задач +- Практика LINQ +- Формирование API-ответа с метаданными пагинации + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +В этом ДЗ необходимо доработать endpoint `GET /api/users/{userId}/tasks` и добавить в него пагинацию. + +1. Добавьте параметры пагинации в endpoint + - В `TasksController` для метода `GET /api/users/{userId}/tasks` добавьте query-параметры: + - `page` (номер страницы, начиная с 1) + - `pageSize` (размер страницы) + - Значения по умолчанию: + - `page = 1` + - `pageSize = 5` + +2. Добавьте валидацию параметров + - Если `page < 1`, вернуть `BadRequest` + - Если `pageSize < 1`, вернуть `BadRequest` + - Если `pageSize > 100`, вернуть `BadRequest` + - Текст ошибок можно выбрать самостоятельно, но он должен явно объяснять причину + +3. Реализуйте пагинацию в приложении + - Используйте LINQ (`Skip` и `Take`) для получения нужного "среза" задач + - Пагинация применяется после получения полного набора задач пользователя + +4. Добавьте DTO ответа с метаданными пагинации + - Создайте DTO (например, `PagedResponse`), который содержит: + - `IReadOnlyList Items` + - `int Page` + - `int PageSize` + - `int TotalCount` + - `int TotalPages` + - Метод `GET /api/users/{userId}/tasks` должен возвращать этот DTO с `TaskResponse` в `Items` + +5. Добавьте использование LINQ в других местах приложения, где это применимо + +**Примечание (выполнять не нужно):** +В этом ДЗ пагинация реализуется после получения полного набора задач пользователя в память, чтобы отработать базовую механику (`Skip`/`Take`) на уровне приложения. Такой подход подходит для учебных целей, но в реальных проектах пагинацию обычно делают на уровне хранения данных (например, SQL-запросом с `OFFSET/LIMIT`), чтобы не загружать лишние записи. + +--- + +### Критерии оценивания + +- Пункт 1 - 2 балла +- Пункт 2 - 2 балла +- Пункт 3 - 2 балла +- Пункт 4 - 2 балла +- Пункт 5 - 2 балла + +Для зачёта домашнего задания достаточно 8 баллов. \ No newline at end of file diff --git "a/Homeworks/v2/13 \320\234\320\276\320\264\320\265\320\273\321\214 \320\261\320\260\320\267\321\213 \320\264\320\260\320\275\320\275\321\213\321\205/Task.md" "b/Homeworks/v2/13 \320\234\320\276\320\264\320\265\320\273\321\214 \320\261\320\260\320\267\321\213 \320\264\320\260\320\275\320\275\321\213\321\205/Task.md" new file mode 100644 index 0000000..a11ca7a --- /dev/null +++ "b/Homeworks/v2/13 \320\234\320\276\320\264\320\265\320\273\321\214 \320\261\320\260\320\267\321\213 \320\264\320\260\320\275\320\275\321\213\321\205/Task.md" @@ -0,0 +1,57 @@ +### Цель + +Проектирование модели базы данных для приложения, разработанного в предыдущих домашних заданиях: + +- Проектировать модель БД +- Писать DDL скрипты +- Писать DML скрипты +- Создавать индексы + +--- + +### Описание + +Ссылка на [GitHub](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/13%20%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C%20%D0%B1%D0%B0%D0%B7%D1%8B%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85/Task.md) + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Установка PostgreSQL + - Установите PostgreSQL на локальный компьютер (см. материалы занятия) + - Создать новую БД с именем ToDoList +2. Проектирование модели базы данных + - Таблицы на основе классов из Core/Entities. У таблиц должны быть PRIMARY KEY. Для ToDoItemState можно использовать тип INT + - ToDoUser + - ToDoList + - ToDoItem + - Cвязи между таблицами (внешние ключи) + - ToDoList.UserId -> ToDoUser + - ToDoItem.UserId -> ToDoUser + - ToDoItem.ListId -> ToDoList + - Напишите SQL-скрипты для создания таблиц и внешних ключей +3. Проектирование индексов + - Создайте индексы для всех внешних ключей + - Создайте уникальный индекс для ToDoUser.UserName + - Сохраните все скрипты (создание таблиц, внешних ключей и индексов) в один файл ToDoListDb.sql + - Разместите файл в репозитории рядом с проектом +4. Заполнение базы данных + - Напишите SQL-скрипты для заполнения всех таблиц тестовыми данными (минимум 2 записи на таблицу) + - Сохраните скрипт в файл ToDoListDb_Insert.sql + - Разместите файл в репозитории рядом с проектом +5. Выборка данных + - Напишите SQL-скрипты для методов интерфейса IToDoRepository, которые выбирают данные + - Сохраните скрипты в файл ToDoListDb_Select.sql + - Разместите файл в репозитории рядом с проектом + +Примечание: Используйте двойные кавычки для имен таблиц, столбцов, индексов и тд, чтобы сохранить регистр. + +--- + +### Критерии оценивания + +- Пункт 1 - 2 балла +- Пункт 2 - 2 балла +- Пункт 3 - 2 балла +- Пункт 4 - 2 балла +- Пункт 5 - 2 балла + +Для зачёта домашнего задания достаточно 8 баллов. \ No newline at end of file diff --git "a/Homeworks/v2/14 \320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265 ORM/Task.md" "b/Homeworks/v2/14 \320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265 ORM/Task.md" new file mode 100644 index 0000000..9abb7f9 --- /dev/null +++ "b/Homeworks/v2/14 \320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265 ORM/Task.md" @@ -0,0 +1,82 @@ +### Цель + +Подключение ORM для приложения, разработанного в предыдущих домашних заданиях: + +- Использовать linq2db.PostgreSQL +- Описывать модель БД через классы +- Выполнять запросы в БД через linq2db + +--- + +### Описание + +Ссылка на [GitHub](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/14%20%D0%9F%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20ORM/Task.md) + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +1. Подготовка моделей для описания структуры БД + - Подключите в проект последную версию nuget пакета `linq2db.PostgreSQL` + - Удалить все конструкторы и сделайте все свойства открытыми (get; set;) в классах в Core/Entities. Будем использовать анемичную модель, для этого нужны чистые классы + - Создать классы модели для таблиц в Core/DataAccess/Models + - `ToDoItemModel` + - `ToDoListModel` + - `ToDoUserModel` + - Через атрибуты отпределите имена таблиц([Table("...")]), первичные ключи ([PrimaryKey]), колонки ([Column]), внешние ключи ([Association(ThisKey = nameof(), OtherKey = nameof())]). Подробную информацию можно найти в [документации](https://linq2db.github.io/#define-poco-class) +2. Создание DataContext + - Создайте класс `ToDoDataContext` в Infrastructure/DataAccess. + - Наследуется от DataConnection + - Конструктор public ToDoDataContext(string connectionString) : base(ProviderName.PostgreSQL, connectionString) + - Иметь свойства, которые отражают таблицы в БД (ToDoUsers, ToDoLists, ToDoItems) + - Пример из [документации](https://linq2db.github.io/#dataconnection-class) + - Создать интерфейс IDataContextFactory. Нужно чтобы создавать `DataConnection` на каждую сессию https://linq2db.github.io/articles/general/Managing-data-connection.html + ```csharp + public interface IDataContextFactory where TDataContext : DataConnection + { + TDataContext CreateDataContext(); + } + ``` + - Создать класс `DataContextFactory`, который реализует интерфейс `IDataContextFactory` +3. Создание маппера + - Создать статический класс `ModelMapper` в Infrastructure/DataAccess. Через него будем делать маппинг между Infrastructure/DataAccess/Models и Core/Entities + ```csharp + internal static class ModelMapper + { + public static ToDoUser MapFromModel(ToDoUserModel model); + public static ToDoUserModel MapToModel(ToDoUser entity); + public static ToDoItem MapFromModel(ToDoItemModel model); + public static ToDoItemModel MapToModel(ToDoItem entity); + public static ToDoList MapFromModel(ToDoListModel model); + public static ToDoListModel MapToModel(ToDoList entity); + } + ``` + - Реализовать все методы +4. Реализация SqlToDoRepository + - Создать класс `SqlToDoRepository`, который реализует интерфейс `IToDoRepository` + - В конструкторе получать IDataContextFactory factory + - Реализовать все методы интерфейса. Создавать dbContext в каждом методе. using var dbContext = factory.CreateDataContext(); + - Использовать `ModelMapper` + - Не забудь добавлять LoadWith, чтобы загружать связанные сущности(eager loading) + ```csharp + .LoadWith(i => i.User) + .LoadWith(i => i.List) + .LoadWith(i => i.List!.User) + ``` +5. Аналогично создать класс `SqlToDoListRepository`, который реализует интерфейс `IToDoListRepository` +6. Аналогично создать класс `SqlUserRepository`, который реализует интерфейс `IUserRepository` +7. Добавление использовать SQL репозиториев + - Добавить использование этих репозиториев вместо File реализаций + - Указать connectionString до БД, которая разрабатывалась в ДЗ "Модель базы данных" + +--- + +### Критерии оценивания + +- Пункт 1 - 2 балла +- Пункт 2 - 2 балла +- Пункт 3 - 2 балла +- Пункт 4 - 1 балл +- Пункт 5 - 1 балл +- Пункт 6 - 1 балл +- Пункт 7 - 1 балл + +Для зачёта домашнего задания достаточно 8 баллов. diff --git "a/Homeworks/v2/15 \320\244\320\276\320\275\320\276\320\262\321\213\320\265 \320\267\320\260\320\264\320\260\321\207\320\270/Task.md" "b/Homeworks/v2/15 \320\244\320\276\320\275\320\276\320\262\321\213\320\265 \320\267\320\260\320\264\320\260\321\207\320\270/Task.md" new file mode 100644 index 0000000..f2ef7f6 --- /dev/null +++ "b/Homeworks/v2/15 \320\244\320\276\320\275\320\276\320\262\321\213\320\265 \320\267\320\260\320\264\320\260\321\207\320\270/Task.md" @@ -0,0 +1,50 @@ +### Цель + +Добавление фоновых задач в Web API приложение: + +- `IHostedService` / `BackgroundService` +- Мягкое удаление задач +- Физическая очистка устаревших записей + +--- + +### Описание + +Перед выполнением нужно ознакомиться с [Правила отправки домашнего задания на проверку](https://github.com/OTUS-NET/C-Sharp-Basic/blob/main/Homeworks/README.md) + +**До этого ДЗ** удаление задач было **физическим**. В этом ДЗ меняется модель удаления. + +1. Расширить `ToDoItemState`: + ```csharp + public enum ToDoItemState { Active, Completed, Deleted } + ``` +2. Перевести `IToDoService.Delete` и `DELETE /api/tasks/{taskId}` на **мягкое удаление**: + - `State = Deleted` + - `StateChangedAt = DateTime.UtcNow` + - Запись остаётся в хранилище +3. Обновить выборки — **не возвращать** задачи в статусе `Deleted`. +4. Добавить в `IToDoRepository`: + ```csharp + Task> GetDeletedOlderThan(TimeSpan age, CancellationToken ct); + Task Purge(Guid id, CancellationToken ct); + ``` +5. Создать `DeletedTasksCleanupHostedService` (`BackgroundService`): + - Документация https://learn.microsoft.com/ru-ru/aspnet/core/fundamentals/host/hosted-services + - Раз в сутки (`TimeSpan.FromHours(24)`) + - Через `IServiceScopeFactory` получить `IToDoRepository` + - Найти задачи: `State == Deleted` и `StateChangedAt < UtcNow.AddDays(-90)` + - Вызвать `Purge` для каждой +6. Зарегистрировать в `Program.cs`: + ```csharp + builder.Services.AddHostedService(); + ``` + +--- + +### Критерии оценивания + +- Пункты 1–3 — 4 балла +- Пункт 4 — 2 балла +- Пункты 5–6 — 4 балла + +Для зачёта домашнего задания достаточно 8 баллов. diff --git "a/Homeworks/v2/16 \320\237\321\200\320\276\320\265\320\272\321\202\320\275\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260/Task.md" "b/Homeworks/v2/16 \320\237\321\200\320\276\320\265\320\272\321\202\320\275\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260/Task.md" new file mode 100644 index 0000000..57cbfc9 --- /dev/null +++ "b/Homeworks/v2/16 \320\237\321\200\320\276\320\265\320\272\321\202\320\275\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260/Task.md" @@ -0,0 +1,28 @@ +### Цель + +Разработка полноценного приложения на C#: архитектура, бизнес-логика, база данных, **Web API** (Controllers). + +--- + +### Описание + +1. Определить тему и функциональность приложения. +2. Спроектировать архитектуру (Core / Infrastructure / Controllers). +3. Модель БД + SQL-скрипты + слой доступа (Linq2db). +4. Реализовать Web API с Controllers, DI, Swagger. +5. Протестировать ключевые сценарии через Swagger или HTTP-клиент. +6. Подготовить материалы для защиты: презентация, ссылка на репозиторий, SQL-скрипты. + +За основу можно взять проект из цепочки ДЗ. + +--- + +### Критерии оценивания + +- Реализована основная функциональность приложения - 50 баллов +- Наличие базы данных - 10 баллов +- Код разделен на слои. Используются интерфейсы - 10 баллов +- В коде нет закомментированных кусков, а также паролей и API ключей в открытом виде. В IDE нет warnings - 10 баллов +- Качество защиты - 20 баллов + +Для зачёта проектной работы достаточно 60 баллов. diff --git a/Homeworks/v2/MIGRATION_TELEGRAM_TO_API.md b/Homeworks/v2/MIGRATION_TELEGRAM_TO_API.md new file mode 100644 index 0000000..2e7464e --- /dev/null +++ b/Homeworks/v2/MIGRATION_TELEGRAM_TO_API.md @@ -0,0 +1,15 @@ +# Миграция: Telegram → Web API + +Цепочка ДЗ ToDo переведена с Telegram-бота на **ASP.NET Core Web API (Controllers)**. + +## Основные изменения + +| Было | Стало | +|------|--------| +| Telegram Bot, ConsoleBot | Web API Controllers | +| ДЗ 08 Telegram | ДЗ 09 Web API + DI | +| ДЗ 10 Сценарии | Удалено | +| ДЗ 16 Нотификации | Удалено | +| `BackgroundTaskRunner` | `IHostedService` | + +Чтобы перейти на новый формат ДЗ нужно в курс добавить ASP.NET Core Web API (DI + Swagger) вместо Telegram