diff --git a/assets/vue/components/layout/DashboardLayout.vue b/assets/vue/components/layout/DashboardLayout.vue
index 10f9569d5f..17f6b187e6 100644
--- a/assets/vue/components/layout/DashboardLayout.vue
+++ b/assets/vue/components/layout/DashboardLayout.vue
@@ -33,9 +33,12 @@
-
-
-
+
+ Profile
+
+
+
+
+
diff --git a/assets/vue/components/usergroup/Layout.vue b/assets/vue/components/usergroup/Layout.vue
new file mode 100644
index 0000000000..1b86f434a8
--- /dev/null
+++ b/assets/vue/components/usergroup/Layout.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/assets/vue/components/userreluser/Layout.vue b/assets/vue/components/userreluser/Layout.vue
new file mode 100644
index 0000000000..4c4e209578
--- /dev/null
+++ b/assets/vue/components/userreluser/Layout.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/assets/vue/main.js b/assets/vue/main.js
index df05950450..eb28f8752d 100644
--- a/assets/vue/main.js
+++ b/assets/vue/main.js
@@ -4,6 +4,9 @@ import i18n from './i18n';
import router from './router';
import store from './store';
import axios from 'axios'
+
+// Services
+
import courseCategoryService from './services/coursecategory';
import documentsService from './services/documents';
import courseService from './services/course';
@@ -11,6 +14,11 @@ import personalFileService from './services/personalfile';
import resourceLinkService from './services/resourcelink';
import resourceNodeService from './services/resourcenode';
import messageService from './services/message';
+import userService from './services/user';
+import userGroupService from './services/usergroup';
+import userRelUserService from './services/userreluser';
+
+
import makeCrudModule from './store/modules/crud';
//import vuetify from './plugins/vuetify' // path to vuetify export
@@ -79,6 +87,29 @@ store.registerModule(
})
);
+store.registerModule(
+ 'userreluser',
+ makeCrudModule({
+ service: userRelUserService
+ })
+);
+
+store.registerModule(
+ 'user',
+ makeCrudModule({
+ service: userService
+ })
+);
+
+store.registerModule(
+ 'usergroup',
+ makeCrudModule({
+ service: userGroupService
+ })
+);
+
+
+
// Vuetify.
import '@mdi/font/css/materialdesignicons.css';
import 'vuetify/lib/styles/main.sass';
diff --git a/assets/vue/router/index.js b/assets/vue/router/index.js
index a97fac527b..3ea235c450 100644
--- a/assets/vue/router/index.js
+++ b/assets/vue/router/index.js
@@ -3,12 +3,13 @@ import courseRoutes from './course';
import accountRoutes from './account';
import personalFileRoutes from './personalfile';
import messageRoutes from './message';
+import userRoutes from './user';
+import userGroupRoutes from './usergroup';
+import userRelUserRoutes from './userreluser';
//import courseCategoryRoutes from './coursecategory';
import documents from './documents';
import store from '../store';
-//import Legacy from '../views/Legacy.vue';
-//import Home from '../views/Home.vue';
import MyCourseList from '../views/user/courses/List.vue';
import MySessionList from '../views/user/sessions/List.vue';
@@ -91,7 +92,10 @@ const router = createRouter({
documents,
accountRoutes,
personalFileRoutes,
- messageRoutes
+ messageRoutes,
+ userRoutes,
+ userGroupRoutes,
+ userRelUserRoutes,
]
});
diff --git a/assets/vue/router/user.js b/assets/vue/router/user.js
new file mode 100644
index 0000000000..c465a54a00
--- /dev/null
+++ b/assets/vue/router/user.js
@@ -0,0 +1,15 @@
+export default {
+ path: '/resources/users',
+ meta: { requiresAuth: true },
+ name: 'users',
+ component: () => import('../components/user/Layout.vue'),
+ //redirect: { name: 'UserGroupList' },
+ children: [
+ {
+ name: 'UserGroupShow',
+ //path: ':id',
+ path: 'show',
+ component: () => import('../views/usergroup/Show.vue')
+ }
+ ]
+};
diff --git a/assets/vue/router/usergroup.js b/assets/vue/router/usergroup.js
new file mode 100644
index 0000000000..ca160f1802
--- /dev/null
+++ b/assets/vue/router/usergroup.js
@@ -0,0 +1,20 @@
+export default {
+ path: '/resources/usergroups',
+ meta: { requiresAuth: true },
+ name: 'usergroups',
+ component: () => import('../components/usergroup/Layout.vue'),
+ redirect: { name: 'UserGroupList' },
+ children: [
+ {
+ name: 'UserGroupList',
+ path: '',
+ component: () => import('../views/usergroup/List.vue')
+ },
+ {
+ name: 'UserGroupShow',
+ //path: ':id',
+ path: 'show',
+ component: () => import('../views/usergroup/Show.vue')
+ }
+ ]
+};
diff --git a/assets/vue/router/userreluser.js b/assets/vue/router/userreluser.js
new file mode 100644
index 0000000000..a411751f91
--- /dev/null
+++ b/assets/vue/router/userreluser.js
@@ -0,0 +1,20 @@
+export default {
+ path: '/resources/friends',
+ meta: { requiresAuth: true },
+ name: 'friends',
+ component: () => import('../components/userreluser/Layout.vue'),
+ redirect: { name: 'UserGroupList' },
+ children: [
+ {
+ name: 'UserRelUserList',
+ path: '',
+ component: () => import('../views/userreluser/List.vue')
+ },
+ {
+ name: 'UserRelUserAdd',
+ //path: ':id',
+ path: 'add',
+ component: () => import('../views/userreluser/Add.vue')
+ }
+ ]
+};
diff --git a/assets/vue/services/user.js b/assets/vue/services/user.js
new file mode 100644
index 0000000000..24de6c6ab6
--- /dev/null
+++ b/assets/vue/services/user.js
@@ -0,0 +1,3 @@
+import makeService from './api';
+
+export default makeService('user');
diff --git a/assets/vue/services/usergroup.js b/assets/vue/services/usergroup.js
new file mode 100644
index 0000000000..32e35df395
--- /dev/null
+++ b/assets/vue/services/usergroup.js
@@ -0,0 +1,3 @@
+import makeService from './api';
+
+export default makeService('usergroups');
diff --git a/assets/vue/services/userreluser.js b/assets/vue/services/userreluser.js
new file mode 100644
index 0000000000..90498d70d5
--- /dev/null
+++ b/assets/vue/services/userreluser.js
@@ -0,0 +1,3 @@
+import makeService from './api';
+
+export default makeService('user_rel_users');
diff --git a/assets/vue/views/account/Home.vue b/assets/vue/views/account/Home.vue
index 522ddf3146..0d6dc66087 100644
--- a/assets/vue/views/account/Home.vue
+++ b/assets/vue/views/account/Home.vue
@@ -1,18 +1,21 @@
-
+
+
+
+
+
+
{{ user.firstname }} {{ user.lastname }}
+
-
-
-
-
+
Edit profile
-
+
diff --git a/assets/vue/views/usergroup/Show.vue b/assets/vue/views/usergroup/Show.vue
new file mode 100644
index 0000000000..f83865c579
--- /dev/null
+++ b/assets/vue/views/usergroup/Show.vue
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ From:
+
+
+
+
+ {{ item['userSender']['username'] }}
+
+
+
+ {{ $luxonDateTime.fromISO(item['sendDate']).toRelative() }}
+
+
+
+
{{ item.title }}
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/vue/views/userreluser/Add.vue b/assets/vue/views/userreluser/Add.vue
new file mode 100644
index 0000000000..9ff9aa8ea2
--- /dev/null
+++ b/assets/vue/views/userreluser/Add.vue
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/vue/views/userreluser/List.vue b/assets/vue/views/userreluser/List.vue
new file mode 100644
index 0000000000..4587493a5a
--- /dev/null
+++ b/assets/vue/views/userreluser/List.vue
@@ -0,0 +1,381 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Friends
+
+
+
+
+
+
+
+
+
+ {{ slotProps.data.friend.username }}
+
+
+
+
+
+ {{$luxonDateTime.fromISO(slotProps.data.createdAt).toRelative() }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/CoreBundle/Entity/UserRelUser.php b/src/CoreBundle/Entity/UserRelUser.php
index de4ee8e085..c7a3beb7a1 100644
--- a/src/CoreBundle/Entity/UserRelUser.php
+++ b/src/CoreBundle/Entity/UserRelUser.php
@@ -6,7 +6,9 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Entity;
+use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
+use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use Chamilo\CoreBundle\Traits\TimestampableTypedEntity;
use Chamilo\CoreBundle\Traits\UserTrait;
use Doctrine\ORM\Mapping as ORM;
@@ -53,6 +55,11 @@ use Symfony\Component\Validator\Constraints as Assert;
'groups' => ['user_rel_user:read', 'timestampable_created:read'],
],
)]
+#[ApiFilter(SearchFilter::class, properties: [
+ 'user' => 'exact',
+ 'friend' => 'exact',
+ 'relationType' => 'exact',
+])]
class UserRelUser
{
use UserTrait;