• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NIT-Administrative-Systems / dynamic-forms / 13506106128

24 Feb 2025 07:22PM UTC coverage: 59.275% (-34.7%) from 94.003%
13506106128

Pull #480

github

nie7321
Additional annotations
Pull Request #480: Laravel 12

818 of 1380 relevant lines covered (59.28%)

44.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.06
/src/Storage/S3Driver.php
1
<?php
2

3
namespace Northwestern\SysDev\DynamicForms\Storage;
4

5
use Aws\S3\Exception\S3Exception;
6
use Aws\S3\S3Client;
7
use Illuminate\Http\JsonResponse;
8

9
class S3Driver implements StorageInterface
10
{
11
    /** @var string */
12
    const STORAGE_S3 = 's3';
13

14
    protected S3Client $client;
15
    protected string $bucket;
16

17
    public function __construct(array $clientConfig, string $bucketName)
18
    {
19
        $this->client = new S3Client($clientConfig);
18✔
20
        $this->bucket = $bucketName;
18✔
21
    }
22

23
    public function findObject(string $key): bool
24
    {
25
        $client = $this->storageClient();
6✔
26
        try {
27
            $client->execute($client->getCommand('headObject', array_filter([
6✔
28
                'Bucket' => $this->bucket,
6✔
29
                'Key' => $key,
6✔
30
            ])));
6✔
31

32
            return true;
3✔
33
        } catch (S3Exception) {
3✔
34
            return false;
3✔
35
        }
36
    }
37

38
    public function storageClient(): S3Client
39
    {
40
        return $this->client;
18✔
41
    }
42

43
    public function setStorageClient(S3Client $client): void
44
    {
45
        $this->client = $client;
18✔
46
    }
47

48
    /**
49
     * @param string $urlValidityPeriod The time at which the URL should expire. This can be a Unix timestamp, a PHP DateTime object, or a string that can be evaluated by strtotime().
50
     */
51
    public function getDirectDownloadLink(
52
        string $key,
53
        ?string $originalName = null,
54
        bool $forceDownload = true,
55
        string $urlValidityPeriod = '+5 minutes',
56
        array $additionalCommandParameters = []
57
    ): string {
58
        $client = $this->storageClient();
6✔
59
        $disposition = [$forceDownload ? 'attachment' : 'inline'];
6✔
60

61
        if ($originalName) {
6✔
62
            $disposition[] = sprintf('filename="%s"', str_replace('"', '\"', $originalName));
×
63
        }
64

65
        $parameters = array_merge([
6✔
66
            'Bucket' => $this->bucket,
6✔
67
            'Key' => $key,
6✔
68
            'ResponseContentDisposition' => implode('; ', $disposition),
6✔
69
        ], $additionalCommandParameters);
6✔
70

71
        $signedRequest =
6✔
72
            $client->createPresignedRequest(
6✔
73
                $client->getCommand('getObject', array_filter($parameters)),
6✔
74
                $urlValidityPeriod
6✔
75
            );
6✔
76

77
        return $signedRequest->getUri();
6✔
78
    }
79

80
    public function getDownloadLink(
81
        string $key,
82
        ?string $originalName = null,
83
        string $urlValidityPeriod = '+5 minutes',
84
        array $additionalCommandParameters = []
85
    ): JsonResponse {
86
        return response()->json([
3✔
87
            'url' => $this->getDirectDownloadLink($key, $originalName, true, $urlValidityPeriod, $additionalCommandParameters),
3✔
88
        ], 201);
3✔
89
    }
90

91
    /**
92
     * @param string $urlValidityPeriod The time at which the URL should expire. This can be a Unix timestamp, a PHP DateTime object, or a string that can be evaluated by strtotime().
93
     */
94
    public function getUploadLink(
95
        string $key,
96
        string $urlValidityPeriod = '+5 minutes',
97
        array $additionalCommandParameters = []
98
    ): JsonResponse {
99
        $client = $this->storageClient();
3✔
100
        $parameters = array_merge(
3✔
101
            [
3✔
102
                'Bucket' => $this->bucket,
3✔
103
                'Key' => $key,
3✔
104
                'ACL' => 'private',
3✔
105
                'ContentType' => 'application/octet-stream',
3✔
106
            ],
3✔
107
            $additionalCommandParameters
3✔
108
        );
3✔
109

110
        $signedRequest = $client->createPresignedRequest(
3✔
111
            $client->getCommand('putObject', array_filter($parameters)),
3✔
112
            $urlValidityPeriod
3✔
113
        );
3✔
114

115
        return response()->json([
3✔
116
            'signed' => (string) $signedRequest->getUri(),
3✔
117
            'headers' => array_merge(
3✔
118
                $signedRequest->getHeaders(),
3✔
119
                [
3✔
120
                    'Content-Type' => 'application/octet-stream',
3✔
121
                ]
3✔
122
            ),
3✔
123
            'url' => route('dynamic-forms.S3-file-download'),
3✔
124
            'data' => [
3✔
125
                'fileName' => $key,
3✔
126
            ],
3✔
127
        ], 201);
3✔
128
    }
129

130
    public function isValid(mixed $value): bool
131
    {
132
        // Check if all fields exist
133
        if (! isset($value) || ! isset($value['name']) || ! isset($value['key']) || ! isset($value['url'])) {
×
134
            return false;
×
135
        }
136

137
        /**
138
         * Check consistency of fields.
139
         *
140
         * Laravel's route() helper will provide a URL-encoded URL, but Formio will not. Rectify the difference
141
         * before trying to validate.
142
         */
143
        $expectedUrl = urldecode(route('dynamic-forms.S3-file-redirect', ['fileKey' => $value['key']]));
×
144
        if ($expectedUrl != $value['url']) {
×
145
            return false;
×
146
        }
147

148
        return $this->findObject($value['key']);
×
149
    }
150

151
    public static function getStorageMethod(): string
152
    {
153
        return self::STORAGE_S3;
12✔
154
    }
155
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc