Skip to content

Add support for updating attachments #395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- New method `Redmine\Api\Attachment::update()` for updating attachments.
- New interface `Redmine\Http\HttpClient` for new minimalistic HTTP clients.
- New interface `Redmine\Http\Request` for sending data with new minimalistic HTTP clients.
- New method `Redmine\Api\...::getLastResponse()` to get the last response made by the API class.
- Add support for custom arrays in `Redmine\Serializer\XmlSerializer`
- Add support for custom arrays in `Redmine\Serializer\XmlSerializer`.

### Changed

Expand Down
34 changes: 34 additions & 0 deletions src/Redmine/Api/Attachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Redmine\Api;

use Redmine\Exception\SerializerException;
use Redmine\Exception\UnexpectedResponseException;
use Redmine\Http\HttpFactory;
use Redmine\Serializer\JsonSerializer;
use Redmine\Serializer\PathSerializer;
Expand Down Expand Up @@ -46,6 +47,39 @@ public function show($id)
}
}

/**
* Update information about an attachment.
*
* @see https://www.redmine.org/projects/redmine/wiki/Rest_Attachments#PATCH
*
* @param int $id the attachment id
* @param array $params available $params:
* - filename: filename of the attachment
* - description: new description of the attachment
*
* @throws SerializerException if $params contains invalid values
* @throws UnexpectedResponseException if the Redmine server delivers an unexpected response
*
* @return true if the request was successful
*/
final public function update(int $id, array $params): bool
{
// we are using `PUT` instead of documented `PATCH`
// @see https://github.com/kbsali/php-redmine-api/pull/395#issuecomment-2004089154
// @see https://www.redmine.org/projects/redmine/wiki/Rest_Attachments#PATCH
$this->lastResponse = $this->getHttpClient()->request(HttpFactory::makeJsonRequest(
'PUT',
'/attachments/' . $id . '.json',
JsonSerializer::createFromArray(['attachment' => $params])->getEncoded()
));

if ($this->lastResponse->getStatusCode() !== 204) {
throw UnexpectedResponseException::create($this->lastResponse);
}

return true;
}

/**
* Get attachment content as a binary file.
*
Expand Down
21 changes: 20 additions & 1 deletion tests/Behat/Bootstrap/AttachmentContextTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Redmine\Tests\Behat\Bootstrap;

use Behat\Behat\Tester\Exception\PendingException;
use Behat\Gherkin\Node\TableNode;
use Redmine\Api\Attachment;

Expand Down Expand Up @@ -32,6 +31,26 @@ public function iUploadTheContentOfTheFileWithTheFollowingData(string $filepath,
);
}

/**
* @When I update the attachment with the id :attachmentId with the following data
*/
public function iUpdateTheAttachmentWithTheIdWithTheFollowingData(int $attachmentId, TableNode $table)
{
$data = [];

foreach ($table as $row) {
$data[$row['property']] = $row['value'];
}

/** @var Attachment */
$api = $this->getNativeCurlClient()->getApi('attachment');

$this->registerClientResponse(
$api->update($attachmentId, $data),
$api->getLastResponse()
);
}

/**
* @When I show the attachment with the id :attachmentId
*/
Expand Down
15 changes: 15 additions & 0 deletions tests/Behat/features/attachments.feature
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ Feature: Interacting with the REST API for attachments
| id | 1 |
| token | 1.7b962f8af22e26802b87abfa0b07b21dbd03b984ec8d6888dabd3f69cff162f8 |

@attachment
Scenario: Updating the details of an attachment
Given I have a "NativeCurlClient" client
And I create a project with name "Test Project" and identifier "test-project"
And I upload the content of the file "%tests_dir%/Fixtures/testfile_01.txt" with the following data
| property | value |
| filename | testfile.txt |
When I update the attachment with the id "1" with the following data
| property | value |
| filename | testfile2.txt |
Then the response has the status code "204"
And the response has an empty content type
And the response has the content ""
And the returned data is true

@attachment
Scenario: Showing the details of an attachment
Given I have a "NativeCurlClient" client
Expand Down
79 changes: 79 additions & 0 deletions tests/Unit/Api/Attachment/UpdateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

namespace Redmine\Tests\Unit\Api\Attachment;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Redmine\Api\Attachment;
use Redmine\Exception\UnexpectedResponseException;
use Redmine\Tests\Fixtures\AssertingHttpClient;

#[CoversClass(Attachment::class)]
class UpdateTest extends TestCase
{
/**
* @dataProvider getUpdateData
*/
#[DataProvider('getUpdateData')]
public function testUpdateReturnsCorrectResponse($id, array $params, $expectedPath, $expectedContent, $expectedReturn)
{
$client = AssertingHttpClient::create(
$this,
[
'PUT',
$expectedPath,
'application/json',
$expectedContent,
204,
'',
''
]
);

// Create the object under test
$api = new Attachment($client);

// Perform the tests
$this->assertSame($expectedReturn, $api->update($id, $params));
}

public static function getUpdateData(): array
{
return [
'test with all params' => [
5,
[
'filename' => 'renamed.zip',
'description' => 'updated',
],
'/attachments/5.json',
'{"attachment":{"filename":"renamed.zip","description":"updated"}}',
true,
],
];
}

public function testUpdateThrowsUnexpectedResponseException()
{
$client = AssertingHttpClient::create(
$this,
[
'PUT',
'/attachments/5.json',
'application/json',
'{"attachment":[]}',
403,
'',
'',
]
);

$api = new Attachment($client);

$this->expectException(UnexpectedResponseException::class);
$this->expectExceptionMessage('The Redmine server replied with an unexpected response.');

$api->update(5, []);
}
}