Internal: Fix relation Course <-> CourseRelUser

pull/4752/head
Angel Fernando Quiroz Campos 2 years ago
parent 5883d6b371
commit f088413dd6
  1. 2
      public/main/inc/ajax/social.ajax.php
  2. 4
      public/main/inc/lib/add_course.lib.inc.php
  3. 2
      public/main/inc/lib/course.lib.php
  4. 2
      public/plugin/buycourses/src/buy_course_plugin.class.php
  5. 2
      public/plugin/buycourses/src/configure_course.php
  6. 2
      public/plugin/grading_electronic/generate.php
  7. 2
      src/CoreBundle/Controller/CourseController.php
  8. 126
      src/CoreBundle/Entity/Course.php
  9. 39
      src/CoreBundle/Entity/CourseRelUser.php
  10. 9
      src/CoreBundle/Entity/User.php
  11. 2
      src/CoreBundle/Migrations/Schema/V200/Version20201215142610.php
  12. 8
      src/CoreBundle/Security/Authorization/Voter/CourseVoter.php
  13. 4
      src/CoreBundle/Security/Authorization/Voter/GroupVoter.php
  14. 2
      src/CoreBundle/Security/Authorization/Voter/TrackEExerciseVoter.php
  15. 4
      tests/CoreBundle/Controller/CourseControllerTest.php
  16. 44
      tests/CoreBundle/Repository/Node/CourseRepositoryTest.php
  17. 8
      tests/CoreBundle/Security/Authorization/Voter/CourseVoterTest.php
  18. 12
      tests/CoreBundle/Security/Authorization/Voter/GroupVoterTest.php
  19. 4
      tests/CoreBundle/Security/Authorization/Voter/SessionVoterTest.php

