first commit
This commit is contained in:
commit
5460bf2019
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/test.iml" filepath="$PROJECT_DIR$/.idea/test.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,407 @@
|
|||
# Документация API
|
||||
|
||||
## Обзор
|
||||
Этот проект представляет собой RESTful API для управления пользователями и Todo пользователей.
|
||||
В качестве ORM используется GORM.
|
||||
|
||||
# Структура проекта
|
||||
|
||||
- ## cmd/
|
||||
- ### main.go
|
||||
- Запуск сервера
|
||||
|
||||
- ## config/
|
||||
- ### config.go
|
||||
- Инициализация и соединение с бд
|
||||
|
||||
- ## controllers/
|
||||
- ### todo_controller.go
|
||||
- контроллер для обработки HTTP-запросов с использованием фреймворка Gin. Он включает в себя несколько функций, каждая из которых отвечает за определённый CRUD (Create, Read, Update, Delete) функционал для задач (Todo).
|
||||
|
||||
1. **CreateTodo**:
|
||||
- Получает JSON-запрос и пытается его привязать к структуре `Todo`.
|
||||
- Валидирует структуру с использованием библиотеки `validator`.
|
||||
- Вызывает сервис для создания новой задачи.
|
||||
- Возвращает ответ с созданной задачей или ошибкой.
|
||||
|
||||
2. **GetTodos**:
|
||||
- Вызывает сервис для получения всех задач.
|
||||
- Возвращает список задач или ошибку.
|
||||
|
||||
3. **GetTodoByID**:
|
||||
- Получает ID задачи из параметров URL.
|
||||
- Вызывает сервис для получения задачи по этому ID.
|
||||
- Возвращает найденную задачу или сообщение об ошибке, если задача не найдена.
|
||||
|
||||
4. **UpdateTodo**:
|
||||
- Получает ID задачи из параметров URL.
|
||||
- Получает JSON-запрос и пытается его привязать к структуре `Todo`.
|
||||
- Валидирует структуру с использованием библиотеки `validator`.
|
||||
- Вызывает сервис для обновления задачи по ID.
|
||||
- Возвращает обновлённую задачу или ошибку.
|
||||
|
||||
5. **DeleteTodo**:
|
||||
- Получает ID задачи из параметров URL.
|
||||
- Вызывает сервис для удаления задачи по этому ID.
|
||||
- Возвращает сообщение об успешном удалении или ошибку, если задача не найдена.
|
||||
|
||||
- ### user_controller.go
|
||||
- контроллеры для управления пользователями с использованием фреймворка Gin
|
||||
1. **Register**:
|
||||
- Получает данные пользователя из тела запроса и преобразует их в структуру `User`.
|
||||
- Проверяет корректность данных (валидацию).
|
||||
- Вызывает сервис для регистрации пользователя.
|
||||
- Возвращает ответ с соответствующим статусом (успешная регистрация или ошибка).
|
||||
|
||||
2. **Login**:
|
||||
- Получает данные для входа (имя пользователя и пароль) из тела запроса.
|
||||
- Вызывает сервис для аутентификации пользователя и получения токена.
|
||||
- Возвращает токен или сообщение об ошибке.
|
||||
|
||||
3. **GetUserProfile**:
|
||||
- Получает текущего пользователя из контекста запроса.
|
||||
- Возвращает данные профиля пользователя или сообщение об ошибке, если пользователь не найден.
|
||||
|
||||
4. **GetUsers**:
|
||||
- Получает всех пользователей с помощью сервиса.
|
||||
- Возвращает список пользователей или сообщение об ошибке.
|
||||
|
||||
5. **GetUserByID**:
|
||||
- Получает ID пользователя из параметров URL.
|
||||
- Вызывает сервис для получения данных пользователя по ID.
|
||||
- Возвращает данные пользователя или сообщение об ошибке, если пользователь не найден.
|
||||
|
||||
6. **UpdateUser**:
|
||||
- Получает ID пользователя из параметров URL и новые данные пользователя из тела запроса.
|
||||
- Проверяет корректность новых данных (валидацию).
|
||||
- Вызывает сервис для обновления данных пользователя.
|
||||
- Возвращает обновленные данные пользователя или сообщение об ошибке.
|
||||
|
||||
7. **DeleteUser**:
|
||||
- Получает ID пользователя из параметров URL.
|
||||
- Вызывает сервис для удаления пользователя по ID.
|
||||
- Возвращает сообщение об успешном удалении или сообщение об ошибке, если пользователь не найден.
|
||||
|
||||
- *Основные компоненты*:
|
||||
|
||||
- **Gin**: веб-фреймворк для маршрутизации и обработки HTTP-запросов.
|
||||
- **Validator**: библиотека для валидации структур данных.
|
||||
- **Services**: пакет, содержащий бизнес-логику для работы с задачами.
|
||||
- **Utils**: пакет для вспомогательных функций, таких как формирование ответов.
|
||||
|
||||
- ## database/
|
||||
- ### migration.go
|
||||
- Основная точку входа, которая использует пакет `gorm` для работы с базой данных.
|
||||
|
||||
1. **Main**:
|
||||
- Инициализация базы данных:
|
||||
- Получение объекта базы данных:
|
||||
- Миграция таблиц:
|
||||
|
||||
- ## domain/
|
||||
- ### error_response.go
|
||||
- Структура ErrorResponse, которая используется для представления сообщений об ошибках в формате JSON.
|
||||
|
||||
- ### success_response.go
|
||||
- Структура Response, которая используется для представления сообщений об успехах в формате JSON.
|
||||
|
||||
- ### todo.go
|
||||
- Стуруктура Todo
|
||||
|
||||
- ### todoResponse
|
||||
- Структура TodoResponse, которая используется для представлния сообщений с Todo
|
||||
|
||||
- ### user.go
|
||||
- Структура User
|
||||
|
||||
- ### userResponse.go
|
||||
- Структура UserResponse, которая используется для представлния сообщений с User
|
||||
|
||||
- ## middleware/
|
||||
- ### auth_middleware.go
|
||||
- Middleware проверяет наличие и валидность токена аутентификации в заголовке HTTP-запроса и выполняет соответствующие действия.
|
||||
|
||||
1. **Функция `AuthMiddleware`**:
|
||||
- Определяется функция `AuthMiddleware`, возвращающая обработчик (handler) для использования в качестве middleware.
|
||||
|
||||
2. **Основная логика аутентификации**:
|
||||
- *Получение токена*:
|
||||
- Извлекается заголовок `Authorization` из HTTP-запроса.
|
||||
- Если токен отсутствует, возвращается ответ с кодом `http.StatusUnauthorized` и сообщение об ошибке, после чего обработка запроса прекращается (`c.Abort()`).
|
||||
|
||||
- *Проверка токена*:
|
||||
- Токен проверяется с помощью функции `utils.ValidateToken`, которая возвращает информацию о пользователе (`claims`) и ошибку (`err`).
|
||||
- Если проверка не проходит, возвращается ответ с кодом `http.StatusUnauthorized` и сообщение об ошибке, после чего обработка запроса прекращается.
|
||||
|
||||
- *Загрузка пользователя*:
|
||||
- Выполняется запрос к базе данных для получения пользователя по идентификатору из токена (`claims.UserID`).
|
||||
- Если пользователь не найден, возвращается ответ с кодом `http.StatusUnauthorized` и сообщение об ошибке, после чего обработка запроса прекращается.
|
||||
|
||||
- *Установка пользователя в контекст*:
|
||||
- Если пользователь успешно найден, он устанавливается в контекст запроса (`c.Set("user", user)`), чтобы быть доступным в последующих обработчиках.
|
||||
|
||||
3. **Продолжение обработки запроса**:
|
||||
- Если все проверки прошли успешно, запрос передается дальше следующему обработчику в цепочке (`c.Next()`).
|
||||
|
||||
- ## repositories/
|
||||
- ### todo_repository.go
|
||||
- функции-репозитории для работы с задачами (Todo) в базе данных, используя GORM. Репозитории инкапсулируют логику доступа к данным и обеспечивают CRUD-операции (создание, чтение, обновление, удаление).
|
||||
|
||||
1. **CreateTodoRepository**:
|
||||
- Создает новую задачу в базе данных.
|
||||
- Получает соединение с базой данных через `config.GetDB()`.
|
||||
- Использует метод `Create` для добавления новой задачи и возвращает возможную ошибку.
|
||||
|
||||
2. **GetTodosRepository**:
|
||||
- Возвращает все задачи из базы данных.
|
||||
- Инициализирует срез `todos` для хранения задач.
|
||||
- Получает соединение с базой данных и использует метод `Find` для получения всех задач.
|
||||
- Возвращает список задач и возможную ошибку.
|
||||
|
||||
3. **GetTodoByIDRepository**:
|
||||
- Возвращает задачу по её идентификатору (ID).
|
||||
- Инициализирует переменную `todo` для хранения задачи.
|
||||
- Получает соединение с базой данных и использует метод `First` для поиска задачи по ID.
|
||||
- Возвращает найденную задачу и возможную ошибку.
|
||||
|
||||
4. **UpdateTodoRepository**:
|
||||
- Обновляет информацию о задаче в базе данных.
|
||||
- Получает соединение с базой данных и использует метод `Save` для обновления задачи.
|
||||
- Возвращает возможную ошибку.
|
||||
|
||||
5. **DeleteTodoRepository**:
|
||||
- Удаляет задачу из базы данных по её идентификатору (ID).
|
||||
- Получает соединение с базой данных и использует метод `Delete` для удаления задачи.
|
||||
- Возвращает возможную ошибку.
|
||||
|
||||
- ### user_repository.go
|
||||
- функции-репозитории для работы с пользователями в базе данных, используя GORM. Репозитории обеспечивают CRUD-операции (создание, чтение, обновление, удаление) для сущности пользователя (User).
|
||||
|
||||
1. **CreateUserRepository**:
|
||||
- Создает нового пользователя в базе данных.
|
||||
- Получает соединение с базой данных через `config.GetDB()`.
|
||||
- Использует метод `Create` для добавления нового пользователя и возвращает возможную ошибку.
|
||||
|
||||
2. **GetUsersRepository**:
|
||||
- Возвращает всех пользователей из базы данных.
|
||||
- Инициализирует срез `users` для хранения пользователей.
|
||||
- Получает соединение с базой данных и использует метод `Find` для получения всех пользователей, предварительно загружая связанные задачи (`Todos`).
|
||||
- Возвращает список пользователей и возможную ошибку.
|
||||
|
||||
3. **GetUserByUsername**:
|
||||
- Возвращает пользователя по его имени (username).
|
||||
- Инициализирует переменную `user` для хранения пользователя.
|
||||
- Получает соединение с базой данных и использует метод `Where` для поиска пользователя по имени и метод `First` для получения первого найденного результата.
|
||||
- Возвращает найденного пользователя и возможную ошибку.
|
||||
|
||||
4. **GetUserByIDRepository**:
|
||||
- Возвращает пользователя по его идентификатору (ID).
|
||||
- Инициализирует переменную `user` для хранения пользователя.
|
||||
- Получает соединение с базой данных и использует метод `First` для поиска пользователя по ID, предварительно загружая связанные задачи (`Todos`).
|
||||
- Возвращает найденного пользователя и возможную ошибку.
|
||||
|
||||
5. **UpdateUserRepository**:
|
||||
- Обновляет информацию о пользователе в базе данных.
|
||||
- Получает соединение с базой данных и использует метод `Save` для обновления пользователя.
|
||||
- Возвращает возможную ошибку.
|
||||
|
||||
6. **DeleteUserRepository**:
|
||||
- Удаляет пользователя из базы данных по его идентификатору (ID).
|
||||
- Получает соединение с базой данных и использует метод `Delete` для удаления пользователя.
|
||||
- Возвращает возможную ошибку.
|
||||
|
||||
- ## routes/
|
||||
- ### routes.go
|
||||
- маршруты (routes) на основе Gin, задавая пути для операций с пользователями и задачами (Todo). Он также применяет middleware для аутентификации к определённым маршрутам.
|
||||
|
||||
1. **Пакеты и импорт**:
|
||||
- Импортируются необходимые пакеты: `gin-gonic/gin` для работы с веб-фреймворком Gin, а также локальные пакеты `todolist/controllers` и `todolist/middleware`.
|
||||
|
||||
2. **Функция `RegisterRoutes`**:
|
||||
- Функция `RegisterRoutes` регистрирует маршруты для приложения, принимая на вход экземпляр `gin.Engine`.
|
||||
|
||||
3. **Маршруты для пользователей**
|
||||
|
||||
- `r.POST("/register", controllers.Register)`: Маршрут для регистрации нового пользователя.
|
||||
|
||||
- `r.POST("/login", controllers.Login)`: Маршрут для входа пользователя.
|
||||
|
||||
- `r.GET("/users/:id", controllers.GetUserByID)`: Маршрут для получения пользователя по его ID.
|
||||
|
||||
- `r.GET("/users", controllers.GetUsers)`: Маршрут для получения всех пользователей.
|
||||
|
||||
- Группа маршрутов `userRoutes` с префиксом `/user`, к которой применяется middleware аутентификации `AuthMiddleware`:
|
||||
- `userRoutes.GET("/profile", controllers.GetUserProfile)`: Маршрут для получения профиля текущего пользователя.
|
||||
- `userRoutes.PATCH("/:id", controllers.UpdateUser)`: Маршрут для обновления пользователя по его ID.
|
||||
- `userRoutes.DELETE("/:id", controllers.DeleteUser)`: Маршрут для удаления пользователя по его ID.
|
||||
|
||||
4. **Маршруты для задач (Todo)**:
|
||||
- Группа маршрутов `todoRoutes` с префиксом `/todos`, к которой применяется middleware аутентификации `AuthMiddleware`:
|
||||
- `todoRoutes.POST("/", controllers.CreateTodo)`: Маршрут для создания новой задачи.
|
||||
- `todoRoutes.GET("/", controllers.GetTodos)`: Маршрут для получения всех задач.
|
||||
- `todoRoutes.GET("/:id", controllers.GetTodoByID)`: Маршрут для получения задачи по её ID.
|
||||
- `todoRoutes.PATCH("/:id", controllers.UpdateTodo)`: Маршрут для обновления задачи по её ID.
|
||||
- `todoRoutes.DELETE("/:id", controllers.DeleteTodo)`: Маршрут для удаления задачи по её ID.
|
||||
|
||||
- ## services/
|
||||
- ### todo_service.go
|
||||
- сервисы для работы с задачами (Todo), используя репозитории для выполнения операций с базой данных. Сервисы предоставляют более высокий уровень абстракции для логики бизнес-процессов, инкапсулируя детали взаимодействия с репозиториями.
|
||||
|
||||
1. **CreateTodoService**:
|
||||
- Создает новую задачу.
|
||||
- Вызывает функцию репозитория `CreateTodoRepository` для добавления новой задачи в базу данных.
|
||||
- Возвращает возможную ошибку.
|
||||
|
||||
2. **GetTodosService**:
|
||||
- Получает все задачи из базы данных.
|
||||
- Вызывает функцию репозитория `GetTodosRepository` для получения всех задач.
|
||||
- Возвращает список задач и возможную ошибку.
|
||||
|
||||
3. **GetTodoByIDService**:
|
||||
- Получает задачу по её идентификатору (ID).
|
||||
- Вызывает функцию репозитория `GetTodoByIDRepository` для получения задачи по ID.
|
||||
- Возвращает найденную задачу и возможную ошибку.
|
||||
|
||||
4. **UpdateTodoService**:
|
||||
- Обновляет информацию о задаче.
|
||||
- Сначала получает существующую задачу по её ID с помощью `GetTodoByIDRepository`.
|
||||
- Если задача найдена, обновляет её поля (заголовок и статус выполнения) значениями из переданного объекта `todo`.
|
||||
- Вызывает функцию репозитория `UpdateTodoRepository` для сохранения обновлённой задачи в базе данных.
|
||||
- Возвращает обновлённую задачу и возможную ошибку.
|
||||
|
||||
5. **DeleteTodoService**:
|
||||
- Удаляет задачу из базы данных по её идентификатору (ID).
|
||||
- Вызывает функцию репозитория `DeleteTodoRepository` для удаления задачи.
|
||||
- Возвращает возможную ошибку.
|
||||
|
||||
- ### user_service.go
|
||||
- сервисы для работы с пользователями, используя репозитории и утилиты для выполнения операций. Сервисы предоставляют более высокий уровень абстракции для логики бизнес-процессов.
|
||||
|
||||
1. **RegisterService**:
|
||||
- Регистрирует нового пользователя.
|
||||
- Хэширует пароль пользователя с помощью `bcrypt`.
|
||||
- Обновляет пароль пользователя на хэшированный.
|
||||
- Вызывает функцию репозитория `CreateUserRepository` для добавления нового пользователя в базу данных.
|
||||
- Возвращает возможную ошибку.
|
||||
|
||||
2. **LoginService**:
|
||||
- Выполняет вход пользователя.
|
||||
- Ищет пользователя по его имени с помощью `GetUserByUsername`.
|
||||
- Если пользователь не найден, возвращает ошибку "user not found".
|
||||
- Сравнивает хэшированный пароль пользователя с введенным паролем с помощью `bcrypt.CompareHashAndPassword`.
|
||||
- Если пароли не совпадают, возвращает ошибку "invalid credentials".
|
||||
- Генерирует токен для пользователя с помощью `utils.GenerateToken`.
|
||||
- Обновляет пользователя с новым токеном в базе данных с помощью `UpdateUserRepository`.
|
||||
- Возвращает токен и возможную ошибку.
|
||||
|
||||
3. **GetUsersService**:
|
||||
- Получает всех пользователей из базы данных.
|
||||
- Вызывает функцию репозитория `GetUsersRepository` для получения всех пользователей.
|
||||
- Возвращает список пользователей и возможную ошибку.
|
||||
|
||||
4. **GetUserByIDService**:
|
||||
- Получает пользователя по его идентификатору (ID).
|
||||
- Вызывает функцию репозитория `GetUserByIDRepository` для получения пользователя по ID.
|
||||
- Возвращает найденного пользователя и возможную ошибку.
|
||||
|
||||
5. **UpdateUserService**:
|
||||
- Обновляет информацию о пользователе.
|
||||
- Получает существующего пользователя по его ID с помощью `GetUserByIDRepository`.
|
||||
- Хэширует пароль пользователя с помощью `bcrypt`.
|
||||
- Обновляет поля пользователя (имя и пароль) значениями из переданного объекта `user`.
|
||||
- Вызывает функцию репозитория `UpdateUserRepository` для сохранения обновленного пользователя в базе данных.
|
||||
- Возвращает обновленного пользователя и возможную ошибку.
|
||||
|
||||
6. **DeleteUserService**:
|
||||
- Удаляет пользователя из базы данных по его идентификатору (ID).
|
||||
- Вызывает функцию репозитория `DeleteUserRepository` для удаления пользователя.
|
||||
- Возвращает возможную ошибку.
|
||||
|
||||
- ## utils/
|
||||
- ### todo_response_utils.go
|
||||
- утилитная функция для создания ответа на основе списка задач (Todo).
|
||||
|
||||
**Функция `CreateTodoResponse`**:
|
||||
- Принимает срез задач (`todos []domain.Todo`) в качестве входного параметра.
|
||||
- Создаёт пустой срез `todosModel` типа `[]domain.TodoResponse` для хранения преобразованных задач.
|
||||
- Использует функцию `lo.ForEach` для итерации по каждой задаче в списке `todos`.
|
||||
- Для каждой задачи создаёт объект `domain.TodoResponse`, копируя значения полей `Title` и `Completed` из оригинальной задачи.
|
||||
- Добавляет созданный объект `domain.TodoResponse` в `todosModel`.
|
||||
- Возвращает срез `todosModel`, содержащий преобразованные задачи.
|
||||
|
||||
- ### token_utils.go
|
||||
- утилиты для работы с JSON Web Tokens (JWT). Основные функции включают генерацию и валидацию JWT.
|
||||
|
||||
1. **Функция GenerateToken**:
|
||||
- Принимает идентификатор пользователя (`userID`) в качестве параметра.
|
||||
- Устанавливает время истечения токена на 24 часа с текущего момента (`expirationTime`).
|
||||
- Создаёт объект `Claims` с `UserID` и `ExpiresAt`.
|
||||
- Создаёт новый JWT с помощью метода `jwt.NewWithClaims`, используя алгоритм HMAC SHA256 (`jwt.SigningMethodHS256`) и claims.
|
||||
- Подписывает токен с использованием `jwtKey` и возвращает подписанную строку токена или ошибку.
|
||||
|
||||
2. **Функция ValidateToken**:
|
||||
- Принимает строку токена (`tokenString`) в качестве параметра.
|
||||
- Инициализирует объект `Claims`.
|
||||
- Использует метод `jwt.ParseWithClaims` для парсинга и валидации токена, передавая функцию, которая возвращает секретный ключ (`jwtKey`).
|
||||
- Если при парсинге произошла ошибка или токен недействителен (`!token.Valid`), возвращает соответствующую ошибку.
|
||||
- Если токен валиден, возвращает claims и `nil` в качестве ошибки.
|
||||
|
||||
- ### user_response_utils.go
|
||||
- утилитная функция для создания ответа на основе списка пользователей, включающего их задачи (Todos).
|
||||
|
||||
1. **Функция CreateUserResponse**:
|
||||
- Принимает срез пользователей (`users []domain.User`) в качестве входного параметра.
|
||||
- Инициализирует пустые срезы `usersModel` типа `[]domain.UserResponse` для хранения преобразованных пользователей и `todosModel` типа `[]domain.TodoResponse` для хранения преобразованных задач.
|
||||
- Использует функцию `lo.ForEach` для итерации по каждому пользователю в списке `users`.
|
||||
- Внутри первой итерации использует ещё одну итерацию `lo.ForEach` для каждого задания (Todo) пользователя.
|
||||
- Для каждой задачи создаёт объект `domain.TodoResponse`, копируя значения полей `Title` и `Completed` из оригинальной задачи, и добавляет его в `todosModel`.
|
||||
- После итерации по задачам пользователя, создаёт объект `domain.UserResponse`, копируя значения поля `Username` из оригинального пользователя и добавляя список задач `todosModel`.
|
||||
- Добавляет созданный объект `domain.UserResponse` в `usersModel`.
|
||||
- Возвращает срез `usersModel`, содержащий преобразованных пользователей и их задачи.
|
||||
|
||||
|
||||
|
||||
## Endpoints
|
||||
|
||||
### Todos
|
||||
|
||||
- **POST /todos/** - Создание нового Todo. Требуется JSON с данными Todo. Требуется токен пользователя.
|
||||
- **GET /todos/** - Получение списка всех Todos. Требуется токен пользователя.
|
||||
- **GET /todos/:id** - Получение информации о конкретном Todo. Требуется токен пользователя.
|
||||
- **PATCH /todos/:id** - Изменение Todo по идентификатору. Требуется JSON с данными Todo. Требуется токен пользователя.
|
||||
- **DELETE /todos/:id** - Удаление Todo по идентификатору. Требуется токен пользователя.
|
||||
|
||||
Пример JSON для создания Todo
|
||||
``` json
|
||||
|
||||
{
|
||||
"title": "newtitle",
|
||||
"completed": false,
|
||||
"title": 1,
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Пользователи
|
||||
|
||||
- **POST /register** - Регистрация нового пользователя. Требуется JSON с данными пользователя.
|
||||
- **POST /login** - Вход пользователя. Требуется JSON с данными для входа.
|
||||
- **GET /user/profile** - Получение данных текущего пользователя. Требуется токен пользователя.
|
||||
- **GET /users** - Получение списка всех пользователей.
|
||||
- **GET /users/:id** - Получение пользователя.
|
||||
- **PATCH /user/:id** - Редактирование имени и/или пароля пользователя. Требуется JSON с новым именем и/или паролем. Требуется токен пользователя.
|
||||
- **DELETE /user/:id** - Удаление пользователя. Требуется JSON с суммой. Требуется токен пользователя.
|
||||
|
||||
## Запуск сервера
|
||||
|
||||
- При запуске впервый раз:
|
||||
|
||||
``` go run database/migration.go ```
|
||||
|
||||
- Затем можно запускать контейнер вместе с БД Postgresql командой:
|
||||
|
||||
``` docker-compose up -d ```
|
||||
|
||||
- Затем запуск самого сервера
|
||||
|
||||
``` go run cmd/main.go ```
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"version": "1",
|
||||
"name": "bruno",
|
||||
"type": "collection",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
".git"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: dd
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
post {
|
||||
url:
|
||||
body: none
|
||||
auth: none
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"todolist/config"
|
||||
"todolist/routes"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
config.InitDatabase()
|
||||
routes.RegisterRoutes(r)
|
||||
err := r.Run(":8081")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to start server: %v", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"log"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func InitDatabase() {
|
||||
dsn := "host=localhost user=postgres password=example dbname=database port=5432 sslmode=disable TimeZone=Asia/Yekaterinburg"
|
||||
var err error
|
||||
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to connect database: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetDB() *gorm.DB {
|
||||
if db == nil {
|
||||
// если база данных не инициализирована
|
||||
log.Fatalf("database connection is not initialized")
|
||||
}
|
||||
return db
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"todolist/domain"
|
||||
"todolist/services"
|
||||
"todolist/utils"
|
||||
)
|
||||
|
||||
var validate = validator.New()
|
||||
|
||||
func CreateTodo(c *gin.Context) {
|
||||
var todo domain.Todo
|
||||
if err := c.ShouldBindJSON(&todo); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := validate.Struct(todo); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := services.CreateTodoService(&todo); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, utils.CreateTodoResponse([]domain.Todo{todo}))
|
||||
}
|
||||
|
||||
func GetTodos(c *gin.Context) {
|
||||
todos, err := services.GetTodosService()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, utils.CreateTodoResponse(todos))
|
||||
}
|
||||
|
||||
func GetTodoByID(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
todo, err := services.GetTodoByIDService(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, domain.ErrorResponse{Message: "Todo not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, utils.CreateTodoResponse([]domain.Todo{*todo}))
|
||||
}
|
||||
|
||||
func UpdateTodo(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
var todo domain.Todo
|
||||
if err := c.ShouldBindJSON(&todo); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := validate.Struct(todo); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
updatedTodo, err := services.UpdateTodoService(uint(id), &todo)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, utils.CreateTodoResponse([]domain.Todo{*updatedTodo}))
|
||||
}
|
||||
|
||||
func DeleteTodo(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
err := services.DeleteTodoService(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, domain.ErrorResponse{Message: "Todo not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Todo deleted successfully"})
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"todolist/domain"
|
||||
"todolist/services"
|
||||
"todolist/utils"
|
||||
)
|
||||
|
||||
func Register(c *gin.Context) {
|
||||
var user domain.User
|
||||
if err := c.ShouldBindJSON(&user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := validate.Struct(user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := services.RegisterService(&user); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, domain.Response{Message: "User created successfully!"})
|
||||
}
|
||||
|
||||
func Login(c *gin.Context) {
|
||||
var user domain.User
|
||||
if err := c.ShouldBindJSON(&user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := services.LoginService(user.Username, user.Password)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"token": token})
|
||||
}
|
||||
|
||||
func GetUserProfile(c *gin.Context) {
|
||||
user, exists := c.Get("user")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, domain.ErrorResponse{Message: "User not found"})
|
||||
return
|
||||
}
|
||||
|
||||
userModel, _ := user.(domain.User)
|
||||
|
||||
c.JSON(http.StatusOK, utils.CreateUserResponse([]domain.User{userModel}))
|
||||
}
|
||||
func GetUsers(c *gin.Context) {
|
||||
users, err := services.GetUsersService()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, utils.CreateUserResponse(users))
|
||||
}
|
||||
|
||||
func GetUserByID(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
user, err := services.GetUserByIDService(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, domain.ErrorResponse{Message: "User not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, user)
|
||||
}
|
||||
|
||||
func UpdateUser(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
var user domain.User
|
||||
if err := c.ShouldBindJSON(&user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := validate.Struct(user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
updatedUser, err := services.UpdateUserService(uint(id), &user)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, domain.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, utils.CreateUserResponse([]domain.User{*updatedUser}))
|
||||
}
|
||||
|
||||
func DeleteUser(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
err := services.DeleteUserService(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, domain.ErrorResponse{Message: "User not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, domain.Response{Message: "User deleted successfully!"})
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"todolist/config"
|
||||
"todolist/domain"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Инициализация базы данных
|
||||
config.InitDatabase()
|
||||
|
||||
db := config.GetDB()
|
||||
|
||||
// Миграции таблиц
|
||||
err := db.AutoMigrate(&domain.User{}, &domain.Todo{})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to migrate database: %v", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
# Use postgres/example user/password credentials
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
|
||||
db:
|
||||
image: postgres
|
||||
restart: always
|
||||
# set shared memory limit when using docker-compose
|
||||
shm_size: 128mb
|
||||
# or set shared memory limit when deploy via swarm stack
|
||||
#volumes:
|
||||
# - type: tmpfs
|
||||
# target: /dev/shm
|
||||
# tmpfs:
|
||||
# size: 134217728 # 128*2^20 bytes = 128Mb
|
||||
environment:
|
||||
POSTGRES_PASSWORD: example
|
||||
POSTGRES_DB: database
|
||||
POSTGRES_USER: postgres
|
||||
ports:
|
||||
- "127.0.0.1:5432:5432"
|
||||
|
||||
adminer:
|
||||
image: adminer
|
||||
restart: always
|
||||
ports:
|
||||
- 8000:8080
|
|
@ -0,0 +1,5 @@
|
|||
package domain
|
||||
|
||||
type ErrorResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package domain
|
||||
|
||||
type Response struct {
|
||||
Message string `json:"message"`
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Todo struct {
|
||||
gorm.Model
|
||||
Title string `json:"title" validate:"required"`
|
||||
Completed bool `json:"completed"`
|
||||
UserID uint `json:"user_id" gorm:"foreignKey:UserID;references:ID:"`
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package domain
|
||||
|
||||
type TodoResponse struct {
|
||||
Title string `json:"title"`
|
||||
Completed bool `json:"completed"`
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
Token string `json:"token"`
|
||||
Todos []Todo `json:"todos"`
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package domain
|
||||
|
||||
type UserResponse struct {
|
||||
Username any `json:"username"`
|
||||
Todos []TodoResponse `json:"todos"`
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
module todolist
|
||||
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-playground/validator/v10 v10.20.0
|
||||
github.com/samber/lo v1.39.0
|
||||
golang.org/x/crypto v0.23.0
|
||||
gorm.io/driver/postgres v1.5.7
|
||||
gorm.io/gorm v1.25.10
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
|
@ -0,0 +1,117 @@
|
|||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
|
||||
github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM=
|
||||
gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
|
||||
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|
@ -0,0 +1,38 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"todolist/config"
|
||||
"todolist/domain"
|
||||
"todolist/utils"
|
||||
)
|
||||
|
||||
func AuthMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
token := c.GetHeader("Authorization")
|
||||
if token == "" {
|
||||
c.JSON(http.StatusUnauthorized, domain.ErrorResponse{Message: "Authorization token required"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := utils.ValidateToken(token)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, domain.ErrorResponse{Message: err.Error()})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
var user domain.User
|
||||
if err := config.GetDB().Preload("Todos").Where("id = ?", claims.UserID).First(&user).Error; err != nil {
|
||||
//c.JSON(http.StatusUnauthorized, domain.ErrorResponse{Message: "Invalid token"})
|
||||
c.JSON(http.StatusUnauthorized, domain.ErrorResponse{Message: err.Error()})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("user", user)
|
||||
c.Next()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package repositories
|
||||
|
||||
import (
|
||||
"todolist/config"
|
||||
"todolist/domain"
|
||||
)
|
||||
|
||||
// CreateTodoRepository создает новую задачу в базе данных.
|
||||
func CreateTodoRepository(todo *domain.Todo) error {
|
||||
db := config.GetDB()
|
||||
return db.Create(todo).Error
|
||||
}
|
||||
|
||||
// GetTodosRepository возвращает все задачи из базы данных.
|
||||
func GetTodosRepository() ([]domain.Todo, error) {
|
||||
var todos []domain.Todo
|
||||
db := config.GetDB()
|
||||
err := db.Find(&todos).Error
|
||||
return todos, err
|
||||
}
|
||||
|
||||
// GetTodoByIDRepository возвращает задачу по ее ID.
|
||||
func GetTodoByIDRepository(id uint) (*domain.Todo, error) {
|
||||
var todo domain.Todo
|
||||
db := config.GetDB()
|
||||
err := db.First(&todo, id).Error
|
||||
return &todo, err
|
||||
}
|
||||
|
||||
// UpdateTodoRepository обновляет информацию о задаче в базе данных.
|
||||
func UpdateTodoRepository(todo *domain.Todo) error {
|
||||
db := config.GetDB()
|
||||
return db.Save(todo).Error
|
||||
}
|
||||
|
||||
// DeleteTodoRepository удаляет задачу из базы данных.
|
||||
func DeleteTodoRepository(id uint) error {
|
||||
db := config.GetDB()
|
||||
return db.Delete(&domain.Todo{}, id).Error
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package repositories
|
||||
|
||||
import (
|
||||
"todolist/config"
|
||||
"todolist/domain"
|
||||
)
|
||||
|
||||
// CreateUserRepository создает нового пользователя в базе данных.
|
||||
func CreateUserRepository(user *domain.User) error {
|
||||
db := config.GetDB()
|
||||
return db.Create(user).Error
|
||||
}
|
||||
|
||||
// GetUsersRepository возвращает всех пользователей из базы данных.
|
||||
func GetUsersRepository() ([]domain.User, error) {
|
||||
var users []domain.User
|
||||
db := config.GetDB()
|
||||
err := db.Preload("Todos").Find(&users).Error
|
||||
return users, err
|
||||
}
|
||||
|
||||
// GetUserByUsername возвращает пользователя по его имени.
|
||||
func GetUserByUsername(username string) (*domain.User, error) {
|
||||
var user domain.User
|
||||
db := config.GetDB()
|
||||
err := db.Where("username = ?", username).First(&user).Error
|
||||
return &user, err
|
||||
}
|
||||
|
||||
// GetUserByIDRepository возвращает пользователя по его ID.
|
||||
func GetUserByIDRepository(userID uint) (*domain.User, error) {
|
||||
var user domain.User
|
||||
db := config.GetDB()
|
||||
err := db.Preload("Todos").First(&user, userID).Error
|
||||
return &user, err
|
||||
}
|
||||
|
||||
// UpdateUserRepository обновляет информацию о пользователе в базе данных.
|
||||
func UpdateUserRepository(user *domain.User) error {
|
||||
db := config.GetDB()
|
||||
return db.Save(user).Error
|
||||
}
|
||||
|
||||
// DeleteUserRepository удаляет пользователя из базы данных.
|
||||
func DeleteUserRepository(id uint) error {
|
||||
db := config.GetDB()
|
||||
return db.Delete(&domain.User{}, id).Error
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"todolist/controllers"
|
||||
"todolist/middleware"
|
||||
)
|
||||
|
||||
func RegisterRoutes(r *gin.Engine) {
|
||||
// User routes
|
||||
r.POST("/register", controllers.Register)
|
||||
r.POST("/login", controllers.Login)
|
||||
r.GET("/users/:id", controllers.GetUserByID)
|
||||
r.GET("/users", controllers.GetUsers)
|
||||
|
||||
userRoutes := r.Group("/user")
|
||||
userRoutes.Use(middleware.AuthMiddleware())
|
||||
{
|
||||
userRoutes.GET("/profile", controllers.GetUserProfile)
|
||||
userRoutes.PATCH("/:id", controllers.UpdateUser)
|
||||
userRoutes.DELETE("/:id", controllers.DeleteUser)
|
||||
}
|
||||
|
||||
// 1todo routes
|
||||
todoRoutes := r.Group("/todos")
|
||||
todoRoutes.Use(middleware.AuthMiddleware())
|
||||
{
|
||||
todoRoutes.POST("/", controllers.CreateTodo)
|
||||
todoRoutes.GET("/", controllers.GetTodos)
|
||||
todoRoutes.GET("/:id", controllers.GetTodoByID)
|
||||
todoRoutes.PATCH("/:id", controllers.UpdateTodo)
|
||||
todoRoutes.DELETE("/:id", controllers.DeleteTodo)
|
||||
// Add other routes such as PUT /:id, DELETE /:id, and GET /:id
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"todolist/domain"
|
||||
"todolist/repositories"
|
||||
)
|
||||
|
||||
// CreateTodoService создает новую задачу.
|
||||
func CreateTodoService(todo *domain.Todo) error {
|
||||
return repositories.CreateTodoRepository(todo)
|
||||
}
|
||||
|
||||
// GetTodosService получает все задачи из базы данных.
|
||||
func GetTodosService() ([]domain.Todo, error) {
|
||||
return repositories.GetTodosRepository()
|
||||
}
|
||||
|
||||
// GetTodoByIDService получает задачу по ее ID.
|
||||
func GetTodoByIDService(id uint) (*domain.Todo, error) {
|
||||
return repositories.GetTodoByIDRepository(id)
|
||||
}
|
||||
|
||||
// UpdateTodoService обновляет информацию о задаче.
|
||||
func UpdateTodoService(id uint, todo *domain.Todo) (*domain.Todo, error) {
|
||||
existingTodo, err := repositories.GetTodoByIDRepository(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingTodo.Title = todo.Title
|
||||
existingTodo.Completed = todo.Completed
|
||||
|
||||
if err := repositories.UpdateTodoRepository(existingTodo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return existingTodo, nil
|
||||
}
|
||||
|
||||
// DeleteTodoService удаляет задачу из базы данных.
|
||||
func DeleteTodoService(id uint) error {
|
||||
return repositories.DeleteTodoRepository(id)
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"todolist/domain"
|
||||
"todolist/repositories"
|
||||
"todolist/utils"
|
||||
)
|
||||
|
||||
func RegisterService(user *domain.User) error {
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.Password = string(hashedPassword)
|
||||
return repositories.CreateUserRepository(user)
|
||||
}
|
||||
|
||||
func LoginService(username, password string) (string, error) {
|
||||
user, err := repositories.GetUserByUsername(username)
|
||||
if err != nil {
|
||||
return "", errors.New("user not found")
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
|
||||
if err != nil {
|
||||
return "", errors.New("invalid credentials")
|
||||
}
|
||||
|
||||
token, err := utils.GenerateToken(user.ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
user.Token = token
|
||||
if err := repositories.UpdateUserRepository(user); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func GetUsersService() ([]domain.User, error) {
|
||||
return repositories.GetUsersRepository()
|
||||
}
|
||||
|
||||
func GetUserByIDService(id uint) (*domain.User, error) {
|
||||
return repositories.GetUserByIDRepository(id)
|
||||
}
|
||||
|
||||
func UpdateUserService(id uint, user *domain.User) (*domain.User, error) {
|
||||
existingUser, err := repositories.GetUserByIDRepository(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(existingUser.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingUser.Username = user.Username
|
||||
existingUser.Password = string(hashedPassword)
|
||||
if err := repositories.UpdateUserRepository(existingUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return existingUser, nil
|
||||
}
|
||||
|
||||
func DeleteUserService(id uint) error {
|
||||
return repositories.DeleteUserRepository(id)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"github.com/samber/lo"
|
||||
"todolist/domain"
|
||||
)
|
||||
|
||||
func CreateTodoResponse(todos []domain.Todo) []domain.TodoResponse {
|
||||
var todosModel []domain.TodoResponse
|
||||
lo.ForEach(todos, func(todo domain.Todo, _ int) {
|
||||
todosModel = append(todosModel, domain.TodoResponse{
|
||||
Title: todo.Title,
|
||||
Completed: todo.Completed,
|
||||
})
|
||||
})
|
||||
|
||||
return todosModel
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"time"
|
||||
)
|
||||
|
||||
var jwtKey = []byte("secret_key")
|
||||
|
||||
type Claims struct {
|
||||
UserID uint `json:"user_id"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
func GenerateToken(userID uint) (string, error) {
|
||||
expirationTime := time.Now().Add(24 * time.Hour)
|
||||
claims := &Claims{
|
||||
UserID: userID,
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
ExpiresAt: expirationTime.Unix(),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(jwtKey)
|
||||
}
|
||||
|
||||
func ValidateToken(tokenString string) (*Claims, error) {
|
||||
claims := &Claims{}
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return jwtKey, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !token.Valid {
|
||||
return nil, errors.New("invalid token")
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"github.com/samber/lo"
|
||||
"todolist/domain"
|
||||
)
|
||||
|
||||
func CreateUserResponse(users []domain.User) []domain.UserResponse {
|
||||
var usersModel []domain.UserResponse
|
||||
var todosModel []domain.TodoResponse
|
||||
lo.ForEach(users, func(user domain.User, _ int) {
|
||||
lo.ForEach(user.Todos, func(todo domain.Todo, _ int) {
|
||||
todosModel = append(todosModel, domain.TodoResponse{
|
||||
Title: todo.Title,
|
||||
Completed: todo.Completed,
|
||||
})
|
||||
})
|
||||
usersModel = append(usersModel, domain.UserResponse{
|
||||
Username: user.Username,
|
||||
Todos: todosModel,
|
||||
})
|
||||
})
|
||||
return usersModel
|
||||
}
|
Loading…
Reference in New Issue