Passed
Push — master ( 2f54b4...577984 )
by
unknown
18:30 queued 09:41
created

PageHelper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 4
dl 0
loc 10
rs 10
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Helpers;
8
9
use Chamilo\CoreBundle\Entity\AccessUrl;
10
use Chamilo\CoreBundle\Entity\Page;
11
use Chamilo\CoreBundle\Entity\PageCategory;
12
use Chamilo\CoreBundle\Entity\User;
13
use Chamilo\CoreBundle\Repository\PageCategoryRepository;
14
use Chamilo\CoreBundle\Repository\PageRepository;
15
use Chamilo\CoreBundle\Repository\SysAnnouncementRepository;
16
use Symfony\Component\Security\Core\User\UserInterface;
17
18
class PageHelper
19
{
20
    protected PageRepository $pageRepository;
21
    protected PageCategoryRepository $pageCategoryRepository;
22
23
    /**
24
     * Repository used to read system announcements (platform news).
25
     */
26
    protected SysAnnouncementRepository $sysAnnouncementRepository;
27
28
    /**
29
     * Helper used to retrieve the current AccessUrl.
30
     */
31
    protected AccessUrlHelper $accessUrlHelper;
32
33
    public function __construct(
34
        PageRepository $pageRepository,
35
        PageCategoryRepository $pageCategoryRepository,
36
        SysAnnouncementRepository $sysAnnouncementRepository,
37
        AccessUrlHelper $accessUrlHelper
38
    ) {
39
        $this->pageRepository = $pageRepository;
40
        $this->pageCategoryRepository = $pageCategoryRepository;
41
        $this->sysAnnouncementRepository = $sysAnnouncementRepository;
42
        $this->accessUrlHelper = $accessUrlHelper;
43
    }
44
45
    public function createDefaultPages(User $user, AccessUrl $url, string $locale): bool
46
    {
47
        $categories = $this->pageCategoryRepository->findAll();
48
49
        if (!empty($categories)) {
50
            return false;
51
        }
52
53
        $category = (new PageCategory())
54
            ->setTitle('home')
55
            ->setType('grid')
56
            ->setCreator($user)
57
        ;
58
        $this->pageCategoryRepository->update($category);
59
60
        $indexCategory = (new PageCategory())
61
            ->setTitle('index')
62
            ->setType('grid')
63
            ->setCreator($user)
64
        ;
65
        $this->pageCategoryRepository->update($indexCategory);
66
67
        $indexCategory = (new PageCategory())
68
            ->setTitle('faq')
69
            ->setType('grid')
70
            ->setCreator($user)
71
        ;
72
        $this->pageCategoryRepository->update($indexCategory);
73
74
        $indexCategory = (new PageCategory())
75
            ->setTitle('demo')
76
            ->setType('grid')
77
            ->setCreator($user)
78
        ;
79
        $this->pageCategoryRepository->update($indexCategory);
80
81
        $page = (new Page())
82
            ->setTitle('Welcome')
83
            ->setContent('Welcome to Chamilo')
84
            ->setCategory($category)
85
            ->setCreator($user)
86
            ->setLocale($locale)
87
            ->setEnabled(true)
88
            ->setUrl($url)
89
        ;
90
91
        $this->pageRepository->update($page);
92
93
        $indexPage = (new Page())
94
            ->setTitle('Welcome')
95
            ->setContent('<img src="/img/document/images/mr_chamilo/svg/teaching.svg" />')
96
            ->setCategory($indexCategory)
97
            ->setCreator($user)
98
            ->setLocale($locale)
99
            ->setEnabled(true)
100
            ->setUrl($url)
101
        ;
102
        $this->pageRepository->update($indexPage);
103
104
        $footerPublicCategory = (new PageCategory())
105
            ->setTitle('footer_public')
106
            ->setType('grid')
107
            ->setCreator($user)
108
        ;
109
110
        $this->pageCategoryRepository->update($footerPublicCategory);
111
112
        $footerPrivateCategory = (new PageCategory())
113
            ->setTitle('footer_private')
114
            ->setType('grid')
115
            ->setCreator($user)
116
        ;
117
118
        $this->pageCategoryRepository->update($footerPrivateCategory);
119
120
        // Categories for extra content in admin blocks.
121
        foreach (self::getCategoriesForAdminBlocks() as $nameBlock) {
122
            $usersAdminBlock = (new PageCategory())
123
                ->setTitle($nameBlock)
124
                ->setType('grid')
125
                ->setCreator($user)
126
            ;
127
            $this->pageCategoryRepository->update($usersAdminBlock);
128
        }
129
130
        $publicCategory = (new PageCategory())
131
            ->setTitle('public')
132
            ->setType('grid')
133
            ->setCreator($user)
134
        ;
135
136
        $this->pageCategoryRepository->update($publicCategory);
137
138
        $introductionCategory = (new PageCategory())
139
            ->setTitle('introduction')
140
            ->setType('grid')
141
            ->setCreator($user)
142
        ;
143
        $this->pageCategoryRepository->update($introductionCategory);
144
145
        return true;
146
    }
147
148
    public static function getCategoriesForAdminBlocks(): array
149
    {
150
        return [
151
            'block-admin-users',
152
            'block-admin-courses',
153
            'block-admin-sessions',
154
            'block-admin-gradebook',
155
            'block-admin-skills',
156
            'block-admin-privacy',
157
            'block-admin-settings',
158
            'block-admin-platform',
159
            'block-admin-chamilo',
160
        ];
161
    }
162
163
    /**
164
     * Checks if a document file URL is effectively exposed through a visible system announcement.
165
     *
166
     * This centralizes the logic used by different parts of the platform (e.g. voters, controllers)
167
     * to decide if a file coming from personal files can be considered "public" because it is
168
     * embedded inside a system announcement that is visible to the current user.
169
     *
170
     * @param string               $pathInfo   Full request path (e.g. /r/document/files/{uuid}/view)
171
     * @param string|null          $identifier File identifier extracted from the URL (usually a UUID)
172
     * @param UserInterface|null   $user       Current user, or null to behave as anonymous
173
     * @param string               $locale     Current locale used to fetch announcements
174
     */
175
    public function isFilePathExposedByVisibleAnnouncement(
176
        string $pathInfo,
177
        ?string $identifier,
178
        ?UserInterface $user,
179
        string $locale
180
    ): bool {
181
        // Only relax security for the document file viewer route.
182
        if ('' === $pathInfo || !str_contains($pathInfo, '/r/document/files/')) {
183
            return false;
184
        }
185
186
        // Normalize user: if no authenticated user is provided, behave as anonymous.
187
        if (null === $user) {
188
            $anon = new User();
189
            $anon->setRoles(['ROLE_ANONYMOUS']);
190
            $user = $anon;
191
        }
192
193
        $accessUrl = $this->accessUrlHelper->getCurrent();
194
195
        // Fetch announcements that are visible for the given user, URL and locale.
196
        $announcements = $this->sysAnnouncementRepository->getAnnouncements(
197
            $user,
198
            $accessUrl,
199
            $locale
200
        );
201
202
        foreach ($announcements as $item) {
203
            $content = '';
204
205
            if (\is_array($item)) {
206
                $content = (string) ($item['content'] ?? '');
207
            } elseif (\is_object($item) && method_exists($item, 'getContent')) {
208
                $content = (string) $item->getContent();
209
            }
210
211
            if ('' === $content) {
212
                continue;
213
            }
214
215
            // Check if the announcement HTML contains the viewer path or the identifier.
216
            if (
217
                str_contains($content, $pathInfo)
218
                || ($identifier && str_contains($content, $identifier))
219
            ) {
220
                return true;
221
            }
222
        }
223
224
        return false;
225
    }
226
}
227