diff --git a/app/finders/banzai/uploads_finder.rb b/app/finders/banzai/uploads_finder.rb index e05e426e27e9ef471d8caaa3244e06b840a48f4f..28dc83b907c337f8405f6d720d3bf3ec4cf3f5ef 100644 --- a/app/finders/banzai/uploads_finder.rb +++ b/app/finders/banzai/uploads_finder.rb @@ -2,6 +2,8 @@ module Banzai class UploadsFinder + include FinderMethods + def initialize(parent:) @parent = parent end diff --git a/app/models/upload.rb b/app/models/upload.rb index bad9fb660af983f788449ef4da4a6dbd47fb7c56..1ebcac75baaeba1a0985a9049007a747748369e7 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -20,6 +20,7 @@ class Upload < ApplicationRecord scope :for_model_type_and_id, ->(type, id) { where(model_type: type, model_id: id) } scope :for_uploader, ->(uploader_class) { where(uploader: uploader_class.to_s) } scope :order_by_created_at_desc, -> { reorder(created_at: :desc) } + scope :preload_uploaded_by_user, -> { preload(:uploaded_by_user) } before_save :calculate_checksum!, if: :foreground_checksummable? # as the FileUploader is not mounted, the default CarrierWave ActiveRecord @@ -98,7 +99,7 @@ def build_uploader(mounted_as = nil) # @return [GitlabUploader] one of the subclasses, defined at the model's uploader attribute def retrieve_uploader(mounted_as = nil) build_uploader(mounted_as).tap do |uploader| - uploader.retrieve_from_store!(identifier) + uploader.retrieve_from_store!(filename) end end @@ -124,7 +125,7 @@ def exist? def uploader_context { - identifier: identifier, + identifier: filename, secret: secret, uploaded_by_user_id: uploaded_by_user_id }.compact @@ -144,6 +145,10 @@ def needs_checksum? checksum.nil? && local? && exist? end + def filename + File.basename(path) + end + private def delete_file! @@ -166,10 +171,6 @@ def uploader_class Object.const_get(uploader, false) end - def identifier - File.basename(path) - end - def mount_point super&.to_sym end diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index a9ad133c0234bebce5a51c1c81765998d2db1be5..249c52bf330b9d326630c451e8fcb6798013020e 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -256,6 +256,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy enable :create_jira_connect_subscription enable :maintainer_access enable :read_upload + enable :admin_upload enable :destroy_upload enable :admin_push_rules end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 09312d4e883f95c99bdfae8d7432e3d1f9901cbb..c8659478d4b438843ae428c24de6bf75dd898fcd 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -613,6 +613,7 @@ class ProjectPolicy < BasePolicy enable :admin_project_aws enable :admin_secure_files enable :read_upload + enable :admin_upload enable :destroy_upload enable :admin_incident_management_timeline_event_tag enable :stop_environment diff --git a/doc/api/groups.md b/doc/api/groups.md index 170e2f41d91f806a83e003c4b8b14e54623e39e3..6d47b06dc1c95ff1c571a7f55c4559c90cc827b4 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -1701,6 +1701,99 @@ Example response: } ``` +## Markdown uploads + +Markdown uploads are files uploaded to a group that can be referenced in Markdown text in an epic or wiki page. + +### List uploads + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157066) in GitLab 17.2. + +Get all uploads of the group sorted by `created_at` in descending order. + +You must have at least the Maintainer role to use this endpoint. + +```plaintext +GET /groups/:id/uploads +``` + +| Attribute | Type | Required | Description | +|-----------|-------------------|----------|-------------| +| `id` | integer or string | Yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). | + +Example request: + +```shell +curl --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/groups/5/uploads" +``` + +Returned object: + +```json +[ + { + "id": 1, + "size": 1024, + "filename": "image.png", + "created_at":"2024-06-20T15:53:03.067Z", + "uploaded_by": { + "id": 18, + "name" : "Alexandra Bashirian", + "username" : "eileen.lowe" + } + }, + { + "id": 2, + "size": 512, + "filename": "other-image.png", + "created_at":"2024-06-19T15:53:03.067Z", + "uploaded_by": null + } +] +``` + +### Download an uploaded file + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157066) in GitLab 17.2. + +You must have at least the Maintainer role to use this endpoint. + +```plaintext +GET /groups/:id/uploads/:upload_id +``` + +| Attribute | Type | Required | Description | +|-------------|-------------------|----------|-------------| +| `id` | integer or string | Yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). | +| `upload_id` | integer | Yes | The ID of the upload. | + +Example request: + +```shell +curl --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/groups/5/uploads/1" +``` + +### Delete an uploaded file + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157066) in GitLab 17.2. + +You must have at least the Maintainer role to use this endpoint. + +```plaintext +DELETE /groups/:id/uploads/:upload_id +``` + +| Attribute | Type | Required | Description | +|-------------|-------------------|----------|-------------| +| `id` | integer or string | Yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). | +| `upload_id` | integer | Yes | The ID of the upload. | + +Example request: + +```shell +curl --request DELETE --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/groups/5/uploads/1" +``` + ## Hooks DETAILS: @@ -2433,11 +2526,11 @@ DELETE /groups/:id/push_rule > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371117) in GitLab 17.2 [with a flag](../administration/feature_flags.md) named `group_agnostic_token_revocation`. Disabled by default. FLAG: -The availability of this feature is controlled by a feature flag. +The availability of this feature is controlled by a feature flag. For more information, see the history. Revoke a token, if it has access to the group or any of its subgroups -and projects. If the token is revoked, or was already revoked, its +and projects. If the token is revoked, or was already revoked, its details are returned in the response. The following criteria must be met: diff --git a/doc/api/projects.md b/doc/api/projects.md index 7de24c1817191f468e0d44c4b959a98a2c911f73..e3cc29d84fe7d9b0eec48f67ca03d7d26207765a 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -2599,7 +2599,11 @@ POST /projects/:id/restore |-----------|-------------------|----------|-------------| | `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). | -## Upload a file +## Markdown uploads + +Markdown uploads are files uploaded to a project that can be referenced in Markdown text in an issue, merge request, snippet, or wiki page. + +### Upload a file > - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112450) in GitLab 15.10. Feature flag `enforce_max_attachment_size_upload_api` removed. @@ -2640,6 +2644,95 @@ The returned `url` is relative to the project path. The returned `full_path` is the absolute path to the file. In Markdown contexts, the link is expanded when the format in `markdown` is used. +### List uploads + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157066) in GitLab 17.2. + +Get all uploads of the project sorted by `created_at` in descending order. + +You must have at least the Maintainer role to use this endpoint. + +```plaintext +GET /projects/:id/uploads +``` + +| Attribute | Type | Required | Description | +|-----------|-------------------|----------|-------------| +| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). | + +Example request: + +```shell +curl --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects/5/uploads" +``` + +Returned object: + +```json +[ + { + "id": 1, + "size": 1024, + "filename": "image.png", + "created_at":"2024-06-20T15:53:03.067Z", + "uploaded_by": { + "id": 18, + "name" : "Alexandra Bashirian", + "username" : "eileen.lowe" + } + }, + { + "id": 2, + "size": 512, + "filename": "other-image.png", + "created_at":"2024-06-19T15:53:03.067Z", + "uploaded_by": null + } +] +``` + +### Download an uploaded file + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157066) in GitLab 17.2. + +You must have at least the Maintainer role to use this endpoint. + +```plaintext +GET /projects/:id/uploads/:upload_id +``` + +| Attribute | Type | Required | Description | +|-------------|-------------------|----------|-------------| +| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). | +| `upload_id` | integer | Yes | The ID of the upload. | + +Example request: + +```shell +curl --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects/5/uploads/1" +``` + +### Delete an uploaded file + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157066) in GitLab 17.2. + +You must have at least the Maintainer role to use this endpoint. + +```plaintext +DELETE /projects/:id/uploads/:upload_id +``` + +| Attribute | Type | Required | Description | +|-------------|-------------------|----------|-------------| +| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). | +| `upload_id` | integer | Yes | The ID of the upload. | + +Example request: + +```shell +curl --request DELETE --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects/5/uploads/1" +``` + ## Upload a project avatar Uploads an avatar to the specified project. diff --git a/doc/security/user_file_uploads.md b/doc/security/user_file_uploads.md index b2d6bc18fc04432d0bdda5529c4fb1cc5a80a207..b70378e0acfb56773ca279e27f39bb366e206d87 100644 --- a/doc/security/user_file_uploads.md +++ b/doc/security/user_file_uploads.md @@ -65,6 +65,7 @@ You cannot select this option for public projects. ## Delete uploaded files > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92791) in GitLab 15.3. +> - REST API [added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157066) support in GitLab 17.2. You should delete an uploaded file when that file contains sensitive or confidential information. When you have deleted that file, users cannot access the file and the direct URL returns a 404 error. @@ -87,6 +88,8 @@ mutation{ Project members that do not have the Owner or Maintainer role cannot access this GraphQL endpoint. +You can also use the REST API for [projects](../api/projects.md#delete-an-uploaded-file) or [groups](../api/groups.md#delete-an-uploaded-file) to delete an uploaded file. +