#5895·kanboard

[Feature]: `createTaskFile`/`createProjectFile` cannot set the uploader: Add optional `creator_id`

Author: TheRealCuranCreated Sep 4, 2026Updated Sep 4, 2026

Feature Summary

Add an optional creator_id parameter to createTaskFile and createProjectFile, validated the same way createTask already validates owner_id/creator_id.

What problem does this feature solve?

FileModel::create() always sets user_id from $this->userSession->getId() ?: 0. Via the Application API (global token) there's no session, so uploaded files get user_id = 0 and show no "Uploaded by" attribution in the UI — unlike files uploaded through the web UI. There's no parameter anywhere in createTaskFileuploadContent → create to override this.

Originally reported in #2645 (2016), closed with no resolution. Still true in 1.2.54.

Use case

We have a bridge service running, that imports (creates/updates) cards from another system. It would be nice being able to mark attachments as belonging to an user – just like we already do for the tasks themselves.

Proposed Solution

Precedent

createTask solves the identical problem for owner_id/creator_id:

php
if ($owner_id !== 0 && ! $this->projectPermissionModel->isAssignable($project_id, $owner_id)) {
    return false;
}

and

php
if ($creator_id !== 0 && ! $this->projectPermissionModel->isAssignable($project_id, $creator_id)) {
    return false;
}

Both validated against project membership via isAssignable(), no session special-casing. Introduced by commit f8c9ebd672efe19aa407793bb5b12965564df31f, "fix(api): allow and validate creator ID assignment in task creation" (direct commit to app/Api/Procedure/TaskProcedure.php, no associated PR found).

Proposed patches

Attached: a 6-commit series against kanboard/kanboard plus 1 commit against kanboard/documentation. Applied via git am to a fresh v1.2.54 clone and verified against a live instance (Apache + mod_php + sqlite, matching .github/workflows/integration_tests.yml):

  1. FileModel::create(): optional $creator_id param, falls back to current behavior when 0.
  2. FileModel::uploadContent(): pass the parameter through.
  3. TaskFileProcedure::createTaskFile(): accepts creator_id, validated via projectPermissionModel->isAssignable(), identical to createTask. An invalid ID is logged server-side and thrown to the client as JsonRPC\Exception\ResponseException (code 422, with creator_id/project_id in getData()) rather than a bare false. The error code was chosen deliberately over the JSON-RPC-reserved -32602, since the reference client's ResponseParser special-cases -32602 into a generic InvalidArgumentException and silently drops the data field.
  4. ProjectFileProcedure::createProjectFile(): dito (parity)
  5. Unit tests covering explicit creator_id on FileModel::create()/uploadContent().
  6. Integration tests covering both the accepted and rejected creator_id cases via the live API, following the existing assignability-test style in SubtaskProcedureTest.php.
  7. (docs repo) Document the new parameter.

The error response was made more descriptive on purpose. Today an API client has basically no way to tell error classes/reasons apart, since false is the only real error signal. With the added code here, I didn't want to continue that pattern and actually tell the API client, where things fell apart. If you prefer a plain false, please let me know and I can change that.

If you want PRs over the patches attached here, let me know and I'll open them.

Note: Anthropic's Sonnet 5 model was used to formulate the patches, since I didn't have time to dig through the Kanboard code base in detail. If you want a "pure human" implementation, I'd out here an can just provide the ticket itself then. I don't have real time available for this relatively minor issue.

Alternatives Considered

There are no alternatives, if you want to have the attribution for files. At least none that I can see.

Additional Context

No response

Checklist

  • I have searched existing issues to ensure this feature hasn't been requested before.
  • I understand that feature requests are not guaranteed to be implemented.