@ -88,7 +88,7 @@ switch ($action) {
$course_code = $course->getCode();
$user = api_get_user_entity();
if ($course->hasUser($user)) {
if ($course->hasSubscriptionByUser($user)) {
//------Forum messages
$forum_result = Container::getForumPostRepository()->countUserForumPosts($user, $course);
$all_result_data = 0;

@ -798,7 +798,7 @@ class AddCourse
->setRelationType(0)
->setUserCourseCat(0)
;
$course->addUsers($courseRelTutor);
$course->addSubscription($courseRelTutor);
}
if (!empty($teachers)) {
@ -827,7 +827,7 @@ class AddCourse
->setRelationType(0)
->setUserCourseCat(0)
;
$course->addUsers($courseRelTeacher);
$course->addSubscription($courseRelTeacher);
}
}

@ -6550,7 +6550,7 @@ class CourseManager
->setSort($relationInfo['sort'])
->setUserCourseCat($relationInfo['user_course_cat']);
$course->addUsers($courseRelUser);
$course->addSubscription($courseRelUser);
$em = Database::getManager();
$em->persist($course);

@ -777,7 +777,7 @@ class BuyCoursesPlugin extends Plugin
'course_img' => null,
];
$courseTeachers = $course->getTeachers();
$courseTeachers = $course->getTeachersSubscriptions();
foreach ($courseTeachers as $teachers) {
$user = $teachers->getUser();

@ -55,7 +55,7 @@ if ($editingCourse) {
$courseItem = $plugin->getCourseForConfiguration($course, $currency);
$defaultBeneficiaries = [];
$teachers = $course->getTeachers();
$teachers = $course->getTeachersSubscriptions();
$teachersOptions = [];
foreach ($teachers as $courseTeacher) {

@ -79,7 +79,7 @@ try {
$students[] = $subscription->getUser();
}
} else {
$subscriptions = $course->getStudents();
$subscriptions = $course->getStudentSubscriptions();
/** @var CourseRelUser $subscription */
foreach ($subscriptions as $subscription) {

@ -435,7 +435,7 @@ class CourseController extends ToolBaseController
$courseValues = new ExtraFieldValue('course');
$urlCourse = api_get_path(WEB_PATH).sprintf('course/%s/about', $courseId);
$courseTeachers = $course->getTeachers();
$courseTeachers = $course->getTeachersSubscriptions();
$teachersData = [];
foreach ($courseTeachers as $teacherSubscription) {

@ -14,7 +14,6 @@ use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Serializer\Filter\PropertyFilter;
use Chamilo\CoreBundle\Entity\Listener\CourseListener;
use Chamilo\CoreBundle\Entity\Listener\ResourceListener;
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
@ -57,7 +56,6 @@ use function in_array;
#[ORM\Entity(repositoryClass: CourseRepository::class)]
#[ORM\EntityListeners([ResourceListener::class, CourseListener::class])]
#[ApiFilter(filterClass: SearchFilter::class, properties: ['title' => 'partial', 'code' => 'partial'])]
#[ApiFilter(filterClass: PropertyFilter::class)]
#[ApiFilter(filterClass: OrderFilter::class, properties: ['id', 'title'])]
class Course extends AbstractResource implements
ResourceInterface,
@ -121,12 +119,12 @@ class Course extends AbstractResource implements
/**
* @var Collection<int, CourseRelUser>
*
* "orphanRemoval" is needed to delete the CourseRelUser relation
* in the CourseAdmin class. The setUsers, getUsers, removeUsers and
* addUsers methods need to be added.
*/
#[Groups(['course:read', 'user:read'])]
#[Groups([
'course:read',
'user:read',
'course_rel_user:read',
])]
#[ORM\OneToMany(mappedBy: 'course', targetEntity: CourseRelUser::class, cascade: ['persist'], orphanRemoval: true)]
protected Collection $users;
@ -457,14 +455,14 @@ class Course extends AbstractResource implements
return $this;
}
public function hasUser(User $user): bool
public function hasSubscriptionByUser(User $user): bool
{
if (0 === $this->getUsers()->count()) {
if (0 === $this->users->count()) {
return false;
}
$criteria = Criteria::create()->where(Criteria::expr()->eq('user', $user));
return $this->getUsers()->matching($criteria)->count() > 0;
return $this->users->matching($criteria)->count() > 0;
}
/**
@ -475,29 +473,28 @@ class Course extends AbstractResource implements
return $this->users;
}
public function setUsers(Collection $users): self
public function addSubscription(CourseRelUser $courseRelUser): self
{
$this->users = new ArrayCollection();
foreach ($users as $user) {
$this->addUsers($user);
$courseRelUser->setCourse($this);
if (!$this->hasUsers($courseRelUser)) {
$this->users->add($courseRelUser);
}
return $this;
}
public function addUsers(CourseRelUser $courseRelUser): self
public function removeSubscription(CourseRelUser $user): void
{
$courseRelUser->setCourse($this);
if (!$this->hasSubscription($courseRelUser)) {
$this->users->add($courseRelUser);
foreach ($this->users as $key => $value) {
if ($value->getId() === $user->getId()) {
unset($this->users[$key]);
}
}
return $this;
}
public function hasSubscription(CourseRelUser $subscription): bool
public function hasUsers(CourseRelUser $subscription): bool
{
if (0 !== $this->getUsers()->count()) {
if (0 !== $this->users->count()) {
$criteria = Criteria::create()
->where(
Criteria::expr()->eq('user', $subscription->getUser())
@ -508,7 +505,7 @@ class Course extends AbstractResource implements
->andWhere(
Criteria::expr()->eq('relationType', $subscription->getRelationType())
);
$relation = $this->getUsers()->matching($criteria);
$relation = $this->users->matching($criteria);
return $relation->count() > 0;
}
@ -516,17 +513,26 @@ class Course extends AbstractResource implements
return false;
}
public function hasStudent(User $user): bool
public function addSubscriptionForUser(User $user, int $relationType, ?string $role, int $status): self
{
$courseRelUser = (new CourseRelUser())
->setCourse($this)
->setUser($user)
->setRelationType($relationType)
->setStatus($status);
$this->addSubscription($courseRelUser);
return $this;
}
public function hasUserAsStudent(User $user): bool
{
$criteria = Criteria::create()->where(Criteria::expr()->eq('user', $user));
return $this->getStudents()->matching($criteria)->count() > 0;
return $this->getStudentSubscriptions()->matching($criteria)->count() > 0;
}
/**
* @return Collection<int, CourseRelUser>
*/
public function getStudents(): Collection
public function getStudentSubscriptions(): Collection
{
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('status', CourseRelUser::STUDENT));
@ -534,18 +540,21 @@ class Course extends AbstractResource implements
return $this->users->matching($criteria);
}
public function hasTeacher(User $user): bool
public function addUserAsStudent(User $user): self
{
$this->addSubscriptionForUser($user, 0, '', CourseRelUser::STUDENT);
return $this;
}
public function hasUserAsTeacher(User $user): bool
{
$criteria = Criteria::create()->where(Criteria::expr()->eq('user', $user));
return $this->getTeachers()->matching($criteria)->count() > 0;
return $this->getTeachersSubscriptions()->matching($criteria)->count() > 0;
}
/**
* @return Collection<int, CourseRelUser>
*/
#[Groups(['course:read', 'user:read'])]
public function getTeachers(): Collection
public function getTeachersSubscriptions(): Collection
{
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('status', CourseRelUser::TEACHER));
@ -553,6 +562,13 @@ class Course extends AbstractResource implements
return $this->users->matching($criteria);
}
public function addUserAsTeacher(User $user): self
{
$this->addSubscriptionForUser($user, 0, 'Trainer', CourseRelUser::TEACHER);
return $this;
}
public function hasGroup(CGroup $group): void
{
/*$criteria = Criteria::create()->where(
@ -561,49 +577,11 @@ class Course extends AbstractResource implements
//return $this->getGroups()->contains($group);
}
/**
* Remove $user.
*/
public function removeUsers(CourseRelUser $user): void
{
foreach ($this->users as $key => $value) {
if ($value->getId() === $user->getId()) {
unset($this->users[$key]);
}
}
}
public function getId(): ?int
{
return $this->id;
}
public function addTeacher(User $user): self
{
$this->addUser($user, 0, 'Trainer', CourseRelUser::TEACHER);
return $this;
}
public function addUser(User $user, int $relationType, ?string $role, int $status): self
{
$courseRelUser = (new CourseRelUser())
->setCourse($this)
->setUser($user)
->setRelationType($relationType)
->setStatus($status);
$this->addUsers($courseRelUser);
return $this;
}
public function addStudent(User $user): self
{
$this->addUser($user, 0, '', CourseRelUser::STUDENT);
return $this;
}
/**
* Get directory, needed in migrations.
*/

@ -30,7 +30,7 @@ use Symfony\Component\Validator\Constraints as Assert;
new Post(security: "is_granted('ROLE_ADMIN')"),
],
normalizationContext: [
'groups' => ['course_rel_user:read', 'user:read'],
'groups' => ['course_rel_user:read'],
'enable_max_depth' => true,
],
security: "is_granted('ROLE_USER')"
@ -47,38 +47,6 @@ use Symfony\Component\Validator\Constraints as Assert;
'user.username' => 'partial',
]
)]
#[ApiResource(
uriTemplate: '/courses/{id}/users.{_format}',
operations: [
new GetCollection(),
],
uriVariables: [
'id' => new Link(
fromClass: Course::class,
identifiers: ['id']
),
],
status: 200,
normalizationContext: [
'groups' => ['course_rel_user:read', 'user:read'],
],
)]
#[ApiResource(
uriTemplate: '/users/{id}/courses.{_format}',
operations: [
new GetCollection(),
],
uriVariables: [
'id' => new Link(
fromClass: User::class,
identifiers: ['id']
),
],
status: 200,
normalizationContext: [
'groups' => ['course_rel_user:read', 'user:read'],
],
)]
class CourseRelUser implements Stringable
{
use UserTrait;
@ -93,13 +61,12 @@ class CourseRelUser implements Stringable
#[ORM\GeneratedValue]
protected ?int $id = null;
#[MaxDepth(1)]
#[Groups(['course:read', 'user:read', 'course_rel_user:read'])]
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'courses', cascade: ['persist'])]
#[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')]
protected User $user;
#[Groups(['user:read'])]
#[Groups(['course_rel_user:read'])]
#[ORM\ManyToOne(targetEntity: Course::class, inversedBy: 'users', cascade: ['persist'])]
#[ORM\JoinColumn(name: 'c_id', referencedColumnName: 'id')]
protected Course $course;
@ -108,7 +75,7 @@ class CourseRelUser implements Stringable
#[ORM\Column(name: 'relation_type', type: 'integer')]
protected int $relationType;
#[Groups(['user:read'])]
#[Groups(['course_rel_user:read'])]
#[ORM\Column(name: 'status', type: 'integer')]
protected int $status;

