diff --git a/api/app/application/users_repository.py b/api/app/application/users_repository.py
index a1b9e81..d061f0c 100644
--- a/api/app/application/users_repository.py
+++ b/api/app/application/users_repository.py
@@ -3,6 +3,7 @@ from typing import Optional, List
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
+from app.domain.models import Role
from app.domain.models.users import User
@@ -31,6 +32,15 @@ class UsersRepository:
result = await self.db.execute(query)
return result.scalars().first()
+ async def get_by_role_name(self, role_name: str) -> List[User]:
+ query = (
+ select(User)
+ .join(User.role)
+ .filter(Role.title == role_name)
+ )
+ result = await self.db.execute(query)
+ return result.scalars().all()
+
async def create(self, user: User) -> User:
self.db.add(user)
await self.db.commit()
diff --git a/api/app/controllers/users_router.py b/api/app/controllers/users_router.py
index b4d59ad..dfa31ac 100644
--- a/api/app/controllers/users_router.py
+++ b/api/app/controllers/users_router.py
@@ -86,3 +86,18 @@ async def create_user(
):
register_service = RegisterService(db)
return await register_service.create_user(user)
+
+
+@users_router.get(
+ '/role/{role_name}/',
+ response_model=List[UserRead],
+ summary='Return all users with given role',
+ description='Return all users with given role',
+)
+async def get_users_by_role_name(
+ role_name: str,
+ db: AsyncSession = Depends(get_db),
+ current_user: User = Depends(require_auth_user),
+):
+ users_service = UsersService(db)
+ return await users_service.get_by_role_name(role_name)
diff --git a/api/app/infrastructure/users_service.py b/api/app/infrastructure/users_service.py
index 3a110ee..d84ae13 100644
--- a/api/app/infrastructure/users_service.py
+++ b/api/app/infrastructure/users_service.py
@@ -95,3 +95,11 @@ class UsersService:
user_model = await self.users_repository.update(user_model)
return UserRead.model_validate(user_model)
+
+ async def get_by_role_name(self, role_name: str) -> List[UserRead]:
+ users = await self.users_repository.get_by_role_name(role_name)
+ response = []
+ for user in users:
+ response.append(UserRead.model_validate(user))
+
+ return response
diff --git a/web/src/Api/coursesApi.js b/web/src/Api/coursesApi.js
new file mode 100644
index 0000000..c526836
--- /dev/null
+++ b/web/src/Api/coursesApi.js
@@ -0,0 +1,74 @@
+import CONFIG from "../Core/сonfig.js";
+import {baseQueryWithAuth} from "./baseQuery.js";
+import {createApi} from "@reduxjs/toolkit/query/react";
+
+
+export const coursesApi = createApi({
+ reducerPath: 'coursesApi',
+ baseQuery: baseQueryWithAuth,
+ endpoints: (builder) => ({
+ getAllCourses: builder.query({
+ query: () => ({
+ url: "/courses/",
+ method: "GET",
+ }),
+ providesTags: ['course'],
+ }),
+ createCourse: builder.mutation({
+ query: (data) => ({
+ url: "/courses/",
+ method: "POST",
+ body: data,
+ }),
+ invalidatesTags: ['course'],
+ }),
+ updateCourse: builder.mutation({
+ query: ({courseId, ...data}) => ({
+ url: `/courses/${courseId}/`,
+ method: "PUT",
+ body: data,
+ }),
+ invalidatesTags: ['course'],
+ }),
+ getCourseTeachers: builder.query({
+ query: (courseId) => ({
+ url: `/courses/${courseId}/teachers/`,
+ method: "GET",
+ }),
+ providesTags: ['teacher'],
+ }),
+ replaceCourseTeachers: builder.mutation({
+ query: ({courseId, ...data}) => ({
+ url: `/courses/${courseId}/teachers/`,
+ method: "PUT",
+ body: data,
+ }),
+ invalidatesTags: ['teacher'],
+ }),
+ getCourseStudents: builder.query({
+ query: (courseId) => ({
+ url: `/courses/${courseId}/students/`,
+ method: "GET",
+ }),
+ providesTags: ['student'],
+ }),
+ replaceCourseStudents: builder.mutation({
+ query: ({courseId, ...data}) => ({
+ url: `/courses/${courseId}/students/`,
+ method: "PUT",
+ body: data,
+ }),
+ invalidatesTags: ['student'],
+ }),
+ }),
+});
+
+export const {
+ useGetAllCoursesQuery,
+ useCreateCourseMutation,
+ useUpdateCourseMutation,
+ useGetCourseTeachersQuery,
+ useReplaceCourseTeachersMutation,
+ useGetCourseStudentsQuery,
+ useReplaceCourseStudentsMutation,
+} = coursesApi;
\ No newline at end of file
diff --git a/web/src/Api/usersApi.js b/web/src/Api/usersApi.js
index 280b620..e1a2333 100644
--- a/web/src/Api/usersApi.js
+++ b/web/src/Api/usersApi.js
@@ -39,6 +39,13 @@ export const usersApi = createApi({
}),
invalidatesTags: ["user"],
}),
+ getUsersByRoleName: builder.query({
+ query: (roleName) => ({
+ url: `/users/role/${roleName}/`,
+ method: "GET",
+ }),
+ providesTags: ["user"],
+ }),
}),
});
@@ -48,4 +55,5 @@ export const {
useUpdateUserMutation,
useUpdateUserPasswordMutation,
useCreateUserMutation,
+ useGetUsersByRoleNameQuery,
} = usersApi;
\ No newline at end of file
diff --git a/web/src/Components/Pages/AdminPage/AdminPage.jsx b/web/src/Components/Pages/AdminPage/AdminPage.jsx
index 33d3290..dcefc4e 100644
--- a/web/src/Components/Pages/AdminPage/AdminPage.jsx
+++ b/web/src/Components/Pages/AdminPage/AdminPage.jsx
@@ -2,8 +2,8 @@ import {Button, Col, Flex, FloatButton, Input, Result, Row, Table, Tooltip, Typo
import {ControlOutlined, PlusOutlined} from "@ant-design/icons";
import useAdminPage from "./useAdminPage.js";
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
-import CreateUserModalForm from "./CreateUserModalForm/CreateUserModalForm.jsx";
-import UpdateUserModalForm from "./UpdateUserModalForm/UpdateUserModalForm.jsx";
+import CreateUserModalForm from "./Components/CreateUserModalForm/CreateUserModalForm.jsx";
+import UpdateUserModalForm from "./Components/UpdateUserModalForm/UpdateUserModalForm.jsx";
const {Title} = Typography;
diff --git a/web/src/Components/Pages/AdminPage/CreateUserModalForm/CreateUserModalForm.jsx b/web/src/Components/Pages/AdminPage/Components/CreateUserModalForm/CreateUserModalForm.jsx
similarity index 100%
rename from web/src/Components/Pages/AdminPage/CreateUserModalForm/CreateUserModalForm.jsx
rename to web/src/Components/Pages/AdminPage/Components/CreateUserModalForm/CreateUserModalForm.jsx
diff --git a/web/src/Components/Pages/AdminPage/CreateUserModalForm/useCreateUserModalForm.js b/web/src/Components/Pages/AdminPage/Components/CreateUserModalForm/useCreateUserModalForm.js
similarity index 92%
rename from web/src/Components/Pages/AdminPage/CreateUserModalForm/useCreateUserModalForm.js
rename to web/src/Components/Pages/AdminPage/Components/CreateUserModalForm/useCreateUserModalForm.js
index 559bfdd..94bbe43 100644
--- a/web/src/Components/Pages/AdminPage/CreateUserModalForm/useCreateUserModalForm.js
+++ b/web/src/Components/Pages/AdminPage/Components/CreateUserModalForm/useCreateUserModalForm.js
@@ -1,8 +1,8 @@
import {useDispatch, useSelector} from "react-redux";
import {Form, notification} from "antd";
-import {setOpenModalCreateUser, setSelectedUserToUpdate} from "../../../../Redux/Slices/usersSlice.js";
-import {useGetAllRolesQuery} from "../../../../Api/rolesApi.js";
-import {useCreateUserMutation} from "../../../../Api/usersApi.js";
+import {setOpenModalCreateUser, setSelectedUserToUpdate} from "../../../../../Redux/Slices/usersSlice.js";
+import {useGetAllRolesQuery} from "../../../../../Api/rolesApi.js";
+import {useCreateUserMutation} from "../../../../../Api/usersApi.js";
const useCreateUserModalForm = () => {
diff --git a/web/src/Components/Pages/AdminPage/UpdateUserModalForm/UpdateUserModalForm.jsx b/web/src/Components/Pages/AdminPage/Components/UpdateUserModalForm/UpdateUserModalForm.jsx
similarity index 99%
rename from web/src/Components/Pages/AdminPage/UpdateUserModalForm/UpdateUserModalForm.jsx
rename to web/src/Components/Pages/AdminPage/Components/UpdateUserModalForm/UpdateUserModalForm.jsx
index b364ece..991d690 100644
--- a/web/src/Components/Pages/AdminPage/UpdateUserModalForm/UpdateUserModalForm.jsx
+++ b/web/src/Components/Pages/AdminPage/Components/UpdateUserModalForm/UpdateUserModalForm.jsx
@@ -23,7 +23,7 @@ import {
TagOutlined,
} from "@ant-design/icons";
import dayjs from "dayjs";
-import LoadingIndicator from "../../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
+import LoadingIndicator from "../../../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
import useUpdateUserModalForm from "./useUpdateUserModalForm.js";
const {Title, Text} = Typography;
diff --git a/web/src/Components/Pages/AdminPage/UpdateUserModalForm/useUpdateUserModalForm.js b/web/src/Components/Pages/AdminPage/Components/UpdateUserModalForm/useUpdateUserModalForm.js
similarity index 94%
rename from web/src/Components/Pages/AdminPage/UpdateUserModalForm/useUpdateUserModalForm.js
rename to web/src/Components/Pages/AdminPage/Components/UpdateUserModalForm/useUpdateUserModalForm.js
index d749512..8267780 100644
--- a/web/src/Components/Pages/AdminPage/UpdateUserModalForm/useUpdateUserModalForm.js
+++ b/web/src/Components/Pages/AdminPage/Components/UpdateUserModalForm/useUpdateUserModalForm.js
@@ -1,11 +1,11 @@
import {useDispatch, useSelector} from "react-redux";
import {Form, notification} from "antd";
-import {setSelectedUserToUpdate} from "../../../../Redux/Slices/usersSlice.js";
-import {useGetAllRolesQuery} from "../../../../Api/rolesApi.js";
+import {setSelectedUserToUpdate} from "../../../../../Redux/Slices/usersSlice.js";
+import {useGetAllRolesQuery} from "../../../../../Api/rolesApi.js";
import {useEffect} from "react";
import dayjs from "dayjs";
-import {useUpdateUserMutation, useUpdateUserPasswordMutation} from "../../../../Api/usersApi.js";
-import {useGetStatusesQuery} from "../../../../Api/statusesApi.js";
+import {useUpdateUserMutation, useUpdateUserPasswordMutation} from "../../../../../Api/usersApi.js";
+import {useGetStatusesQuery} from "../../../../../Api/statusesApi.js";
const useUpdateUserModalForm = () => {
diff --git a/web/src/Components/Pages/Courses/Components/CreateCourseModalForm/CreateCourseModalForm.jsx b/web/src/Components/Pages/Courses/Components/CreateCourseModalForm/CreateCourseModalForm.jsx
new file mode 100644
index 0000000..87a2f32
--- /dev/null
+++ b/web/src/Components/Pages/Courses/Components/CreateCourseModalForm/CreateCourseModalForm.jsx
@@ -0,0 +1,98 @@
+import useCreateCourseModalForm from "./useCreateCourseModalForm.js";
+import {Button, Col, Form, Input, Modal, Result, Row, Select} from "antd";
+import TextArea from "antd/es/input/TextArea.js";
+import LoadingIndicator from "../../../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
+
+
+const CreateCourseModal = () => {
+ const {
+ openCreateCourseModal,
+ handleCancel,
+ form,
+ isLoadinging,
+ isError,
+ teachers,
+ students
+ } = useCreateCourseModalForm();
+
+ if (isLoadinging) {
+ return (
+