Fix: orphaned documents/folders when SPA loses ?cid= in URL — non-admin teachers can't upload#8662
Closed
addow wants to merge 1 commit into
Closed
Fix: orphaned documents/folders when SPA loses ?cid= in URL — non-admin teachers can't upload#8662addow wants to merge 1 commit into
addow wants to merge 1 commit into
Conversation
The shared axios request interceptor in assets/vue/config/api.js reads
getRawCourseContext() from window.location.search and injects cid/sid/gid
into config.params. When the SPA navigates inside a course without
preserving ?cid=… in the URL, that read returns nulls, no params are
injected, and the POST goes out as plain /api/documents (no query).
On the server side, CidReqListener sees an empty $request->get('cid'),
treats the request as out-of-course, and calls cleanSessionHandler()
which removes session.course. CreateDocumentFileAction then runs
buildResourceLinkListFromContext() which finds no course in session and
no cid in the query, so the resource_link entry is built without cid.
The new document is created but is orphaned — no resource_link binding it
to the course — so it disappears from the documents list immediately
after creation. The security check still passes because admins inherit
ROLE_CURRENT_COURSE_TEACHER via Symfony's role_hierarchy (security.yaml),
masking the bug for everyone with ROLE_ADMIN.
Affected: every /api/documents POST that goes through the legacy
makeService("documents").createWithFormData path — i.e. folder creation
and any flow using store.dispatch("documents/createWithFormData", …).
The chunked uploader at DocumentsUpload.vue:609 was already constructing
its own URL with explicit cid/sid/gid and is unaffected.
Surgical fix in services/documents.js:
- Override createWithFormData to construct its own POST request.
- Read cid/sid/gid from the Pinia cidReq store first (authoritative,
maintained by router guards, survives URL changes) and fall back to
getCourseContext() (URL-based) only when the store is not yet active
(early bootstrap / tests).
- Append them as query parameters on /api/documents.
Confirmed: the same code path exists on v2.0.2 and on chamilo/chamilo-lms
upstream master, so this is a community-wide bug. Forwarding it upstream
as a separate PR is on the to-do.
4bcfffd to
4975d85
Compare
Member
|
Thanks for the detailed analysis — the root-cause chain is accurate. However, this is now superseded: course-tool routes require cid at the router level (requiresCourseContext guard in assets/vue/router/index.js), so the documents tool can no longer be reached with a cid-less URL and the axios interceptor always finds the context. The scenario this patches is unreachable. Also, reading the Pinia store in a single service would fork the context-resolution pattern (everything else goes through the shared interceptor), which we'd rather avoid. Two follow-ups worth pursuing instead, if you're up for it:
Closing in favour of the above. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Folders and documents created via the SPA can end up orphaned — created in the database but invisible in the course documents list — when the URL is missing
?cid=…. This happens because:assets/vue/config/api.jsreadsgetRawCourseContext()fromwindow.location.searchand injectscid/sid/gidintoconfig.params. When the SPA navigates inside a course without preserving?cid=…in the URL (e.g. after entering a sub-folder), that read returnsnulls, no params are injected, and the POST goes out as plain/api/documentswith no query.CidReqListenersees an emptycidand callscleanSessionHandler(), wipingsession.course.CreateDocumentFileActionthen runsbuildResourceLinkListFromContext()which finds no course in session and nocidin the query, so theresource_linkis built withoutcid.resource_linkbinding it to the course, so it disappears from the documents list right after creation.The security check still passes because admins inherit
ROLE_CURRENT_COURSE_TEACHERvia Symfony'srole_hierarchy(config/packages/security.yaml), which masks the bug for everyone withROLE_ADMIN. Teachers without admin role hit it.Affected: every
/api/documentsPOST going throughmakeService("documents").createWithFormData— i.e. folder creation and any flow usingstore.dispatch("documents/createWithFormData", …). The chunked uploader atDocumentsUpload.vue:609was already constructing its own URL with explicitcid/sid/gidand is unaffected.Fix
Surgical override in
assets/vue/services/documents.js:createWithFormDatato construct its own POST request.cid/sid/gidfrom the PiniacidReqstore first (authoritative — maintained by router guards, survives URL changes) and fall back togetCourseContext()(URL-based) only when the store is not yet active (early bootstrap / tests)./api/documents.No backend changes; no impact on other modules.
Test plan
?cid=in URL after a few clicks)resource_linkrow has the expectedcourse_idpopulatedROLE_CURRENT_COURSE_TEACHERinheritance)