@ -137,6 +137,7 @@ class User implements
'user:read',
'user:write',
'course:read',
'course_rel_user:read',
'resource_node:read',
'user_json:read',
'message:read',
@ -701,7 +702,13 @@ class User implements
// Property used only during installation.
protected bool $skipResourceNode = false;
#[Groups(['user:read', 'user_json:read', 'social_post:read', 'course:read'])]
#[Groups([
'user:read',
'user_json:read',
'social_post:read',
'course:read',
'course_rel_user:read',
])]
protected string $fullName;
#[ORM\OneToMany(mappedBy: 'sender', targetEntity: SocialPost::class, orphanRemoval: true)]

@ -55,7 +55,7 @@ final class Version20201215142610 extends AbstractMigrationChamilo
foreach ($q->toIterable() as $course) {
$courseId = $course->getId();
$course = $courseRepo->find($courseId);
$courseRelUserList = $course->getTeachers();
$courseRelUserList = $course->getTeachersSubscriptions();
$courseAdmin = null;
if (!empty($courseRelUserList)) {
foreach ($courseRelUserList as $courseRelUser) {

@ -94,7 +94,7 @@ class CourseVoter extends Voter
if (Course::OPEN_PLATFORM === $course->getVisibility()) {
$user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_STUDENT);
if ($course->hasTeacher($user)) {
if ($course->hasUserAsTeacher($user)) {
$user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER);
}
@ -105,10 +105,10 @@ class CourseVoter extends Voter
// Course::REGISTERED
// User must be subscribed in the course no matter if is teacher/student
if ($course->hasUser($user)) {
if ($course->hasSubscriptionByUser($user)) {
$user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_STUDENT);
if ($course->hasTeacher($user)) {
if ($course->hasUserAsTeacher($user)) {
$user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER);
}
@ -121,7 +121,7 @@ class CourseVoter extends Voter
case self::EDIT:
case self::DELETE:
// Only teacher can edit/delete stuff.
if ($course->hasTeacher($user)) {
if ($course->hasUserAsTeacher($user)) {
$user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER);
$token->setUser($user);

@ -84,12 +84,12 @@ class GroupVoter extends Voter
}
if (Course::REGISTERED === $course->getVisibility()) {
if (!$course->hasUser($user)) {
if (!$course->hasSubscriptionByUser($user)) {
return false;
}
}
if ($course->hasTeacher($user)) {
if ($course->hasUserAsTeacher($user)) {
$user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_GROUP_TEACHER);
return true;

@ -61,7 +61,7 @@ class TrackEExerciseVoter extends Voter
return true;
}
} else {
if ($course->hasTeacher($user)) {
if ($course->hasUserAsTeacher($user)) {
return true;
}
}

@ -93,7 +93,7 @@ class CourseControllerTest extends WebTestCase
$test = $this->getUser('test');
$course = $this->getCourse($course->getId());
$course->addStudent($test);
$course->addUserAsStudent($test);
$em->persist($course);
$em->flush();
@ -197,7 +197,7 @@ class CourseControllerTest extends WebTestCase
// simulate $testUser being logged in
$client->loginUser($admin);
$course->addTeacher($teacher);
$course->addUserAsTeacher($teacher);
$em = $this->getEntityManager();
$types = CCourseDescription::getTypes();

@ -155,12 +155,12 @@ class CourseRepositoryTest extends AbstractApiTest
$courses = $courseRepo->getCoursesByUser($student, $this->getAccessUrl());
$this->assertCount(0, $courses);
$course->addUser($student, 0, '', CourseRelUser::STUDENT);
$course->addSubscriptionForUser($student, 0, '', CourseRelUser::STUDENT);
$courseRepo->update($course);
$this->assertTrue($course->hasUser($student));
$this->assertTrue($course->hasStudent($student));
$this->assertFalse($course->hasTeacher($student));
$this->assertTrue($course->hasSubscriptionByUser($student));
$this->assertTrue($course->hasUserAsStudent($student));
$this->assertFalse($course->hasUserAsTeacher($student));
$courses = $courseRepo->getCoursesByUser($student, $this->getAccessUrl());
$this->assertCount(1, $courses);
@ -177,7 +177,7 @@ class CourseRepositoryTest extends AbstractApiTest
$qb = $courseRepo->getSubscribedUsers($course);
$this->assertCount(0, $qb->getQuery()->getResult());
$course->addUser($student, 0, '', CourseRelUser::STUDENT);
$course->addSubscriptionForUser($student, 0, '', CourseRelUser::STUDENT);
$courseRepo->update($course);
$qb = $courseRepo->getSubscribedUsers($course);
@ -208,21 +208,21 @@ class CourseRepositoryTest extends AbstractApiTest
$student = $this->createUser('student', 'student');
// Add user to the course.
$course->addUser($student, 0, null, CourseRelUser::STUDENT);
$course->addSubscriptionForUser($student, 0, null, CourseRelUser::STUDENT);
$courseRepo->update($course);
$this->assertTrue($course->hasStudent($student));
$this->assertFalse($course->hasTeacher($student));
$this->assertTrue($course->hasUserAsStudent($student));
$this->assertFalse($course->hasUserAsTeacher($student));
$this->assertSame(1, $course->getUsers()->count());
// Add the same user again:
$course->addUser($student, 0, null, CourseRelUser::STUDENT);
$course->addSubscriptionForUser($student, 0, null, CourseRelUser::STUDENT);
$courseRepo->update($course);
$this->assertSame(1, $course->getUsers()->count());
$this->assertSame(1, $course->getStudents()->count());
$this->assertSame(0, $course->getTeachers()->count());
$this->assertSame(1, $course->getStudentSubscriptions()->count());
$this->assertSame(0, $course->getTeachersSubscriptions()->count());
$client->request('GET', sprintf('/course/%s/home', $course->getId()));
$this->assertResponseIsSuccessful();
@ -243,26 +243,26 @@ class CourseRepositoryTest extends AbstractApiTest
// Add user to the course.
// Add the same user again:
$course->addUser($teacher, 0, null, CourseRelUser::TEACHER);
$course->addSubscriptionForUser($teacher, 0, null, CourseRelUser::TEACHER);
$courseRepo->update($course);
$this->assertFalse($course->hasStudent($teacher));
$this->assertTrue($course->hasTeacher($teacher));
$this->assertFalse($course->hasUserAsStudent($teacher));
$this->assertTrue($course->hasUserAsTeacher($teacher));
$course->addTeacher($teacher2);
$course->addUserAsTeacher($teacher2);
$courseRepo->update($course);
$this->assertFalse($course->hasStudent($teacher2));
$this->assertTrue($course->hasTeacher($teacher2));
$this->assertFalse($course->hasUserAsStudent($teacher2));
$this->assertTrue($course->hasUserAsTeacher($teacher2));
$this->assertSame(2, $course->getUsers()->count());
$this->assertSame(0, $course->getStudents()->count());
$this->assertSame(2, $course->getTeachers()->count());
$this->assertSame(0, $course->getStudentSubscriptions()->count());
$this->assertSame(2, $course->getTeachersSubscriptions()->count());
// Test adding again.
$course->addUser($teacher, 0, null, CourseRelUser::TEACHER);
$course->addSubscriptionForUser($teacher, 0, null, CourseRelUser::TEACHER);
$courseRepo->update($course);
$this->assertSame(2, $course->getTeachers()->count());
$this->assertSame(2, $course->getTeachersSubscriptions()->count());
$teacher = $this->getUser('teacher');
@ -285,7 +285,7 @@ class CourseRepositoryTest extends AbstractApiTest
$student = $this->createUser('student', 'student');
// Add user to the course.
$course->addUser($student, 0, null, 5);
$course->addSubscriptionForUser($student, 0, null, 5);
$courseRepo->update($course);
$this->assertSame(1, $course->getUsers()->count());

@ -43,8 +43,8 @@ class CourseVoterTest extends WebTestCase
// Public course.
$publicCourse = $this->createCourse('public');
$publicCourse->addUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$publicCourse->addUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$publicCourse->addSubscriptionForUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$publicCourse->addSubscriptionForUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$em->persist($publicCourse);
$em->flush();
@ -60,8 +60,8 @@ class CourseVoterTest extends WebTestCase
// REGISTERED course.
$registeredCourse = $this->createCourse('registered');
$registeredCourse->setVisibility(Course::REGISTERED);
$registeredCourse->addUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$registeredCourse->addUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$registeredCourse->addSubscriptionForUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$registeredCourse->addSubscriptionForUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$em->persist($registeredCourse);
$em->flush();

@ -48,8 +48,8 @@ class GroupVoterTest extends WebTestCase
// Group in public course.
$publicCourse = $this->createCourse('public');
$publicCourse->addUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$publicCourse->addUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$publicCourse->addSubscriptionForUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$publicCourse->addSubscriptionForUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$em->persist($publicCourse);
$group = (new CGroup())
@ -81,10 +81,10 @@ class GroupVoterTest extends WebTestCase
// REGISTERED course.
$registeredCourse = $this->createCourse('registered');
$registeredCourse->setVisibility(Course::REGISTERED);
$registeredCourse->addUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$registeredCourse->addUser($studentInGroup2IsTutor, 0, null, CourseRelUser::STUDENT);
$registeredCourse->addUser($studentInGroup2IsMember, 0, null, CourseRelUser::STUDENT);
$registeredCourse->addUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$registeredCourse->addSubscriptionForUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$registeredCourse->addSubscriptionForUser($studentInGroup2IsTutor, 0, null, CourseRelUser::STUDENT);
$registeredCourse->addSubscriptionForUser($studentInGroup2IsMember, 0, null, CourseRelUser::STUDENT);
$registeredCourse->addSubscriptionForUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$em->persist($registeredCourse);
$em->flush();

@ -44,8 +44,8 @@ class SessionVoterTest extends WebTestCase
$session = $this->createSession('session');
$publicCourse = $this->createCourse('public');
$publicCourse->addUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$publicCourse->addUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$publicCourse->addSubscriptionForUser($studentWithAccess, 0, null, CourseRelUser::STUDENT);
$publicCourse->addSubscriptionForUser($teacherWithAccess, 0, null, CourseRelUser::TEACHER);
$em->persist($publicCourse);
$session->addCourse($publicCourse);

Loading…
Cancel
Save