Skip to content

Commit

Permalink
Merge pull request #395 from kbsali/320-add-support-for-updating-atta…
Browse files Browse the repository at this point in the history
…chments-over-rest-api

Add support for updating attachments
  • Loading branch information
Art4 authored Mar 18, 2024
2 parents 2b4c451 + 8d265a4 commit 3940781
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 2 deletions.
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, []);
}
}

0 comments on commit 3940781

Please sign in to comment.