diff --git a/docs/api/apiv3/components/schemas/meeting_model.yml b/docs/api/apiv3/components/schemas/meeting_model.yml new file mode 100644 index 000000000000..a35a8bb67b50 --- /dev/null +++ b/docs/api/apiv3/components/schemas/meeting_model.yml @@ -0,0 +1,88 @@ +# Schema: Meeting_PageModel +--- +type: object +required: + - title +properties: + id: + type: integer + description: Identifier of this meeting + readOnly: true + exclusiveMinimum: 0 + title: + type: string + description: The meeting's title + _links: + type: object + properties: + self: + allOf: + - "$ref": "./link.yml" + - description: |- + This meeting + + **Resource**: Meeting + readOnly: true + author: + allOf: + - "$ref": "./link.yml" + - description: |- + The user having created the meeting + + **Resource**: User + readOnly: true + project: + allOf: + - "$ref": "./link.yml" + - description: |- + The project the meeting is in + + **Resource**: Project + attachments: + allOf: + - $ref: './link.yml' + - description: |- + The attachment collection of this grid. + + **Resource**: AttachmentCollection + addAttachment: + allOf: + - "$ref": "./link.yml" + - description: |- + Attach a file to the meeting + + # Conditions + + **Permission**: edit meeting + readOnly: true +example: + _type: Meeting + id: 72 + lockVersion: 5 + title: A meeting + startTime: '2014-05-21T08:00:00.000Z' + endTime: '2014-05-21T10:00:00.000Z' + duration: 120 + createdAt: '2014-05-21T08:51:20.396Z' + updatedAt: '2014-05-21T09:14:02.776Z' + _embedded: + project: + _type: Project... + id: 12 + author: + _type: User... + id: 2 + _links: + addAttachment: + href: "/api/v3/meetings/72/attachments" + method: post + attachments: + href: "/api/v3/meetings/72/attachments" + project: + href: "/api/v3/projects/12" + title: some project + author: + href: "/api/v3/users/2" + title: Peggie Feeney + self: + href: "/api/v3/meetings/72" diff --git a/docs/api/apiv3/openapi-spec.yml b/docs/api/apiv3/openapi-spec.yml index 30ae39bbb872..07540f8dd35a 100644 --- a/docs/api/apiv3/openapi-spec.yml +++ b/docs/api/apiv3/openapi-spec.yml @@ -220,6 +220,10 @@ paths: "$ref": "./paths/help_texts.yml" "/api/v3/help_texts/{id}": "$ref": "./paths/help_text.yml" + "/api/v3/meetings": + "$ref": "./paths/meeting.yml" + "/api/v3/meetings/{id}/attachments": + "$ref": "./paths/meeting_attachments.yml" "/api/v3/memberships": "$ref": "./paths/memberships.yml" "/api/v3/memberships/available_projects": @@ -649,6 +653,8 @@ components: "$ref": "./components/schemas/list_of_news_model.yml" List_projects_by_versionModel: "$ref": "./components/schemas/list_projects_by_version_model.yml" + MeetingModel: + "$ref": "./components/schemas/meeting_model.yml" MarkdownModel: "$ref": "./components/schemas/markdown_model.yml" MembershipCollectionModel: diff --git a/docs/api/apiv3/paths/meeting.yml b/docs/api/apiv3/paths/meeting.yml new file mode 100644 index 000000000000..fc052659abcd --- /dev/null +++ b/docs/api/apiv3/paths/meeting.yml @@ -0,0 +1,72 @@ +# /api/v3/meetings/{id} +--- +get: + parameters: + - description: Meeting identifier + example: '1' + in: path + name: id + required: true + schema: + type: integer + responses: + '200': + content: + application/hal+json: + examples: + response: + value: + _embedded: + project: + _type: Project... + id: 12 + author: + _type: User... + id: 2 + _links: + addAttachment: + href: "/api/v3/meetings/72/attachments" + method: post + attachments: + href: "/api/v3/meetings/72/attachments" + project: + href: "/api/v3/projects/12" + title: some project + author: + href: "/api/v3/users/2" + title: Peggie Feeney + self: + href: "/api/v3/meetings/72" + _type: Meeting + id: 72 + lockVersion: 5 + title: A meeting + startTime: '2014-05-21T08:00:00.000Z' + duration: 120 + createdAt: '2014-05-21T08:51:20.396Z' + updatedAt: '2014-05-21T09:14:02.776Z' + schema: + "$ref": "../components/schemas/meeting_model.yml" + description: OK + headers: { } + '404': + content: + application/hal+json: + schema: + $ref: "../components/schemas/error_response.yml" + examples: + response: + value: + _type: Error + errorIdentifier: urn:openproject-org:api:v3:errors:NotFound + message: The requested resource could not be found. + description: |- + Returned if the meeting does not exist or the client does not have sufficient permissions to see it. + + **Required permission:** view meetings in the page's project + headers: { } + tags: + - Meetings + description: Retrieve an individual meeting as identified by the id parameter + operationId: View_Meeting + summary: View Meeting Page diff --git a/docs/api/apiv3/paths/meeting_attachments.yml b/docs/api/apiv3/paths/meeting_attachments.yml new file mode 100644 index 000000000000..592b6272d9cd --- /dev/null +++ b/docs/api/apiv3/paths/meeting_attachments.yml @@ -0,0 +1,260 @@ +# /api/v3/meetings/{id}/attachments +--- +get: + parameters: + - description: ID of the meeting whose attachments will be listed + example: '1' + in: path + name: id + required: true + schema: + type: integer + responses: + '200': + content: + application/hal+json: + examples: + response: + value: + _embedded: + elements: + - _links: + author: + href: "/api/v3/users/1" + title: OpenProject Admin + container: + href: "/api/v3/meetings/72" + title: meeting + delete: + href: "/api/v3/attachments/376" + method: delete + downloadLocation: + href: "/api/v3/attachments/376/content" + self: + href: "/api/v3/attachments/376" + title: 200.gif + _type: Attachment + contentType: image/gif + createdAt: '2018-06-01T07:24:19.896Z' + description: + format: plain + html: '' + raw: '' + digest: + algorithm: md5 + hash: 7ac9c97ef73d47127f590788b84c0c1c + fileName: some.gif + fileSize: 3521772 + id: 376 + _links: + self: + href: "/api/v3/meetings/72/attachments" + _type: Collection + count: 1 + total: 1 + schema: + "$ref": "../components/schemas/attachments_model.yml" + description: OK + headers: {} + '404': + content: + application/hal+json: + schema: + $ref: "../components/schemas/error_response.yml" + examples: + response: + value: + _type: Error + errorIdentifier: urn:openproject-org:api:v3:errors:NotFound + message: The requested resource could not be found. + description: |- + Returned if the meeting does not exist or the client does not have sufficient permissions + to see it. + + **Required permission:** view meetings + + *Note: A client without sufficient permissions shall not be able to test for the existence of a meeting. + That's why a 404 is returned here, even if a 403 might be more appropriate.* + headers: {} + tags: + - Attachments + description: '' + operationId: List_attachments_by_meeting + summary: List attachments by meeting +post: + parameters: + - description: ID of the meeting to receive the attachment + example: '1' + in: path + name: id + required: true + schema: + type: integer + responses: + '200': + content: + application/hal+json: + examples: + response: + value: + _embedded: + author: + _links: + lock: + href: "/api/v3/users/1/lock" + method: post + title: Set lock on admin + self: + href: "/api/v3/users/1" + title: OpenProject Admin + showUser: + href: "/users/1" + type: text/html + updateImmediately: + href: "/api/v3/users/1" + method: patch + title: Update admin + _type: User + admin: true + avatar: '' + createdAt: '2015-03-20T12:56:52.343Z' + email: + firstName: OpenProject + id: 1 + identityUrl: + lastName: Admin + login: admin + name: OpenProject Admin + status: active + updatedAt: '2018-05-29T13:57:44.662Z' + container: + _links: + addAttachment: + href: "/api/v3/meetings/72/attachments" + method: post + attachments: + href: "/api/v3/meetings/72/attachments" + project: + href: "/api/v3/projects/12" + title: Demo project + self: + href: "/api/v3/meetings/72" + _type: Meeting + id: 72 + title: meeting + _links: + author: + href: "/api/v3/users/1" + title: OpenProject Admin + container: + href: "/api/v3/meetings/72" + title: meeting + delete: + href: "/api/v3/attachments/376" + method: delete + downloadLocation: + href: "/api/v3/attachments/376/content" + self: + href: "/api/v3/attachments/376" + title: 200.gif + _type: Attachment + contentType: image/gif + createdAt: '2018-06-01T07:24:19.896Z' + description: + format: plain + html: '' + raw: '' + digest: + algorithm: md5 + hash: 7ac9c97ef73d47127f590788b84c0c1c + fileName: some.gif + fileSize: 3521772 + id: 376 + description: OK + headers: {} + '400': + content: + application/hal+json: + schema: + $ref: "../components/schemas/error_response.yml" + examples: + response: + value: + _type: Error + errorIdentifier: urn:openproject-org:api:v3:errors:InvalidRequestBody + message: The request could not be parsed as JSON. + description: |- + Returned if the client sends a not understandable request. Reasons include: + + * Omitting one of the required parts (metadata and file) + + * sending unparsable JSON in the metadata part + headers: {} + '403': + content: + application/hal+json: + schema: + $ref: "../components/schemas/error_response.yml" + examples: + response: + value: + _type: Error + errorIdentifier: urn:openproject-org:api:v3:errors:MissingPermission + message: You are not allowed to delete this attachment. + description: |- + Returned if the client does not have sufficient permissions. + + **Required permission:** edit meetings + + *Note that you will only receive this error, if you are at least allowed to see the meeting* + headers: {} + '404': + content: + application/hal+json: + schema: + $ref: "../components/schemas/error_response.yml" + examples: + response: + value: + _type: Error + errorIdentifier: urn:openproject-org:api:v3:errors:NotFound + message: The requested resource could not be found. + description: |- + Returned if the meeting does not exist or the client does not have sufficient permissions + to see it. + + **Required permission:** view meetings + + *Note: A client without sufficient permissions shall not be able to test for the existence of a meeting + That's why a 404 is returned here, even if a 403 might be more appropriate.* + headers: {} + '406': + $ref: "../components/responses/missing_content_type.yml" + '415': + $ref: "../components/responses/unsupported_media_type.yml" + '422': + content: + application/hal+json: + schema: + $ref: "../components/schemas/error_response.yml" + examples: + response: + value: + _type: Error + errorIdentifier: urn:openproject-org:api:v3:errors:PropertyConstraintViolation + message: File is too large (maximum size is 5242880 Bytes). + description: |- + Returned if the client tries to send an invalid attachment. + Reasons are: + + * Omitting the file name (`fileName` property of metadata part) + + * Sending a file that is too large + headers: {} + tags: + - Attachments + description: |- + Adds an attachment with the meeting as it's container. + + operationId: Add_attachment_to_meeting + summary: Add attachment to meeting diff --git a/modules/meeting/app/models/meeting.rb b/modules/meeting/app/models/meeting.rb index add973eda076..b2ffac87090f 100644 --- a/modules/meeting/app/models/meeting.rb +++ b/modules/meeting/app/models/meeting.rb @@ -28,6 +28,7 @@ class Meeting < ApplicationRecord include VirtualAttribute + include OpenProject::Journal::AttachmentHelper self.table_name = 'meetings' @@ -59,6 +60,16 @@ class Meeting < ApplicationRecord .merge(Project.allowed_to(args.first || User.current, :view_meetings)) } + acts_as_attachable( + after_remove: :attachments_changed, + order: "#{Attachment.table_name}.file", + add_on_new_permission: :create_meetings, + add_on_persisted_permission: :edit_meetings, + view_permission: :view_meetings, + delete_permission: :edit_meetings, + modification_blocked: ->(*) { false } + ) + acts_as_watchable permission: :view_meetings acts_as_searchable columns: [ diff --git a/modules/meeting/lib/api/v3/attachments/attachments_by_meeting_api.rb b/modules/meeting/lib/api/v3/attachments/attachments_by_meeting_api.rb new file mode 100644 index 000000000000..82ac0c379600 --- /dev/null +++ b/modules/meeting/lib/api/v3/attachments/attachments_by_meeting_api.rb @@ -0,0 +1,56 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module API + module V3 + module Attachments + class AttachmentsByMeetingAPI < ::API::OpenProjectAPI + resources :attachments do + helpers API::V3::Attachments::AttachmentsByContainerAPI::Helpers + + helpers do + def container + @meeting + end + + def get_attachment_self_path + api_v3_paths.attachments_by_meeting_content @meeting.id + end + end + + get &API::V3::Attachments::AttachmentsByContainerAPI.read + post &API::V3::Attachments::AttachmentsByContainerAPI.create + + namespace :prepare do + post &API::V3::Attachments::AttachmentsByContainerAPI.prepare + end + end + end + end + end +end diff --git a/modules/meeting/lib/api/v3/meetings/meeting_representer.rb b/modules/meeting/lib/api/v3/meetings/meeting_representer.rb new file mode 100644 index 000000000000..af49d7dc4f68 --- /dev/null +++ b/modules/meeting/lib/api/v3/meetings/meeting_representer.rb @@ -0,0 +1,83 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module API + module V3 + module Meetings + class MeetingRepresenter < ::API::Decorators::Single + include API::Decorators::LinkedResource + include API::Caching::CachedRepresenter + include API::V3::Attachments::AttachableRepresenterMixin + include API::Decorators::DateProperty + + self_link title_getter: ->(*) { represented.title } + + property :id + property :title + property :location + + property :lock_version, + render_nil: true, + getter: ->(*) { + lock_version.to_i + } + + property :type, + as: :meeting_type, + getter: ->(*) { type } + + date_time_property :start_time + date_time_property :end_time + + property :duration + + associated_resource :author, + v3_path: :user, + representer: ::API::V3::Users::UserRepresenter + + associated_resource :project, + link: ->(*) do + next if represented.project.blank? + + { + href: api_v3_paths.project(represented.project.id), + title: represented.project.name + } + end + + date_time_property :created_at + + date_time_property :updated_at + + def _type + 'Meeting' + end + end + end + end +end diff --git a/modules/meeting/lib/api/v3/meetings/meetings_api.rb b/modules/meeting/lib/api/v3/meetings/meetings_api.rb new file mode 100644 index 000000000000..7f9cd0005188 --- /dev/null +++ b/modules/meeting/lib/api/v3/meetings/meetings_api.rb @@ -0,0 +1,55 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module API + module V3 + module Meetings + class MeetingsAPI < ::API::OpenProjectAPI + resources :meetings do + helpers do + def meeting + MeetingContent.find params[:id] + end + end + + route_param :id, type: Integer, desc: 'Activity ID' do + after_validation do + @meeting = Meeting.visible.find(declared_params[:id]) + end + + get &::API::V3::Utilities::Endpoints::Show + .new(model: ::Meeting) + .mount + + mount ::API::V3::Attachments::AttachmentsByMeetingAPI + end + end + end + end + end +end diff --git a/modules/meeting/lib/open_project/meeting/engine.rb b/modules/meeting/lib/open_project/meeting/engine.rb index 3030589bf398..855c1e68d210 100644 --- a/modules/meeting/lib/open_project/meeting/engine.rb +++ b/modules/meeting/lib/open_project/meeting/engine.rb @@ -161,6 +161,7 @@ class Engine < ::Rails::Engine &::OpenProject::Meeting::Patches::API::WorkPackageRepresenter.extension) add_api_endpoint 'API::V3::Root' do + mount ::API::V3::Meetings::MeetingsAPI mount ::API::V3::Meetings::MeetingContentsAPI end @@ -170,6 +171,10 @@ class Engine < ::Rails::Engine PermittedParams.permit(:search, :meetings) end + add_api_path :meeting do |id| + "#{root}/meetings/#{id}" + end + add_api_path :meeting_content do |id| "#{root}/meeting_contents/#{id}" end @@ -182,6 +187,10 @@ class Engine < ::Rails::Engine meeting_content(id) end + add_api_path :attachments_by_meeting do |id| + "#{meeting(id)}/attachments" + end + add_api_path :attachments_by_meeting_content do |id| "#{meeting_content(id)}/attachments" end diff --git a/modules/meeting/spec/lib/api/v3/meetings/meeting_representer_spec.rb b/modules/meeting/spec/lib/api/v3/meetings/meeting_representer_spec.rb new file mode 100644 index 000000000000..bf376f6b1932 --- /dev/null +++ b/modules/meeting/spec/lib/api/v3/meetings/meeting_representer_spec.rb @@ -0,0 +1,100 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require 'spec_helper' + +RSpec.describe API::V3::Meetings::MeetingRepresenter do + include API::V3::Utilities::PathHelper + + shared_let(:project) { create(:project) } + let(:permissions) { [:view_meetings] } + let(:user) do + create(:user, + member_with_permissions: { project => permissions }, + created_at: 1.day.ago, + updated_at: Time.zone.now) + end + let(:meeting) do + create(:meeting, + author: user, + location: 'https://foo.example.com', + project:) + end + + let(:representer) { described_class.new(meeting, current_user: user) } + + describe 'generation' do + subject(:generated) { representer.to_json } + + describe 'self link' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.meeting(meeting.id) } + let(:title) { meeting.title } + end + end + + it_behaves_like 'has an untitled link' do + let(:link) { :attachments } + let(:href) { api_v3_paths.attachments_by_meeting meeting.id } + end + + it_behaves_like 'has a titled link' do + let(:link) { 'author' } + let(:href) { api_v3_paths.user(user.id) } + let(:title) { user.name } + end + + it_behaves_like 'has a titled link' do + let(:link) { 'project' } + let(:href) { api_v3_paths.project(project.id) } + let(:title) { project.name } + end + + it_behaves_like 'has an untitled action link' do + let(:link) { :addAttachment } + let(:href) { api_v3_paths.attachments_by_meeting meeting.id } + let(:method) { :post } + let(:permission) { :edit_meetings } + end + + it 'describes the object', :aggregate_failures do + expect(subject).to be_json_eql('Meeting'.to_json).at_path('_type') + expect(subject).to be_json_eql(meeting.id.to_json).at_path('id') + expect(subject).to be_json_eql(meeting.title.to_json).at_path('title') + expect(subject).to be_json_eql(meeting.lock_version.to_json).at_path('lockVersion') + expect(subject).to be_json_eql(meeting.start_time.utc.iso8601(3).to_json).at_path('startTime') + expect(subject).to be_json_eql(meeting.end_time.utc.iso8601(3).to_json).at_path('endTime') + expect(subject).to be_json_eql(meeting.duration.to_json).at_path('duration') + expect(subject).to be_json_eql(meeting.location.to_json).at_path('location') + + expect(subject).to be_json_eql(meeting.created_at.utc.iso8601(3).to_json).at_path('createdAt') + expect(subject).to be_json_eql(meeting.updated_at.utc.iso8601(3).to_json).at_path('updatedAt') + end + end +end diff --git a/modules/meeting/spec/lib/api/v3/utilities/path_helper_spec.rb b/modules/meeting/spec/lib/api/v3/utilities/path_helper_spec.rb new file mode 100644 index 000000000000..7f555949b947 --- /dev/null +++ b/modules/meeting/spec/lib/api/v3/utilities/path_helper_spec.rb @@ -0,0 +1,45 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require 'spec_helper' + +RSpec.describe API::V3::Utilities::PathHelper do + let(:helper) { Class.new.tap { |c| c.extend(described_class) }.api_v3_paths } + + describe '#meeting' do + subject { helper.meeting 42 } + + it { is_expected.to eql('/api/v3/meetings/42') } + end + + describe '#attachments_by_meeting' do + subject { helper.attachments_by_meeting 42 } + + it { is_expected.to eql('/api/v3/meetings/42/attachments') } + end +end diff --git a/modules/meeting/spec/requests/api/v3/attachments/meetings_spec.rb b/modules/meeting/spec/requests/api/v3/attachments/meetings_spec.rb new file mode 100644 index 000000000000..bb76e3f8eb18 --- /dev/null +++ b/modules/meeting/spec/requests/api/v3/attachments/meetings_spec.rb @@ -0,0 +1,42 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require 'spec_helper' +require 'requests/api/v3/attachments/attachment_resource_shared_examples' + +RSpec.describe "meetings attachments" do + it_behaves_like "an APIv3 attachment resource" do + let(:attachment_type) { :meeting } + + let(:create_permission) { :create_meetings } + let(:read_permission) { :view_meetings } + let(:update_permission) { :edit_meetings } + + shared_let(:meeting) { create(:meeting, project:) } + end +end diff --git a/modules/meeting/spec/requests/api/v3/meetings/meetings_resource_spec.rb b/modules/meeting/spec/requests/api/v3/meetings/meetings_resource_spec.rb new file mode 100644 index 000000000000..c7918ebd3611 --- /dev/null +++ b/modules/meeting/spec/requests/api/v3/meetings/meetings_resource_spec.rb @@ -0,0 +1,86 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require 'spec_helper' +require 'rack/test' + +RSpec.describe 'API v3 Meeting resource' do + include Rack::Test::Methods + include API::V3::Utilities::PathHelper + + shared_let(:project) { create(:project) } + shared_let(:meeting) { create(:meeting, project:) } + + let(:permissions) { [:view_meetings] } + let(:current_user) do + create(:user, + member_with_permissions: { project => permissions }) + end + + describe 'meetings/:id' do + let(:get_path) { api_v3_paths.meeting meeting.id } + + context 'with logged in user' do + before do + allow(User).to receive(:current).and_return current_user + + get get_path + end + + context 'when valid id' do + it 'returns HTTP 200' do + expect(last_response.status).to eq 200 + end + end + + context 'when valid id, but not visible' do + let(:permissions) { [:view_work_packages] } + + it 'returns HTTP 404' do + expect(last_response.status).to eq 404 + end + end + + context 'when invalid id' do + let(:get_path) { api_v3_paths.budget 'bogus' } + + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } + end + end + end + + context 'with not logged in user' do + before do + get get_path + end + + it_behaves_like 'not found response based on login_required' + end + end +end